node-type-registry 0.21.0 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/authz/authz-app-membership.d.ts +2 -0
- package/authz/{authz-membership-check.js → authz-app-membership.js} +17 -23
- package/authz/index.d.ts +1 -1
- package/authz/index.js +3 -3
- package/blueprint-types.generated.d.ts +339 -270
- package/blueprint-types.generated.js +6 -0
- package/codegen/generate-types.js +105 -4
- package/data/data-feature-flag.d.ts +2 -0
- package/data/data-feature-flag.js +33 -0
- package/data/data-image-embedding.d.ts +2 -0
- package/data/data-image-embedding.js +80 -0
- package/data/data-job-trigger.js +38 -1
- package/data/data-limit-counter.d.ts +2 -0
- package/data/data-limit-counter.js +42 -0
- package/data/data-ownership-in-entity.js +12 -0
- package/data/data-peoplestamps.js +12 -0
- package/data/data-publishable.js +12 -0
- package/data/data-soft-delete.js +12 -0
- package/data/data-timestamps.js +12 -0
- package/data/index.d.ts +3 -0
- package/data/index.js +7 -1
- package/esm/authz/authz-app-membership.d.ts +2 -0
- package/esm/authz/{authz-membership-check.js → authz-app-membership.js} +16 -22
- package/esm/authz/index.d.ts +1 -1
- package/esm/authz/index.js +1 -1
- package/esm/blueprint-types.generated.d.ts +339 -270
- package/esm/blueprint-types.generated.js +6 -0
- package/esm/codegen/generate-types.js +105 -4
- package/esm/data/data-feature-flag.d.ts +2 -0
- package/esm/data/data-feature-flag.js +30 -0
- package/esm/data/data-image-embedding.d.ts +2 -0
- package/esm/data/data-image-embedding.js +77 -0
- package/esm/data/data-job-trigger.js +38 -1
- package/esm/data/data-limit-counter.d.ts +2 -0
- package/esm/data/data-limit-counter.js +39 -0
- package/esm/data/data-ownership-in-entity.js +12 -0
- package/esm/data/data-peoplestamps.js +12 -0
- package/esm/data/data-publishable.js +12 -0
- package/esm/data/data-soft-delete.js +12 -0
- package/esm/data/data-timestamps.js +12 -0
- package/esm/data/index.d.ts +3 -0
- package/esm/data/index.js +3 -0
- package/esm/view/view-aggregated.js +1 -0
- package/package.json +2 -2
- package/view/view-aggregated.js +1 -0
- package/authz/authz-membership-check.d.ts +0 -2
- package/esm/authz/authz-membership-check.d.ts +0 -2
|
@@ -8,6 +8,12 @@
|
|
|
8
8
|
// These types match the JSONB shape expected by construct_blueprint().
|
|
9
9
|
// All field names are snake_case to match the SQL convention.
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
/**
|
|
12
|
+
* ===========================================================================
|
|
13
|
+
* Shared recursive types
|
|
14
|
+
* ===========================================================================
|
|
15
|
+
*/
|
|
16
|
+
;
|
|
11
17
|
/**
|
|
12
18
|
* ===========================================================================
|
|
13
19
|
* Data node type parameters
|
|
@@ -111,6 +111,15 @@ function partialOf(inner) {
|
|
|
111
111
|
// ---------------------------------------------------------------------------
|
|
112
112
|
function ensureArrayItems(schema) {
|
|
113
113
|
const out = { ...schema };
|
|
114
|
+
// Strip $defs — they exist for JSON Schema validators but schema-typescript
|
|
115
|
+
// doesn't understand them and the TS types are emitted separately.
|
|
116
|
+
delete out.$defs;
|
|
117
|
+
// Properties with x-codegen-type get their TS type replaced post-generation,
|
|
118
|
+
// so collapse them to a simple {type:'object'} to avoid confusing
|
|
119
|
+
// schema-typescript with $ref or oneOf it can't resolve.
|
|
120
|
+
if (out['x-codegen-type']) {
|
|
121
|
+
return { type: 'object', description: out.description, 'x-codegen-type': out['x-codegen-type'] };
|
|
122
|
+
}
|
|
114
123
|
// Ensure arrays have an items spec (schema-typescript throws without one)
|
|
115
124
|
if (out.type === 'array' && !out.items) {
|
|
116
125
|
out.items = { type: 'string' };
|
|
@@ -136,6 +145,93 @@ function ensureArrayItems(schema) {
|
|
|
136
145
|
return out;
|
|
137
146
|
}
|
|
138
147
|
// ---------------------------------------------------------------------------
|
|
148
|
+
// TriggerCondition — recursive type for compound WHEN clause conditions.
|
|
149
|
+
// Hand-written because JSON Schema / schema-typescript cannot express
|
|
150
|
+
// self-referencing types.
|
|
151
|
+
// ---------------------------------------------------------------------------
|
|
152
|
+
function buildTriggerConditionInterface() {
|
|
153
|
+
const opType = t.tsUnionType(['=', '!=', '>', '<', '>=', '<=', 'LIKE', 'NOT LIKE', 'IS NULL', 'IS NOT NULL', 'IS DISTINCT FROM']
|
|
154
|
+
.map((op) => t.tsLiteralType(t.stringLiteral(op))));
|
|
155
|
+
const rowType = t.tsUnionType([
|
|
156
|
+
t.tsLiteralType(t.stringLiteral('NEW')),
|
|
157
|
+
t.tsLiteralType(t.stringLiteral('OLD'))
|
|
158
|
+
]);
|
|
159
|
+
const condRef = t.tsTypeReference(t.identifier('TriggerCondition'));
|
|
160
|
+
return addJSDoc(exportInterface('TriggerCondition', [
|
|
161
|
+
addJSDoc(optionalProp('field', t.tsStringKeyword()), 'Column name (validated against the table).'),
|
|
162
|
+
addJSDoc(optionalProp('op', opType), 'Comparison operator.'),
|
|
163
|
+
addJSDoc(optionalProp('value', t.tsAnyKeyword()), 'Comparison value. Type is resolved from the column definition.'),
|
|
164
|
+
addJSDoc(optionalProp('row', rowType), 'Row reference (default: NEW).'),
|
|
165
|
+
addJSDoc(optionalProp('ref', t.tsTypeLiteral([
|
|
166
|
+
optionalProp('field', t.tsStringKeyword()),
|
|
167
|
+
optionalProp('row', rowType)
|
|
168
|
+
])), 'Column reference for field-to-field comparison (alternative to value).'),
|
|
169
|
+
addJSDoc(optionalProp('AND', t.tsArrayType(condRef)), 'Array of conditions combined with AND.'),
|
|
170
|
+
addJSDoc(optionalProp('OR', t.tsArrayType(condRef)), 'Array of conditions combined with OR.'),
|
|
171
|
+
addJSDoc(optionalProp('NOT', condRef), 'Negated condition.')
|
|
172
|
+
]), 'Recursive condition type for compound trigger WHEN clauses. Leaf conditions specify {field, op, value?, row?, ref?}. Combinators nest via AND, OR, NOT.');
|
|
173
|
+
}
|
|
174
|
+
// ---------------------------------------------------------------------------
|
|
175
|
+
// x-codegen-type post-processing — replaces properties that have an
|
|
176
|
+
// 'x-codegen-type' marker in their JSON Schema with a hand-written TS type
|
|
177
|
+
// reference. This lets node type definitions delegate complex types
|
|
178
|
+
// (like recursive TriggerCondition) to the codegen instead of trying to
|
|
179
|
+
// express them in JSON Schema.
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
function applyCodegenTypeOverrides(statements, nodeTypes) {
|
|
182
|
+
// Build a map of typeName -> { propName -> typeString }
|
|
183
|
+
const overrides = new Map();
|
|
184
|
+
for (const nt of nodeTypes) {
|
|
185
|
+
const props = nt.parameter_schema?.properties;
|
|
186
|
+
if (!props)
|
|
187
|
+
continue;
|
|
188
|
+
for (const [propName, propSchema] of Object.entries(props)) {
|
|
189
|
+
const schema = propSchema;
|
|
190
|
+
if (schema['x-codegen-type']) {
|
|
191
|
+
const typeName = `${nt.name}Params`;
|
|
192
|
+
if (!overrides.has(typeName))
|
|
193
|
+
overrides.set(typeName, new Map());
|
|
194
|
+
overrides.get(typeName).set(propName, schema['x-codegen-type']);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (overrides.size === 0)
|
|
199
|
+
return;
|
|
200
|
+
for (const stmt of statements) {
|
|
201
|
+
const decl = stmt.declaration;
|
|
202
|
+
if (!t.isTSInterfaceDeclaration(decl))
|
|
203
|
+
continue;
|
|
204
|
+
const ifaceName = decl.id.name;
|
|
205
|
+
const propOverrides = overrides.get(ifaceName);
|
|
206
|
+
if (!propOverrides)
|
|
207
|
+
continue;
|
|
208
|
+
for (const member of decl.body.body) {
|
|
209
|
+
if (!t.isTSPropertySignature(member))
|
|
210
|
+
continue;
|
|
211
|
+
const key = t.isIdentifier(member.key)
|
|
212
|
+
? member.key.name
|
|
213
|
+
: t.isStringLiteral(member.key)
|
|
214
|
+
? member.key.value
|
|
215
|
+
: null;
|
|
216
|
+
if (!key || !propOverrides.has(key))
|
|
217
|
+
continue;
|
|
218
|
+
const typeStr = propOverrides.get(key);
|
|
219
|
+
// Parse "TypeA | TypeB[]" into a TS union of type references
|
|
220
|
+
const parts = typeStr.split('|').map((s) => s.trim());
|
|
221
|
+
const tsTypes = parts.map((part) => {
|
|
222
|
+
const isArray = part.endsWith('[]');
|
|
223
|
+
const name = isArray ? part.slice(0, -2) : part;
|
|
224
|
+
const ref = t.tsTypeReference(t.identifier(name));
|
|
225
|
+
return isArray ? t.tsArrayType(ref) : ref;
|
|
226
|
+
});
|
|
227
|
+
const annotation = tsTypes.length === 1
|
|
228
|
+
? tsTypes[0]
|
|
229
|
+
: t.tsUnionType(tsTypes);
|
|
230
|
+
member.typeAnnotation = t.tsTypeAnnotation(annotation);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
// ---------------------------------------------------------------------------
|
|
139
235
|
// Generate per-node-type parameter interfaces via schema-typescript
|
|
140
236
|
// ---------------------------------------------------------------------------
|
|
141
237
|
function generateParamsInterfaces(nodeTypes) {
|
|
@@ -162,6 +258,9 @@ function generateParamsInterfaces(nodeTypes) {
|
|
|
162
258
|
results.push(addJSDoc(exportInterface(typeName, []), nt.description));
|
|
163
259
|
}
|
|
164
260
|
}
|
|
261
|
+
// Apply x-codegen-type overrides to replace schema-generated types with
|
|
262
|
+
// hand-written recursive types (e.g. TriggerCondition)
|
|
263
|
+
applyCodegenTypeOverrides(results, nodeTypes);
|
|
165
264
|
return results;
|
|
166
265
|
}
|
|
167
266
|
// ---------------------------------------------------------------------------
|
|
@@ -423,9 +522,8 @@ function buildBlueprintStorageConfig() {
|
|
|
423
522
|
addJSDoc(optionalProp('allowed_origins', t.tsArrayType(t.tsStringKeyword())), 'CORS allowed origins for the storage module.'),
|
|
424
523
|
addJSDoc(optionalProp('provisions', t.tsTypeLiteral([
|
|
425
524
|
optionalProp('files', t.tsTypeReference(t.identifier('BlueprintEntityTableProvision'))),
|
|
426
|
-
optionalProp('buckets', t.tsTypeReference(t.identifier('BlueprintEntityTableProvision')))
|
|
427
|
-
|
|
428
|
-
])), 'Per-table overrides for storage tables. Each key targets a specific storage table (files, buckets, upload_requests) and uses the same shape as table_provision: { nodes, fields, grants, use_rls, policies }. Fanned out to secure_table_provision targeting the corresponding table. When a key includes policies[], those REPLACE the default storage policies for that table; tables without a key still get defaults.')
|
|
525
|
+
optionalProp('buckets', t.tsTypeReference(t.identifier('BlueprintEntityTableProvision')))
|
|
526
|
+
])), 'Per-table overrides for storage tables. Each key targets a specific storage table (files, buckets) and uses the same shape as table_provision: { nodes, fields, grants, use_rls, policies }. Fanned out to secure_table_provision targeting the corresponding table. When a key includes policies[], those REPLACE the default storage policies for that table; tables without a key still get defaults.')
|
|
429
527
|
]), 'Storage configuration for an entity type. Seeds initial buckets, overrides module-level settings (expiry times, file size limits, CORS), and provides per-table provisioning overrides via provisions.');
|
|
430
528
|
}
|
|
431
529
|
function buildBlueprintEntityTableProvision() {
|
|
@@ -451,7 +549,7 @@ function buildBlueprintEntityType() {
|
|
|
451
549
|
addJSDoc(optionalProp('has_limits', t.tsBooleanKeyword()), 'Whether to provision a limits module for this entity type. Defaults to false.'),
|
|
452
550
|
addJSDoc(optionalProp('has_profiles', t.tsBooleanKeyword()), 'Whether to provision a profiles module for this entity type. Defaults to false.'),
|
|
453
551
|
addJSDoc(optionalProp('has_levels', t.tsBooleanKeyword()), 'Whether to provision a levels module for this entity type. Defaults to false.'),
|
|
454
|
-
addJSDoc(optionalProp('has_storage', t.tsBooleanKeyword()), 'Whether to provision a storage module (buckets, files
|
|
552
|
+
addJSDoc(optionalProp('has_storage', t.tsBooleanKeyword()), 'Whether to provision a storage module (buckets, files tables) for this entity type. Defaults to false.'),
|
|
455
553
|
addJSDoc(optionalProp('has_invites', t.tsBooleanKeyword()), 'Whether to provision entity-scoped invite tables ({prefix}_invites, {prefix}_claimed_invites) and a submit_{prefix}_invite_code() function. Defaults to false.'),
|
|
456
554
|
addJSDoc(optionalProp('skip_entity_policies', t.tsBooleanKeyword()), 'Escape hatch: when true AND table_provision is NULL, zero policies are provisioned on the entity table. Defaults to false.'),
|
|
457
555
|
addJSDoc(optionalProp('table_provision', t.tsTypeReference(t.identifier('BlueprintEntityTableProvision'))), 'Override for the entity table. Shape mirrors BlueprintTable / secure_table_provision vocabulary. When supplied, its policies[] replaces the five default entity-table policies; is_visible becomes a no-op. When NULL (default), the five default policies are applied (gated by is_visible).'),
|
|
@@ -514,6 +612,9 @@ function buildProgram(meta) {
|
|
|
514
612
|
const dataNodes = index_1.allNodeTypes.filter((nt) => nt.category !== 'relation' && nt.category !== 'view');
|
|
515
613
|
const relationNodes = index_1.allNodeTypes.filter((nt) => nt.category === 'relation');
|
|
516
614
|
const authzNodes = index_1.allNodeTypes.filter((nt) => nt.category === 'authz');
|
|
615
|
+
// -- Shared recursive types (emitted before parameter interfaces) --
|
|
616
|
+
statements.push(sectionComment('Shared recursive types'));
|
|
617
|
+
statements.push(buildTriggerConditionInterface());
|
|
517
618
|
// -- Parameter interfaces grouped by category --
|
|
518
619
|
const categoryOrder = ['data', 'search', 'authz', 'relation', 'view'];
|
|
519
620
|
for (const cat of categoryOrder) {
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DataFeatureFlag = void 0;
|
|
4
|
+
exports.DataFeatureFlag = {
|
|
5
|
+
name: 'DataFeatureFlag',
|
|
6
|
+
slug: 'data_feature_flag',
|
|
7
|
+
category: 'data',
|
|
8
|
+
display_name: 'Feature Flag',
|
|
9
|
+
description: 'Gates a table behind a feature flag backed by the cap tables. Attaches a BEFORE INSERT trigger that checks whether the named feature cap value is > 0. Features are modeled as caps with max=0 (disabled) or max=1 (enabled) in limit_caps / limit_caps_defaults tables. Resolution: COALESCE(per-entity cap, scope default, 0).',
|
|
10
|
+
parameter_schema: {
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
feature_name: {
|
|
14
|
+
type: 'string',
|
|
15
|
+
description: 'Cap name representing this feature (must match a limit_caps_defaults entry with max=0 or max=1)',
|
|
16
|
+
},
|
|
17
|
+
scope: {
|
|
18
|
+
type: 'string',
|
|
19
|
+
enum: ['app', 'org'],
|
|
20
|
+
description: 'Feature scope: "app" (membership_type=1, app-level caps) or "org" (membership_type=2, per-entity caps)',
|
|
21
|
+
default: 'app',
|
|
22
|
+
},
|
|
23
|
+
entity_field: {
|
|
24
|
+
type: 'string',
|
|
25
|
+
format: 'column-ref',
|
|
26
|
+
description: 'Column on the target table that holds the entity id for per-entity cap lookups (only used for org scope)',
|
|
27
|
+
default: 'entity_id',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
required: ['feature_name'],
|
|
31
|
+
},
|
|
32
|
+
tags: ['limits', 'triggers', 'feature-flags', 'billing', 'caps'],
|
|
33
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DataImageEmbedding = void 0;
|
|
4
|
+
exports.DataImageEmbedding = {
|
|
5
|
+
name: 'DataImageEmbedding',
|
|
6
|
+
slug: 'data_image_embedding',
|
|
7
|
+
category: 'data',
|
|
8
|
+
display_name: 'Image Embedding',
|
|
9
|
+
description: 'Composition wrapper that creates a vector embedding field with HNSW/IVFFlat index (via SearchVector) and a job trigger with compound conditions (via DataJobTrigger) that fires on INSERT for image files matching mime_type patterns. Designed for storage file tables.',
|
|
10
|
+
parameter_schema: {
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
field_name: {
|
|
14
|
+
type: 'string',
|
|
15
|
+
format: 'column-ref',
|
|
16
|
+
description: 'Name of the vector embedding column',
|
|
17
|
+
default: 'embedding'
|
|
18
|
+
},
|
|
19
|
+
dimensions: {
|
|
20
|
+
type: 'integer',
|
|
21
|
+
description: 'Vector dimensions',
|
|
22
|
+
default: 512
|
|
23
|
+
},
|
|
24
|
+
index_method: {
|
|
25
|
+
type: 'string',
|
|
26
|
+
enum: [
|
|
27
|
+
'hnsw',
|
|
28
|
+
'ivfflat'
|
|
29
|
+
],
|
|
30
|
+
description: 'Index type for similarity search',
|
|
31
|
+
default: 'hnsw'
|
|
32
|
+
},
|
|
33
|
+
metric: {
|
|
34
|
+
type: 'string',
|
|
35
|
+
enum: [
|
|
36
|
+
'cosine',
|
|
37
|
+
'l2',
|
|
38
|
+
'ip'
|
|
39
|
+
],
|
|
40
|
+
description: 'Distance metric',
|
|
41
|
+
default: 'cosine'
|
|
42
|
+
},
|
|
43
|
+
task_identifier: {
|
|
44
|
+
type: 'string',
|
|
45
|
+
description: 'Job task identifier for the embedding worker',
|
|
46
|
+
default: 'process_image_embedding'
|
|
47
|
+
},
|
|
48
|
+
mime_patterns: {
|
|
49
|
+
type: 'array',
|
|
50
|
+
items: {
|
|
51
|
+
type: 'string'
|
|
52
|
+
},
|
|
53
|
+
description: 'MIME type LIKE patterns to match (e.g., image/%, video/%). Multiple patterns are OR\'d together.',
|
|
54
|
+
default: ['image/%']
|
|
55
|
+
},
|
|
56
|
+
payload_custom: {
|
|
57
|
+
type: 'object',
|
|
58
|
+
additionalProperties: {
|
|
59
|
+
type: 'string',
|
|
60
|
+
format: 'column-ref'
|
|
61
|
+
},
|
|
62
|
+
description: 'Custom payload key-to-column mapping for the job trigger',
|
|
63
|
+
default: {
|
|
64
|
+
file_id: 'id',
|
|
65
|
+
key: 'key',
|
|
66
|
+
mime_type: 'mime_type',
|
|
67
|
+
bucket_id: 'bucket_id'
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
tags: [
|
|
73
|
+
'embedding',
|
|
74
|
+
'image',
|
|
75
|
+
'vector',
|
|
76
|
+
'ai',
|
|
77
|
+
'composition',
|
|
78
|
+
'jobs'
|
|
79
|
+
]
|
|
80
|
+
};
|
package/data/data-job-trigger.js
CHANGED
|
@@ -1,6 +1,31 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DataJobTrigger = void 0;
|
|
4
|
+
const triggerConditionSchema = {
|
|
5
|
+
type: 'object',
|
|
6
|
+
description: 'A leaf condition ({field, op, value?, row?, ref?}) or a combinator ({AND, OR, NOT}).',
|
|
7
|
+
properties: {
|
|
8
|
+
field: { type: 'string', format: 'column-ref', description: 'Column name (validated against the table).' },
|
|
9
|
+
op: {
|
|
10
|
+
type: 'string',
|
|
11
|
+
enum: ['=', '!=', '>', '<', '>=', '<=', 'LIKE', 'NOT LIKE', 'IS NULL', 'IS NOT NULL', 'IS DISTINCT FROM'],
|
|
12
|
+
description: 'Comparison operator.'
|
|
13
|
+
},
|
|
14
|
+
value: { description: 'Comparison value. Type is resolved from the column definition. Omit for IS NULL, IS NOT NULL, IS DISTINCT FROM.' },
|
|
15
|
+
row: { type: 'string', enum: ['NEW', 'OLD'], default: 'NEW', description: 'Row reference (default: NEW).' },
|
|
16
|
+
ref: {
|
|
17
|
+
type: 'object',
|
|
18
|
+
description: 'Column reference for field-to-field comparison (alternative to value).',
|
|
19
|
+
properties: {
|
|
20
|
+
field: { type: 'string', format: 'column-ref' },
|
|
21
|
+
row: { type: 'string', enum: ['NEW', 'OLD'], default: 'NEW' }
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
AND: { type: 'array', description: 'Array of conditions combined with AND.', items: { $ref: '#/$defs/triggerCondition' } },
|
|
25
|
+
OR: { type: 'array', description: 'Array of conditions combined with OR.', items: { $ref: '#/$defs/triggerCondition' } },
|
|
26
|
+
NOT: { $ref: '#/$defs/triggerCondition', description: 'Negated condition.' }
|
|
27
|
+
}
|
|
28
|
+
};
|
|
4
29
|
exports.DataJobTrigger = {
|
|
5
30
|
name: 'DataJobTrigger',
|
|
6
31
|
slug: 'data_job_trigger',
|
|
@@ -9,6 +34,9 @@ exports.DataJobTrigger = {
|
|
|
9
34
|
description: 'Dynamically creates PostgreSQL triggers that enqueue jobs via app_jobs.add_job() when table rows are inserted, updated, or deleted. Supports configurable payload strategies (full row, row ID, selected fields, or custom mapping), conditional firing via WHEN clauses, watched field changes, and extended job options (queue, priority, delay, max attempts).',
|
|
10
35
|
parameter_schema: {
|
|
11
36
|
type: 'object',
|
|
37
|
+
$defs: {
|
|
38
|
+
triggerCondition: triggerConditionSchema
|
|
39
|
+
},
|
|
12
40
|
properties: {
|
|
13
41
|
task_identifier: {
|
|
14
42
|
type: 'string',
|
|
@@ -36,7 +64,8 @@ exports.DataJobTrigger = {
|
|
|
36
64
|
payload_custom: {
|
|
37
65
|
type: 'object',
|
|
38
66
|
additionalProperties: {
|
|
39
|
-
type: 'string'
|
|
67
|
+
type: 'string',
|
|
68
|
+
format: 'column-ref'
|
|
40
69
|
},
|
|
41
70
|
description: 'Key-to-column mapping for custom payload (e.g., {"invoice_id": "id", "total": "amount"})'
|
|
42
71
|
},
|
|
@@ -75,6 +104,14 @@ exports.DataJobTrigger = {
|
|
|
75
104
|
type: 'string',
|
|
76
105
|
description: 'Value to compare against condition_field in WHEN clause'
|
|
77
106
|
},
|
|
107
|
+
conditions: {
|
|
108
|
+
description: 'Compound conditions for the trigger WHEN clause. Accepts a single leaf condition, an array of conditions (implicitly AND), or a nested combinator tree ({AND: [...], OR: [...], NOT: {...}}). Each leaf is {field, op, value?, row?, ref?}. Column types are resolved automatically from the table schema. Cannot be combined with condition_field or watch_fields.',
|
|
109
|
+
'x-codegen-type': 'TriggerCondition | TriggerCondition[]',
|
|
110
|
+
oneOf: [
|
|
111
|
+
{ $ref: '#/$defs/triggerCondition' },
|
|
112
|
+
{ type: 'array', items: { $ref: '#/$defs/triggerCondition' } }
|
|
113
|
+
]
|
|
114
|
+
},
|
|
78
115
|
watch_fields: {
|
|
79
116
|
type: 'array',
|
|
80
117
|
items: {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DataLimitCounter = void 0;
|
|
4
|
+
exports.DataLimitCounter = {
|
|
5
|
+
name: 'DataLimitCounter',
|
|
6
|
+
slug: 'data_limit_counter',
|
|
7
|
+
category: 'data',
|
|
8
|
+
display_name: 'Limit Counter',
|
|
9
|
+
description: 'Declaratively attaches limit-tracking triggers to a table. On INSERT the named limit is incremented; on DELETE it is decremented. Requires a provisioned limits_module for the target scope.',
|
|
10
|
+
parameter_schema: {
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
limit_name: {
|
|
14
|
+
type: 'string',
|
|
15
|
+
description: 'Name of the limit to track (must match a default_limits entry, e.g. "projects", "members")',
|
|
16
|
+
},
|
|
17
|
+
scope: {
|
|
18
|
+
type: 'string',
|
|
19
|
+
enum: ['app', 'org'],
|
|
20
|
+
description: 'Limit scope: "app" (membership_type=1, user-level) or "org" (membership_type=2, entity-level)',
|
|
21
|
+
default: 'app',
|
|
22
|
+
},
|
|
23
|
+
actor_field: {
|
|
24
|
+
type: 'string',
|
|
25
|
+
format: 'column-ref',
|
|
26
|
+
description: 'Column on the target table that holds the actor or entity id used for limit lookup',
|
|
27
|
+
default: 'owner_id',
|
|
28
|
+
},
|
|
29
|
+
events: {
|
|
30
|
+
type: 'array',
|
|
31
|
+
items: {
|
|
32
|
+
type: 'string',
|
|
33
|
+
enum: ['INSERT', 'DELETE', 'UPDATE'],
|
|
34
|
+
},
|
|
35
|
+
description: 'Which DML events to attach triggers for',
|
|
36
|
+
default: ['INSERT', 'DELETE'],
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
required: ['limit_name'],
|
|
40
|
+
},
|
|
41
|
+
tags: ['limits', 'triggers', 'billing'],
|
|
42
|
+
};
|
|
@@ -10,6 +10,18 @@ exports.DataOwnershipInEntity = {
|
|
|
10
10
|
parameter_schema: {
|
|
11
11
|
type: 'object',
|
|
12
12
|
properties: {
|
|
13
|
+
owner_field_name: {
|
|
14
|
+
type: 'string',
|
|
15
|
+
format: 'column-ref',
|
|
16
|
+
description: 'Column name for the owner reference',
|
|
17
|
+
default: 'owner_id'
|
|
18
|
+
},
|
|
19
|
+
entity_field_name: {
|
|
20
|
+
type: 'string',
|
|
21
|
+
format: 'column-ref',
|
|
22
|
+
description: 'Column name for the entity reference',
|
|
23
|
+
default: 'entity_id'
|
|
24
|
+
},
|
|
13
25
|
include_id: {
|
|
14
26
|
type: 'boolean',
|
|
15
27
|
description: 'If true, also adds a UUID primary key column with auto-generation',
|
|
@@ -10,6 +10,18 @@ exports.DataPeoplestamps = {
|
|
|
10
10
|
parameter_schema: {
|
|
11
11
|
type: 'object',
|
|
12
12
|
properties: {
|
|
13
|
+
created_by_field: {
|
|
14
|
+
type: 'string',
|
|
15
|
+
format: 'column-ref',
|
|
16
|
+
description: 'Column name for the creating user reference',
|
|
17
|
+
default: 'created_by'
|
|
18
|
+
},
|
|
19
|
+
updated_by_field: {
|
|
20
|
+
type: 'string',
|
|
21
|
+
format: 'column-ref',
|
|
22
|
+
description: 'Column name for the last-updating user reference',
|
|
23
|
+
default: 'updated_by'
|
|
24
|
+
},
|
|
13
25
|
include_id: {
|
|
14
26
|
type: 'boolean',
|
|
15
27
|
description: 'If true, also adds a UUID primary key column with auto-generation',
|
package/data/data-publishable.js
CHANGED
|
@@ -10,6 +10,18 @@ exports.DataPublishable = {
|
|
|
10
10
|
parameter_schema: {
|
|
11
11
|
type: 'object',
|
|
12
12
|
properties: {
|
|
13
|
+
is_published_field: {
|
|
14
|
+
type: 'string',
|
|
15
|
+
format: 'column-ref',
|
|
16
|
+
description: 'Column name for the published boolean flag',
|
|
17
|
+
default: 'is_published'
|
|
18
|
+
},
|
|
19
|
+
published_at_field: {
|
|
20
|
+
type: 'string',
|
|
21
|
+
format: 'column-ref',
|
|
22
|
+
description: 'Column name for the publish timestamp',
|
|
23
|
+
default: 'published_at'
|
|
24
|
+
},
|
|
13
25
|
include_id: {
|
|
14
26
|
type: 'boolean',
|
|
15
27
|
description: 'If true, also adds a UUID primary key column with auto-generation',
|
package/data/data-soft-delete.js
CHANGED
|
@@ -10,6 +10,18 @@ exports.DataSoftDelete = {
|
|
|
10
10
|
parameter_schema: {
|
|
11
11
|
type: 'object',
|
|
12
12
|
properties: {
|
|
13
|
+
deleted_at_field: {
|
|
14
|
+
type: 'string',
|
|
15
|
+
format: 'column-ref',
|
|
16
|
+
description: 'Column name for the soft-delete timestamp',
|
|
17
|
+
default: 'deleted_at'
|
|
18
|
+
},
|
|
19
|
+
is_deleted_field: {
|
|
20
|
+
type: 'string',
|
|
21
|
+
format: 'column-ref',
|
|
22
|
+
description: 'Column name for the soft-delete boolean flag',
|
|
23
|
+
default: 'is_deleted'
|
|
24
|
+
},
|
|
13
25
|
include_id: {
|
|
14
26
|
type: 'boolean',
|
|
15
27
|
description: 'If true, also adds a UUID primary key column with auto-generation',
|
package/data/data-timestamps.js
CHANGED
|
@@ -10,6 +10,18 @@ exports.DataTimestamps = {
|
|
|
10
10
|
parameter_schema: {
|
|
11
11
|
type: 'object',
|
|
12
12
|
properties: {
|
|
13
|
+
created_at_field: {
|
|
14
|
+
type: 'string',
|
|
15
|
+
format: 'column-ref',
|
|
16
|
+
description: 'Column name for the creation timestamp',
|
|
17
|
+
default: 'created_at'
|
|
18
|
+
},
|
|
19
|
+
updated_at_field: {
|
|
20
|
+
type: 'string',
|
|
21
|
+
format: 'column-ref',
|
|
22
|
+
description: 'Column name for the last-updated timestamp',
|
|
23
|
+
default: 'updated_at'
|
|
24
|
+
},
|
|
13
25
|
include_id: {
|
|
14
26
|
type: 'boolean',
|
|
15
27
|
description: 'If true, also adds a UUID primary key column with auto-generation',
|
package/data/index.d.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
export { DataCompositeField } from './data-composite-field';
|
|
2
2
|
export { DataDirectOwner } from './data-direct-owner';
|
|
3
3
|
export { DataEntityMembership } from './data-entity-membership';
|
|
4
|
+
export { DataFeatureFlag } from './data-feature-flag';
|
|
4
5
|
export { DataForceCurrentUser } from './data-force-current-user';
|
|
5
6
|
export { DataId } from './data-id';
|
|
7
|
+
export { DataImageEmbedding } from './data-image-embedding';
|
|
6
8
|
export { DataImmutableFields } from './data-immutable-fields';
|
|
7
9
|
export { DataInflection } from './data-inflection';
|
|
8
10
|
export { DataInheritFromParent } from './data-inherit-from-parent';
|
|
9
11
|
export { DataJobTrigger } from './data-job-trigger';
|
|
12
|
+
export { DataLimitCounter } from './data-limit-counter';
|
|
10
13
|
export { DataJsonb } from './data-jsonb';
|
|
11
14
|
export { DataOwnedFields } from './data-owned-fields';
|
|
12
15
|
export { DataOwnershipInEntity } from './data-ownership-in-entity';
|
package/data/index.js
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.TableUserSettings = exports.TableUserProfiles = exports.TableOrganizationSettings = exports.SearchVector = exports.SearchUnified = exports.SearchTrgm = exports.SearchSpatialAggregate = exports.SearchSpatial = exports.SearchFullText = exports.SearchBm25 = exports.DataTimestamps = exports.DataTags = exports.DataStatusField = exports.DataSoftDelete = exports.DataSlug = exports.DataPublishable = exports.DataPeoplestamps = exports.DataOwnershipInEntity = exports.DataOwnedFields = exports.DataJsonb = exports.DataJobTrigger = exports.DataInheritFromParent = exports.DataInflection = exports.DataImmutableFields = exports.DataId = exports.DataForceCurrentUser = exports.DataEntityMembership = exports.DataDirectOwner = exports.DataCompositeField = void 0;
|
|
3
|
+
exports.TableUserSettings = exports.TableUserProfiles = exports.TableOrganizationSettings = exports.SearchVector = exports.SearchUnified = exports.SearchTrgm = exports.SearchSpatialAggregate = exports.SearchSpatial = exports.SearchFullText = exports.SearchBm25 = exports.DataTimestamps = exports.DataTags = exports.DataStatusField = exports.DataSoftDelete = exports.DataSlug = exports.DataPublishable = exports.DataPeoplestamps = exports.DataOwnershipInEntity = exports.DataOwnedFields = exports.DataJsonb = exports.DataLimitCounter = exports.DataJobTrigger = exports.DataInheritFromParent = exports.DataInflection = exports.DataImmutableFields = exports.DataImageEmbedding = exports.DataId = exports.DataForceCurrentUser = exports.DataFeatureFlag = exports.DataEntityMembership = exports.DataDirectOwner = exports.DataCompositeField = void 0;
|
|
4
4
|
var data_composite_field_1 = require("./data-composite-field");
|
|
5
5
|
Object.defineProperty(exports, "DataCompositeField", { enumerable: true, get: function () { return data_composite_field_1.DataCompositeField; } });
|
|
6
6
|
var data_direct_owner_1 = require("./data-direct-owner");
|
|
7
7
|
Object.defineProperty(exports, "DataDirectOwner", { enumerable: true, get: function () { return data_direct_owner_1.DataDirectOwner; } });
|
|
8
8
|
var data_entity_membership_1 = require("./data-entity-membership");
|
|
9
9
|
Object.defineProperty(exports, "DataEntityMembership", { enumerable: true, get: function () { return data_entity_membership_1.DataEntityMembership; } });
|
|
10
|
+
var data_feature_flag_1 = require("./data-feature-flag");
|
|
11
|
+
Object.defineProperty(exports, "DataFeatureFlag", { enumerable: true, get: function () { return data_feature_flag_1.DataFeatureFlag; } });
|
|
10
12
|
var data_force_current_user_1 = require("./data-force-current-user");
|
|
11
13
|
Object.defineProperty(exports, "DataForceCurrentUser", { enumerable: true, get: function () { return data_force_current_user_1.DataForceCurrentUser; } });
|
|
12
14
|
var data_id_1 = require("./data-id");
|
|
13
15
|
Object.defineProperty(exports, "DataId", { enumerable: true, get: function () { return data_id_1.DataId; } });
|
|
16
|
+
var data_image_embedding_1 = require("./data-image-embedding");
|
|
17
|
+
Object.defineProperty(exports, "DataImageEmbedding", { enumerable: true, get: function () { return data_image_embedding_1.DataImageEmbedding; } });
|
|
14
18
|
var data_immutable_fields_1 = require("./data-immutable-fields");
|
|
15
19
|
Object.defineProperty(exports, "DataImmutableFields", { enumerable: true, get: function () { return data_immutable_fields_1.DataImmutableFields; } });
|
|
16
20
|
var data_inflection_1 = require("./data-inflection");
|
|
@@ -19,6 +23,8 @@ var data_inherit_from_parent_1 = require("./data-inherit-from-parent");
|
|
|
19
23
|
Object.defineProperty(exports, "DataInheritFromParent", { enumerable: true, get: function () { return data_inherit_from_parent_1.DataInheritFromParent; } });
|
|
20
24
|
var data_job_trigger_1 = require("./data-job-trigger");
|
|
21
25
|
Object.defineProperty(exports, "DataJobTrigger", { enumerable: true, get: function () { return data_job_trigger_1.DataJobTrigger; } });
|
|
26
|
+
var data_limit_counter_1 = require("./data-limit-counter");
|
|
27
|
+
Object.defineProperty(exports, "DataLimitCounter", { enumerable: true, get: function () { return data_limit_counter_1.DataLimitCounter; } });
|
|
22
28
|
var data_jsonb_1 = require("./data-jsonb");
|
|
23
29
|
Object.defineProperty(exports, "DataJsonb", { enumerable: true, get: function () { return data_jsonb_1.DataJsonb; } });
|
|
24
30
|
var data_owned_fields_1 = require("./data-owned-fields");
|
|
@@ -1,47 +1,41 @@
|
|
|
1
|
-
export const
|
|
2
|
-
name: '
|
|
3
|
-
slug: '
|
|
1
|
+
export const AuthzAppMembership = {
|
|
2
|
+
name: 'AuthzAppMembership',
|
|
3
|
+
slug: 'authz_app_membership_check',
|
|
4
4
|
category: 'authz',
|
|
5
|
-
display_name: 'Membership Check',
|
|
6
|
-
description: '
|
|
5
|
+
display_name: 'App Membership Check',
|
|
6
|
+
description: 'App-level membership check (membership_type=1). Verifies the user has app membership (optionally with specific permission) without binding to any entity from the row. Uses EXISTS subquery against SPRT table. Replaces AuthzMembership for clarity.',
|
|
7
7
|
parameter_schema: {
|
|
8
8
|
type: 'object',
|
|
9
9
|
properties: {
|
|
10
10
|
membership_type: {
|
|
11
|
-
type: [
|
|
12
|
-
|
|
13
|
-
'string'
|
|
14
|
-
],
|
|
15
|
-
description: 'Scope: 1=app, 2=org, 3+=dynamic entity types (or string name resolved via membership_types_module)'
|
|
11
|
+
type: ['integer', 'string'],
|
|
12
|
+
description: 'Scope: 1=app, 2=org, 3+=dynamic entity types (or string name resolved via membership_types_module)',
|
|
16
13
|
},
|
|
17
14
|
entity_type: {
|
|
18
15
|
type: 'string',
|
|
19
|
-
description: "Entity type prefix (e.g. 'channel', 'department'). Resolved to membership_type integer via memberships_module lookup. Use instead of membership_type for readability."
|
|
16
|
+
description: "Entity type prefix (e.g. 'channel', 'department'). Resolved to membership_type integer via memberships_module lookup. Use instead of membership_type for readability.",
|
|
20
17
|
},
|
|
21
18
|
permission: {
|
|
22
19
|
type: 'string',
|
|
23
|
-
description: 'Single permission name to check (resolved to bitstring mask)'
|
|
20
|
+
description: 'Single permission name to check (resolved to bitstring mask)',
|
|
24
21
|
},
|
|
25
22
|
permissions: {
|
|
26
23
|
type: 'array',
|
|
27
24
|
items: {
|
|
28
|
-
type: 'string'
|
|
25
|
+
type: 'string',
|
|
29
26
|
},
|
|
30
|
-
description: 'Multiple permission names to check (ORed together into mask)'
|
|
27
|
+
description: 'Multiple permission names to check (ORed together into mask)',
|
|
31
28
|
},
|
|
32
29
|
is_admin: {
|
|
33
30
|
type: 'boolean',
|
|
34
|
-
description: 'If true, require is_admin flag'
|
|
31
|
+
description: 'If true, require is_admin flag',
|
|
35
32
|
},
|
|
36
33
|
is_owner: {
|
|
37
34
|
type: 'boolean',
|
|
38
|
-
description: 'If true, require is_owner flag'
|
|
39
|
-
}
|
|
35
|
+
description: 'If true, require is_owner flag',
|
|
36
|
+
},
|
|
40
37
|
},
|
|
41
|
-
required: []
|
|
38
|
+
required: [],
|
|
42
39
|
},
|
|
43
|
-
tags: [
|
|
44
|
-
'membership',
|
|
45
|
-
'authz'
|
|
46
|
-
]
|
|
40
|
+
tags: ['membership', 'authz'],
|
|
47
41
|
};
|
package/esm/authz/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
export { AuthzAllowAll } from './authz-allow-all';
|
|
2
|
+
export { AuthzAppMembership } from './authz-app-membership';
|
|
2
3
|
export { AuthzComposite } from './authz-composite';
|
|
3
4
|
export { AuthzDenyAll } from './authz-deny-all';
|
|
4
5
|
export { AuthzDirectOwner } from './authz-direct-owner';
|
|
5
6
|
export { AuthzDirectOwnerAny } from './authz-direct-owner-any';
|
|
6
7
|
export { AuthzEntityMembership } from './authz-entity-membership';
|
|
7
8
|
export { AuthzMemberList } from './authz-member-list';
|
|
8
|
-
export { AuthzMembership } from './authz-membership-check';
|
|
9
9
|
export { AuthzNotReadOnly } from './authz-not-read-only';
|
|
10
10
|
export { AuthzOrgHierarchy } from './authz-org-hierarchy';
|
|
11
11
|
export { AuthzPeerOwnership } from './authz-peer-ownership';
|