@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,49 @@
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.resolveRecipientAlias = resolveRecipientAlias;
6
+ exports._resetAliasCache = _resetAliasCache;
7
+ const auth_1 = require("../middleware/auth");
8
+ /** Lazily-cached set of support aliases, parsed from SUPPORT_ALIASES on first access. */
9
+ let _supportAliases;
10
+ function getSupportAliases() {
11
+ if (!_supportAliases) {
12
+ const raw = process.env.SUPPORT_ALIASES || '';
13
+ _supportAliases = new Set(raw
14
+ .split(',')
15
+ .map(alias => alias.trim().toLowerCase())
16
+ .filter(alias => alias.length > 0));
17
+ }
18
+ return _supportAliases;
19
+ }
20
+ /**
21
+ * Resolve an email-like alias to an actual organization ID.
22
+ *
23
+ * If the input matches a configured support alias, it resolves to the system
24
+ * org ID. Otherwise the input is returned as-is (lowercased).
25
+ */
26
+ function resolveRecipientAlias(recipientOrgId) {
27
+ const normalized = recipientOrgId.trim().toLowerCase();
28
+ const aliases = getSupportAliases();
29
+ if (aliases.has(normalized)) {
30
+ return {
31
+ resolvedOrgId: auth_1.SYSTEM_ORG_ID,
32
+ wasAlias: true,
33
+ originalValue: recipientOrgId,
34
+ };
35
+ }
36
+ return {
37
+ resolvedOrgId: normalized,
38
+ wasAlias: false,
39
+ originalValue: recipientOrgId,
40
+ };
41
+ }
42
+ /**
43
+ * Reset the cached aliases (for testing purposes only).
44
+ * @internal
45
+ */
46
+ function _resetAliasCache() {
47
+ _supportAliases = undefined;
48
+ }
49
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWxpYXMtcmVzb2x2ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvYWxpYXMtcmVzb2x2ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7O0FBb0N0QyxzREFpQkM7QUFNRCw0Q0FFQztBQTNERCw2Q0FBbUQ7QUFFbkQseUZBQXlGO0FBQ3pGLElBQUksZUFBd0MsQ0FBQztBQUU3QyxTQUFTLGlCQUFpQjtJQUN4QixJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7UUFDckIsTUFBTSxHQUFHLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxlQUFlLElBQUksRUFBRSxDQUFDO1FBQzlDLGVBQWUsR0FBRyxJQUFJLEdBQUcsQ0FDdkIsR0FBRzthQUNBLEtBQUssQ0FBQyxHQUFHLENBQUM7YUFDVixHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUMsV0FBVyxFQUFFLENBQUM7YUFDeEMsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FDckMsQ0FBQztJQUNKLENBQUM7SUFDRCxPQUFPLGVBQWUsQ0FBQztBQUN6QixDQUFDO0FBWUQ7Ozs7O0dBS0c7QUFDSCxTQUFnQixxQkFBcUIsQ0FBQyxjQUFzQjtJQUMxRCxNQUFNLFVBQVUsR0FBRyxjQUFjLENBQUMsSUFBSSxFQUFFLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDdkQsTUFBTSxPQUFPLEdBQUcsaUJBQWlCLEVBQUUsQ0FBQztJQUVwQyxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQztRQUM1QixPQUFPO1lBQ0wsYUFBYSxFQUFFLG9CQUFhO1lBQzVCLFFBQVEsRUFBRSxJQUFJO1lBQ2QsYUFBYSxFQUFFLGNBQWM7U0FDOUIsQ0FBQztJQUNKLENBQUM7SUFFRCxPQUFPO1FBQ0wsYUFBYSxFQUFFLFVBQVU7UUFDekIsUUFBUSxFQUFFLEtBQUs7UUFDZixhQUFhLEVBQUUsY0FBYztLQUM5QixDQUFDO0FBQ0osQ0FBQztBQUVEOzs7R0FHRztBQUNILFNBQWdCLGdCQUFnQjtJQUM5QixlQUFlLEdBQUcsU0FBUyxDQUFDO0FBQzlCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuaW1wb3J0IHsgU1lTVEVNX09SR19JRCB9IGZyb20gJy4uL21pZGRsZXdhcmUvYXV0aCc7XG5cbi8qKiBMYXppbHktY2FjaGVkIHNldCBvZiBzdXBwb3J0IGFsaWFzZXMsIHBhcnNlZCBmcm9tIFNVUFBPUlRfQUxJQVNFUyBvbiBmaXJzdCBhY2Nlc3MuICovXG5sZXQgX3N1cHBvcnRBbGlhc2VzOiBTZXQ8c3RyaW5nPiB8IHVuZGVmaW5lZDtcblxuZnVuY3Rpb24gZ2V0U3VwcG9ydEFsaWFzZXMoKTogU2V0PHN0cmluZz4ge1xuICBpZiAoIV9zdXBwb3J0QWxpYXNlcykge1xuICAgIGNvbnN0IHJhdyA9IHByb2Nlc3MuZW52LlNVUFBPUlRfQUxJQVNFUyB8fCAnJztcbiAgICBfc3VwcG9ydEFsaWFzZXMgPSBuZXcgU2V0KFxuICAgICAgcmF3XG4gICAgICAgIC5zcGxpdCgnLCcpXG4gICAgICAgIC5tYXAoYWxpYXMgPT4gYWxpYXMudHJpbSgpLnRvTG93ZXJDYXNlKCkpXG4gICAgICAgIC5maWx0ZXIoYWxpYXMgPT4gYWxpYXMubGVuZ3RoID4gMCksXG4gICAgKTtcbiAgfVxuICByZXR1cm4gX3N1cHBvcnRBbGlhc2VzO1xufVxuXG4vKiogUmVzdWx0IG9mIGFsaWFzIHJlc29sdXRpb24uICovXG5leHBvcnQgaW50ZXJmYWNlIEFsaWFzUmVzb2x1dGlvbiB7XG4gIC8qKiBUaGUgcmVzb2x2ZWQgb3JnYW5pemF0aW9uIElEIChlLmcuLCAnc3lzdGVtJykuICovXG4gIHJlc29sdmVkT3JnSWQ6IHN0cmluZztcbiAgLyoqIFdoZXRoZXIgdGhlIGlucHV0IHdhcyBhbiBhbGlhcyB0aGF0IGdvdCByZXNvbHZlZC4gKi9cbiAgd2FzQWxpYXM6IGJvb2xlYW47XG4gIC8qKiBUaGUgb3JpZ2luYWwgaW5wdXQgdmFsdWUsIHVzZWZ1bCBmb3IgYXVkaXQgbG9nZ2luZy4gKi9cbiAgb3JpZ2luYWxWYWx1ZTogc3RyaW5nO1xufVxuXG4vKipcbiAqIFJlc29sdmUgYW4gZW1haWwtbGlrZSBhbGlhcyB0byBhbiBhY3R1YWwgb3JnYW5pemF0aW9uIElELlxuICpcbiAqIElmIHRoZSBpbnB1dCBtYXRjaGVzIGEgY29uZmlndXJlZCBzdXBwb3J0IGFsaWFzLCBpdCByZXNvbHZlcyB0byB0aGUgc3lzdGVtXG4gKiBvcmcgSUQuIE90aGVyd2lzZSB0aGUgaW5wdXQgaXMgcmV0dXJuZWQgYXMtaXMgKGxvd2VyY2FzZWQpLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZVJlY2lwaWVudEFsaWFzKHJlY2lwaWVudE9yZ0lkOiBzdHJpbmcpOiBBbGlhc1Jlc29sdXRpb24ge1xuICBjb25zdCBub3JtYWxpemVkID0gcmVjaXBpZW50T3JnSWQudHJpbSgpLnRvTG93ZXJDYXNlKCk7XG4gIGNvbnN0IGFsaWFzZXMgPSBnZXRTdXBwb3J0QWxpYXNlcygpO1xuXG4gIGlmIChhbGlhc2VzLmhhcyhub3JtYWxpemVkKSkge1xuICAgIHJldHVybiB7XG4gICAgICByZXNvbHZlZE9yZ0lkOiBTWVNURU1fT1JHX0lELFxuICAgICAgd2FzQWxpYXM6IHRydWUsXG4gICAgICBvcmlnaW5hbFZhbHVlOiByZWNpcGllbnRPcmdJZCxcbiAgICB9O1xuICB9XG5cbiAgcmV0dXJuIHtcbiAgICByZXNvbHZlZE9yZ0lkOiBub3JtYWxpemVkLFxuICAgIHdhc0FsaWFzOiBmYWxzZSxcbiAgICBvcmlnaW5hbFZhbHVlOiByZWNpcGllbnRPcmdJZCxcbiAgfTtcbn1cblxuLyoqXG4gKiBSZXNldCB0aGUgY2FjaGVkIGFsaWFzZXMgKGZvciB0ZXN0aW5nIHB1cnBvc2VzIG9ubHkpLlxuICogQGludGVybmFsXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBfcmVzZXRBbGlhc0NhY2hlKCk6IHZvaWQge1xuICBfc3VwcG9ydEFsaWFzZXMgPSB1bmRlZmluZWQ7XG59XG4iXX0=
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Express 5 header type.
3
+ */
4
+ type HeaderValue = string | string[] | undefined;
5
+ /**
6
+ * Extract a single string from a header value that may be string | string[] | undefined.
7
+ *
8
+ * @param value - Header value from Express request
9
+ * @returns First value if array, the value if string, or undefined
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * const orgId = getHeaderString(req.headers['x-org-id']);
14
+ * const auth = getHeaderString(req.headers.authorization);
15
+ * ```
16
+ */
17
+ export declare function getHeaderString(value: HeaderValue): string | undefined;
18
+ export {};
@@ -0,0 +1,24 @@
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.getHeaderString = getHeaderString;
6
+ /**
7
+ * Extract a single string from a header value that may be string | string[] | undefined.
8
+ *
9
+ * @param value - Header value from Express request
10
+ * @returns First value if array, the value if string, or undefined
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const orgId = getHeaderString(req.headers['x-org-id']);
15
+ * const auth = getHeaderString(req.headers.authorization);
16
+ * ```
17
+ */
18
+ function getHeaderString(value) {
19
+ if (Array.isArray(value)) {
20
+ return value[0];
21
+ }
22
+ return value;
23
+ }
24
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVhZGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91dGlscy9oZWFkZXJzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDOztBQW1CdEMsMENBS0M7QUFqQkQ7Ozs7Ozs7Ozs7O0dBV0c7QUFDSCxTQUFnQixlQUFlLENBQUMsS0FBa0I7SUFDaEQsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDekIsT0FBTyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDbEIsQ0FBQztJQUNELE9BQU8sS0FBSyxDQUFDO0FBQ2YsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG4vKipcbiAqIEV4cHJlc3MgNSBoZWFkZXIgdHlwZS5cbiAqL1xudHlwZSBIZWFkZXJWYWx1ZSA9IHN0cmluZyB8IHN0cmluZ1tdIHwgdW5kZWZpbmVkO1xuXG4vKipcbiAqIEV4dHJhY3QgYSBzaW5nbGUgc3RyaW5nIGZyb20gYSBoZWFkZXIgdmFsdWUgdGhhdCBtYXkgYmUgc3RyaW5nIHwgc3RyaW5nW10gfCB1bmRlZmluZWQuXG4gKlxuICogQHBhcmFtIHZhbHVlIC0gSGVhZGVyIHZhbHVlIGZyb20gRXhwcmVzcyByZXF1ZXN0XG4gKiBAcmV0dXJucyBGaXJzdCB2YWx1ZSBpZiBhcnJheSwgdGhlIHZhbHVlIGlmIHN0cmluZywgb3IgdW5kZWZpbmVkXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IG9yZ0lkID0gZ2V0SGVhZGVyU3RyaW5nKHJlcS5oZWFkZXJzWyd4LW9yZy1pZCddKTtcbiAqIGNvbnN0IGF1dGggPSBnZXRIZWFkZXJTdHJpbmcocmVxLmhlYWRlcnMuYXV0aG9yaXphdGlvbik7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldEhlYWRlclN0cmluZyh2YWx1ZTogSGVhZGVyVmFsdWUpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBpZiAoQXJyYXkuaXNBcnJheSh2YWx1ZSkpIHtcbiAgICByZXR1cm4gdmFsdWVbMF07XG4gIH1cbiAgcmV0dXJuIHZhbHVlO1xufVxuIl19
@@ -0,0 +1,61 @@
1
+ import { HttpRequest } from '../types/http';
2
+ /**
3
+ * Identity information extracted from request headers.
4
+ */
5
+ export interface RequestIdentity {
6
+ /** Organization ID from x-org-id header */
7
+ readonly orgId?: string;
8
+ /** User ID from x-user-id header */
9
+ readonly userId?: string;
10
+ /** Request ID from x-request-id header */
11
+ readonly requestId?: string;
12
+ /** User role from x-user-role header (decoded from JWT) */
13
+ readonly role?: string;
14
+ }
15
+ /**
16
+ * Extract identity information from request headers.
17
+ *
18
+ * Extracts common identity headers used for multi-tenant authentication:
19
+ * - x-org-id: Organization identifier
20
+ * - x-user-id: User identifier
21
+ * - x-request-id: Request trace identifier
22
+ * - x-user-role: User role
23
+ *
24
+ * @param req - HTTP request object
25
+ * @returns Identity object with orgId, userId, requestId, and role
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * app.post('/api/resource', requireAuth, async (req, res) => {
30
+ * const identity = getIdentity(req);
31
+ *
32
+ * if (!identity.orgId) {
33
+ * return sendError(res, 400, 'x-org-id header required');
34
+ * }
35
+ *
36
+ * // Use identity.orgId, identity.userId, etc.
37
+ * });
38
+ * ```
39
+ */
40
+ export declare function getIdentity(req: HttpRequest): RequestIdentity;
41
+ /**
42
+ * Validate that required identity fields are present.
43
+ *
44
+ * @param identity - Identity object to validate
45
+ * @param required - Array of required field names
46
+ * @returns Object with isValid boolean and missing fields array
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * const identity = getIdentity(req);
51
+ * const validation = validateIdentity(identity, ['orgId', 'userId']);
52
+ *
53
+ * if (!validation.isValid) {
54
+ * return sendError(res, 400, `Missing required headers: ${validation.missing.join(', ')}`);
55
+ * }
56
+ * ```
57
+ */
58
+ export declare function validateIdentity(identity: RequestIdentity, required: (keyof RequestIdentity)[]): {
59
+ isValid: boolean;
60
+ missing: string[];
61
+ };
@@ -0,0 +1,75 @@
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.getIdentity = getIdentity;
6
+ exports.validateIdentity = validateIdentity;
7
+ const headers_1 = require("./headers");
8
+ /**
9
+ * Extract identity information from request headers.
10
+ *
11
+ * Extracts common identity headers used for multi-tenant authentication:
12
+ * - x-org-id: Organization identifier
13
+ * - x-user-id: User identifier
14
+ * - x-request-id: Request trace identifier
15
+ * - x-user-role: User role
16
+ *
17
+ * @param req - HTTP request object
18
+ * @returns Identity object with orgId, userId, requestId, and role
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * app.post('/api/resource', requireAuth, async (req, res) => {
23
+ * const identity = getIdentity(req);
24
+ *
25
+ * if (!identity.orgId) {
26
+ * return sendError(res, 400, 'x-org-id header required');
27
+ * }
28
+ *
29
+ * // Use identity.orgId, identity.userId, etc.
30
+ * });
31
+ * ```
32
+ */
33
+ function getIdentity(req) {
34
+ // Prefer JWT-verified claims (req.user) over raw headers to prevent spoofing.
35
+ // Headers are only used as fallback or for fields not in the JWT (e.g. requestId).
36
+ const user = req.user;
37
+ return {
38
+ orgId: user?.organizationId || (0, headers_1.getHeaderString)(req.headers['x-org-id']),
39
+ userId: user?.sub
40
+ || user?.userId
41
+ || (0, headers_1.getHeaderString)(req.headers['x-user-id']),
42
+ requestId: (0, headers_1.getHeaderString)(req.headers['x-request-id']),
43
+ role: user?.role || (0, headers_1.getHeaderString)(req.headers['x-user-role']),
44
+ };
45
+ }
46
+ /**
47
+ * Validate that required identity fields are present.
48
+ *
49
+ * @param identity - Identity object to validate
50
+ * @param required - Array of required field names
51
+ * @returns Object with isValid boolean and missing fields array
52
+ *
53
+ * @example
54
+ * ```typescript
55
+ * const identity = getIdentity(req);
56
+ * const validation = validateIdentity(identity, ['orgId', 'userId']);
57
+ *
58
+ * if (!validation.isValid) {
59
+ * return sendError(res, 400, `Missing required headers: ${validation.missing.join(', ')}`);
60
+ * }
61
+ * ```
62
+ */
63
+ function validateIdentity(identity, required) {
64
+ const missing = [];
65
+ for (const field of required) {
66
+ if (!identity[field]) {
67
+ missing.push(`x-${field.replace(/([A-Z])/g, '-$1').toLowerCase()}`);
68
+ }
69
+ }
70
+ return {
71
+ isValid: missing.length === 0,
72
+ missing,
73
+ };
74
+ }
75
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaWRlbnRpdHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvaWRlbnRpdHkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7O0FBNEN0QyxrQ0FZQztBQW1CRCw0Q0FnQkM7QUF6RkQsdUNBQTRDO0FBaUI1Qzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBd0JHO0FBQ0gsU0FBZ0IsV0FBVyxDQUFDLEdBQWdCO0lBQzFDLDhFQUE4RTtJQUM5RSxtRkFBbUY7SUFDbkYsTUFBTSxJQUFJLEdBQUcsR0FBRyxDQUFDLElBQUksQ0FBQztJQUN0QixPQUFPO1FBQ0wsS0FBSyxFQUFFLElBQUksRUFBRSxjQUFjLElBQUksSUFBQSx5QkFBZSxFQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDdkUsTUFBTSxFQUFHLElBQTRDLEVBQUUsR0FBeUI7ZUFDM0UsSUFBSSxFQUFFLE1BQU07ZUFDWixJQUFBLHlCQUFlLEVBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUM5QyxTQUFTLEVBQUUsSUFBQSx5QkFBZSxFQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFDLENBQUM7UUFDdkQsSUFBSSxFQUFFLElBQUksRUFBRSxJQUFJLElBQUksSUFBQSx5QkFBZSxFQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLENBQUM7S0FDaEUsQ0FBQztBQUNKLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7Ozs7OztHQWdCRztBQUNILFNBQWdCLGdCQUFnQixDQUM5QixRQUF5QixFQUN6QixRQUFtQztJQUVuQyxNQUFNLE9BQU8sR0FBYSxFQUFFLENBQUM7SUFFN0IsS0FBSyxNQUFNLEtBQUssSUFBSSxRQUFRLEVBQUUsQ0FBQztRQUM3QixJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDckIsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLEtBQUssQ0FBQyxPQUFPLENBQUMsVUFBVSxFQUFFLEtBQUssQ0FBQyxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUN0RSxDQUFDO0lBQ0gsQ0FBQztJQUVELE9BQU87UUFDTCxPQUFPLEVBQUUsT0FBTyxDQUFDLE1BQU0sS0FBSyxDQUFDO1FBQzdCLE9BQU87S0FDUixDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgeyBnZXRIZWFkZXJTdHJpbmcgfSBmcm9tICcuL2hlYWRlcnMnO1xuaW1wb3J0IHsgSHR0cFJlcXVlc3QgfSBmcm9tICcuLi90eXBlcy9odHRwJztcblxuLyoqXG4gKiBJZGVudGl0eSBpbmZvcm1hdGlvbiBleHRyYWN0ZWQgZnJvbSByZXF1ZXN0IGhlYWRlcnMuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmVxdWVzdElkZW50aXR5IHtcbiAgLyoqIE9yZ2FuaXphdGlvbiBJRCBmcm9tIHgtb3JnLWlkIGhlYWRlciAqL1xuICByZWFkb25seSBvcmdJZD86IHN0cmluZztcbiAgLyoqIFVzZXIgSUQgZnJvbSB4LXVzZXItaWQgaGVhZGVyICovXG4gIHJlYWRvbmx5IHVzZXJJZD86IHN0cmluZztcbiAgLyoqIFJlcXVlc3QgSUQgZnJvbSB4LXJlcXVlc3QtaWQgaGVhZGVyICovXG4gIHJlYWRvbmx5IHJlcXVlc3RJZD86IHN0cmluZztcbiAgLyoqIFVzZXIgcm9sZSBmcm9tIHgtdXNlci1yb2xlIGhlYWRlciAoZGVjb2RlZCBmcm9tIEpXVCkgKi9cbiAgcmVhZG9ubHkgcm9sZT86IHN0cmluZztcbn1cblxuLyoqXG4gKiBFeHRyYWN0IGlkZW50aXR5IGluZm9ybWF0aW9uIGZyb20gcmVxdWVzdCBoZWFkZXJzLlxuICpcbiAqIEV4dHJhY3RzIGNvbW1vbiBpZGVudGl0eSBoZWFkZXJzIHVzZWQgZm9yIG11bHRpLXRlbmFudCBhdXRoZW50aWNhdGlvbjpcbiAqIC0geC1vcmctaWQ6IE9yZ2FuaXphdGlvbiBpZGVudGlmaWVyXG4gKiAtIHgtdXNlci1pZDogVXNlciBpZGVudGlmaWVyXG4gKiAtIHgtcmVxdWVzdC1pZDogUmVxdWVzdCB0cmFjZSBpZGVudGlmaWVyXG4gKiAtIHgtdXNlci1yb2xlOiBVc2VyIHJvbGVcbiAqXG4gKiBAcGFyYW0gcmVxIC0gSFRUUCByZXF1ZXN0IG9iamVjdFxuICogQHJldHVybnMgSWRlbnRpdHkgb2JqZWN0IHdpdGggb3JnSWQsIHVzZXJJZCwgcmVxdWVzdElkLCBhbmQgcm9sZVxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBhcHAucG9zdCgnL2FwaS9yZXNvdXJjZScsIHJlcXVpcmVBdXRoLCBhc3luYyAocmVxLCByZXMpID0+IHtcbiAqICAgY29uc3QgaWRlbnRpdHkgPSBnZXRJZGVudGl0eShyZXEpO1xuICpcbiAqICAgaWYgKCFpZGVudGl0eS5vcmdJZCkge1xuICogICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCA0MDAsICd4LW9yZy1pZCBoZWFkZXIgcmVxdWlyZWQnKTtcbiAqICAgfVxuICpcbiAqICAgLy8gVXNlIGlkZW50aXR5Lm9yZ0lkLCBpZGVudGl0eS51c2VySWQsIGV0Yy5cbiAqIH0pO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRJZGVudGl0eShyZXE6IEh0dHBSZXF1ZXN0KTogUmVxdWVzdElkZW50aXR5IHtcbiAgLy8gUHJlZmVyIEpXVC12ZXJpZmllZCBjbGFpbXMgKHJlcS51c2VyKSBvdmVyIHJhdyBoZWFkZXJzIHRvIHByZXZlbnQgc3Bvb2ZpbmcuXG4gIC8vIEhlYWRlcnMgYXJlIG9ubHkgdXNlZCBhcyBmYWxsYmFjayBvciBmb3IgZmllbGRzIG5vdCBpbiB0aGUgSldUIChlLmcuIHJlcXVlc3RJZCkuXG4gIGNvbnN0IHVzZXIgPSByZXEudXNlcjtcbiAgcmV0dXJuIHtcbiAgICBvcmdJZDogdXNlcj8ub3JnYW5pemF0aW9uSWQgfHwgZ2V0SGVhZGVyU3RyaW5nKHJlcS5oZWFkZXJzWyd4LW9yZy1pZCddKSxcbiAgICB1c2VySWQ6ICh1c2VyIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+IHwgdW5kZWZpbmVkKT8uc3ViIGFzIHN0cmluZyB8IHVuZGVmaW5lZFxuICAgICAgfHwgdXNlcj8udXNlcklkXG4gICAgICB8fCBnZXRIZWFkZXJTdHJpbmcocmVxLmhlYWRlcnNbJ3gtdXNlci1pZCddKSxcbiAgICByZXF1ZXN0SWQ6IGdldEhlYWRlclN0cmluZyhyZXEuaGVhZGVyc1sneC1yZXF1ZXN0LWlkJ10pLFxuICAgIHJvbGU6IHVzZXI/LnJvbGUgfHwgZ2V0SGVhZGVyU3RyaW5nKHJlcS5oZWFkZXJzWyd4LXVzZXItcm9sZSddKSxcbiAgfTtcbn1cblxuLyoqXG4gKiBWYWxpZGF0ZSB0aGF0IHJlcXVpcmVkIGlkZW50aXR5IGZpZWxkcyBhcmUgcHJlc2VudC5cbiAqXG4gKiBAcGFyYW0gaWRlbnRpdHkgLSBJZGVudGl0eSBvYmplY3QgdG8gdmFsaWRhdGVcbiAqIEBwYXJhbSByZXF1aXJlZCAtIEFycmF5IG9mIHJlcXVpcmVkIGZpZWxkIG5hbWVzXG4gKiBAcmV0dXJucyBPYmplY3Qgd2l0aCBpc1ZhbGlkIGJvb2xlYW4gYW5kIG1pc3NpbmcgZmllbGRzIGFycmF5XG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IGlkZW50aXR5ID0gZ2V0SWRlbnRpdHkocmVxKTtcbiAqIGNvbnN0IHZhbGlkYXRpb24gPSB2YWxpZGF0ZUlkZW50aXR5KGlkZW50aXR5LCBbJ29yZ0lkJywgJ3VzZXJJZCddKTtcbiAqXG4gKiBpZiAoIXZhbGlkYXRpb24uaXNWYWxpZCkge1xuICogICByZXR1cm4gc2VuZEVycm9yKHJlcywgNDAwLCBgTWlzc2luZyByZXF1aXJlZCBoZWFkZXJzOiAke3ZhbGlkYXRpb24ubWlzc2luZy5qb2luKCcsICcpfWApO1xuICogfVxuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB2YWxpZGF0ZUlkZW50aXR5KFxuICBpZGVudGl0eTogUmVxdWVzdElkZW50aXR5LFxuICByZXF1aXJlZDogKGtleW9mIFJlcXVlc3RJZGVudGl0eSlbXSxcbik6IHsgaXNWYWxpZDogYm9vbGVhbjsgbWlzc2luZzogc3RyaW5nW10gfSB7XG4gIGNvbnN0IG1pc3Npbmc6IHN0cmluZ1tdID0gW107XG5cbiAgZm9yIChjb25zdCBmaWVsZCBvZiByZXF1aXJlZCkge1xuICAgIGlmICghaWRlbnRpdHlbZmllbGRdKSB7XG4gICAgICBtaXNzaW5nLnB1c2goYHgtJHtmaWVsZC5yZXBsYWNlKC8oW0EtWl0pL2csICctJDEnKS50b0xvd2VyQ2FzZSgpfWApO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiB7XG4gICAgaXNWYWxpZDogbWlzc2luZy5sZW5ndGggPT09IDAsXG4gICAgbWlzc2luZyxcbiAgfTtcbn1cbiJdfQ==
@@ -0,0 +1,7 @@
1
+ export * from './logger';
2
+ export * from './response';
3
+ export * from './params';
4
+ export * from './headers';
5
+ export * from './identity';
6
+ export * from './object';
7
+ export * from './alias-resolver';
@@ -0,0 +1,26 @@
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("./logger"), exports);
20
+ __exportStar(require("./response"), exports);
21
+ __exportStar(require("./params"), exports);
22
+ __exportStar(require("./headers"), exports);
23
+ __exportStar(require("./identity"), exports);
24
+ __exportStar(require("./object"), exports);
25
+ __exportStar(require("./alias-resolver"), exports);
26
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7Ozs7Ozs7Ozs7Ozs7Ozs7QUFFdEMsMkNBQXlCO0FBQ3pCLDZDQUEyQjtBQUMzQiwyQ0FBeUI7QUFDekIsNENBQTBCO0FBQzFCLDZDQUEyQjtBQUMzQiwyQ0FBeUI7QUFDekIsbURBQWlDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmV4cG9ydCAqIGZyb20gJy4vbG9nZ2VyJztcbmV4cG9ydCAqIGZyb20gJy4vcmVzcG9uc2UnO1xuZXhwb3J0ICogZnJvbSAnLi9wYXJhbXMnO1xuZXhwb3J0ICogZnJvbSAnLi9oZWFkZXJzJztcbmV4cG9ydCAqIGZyb20gJy4vaWRlbnRpdHknO1xuZXhwb3J0ICogZnJvbSAnLi9vYmplY3QnO1xuZXhwb3J0ICogZnJvbSAnLi9hbGlhcy1yZXNvbHZlcic7XG4iXX0=
@@ -0,0 +1,28 @@
1
+ import winston from 'winston';
2
+ /**
3
+ * Create a logger instance for a service.
4
+ *
5
+ * When LOG_FORMAT=json (default), outputs structured JSON for Loki ingestion:
6
+ * {"level":"info","message":"Server started","service":"pipeline","timestamp":"..."}
7
+ *
8
+ * When LOG_FORMAT=text, outputs colorized human-readable format:
9
+ * 2026-02-13T10:30:00.000Z info [pipeline] Server started
10
+ *
11
+ * @param serviceName - Name of the service for log identification
12
+ * @returns Configured Winston logger instance
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * import { createLogger } from '@pipeline-builder/api-core';
17
+ *
18
+ * const logger = createLogger('get-plugin');
19
+ * logger.info('Server started', { port: 3000 });
20
+ * logger.error('Database error', { error: err.message });
21
+ * ```
22
+ */
23
+ export declare function createLogger(serviceName: string): winston.Logger;
24
+ /**
25
+ * Default logger instance (service name from SERVICE_NAME env var or 'api').
26
+ */
27
+ export declare const logger: winston.Logger;
28
+ export default logger;
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ // Copyright 2026 Pipeline Builder Contributors
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ var __importDefault = (this && this.__importDefault) || function (mod) {
5
+ return (mod && mod.__esModule) ? mod : { "default": mod };
6
+ };
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.logger = void 0;
9
+ exports.createLogger = createLogger;
10
+ const winston_1 = __importDefault(require("winston"));
11
+ const { combine, timestamp, printf, colorize, errors, json } = winston_1.default.format;
12
+ /**
13
+ * Custom log format for human-readable console output.
14
+ */
15
+ const consoleFormat = printf(({ level, message, timestamp, service, ...meta }) => {
16
+ const serviceName = service ? `[${service}]` : '';
17
+ const metaStr = Object.keys(meta).length ? ` ${JSON.stringify(meta)}` : '';
18
+ return `${timestamp} ${level} ${serviceName} ${message}${metaStr}`;
19
+ });
20
+ /**
21
+ * Create a logger instance for a service.
22
+ *
23
+ * When LOG_FORMAT=json (default), outputs structured JSON for Loki ingestion:
24
+ * {"level":"info","message":"Server started","service":"pipeline","timestamp":"..."}
25
+ *
26
+ * When LOG_FORMAT=text, outputs colorized human-readable format:
27
+ * 2026-02-13T10:30:00.000Z info [pipeline] Server started
28
+ *
29
+ * @param serviceName - Name of the service for log identification
30
+ * @returns Configured Winston logger instance
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * import { createLogger } from '@pipeline-builder/api-core';
35
+ *
36
+ * const logger = createLogger('get-plugin');
37
+ * logger.info('Server started', { port: 3000 });
38
+ * logger.error('Database error', { error: err.message });
39
+ * ```
40
+ */
41
+ function createLogger(serviceName) {
42
+ const logLevel = process.env.LOG_LEVEL || 'info';
43
+ const logFormat = process.env.LOG_FORMAT || 'json';
44
+ if (logFormat !== 'json' && logFormat !== 'text') {
45
+ // eslint-disable-next-line no-console -- startup warning before logger is available
46
+ console.warn(`Invalid LOG_FORMAT="${logFormat}", expected "json" or "text". Defaulting to "json".`);
47
+ }
48
+ const useJson = logFormat !== 'text';
49
+ const baseFormats = [
50
+ errors({ stack: true }),
51
+ timestamp({ format: 'YYYY-MM-DDTHH:mm:ss.SSSZ' }),
52
+ ];
53
+ if (useJson) {
54
+ return winston_1.default.createLogger({
55
+ level: logLevel,
56
+ defaultMeta: { service: serviceName },
57
+ format: combine(...baseFormats, json()),
58
+ transports: [new winston_1.default.transports.Console()],
59
+ });
60
+ }
61
+ return winston_1.default.createLogger({
62
+ level: logLevel,
63
+ defaultMeta: { service: serviceName },
64
+ format: combine(...baseFormats),
65
+ transports: [
66
+ new winston_1.default.transports.Console({
67
+ format: combine(colorize(), consoleFormat),
68
+ }),
69
+ ],
70
+ });
71
+ }
72
+ /**
73
+ * Default logger instance (service name from SERVICE_NAME env var or 'api').
74
+ */
75
+ exports.logger = createLogger(process.env.SERVICE_NAME || 'api');
76
+ exports.default = exports.logger;
77
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9nZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0aWxzL2xvZ2dlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsK0NBQStDO0FBQy9DLHNDQUFzQzs7Ozs7O0FBb0N0QyxvQ0FpQ0M7QUFuRUQsc0RBQThCO0FBRTlCLE1BQU0sRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxHQUFHLGlCQUFPLENBQUMsTUFBTSxDQUFDO0FBRTlFOztHQUVHO0FBQ0gsTUFBTSxhQUFhLEdBQUcsTUFBTSxDQUFDLENBQUMsRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLFNBQVMsRUFBRSxPQUFPLEVBQUUsR0FBRyxJQUFJLEVBQUUsRUFBRSxFQUFFO0lBQy9FLE1BQU0sV0FBVyxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUMsSUFBSSxPQUFPLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0lBQ2xELE1BQU0sT0FBTyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0lBQzNFLE9BQU8sR0FBRyxTQUFTLElBQUksS0FBSyxJQUFJLFdBQVcsSUFBSSxPQUFPLEdBQUcsT0FBTyxFQUFFLENBQUM7QUFDckUsQ0FBQyxDQUFDLENBQUM7QUFFSDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FvQkc7QUFDSCxTQUFnQixZQUFZLENBQUMsV0FBbUI7SUFDOUMsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxTQUFTLElBQUksTUFBTSxDQUFDO0lBQ2pELE1BQU0sU0FBUyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsVUFBVSxJQUFJLE1BQU0sQ0FBQztJQUNuRCxJQUFJLFNBQVMsS0FBSyxNQUFNLElBQUksU0FBUyxLQUFLLE1BQU0sRUFBRSxDQUFDO1FBQ2pELG9GQUFvRjtRQUNwRixPQUFPLENBQUMsSUFBSSxDQUFDLHVCQUF1QixTQUFTLHFEQUFxRCxDQUFDLENBQUM7SUFDdEcsQ0FBQztJQUNELE1BQU0sT0FBTyxHQUFHLFNBQVMsS0FBSyxNQUFNLENBQUM7SUFFckMsTUFBTSxXQUFXLEdBQUc7UUFDbEIsTUFBTSxDQUFDLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxDQUFDO1FBQ3ZCLFNBQVMsQ0FBQyxFQUFFLE1BQU0sRUFBRSwwQkFBMEIsRUFBRSxDQUFDO0tBQ2xELENBQUM7SUFFRixJQUFJLE9BQU8sRUFBRSxDQUFDO1FBQ1osT0FBTyxpQkFBTyxDQUFDLFlBQVksQ0FBQztZQUMxQixLQUFLLEVBQUUsUUFBUTtZQUNmLFdBQVcsRUFBRSxFQUFFLE9BQU8sRUFBRSxXQUFXLEVBQUU7WUFDckMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxHQUFHLFdBQVcsRUFBRSxJQUFJLEVBQUUsQ0FBQztZQUN2QyxVQUFVLEVBQUUsQ0FBQyxJQUFJLGlCQUFPLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxDQUFDO1NBQy9DLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRCxPQUFPLGlCQUFPLENBQUMsWUFBWSxDQUFDO1FBQzFCLEtBQUssRUFBRSxRQUFRO1FBQ2YsV0FBVyxFQUFFLEVBQUUsT0FBTyxFQUFFLFdBQVcsRUFBRTtRQUNyQyxNQUFNLEVBQUUsT0FBTyxDQUFDLEdBQUcsV0FBVyxDQUFDO1FBQy9CLFVBQVUsRUFBRTtZQUNWLElBQUksaUJBQU8sQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDO2dCQUM3QixNQUFNLEVBQUUsT0FBTyxDQUFDLFFBQVEsRUFBRSxFQUFFLGFBQWEsQ0FBQzthQUMzQyxDQUFDO1NBQ0g7S0FDRixDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQ7O0dBRUc7QUFDVSxRQUFBLE1BQU0sR0FBRyxZQUFZLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxZQUFZLElBQUksS0FBSyxDQUFDLENBQUM7QUFFdEUsa0JBQWUsY0FBTSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCB3aW5zdG9uIGZyb20gJ3dpbnN0b24nO1xuXG5jb25zdCB7IGNvbWJpbmUsIHRpbWVzdGFtcCwgcHJpbnRmLCBjb2xvcml6ZSwgZXJyb3JzLCBqc29uIH0gPSB3aW5zdG9uLmZvcm1hdDtcblxuLyoqXG4gKiBDdXN0b20gbG9nIGZvcm1hdCBmb3IgaHVtYW4tcmVhZGFibGUgY29uc29sZSBvdXRwdXQuXG4gKi9cbmNvbnN0IGNvbnNvbGVGb3JtYXQgPSBwcmludGYoKHsgbGV2ZWwsIG1lc3NhZ2UsIHRpbWVzdGFtcCwgc2VydmljZSwgLi4ubWV0YSB9KSA9PiB7XG4gIGNvbnN0IHNlcnZpY2VOYW1lID0gc2VydmljZSA/IGBbJHtzZXJ2aWNlfV1gIDogJyc7XG4gIGNvbnN0IG1ldGFTdHIgPSBPYmplY3Qua2V5cyhtZXRhKS5sZW5ndGggPyBgICR7SlNPTi5zdHJpbmdpZnkobWV0YSl9YCA6ICcnO1xuICByZXR1cm4gYCR7dGltZXN0YW1wfSAke2xldmVsfSAke3NlcnZpY2VOYW1lfSAke21lc3NhZ2V9JHttZXRhU3RyfWA7XG59KTtcblxuLyoqXG4gKiBDcmVhdGUgYSBsb2dnZXIgaW5zdGFuY2UgZm9yIGEgc2VydmljZS5cbiAqXG4gKiBXaGVuIExPR19GT1JNQVQ9anNvbiAoZGVmYXVsdCksIG91dHB1dHMgc3RydWN0dXJlZCBKU09OIGZvciBMb2tpIGluZ2VzdGlvbjpcbiAqICAge1wibGV2ZWxcIjpcImluZm9cIixcIm1lc3NhZ2VcIjpcIlNlcnZlciBzdGFydGVkXCIsXCJzZXJ2aWNlXCI6XCJwaXBlbGluZVwiLFwidGltZXN0YW1wXCI6XCIuLi5cIn1cbiAqXG4gKiBXaGVuIExPR19GT1JNQVQ9dGV4dCwgb3V0cHV0cyBjb2xvcml6ZWQgaHVtYW4tcmVhZGFibGUgZm9ybWF0OlxuICogICAyMDI2LTAyLTEzVDEwOjMwOjAwLjAwMFogaW5mbyBbcGlwZWxpbmVdIFNlcnZlciBzdGFydGVkXG4gKlxuICogQHBhcmFtIHNlcnZpY2VOYW1lIC0gTmFtZSBvZiB0aGUgc2VydmljZSBmb3IgbG9nIGlkZW50aWZpY2F0aW9uXG4gKiBAcmV0dXJucyBDb25maWd1cmVkIFdpbnN0b24gbG9nZ2VyIGluc3RhbmNlXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGltcG9ydCB7IGNyZWF0ZUxvZ2dlciB9IGZyb20gJ0BwaXBlbGluZS1idWlsZGVyL2FwaS1jb3JlJztcbiAqXG4gKiBjb25zdCBsb2dnZXIgPSBjcmVhdGVMb2dnZXIoJ2dldC1wbHVnaW4nKTtcbiAqIGxvZ2dlci5pbmZvKCdTZXJ2ZXIgc3RhcnRlZCcsIHsgcG9ydDogMzAwMCB9KTtcbiAqIGxvZ2dlci5lcnJvcignRGF0YWJhc2UgZXJyb3InLCB7IGVycm9yOiBlcnIubWVzc2FnZSB9KTtcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlTG9nZ2VyKHNlcnZpY2VOYW1lOiBzdHJpbmcpOiB3aW5zdG9uLkxvZ2dlciB7XG4gIGNvbnN0IGxvZ0xldmVsID0gcHJvY2Vzcy5lbnYuTE9HX0xFVkVMIHx8ICdpbmZvJztcbiAgY29uc3QgbG9nRm9ybWF0ID0gcHJvY2Vzcy5lbnYuTE9HX0ZPUk1BVCB8fCAnanNvbic7XG4gIGlmIChsb2dGb3JtYXQgIT09ICdqc29uJyAmJiBsb2dGb3JtYXQgIT09ICd0ZXh0Jykge1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1jb25zb2xlIC0tIHN0YXJ0dXAgd2FybmluZyBiZWZvcmUgbG9nZ2VyIGlzIGF2YWlsYWJsZVxuICAgIGNvbnNvbGUud2FybihgSW52YWxpZCBMT0dfRk9STUFUPVwiJHtsb2dGb3JtYXR9XCIsIGV4cGVjdGVkIFwianNvblwiIG9yIFwidGV4dFwiLiBEZWZhdWx0aW5nIHRvIFwianNvblwiLmApO1xuICB9XG4gIGNvbnN0IHVzZUpzb24gPSBsb2dGb3JtYXQgIT09ICd0ZXh0JztcblxuICBjb25zdCBiYXNlRm9ybWF0cyA9IFtcbiAgICBlcnJvcnMoeyBzdGFjazogdHJ1ZSB9KSxcbiAgICB0aW1lc3RhbXAoeyBmb3JtYXQ6ICdZWVlZLU1NLUREVEhIOm1tOnNzLlNTU1onIH0pLFxuICBdO1xuXG4gIGlmICh1c2VKc29uKSB7XG4gICAgcmV0dXJuIHdpbnN0b24uY3JlYXRlTG9nZ2VyKHtcbiAgICAgIGxldmVsOiBsb2dMZXZlbCxcbiAgICAgIGRlZmF1bHRNZXRhOiB7IHNlcnZpY2U6IHNlcnZpY2VOYW1lIH0sXG4gICAgICBmb3JtYXQ6IGNvbWJpbmUoLi4uYmFzZUZvcm1hdHMsIGpzb24oKSksXG4gICAgICB0cmFuc3BvcnRzOiBbbmV3IHdpbnN0b24udHJhbnNwb3J0cy5Db25zb2xlKCldLFxuICAgIH0pO1xuICB9XG5cbiAgcmV0dXJuIHdpbnN0b24uY3JlYXRlTG9nZ2VyKHtcbiAgICBsZXZlbDogbG9nTGV2ZWwsXG4gICAgZGVmYXVsdE1ldGE6IHsgc2VydmljZTogc2VydmljZU5hbWUgfSxcbiAgICBmb3JtYXQ6IGNvbWJpbmUoLi4uYmFzZUZvcm1hdHMpLFxuICAgIHRyYW5zcG9ydHM6IFtcbiAgICAgIG5ldyB3aW5zdG9uLnRyYW5zcG9ydHMuQ29uc29sZSh7XG4gICAgICAgIGZvcm1hdDogY29tYmluZShjb2xvcml6ZSgpLCBjb25zb2xlRm9ybWF0KSxcbiAgICAgIH0pLFxuICAgIF0sXG4gIH0pO1xufVxuXG4vKipcbiAqIERlZmF1bHQgbG9nZ2VyIGluc3RhbmNlIChzZXJ2aWNlIG5hbWUgZnJvbSBTRVJWSUNFX05BTUUgZW52IHZhciBvciAnYXBpJykuXG4gKi9cbmV4cG9ydCBjb25zdCBsb2dnZXIgPSBjcmVhdGVMb2dnZXIocHJvY2Vzcy5lbnYuU0VSVklDRV9OQU1FIHx8ICdhcGknKTtcblxuZXhwb3J0IGRlZmF1bHQgbG9nZ2VyO1xuIl19
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Filter an object to only include entries where the value is not `undefined`.
3
+ * Keeps `null`, `false`, `0`, and empty string — only removes `undefined`.
4
+ *
5
+ * Useful for building partial update payloads from validated request bodies.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * const body = { name: 'foo', description: undefined, isActive: false };
10
+ * pickDefined(body); // { name: 'foo', isActive: false }
11
+ * ```
12
+ */
13
+ export declare function pickDefined<T extends Record<string, unknown>>(obj: T): Partial<T>;
@@ -0,0 +1,21 @@
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.pickDefined = pickDefined;
6
+ /**
7
+ * Filter an object to only include entries where the value is not `undefined`.
8
+ * Keeps `null`, `false`, `0`, and empty string — only removes `undefined`.
9
+ *
10
+ * Useful for building partial update payloads from validated request bodies.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const body = { name: 'foo', description: undefined, isActive: false };
15
+ * pickDefined(body); // { name: 'foo', isActive: false }
16
+ * ```
17
+ */
18
+ function pickDefined(obj) {
19
+ return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== undefined));
20
+ }
21
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib2JqZWN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0aWxzL29iamVjdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsK0NBQStDO0FBQy9DLHNDQUFzQzs7QUFjdEMsa0NBSUM7QUFoQkQ7Ozs7Ozs7Ozs7O0dBV0c7QUFDSCxTQUFnQixXQUFXLENBQW9DLEdBQU07SUFDbkUsT0FBTyxNQUFNLENBQUMsV0FBVyxDQUN2QixNQUFNLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxLQUFLLFNBQVMsQ0FBQyxDQUN6QyxDQUFDO0FBQ2xCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuLyoqXG4gKiBGaWx0ZXIgYW4gb2JqZWN0IHRvIG9ubHkgaW5jbHVkZSBlbnRyaWVzIHdoZXJlIHRoZSB2YWx1ZSBpcyBub3QgYHVuZGVmaW5lZGAuXG4gKiBLZWVwcyBgbnVsbGAsIGBmYWxzZWAsIGAwYCwgYW5kIGVtcHR5IHN0cmluZyDigJQgb25seSByZW1vdmVzIGB1bmRlZmluZWRgLlxuICpcbiAqIFVzZWZ1bCBmb3IgYnVpbGRpbmcgcGFydGlhbCB1cGRhdGUgcGF5bG9hZHMgZnJvbSB2YWxpZGF0ZWQgcmVxdWVzdCBib2RpZXMuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IGJvZHkgPSB7IG5hbWU6ICdmb28nLCBkZXNjcmlwdGlvbjogdW5kZWZpbmVkLCBpc0FjdGl2ZTogZmFsc2UgfTtcbiAqIHBpY2tEZWZpbmVkKGJvZHkpOyAvLyB7IG5hbWU6ICdmb28nLCBpc0FjdGl2ZTogZmFsc2UgfVxuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwaWNrRGVmaW5lZDxUIGV4dGVuZHMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4+KG9iajogVCk6IFBhcnRpYWw8VD4ge1xuICByZXR1cm4gT2JqZWN0LmZyb21FbnRyaWVzKFxuICAgIE9iamVjdC5lbnRyaWVzKG9iaikuZmlsdGVyKChbLCB2XSkgPT4gdiAhPT0gdW5kZWZpbmVkKSxcbiAgKSBhcyBQYXJ0aWFsPFQ+O1xufVxuIl19
@@ -0,0 +1,89 @@
1
+ import { Request } from 'express';
2
+ /**
3
+ * Express 5 parameter type.
4
+ */
5
+ type ParamValue = string | string[] | undefined;
6
+ /**
7
+ * Extract a single string parameter from Express 5 route params.
8
+ *
9
+ * @param params - Request params object
10
+ * @param key - Parameter key
11
+ * @returns The parameter value as a string, or undefined if not present
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * // Route: GET /plugins/:id
16
+ * const id = getParam(req.params, 'id');
17
+ * if (!id) {
18
+ * return sendError(res, 400, 'Missing id parameter');
19
+ * }
20
+ * ```
21
+ */
22
+ export declare function getParam(params: Record<string, ParamValue>, key: string): string | undefined;
23
+ /**
24
+ * Extract the organization ID from request.
25
+ * Checks params, headers, and user object.
26
+ *
27
+ * @param req - Express request object
28
+ * @returns Organization ID or undefined
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * const orgId = getOrgId(req);
33
+ * if (!orgId) {
34
+ * return sendError(res, 400, 'Organization ID required');
35
+ * }
36
+ * ```
37
+ */
38
+ export declare function getOrgId(req: Request): string | undefined;
39
+ /**
40
+ * Get the authorization header from request.
41
+ *
42
+ * @param req - Express request object
43
+ * @returns Authorization header value or empty string
44
+ */
45
+ export declare function getAuthHeader(req: Request): string;
46
+ /**
47
+ * Parse a query parameter as a boolean.
48
+ *
49
+ * @param value - Query parameter value
50
+ * @returns Parsed boolean or undefined
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * const isActive = parseQueryBoolean(req.query.isActive);
55
+ * ```
56
+ */
57
+ export declare function parseQueryBoolean(value: unknown): boolean | undefined;
58
+ /**
59
+ * Parse a query parameter as an integer.
60
+ *
61
+ * @param value - Query parameter value
62
+ * @param defaultValue - Default value if parsing fails
63
+ * @returns Parsed integer
64
+ *
65
+ * @example
66
+ * ```typescript
67
+ * const limit = parseQueryInt(req.query.limit, 10);
68
+ * const offset = parseQueryInt(req.query.offset, 0);
69
+ * ```
70
+ */
71
+ export declare function parseQueryInt(value: unknown, defaultValue: number): number;
72
+ /**
73
+ * Parse a query parameter as a string.
74
+ *
75
+ * @param value - Query parameter value
76
+ * @returns String value or undefined
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * const search = parseQueryString(req.query.search);
81
+ * ```
82
+ */
83
+ export declare function parseQueryString(value: unknown): string | undefined;
84
+ /**
85
+ * Parse a string to a positive integer, returning a fallback if invalid.
86
+ * Useful for parsing environment variables with numeric defaults.
87
+ */
88
+ export declare function parsePositiveInt(value: string | undefined, fallback: number): number;
89
+ export {};