node-type-registry 0.47.0 → 0.49.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/README.md CHANGED
@@ -135,6 +135,17 @@ Common issues and solutions for pgpm, PostgreSQL, and testing.
135
135
 
136
136
  * [constructive-skills](https://github.com/constructive-io/constructive-skills): **📖 Platform documentation and AI agent skills** — feature catalog, blueprint reference, SDK guides (i18n, billing, limits, events, uploads, security, entities, search, AI), and deployment guides.
137
137
 
138
+ Install skills for AI coding agents:
139
+
140
+ ```bash
141
+ # All platform skills (security, blueprints, codegen, billing, etc.)
142
+ npx skills add constructive-io/constructive-skills
143
+
144
+ # Individual repo skills (pgpm, testing, CLI, search, etc.)
145
+ npx skills add https://github.com/constructive-io/constructive --skill pgpm
146
+ npx skills add https://github.com/constructive-io/constructive --skill constructive-testing
147
+ ```
148
+
138
149
  ## Credits
139
150
 
140
151
  **🛠 Built by the [Constructive](https://constructive.io) team — creators of modular Postgres tooling for secure, composable backends. If you like our work, contribute on [GitHub](https://github.com/constructive-io).**
@@ -827,7 +827,7 @@ function buildProgram(meta) {
827
827
  statements.push(buildFieldTypeInterface());
828
828
  statements.push(buildFieldDefaultInterface());
829
829
  // -- Parameter interfaces grouped by category --
830
- const categoryOrder = ['billing', 'check', 'data', 'event', 'limit', 'limit_enforce', 'limit_track', 'limit_warning', 'search', 'job', 'process', 'authz', 'relation', 'view'];
830
+ const categoryOrder = ['billing', 'check', 'data', 'event', 'guard', 'limit', 'limit_enforce', 'limit_track', 'limit_warning', 'search', 'job', 'process', 'authz', 'relation', 'view'];
831
831
  for (const cat of categoryOrder) {
832
832
  const nts = categories.get(cat);
833
833
  if (!nts || nts.length === 0)
@@ -0,0 +1,2 @@
1
+ import type { NodeTypeDefinition } from '../types';
2
+ export declare const DataDenormalized: NodeTypeDefinition;
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DataDenormalized = void 0;
4
+ exports.DataDenormalized = {
5
+ name: 'DataDenormalized',
6
+ slug: 'data_denormalized',
7
+ category: 'data',
8
+ display_name: 'Denormalized Field',
9
+ description: 'Creates INSERT and UPDATE triggers that copy field values from a referenced (parent) table into the current table whenever the FK changes. Used to denormalize frequently-read columns (e.g. database_id on junction tables) so that RLS and queries can filter locally without joining.',
10
+ parameter_schema: {
11
+ type: 'object',
12
+ properties: {
13
+ field: {
14
+ type: 'string',
15
+ format: 'column-ref',
16
+ description: 'FK field on this table that references the parent row (e.g. view_id)'
17
+ },
18
+ set_fields: {
19
+ type: 'array',
20
+ items: {
21
+ type: 'string',
22
+ format: 'column-ref'
23
+ },
24
+ description: 'Field names on this table to be populated from the parent (e.g. ["database_id"])'
25
+ },
26
+ ref_field: {
27
+ type: 'string',
28
+ format: 'column-ref',
29
+ description: 'Field on the parent table that is the FK target (e.g. id)'
30
+ },
31
+ ref_fields: {
32
+ type: 'array',
33
+ items: {
34
+ type: 'string',
35
+ format: 'column-ref'
36
+ },
37
+ description: 'Field names on the parent table to copy from (e.g. ["database_id"])'
38
+ },
39
+ use_updates: {
40
+ type: 'boolean',
41
+ description: 'If true, also creates an UPDATE trigger so changes to the FK re-copy values',
42
+ default: true
43
+ },
44
+ update_defaults: {
45
+ type: 'boolean',
46
+ description: 'If true, sets the default value of set_fields to uuid_nil() so they are populated by the trigger',
47
+ default: true
48
+ },
49
+ func_name: {
50
+ type: 'string',
51
+ description: 'Custom function name suffix (defaults to the FK field name)'
52
+ },
53
+ func_order: {
54
+ type: 'integer',
55
+ description: 'Trigger ordering (0-padded). Lower numbers fire first',
56
+ default: 0
57
+ }
58
+ },
59
+ required: [
60
+ 'field',
61
+ 'set_fields',
62
+ 'ref_field',
63
+ 'ref_fields'
64
+ ]
65
+ },
66
+ tags: [
67
+ 'trigger',
68
+ 'denormalization',
69
+ 'schema'
70
+ ]
71
+ };
package/data/index.d.ts CHANGED
@@ -3,6 +3,7 @@ export { CheckLessThan } from './check-less-than';
3
3
  export { CheckNotEqual } from './check-not-equal';
4
4
  export { CheckOneOf } from './check-one-of';
5
5
  export { DataBulk } from './data-bulk';
6
+ export { DataDenormalized } from './data-denormalized';
6
7
  export { DataCompositeField } from './data-composite-field';
7
8
  export { DataDirectOwner } from './data-direct-owner';
8
9
  export { DataEntityMembership } from './data-entity-membership';
package/data/index.js CHANGED
@@ -1,6 +1,6 @@
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.DataRealtime = exports.DataPublishable = exports.DataPeoplestamps = exports.DataOwnershipInEntity = exports.DataOwnedFields = exports.DataMemberOwner = exports.DataJsonb = exports.DataInheritFromParent = exports.DataInflection = exports.DataImmutableFields = exports.DataId = exports.DataI18n = exports.DataForceCurrentUser = exports.DataEntityMembership = exports.DataDirectOwner = exports.DataCompositeField = exports.DataBulk = exports.CheckOneOf = exports.CheckNotEqual = exports.CheckLessThan = exports.CheckGreaterThan = 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.DataRealtime = exports.DataPublishable = exports.DataPeoplestamps = exports.DataOwnershipInEntity = exports.DataOwnedFields = exports.DataMemberOwner = exports.DataJsonb = exports.DataInheritFromParent = exports.DataInflection = exports.DataImmutableFields = exports.DataId = exports.DataI18n = exports.DataForceCurrentUser = exports.DataEntityMembership = exports.DataDirectOwner = exports.DataCompositeField = exports.DataDenormalized = exports.DataBulk = exports.CheckOneOf = exports.CheckNotEqual = exports.CheckLessThan = exports.CheckGreaterThan = void 0;
4
4
  var check_greater_than_1 = require("./check-greater-than");
5
5
  Object.defineProperty(exports, "CheckGreaterThan", { enumerable: true, get: function () { return check_greater_than_1.CheckGreaterThan; } });
6
6
  var check_less_than_1 = require("./check-less-than");
@@ -11,6 +11,8 @@ var check_one_of_1 = require("./check-one-of");
11
11
  Object.defineProperty(exports, "CheckOneOf", { enumerable: true, get: function () { return check_one_of_1.CheckOneOf; } });
12
12
  var data_bulk_1 = require("./data-bulk");
13
13
  Object.defineProperty(exports, "DataBulk", { enumerable: true, get: function () { return data_bulk_1.DataBulk; } });
14
+ var data_denormalized_1 = require("./data-denormalized");
15
+ Object.defineProperty(exports, "DataDenormalized", { enumerable: true, get: function () { return data_denormalized_1.DataDenormalized; } });
14
16
  var data_composite_field_1 = require("./data-composite-field");
15
17
  Object.defineProperty(exports, "DataCompositeField", { enumerable: true, get: function () { return data_composite_field_1.DataCompositeField; } });
16
18
  var data_direct_owner_1 = require("./data-direct-owner");
@@ -792,7 +792,7 @@ function buildProgram(meta) {
792
792
  statements.push(buildFieldTypeInterface());
793
793
  statements.push(buildFieldDefaultInterface());
794
794
  // -- Parameter interfaces grouped by category --
795
- const categoryOrder = ['billing', 'check', 'data', 'event', 'limit', 'limit_enforce', 'limit_track', 'limit_warning', 'search', 'job', 'process', 'authz', 'relation', 'view'];
795
+ const categoryOrder = ['billing', 'check', 'data', 'event', 'guard', 'limit', 'limit_enforce', 'limit_track', 'limit_warning', 'search', 'job', 'process', 'authz', 'relation', 'view'];
796
796
  for (const cat of categoryOrder) {
797
797
  const nts = categories.get(cat);
798
798
  if (!nts || nts.length === 0)
@@ -0,0 +1,2 @@
1
+ import type { NodeTypeDefinition } from '../types';
2
+ export declare const DataDenormalized: NodeTypeDefinition;
@@ -0,0 +1,68 @@
1
+ export const DataDenormalized = {
2
+ name: 'DataDenormalized',
3
+ slug: 'data_denormalized',
4
+ category: 'data',
5
+ display_name: 'Denormalized Field',
6
+ description: 'Creates INSERT and UPDATE triggers that copy field values from a referenced (parent) table into the current table whenever the FK changes. Used to denormalize frequently-read columns (e.g. database_id on junction tables) so that RLS and queries can filter locally without joining.',
7
+ parameter_schema: {
8
+ type: 'object',
9
+ properties: {
10
+ field: {
11
+ type: 'string',
12
+ format: 'column-ref',
13
+ description: 'FK field on this table that references the parent row (e.g. view_id)'
14
+ },
15
+ set_fields: {
16
+ type: 'array',
17
+ items: {
18
+ type: 'string',
19
+ format: 'column-ref'
20
+ },
21
+ description: 'Field names on this table to be populated from the parent (e.g. ["database_id"])'
22
+ },
23
+ ref_field: {
24
+ type: 'string',
25
+ format: 'column-ref',
26
+ description: 'Field on the parent table that is the FK target (e.g. id)'
27
+ },
28
+ ref_fields: {
29
+ type: 'array',
30
+ items: {
31
+ type: 'string',
32
+ format: 'column-ref'
33
+ },
34
+ description: 'Field names on the parent table to copy from (e.g. ["database_id"])'
35
+ },
36
+ use_updates: {
37
+ type: 'boolean',
38
+ description: 'If true, also creates an UPDATE trigger so changes to the FK re-copy values',
39
+ default: true
40
+ },
41
+ update_defaults: {
42
+ type: 'boolean',
43
+ description: 'If true, sets the default value of set_fields to uuid_nil() so they are populated by the trigger',
44
+ default: true
45
+ },
46
+ func_name: {
47
+ type: 'string',
48
+ description: 'Custom function name suffix (defaults to the FK field name)'
49
+ },
50
+ func_order: {
51
+ type: 'integer',
52
+ description: 'Trigger ordering (0-padded). Lower numbers fire first',
53
+ default: 0
54
+ }
55
+ },
56
+ required: [
57
+ 'field',
58
+ 'set_fields',
59
+ 'ref_field',
60
+ 'ref_fields'
61
+ ]
62
+ },
63
+ tags: [
64
+ 'trigger',
65
+ 'denormalization',
66
+ 'schema'
67
+ ]
68
+ };
@@ -3,6 +3,7 @@ export { CheckLessThan } from './check-less-than';
3
3
  export { CheckNotEqual } from './check-not-equal';
4
4
  export { CheckOneOf } from './check-one-of';
5
5
  export { DataBulk } from './data-bulk';
6
+ export { DataDenormalized } from './data-denormalized';
6
7
  export { DataCompositeField } from './data-composite-field';
7
8
  export { DataDirectOwner } from './data-direct-owner';
8
9
  export { DataEntityMembership } from './data-entity-membership';
package/esm/data/index.js CHANGED
@@ -3,6 +3,7 @@ export { CheckLessThan } from './check-less-than';
3
3
  export { CheckNotEqual } from './check-not-equal';
4
4
  export { CheckOneOf } from './check-one-of';
5
5
  export { DataBulk } from './data-bulk';
6
+ export { DataDenormalized } from './data-denormalized';
6
7
  export { DataCompositeField } from './data-composite-field';
7
8
  export { DataDirectOwner } from './data-direct-owner';
8
9
  export { DataEntityMembership } from './data-entity-membership';
@@ -0,0 +1 @@
1
+ export { GuardStepUp } from './step-up';
@@ -0,0 +1 @@
1
+ export { GuardStepUp } from './step-up';
@@ -0,0 +1,2 @@
1
+ import type { NodeTypeDefinition } from '../types';
2
+ export declare const GuardStepUp: NodeTypeDefinition;
@@ -0,0 +1,37 @@
1
+ import { conditionDefs, conditionProperties } from '../conditions';
2
+ export const GuardStepUp = {
3
+ name: 'GuardStepUp',
4
+ slug: 'guard_step_up',
5
+ category: 'guard',
6
+ display_name: 'Guard Step-Up',
7
+ description: 'Attaches a BEFORE trigger that calls require_step_up() to enforce recent ' +
8
+ 'password or MFA verification before allowing mutations. Requires a ' +
9
+ 'provisioned sessions_module (with app_settings_auth) for the target database. ' +
10
+ 'The step_up_window is read from app_settings_auth at runtime (default 30 minutes). ' +
11
+ 'Supports compound conditions (AND/OR/NOT), watch_fields (fire only when specific ' +
12
+ 'fields change), and simple condition_field/condition_value leaf conditions.',
13
+ parameter_schema: {
14
+ type: 'object',
15
+ $defs: conditionDefs,
16
+ properties: {
17
+ step_up_type: {
18
+ type: 'string',
19
+ enum: ['password', 'mfa', 'password_or_mfa'],
20
+ description: 'Which verification method satisfies the step-up requirement',
21
+ default: 'password_or_mfa',
22
+ },
23
+ events: {
24
+ type: 'array',
25
+ items: {
26
+ type: 'string',
27
+ enum: ['INSERT', 'UPDATE', 'DELETE'],
28
+ },
29
+ description: 'Which DML events require step-up verification',
30
+ default: ['UPDATE', 'DELETE'],
31
+ },
32
+ ...conditionProperties,
33
+ },
34
+ required: [],
35
+ },
36
+ tags: ['guard', 'triggers', 'auth', 'step-up', 'mfa', 'security'],
37
+ };
package/esm/index.d.ts CHANGED
@@ -3,6 +3,7 @@ export * from './blueprint-types.generated';
3
3
  export * from './conditions';
4
4
  export * from './data';
5
5
  export * from './event';
6
+ export * from './guard';
6
7
  export * from './job';
7
8
  export * from './limit';
8
9
  export * from './module-presets';
package/esm/index.js CHANGED
@@ -3,6 +3,7 @@ export * from './blueprint-types.generated';
3
3
  export * from './conditions';
4
4
  export * from './data';
5
5
  export * from './event';
6
+ export * from './guard';
6
7
  export * from './job';
7
8
  export * from './limit';
8
9
  export * from './module-presets';
@@ -12,6 +13,7 @@ export * from './view';
12
13
  import * as authz from './authz';
13
14
  import * as data from './data';
14
15
  import * as event from './event';
16
+ import * as guard from './guard';
15
17
  import * as job from './job';
16
18
  import * as limit from './limit';
17
19
  import * as process from './process';
@@ -21,6 +23,7 @@ export const allNodeTypes = [
21
23
  ...Object.values(authz),
22
24
  ...Object.values(data),
23
25
  ...Object.values(event),
26
+ ...Object.values(guard),
24
27
  ...Object.values(job),
25
28
  ...Object.values(limit),
26
29
  ...Object.values(process),
@@ -0,0 +1 @@
1
+ export { GuardStepUp } from './step-up';
package/guard/index.js ADDED
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GuardStepUp = void 0;
4
+ var step_up_1 = require("./step-up");
5
+ Object.defineProperty(exports, "GuardStepUp", { enumerable: true, get: function () { return step_up_1.GuardStepUp; } });
@@ -0,0 +1,2 @@
1
+ import type { NodeTypeDefinition } from '../types';
2
+ export declare const GuardStepUp: NodeTypeDefinition;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GuardStepUp = void 0;
4
+ const conditions_1 = require("../conditions");
5
+ exports.GuardStepUp = {
6
+ name: 'GuardStepUp',
7
+ slug: 'guard_step_up',
8
+ category: 'guard',
9
+ display_name: 'Guard Step-Up',
10
+ description: 'Attaches a BEFORE trigger that calls require_step_up() to enforce recent ' +
11
+ 'password or MFA verification before allowing mutations. Requires a ' +
12
+ 'provisioned sessions_module (with app_settings_auth) for the target database. ' +
13
+ 'The step_up_window is read from app_settings_auth at runtime (default 30 minutes). ' +
14
+ 'Supports compound conditions (AND/OR/NOT), watch_fields (fire only when specific ' +
15
+ 'fields change), and simple condition_field/condition_value leaf conditions.',
16
+ parameter_schema: {
17
+ type: 'object',
18
+ $defs: conditions_1.conditionDefs,
19
+ properties: {
20
+ step_up_type: {
21
+ type: 'string',
22
+ enum: ['password', 'mfa', 'password_or_mfa'],
23
+ description: 'Which verification method satisfies the step-up requirement',
24
+ default: 'password_or_mfa',
25
+ },
26
+ events: {
27
+ type: 'array',
28
+ items: {
29
+ type: 'string',
30
+ enum: ['INSERT', 'UPDATE', 'DELETE'],
31
+ },
32
+ description: 'Which DML events require step-up verification',
33
+ default: ['UPDATE', 'DELETE'],
34
+ },
35
+ ...conditions_1.conditionProperties,
36
+ },
37
+ required: [],
38
+ },
39
+ tags: ['guard', 'triggers', 'auth', 'step-up', 'mfa', 'security'],
40
+ };
package/index.d.ts CHANGED
@@ -3,6 +3,7 @@ export * from './blueprint-types.generated';
3
3
  export * from './conditions';
4
4
  export * from './data';
5
5
  export * from './event';
6
+ export * from './guard';
6
7
  export * from './job';
7
8
  export * from './limit';
8
9
  export * from './module-presets';
package/index.js CHANGED
@@ -42,6 +42,7 @@ __exportStar(require("./blueprint-types.generated"), exports);
42
42
  __exportStar(require("./conditions"), exports);
43
43
  __exportStar(require("./data"), exports);
44
44
  __exportStar(require("./event"), exports);
45
+ __exportStar(require("./guard"), exports);
45
46
  __exportStar(require("./job"), exports);
46
47
  __exportStar(require("./limit"), exports);
47
48
  __exportStar(require("./module-presets"), exports);
@@ -51,6 +52,7 @@ __exportStar(require("./view"), exports);
51
52
  const authz = __importStar(require("./authz"));
52
53
  const data = __importStar(require("./data"));
53
54
  const event = __importStar(require("./event"));
55
+ const guard = __importStar(require("./guard"));
54
56
  const job = __importStar(require("./job"));
55
57
  const limit = __importStar(require("./limit"));
56
58
  const process = __importStar(require("./process"));
@@ -60,6 +62,7 @@ exports.allNodeTypes = [
60
62
  ...Object.values(authz),
61
63
  ...Object.values(data),
62
64
  ...Object.values(event),
65
+ ...Object.values(guard),
63
66
  ...Object.values(job),
64
67
  ...Object.values(limit),
65
68
  ...Object.values(process),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-type-registry",
3
- "version": "0.47.0",
3
+ "version": "0.49.0",
4
4
  "description": "Node type definitions for the Constructive blueprint system. Single source of truth for all Authz*, Data*, Relation*, and View* node types.",
5
5
  "author": "Constructive <developers@constructive.io>",
6
6
  "main": "index.js",
@@ -47,5 +47,5 @@
47
47
  "registry",
48
48
  "graphile"
49
49
  ],
50
- "gitHead": "c9ff6a6cec5d8cb455010b190b78c3d055097981"
50
+ "gitHead": "6d810d1b800a6e70ef25749415b69de17b066e50"
51
51
  }