@pipeline-builder/api-server 3.4.78 → 3.4.80

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.
@@ -3,6 +3,7 @@ export * from './middleware-factory.js';
3
3
  export * from './context-middleware.js';
4
4
  export * from './check-quota.js';
5
5
  export * from './require-org-id.js';
6
+ export * from './tenant-context.js';
6
7
  export * from './get-context.js';
7
8
  export * from './app-factory.js';
8
9
  export * from './health-checks.js';
package/lib/api/index.js CHANGED
@@ -6,6 +6,7 @@ export * from './middleware-factory.js';
6
6
  export * from './context-middleware.js';
7
7
  export * from './check-quota.js';
8
8
  export * from './require-org-id.js';
9
+ export * from './tenant-context.js';
9
10
  export * from './get-context.js';
10
11
  // App factory
11
12
  export * from './app-factory.js';
@@ -26,4 +27,4 @@ export * from './server.js';
26
27
  export * from './route-wrapper.js';
27
28
  // Request/Response types
28
29
  export * from './request-types.js';
29
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYXBpL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEMsYUFBYTtBQUNiLGNBQWMsaUJBQWlCLENBQUM7QUFDaEMsY0FBYyx5QkFBeUIsQ0FBQztBQUN4QyxjQUFjLHlCQUF5QixDQUFDO0FBQ3hDLGNBQWMsa0JBQWtCLENBQUM7QUFDakMsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxjQUFjLGtCQUFrQixDQUFDO0FBRWpDLGNBQWM7QUFDZCxjQUFjLGtCQUFrQixDQUFDO0FBRWpDLHVCQUF1QjtBQUN2QixjQUFjLG9CQUFvQixDQUFDO0FBRW5DLDJEQUEyRDtBQUMzRCxjQUFjLG9CQUFvQixDQUFDO0FBRW5DLGdCQUFnQjtBQUNoQixjQUFjLG9CQUFvQixDQUFDO0FBRW5DLGNBQWM7QUFDZCxjQUFjLDZCQUE2QixDQUFDO0FBRTVDLGdCQUFnQjtBQUNoQixjQUFjLGNBQWMsQ0FBQztBQUM3QixjQUFjLGNBQWMsQ0FBQztBQUU3QixtQkFBbUI7QUFDbkIsY0FBYyxhQUFhLENBQUM7QUFFNUIsZ0JBQWdCO0FBQ2hCLGNBQWMsb0JBQW9CLENBQUM7QUFFbkMseUJBQXlCO0FBQ3pCLGNBQWMsb0JBQW9CLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuLy8gTWlkZGxld2FyZVxuZXhwb3J0ICogZnJvbSAnLi9taWRkbGV3YXJlLmpzJztcbmV4cG9ydCAqIGZyb20gJy4vbWlkZGxld2FyZS1mYWN0b3J5LmpzJztcbmV4cG9ydCAqIGZyb20gJy4vY29udGV4dC1taWRkbGV3YXJlLmpzJztcbmV4cG9ydCAqIGZyb20gJy4vY2hlY2stcXVvdGEuanMnO1xuZXhwb3J0ICogZnJvbSAnLi9yZXF1aXJlLW9yZy1pZC5qcyc7XG5leHBvcnQgKiBmcm9tICcuL2dldC1jb250ZXh0LmpzJztcblxuLy8gQXBwIGZhY3RvcnlcbmV4cG9ydCAqIGZyb20gJy4vYXBwLWZhY3RvcnkuanMnO1xuXG4vLyBIZWFsdGgtY2hlY2sgaGVscGVyc1xuZXhwb3J0ICogZnJvbSAnLi9oZWFsdGgtY2hlY2tzLmpzJztcblxuLy8gTW9uZ29EQiBjb25uZWN0aW9uIGhlbHBlciAoZGVwZW5kZW5jeS1pbmplY3RlZCBtb25nb29zZSlcbmV4cG9ydCAqIGZyb20gJy4vbW9uZ28tY29ubmVjdC5qcyc7XG5cbi8vIFF1b3RhIGhlbHBlcnNcbmV4cG9ydCAqIGZyb20gJy4vcXVvdGEtaGVscGVycy5qcyc7XG5cbi8vIElkZW1wb3RlbmN5XG5leHBvcnQgKiBmcm9tICcuL2lkZW1wb3RlbmN5LW1pZGRsZXdhcmUuanMnO1xuXG4vLyBPYnNlcnZhYmlsaXR5XG5leHBvcnQgKiBmcm9tICcuL3RyYWNpbmcuanMnO1xuZXhwb3J0ICogZnJvbSAnLi9tZXRyaWNzLmpzJztcblxuLy8gU2VydmVyIHV0aWxpdGllc1xuZXhwb3J0ICogZnJvbSAnLi9zZXJ2ZXIuanMnO1xuXG4vLyBSb3V0ZSB3cmFwcGVyXG5leHBvcnQgKiBmcm9tICcuL3JvdXRlLXdyYXBwZXIuanMnO1xuXG4vLyBSZXF1ZXN0L1Jlc3BvbnNlIHR5cGVzXG5leHBvcnQgKiBmcm9tICcuL3JlcXVlc3QtdHlwZXMuanMnO1xuIl19
30
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYXBpL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEMsYUFBYTtBQUNiLGNBQWMsaUJBQWlCLENBQUM7QUFDaEMsY0FBYyx5QkFBeUIsQ0FBQztBQUN4QyxjQUFjLHlCQUF5QixDQUFDO0FBQ3hDLGNBQWMsa0JBQWtCLENBQUM7QUFDakMsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxjQUFjLHFCQUFxQixDQUFDO0FBQ3BDLGNBQWMsa0JBQWtCLENBQUM7QUFFakMsY0FBYztBQUNkLGNBQWMsa0JBQWtCLENBQUM7QUFFakMsdUJBQXVCO0FBQ3ZCLGNBQWMsb0JBQW9CLENBQUM7QUFFbkMsMkRBQTJEO0FBQzNELGNBQWMsb0JBQW9CLENBQUM7QUFFbkMsZ0JBQWdCO0FBQ2hCLGNBQWMsb0JBQW9CLENBQUM7QUFFbkMsY0FBYztBQUNkLGNBQWMsNkJBQTZCLENBQUM7QUFFNUMsZ0JBQWdCO0FBQ2hCLGNBQWMsY0FBYyxDQUFDO0FBQzdCLGNBQWMsY0FBYyxDQUFDO0FBRTdCLG1CQUFtQjtBQUNuQixjQUFjLGFBQWEsQ0FBQztBQUU1QixnQkFBZ0I7QUFDaEIsY0FBYyxvQkFBb0IsQ0FBQztBQUVuQyx5QkFBeUI7QUFDekIsY0FBYyxvQkFBb0IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG4vLyBNaWRkbGV3YXJlXG5leHBvcnQgKiBmcm9tICcuL21pZGRsZXdhcmUuanMnO1xuZXhwb3J0ICogZnJvbSAnLi9taWRkbGV3YXJlLWZhY3RvcnkuanMnO1xuZXhwb3J0ICogZnJvbSAnLi9jb250ZXh0LW1pZGRsZXdhcmUuanMnO1xuZXhwb3J0ICogZnJvbSAnLi9jaGVjay1xdW90YS5qcyc7XG5leHBvcnQgKiBmcm9tICcuL3JlcXVpcmUtb3JnLWlkLmpzJztcbmV4cG9ydCAqIGZyb20gJy4vdGVuYW50LWNvbnRleHQuanMnO1xuZXhwb3J0ICogZnJvbSAnLi9nZXQtY29udGV4dC5qcyc7XG5cbi8vIEFwcCBmYWN0b3J5XG5leHBvcnQgKiBmcm9tICcuL2FwcC1mYWN0b3J5LmpzJztcblxuLy8gSGVhbHRoLWNoZWNrIGhlbHBlcnNcbmV4cG9ydCAqIGZyb20gJy4vaGVhbHRoLWNoZWNrcy5qcyc7XG5cbi8vIE1vbmdvREIgY29ubmVjdGlvbiBoZWxwZXIgKGRlcGVuZGVuY3ktaW5qZWN0ZWQgbW9uZ29vc2UpXG5leHBvcnQgKiBmcm9tICcuL21vbmdvLWNvbm5lY3QuanMnO1xuXG4vLyBRdW90YSBoZWxwZXJzXG5leHBvcnQgKiBmcm9tICcuL3F1b3RhLWhlbHBlcnMuanMnO1xuXG4vLyBJZGVtcG90ZW5jeVxuZXhwb3J0ICogZnJvbSAnLi9pZGVtcG90ZW5jeS1taWRkbGV3YXJlLmpzJztcblxuLy8gT2JzZXJ2YWJpbGl0eVxuZXhwb3J0ICogZnJvbSAnLi90cmFjaW5nLmpzJztcbmV4cG9ydCAqIGZyb20gJy4vbWV0cmljcy5qcyc7XG5cbi8vIFNlcnZlciB1dGlsaXRpZXNcbmV4cG9ydCAqIGZyb20gJy4vc2VydmVyLmpzJztcblxuLy8gUm91dGUgd3JhcHBlclxuZXhwb3J0ICogZnJvbSAnLi9yb3V0ZS13cmFwcGVyLmpzJztcblxuLy8gUmVxdWVzdC9SZXNwb25zZSB0eXBlc1xuZXhwb3J0ICogZnJvbSAnLi9yZXF1ZXN0LXR5cGVzLmpzJztcbiJdfQ==
@@ -6,7 +6,8 @@ import type { RequestHandler } from 'express';
6
6
  * Applies middleware in order:
7
7
  * 1. requireAuth - Validates JWT and extracts user identity
8
8
  * 2. requireOrgId - Ensures request has x-org-id header
9
- * 3. checkQuota - Validates quota for the specified resource type
9
+ * 3. withTenantContext - Opens the RLS tenant scope (orgId + isSuperAdmin) for the request
10
+ * 4. checkQuota - Validates quota for the specified resource type
10
11
  *
11
12
  * @param quotaService - Quota service client
12
13
  * @param quotaType - Which quota to check (e.g., 'apiCalls', 'pipelines', 'plugins')
@@ -29,6 +30,7 @@ export declare function createProtectedRoute(quotaService: QuotaService, quotaTy
29
30
  * Applies middleware in order:
30
31
  * 1. requireAuth - Validates JWT and extracts user identity
31
32
  * 2. requireOrgId - Ensures request has x-org-id header
33
+ * 3. withTenantContext - Opens the RLS tenant scope (orgId + isSuperAdmin) for the request
32
34
  *
33
35
  * Use this for read-only routes that don't consume quota.
34
36
  *
@@ -3,13 +3,15 @@
3
3
  import { checkQuota } from './check-quota.js';
4
4
  import { requireAuth } from './middleware.js';
5
5
  import { requireOrgId } from './require-org-id.js';
6
+ import { withTenantContext } from './tenant-context.js';
6
7
  /**
7
8
  * Creates a middleware chain for protected routes requiring authentication, org ID, and quota check.
8
9
  *
9
10
  * Applies middleware in order:
10
11
  * 1. requireAuth - Validates JWT and extracts user identity
11
12
  * 2. requireOrgId - Ensures request has x-org-id header
12
- * 3. checkQuota - Validates quota for the specified resource type
13
+ * 3. withTenantContext - Opens the RLS tenant scope (orgId + isSuperAdmin) for the request
14
+ * 4. checkQuota - Validates quota for the specified resource type
13
15
  *
14
16
  * @param quotaService - Quota service client
15
17
  * @param quotaType - Which quota to check (e.g., 'apiCalls', 'pipelines', 'plugins')
@@ -29,6 +31,7 @@ export function createProtectedRoute(quotaService, quotaType) {
29
31
  return [
30
32
  requireAuth,
31
33
  requireOrgId(),
34
+ withTenantContext(),
32
35
  checkQuota(quotaService, quotaType),
33
36
  ];
34
37
  }
@@ -38,6 +41,7 @@ export function createProtectedRoute(quotaService, quotaType) {
38
41
  * Applies middleware in order:
39
42
  * 1. requireAuth - Validates JWT and extracts user identity
40
43
  * 2. requireOrgId - Ensures request has x-org-id header
44
+ * 3. withTenantContext - Opens the RLS tenant scope (orgId + isSuperAdmin) for the request
41
45
  *
42
46
  * Use this for read-only routes that don't consume quota.
43
47
  *
@@ -57,6 +61,7 @@ export function createAuthenticatedWithOrgRoute() {
57
61
  return [
58
62
  requireAuth,
59
63
  requireOrgId(),
64
+ withTenantContext(),
60
65
  ];
61
66
  }
62
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWlkZGxld2FyZS1mYWN0b3J5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FwaS9taWRkbGV3YXJlLWZhY3RvcnkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUl0QyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDOUMsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQzlDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUVuRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBcUJHO0FBQ0gsTUFBTSxVQUFVLG9CQUFvQixDQUNsQyxZQUEwQixFQUMxQixTQUFvQjtJQUVwQixPQUFPO1FBQ0wsV0FBNkI7UUFDN0IsWUFBWSxFQUFvQjtRQUNoQyxVQUFVLENBQUMsWUFBWSxFQUFFLFNBQVMsQ0FBbUI7S0FDdEQsQ0FBQztBQUNKLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FvQkc7QUFDSCxNQUFNLFVBQVUsK0JBQStCO0lBQzdDLE9BQU87UUFDTCxXQUE2QjtRQUM3QixZQUFZLEVBQW9CO0tBQ2pDLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCB0eXBlIHsgUXVvdGFUeXBlLCBRdW90YVNlcnZpY2UgfSBmcm9tICdAcGlwZWxpbmUtYnVpbGRlci9hcGktY29yZSc7XG5pbXBvcnQgdHlwZSB7IFJlcXVlc3RIYW5kbGVyIH0gZnJvbSAnZXhwcmVzcyc7XG5pbXBvcnQgeyBjaGVja1F1b3RhIH0gZnJvbSAnLi9jaGVjay1xdW90YS5qcyc7XG5pbXBvcnQgeyByZXF1aXJlQXV0aCB9IGZyb20gJy4vbWlkZGxld2FyZS5qcyc7XG5pbXBvcnQgeyByZXF1aXJlT3JnSWQgfSBmcm9tICcuL3JlcXVpcmUtb3JnLWlkLmpzJztcblxuLyoqXG4gKiBDcmVhdGVzIGEgbWlkZGxld2FyZSBjaGFpbiBmb3IgcHJvdGVjdGVkIHJvdXRlcyByZXF1aXJpbmcgYXV0aGVudGljYXRpb24sIG9yZyBJRCwgYW5kIHF1b3RhIGNoZWNrLlxuICpcbiAqIEFwcGxpZXMgbWlkZGxld2FyZSBpbiBvcmRlcjpcbiAqIDEuIHJlcXVpcmVBdXRoIC0gVmFsaWRhdGVzIEpXVCBhbmQgZXh0cmFjdHMgdXNlciBpZGVudGl0eVxuICogMi4gcmVxdWlyZU9yZ0lkIC0gRW5zdXJlcyByZXF1ZXN0IGhhcyB4LW9yZy1pZCBoZWFkZXJcbiAqIDMuIGNoZWNrUXVvdGEgLSBWYWxpZGF0ZXMgcXVvdGEgZm9yIHRoZSBzcGVjaWZpZWQgcmVzb3VyY2UgdHlwZVxuICpcbiAqIEBwYXJhbSBxdW90YVNlcnZpY2UgLSBRdW90YSBzZXJ2aWNlIGNsaWVudFxuICogQHBhcmFtIHF1b3RhVHlwZSAtIFdoaWNoIHF1b3RhIHRvIGNoZWNrIChlLmcuLCAnYXBpQ2FsbHMnLCAncGlwZWxpbmVzJywgJ3BsdWdpbnMnKVxuICogQHJldHVybnMgQXJyYXkgb2YgbWlkZGxld2FyZSBoYW5kbGVycyByZWFkeSB0byBzcHJlYWQgaW50byByb3V0ZSBkZWZpbml0aW9uXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIHJvdXRlci5wb3N0KCcvJyxcbiAqICAgLi4uY3JlYXRlUHJvdGVjdGVkUm91dGUocXVvdGFTZXJ2aWNlLCAncGlwZWxpbmVzJyksXG4gKiAgIGFzeW5jIChyZXEsIHJlcykgPT4ge1xuICogICAgIC8vIEhhbmRsZXIgaW1wbGVtZW50YXRpb25cbiAqICAgfVxuICogKTtcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlUHJvdGVjdGVkUm91dGUoXG4gIHF1b3RhU2VydmljZTogUXVvdGFTZXJ2aWNlLFxuICBxdW90YVR5cGU6IFF1b3RhVHlwZSxcbik6IFJlcXVlc3RIYW5kbGVyW10ge1xuICByZXR1cm4gW1xuICAgIHJlcXVpcmVBdXRoIGFzIFJlcXVlc3RIYW5kbGVyLFxuICAgIHJlcXVpcmVPcmdJZCgpIGFzIFJlcXVlc3RIYW5kbGVyLFxuICAgIGNoZWNrUXVvdGEocXVvdGFTZXJ2aWNlLCBxdW90YVR5cGUpIGFzIFJlcXVlc3RIYW5kbGVyLFxuICBdO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgYSBtaWRkbGV3YXJlIGNoYWluIGZvciBhdXRoZW50aWNhdGVkIHJvdXRlcyB3aXRoIG9yZyBJRCByZXF1aXJlbWVudCBidXQgbm8gcXVvdGEgY2hlY2suXG4gKlxuICogQXBwbGllcyBtaWRkbGV3YXJlIGluIG9yZGVyOlxuICogMS4gcmVxdWlyZUF1dGggLSBWYWxpZGF0ZXMgSldUIGFuZCBleHRyYWN0cyB1c2VyIGlkZW50aXR5XG4gKiAyLiByZXF1aXJlT3JnSWQgLSBFbnN1cmVzIHJlcXVlc3QgaGFzIHgtb3JnLWlkIGhlYWRlclxuICpcbiAqIFVzZSB0aGlzIGZvciByZWFkLW9ubHkgcm91dGVzIHRoYXQgZG9uJ3QgY29uc3VtZSBxdW90YS5cbiAqXG4gKiBAcmV0dXJucyBBcnJheSBvZiBtaWRkbGV3YXJlIGhhbmRsZXJzIHJlYWR5IHRvIHNwcmVhZCBpbnRvIHJvdXRlIGRlZmluaXRpb25cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogcm91dGVyLmdldCgnLycsXG4gKiAgIC4uLmNyZWF0ZUF1dGhlbnRpY2F0ZWRXaXRoT3JnUm91dGUoKSxcbiAqICAgYXN5bmMgKHJlcSwgcmVzKSA9PiB7XG4gKiAgICAgLy8gSGFuZGxlciBpbXBsZW1lbnRhdGlvblxuICogICB9XG4gKiApO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVBdXRoZW50aWNhdGVkV2l0aE9yZ1JvdXRlKCk6IFJlcXVlc3RIYW5kbGVyW10ge1xuICByZXR1cm4gW1xuICAgIHJlcXVpcmVBdXRoIGFzIFJlcXVlc3RIYW5kbGVyLFxuICAgIHJlcXVpcmVPcmdJZCgpIGFzIFJlcXVlc3RIYW5kbGVyLFxuICBdO1xufVxuIl19
67
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWlkZGxld2FyZS1mYWN0b3J5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FwaS9taWRkbGV3YXJlLWZhY3RvcnkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUl0QyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDOUMsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQzlDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUNuRCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUV4RDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXNCRztBQUNILE1BQU0sVUFBVSxvQkFBb0IsQ0FDbEMsWUFBMEIsRUFDMUIsU0FBb0I7SUFFcEIsT0FBTztRQUNMLFdBQTZCO1FBQzdCLFlBQVksRUFBb0I7UUFDaEMsaUJBQWlCLEVBQW9CO1FBQ3JDLFVBQVUsQ0FBQyxZQUFZLEVBQUUsU0FBUyxDQUFtQjtLQUN0RCxDQUFDO0FBQ0osQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FxQkc7QUFDSCxNQUFNLFVBQVUsK0JBQStCO0lBQzdDLE9BQU87UUFDTCxXQUE2QjtRQUM3QixZQUFZLEVBQW9CO1FBQ2hDLGlCQUFpQixFQUFvQjtLQUN0QyxDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgdHlwZSB7IFF1b3RhVHlwZSwgUXVvdGFTZXJ2aWNlIH0gZnJvbSAnQHBpcGVsaW5lLWJ1aWxkZXIvYXBpLWNvcmUnO1xuaW1wb3J0IHR5cGUgeyBSZXF1ZXN0SGFuZGxlciB9IGZyb20gJ2V4cHJlc3MnO1xuaW1wb3J0IHsgY2hlY2tRdW90YSB9IGZyb20gJy4vY2hlY2stcXVvdGEuanMnO1xuaW1wb3J0IHsgcmVxdWlyZUF1dGggfSBmcm9tICcuL21pZGRsZXdhcmUuanMnO1xuaW1wb3J0IHsgcmVxdWlyZU9yZ0lkIH0gZnJvbSAnLi9yZXF1aXJlLW9yZy1pZC5qcyc7XG5pbXBvcnQgeyB3aXRoVGVuYW50Q29udGV4dCB9IGZyb20gJy4vdGVuYW50LWNvbnRleHQuanMnO1xuXG4vKipcbiAqIENyZWF0ZXMgYSBtaWRkbGV3YXJlIGNoYWluIGZvciBwcm90ZWN0ZWQgcm91dGVzIHJlcXVpcmluZyBhdXRoZW50aWNhdGlvbiwgb3JnIElELCBhbmQgcXVvdGEgY2hlY2suXG4gKlxuICogQXBwbGllcyBtaWRkbGV3YXJlIGluIG9yZGVyOlxuICogMS4gcmVxdWlyZUF1dGggLSBWYWxpZGF0ZXMgSldUIGFuZCBleHRyYWN0cyB1c2VyIGlkZW50aXR5XG4gKiAyLiByZXF1aXJlT3JnSWQgLSBFbnN1cmVzIHJlcXVlc3QgaGFzIHgtb3JnLWlkIGhlYWRlclxuICogMy4gd2l0aFRlbmFudENvbnRleHQgLSBPcGVucyB0aGUgUkxTIHRlbmFudCBzY29wZSAob3JnSWQgKyBpc1N1cGVyQWRtaW4pIGZvciB0aGUgcmVxdWVzdFxuICogNC4gY2hlY2tRdW90YSAtIFZhbGlkYXRlcyBxdW90YSBmb3IgdGhlIHNwZWNpZmllZCByZXNvdXJjZSB0eXBlXG4gKlxuICogQHBhcmFtIHF1b3RhU2VydmljZSAtIFF1b3RhIHNlcnZpY2UgY2xpZW50XG4gKiBAcGFyYW0gcXVvdGFUeXBlIC0gV2hpY2ggcXVvdGEgdG8gY2hlY2sgKGUuZy4sICdhcGlDYWxscycsICdwaXBlbGluZXMnLCAncGx1Z2lucycpXG4gKiBAcmV0dXJucyBBcnJheSBvZiBtaWRkbGV3YXJlIGhhbmRsZXJzIHJlYWR5IHRvIHNwcmVhZCBpbnRvIHJvdXRlIGRlZmluaXRpb25cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogcm91dGVyLnBvc3QoJy8nLFxuICogICAuLi5jcmVhdGVQcm90ZWN0ZWRSb3V0ZShxdW90YVNlcnZpY2UsICdwaXBlbGluZXMnKSxcbiAqICAgYXN5bmMgKHJlcSwgcmVzKSA9PiB7XG4gKiAgICAgLy8gSGFuZGxlciBpbXBsZW1lbnRhdGlvblxuICogICB9XG4gKiApO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVQcm90ZWN0ZWRSb3V0ZShcbiAgcXVvdGFTZXJ2aWNlOiBRdW90YVNlcnZpY2UsXG4gIHF1b3RhVHlwZTogUXVvdGFUeXBlLFxuKTogUmVxdWVzdEhhbmRsZXJbXSB7XG4gIHJldHVybiBbXG4gICAgcmVxdWlyZUF1dGggYXMgUmVxdWVzdEhhbmRsZXIsXG4gICAgcmVxdWlyZU9yZ0lkKCkgYXMgUmVxdWVzdEhhbmRsZXIsXG4gICAgd2l0aFRlbmFudENvbnRleHQoKSBhcyBSZXF1ZXN0SGFuZGxlcixcbiAgICBjaGVja1F1b3RhKHF1b3RhU2VydmljZSwgcXVvdGFUeXBlKSBhcyBSZXF1ZXN0SGFuZGxlcixcbiAgXTtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgbWlkZGxld2FyZSBjaGFpbiBmb3IgYXV0aGVudGljYXRlZCByb3V0ZXMgd2l0aCBvcmcgSUQgcmVxdWlyZW1lbnQgYnV0IG5vIHF1b3RhIGNoZWNrLlxuICpcbiAqIEFwcGxpZXMgbWlkZGxld2FyZSBpbiBvcmRlcjpcbiAqIDEuIHJlcXVpcmVBdXRoIC0gVmFsaWRhdGVzIEpXVCBhbmQgZXh0cmFjdHMgdXNlciBpZGVudGl0eVxuICogMi4gcmVxdWlyZU9yZ0lkIC0gRW5zdXJlcyByZXF1ZXN0IGhhcyB4LW9yZy1pZCBoZWFkZXJcbiAqIDMuIHdpdGhUZW5hbnRDb250ZXh0IC0gT3BlbnMgdGhlIFJMUyB0ZW5hbnQgc2NvcGUgKG9yZ0lkICsgaXNTdXBlckFkbWluKSBmb3IgdGhlIHJlcXVlc3RcbiAqXG4gKiBVc2UgdGhpcyBmb3IgcmVhZC1vbmx5IHJvdXRlcyB0aGF0IGRvbid0IGNvbnN1bWUgcXVvdGEuXG4gKlxuICogQHJldHVybnMgQXJyYXkgb2YgbWlkZGxld2FyZSBoYW5kbGVycyByZWFkeSB0byBzcHJlYWQgaW50byByb3V0ZSBkZWZpbml0aW9uXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIHJvdXRlci5nZXQoJy8nLFxuICogICAuLi5jcmVhdGVBdXRoZW50aWNhdGVkV2l0aE9yZ1JvdXRlKCksXG4gKiAgIGFzeW5jIChyZXEsIHJlcykgPT4ge1xuICogICAgIC8vIEhhbmRsZXIgaW1wbGVtZW50YXRpb25cbiAqICAgfVxuICogKTtcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlQXV0aGVudGljYXRlZFdpdGhPcmdSb3V0ZSgpOiBSZXF1ZXN0SGFuZGxlcltdIHtcbiAgcmV0dXJuIFtcbiAgICByZXF1aXJlQXV0aCBhcyBSZXF1ZXN0SGFuZGxlcixcbiAgICByZXF1aXJlT3JnSWQoKSBhcyBSZXF1ZXN0SGFuZGxlcixcbiAgICB3aXRoVGVuYW50Q29udGV4dCgpIGFzIFJlcXVlc3RIYW5kbGVyLFxuICBdO1xufVxuIl19
@@ -0,0 +1,27 @@
1
+ import { type TenantContext } from '@pipeline-builder/pipeline-core';
2
+ import type { Request, Response, NextFunction } from 'express';
3
+ /**
4
+ * Resolves the RLS tenant scope for a request. The default reads the CALLER's
5
+ * authenticated identity org (`ctx.identity.orgId`, validated by requireOrgId) — NOT
6
+ * `getOrgId(req)`, which prefers route params (the queried scope), the wrong tenant for
7
+ * RLS. Services with a different request boundary supply their own resolver (e.g. platform
8
+ * sets the scope pre-auth from an unverified JWT peek so unauthenticated endpoints still
9
+ * get a sane default).
10
+ */
11
+ export type TenantScopeResolver = (req: Request) => TenantContext;
12
+ /**
13
+ * Establish the request's row-level-security tenant scope.
14
+ *
15
+ * Runs the rest of the request inside `runWithTenantContext({ orgId, isSuperAdmin })` (an
16
+ * AsyncLocalStorage scope) so every `withTenantTx` query downstream can `SET LOCAL` the
17
+ * Postgres GUCs that RLS policies read. Without this, reads against FORCE-RLS tables (e.g.
18
+ * `plugins`, `pipelines`) run with empty GUCs and silently return no rows — the "set once
19
+ * at the request boundary" bookend the RLS enforcement plan calls for.
20
+ *
21
+ * Default placement is AFTER `requireAuth` + `requireOrgId` (the route factories do this);
22
+ * pass a custom `resolve` for a different boundary. If the resolver throws (e.g. the request
23
+ * context was never attached because `attachRequestContext` is missing), we fail OPEN —
24
+ * proceed without a scope rather than 500. Empty GUCs HIDE rows (never expose them), so
25
+ * this degrades safely.
26
+ */
27
+ export declare function withTenantContext(resolve?: TenantScopeResolver): (req: Request, _res: Response, next: NextFunction) => void;
@@ -0,0 +1,39 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { isSystemAdmin } from '@pipeline-builder/api-core';
4
+ import { runWithTenantContext } from '@pipeline-builder/pipeline-core';
5
+ import { getContext } from './get-context.js';
6
+ /** Default resolver: the authenticated identity's org + super-admin flag. */
7
+ const identityScope = (req) => ({
8
+ orgId: getContext(req).identity.orgId,
9
+ isSuperAdmin: isSystemAdmin(req),
10
+ });
11
+ /**
12
+ * Establish the request's row-level-security tenant scope.
13
+ *
14
+ * Runs the rest of the request inside `runWithTenantContext({ orgId, isSuperAdmin })` (an
15
+ * AsyncLocalStorage scope) so every `withTenantTx` query downstream can `SET LOCAL` the
16
+ * Postgres GUCs that RLS policies read. Without this, reads against FORCE-RLS tables (e.g.
17
+ * `plugins`, `pipelines`) run with empty GUCs and silently return no rows — the "set once
18
+ * at the request boundary" bookend the RLS enforcement plan calls for.
19
+ *
20
+ * Default placement is AFTER `requireAuth` + `requireOrgId` (the route factories do this);
21
+ * pass a custom `resolve` for a different boundary. If the resolver throws (e.g. the request
22
+ * context was never attached because `attachRequestContext` is missing), we fail OPEN —
23
+ * proceed without a scope rather than 500. Empty GUCs HIDE rows (never expose them), so
24
+ * this degrades safely.
25
+ */
26
+ export function withTenantContext(resolve = identityScope) {
27
+ return (req, _res, next) => {
28
+ let scope;
29
+ try {
30
+ scope = resolve(req);
31
+ }
32
+ catch {
33
+ next();
34
+ return;
35
+ }
36
+ runWithTenantContext(scope, () => next());
37
+ };
38
+ }
39
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVuYW50LWNvbnRleHQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYXBpL3RlbmFudC1jb250ZXh0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQzNELE9BQU8sRUFBRSxvQkFBb0IsRUFBc0IsTUFBTSxpQ0FBaUMsQ0FBQztBQUUzRixPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFZOUMsNkVBQTZFO0FBQzdFLE1BQU0sYUFBYSxHQUF3QixDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUNuRCxLQUFLLEVBQUUsVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxLQUFLO0lBQ3JDLFlBQVksRUFBRSxhQUFhLENBQUMsR0FBRyxDQUFDO0NBQ2pDLENBQUMsQ0FBQztBQUVIOzs7Ozs7Ozs7Ozs7OztHQWNHO0FBQ0gsTUFBTSxVQUFVLGlCQUFpQixDQUFDLFVBQStCLGFBQWE7SUFDNUUsT0FBTyxDQUFDLEdBQVksRUFBRSxJQUFjLEVBQUUsSUFBa0IsRUFBUSxFQUFFO1FBQ2hFLElBQUksS0FBb0IsQ0FBQztRQUN6QixJQUFJLENBQUM7WUFDSCxLQUFLLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3ZCLENBQUM7UUFBQyxNQUFNLENBQUM7WUFDUCxJQUFJLEVBQUUsQ0FBQztZQUNQLE9BQU87UUFDVCxDQUFDO1FBQ0Qsb0JBQW9CLENBQUMsS0FBSyxFQUFFLEdBQUcsRUFBRSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7SUFDNUMsQ0FBQyxDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgeyBpc1N5c3RlbUFkbWluIH0gZnJvbSAnQHBpcGVsaW5lLWJ1aWxkZXIvYXBpLWNvcmUnO1xuaW1wb3J0IHsgcnVuV2l0aFRlbmFudENvbnRleHQsIHR5cGUgVGVuYW50Q29udGV4dCB9IGZyb20gJ0BwaXBlbGluZS1idWlsZGVyL3BpcGVsaW5lLWNvcmUnO1xuaW1wb3J0IHR5cGUgeyBSZXF1ZXN0LCBSZXNwb25zZSwgTmV4dEZ1bmN0aW9uIH0gZnJvbSAnZXhwcmVzcyc7XG5pbXBvcnQgeyBnZXRDb250ZXh0IH0gZnJvbSAnLi9nZXQtY29udGV4dC5qcyc7XG5cbi8qKlxuICogUmVzb2x2ZXMgdGhlIFJMUyB0ZW5hbnQgc2NvcGUgZm9yIGEgcmVxdWVzdC4gVGhlIGRlZmF1bHQgcmVhZHMgdGhlIENBTExFUidzXG4gKiBhdXRoZW50aWNhdGVkIGlkZW50aXR5IG9yZyAoYGN0eC5pZGVudGl0eS5vcmdJZGAsIHZhbGlkYXRlZCBieSByZXF1aXJlT3JnSWQpIOKAlCBOT1RcbiAqIGBnZXRPcmdJZChyZXEpYCwgd2hpY2ggcHJlZmVycyByb3V0ZSBwYXJhbXMgKHRoZSBxdWVyaWVkIHNjb3BlKSwgdGhlIHdyb25nIHRlbmFudCBmb3JcbiAqIFJMUy4gU2VydmljZXMgd2l0aCBhIGRpZmZlcmVudCByZXF1ZXN0IGJvdW5kYXJ5IHN1cHBseSB0aGVpciBvd24gcmVzb2x2ZXIgKGUuZy4gcGxhdGZvcm1cbiAqIHNldHMgdGhlIHNjb3BlIHByZS1hdXRoIGZyb20gYW4gdW52ZXJpZmllZCBKV1QgcGVlayBzbyB1bmF1dGhlbnRpY2F0ZWQgZW5kcG9pbnRzIHN0aWxsXG4gKiBnZXQgYSBzYW5lIGRlZmF1bHQpLlxuICovXG5leHBvcnQgdHlwZSBUZW5hbnRTY29wZVJlc29sdmVyID0gKHJlcTogUmVxdWVzdCkgPT4gVGVuYW50Q29udGV4dDtcblxuLyoqIERlZmF1bHQgcmVzb2x2ZXI6IHRoZSBhdXRoZW50aWNhdGVkIGlkZW50aXR5J3Mgb3JnICsgc3VwZXItYWRtaW4gZmxhZy4gKi9cbmNvbnN0IGlkZW50aXR5U2NvcGU6IFRlbmFudFNjb3BlUmVzb2x2ZXIgPSAocmVxKSA9PiAoe1xuICBvcmdJZDogZ2V0Q29udGV4dChyZXEpLmlkZW50aXR5Lm9yZ0lkLFxuICBpc1N1cGVyQWRtaW46IGlzU3lzdGVtQWRtaW4ocmVxKSxcbn0pO1xuXG4vKipcbiAqIEVzdGFibGlzaCB0aGUgcmVxdWVzdCdzIHJvdy1sZXZlbC1zZWN1cml0eSB0ZW5hbnQgc2NvcGUuXG4gKlxuICogUnVucyB0aGUgcmVzdCBvZiB0aGUgcmVxdWVzdCBpbnNpZGUgYHJ1bldpdGhUZW5hbnRDb250ZXh0KHsgb3JnSWQsIGlzU3VwZXJBZG1pbiB9KWAgKGFuXG4gKiBBc3luY0xvY2FsU3RvcmFnZSBzY29wZSkgc28gZXZlcnkgYHdpdGhUZW5hbnRUeGAgcXVlcnkgZG93bnN0cmVhbSBjYW4gYFNFVCBMT0NBTGAgdGhlXG4gKiBQb3N0Z3JlcyBHVUNzIHRoYXQgUkxTIHBvbGljaWVzIHJlYWQuIFdpdGhvdXQgdGhpcywgcmVhZHMgYWdhaW5zdCBGT1JDRS1STFMgdGFibGVzIChlLmcuXG4gKiBgcGx1Z2luc2AsIGBwaXBlbGluZXNgKSBydW4gd2l0aCBlbXB0eSBHVUNzIGFuZCBzaWxlbnRseSByZXR1cm4gbm8gcm93cyDigJQgdGhlIFwic2V0IG9uY2VcbiAqIGF0IHRoZSByZXF1ZXN0IGJvdW5kYXJ5XCIgYm9va2VuZCB0aGUgUkxTIGVuZm9yY2VtZW50IHBsYW4gY2FsbHMgZm9yLlxuICpcbiAqIERlZmF1bHQgcGxhY2VtZW50IGlzIEFGVEVSIGByZXF1aXJlQXV0aGAgKyBgcmVxdWlyZU9yZ0lkYCAodGhlIHJvdXRlIGZhY3RvcmllcyBkbyB0aGlzKTtcbiAqIHBhc3MgYSBjdXN0b20gYHJlc29sdmVgIGZvciBhIGRpZmZlcmVudCBib3VuZGFyeS4gSWYgdGhlIHJlc29sdmVyIHRocm93cyAoZS5nLiB0aGUgcmVxdWVzdFxuICogY29udGV4dCB3YXMgbmV2ZXIgYXR0YWNoZWQgYmVjYXVzZSBgYXR0YWNoUmVxdWVzdENvbnRleHRgIGlzIG1pc3NpbmcpLCB3ZSBmYWlsIE9QRU4g4oCUXG4gKiBwcm9jZWVkIHdpdGhvdXQgYSBzY29wZSByYXRoZXIgdGhhbiA1MDAuIEVtcHR5IEdVQ3MgSElERSByb3dzIChuZXZlciBleHBvc2UgdGhlbSksIHNvXG4gKiB0aGlzIGRlZ3JhZGVzIHNhZmVseS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHdpdGhUZW5hbnRDb250ZXh0KHJlc29sdmU6IFRlbmFudFNjb3BlUmVzb2x2ZXIgPSBpZGVudGl0eVNjb3BlKSB7XG4gIHJldHVybiAocmVxOiBSZXF1ZXN0LCBfcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKTogdm9pZCA9PiB7XG4gICAgbGV0IHNjb3BlOiBUZW5hbnRDb250ZXh0O1xuICAgIHRyeSB7XG4gICAgICBzY29wZSA9IHJlc29sdmUocmVxKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIG5leHQoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgcnVuV2l0aFRlbmFudENvbnRleHQoc2NvcGUsICgpID0+IG5leHQoKSk7XG4gIH07XG59XG4iXX0=
package/package.json CHANGED
@@ -44,7 +44,7 @@
44
44
  "swagger-ui-express": "5.0.1",
45
45
  "uuid": "14.0.0",
46
46
  "@pipeline-builder/api-core": "3.4.70",
47
- "@pipeline-builder/pipeline-core": "3.4.76"
47
+ "@pipeline-builder/pipeline-core": "3.4.77"
48
48
  },
49
49
  "keywords": [
50
50
  "aws",
@@ -88,7 +88,7 @@
88
88
  "access": "public",
89
89
  "registry": "https://registry.npmjs.org/"
90
90
  },
91
- "version": "3.4.78",
91
+ "version": "3.4.80",
92
92
  "bugs": {
93
93
  "url": "https://github.com/mwashburn160/pipeline-builder/issues"
94
94
  },