@pipeline-builder/pipeline-data 0.0.1

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 (48) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +61 -0
  3. package/drizzle.config.ts +17 -0
  4. package/lib/api/access-control-builder.d.ts +148 -0
  5. package/lib/api/access-control-builder.js +199 -0
  6. package/lib/api/crud-service.d.ts +343 -0
  7. package/lib/api/crud-service.js +849 -0
  8. package/lib/api/query-builders.d.ts +82 -0
  9. package/lib/api/query-builders.js +460 -0
  10. package/lib/api/reporting-service.d.ts +685 -0
  11. package/lib/api/reporting-service.js +1564 -0
  12. package/lib/api/soft-delete-sweep.d.ts +65 -0
  13. package/lib/api/soft-delete-sweep.js +124 -0
  14. package/lib/api/viewer-context.d.ts +29 -0
  15. package/lib/api/viewer-context.js +63 -0
  16. package/lib/core/query-filters.d.ts +263 -0
  17. package/lib/core/query-filters.js +4 -0
  18. package/lib/database/drizzle-schema.d.ts +7357 -0
  19. package/lib/database/drizzle-schema.js +66 -0
  20. package/lib/database/index.d.ts +5 -0
  21. package/lib/database/index.js +8 -0
  22. package/lib/database/migrator.d.ts +20 -0
  23. package/lib/database/migrator.js +80 -0
  24. package/lib/database/postgres-connection.d.ts +201 -0
  25. package/lib/database/postgres-connection.js +413 -0
  26. package/lib/database/retry-strategy.d.ts +68 -0
  27. package/lib/database/retry-strategy.js +122 -0
  28. package/lib/database/schema/alert.d.ts +588 -0
  29. package/lib/database/schema/alert.js +130 -0
  30. package/lib/database/schema/compliance.d.ts +3319 -0
  31. package/lib/database/schema/compliance.js +377 -0
  32. package/lib/database/schema/dashboard.d.ts +474 -0
  33. package/lib/database/schema/dashboard.js +129 -0
  34. package/lib/database/schema/message-attachment.d.ts +183 -0
  35. package/lib/database/schema/message-attachment.js +40 -0
  36. package/lib/database/schema/message.d.ts +411 -0
  37. package/lib/database/schema/message.js +114 -0
  38. package/lib/database/schema/pipeline-template.d.ts +466 -0
  39. package/lib/database/schema/pipeline-template.js +80 -0
  40. package/lib/database/schema/pipeline.d.ts +1613 -0
  41. package/lib/database/schema/pipeline.js +332 -0
  42. package/lib/database/schema/plugin.d.ts +749 -0
  43. package/lib/database/schema/plugin.js +166 -0
  44. package/lib/database/tenancy.d.ts +103 -0
  45. package/lib/database/tenancy.js +167 -0
  46. package/lib/index.d.ts +32 -0
  47. package/lib/index.js +38 -0
  48. package/package.json +161 -0
@@ -0,0 +1,166 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { ComputeType, PluginType, SYSTEM_ORG_ID, } from '@pipeline-builder/api-core';
4
+ import { sql } from 'drizzle-orm';
5
+ import { boolean, integer, varchar, pgTable, text, timestamp, uuid, jsonb, index, uniqueIndex, check } from 'drizzle-orm/pg-core';
6
+ /**
7
+ * Table for storing reusable plugin configurations.
8
+ * Plugins define the behavior of synth/build steps in CDK pipelines.
9
+ *
10
+ * Features * - Versioning support with semantic versioning
11
+ * - Access control via orgId and the three-rung `visibility` ladder
12
+ * - Full audit trail (created/updated by/at)
13
+ * - Flexible metadata storage via JSONB
14
+ * - Support for both ShellStep and CodeBuildStep types
15
+ *
16
+ * @table plugins
17
+ */
18
+ export const plugin = pgTable('plugins', {
19
+ // Primary key
20
+ id: uuid('id').primaryKey().defaultRandom(),
21
+ // Organization and access control
22
+ orgId: varchar('org_id', { length: 255 })
23
+ .default(SYSTEM_ORG_ID)
24
+ .notNull(),
25
+ // Audit fields
26
+ createdBy: text('created_by')
27
+ .default(SYSTEM_ORG_ID)
28
+ .notNull(),
29
+ createdAt: timestamp('created_at', { withTimezone: true })
30
+ .defaultNow()
31
+ .notNull(),
32
+ updatedBy: text('updated_by')
33
+ .default(SYSTEM_ORG_ID)
34
+ .notNull(),
35
+ updatedAt: timestamp('updated_at', { withTimezone: true })
36
+ .defaultNow()
37
+ .notNull(),
38
+ // Core plugin information
39
+ name: varchar('name', { length: 255 })
40
+ .notNull(),
41
+ description: text('description'),
42
+ keywords: jsonb('keywords')
43
+ .$type()
44
+ .default([])
45
+ .notNull(),
46
+ version: varchar('version', { length: 50 })
47
+ .default('1.0.0')
48
+ .notNull(),
49
+ // Plugin classification
50
+ category: varchar('category', { length: 50 })
51
+ .default('unknown')
52
+ .notNull(),
53
+ // Plugin configuration
54
+ metadata: jsonb('metadata')
55
+ .$type()
56
+ .default({})
57
+ .notNull(),
58
+ pluginType: varchar('plugin_type', { length: 50 })
59
+ .$type()
60
+ .default('CodeBuildStep')
61
+ .notNull(),
62
+ computeType: varchar('compute_type', { length: 50 })
63
+ .$type()
64
+ .default('SMALL')
65
+ .notNull(),
66
+ timeout: integer('timeout'),
67
+ failureBehavior: varchar('failure_behavior', { length: 10 })
68
+ .$type()
69
+ .default('fail')
70
+ .notNull(),
71
+ secrets: jsonb('secrets')
72
+ .$type()
73
+ .default([])
74
+ .notNull(),
75
+ primaryOutputDirectory: varchar('primary_output_directory', { length: 28 }),
76
+ // Build configuration
77
+ env: jsonb('env')
78
+ .$type()
79
+ .default({})
80
+ .notNull(),
81
+ buildArgs: jsonb('build_args')
82
+ .$type()
83
+ .default({})
84
+ .notNull(),
85
+ installCommands: text('install_commands')
86
+ .array()
87
+ .default([])
88
+ .notNull(),
89
+ commands: text('commands')
90
+ .array()
91
+ .default([])
92
+ .notNull(),
93
+ // Docker configuration
94
+ dockerfile: text('dockerfile'),
95
+ buildType: varchar('build_type', { length: 20 })
96
+ .default('build_image')
97
+ .notNull(),
98
+ // Developer-portal catalog metadata (ownership / lifecycle / classification).
99
+ // ownerId defaults to the creating user (set at insert), so every plugin has
100
+ // an owner for "my services" views; ownerType distinguishes user vs team.
101
+ ownerId: text('owner_id'),
102
+ ownerType: varchar('owner_type', { length: 10 }).$type(),
103
+ lifecycle: varchar('lifecycle', { length: 20 })
104
+ .$type()
105
+ .default('production')
106
+ .notNull(),
107
+ criticality: varchar('criticality', { length: 10 }).$type(),
108
+ labels: jsonb('labels')
109
+ .$type()
110
+ .default({})
111
+ .notNull(),
112
+ links: jsonb('links')
113
+ .$type()
114
+ .default([])
115
+ .notNull(),
116
+ // Access and visibility — the shared three-rung ladder (see api-core's
117
+ // `Visibility`): `private` is author-only (`created_by`), `org` is the whole
118
+ // owning org, `public` reaches the org's teams and — from the system org —
119
+ // every org. Constrained at the SQL layer too via a CHECK in postgres-init.sql
120
+ // so a typo can't sneak past the application layer.
121
+ visibility: varchar('visibility', { length: 10 })
122
+ .$type()
123
+ .default('private')
124
+ .notNull(),
125
+ isDefault: boolean('is_default')
126
+ .default(false)
127
+ .notNull(),
128
+ isActive: boolean('is_active')
129
+ .default(true)
130
+ .notNull(),
131
+ // Deletion tracking (soft delete)
132
+ deletedAt: timestamp('deleted_at', { withTimezone: true }),
133
+ deletedBy: text('deleted_by'),
134
+ // Soft-delete purge deadline: the retention sweep hard-deletes tombstoned
135
+ // rows once `purge_after` has passed (set on delete alongside deleted_at).
136
+ purgeAfter: timestamp('purge_after', { withTimezone: true }),
137
+ }, (table) => ({
138
+ // Partial index over just the tombstones — drives the retention purge sweep.
139
+ purgeIdx: index('plugin_purge_idx').on(table.purgeAfter).where(sql `deleted_at IS NOT NULL`),
140
+ // Indexes for common queries
141
+ nameIdx: index('plugin_name_idx').on(table.name),
142
+ orgIdIdx: index('plugin_org_id_idx').on(table.orgId),
143
+ versionIdx: index('plugin_version_idx').on(table.version),
144
+ activeIdx: index('plugin_active_idx').on(table.isActive),
145
+ createdAtIdx: index('plugin_created_at_idx').on(table.createdAt),
146
+ updatedAtIdx: index('plugin_updated_at_idx').on(table.updatedAt),
147
+ // Category index for filtering
148
+ categoryIdx: index('plugin_category_idx').on(table.category),
149
+ // Developer-portal catalog indexes: "my services" (owner) + lifecycle filter.
150
+ ownerIdx: index('plugin_owner_idx').on(table.orgId, table.ownerId),
151
+ lifecycleIdx: index('plugin_lifecycle_idx').on(table.orgId, table.lifecycle),
152
+ // Composite index for common access pattern (orgId + isActive)
153
+ orgActiveIdx: index('plugin_org_active_idx').on(table.orgId, table.isActive),
154
+ // Composite index for filtered queries (orgId + visibility + isActive)
155
+ orgVisibilityActiveIdx: index('plugin_org_visibility_active_idx').on(table.orgId, table.visibility, table.isActive),
156
+ // Drives the "my private drafts" leg of the visibility predicate.
157
+ createdByIdx: index('plugin_created_by_idx').on(table.orgId, table.createdBy),
158
+ // Partial index for active-only queries (smaller, faster than full index)
159
+ activeOnlyOrgIdx: index('plugin_active_only_org_idx').on(table.orgId, table.createdAt).where(sql `is_active = true`),
160
+ // Unique constraint on name + version + orgId
161
+ nameVersionOrgUnique: uniqueIndex('plugin_name_version_org_unique')
162
+ .on(table.name, table.version, table.orgId),
163
+ // Check constraints
164
+ versionCheck: check('plugin_version_check', sql `${table.version} ~ '^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$'`),
165
+ }));
166
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2RhdGFiYXNlL3NjaGVtYS9wbHVnaW4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0QyxPQUFPLEVBQ0wsV0FBVyxFQUFFLFVBQVUsRUFBRSxhQUFhLEdBRXZDLE1BQU0sNEJBQTRCLENBQUM7QUFDcEMsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUNsQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsV0FBVyxFQUFFLEtBQUssRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBWWxJOzs7Ozs7Ozs7OztHQVdHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxTQUFTLEVBQUU7SUFDdkMsY0FBYztJQUNkLEVBQUUsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsVUFBVSxFQUFFLENBQUMsYUFBYSxFQUFFO0lBRTNDLGtDQUFrQztJQUNsQyxLQUFLLEVBQUUsT0FBTyxDQUFDLFFBQVEsRUFBRSxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUUsQ0FBQztTQUN0QyxPQUFPLENBQUMsYUFBYSxDQUFDO1NBQ3RCLE9BQU8sRUFBRTtJQUVaLGVBQWU7SUFDZixTQUFTLEVBQUUsSUFBSSxDQUFDLFlBQVksQ0FBQztTQUMxQixPQUFPLENBQUMsYUFBYSxDQUFDO1NBQ3RCLE9BQU8sRUFBRTtJQUNaLFNBQVMsRUFBRSxTQUFTLENBQUMsWUFBWSxFQUFFLEVBQUUsWUFBWSxFQUFFLElBQUksRUFBRSxDQUFDO1NBQ3ZELFVBQVUsRUFBRTtTQUNaLE9BQU8sRUFBRTtJQUNaLFNBQVMsRUFBRSxJQUFJLENBQUMsWUFBWSxDQUFDO1NBQzFCLE9BQU8sQ0FBQyxh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QyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCB7XG4gIENvbXB1dGVUeXBlLCBQbHVnaW5UeXBlLCBTWVNURU1fT1JHX0lELCB0eXBlIENyaXRpY2FsaXR5LCB0eXBlIEVudGl0eUxhYmVscywgdHlwZSBFbnRpdHlMaW5rLCB0eXBlIExpZmVjeWNsZSwgdHlwZSBPd25lclR5cGUsXG4gIHR5cGUgVmlzaWJpbGl0eSxcbn0gZnJvbSAnQHBpcGVsaW5lLWJ1aWxkZXIvYXBpLWNvcmUnO1xuaW1wb3J0IHsgc3FsIH0gZnJvbSAnZHJpenpsZS1vcm0nO1xuaW1wb3J0IHsgYm9vbGVhbiwgaW50ZWdlciwgdmFyY2hhciwgcGdUYWJsZSwgdGV4dCwgdGltZXN0YW1wLCB1dWlkLCBqc29uYiwgaW5kZXgsIHVuaXF1ZUluZGV4LCBjaGVjayB9IGZyb20gJ2RyaXp6bGUtb3JtL3BnLWNvcmUnO1xuXG4vKipcbiAqIFNlY3JldCByZXF1aXJlbWVudCBmb3IgYSBwbHVnaW4uXG4gKiBEZWNsYXJlcyBuYW1lZCBzZWNyZXRzIHRoZSBwbHVnaW4gZXhwZWN0cyBhdCBidWlsZCB0aW1lLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFBsdWdpblNlY3JldCB7XG4gIG5hbWU6IHN0cmluZztcbiAgcmVxdWlyZWQ6IGJvb2xlYW47XG4gIGRlc2NyaXB0aW9uPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIFRhYmxlIGZvciBzdG9yaW5nIHJldXNhYmxlIHBsdWdpbiBjb25maWd1cmF0aW9ucy5cbiAqIFBsdWdpbnMgZGVmaW5lIHRoZSBiZWhhdmlvciBvZiBzeW50aC9idWlsZCBzdGVwcyBpbiBDREsgcGlwZWxpbmVzLlxuICpcbiAqIEZlYXR1cmVzICogLSBWZXJzaW9uaW5nIHN1cHBvcnQgd2l0aCBzZW1hbnRpYyB2ZXJzaW9uaW5nXG4gKiAtIEFjY2VzcyBjb250cm9sIHZpYSBvcmdJZCBhbmQgdGhlIHRocmVlLXJ1bmcgYHZpc2liaWxpdHlgIGxhZGRlclxuICogLSBGdWxsIGF1ZGl0IHRyYWlsIChjcmVhdGVkL3VwZGF0ZWQgYnkvYXQpXG4gKiAtIEZsZXhpYmxlIG1ldGFkYXRhIHN0b3JhZ2UgdmlhIEpTT05CXG4gKiAtIFN1cHBvcnQgZm9yIGJvdGggU2hlbGxTdGVwIGFuZCBDb2RlQnVpbGRTdGVwIHR5cGVzXG4gKlxuICogQHRhYmxlIHBsdWdpbnNcbiAqL1xuZXhwb3J0IGNvbnN0IHBsdWdpbiA9IHBnVGFibGUoJ3BsdWdpbnMnLCB7XG4gIC8vIFByaW1hcnkga2V5XG4gIGlkOiB1dWlkKCdpZCcpLnByaW1hcnlLZXkoKS5kZWZhdWx0UmFuZG9tKCksXG5cbiAgLy8gT3JnYW5pemF0aW9uIGFuZCBhY2Nlc3MgY29udHJvbFxuICBvcmdJZDogdmFyY2hhcignb3JnX2lkJywgeyBsZW5ndGg6IDI1NSB9KVxuICAgIC5kZWZhdWx0KFNZU1RFTV9PUkdfSUQpXG4gICAgLm5vdE51bGwoKSxcblxuICAvLyBBdWRpdCBmaWVsZHNcbiAgY3JlYXRlZEJ5OiB0ZXh0KCdjcmVhdGVkX2J5JylcbiAgICAuZGVmYXVsdChTWVNURU1fT1JHX0lEKVxuICAgIC5ub3ROdWxsKCksXG4gIGNyZWF0ZWRBdDogdGltZXN0YW1wKCdjcmVhdGVkX2F0JywgeyB3aXRoVGltZXpvbmU6IHRydWUgfSlcbiAgICAuZGVmYXVsdE5vdygpXG4gICAgLm5vdE51bGwoKSxcbiAgdXBkYXRlZEJ5OiB0ZXh0KCd1cGRhdGVkX2J5JylcbiAgICAuZGVmYXVsdChTWVNURU1fT1JHX0lEKVxuICAgIC5ub3ROdWxsKCksXG4gIHVwZGF0ZWRBdDogdGltZXN0YW1wKCd1cGRhdGVkX2F0JywgeyB3aXRoVGltZXpvbmU6IHRydWUgfSlcbiAgICAuZGVmYXVsdE5vdygpXG4gICAgLm5vdE51bGwoKSxcblxuICAvLyBDb3JlIHBsdWdpbiBpbmZvcm1hdGlvblxuICBuYW1lOiB2YXJjaGFyKCduYW1lJywgeyBsZW5ndGg6IDI1NSB9KVxuICAgIC5ub3ROdWxsKCksXG4gIGRlc2NyaXB0aW9uOiB0ZXh0KCdkZXNjcmlwdGlvbicpLFxuICBrZXl3b3JkczoganNvbmIoJ2tleXdvcmRzJylcbiAgICAuJHR5cGU8c3RyaW5nW10+KClcbiAgICAuZGVmYXVsdChbXSlcbiAgICAubm90TnVsbCgpLFxuICB2ZXJzaW9uOiB2YXJjaGFyKCd2ZXJzaW9uJywgeyBsZW5ndGg6IDUwIH0pXG4gICAgLmRlZmF1bHQoJzEuMC4wJylcbiAgICAubm90TnVsbCgpLFxuXG4gIC8vIFBsdWdpbiBjbGFzc2lmaWNhdGlvblxuICBjYXRlZ29yeTogdmFyY2hhcignY2F0ZWdvcnknLCB7IGxlbmd0aDogNTAgfSlcbiAgICAuZGVmYXVsdCgndW5rbm93bicpXG4gICAgLm5vdE51bGwoKSxcblxuICAvLyBQbHVnaW4gY29uZmlndXJhdGlvblxuICBtZXRhZGF0YToganNvbmIoJ21ldGFkYXRhJylcbiAgICAuJHR5cGU8UmVjb3JkPHN0cmluZywgc3RyaW5nIHwgbnVtYmVyIHwgYm9vbGVhbj4+KClcbiAgICAuZGVmYXVsdCh7fSlcbiAgICAubm90TnVsbCgpLFxuICBwbHVnaW5UeXBlOiB2YXJjaGFyKCdwbHVnaW5fdHlwZScsIHsgbGVuZ3RoOiA1MCB9KVxuICAgIC4kdHlwZTxQbHVnaW5UeXBlPigpXG4gICAgLmRlZmF1bHQoJ0NvZGVCdWlsZFN0ZXAnIGFzIFBsdWdpblR5cGUpXG4gICAgLm5vdE51bGwoKSxcbiAgY29tcHV0ZVR5cGU6IHZhcmNoYXIoJ2NvbXB1dGVfdHlwZScsIHsgbGVuZ3RoOiA1MCB9KVxuICAgIC4kdHlwZTxDb21wdXRlVHlwZT4oKVxuICAgIC5kZWZhdWx0KCdTTUFMTCcgYXMgQ29tcHV0ZVR5cGUpXG4gICAgLm5vdE51bGwoKSxcbiAgdGltZW91dDogaW50ZWdlcigndGltZW91dCcpLFxuICBmYWlsdXJlQmVoYXZpb3I6IHZhcmNoYXIoJ2ZhaWx1cmVfYmVoYXZpb3InLCB7IGxlbmd0aDogMTAgfSlcbiAgICAuJHR5cGU8J2ZhaWwnIHwgJ3dhcm4nIHwgJ2lnbm9yZSc+KClcbiAgICAuZGVmYXVsdCgnZmFpbCcpXG4gICAgLm5vdE51bGwoKSxcbiAgc2VjcmV0czoganNvbmIoJ3NlY3JldHMnKVxuICAgIC4kdHlwZTxQbHVnaW5TZWNyZXRbXT4oKVxuICAgIC5kZWZhdWx0KFtdKVxuICAgIC5ub3ROdWxsKCksXG4gIHByaW1hcnlPdXRwdXREaXJlY3Rvcnk6IHZhcmNoYXIoJ3ByaW1hcnlfb3V0cHV0X2RpcmVjdG9yeScsIHsgbGVuZ3RoOiAyOCB9KSxcblxuICAvLyBCdWlsZCBjb25maWd1cmF0aW9uXG4gIGVudjoganNvbmIoJ2VudicpXG4gICAgLiR0eXBlPFJlY29yZDxzdHJpbmcsIHN0cmluZz4+KClcbiAgICAuZGVmYXVsdCh7fSlcbiAgICAubm90TnVsbCgpLFxuICBidWlsZEFyZ3M6IGpzb25iKCdidWlsZF9hcmdzJylcbiAgICAuJHR5cGU8UmVjb3JkPHN0cmluZywgc3RyaW5nPj4oKVxuICAgIC5kZWZhdWx0KHt9KVxuICAgIC5ub3ROdWxsKCksXG4gIGluc3RhbGxDb21tYW5kczogdGV4dCgnaW5zdGFsbF9jb21tYW5kcycpXG4gICAgLmFycmF5KClcbiAgICAuZGVmYXVsdChbXSlcbiAgICAubm90TnVsbCgpLFxuICBjb21tYW5kczogdGV4dCgnY29tbWFuZHMnKVxuICAgIC5hcnJheSgpXG4gICAgLmRlZmF1bHQoW10pXG4gICAgLm5vdE51bGwoKSxcblxuICAvLyBEb2NrZXIgY29uZmlndXJhdGlvblxuICBkb2NrZXJmaWxlOiB0ZXh0KCdkb2NrZXJmaWxlJyksXG4gIGJ1aWxkVHlwZTogdmFyY2hhcignYnVpbGRfdHlwZScsIHsgbGVuZ3RoOiAyMCB9KVxuICAgIC5kZWZhdWx0KCdidWlsZF9pbWFnZScpXG4gICAgLm5vdE51bGwoKSxcblxuICAvLyBEZXZlbG9wZXItcG9ydGFsIGNhdGFsb2cgbWV0YWRhdGEgKG93bmVyc2hpcCAvIGxpZmVjeWNsZSAvIGNsYXNzaWZpY2F0aW9uKS5cbiAgLy8gb3duZXJJZCBkZWZhdWx0cyB0byB0aGUgY3JlYXRpbmcgdXNlciAoc2V0IGF0IGluc2VydCksIHNvIGV2ZXJ5IHBsdWdpbiBoYXNcbiAgLy8gYW4gb3duZXIgZm9yIFwibXkgc2VydmljZXNcIiB2aWV3czsgb3duZXJUeXBlIGRpc3Rpbmd1aXNoZXMgdXNlciB2cyB0ZWFtLlxuICBvd25lcklkOiB0ZXh0KCdvd25lcl9pZCcpLFxuICBvd25lclR5cGU6IHZhcmNoYXIoJ293bmVyX3R5cGUnLCB7IGxlbmd0aDogMTAgfSkuJHR5cGU8T3duZXJUeXBlPigpLFxuICBsaWZlY3ljbGU6IHZhcmNoYXIoJ2xpZmVjeWNsZScsIHsgbGVuZ3RoOiAyMCB9KVxuICAgIC4kdHlwZTxMaWZlY3ljbGU+KClcbiAgICAuZGVmYXVsdCgncHJvZHVjdGlvbicgYXMgTGlmZWN5Y2xlKVxuICAgIC5ub3ROdWxsKCksXG4gIGNyaXRpY2FsaXR5OiB2YXJjaGFyKCdjcml0aWNhbGl0eScsIHsgbGVuZ3RoOiAxMCB9KS4kdHlwZTxDcml0aWNhbGl0eT4oKSxcbiAgbGFiZWxzOiBqc29uYignbGFiZWxzJylcbiAgICAuJHR5cGU8RW50aXR5TGFiZWxzPigpXG4gICAgLmRlZmF1bHQoe30pXG4gICAgLm5vdE51bGwoKSxcbiAgbGlua3M6IGpzb25iKCdsaW5rcycpXG4gICAgLiR0eXBlPEVudGl0eUxpbmtbXT4oKVxuICAgIC5kZWZhdWx0KFtdKVxuICAgIC5ub3ROdWxsKCksXG5cbiAgLy8gQWNjZXNzIGFuZCB2aXNpYmlsaXR5IOKAlCB0aGUgc2hhcmVkIHRocmVlLXJ1bmcgbGFkZGVyIChzZWUgYXBpLWNvcmUnc1xuICAvLyBgVmlzaWJpbGl0eWApOiBgcHJpdmF0ZWAgaXMgYXV0aG9yLW9ubHkgKGBjcmVhdGVkX2J5YCksIGBvcmdgIGlzIHRoZSB3aG9sZVxuICAvLyBvd25pbmcgb3JnLCBgcHVibGljYCByZWFjaGVzIHRoZSBvcmcncyB0ZWFtcyBhbmQg4oCUIGZyb20gdGhlIHN5c3RlbSBvcmcg4oCUXG4gIC8vIGV2ZXJ5IG9yZy4gQ29uc3RyYWluZWQgYXQgdGhlIFNRTCBsYXllciB0b28gdmlhIGEgQ0hFQ0sgaW4gcG9zdGdyZXMtaW5pdC5zcWxcbiAgLy8gc28gYSB0eXBvIGNhbid0IHNuZWFrIHBhc3QgdGhlIGFwcGxpY2F0aW9uIGxheWVyLlxuICB2aXNpYmlsaXR5OiB2YXJjaGFyKCd2aXNpYmlsaXR5JywgeyBsZW5ndGg6IDEwIH0pXG4gICAgLiR0eXBlPFZpc2liaWxpdHk+KClcbiAgICAuZGVmYXVsdCgncHJpdmF0ZScpXG4gICAgLm5vdE51bGwoKSxcbiAgaXNEZWZhdWx0OiBib29sZWFuKCdpc19kZWZhdWx0JylcbiAgICAuZGVmYXVsdChmYWxzZSlcbiAgICAubm90TnVsbCgpLFxuICBpc0FjdGl2ZTogYm9vbGVhbignaXNfYWN0aXZlJylcbiAgICAuZGVmYXVsdCh0cnVlKVxuICAgIC5ub3ROdWxsKCksXG5cbiAgLy8gRGVsZXRpb24gdHJhY2tpbmcgKHNvZnQgZGVsZXRlKVxuICBkZWxldGVkQXQ6IHRpbWVzdGFtcCgnZGVsZXRlZF9hdCcsIHsgd2l0aFRpbWV6b25lOiB0cnVlIH0pLFxuICBkZWxldGVkQnk6IHRleHQoJ2RlbGV0ZWRfYnknKSxcbiAgLy8gU29mdC1kZWxldGUgcHVyZ2UgZGVhZGxpbmU6IHRoZSByZXRlbnRpb24gc3dlZXAgaGFyZC1kZWxldGVzIHRvbWJzdG9uZWRcbiAgLy8gcm93cyBvbmNlIGBwdXJnZV9hZnRlcmAgaGFzIHBhc3NlZCAoc2V0IG9uIGRlbGV0ZSBhbG9uZ3NpZGUgZGVsZXRlZF9hdCkuXG4gIHB1cmdlQWZ0ZXI6IHRpbWVzdGFtcCgncHVyZ2VfYWZ0ZXInLCB7IHdpdGhUaW1lem9uZTogdHJ1ZSB9KSxcbn0sICh0YWJsZSkgPT4gKHtcbiAgLy8gUGFydGlhbCBpbmRleCBvdmVyIGp1c3QgdGhlIHRvbWJzdG9uZXMg4oCUIGRyaXZlcyB0aGUgcmV0ZW50aW9uIHB1cmdlIHN3ZWVwLlxuICBwdXJnZUlkeDogaW5kZXgoJ3BsdWdpbl9wdXJnZV9pZHgnKS5vbih0YWJsZS5wdXJnZUFmdGVyKS53aGVyZShzcWxgZGVsZXRlZF9hdCBJUyBOT1QgTlVMTGApLFxuICAvLyBJbmRleGVzIGZvciBjb21tb24gcXVlcmllc1xuICBuYW1lSWR4OiBpbmRleCgncGx1Z2luX25hbWVfaWR4Jykub24odGFibGUubmFtZSksXG4gIG9yZ0lkSWR4OiBpbmRleCgncGx1Z2luX29yZ19pZF9pZHgnKS5vbih0YWJsZS5vcmdJZCksXG4gIHZlcnNpb25JZHg6IGluZGV4KCdwbHVnaW5fdmVyc2lvbl9pZHgnKS5vbih0YWJsZS52ZXJzaW9uKSxcbiAgYWN0aXZlSWR4OiBpbmRleCgncGx1Z2luX2FjdGl2ZV9pZHgnKS5vbih0YWJsZS5pc0FjdGl2ZSksXG4gIGNyZWF0ZWRBdElkeDogaW5kZXgoJ3BsdWdpbl9jcmVhdGVkX2F0X2lkeCcpLm9uKHRhYmxlLmNyZWF0ZWRBdCksXG4gIHVwZGF0ZWRBdElkeDogaW5kZXgoJ3BsdWdpbl91cGRhdGVkX2F0X2lkeCcpLm9uKHRhYmxlLnVwZGF0ZWRBdCksXG5cbiAgLy8gQ2F0ZWdvcnkgaW5kZXggZm9yIGZpbHRlcmluZ1xuICBjYXRlZ29yeUlkeDogaW5kZXgoJ3BsdWdpbl9jYXRlZ29yeV9pZHgnKS5vbih0YWJsZS5jYXRlZ29yeSksXG5cbiAgLy8gRGV2ZWxvcGVyLXBvcnRhbCBjYXRhbG9nIGluZGV4ZXM6IFwibXkgc2VydmljZXNcIiAob3duZXIpICsgbGlmZWN5Y2xlIGZpbHRlci5cbiAgb3duZXJJZHg6IGluZGV4KCdwbHVnaW5fb3duZXJfaWR4Jykub24odGFibGUub3JnSWQsIHRhYmxlLm93bmVySWQpLFxuICBsaWZlY3ljbGVJZHg6IGluZGV4KCdwbHVnaW5fbGlmZWN5Y2xlX2lkeCcpLm9uKHRhYmxlLm9yZ0lkLCB0YWJsZS5saWZlY3ljbGUpLFxuXG4gIC8vIENvbXBvc2l0ZSBpbmRleCBmb3IgY29tbW9uIGFjY2VzcyBwYXR0ZXJuIChvcmdJZCArIGlzQWN0aXZlKVxuICBvcmdBY3RpdmVJZHg6IGluZGV4KCdwbHVnaW5fb3JnX2FjdGl2ZV9pZHgnKS5vbih0YWJsZS5vcmdJZCwgdGFibGUuaXNBY3RpdmUpLFxuXG4gIC8vIENvbXBvc2l0ZSBpbmRleCBmb3IgZmlsdGVyZWQgcXVlcmllcyAob3JnSWQgKyB2aXNpYmlsaXR5ICsgaXNBY3RpdmUpXG4gIG9yZ1Zpc2liaWxpdHlBY3RpdmVJZHg6IGluZGV4KCdwbHVnaW5fb3JnX3Zpc2liaWxpdHlfYWN0aXZlX2lkeCcpLm9uKHRhYmxlLm9yZ0lkLCB0YWJsZS52aXNpYmlsaXR5LCB0YWJsZS5pc0FjdGl2ZSksXG4gIC8vIERyaXZlcyB0aGUgXCJteSBwcml2YXRlIGRyYWZ0c1wiIGxlZyBvZiB0aGUgdmlzaWJpbGl0eSBwcmVkaWNhdGUuXG4gIGNyZWF0ZWRCeUlkeDogaW5kZXgoJ3BsdWdpbl9jcmVhdGVkX2J5X2lkeCcpLm9uKHRhYmxlLm9yZ0lkLCB0YWJsZS5jcmVhdGVkQnkpLFxuXG4gIC8vIFBhcnRpYWwgaW5kZXggZm9yIGFjdGl2ZS1vbmx5IHF1ZXJpZXMgKHNtYWxsZXIsIGZhc3RlciB0aGFuIGZ1bGwgaW5kZXgpXG4gIGFjdGl2ZU9ubHlPcmdJZHg6IGluZGV4KCdwbHVnaW5fYWN0aXZlX29ubHlfb3JnX2lkeCcpLm9uKHRhYmxlLm9yZ0lkLCB0YWJsZS5jcmVhdGVkQXQpLndoZXJlKHNxbGBpc19hY3RpdmUgPSB0cnVlYCksXG5cbiAgLy8gVW5pcXVlIGNvbnN0cmFpbnQgb24gbmFtZSArIHZlcnNpb24gKyBvcmdJZFxuICBuYW1lVmVyc2lvbk9yZ1VuaXF1ZTogdW5pcXVlSW5kZXgoJ3BsdWdpbl9uYW1lX3ZlcnNpb25fb3JnX3VuaXF1ZScpXG4gICAgLm9uKHRhYmxlLm5hbWUsIHRhYmxlLnZlcnNpb24sIHRhYmxlLm9yZ0lkKSxcblxuICAvLyBDaGVjayBjb25zdHJhaW50c1xuICB2ZXJzaW9uQ2hlY2s6IGNoZWNrKCAncGx1Z2luX3ZlcnNpb25fY2hlY2snLFxuICAgIHNxbGAke3RhYmxlLnZlcnNpb259IH4gJ15bMC05XStcXC5bMC05XStcXC5bMC05XSsoLVthLXpBLVowLTkuLV0rKT8oXFwrW2EtekEtWjAtOS4tXSspPyQnYCxcbiAgKSxcbn0pKTtcblxuLyoqXG4gKiBUeXBlU2NyaXB0IHR5cGVzIHJlcHJlc2VudGluZyBkYXRhYmFzZSByb3dzXG4gKi9cbmV4cG9ydCB0eXBlIFBsdWdpbiA9IHR5cGVvZiBwbHVnaW4uJGluZmVyU2VsZWN0O1xuZXhwb3J0IHR5cGUgUGx1Z2luSW5zZXJ0ID0gdHlwZW9mIHBsdWdpbi4kaW5mZXJJbnNlcnQ7XG5cbi8qKlxuICogSGVscGVyIHR5cGVzIGZvciB3b3JraW5nIHdpdGggcGFydGlhbCB1cGRhdGVzXG4gKi9cbmV4cG9ydCB0eXBlIFBsdWdpblVwZGF0ZSA9IFBhcnRpYWw8T21pdDxQbHVnaW5JbnNlcnQsICdpZCcgfCAnY3JlYXRlZEF0JyB8ICdjcmVhdGVkQnknPj47XG4iXX0=
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Tenant-context plumbing for Postgres row-level security.
3
+ *
4
+ * Background: postgres-init.sql installs RLS policies on every user-data
5
+ * table that consult two session GUCs — `app.org_id` and `app.is_sysadmin`.
6
+ * Most user-data tables have been flipped to `FORCE ROW LEVEL SECURITY`, so
7
+ * the policies DO enforce even for the (owning) connection user — a query
8
+ * against a FORCE'd table must run inside a transaction that has SET LOCAL'd
9
+ * both GUCs or it returns zero rows for non-sysadmins (and may fail to write
10
+ * for any caller). A few tables remain `ENABLE`-only (owner-bypass) pending
11
+ * their soak; the same context plumbing covers both.
12
+ *
13
+ * This module is the seam.
14
+ *
15
+ * 1. `tenantContext` (AsyncLocalStorage) carries `{orgId, isSuperAdmin}`
16
+ * down the call chain without prop-drilling. Set once at the request
17
+ * boundary; readable from anywhere.
18
+ *
19
+ * 2. `withTenantTx(fn)` opens a transaction, SET LOCAL's both GUCs from
20
+ * the surrounding context, then invokes `fn(tx)`. Services migrate one
21
+ * at a time by wrapping their existing drizzle calls in this helper —
22
+ * `db.select().from(...)` becomes `withTenantTx(tx => tx.select().from(...))`.
23
+ *
24
+ * 3. `runWithTenantContext(ctx, fn)` is the Express-middleware-side
25
+ * bookend that establishes the AsyncLocalStorage scope for the request.
26
+ *
27
+ * Migration order (see docs/plans/f-1-0-rls-enforcement.md):
28
+ * - First adopters: newly-written services (dashboard, alert-destination)
29
+ * where the change is mechanical.
30
+ * - Then high-write services (plugin, pipeline). Soak each one before
31
+ * flipping the underlying table to FORCE.
32
+ * - admin_audit_log uses a sysadmin-only policy — sysadmin paths must
33
+ * also set `app.is_sysadmin = 'true'` or they'll lose access to it.
34
+ */
35
+ import { AsyncLocalStorage } from 'node:async_hooks';
36
+ import { db } from './postgres-connection.js';
37
+ export interface TenantContext {
38
+ /** Caller's org. Undefined for un-authenticated / system jobs. */
39
+ orgId?: string;
40
+ /** Caller's user id. Not used for RLS — Postgres policies are org-grained,
41
+ * with no per-user session GUC — but carried so app-layer predicates with a
42
+ * PER-USER rung (pipeline templates' `private` visibility) can resolve "who
43
+ * is asking" on paths that have nowhere to pass it, notably CrudService's
44
+ * `writeConditions`. Absent for system jobs, which is the fail-closed case:
45
+ * no viewer ⇒ no private rows. */
46
+ userId?: string;
47
+ /** True when the caller is a sysadmin (system-org admin). Bypasses RLS
48
+ * policies via the sysadmin-bypass branch in `current_is_sysadmin()`. */
49
+ isSuperAdmin: boolean;
50
+ /** Org → team hierarchy: the caller's active-org parent (present only when the
51
+ * active org is a team). Not used for RLS; carried so downstream side-effects
52
+ * (e.g. entity-event compliance eval) can honor parent `propagateToChildren`
53
+ * rules without a request in scope. */
54
+ parentOrgId?: string;
55
+ }
56
+ /**
57
+ * Per-request tenant context. Populated by Express middleware once the JWT
58
+ * is validated; consumed by `withTenantTx` and any helper that needs to
59
+ * know "who is the caller" without re-deriving from the request object.
60
+ */
61
+ export declare const tenantContext: AsyncLocalStorage<TenantContext>;
62
+ /**
63
+ * Run `fn` inside the given tenant scope. The AsyncLocalStorage scope
64
+ * survives across async boundaries (Promises, setTimeout, etc.), so any
65
+ * `withTenantTx` call inside `fn` — directly or through any depth of
66
+ * async helpers — picks up `ctx`.
67
+ *
68
+ * Wrap `next()` from an Express middleware to establish per-request scope:
69
+ *
70
+ * app.use((req, res, next) => {
71
+ * runWithTenantContext({ orgId, isSuperAdmin }, () => next());
72
+ * });
73
+ */
74
+ export declare function runWithTenantContext<T>(ctx: TenantContext, fn: () => T): T;
75
+ /** Read the current tenant context. Returns undefined outside an
76
+ * `runWithTenantContext` scope (e.g. background workers, migrations). */
77
+ export declare function getTenantContext(): TenantContext | undefined;
78
+ /**
79
+ * Assert that the current code is running inside a tenant scope. Callers
80
+ * that legitimately need to refuse to operate without one (e.g. handlers
81
+ * that touch FORCE'd RLS tables) can use this instead of relying on the
82
+ * downstream "permission denied" error to surface the bug.
83
+ */
84
+ export declare function requireTenantContext(): TenantContext;
85
+ /**
86
+ * Open a transaction with RLS GUCs SET LOCAL from the current
87
+ * AsyncLocalStorage tenant context, then invoke `fn(tx)`.
88
+ *
89
+ * - When called outside a tenant scope (e.g. from a background job that
90
+ * doesn't have a caller identity), the transaction is opened with both
91
+ * GUCs cleared — RLS policies will return zero rows on FORCE'd tables.
92
+ * Callers that need a sysadmin-equivalent scope should wrap themselves in
93
+ * `runWithTenantContext({ isSuperAdmin: true }, …)` explicitly.
94
+ *
95
+ * - Uses `set_config(key, value, true)` (the boolean = `is_local`, i.e.
96
+ * transaction-scoped). Equivalent to `SET LOCAL` but takes the value as
97
+ * a parameter, which is what we want — Drizzle's `sql` template binds the
98
+ * value safely so an attacker-controlled `orgId` can't escape the quoting.
99
+ *
100
+ * - Returns whatever `fn` returns; throws whatever `fn` throws (Drizzle
101
+ * handles the COMMIT/ROLLBACK for us).
102
+ */
103
+ export declare function withTenantTx<T>(fn: (tx: Parameters<Parameters<typeof db.transaction>[0]>[0]) => Promise<T>): Promise<T>;
@@ -0,0 +1,167 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Tenant-context plumbing for Postgres row-level security.
5
+ *
6
+ * Background: postgres-init.sql installs RLS policies on every user-data
7
+ * table that consult two session GUCs — `app.org_id` and `app.is_sysadmin`.
8
+ * Most user-data tables have been flipped to `FORCE ROW LEVEL SECURITY`, so
9
+ * the policies DO enforce even for the (owning) connection user — a query
10
+ * against a FORCE'd table must run inside a transaction that has SET LOCAL'd
11
+ * both GUCs or it returns zero rows for non-sysadmins (and may fail to write
12
+ * for any caller). A few tables remain `ENABLE`-only (owner-bypass) pending
13
+ * their soak; the same context plumbing covers both.
14
+ *
15
+ * This module is the seam.
16
+ *
17
+ * 1. `tenantContext` (AsyncLocalStorage) carries `{orgId, isSuperAdmin}`
18
+ * down the call chain without prop-drilling. Set once at the request
19
+ * boundary; readable from anywhere.
20
+ *
21
+ * 2. `withTenantTx(fn)` opens a transaction, SET LOCAL's both GUCs from
22
+ * the surrounding context, then invokes `fn(tx)`. Services migrate one
23
+ * at a time by wrapping their existing drizzle calls in this helper —
24
+ * `db.select().from(...)` becomes `withTenantTx(tx => tx.select().from(...))`.
25
+ *
26
+ * 3. `runWithTenantContext(ctx, fn)` is the Express-middleware-side
27
+ * bookend that establishes the AsyncLocalStorage scope for the request.
28
+ *
29
+ * Migration order (see docs/plans/f-1-0-rls-enforcement.md):
30
+ * - First adopters: newly-written services (dashboard, alert-destination)
31
+ * where the change is mechanical.
32
+ * - Then high-write services (plugin, pipeline). Soak each one before
33
+ * flipping the underlying table to FORCE.
34
+ * - admin_audit_log uses a sysadmin-only policy — sysadmin paths must
35
+ * also set `app.is_sysadmin = 'true'` or they'll lose access to it.
36
+ */
37
+ import { AsyncLocalStorage } from 'node:async_hooks';
38
+ import { createLogger } from '@pipeline-builder/api-core';
39
+ import { sql } from 'drizzle-orm';
40
+ import { db } from './postgres-connection.js';
41
+ const logger = createLogger('tenant-context');
42
+ function getContextMode() {
43
+ const raw = process.env.RLS_CONTEXT_MODE?.toLowerCase();
44
+ if (raw === 'silent' || raw === 'warn' || raw === 'strict')
45
+ return raw;
46
+ // No explicit override: fail-fast in production, warn everywhere else.
47
+ return process.env.NODE_ENV === 'production' ? 'strict' : 'warn';
48
+ }
49
+ /**
50
+ * Per-statement server-side timeout (ms) applied INSIDE every `withTenantTx`
51
+ * transaction, next to the RLS GUCs. `withTenantTx` is the real query path for
52
+ * all RLS/CRUD reads and writes, so this is where the DB-side guard belongs (the
53
+ * old `Connection.transaction` wrapper that set it is dead — see
54
+ * postgres-connection.ts). Bounds a runaway query so it can't hold a pooled
55
+ * connection open indefinitely. Env-configurable via `DB_STATEMENT_TIMEOUT_MS`
56
+ * (default 30s); set to `0` to disable the timeout.
57
+ */
58
+ function getStatementTimeoutMs() {
59
+ const raw = parseInt(process.env.DB_STATEMENT_TIMEOUT_MS ?? '', 10);
60
+ return Number.isFinite(raw) && raw >= 0 ? raw : 30000;
61
+ }
62
+ /**
63
+ * Per-request tenant context. Populated by Express middleware once the JWT
64
+ * is validated; consumed by `withTenantTx` and any helper that needs to
65
+ * know "who is the caller" without re-deriving from the request object.
66
+ */
67
+ export const tenantContext = new AsyncLocalStorage();
68
+ /**
69
+ * Run `fn` inside the given tenant scope. The AsyncLocalStorage scope
70
+ * survives across async boundaries (Promises, setTimeout, etc.), so any
71
+ * `withTenantTx` call inside `fn` — directly or through any depth of
72
+ * async helpers — picks up `ctx`.
73
+ *
74
+ * Wrap `next()` from an Express middleware to establish per-request scope:
75
+ *
76
+ * app.use((req, res, next) => {
77
+ * runWithTenantContext({ orgId, isSuperAdmin }, () => next());
78
+ * });
79
+ */
80
+ export function runWithTenantContext(ctx, fn) {
81
+ return tenantContext.run(ctx, fn);
82
+ }
83
+ /** Read the current tenant context. Returns undefined outside an
84
+ * `runWithTenantContext` scope (e.g. background workers, migrations). */
85
+ export function getTenantContext() {
86
+ return tenantContext.getStore();
87
+ }
88
+ /**
89
+ * Assert that the current code is running inside a tenant scope. Callers
90
+ * that legitimately need to refuse to operate without one (e.g. handlers
91
+ * that touch FORCE'd RLS tables) can use this instead of relying on the
92
+ * downstream "permission denied" error to surface the bug.
93
+ */
94
+ export function requireTenantContext() {
95
+ const ctx = tenantContext.getStore();
96
+ if (!ctx) {
97
+ throw new Error('requireTenantContext: no tenant scope active. Wrap your handler/worker in '
98
+ + 'runWithTenantContext({ orgId, isSuperAdmin }, ...) before any DB call.');
99
+ }
100
+ return ctx;
101
+ }
102
+ /**
103
+ * Open a transaction with RLS GUCs SET LOCAL from the current
104
+ * AsyncLocalStorage tenant context, then invoke `fn(tx)`.
105
+ *
106
+ * - When called outside a tenant scope (e.g. from a background job that
107
+ * doesn't have a caller identity), the transaction is opened with both
108
+ * GUCs cleared — RLS policies will return zero rows on FORCE'd tables.
109
+ * Callers that need a sysadmin-equivalent scope should wrap themselves in
110
+ * `runWithTenantContext({ isSuperAdmin: true }, …)` explicitly.
111
+ *
112
+ * - Uses `set_config(key, value, true)` (the boolean = `is_local`, i.e.
113
+ * transaction-scoped). Equivalent to `SET LOCAL` but takes the value as
114
+ * a parameter, which is what we want — Drizzle's `sql` template binds the
115
+ * value safely so an attacker-controlled `orgId` can't escape the quoting.
116
+ *
117
+ * - Returns whatever `fn` returns; throws whatever `fn` throws (Drizzle
118
+ * handles the COMMIT/ROLLBACK for us).
119
+ */
120
+ export async function withTenantTx(fn) {
121
+ const ctx = tenantContext.getStore();
122
+ if (!ctx) {
123
+ // Surface the bug instead of silently SET'ing empty GUCs. The default
124
+ // mode ('warn') logs an actionable trace so the bad call site is easy
125
+ // to find; production deployments that have finished the audit can set
126
+ // RLS_CONTEXT_MODE=strict to fail-fast at the call site (better stack
127
+ // trace than the Postgres "permission denied" that would otherwise
128
+ // surface from FORCE'd RLS).
129
+ const mode = getContextMode();
130
+ if (mode === 'strict') {
131
+ throw new Error('withTenantTx called outside a tenant scope. Wrap your handler/worker '
132
+ + 'in runWithTenantContext({ orgId, isSuperAdmin }, ...) before invoking '
133
+ + 'any service that touches RLS-enforced tables.');
134
+ }
135
+ if (mode === 'warn') {
136
+ // Include a synthetic stack so the offending call site is in the log.
137
+ logger.warn('withTenantTx called outside a tenant scope; RLS GUCs will be empty', {
138
+ stack: new Error('tenant-context missing').stack,
139
+ });
140
+ }
141
+ }
142
+ const orgId = ctx?.orgId ?? '';
143
+ const isSuperAdmin = ctx?.isSuperAdmin ? 'true' : 'false';
144
+ const statementTimeoutMs = getStatementTimeoutMs();
145
+ return db.transaction(async (tx) => {
146
+ // Set every transaction-scoped GUC in a SINGLE round-trip. `set_config()`
147
+ // returns its value, so multiple calls compose in one SELECT — previously
148
+ // these were 2–3 separate `tx.execute()` round-trips PER read, each a
149
+ // network hop that taxes the shared PgBouncer pool on the hot path. `true`
150
+ // = is_local (SET LOCAL semantics: auto-released on COMMIT/ROLLBACK). The
151
+ // driver binds the values as parameters, so a hostile org_id can't break out
152
+ // of the GUC syntax.
153
+ //
154
+ // The statement_timeout GUC bounds a runaway query so it can't hold a pooled
155
+ // connection open indefinitely (`SET LOCAL statement_timeout = $1` is rejected
156
+ // by Postgres, hence set_config with a bound ms value). Included in the same
157
+ // statement when enabled (>0), dropped entirely when disabled (0).
158
+ if (statementTimeoutMs > 0) {
159
+ await tx.execute(sql `SELECT set_config('app.org_id', ${orgId}, true), set_config('app.is_sysadmin', ${isSuperAdmin}, true), set_config('statement_timeout', ${String(statementTimeoutMs)}, true)`);
160
+ }
161
+ else {
162
+ await tx.execute(sql `SELECT set_config('app.org_id', ${orgId}, true), set_config('app.is_sysadmin', ${isSuperAdmin}, true)`);
163
+ }
164
+ return fn(tx);
165
+ });
166
+ }
167
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVuYW5jeS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9kYXRhYmFzZS90ZW5hbmN5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWlDRztBQUVILE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ3JELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUMxRCxPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ2xDLE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUU5QyxNQUFNLE1BQU0sR0FBRyxZQUFZLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztBQWU5QyxTQUFTLGNBQWM7SUFDckIsTUFBTSxHQUFHLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsRUFBRSxXQUFXLEVBQUUsQ0FBQztJQUN4RCxJQUFJLEdBQUcsS0FBSyxRQUFRLElBQUksR0FBRyxLQUFLLE1BQU0sSUFBSSxHQUFHLEtBQUssUUFBUTtRQUFFLE9BQU8sR0FBRyxDQUFDO0lBQ3ZFLHVFQUF1RTtJQUN2RSxPQUFPLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxLQUFLLFlBQVksQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUM7QUFDbkUsQ0FBQztBQUVEOzs7Ozs7OztHQVFHO0FBQ0gsU0FBUyxxQkFBcUI7SUFDNUIsTUFBTSxHQUFHLEdBQUcsUUFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsdUJBQXVCLElBQUksRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ3BFLE9BQU8sTUFBTSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FB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eXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbi8qKlxuICogVGVuYW50LWNvbnRleHQgcGx1bWJpbmcgZm9yIFBvc3RncmVzIHJvdy1sZXZlbCBzZWN1cml0eS5cbiAqXG4gKiBCYWNrZ3JvdW5kOiBwb3N0Z3Jlcy1pbml0LnNxbCBpbnN0YWxscyBSTFMgcG9saWNpZXMgb24gZXZlcnkgdXNlci1kYXRhXG4gKiB0YWJsZSB0aGF0IGNvbnN1bHQgdHdvIHNlc3Npb24gR1VDcyDigJQgYGFwcC5vcmdfaWRgIGFuZCBgYXBwLmlzX3N5c2FkbWluYC5cbiAqIE1vc3QgdXNlci1kYXRhIHRhYmxlcyBoYXZlIGJlZW4gZmxpcHBlZCB0byBgRk9SQ0UgUk9XIExFVkVMIFNFQ1VSSVRZYCwgc29cbiAqIHRoZSBwb2xpY2llcyBETyBlbmZvcmNlIGV2ZW4gZm9yIHRoZSAob3duaW5nKSBjb25uZWN0aW9uIHVzZXIg4oCUIGEgcXVlcnlcbiAqIGFnYWluc3QgYSBGT1JDRSdkIHRhYmxlIG11c3QgcnVuIGluc2lkZSBhIHRyYW5zYWN0aW9uIHRoYXQgaGFzIFNFVCBMT0NBTCdkXG4gKiBib3RoIEdVQ3Mgb3IgaXQgcmV0dXJucyB6ZXJvIHJvd3MgZm9yIG5vbi1zeXNhZG1pbnMgKGFuZCBtYXkgZmFpbCB0byB3cml0ZVxuICogZm9yIGFueSBjYWxsZXIpLiBBIGZldyB0YWJsZXMgcmVtYWluIGBFTkFCTEVgLW9ubHkgKG93bmVyLWJ5cGFzcykgcGVuZGluZ1xuICogdGhlaXIgc29hazsgdGhlIHNhbWUgY29udGV4dCBwbHVtYmluZyBjb3ZlcnMgYm90aC5cbiAqXG4gKiBUaGlzIG1vZHVsZSBpcyB0aGUgc2VhbS5cbiAqXG4gKiAgIDEuIGB0ZW5hbnRDb250ZXh0YCAoQXN5bmNMb2NhbFN0b3JhZ2UpIGNhcnJpZXMgYHtvcmdJZCwgaXNTdXBlckFkbWlufWBcbiAqICAgICAgZG93biB0aGUgY2FsbCBjaGFpbiB3aXRob3V0IHByb3AtZHJpbGxpbmcuIFNldCBvbmNlIGF0IHRoZSByZXF1ZXN0XG4gKiAgICAgIGJvdW5kYXJ5OyByZWFkYWJsZSBmcm9tIGFueXdoZXJlLlxuICpcbiAqICAgMi4gYHdpdGhUZW5hbnRUeChmbilgIG9wZW5zIGEgdHJhbnNhY3Rpb24sIFNFVCBMT0NBTCdzIGJvdGggR1VDcyBmcm9tXG4gKiAgICAgIHRoZSBzdXJyb3VuZGluZyBjb250ZXh0LCB0aGVuIGludm9rZXMgYGZuKHR4KWAuIFNlcnZpY2VzIG1pZ3JhdGUgb25lXG4gKiAgICAgIGF0IGEgdGltZSBieSB3cmFwcGluZyB0aGVpciBleGlzdGluZyBkcml6emxlIGNhbGxzIGluIHRoaXMgaGVscGVyIOKAlFxuICogICAgICBgZGIuc2VsZWN0KCkuZnJvbSguLi4pYCBiZWNvbWVzIGB3aXRoVGVuYW50VHgodHggPT4gdHguc2VsZWN0KCkuZnJvbSguLi4pKWAuXG4gKlxuICogICAzLiBgcnVuV2l0aFRlbmFudENvbnRleHQoY3R4LCBmbilgIGlzIHRoZSBFeHByZXNzLW1pZGRsZXdhcmUtc2lkZVxuICogICAgICBib29rZW5kIHRoYXQgZXN0YWJsaXNoZXMgdGhlIEFzeW5jTG9jYWxTdG9yYWdlIHNjb3BlIGZvciB0aGUgcmVxdWVzdC5cbiAqXG4gKiBNaWdyYXRpb24gb3JkZXIgKHNlZSBkb2NzL3BsYW5zL2YtMS0wLXJscy1lbmZvcmNlbWVudC5tZCk6XG4gKiAgIC0gRmlyc3QgYWRvcHRlcnM6IG5ld2x5LXdyaXR0ZW4gc2VydmljZXMgKGRhc2hib2FyZCwgYWxlcnQtZGVzdGluYXRpb24pXG4gKiAgICAgd2hlcmUgdGhlIGNoYW5nZSBpcyBtZWNoYW5pY2FsLlxuICogICAtIFRoZW4gaGlnaC13cml0ZSBzZXJ2aWNlcyAocGx1Z2luLCBwaXBlbGluZSkuIFNvYWsgZWFjaCBvbmUgYmVmb3JlXG4gKiAgICAgZmxpcHBpbmcgdGhlIHVuZGVybHlpbmcgdGFibGUgdG8gRk9SQ0UuXG4gKiAgIC0gYWRtaW5fYXVkaXRfbG9nIHVzZXMgYSBzeXNhZG1pbi1vbmx5IHBvbGljeSDigJQgc3lzYWRtaW4gcGF0aHMgbXVzdFxuICogICAgIGFsc28gc2V0IGBhcHAuaXNfc3lzYWRtaW4gPSAndHJ1ZSdgIG9yIHRoZXknbGwgbG9zZSBhY2Nlc3MgdG8gaXQuXG4gKi9cblxuaW1wb3J0IHsgQXN5bmNMb2NhbFN0b3JhZ2UgfSBmcm9tICdub2RlOmFzeW5jX2hvb2tzJztcbmltcG9ydCB7IGNyZWF0ZUxvZ2dlciB9IGZyb20gJ0BwaXBlbGluZS1idWlsZGVyL2FwaS1jb3JlJztcbmltcG9ydCB7IHNxbCB9IGZyb20gJ2RyaXp6bGUtb3JtJztcbmltcG9ydCB7IGRiIH0gZnJvbSAnLi9wb3N0Z3Jlcy1jb25uZWN0aW9uLmpzJztcblxuY29uc3QgbG9nZ2VyID0gY3JlYXRlTG9nZ2VyKCd0ZW5hbnQtY29udGV4dCcpO1xuXG4vKipcbiAqIEJlaGF2aW9yIHdoZW4gYHdpdGhUZW5hbnRUeGAgaXMgaW52b2tlZCBvdXRzaWRlIGFueSBgcnVuV2l0aFRlbmFudENvbnRleHRgXG4gKiBzY29wZS4gVGhlIGVmZmVjdGl2ZSBkZWZhdWx0IGlzIGZhaWwtZmFzdCAoJ3N0cmljdCcpIGluIHByb2R1Y3Rpb24gc28gYVxuICogbWlzc2luZyB0ZW5hbnQgc2NvcGUgc3VyZmFjZXMgYXQgdGhlIGJhZCBjYWxsIHNpdGUgaW5zdGVhZCBvZiBzaWxlbnRseVxuICogcnVubmluZyB3aXRoIGVtcHR5IFJMUyBHVUNzOyBvdXRzaWRlIHByb2R1Y3Rpb24gaXQgZGVmYXVsdHMgdG8gJ3dhcm4nIHNvXG4gKiB1bi1hdWRpdGVkIGRldi90ZXN0IHBhdGhzIGtlZXAgd29ya2luZyBidXQgbG9nIGFuIGFjdGlvbmFibGUgdHJhY2UuIEFuXG4gKiBleHBsaWNpdCBSTFNfQ09OVEVYVF9NT0RFIGVudiBvdmVycmlkZSBhbHdheXMgd2lucy5cbiAqXG4gKiAnc2lsZW50JyBpcyBrZXB0IGZvciB0ZXN0cyBhbmQgc2NyaXB0cyB0aGF0IGludGVudGlvbmFsbHkgZW50ZXIgdGhlIERCXG4gKiB3aXRob3V0IGNvbnRleHQgKGUuZy4gaW50ZWdyYXRpb24gdGVzdCBzZXR1cCB0aGF0IHJ1bnMgYXMgdGhlIGNvbm5lY3Rpb25cbiAqIG93bmVyIGJlZm9yZSBhbnkgdGVuYW50IGlzIHByb3Zpc2lvbmVkKS5cbiAqL1xudHlwZSBDb250ZXh0TW9kZSA9ICdzaWxlbnQnIHwgJ3dhcm4nIHwgJ3N0cmljdCc7XG5mdW5jdGlvbiBnZXRDb250ZXh0TW9kZSgpOiBDb250ZXh0TW9kZSB7XG4gIGNvbnN0IHJhdyA9IHByb2Nlc3MuZW52LlJMU19DT05URVhUX01PREU/LnRvTG93ZXJDYXNlKCk7XG4gIGlmIChyYXcgPT09ICdzaWxlbnQnIHx8IHJhdyA9PT0gJ3dhcm4nIHx8IHJhdyA9PT0gJ3N0cmljdCcpIHJldHVybiByYXc7XG4gIC8vIE5vIGV4cGxpY2l0IG92ZXJyaWRlOiBmYWlsLWZhc3QgaW4gcHJvZHVjdGlvbiwgd2FybiBldmVyeXdoZXJlIGVsc2UuXG4gIHJldHVybiBwcm9jZXNzLmVudi5OT0RFX0VOViA9PT0gJ3Byb2R1Y3Rpb24nID8gJ3N0cmljdCcgOiAnd2Fybic7XG59XG5cbi8qKlxuICogUGVyLXN0YXRlbWVudCBzZXJ2ZXItc2lkZSB0aW1lb3V0IChtcykgYXBwbGllZCBJTlNJREUgZXZlcnkgYHdpdGhUZW5hbnRUeGBcbiAqIHRyYW5zYWN0aW9uLCBuZXh0IHRvIHRoZSBSTFMgR1VDcy4gYHdpdGhUZW5hbnRUeGAgaXMgdGhlIHJlYWwgcXVlcnkgcGF0aCBmb3JcbiAqIGFsbCBSTFMvQ1JVRCByZWFkcyBhbmQgd3JpdGVzLCBzbyB0aGlzIGlzIHdoZXJlIHRoZSBEQi1zaWRlIGd1YXJkIGJlbG9uZ3MgKHRoZVxuICogb2xkIGBDb25uZWN0aW9uLnRyYW5zYWN0aW9uYCB3cmFwcGVyIHRoYXQgc2V0IGl0IGlzIGRlYWQg4oCUIHNlZVxuICogcG9zdGdyZXMtY29ubmVjdGlvbi50cykuIEJvdW5kcyBhIHJ1bmF3YXkgcXVlcnkgc28gaXQgY2FuJ3QgaG9sZCBhIHBvb2xlZFxuICogY29ubmVjdGlvbiBvcGVuIGluZGVmaW5pdGVseS4gRW52LWNvbmZpZ3VyYWJsZSB2aWEgYERCX1NUQVRFTUVOVF9USU1FT1VUX01TYFxuICogKGRlZmF1bHQgMzBzKTsgc2V0IHRvIGAwYCB0byBkaXNhYmxlIHRoZSB0aW1lb3V0LlxuICovXG5mdW5jdGlvbiBnZXRTdGF0ZW1lbnRUaW1lb3V0TXMoKTogbnVtYmVyIHtcbiAgY29uc3QgcmF3ID0gcGFyc2VJbnQocHJvY2Vzcy5lbnYuREJfU1RBVEVNRU5UX1RJTUVPVVRfTVMgPz8gJycsIDEwKTtcbiAgcmV0dXJuIE51bWJlci5pc0Zpbml0ZShyYXcpICYmIHJhdyA+PSAwID8gcmF3IDogMzAwMDA7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVGVuYW50Q29udGV4dCB7XG4gIC8qKiBDYWxsZXIncyBvcmcuIFVuZGVmaW5lZCBmb3IgdW4tYXV0aGVudGljYXRlZCAvIHN5c3RlbSBqb2JzLiAqL1xuICBvcmdJZD86IHN0cmluZztcbiAgLyoqIENhbGxlcidzIHVzZXIgaWQuIE5vdCB1c2VkIGZvciBSTFMg4oCUIFBvc3RncmVzIHBvbGljaWVzIGFyZSBvcmctZ3JhaW5lZCxcbiAgICogIHdpdGggbm8gcGVyLXVzZXIgc2Vzc2lvbiBHVUMg4oCUIGJ1dCBjYXJyaWVkIHNvIGFwcC1sYXllciBwcmVkaWNhdGVzIHdpdGggYVxuICAgKiAgUEVSLVVTRVIgcnVuZyAocGlwZWxpbmUgdGVtcGxhdGVzJyBgcHJpdmF0ZWAgdmlzaWJpbGl0eSkgY2FuIHJlc29sdmUgXCJ3aG9cbiAgICogIGlzIGFza2luZ1wiIG9uIHBhdGhzIHRoYXQgaGF2ZSBub3doZXJlIHRvIHBhc3MgaXQsIG5vdGFibHkgQ3J1ZFNlcnZpY2Unc1xuICAgKiAgYHdyaXRlQ29uZGl0aW9uc2AuIEFic2VudCBmb3Igc3lzdGVtIGpvYnMsIHdoaWNoIGlzIHRoZSBmYWlsLWNsb3NlZCBjYXNlOlxuICAgKiAgbm8gdmlld2VyIOKHkiBubyBwcml2YXRlIHJvd3MuICovXG4gIHVzZXJJZD86IHN0cmluZztcbiAgLyoqIFRydWUgd2hlbiB0aGUgY2FsbGVyIGlzIGEgc3lzYWRtaW4gKHN5c3RlbS1vcmcgYWRtaW4pLiBCeXBhc3NlcyBSTFNcbiAgICogIHBvbGljaWVzIHZpYSB0aGUgc3lzYWRtaW4tYnlwYXNzIGJyYW5jaCBpbiBgY3VycmVudF9pc19zeXNhZG1pbigpYC4gKi9cbiAgaXNTdXBlckFkbWluOiBib29sZWFuO1xuICAvKiogT3JnIOKGkiB0ZWFtIGhpZXJhcmNoeTogdGhlIGNhbGxlcidzIGFjdGl2ZS1vcmcgcGFyZW50IChwcmVzZW50IG9ubHkgd2hlbiB0aGVcbiAgICogIGFjdGl2ZSBvcmcgaXMgYSB0ZWFtKS4gTm90IHVzZWQgZm9yIFJMUzsgY2FycmllZCBzbyBkb3duc3RyZWFtIHNpZGUtZWZmZWN0c1xuICAgKiAgKGUuZy4gZW50aXR5LWV2ZW50IGNvbXBsaWFuY2UgZXZhbCkgY2FuIGhvbm9yIHBhcmVudCBgcHJvcGFnYXRlVG9DaGlsZHJlbmBcbiAgICogIHJ1bGVzIHdpdGhvdXQgYSByZXF1ZXN0IGluIHNjb3BlLiAqL1xuICBwYXJlbnRPcmdJZD86IHN0cmluZztcbn1cblxuLyoqXG4gKiBQZXItcmVxdWVzdCB0ZW5hbnQgY29udGV4dC4gUG9wdWxhdGVkIGJ5IEV4cHJlc3MgbWlkZGxld2FyZSBvbmNlIHRoZSBKV1RcbiAqIGlzIHZhbGlkYXRlZDsgY29uc3VtZWQgYnkgYHdpdGhUZW5hbnRUeGAgYW5kIGFueSBoZWxwZXIgdGhhdCBuZWVkcyB0b1xuICoga25vdyBcIndobyBpcyB0aGUgY2FsbGVyXCIgd2l0aG91dCByZS1kZXJpdmluZyBmcm9tIHRoZSByZXF1ZXN0IG9iamVjdC5cbiAqL1xuZXhwb3J0IGNvbnN0IHRlbmFudENvbnRleHQgPSBuZXcgQXN5bmNMb2NhbFN0b3JhZ2U8VGVuYW50Q29udGV4dD4oKTtcblxuLyoqXG4gKiBSdW4gYGZuYCBpbnNpZGUgdGhlIGdpdmVuIHRlbmFudCBzY29wZS4gVGhlIEFzeW5jTG9jYWxTdG9yYWdlIHNjb3BlXG4gKiBzdXJ2aXZlcyBhY3Jvc3MgYXN5bmMgYm91bmRhcmllcyAoUHJvbWlzZXMsIHNldFRpbWVvdXQsIGV0Yy4pLCBzbyBhbnlcbiAqIGB3aXRoVGVuYW50VHhgIGNhbGwgaW5zaWRlIGBmbmAg4oCUIGRpcmVjdGx5IG9yIHRocm91Z2ggYW55IGRlcHRoIG9mXG4gKiBhc3luYyBoZWxwZXJzIOKAlCBwaWNrcyB1cCBgY3R4YC5cbiAqXG4gKiBXcmFwIGBuZXh0KClgIGZyb20gYW4gRXhwcmVzcyBtaWRkbGV3YXJlIHRvIGVzdGFibGlzaCBwZXItcmVxdWVzdCBzY29wZTpcbiAqXG4gKiAgICAgYXBwLnVzZSgocmVxLCByZXMsIG5leHQpID0+IHtcbiAqICAgICAgIHJ1bldpdGhUZW5hbnRDb250ZXh0KHsgb3JnSWQsIGlzU3VwZXJBZG1pbiB9LCAoKSA9PiBuZXh0KCkpO1xuICogICAgIH0pO1xuICovXG5leHBvcnQgZnVuY3Rpb24gcnVuV2l0aFRlbmFudENvbnRleHQ8VD4oY3R4OiBUZW5hbnRDb250ZXh0LCBmbjogKCkgPT4gVCk6IFQge1xuICByZXR1cm4gdGVuYW50Q29udGV4dC5ydW4oY3R4LCBmbik7XG59XG5cbi8qKiBSZWFkIHRoZSBjdXJyZW50IHRlbmFudCBjb250ZXh0LiBSZXR1cm5zIHVuZGVmaW5lZCBvdXRzaWRlIGFuXG4gKiAgYHJ1bldpdGhUZW5hbnRDb250ZXh0YCBzY29wZSAoZS5nLiBiYWNrZ3JvdW5kIHdvcmtlcnMsIG1pZ3JhdGlvbnMpLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFRlbmFudENvbnRleHQoKTogVGVuYW50Q29udGV4dCB8IHVuZGVmaW5lZCB7XG4gIHJldHVybiB0ZW5hbnRDb250ZXh0LmdldFN0b3JlKCk7XG59XG5cbi8qKlxuICogQXNzZXJ0IHRoYXQgdGhlIGN1cnJlbnQgY29kZSBpcyBydW5uaW5nIGluc2lkZSBhIHRlbmFudCBzY29wZS4gQ2FsbGVyc1xuICogdGhhdCBsZWdpdGltYXRlbHkgbmVlZCB0byByZWZ1c2UgdG8gb3BlcmF0ZSB3aXRob3V0IG9uZSAoZS5nLiBoYW5kbGVyc1xuICogdGhhdCB0b3VjaCBGT1JDRSdkIFJMUyB0YWJsZXMpIGNhbiB1c2UgdGhpcyBpbnN0ZWFkIG9mIHJlbHlpbmcgb24gdGhlXG4gKiBkb3duc3RyZWFtIFwicGVybWlzc2lvbiBkZW5pZWRcIiBlcnJvciB0byBzdXJmYWNlIHRoZSBidWcuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlVGVuYW50Q29udGV4dCgpOiBUZW5hbnRDb250ZXh0IHtcbiAgY29uc3QgY3R4ID0gdGVuYW50Q29udGV4dC5nZXRTdG9yZSgpO1xuICBpZiAoIWN0eCkge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICdyZXF1aXJlVGVuYW50Q29udGV4dDogbm8gdGVuYW50IHNjb3BlIGFjdGl2ZS4gV3JhcCB5b3VyIGhhbmRsZXIvd29ya2VyIGluICdcbiAgICAgICsgJ3J1bldpdGhUZW5hbnRDb250ZXh0KHsgb3JnSWQsIGlzU3VwZXJBZG1pbiB9LCAuLi4pIGJlZm9yZSBhbnkgREIgY2FsbC4nLFxuICAgICk7XG4gIH1cbiAgcmV0dXJuIGN0eDtcbn1cblxuLyoqXG4gKiBPcGVuIGEgdHJhbnNhY3Rpb24gd2l0aCBSTFMgR1VDcyBTRVQgTE9DQUwgZnJvbSB0aGUgY3VycmVudFxuICogQXN5bmNMb2NhbFN0b3JhZ2UgdGVuYW50IGNvbnRleHQsIHRoZW4gaW52b2tlIGBmbih0eClgLlxuICpcbiAqIC0gV2hlbiBjYWxsZWQgb3V0c2lkZSBhIHRlbmFudCBzY29wZSAoZS5nLiBmcm9tIGEgYmFja2dyb3VuZCBqb2IgdGhhdFxuICogICBkb2Vzbid0IGhhdmUgYSBjYWxsZXIgaWRlbnRpdHkpLCB0aGUgdHJhbnNhY3Rpb24gaXMgb3BlbmVkIHdpdGggYm90aFxuICogICBHVUNzIGNsZWFyZWQg4oCUIFJMUyBwb2xpY2llcyB3aWxsIHJldHVybiB6ZXJvIHJvd3Mgb24gRk9SQ0UnZCB0YWJsZXMuXG4gKiAgIENhbGxlcnMgdGhhdCBuZWVkIGEgc3lzYWRtaW4tZXF1aXZhbGVudCBzY29wZSBzaG91bGQgd3JhcCB0aGVtc2VsdmVzIGluXG4gKiAgIGBydW5XaXRoVGVuYW50Q29udGV4dCh7IGlzU3VwZXJBZG1pbjogdHJ1ZSB9LCDigKYpYCBleHBsaWNpdGx5LlxuICpcbiAqIC0gVXNlcyBgc2V0X2NvbmZpZyhrZXksIHZhbHVlLCB0cnVlKWAgKHRoZSBib29sZWFuID0gYGlzX2xvY2FsYCwgaS5lLlxuICogICB0cmFuc2FjdGlvbi1zY29wZWQpLiBFcXVpdmFsZW50IHRvIGBTRVQgTE9DQUxgIGJ1dCB0YWtlcyB0aGUgdmFsdWUgYXNcbiAqICAgYSBwYXJhbWV0ZXIsIHdoaWNoIGlzIHdoYXQgd2Ugd2FudCDigJQgRHJpenpsZSdzIGBzcWxgIHRlbXBsYXRlIGJpbmRzIHRoZVxuICogICB2YWx1ZSBzYWZlbHkgc28gYW4gYXR0YWNrZXItY29udHJvbGxlZCBgb3JnSWRgIGNhbid0IGVzY2FwZSB0aGUgcXVvdGluZy5cbiAqXG4gKiAtIFJldHVybnMgd2hhdGV2ZXIgYGZuYCByZXR1cm5zOyB0aHJvd3Mgd2hhdGV2ZXIgYGZuYCB0aHJvd3MgKERyaXp6bGVcbiAqICAgaGFuZGxlcyB0aGUgQ09NTUlUL1JPTExCQUNLIGZvciB1cykuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB3aXRoVGVuYW50VHg8VD4oXG4gIGZuOiAodHg6IFBhcmFtZXRlcnM8UGFyYW1ldGVyczx0eXBlb2YgZGIudHJhbnNhY3Rpb24+WzBdPlswXSkgPT4gUHJvbWlzZTxUPixcbik6IFByb21pc2U8VD4ge1xuICBjb25zdCBjdHggPSB0ZW5hbnRDb250ZXh0LmdldFN0b3JlKCk7XG5cbiAgaWYgKCFjdHgpIHtcbiAgICAvLyBTdXJmYWNlIHRoZSBidWcgaW5zdGVhZCBvZiBzaWxlbnRseSBTRVQnaW5nIGVtcHR5IEdVQ3MuIFRoZSBkZWZhdWx0XG4gICAgLy8gbW9kZSAoJ3dhcm4nKSBsb2dzIGFuIGFjdGlvbmFibGUgdHJhY2Ugc28gdGhlIGJhZCBjYWxsIHNpdGUgaXMgZWFzeVxuICAgIC8vIHRvIGZpbmQ7IHByb2R1Y3Rpb24gZGVwbG95bWVudHMgdGhhdCBoYXZlIGZpbmlzaGVkIHRoZSBhdWRpdCBjYW4gc2V0XG4gICAgLy8gUkxTX0NPTlRFWFRfTU9ERT1zdHJpY3QgdG8gZmFpbC1mYXN0IGF0IHRoZSBjYWxsIHNpdGUgKGJldHRlciBzdGFja1xuICAgIC8vIHRyYWNlIHRoYW4gdGhlIFBvc3RncmVzIFwicGVybWlzc2lvbiBkZW5pZWRcIiB0aGF0IHdvdWxkIG90aGVyd2lzZVxuICAgIC8vIHN1cmZhY2UgZnJvbSBGT1JDRSdkIFJMUykuXG4gICAgY29uc3QgbW9kZSA9IGdldENvbnRleHRNb2RlKCk7XG4gICAgaWYgKG1vZGUgPT09ICdzdHJpY3QnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICd3aXRoVGVuYW50VHggY2FsbGVkIG91dHNpZGUgYSB0ZW5hbnQgc2NvcGUuIFdyYXAgeW91ciBoYW5kbGVyL3dvcmtlciAnXG4gICAgICAgICsgJ2luIHJ1bldpdGhUZW5hbnRDb250ZXh0KHsgb3JnSWQsIGlzU3VwZXJBZG1pbiB9LCAuLi4pIGJlZm9yZSBpbnZva2luZyAnXG4gICAgICAgICsgJ2FueSBzZXJ2aWNlIHRoYXQgdG91Y2hlcyBSTFMtZW5mb3JjZWQgdGFibGVzLicsXG4gICAgICApO1xuICAgIH1cbiAgICBpZiAobW9kZSA9PT0gJ3dhcm4nKSB7XG4gICAgICAvLyBJbmNsdWRlIGEgc3ludGhldGljIHN0YWNrIHNvIHRoZSBvZmZlbmRpbmcgY2FsbCBzaXRlIGlzIGluIHRoZSBsb2cuXG4gICAgICBsb2dnZXIud2Fybignd2l0aFRlbmFudFR4IGNhbGxlZCBvdXRzaWRlIGEgdGVuYW50IHNjb3BlOyBSTFMgR1VDcyB3aWxsIGJlIGVtcHR5Jywge1xuICAgICAgICBzdGFjazogbmV3IEVycm9yKCd0ZW5hbnQtY29udGV4dCBtaXNzaW5nJykuc3RhY2ssXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBjb25zdCBvcmdJZCA9IGN0eD8ub3JnSWQgPz8gJyc7XG4gIGNvbnN0IGlzU3VwZXJBZG1pbiA9IGN0eD8uaXNTdXBlckFkbWluID8gJ3RydWUnIDogJ2ZhbHNlJztcblxuICBjb25zdCBzdGF0ZW1lbnRUaW1lb3V0TXMgPSBnZXRTdGF0ZW1lbnRUaW1lb3V0TXMoKTtcblxuICByZXR1cm4gZGIudHJhbnNhY3Rpb24oYXN5bmMgKHR4KSA9PiB7XG4gICAgLy8gU2V0IGV2ZXJ5IHRyYW5zYWN0aW9uLXNjb3BlZCBHVUMgaW4gYSBTSU5HTEUgcm91bmQtdHJpcC4gYHNldF9jb25maWcoKWBcbiAgICAvLyByZXR1cm5zIGl0cyB2YWx1ZSwgc28gbXVsdGlwbGUgY2FsbHMgY29tcG9zZSBpbiBvbmUgU0VMRUNUIOKAlCBwcmV2aW91c2x5XG4gICAgLy8gdGhlc2Ugd2VyZSAy4oCTMyBzZXBhcmF0ZSBgdHguZXhlY3V0ZSgpYCByb3VuZC10cmlwcyBQRVIgcmVhZCwgZWFjaCBhXG4gICAgLy8gbmV0d29yayBob3AgdGhhdCB0YXhlcyB0aGUgc2hhcmVkIFBnQm91bmNlciBwb29sIG9uIHRoZSBob3QgcGF0aC4gYHRydWVgXG4gICAgLy8gPSBpc19sb2NhbCAoU0VUIExPQ0FMIHNlbWFudGljczogYXV0by1yZWxlYXNlZCBvbiBDT01NSVQvUk9MTEJBQ0spLiBUaGVcbiAgICAvLyBkcml2ZXIgYmluZHMgdGhlIHZhbHVlcyBhcyBwYXJhbWV0ZXJzLCBzbyBhIGhvc3RpbGUgb3JnX2lkIGNhbid0IGJyZWFrIG91dFxuICAgIC8vIG9mIHRoZSBHVUMgc3ludGF4LlxuICAgIC8vXG4gICAgLy8gVGhlIHN0YXRlbWVudF90aW1lb3V0IEdVQyBib3VuZHMgYSBydW5hd2F5IHF1ZXJ5IHNvIGl0IGNhbid0IGhvbGQgYSBwb29sZWRcbiAgICAvLyBjb25uZWN0aW9uIG9wZW4gaW5kZWZpbml0ZWx5IChgU0VUIExPQ0FMIHN0YXRlbWVudF90aW1lb3V0ID0gJDFgIGlzIHJlamVjdGVkXG4gICAgLy8gYnkgUG9zdGdyZXMsIGhlbmNlIHNldF9jb25maWcgd2l0aCBhIGJvdW5kIG1zIHZhbHVlKS4gSW5jbHVkZWQgaW4gdGhlIHNhbWVcbiAgICAvLyBzdGF0ZW1lbnQgd2hlbiBlbmFibGVkICg+MCksIGRyb3BwZWQgZW50aXJlbHkgd2hlbiBkaXNhYmxlZCAoMCkuXG4gICAgaWYgKHN0YXRlbWVudFRpbWVvdXRNcyA+IDApIHtcbiAgICAgIGF3YWl0IHR4LmV4ZWN1dGUoXG4gICAgICAgIHNxbGBTRUxFQ1Qgc2V0X2NvbmZpZygnYXBwLm9yZ19pZCcsICR7b3JnSWR9LCB0cnVlKSwgc2V0X2NvbmZpZygnYXBwLmlzX3N5c2FkbWluJywgJHtpc1N1cGVyQWRtaW59LCB0cnVlKSwgc2V0X2NvbmZpZygnc3RhdGVtZW50X3RpbWVvdXQnLCAke1N0cmluZyhzdGF0ZW1lbnRUaW1lb3V0TXMpfSwgdHJ1ZSlgLFxuICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgYXdhaXQgdHguZXhlY3V0ZShcbiAgICAgICAgc3FsYFNFTEVDVCBzZXRfY29uZmlnKCdhcHAub3JnX2lkJywgJHtvcmdJZH0sIHRydWUpLCBzZXRfY29uZmlnKCdhcHAuaXNfc3lzYWRtaW4nLCAke2lzU3VwZXJBZG1pbn0sIHRydWUpYCxcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBmbih0eCk7XG4gIH0pO1xufVxuIl19
package/lib/index.d.ts ADDED
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @module @pipeline-builder/pipeline-data
3
+ *
4
+ * Database layer: Drizzle ORM schemas, connection management, and query infrastructure.
5
+ *
6
+ * **Database**
7
+ * - db — shared Drizzle database instance
8
+ * - getConnection, closeConnection — PostgreSQL connection lifecycle with retry logic
9
+ * - schema — Drizzle table definitions (plugins, pipelines, messages, compliance, etc.)
10
+ *
11
+ * **Services**
12
+ * - CrudService — generic base class for multi-tenant CRUD with access control and pagination
13
+ * - ReportingService — aggregate query and reporting base class
14
+ *
15
+ * **Query Builders**
16
+ * - buildPluginConditions, buildPipelineConditions, buildMessageConditions — filter-to-SQL condition builders
17
+ * - buildCompliancePolicyConditions, buildComplianceRuleConditions, etc. — compliance query builders
18
+ * - AccessControlBuilder — row-level access control condition builder
19
+ *
20
+ * **Filters**
21
+ * - PluginFilter, PipelineFilter, MessageFilter — typed filter interfaces
22
+ * - CompliancePolicyFilter, ComplianceRuleFilter, etc. — compliance filter interfaces
23
+ * - drizzleRows, drizzleCount — Drizzle result type helpers
24
+ */
25
+ export * from './database/index.js';
26
+ export * from './api/query-builders.js';
27
+ export * from './api/access-control-builder.js';
28
+ export * from './api/viewer-context.js';
29
+ export * from './api/crud-service.js';
30
+ export * from './api/soft-delete-sweep.js';
31
+ export * from './api/reporting-service.js';
32
+ export * from './core/query-filters.js';
package/lib/index.js ADDED
@@ -0,0 +1,38 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * @module @pipeline-builder/pipeline-data
5
+ *
6
+ * Database layer: Drizzle ORM schemas, connection management, and query infrastructure.
7
+ *
8
+ * **Database**
9
+ * - db — shared Drizzle database instance
10
+ * - getConnection, closeConnection — PostgreSQL connection lifecycle with retry logic
11
+ * - schema — Drizzle table definitions (plugins, pipelines, messages, compliance, etc.)
12
+ *
13
+ * **Services**
14
+ * - CrudService — generic base class for multi-tenant CRUD with access control and pagination
15
+ * - ReportingService — aggregate query and reporting base class
16
+ *
17
+ * **Query Builders**
18
+ * - buildPluginConditions, buildPipelineConditions, buildMessageConditions — filter-to-SQL condition builders
19
+ * - buildCompliancePolicyConditions, buildComplianceRuleConditions, etc. — compliance query builders
20
+ * - AccessControlBuilder — row-level access control condition builder
21
+ *
22
+ * **Filters**
23
+ * - PluginFilter, PipelineFilter, MessageFilter — typed filter interfaces
24
+ * - CompliancePolicyFilter, ComplianceRuleFilter, etc. — compliance filter interfaces
25
+ * - drizzleRows, drizzleCount — Drizzle result type helpers
26
+ */
27
+ // Database
28
+ export * from './database/index.js';
29
+ // Query builders and services
30
+ export * from './api/query-builders.js';
31
+ export * from './api/access-control-builder.js';
32
+ export * from './api/viewer-context.js';
33
+ export * from './api/crud-service.js';
34
+ export * from './api/soft-delete-sweep.js';
35
+ export * from './api/reporting-service.js';
36
+ // Filters
37
+ export * from './core/query-filters.js';
38
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0Qzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F1Qkc7QUFFSCxXQUFXO0FBQ1gsY0FBYyxxQkFBcUIsQ0FBQztBQUVwQyw4QkFBOEI7QUFDOUIsY0FBYyx5QkFBeUIsQ0FBQztBQUN4QyxjQUFjLGlDQUFpQyxDQUFDO0FBQ2hELGNBQWMseUJBQXlCLENBQUM7QUFDeEMsY0FBYyx1QkFBdUIsQ0FBQztBQUN0QyxjQUFjLDRCQUE0QixDQUFDO0FBQzNDLGNBQWMsNEJBQTRCLENBQUM7QUFFM0MsVUFBVTtBQUNWLGNBQWMseUJBQXlCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuLyoqXG4gKiBAbW9kdWxlIEBwaXBlbGluZS1idWlsZGVyL3BpcGVsaW5lLWRhdGFcbiAqXG4gKiBEYXRhYmFzZSBsYXllcjogRHJpenpsZSBPUk0gc2NoZW1hcywgY29ubmVjdGlvbiBtYW5hZ2VtZW50LCBhbmQgcXVlcnkgaW5mcmFzdHJ1Y3R1cmUuXG4gKlxuICogKipEYXRhYmFzZSoqXG4gKiAtIGRiIOKAlCBzaGFyZWQgRHJpenpsZSBkYXRhYmFzZSBpbnN0YW5jZVxuICogLSBnZXRDb25uZWN0aW9uLCBjbG9zZUNvbm5lY3Rpb24g4oCUIFBvc3RncmVTUUwgY29ubmVjdGlvbiBsaWZlY3ljbGUgd2l0aCByZXRyeSBsb2dpY1xuICogLSBzY2hlbWEg4oCUIERyaXp6bGUgdGFibGUgZGVmaW5pdGlvbnMgKHBsdWdpbnMsIHBpcGVsaW5lcywgbWVzc2FnZXMsIGNvbXBsaWFuY2UsIGV0Yy4pXG4gKlxuICogKipTZXJ2aWNlcyoqXG4gKiAtIENydWRTZXJ2aWNlIOKAlCBnZW5lcmljIGJhc2UgY2xhc3MgZm9yIG11bHRpLXRlbmFudCBDUlVEIHdpdGggYWNjZXNzIGNvbnRyb2wgYW5kIHBhZ2luYXRpb25cbiAqIC0gUmVwb3J0aW5nU2VydmljZSDigJQgYWdncmVnYXRlIHF1ZXJ5IGFuZCByZXBvcnRpbmcgYmFzZSBjbGFzc1xuICpcbiAqICoqUXVlcnkgQnVpbGRlcnMqKlxuICogLSBidWlsZFBsdWdpbkNvbmRpdGlvbnMsIGJ1aWxkUGlwZWxpbmVDb25kaXRpb25zLCBidWlsZE1lc3NhZ2VDb25kaXRpb25zIOKAlCBmaWx0ZXItdG8tU1FMIGNvbmRpdGlvbiBidWlsZGVyc1xuICogLSBidWlsZENvbXBsaWFuY2VQb2xpY3lDb25kaXRpb25zLCBidWlsZENvbXBsaWFuY2VSdWxlQ29uZGl0aW9ucywgZXRjLiDigJQgY29tcGxpYW5jZSBxdWVyeSBidWlsZGVyc1xuICogLSBBY2Nlc3NDb250cm9sQnVpbGRlciDigJQgcm93LWxldmVsIGFjY2VzcyBjb250cm9sIGNvbmRpdGlvbiBidWlsZGVyXG4gKlxuICogKipGaWx0ZXJzKipcbiAqIC0gUGx1Z2luRmlsdGVyLCBQaXBlbGluZUZpbHRlciwgTWVzc2FnZUZpbHRlciDigJQgdHlwZWQgZmlsdGVyIGludGVyZmFjZXNcbiAqIC0gQ29tcGxpYW5jZVBvbGljeUZpbHRlciwgQ29tcGxpYW5jZVJ1bGVGaWx0ZXIsIGV0Yy4g4oCUIGNvbXBsaWFuY2UgZmlsdGVyIGludGVyZmFjZXNcbiAqIC0gZHJpenpsZVJvd3MsIGRyaXp6bGVDb3VudCDigJQgRHJpenpsZSByZXN1bHQgdHlwZSBoZWxwZXJzXG4gKi9cblxuLy8gRGF0YWJhc2VcbmV4cG9ydCAqIGZyb20gJy4vZGF0YWJhc2UvaW5kZXguanMnO1xuXG4vLyBRdWVyeSBidWlsZGVycyBhbmQgc2VydmljZXNcbmV4cG9ydCAqIGZyb20gJy4vYXBpL3F1ZXJ5LWJ1aWxkZXJzLmpzJztcbmV4cG9ydCAqIGZyb20gJy4vYXBpL2FjY2Vzcy1jb250cm9sLWJ1aWxkZXIuanMnO1xuZXhwb3J0ICogZnJvbSAnLi9hcGkvdmlld2VyLWNvbnRleHQuanMnO1xuZXhwb3J0ICogZnJvbSAnLi9hcGkvY3J1ZC1zZXJ2aWNlLmpzJztcbmV4cG9ydCAqIGZyb20gJy4vYXBpL3NvZnQtZGVsZXRlLXN3ZWVwLmpzJztcbmV4cG9ydCAqIGZyb20gJy4vYXBpL3JlcG9ydGluZy1zZXJ2aWNlLmpzJztcblxuLy8gRmlsdGVyc1xuZXhwb3J0ICogZnJvbSAnLi9jb3JlL3F1ZXJ5LWZpbHRlcnMuanMnO1xuIl19