@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.
- package/LICENSE +202 -0
- package/README.md +61 -0
- package/drizzle.config.ts +17 -0
- package/lib/api/access-control-builder.d.ts +148 -0
- package/lib/api/access-control-builder.js +199 -0
- package/lib/api/crud-service.d.ts +343 -0
- package/lib/api/crud-service.js +849 -0
- package/lib/api/query-builders.d.ts +82 -0
- package/lib/api/query-builders.js +460 -0
- package/lib/api/reporting-service.d.ts +685 -0
- package/lib/api/reporting-service.js +1564 -0
- package/lib/api/soft-delete-sweep.d.ts +65 -0
- package/lib/api/soft-delete-sweep.js +124 -0
- package/lib/api/viewer-context.d.ts +29 -0
- package/lib/api/viewer-context.js +63 -0
- package/lib/core/query-filters.d.ts +263 -0
- package/lib/core/query-filters.js +4 -0
- package/lib/database/drizzle-schema.d.ts +7357 -0
- package/lib/database/drizzle-schema.js +66 -0
- package/lib/database/index.d.ts +5 -0
- package/lib/database/index.js +8 -0
- package/lib/database/migrator.d.ts +20 -0
- package/lib/database/migrator.js +80 -0
- package/lib/database/postgres-connection.d.ts +201 -0
- package/lib/database/postgres-connection.js +413 -0
- package/lib/database/retry-strategy.d.ts +68 -0
- package/lib/database/retry-strategy.js +122 -0
- package/lib/database/schema/alert.d.ts +588 -0
- package/lib/database/schema/alert.js +130 -0
- package/lib/database/schema/compliance.d.ts +3319 -0
- package/lib/database/schema/compliance.js +377 -0
- package/lib/database/schema/dashboard.d.ts +474 -0
- package/lib/database/schema/dashboard.js +129 -0
- package/lib/database/schema/message-attachment.d.ts +183 -0
- package/lib/database/schema/message-attachment.js +40 -0
- package/lib/database/schema/message.d.ts +411 -0
- package/lib/database/schema/message.js +114 -0
- package/lib/database/schema/pipeline-template.d.ts +466 -0
- package/lib/database/schema/pipeline-template.js +80 -0
- package/lib/database/schema/pipeline.d.ts +1613 -0
- package/lib/database/schema/pipeline.js +332 -0
- package/lib/database/schema/plugin.d.ts +749 -0
- package/lib/database/schema/plugin.js +166 -0
- package/lib/database/tenancy.d.ts +103 -0
- package/lib/database/tenancy.js +167 -0
- package/lib/index.d.ts +32 -0
- package/lib/index.js +38 -0
- 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
|