node-type-registry 0.10.0 → 0.11.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
@@ -1,5 +1,17 @@
1
1
  # node-type-registry
2
2
 
3
+ <p align="center" width="100%">
4
+ <img height="250" src="https://raw.githubusercontent.com/constructive-io/constructive/refs/heads/main/assets/outline-logo.svg" />
5
+ </p>
6
+
7
+ <p align="center" width="100%">
8
+ <a href="https://github.com/constructive-io/constructive/actions/workflows/run-tests.yaml">
9
+ <img height="20" src="https://github.com/constructive-io/constructive/actions/workflows/run-tests.yaml/badge.svg" />
10
+ </a>
11
+ <a href="https://github.com/constructive-io/constructive/blob/main/LICENSE"><img height="20" src="https://img.shields.io/badge/license-MIT-blue.svg"/></a>
12
+ <a href="https://www.npmjs.com/package/node-type-registry"><img height="20" src="https://img.shields.io/github/package-json/v/constructive-io/constructive?filename=graphql%2Fnode-type-registry%2Fpackage.json"/></a>
13
+ </p>
14
+
3
15
  Node type definitions for the Constructive blueprint system. Single source of truth for all Authz*, Data*, Relation*, View*, and Table* node types.
4
16
 
5
17
  ## Usage
@@ -19,7 +19,11 @@ exports.AuthzEntityMembership = {
19
19
  "integer",
20
20
  "string"
21
21
  ],
22
- "description": "Scope: 1=app, 2=org, 3=group (or string name resolved via membership_types_module)"
22
+ "description": "Scope: 1=app, 2=org, 3+=dynamic entity types (or string name resolved via membership_types_module)"
23
+ },
24
+ "entity_type": {
25
+ "type": "string",
26
+ "description": "Entity type prefix (e.g. 'channel', 'department'). Resolved to membership_type integer via memberships_module lookup. Use instead of membership_type for readability."
23
27
  },
24
28
  "permission": {
25
29
  "type": "string",
@@ -15,7 +15,11 @@ exports.AuthzMembership = {
15
15
  "integer",
16
16
  "string"
17
17
  ],
18
- "description": "Scope: 1=app, 2=org, 3=group (or string name resolved via membership_types_module)"
18
+ "description": "Scope: 1=app, 2=org, 3+=dynamic entity types (or string name resolved via membership_types_module)"
19
+ },
20
+ "entity_type": {
21
+ "type": "string",
22
+ "description": "Entity type prefix (e.g. 'channel', 'department'). Resolved to membership_type integer via memberships_module lookup. Use instead of membership_type for readability."
19
23
  },
20
24
  "permission": {
21
25
  "type": "string",
@@ -37,9 +41,7 @@ exports.AuthzMembership = {
37
41
  "description": "If true, require is_owner flag"
38
42
  }
39
43
  },
40
- "required": [
41
- "membership_type"
42
- ]
44
+ "required": []
43
45
  },
44
46
  "tags": [
45
47
  "membership",
@@ -19,7 +19,11 @@ exports.AuthzPeerOwnership = {
19
19
  "integer",
20
20
  "string"
21
21
  ],
22
- "description": "Scope: 1=app, 2=org, 3=group (or string name resolved via membership_types_module)"
22
+ "description": "Scope: 1=app, 2=org, 3+=dynamic entity types (or string name resolved via membership_types_module)"
23
+ },
24
+ "entity_type": {
25
+ "type": "string",
26
+ "description": "Entity type prefix (e.g. 'channel', 'department'). Resolved to membership_type integer via memberships_module lookup. Use instead of membership_type for readability."
23
27
  },
24
28
  "permission": {
25
29
  "type": "string",
@@ -19,7 +19,11 @@ exports.AuthzRelatedEntityMembership = {
19
19
  "integer",
20
20
  "string"
21
21
  ],
22
- "description": "Scope: 1=app, 2=org, 3=group (or string name resolved via membership_types_module)"
22
+ "description": "Scope: 1=app, 2=org, 3+=dynamic entity types (or string name resolved via membership_types_module)"
23
+ },
24
+ "entity_type": {
25
+ "type": "string",
26
+ "description": "Entity type prefix (e.g. 'channel', 'department'). Resolved to membership_type integer via memberships_module lookup. Use instead of membership_type for readability."
23
27
  },
24
28
  "obj_table_id": {
25
29
  "type": "string",
@@ -19,7 +19,11 @@ exports.AuthzRelatedPeerOwnership = {
19
19
  "integer",
20
20
  "string"
21
21
  ],
22
- "description": "Scope: 1=app, 2=org, 3=group (or string name resolved via membership_types_module)"
22
+ "description": "Scope: 1=app, 2=org, 3+=dynamic entity types (or string name resolved via membership_types_module)"
23
+ },
24
+ "entity_type": {
25
+ "type": "string",
26
+ "description": "Entity type prefix (e.g. 'channel', 'department'). Resolved to membership_type integer via memberships_module lookup. Use instead of membership_type for readability."
23
27
  },
24
28
  "obj_table_id": {
25
29
  "type": "string",
@@ -549,6 +549,29 @@ export interface BlueprintTableUniqueConstraint {
549
549
  /** Optional schema name override. */
550
550
  schema_name?: string;
551
551
  }
552
+ /** A membership type entry for Phase 0 of construct_blueprint(). Provisions a full entity type with its own entity table, membership modules, and security policies via entity_type_provision. */
553
+ export interface BlueprintMembershipType {
554
+ /** Entity type name (e.g., "data_room", "channel", "department"). Must be unique per database. */
555
+ name: string;
556
+ /** Short prefix for generated objects (e.g., "dr", "ch", "dept"). Used in table/trigger naming. */
557
+ prefix: string;
558
+ /** Human-readable description of this entity type. */
559
+ description?: string;
560
+ /** Parent entity type name. Defaults to "org". */
561
+ parent_entity?: string;
562
+ /** Custom table name for the entity table. Defaults to name-derived convention. */
563
+ table_name?: string;
564
+ /** Whether this entity type is visible in the API. Defaults to true. */
565
+ is_visible?: boolean;
566
+ /** Whether to provision a limits module for this entity type. Defaults to false. */
567
+ has_limits?: boolean;
568
+ /** Whether to provision a profiles module for this entity type. Defaults to false. */
569
+ has_profiles?: boolean;
570
+ /** Whether to provision a levels module for this entity type. Defaults to false. */
571
+ has_levels?: boolean;
572
+ /** Whether to skip creating default RLS policies on the entity table. Defaults to false. */
573
+ skip_entity_policies?: boolean;
574
+ }
552
575
  /** String shorthand -- just the node type name. */
553
576
  export type BlueprintNodeShorthand = "AuthzDirectOwner" | "AuthzDirectOwnerAny" | "AuthzMembership" | "AuthzEntityMembership" | "AuthzRelatedEntityMembership" | "AuthzOrgHierarchy" | "AuthzTemporal" | "AuthzPublishable" | "AuthzMemberList" | "AuthzRelatedMemberList" | "AuthzAllowAll" | "AuthzDenyAll" | "AuthzComposite" | "AuthzPeerOwnership" | "AuthzRelatedPeerOwnership" | "DataId" | "DataDirectOwner" | "DataEntityMembership" | "DataOwnershipInEntity" | "DataTimestamps" | "DataPeoplestamps" | "DataPublishable" | "DataSoftDelete" | "SearchVector" | "SearchFullText" | "SearchBm25" | "SearchUnified" | "SearchSpatial" | "SearchSpatialAggregate" | "DataJobTrigger" | "DataTags" | "DataStatusField" | "DataJsonb" | "SearchTrgm" | "DataSlug" | "DataInflection" | "DataOwnedFields" | "DataInheritFromParent" | "DataForceCurrentUser" | "DataImmutableFields" | "DataCompositeField" | "TableUserProfiles" | "TableOrganizationSettings" | "TableUserSettings";
554
577
  /** Object form -- { $type, data } with typed parameters. */
@@ -750,4 +773,6 @@ export interface BlueprintDefinition {
750
773
  full_text_searches?: BlueprintFullTextSearch[];
751
774
  /** Unique constraints on table columns. */
752
775
  unique_constraints?: BlueprintUniqueConstraint[];
776
+ /** Entity types to provision in Phase 0 (before tables). Each entry creates an entity table with membership modules and security. */
777
+ membership_types?: BlueprintMembershipType[];
753
778
  }
@@ -384,6 +384,20 @@ function buildBlueprintTableUniqueConstraint() {
384
384
  addJSDoc(optionalProp('schema_name', t.tsStringKeyword()), 'Optional schema name override.'),
385
385
  ]), 'A unique constraint nested inside a table definition (table_name not required).');
386
386
  }
387
+ function buildBlueprintMembershipType() {
388
+ return addJSDoc(exportInterface('BlueprintMembershipType', [
389
+ addJSDoc(requiredProp('name', t.tsStringKeyword()), 'Entity type name (e.g., "data_room", "channel", "department"). Must be unique per database.'),
390
+ addJSDoc(requiredProp('prefix', t.tsStringKeyword()), 'Short prefix for generated objects (e.g., "dr", "ch", "dept"). Used in table/trigger naming.'),
391
+ addJSDoc(optionalProp('description', t.tsStringKeyword()), 'Human-readable description of this entity type.'),
392
+ addJSDoc(optionalProp('parent_entity', t.tsStringKeyword()), 'Parent entity type name. Defaults to "org".'),
393
+ addJSDoc(optionalProp('table_name', t.tsStringKeyword()), 'Custom table name for the entity table. Defaults to name-derived convention.'),
394
+ addJSDoc(optionalProp('is_visible', t.tsBooleanKeyword()), 'Whether this entity type is visible in the API. Defaults to true.'),
395
+ addJSDoc(optionalProp('has_limits', t.tsBooleanKeyword()), 'Whether to provision a limits module for this entity type. Defaults to false.'),
396
+ addJSDoc(optionalProp('has_profiles', t.tsBooleanKeyword()), 'Whether to provision a profiles module for this entity type. Defaults to false.'),
397
+ addJSDoc(optionalProp('has_levels', t.tsBooleanKeyword()), 'Whether to provision a levels module for this entity type. Defaults to false.'),
398
+ addJSDoc(optionalProp('skip_entity_policies', t.tsBooleanKeyword()), 'Whether to skip creating default RLS policies on the entity table. Defaults to false.'),
399
+ ]), 'A membership type entry for Phase 0 of construct_blueprint(). Provisions a full entity type with its own entity table, membership modules, and security policies via entity_type_provision.');
400
+ }
387
401
  function buildBlueprintTable() {
388
402
  return addJSDoc(exportInterface('BlueprintTable', [
389
403
  addJSDoc(requiredProp('table_name', t.tsStringKeyword()), 'The PostgreSQL table name to create.'),
@@ -406,6 +420,7 @@ function buildBlueprintDefinition() {
406
420
  addJSDoc(optionalProp('indexes', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintIndex')))), 'Indexes on table columns.'),
407
421
  addJSDoc(optionalProp('full_text_searches', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintFullTextSearch')))), 'Full-text search configurations.'),
408
422
  addJSDoc(optionalProp('unique_constraints', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintUniqueConstraint')))), 'Unique constraints on table columns.'),
423
+ addJSDoc(optionalProp('membership_types', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintMembershipType')))), 'Entity types to provision in Phase 0 (before tables). Each entry creates an entity table with membership modules and security.'),
409
424
  ]), 'The complete blueprint definition -- the JSONB shape accepted by construct_blueprint().');
410
425
  }
411
426
  // ---------------------------------------------------------------------------
@@ -459,6 +474,7 @@ function buildProgram(meta) {
459
474
  statements.push(buildBlueprintTableIndex());
460
475
  statements.push(buildBlueprintUniqueConstraint());
461
476
  statements.push(buildBlueprintTableUniqueConstraint());
477
+ statements.push(buildBlueprintMembershipType());
462
478
  // -- Node types discriminated union --
463
479
  statements.push(sectionComment('Node types -- discriminated union for nodes[] entries'));
464
480
  statements.push(...buildNodeTypes(dataNodes));
@@ -16,7 +16,11 @@ export const AuthzEntityMembership = {
16
16
  "integer",
17
17
  "string"
18
18
  ],
19
- "description": "Scope: 1=app, 2=org, 3=group (or string name resolved via membership_types_module)"
19
+ "description": "Scope: 1=app, 2=org, 3+=dynamic entity types (or string name resolved via membership_types_module)"
20
+ },
21
+ "entity_type": {
22
+ "type": "string",
23
+ "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
24
  },
21
25
  "permission": {
22
26
  "type": "string",
@@ -12,7 +12,11 @@ export const AuthzMembership = {
12
12
  "integer",
13
13
  "string"
14
14
  ],
15
- "description": "Scope: 1=app, 2=org, 3=group (or string name resolved via membership_types_module)"
15
+ "description": "Scope: 1=app, 2=org, 3+=dynamic entity types (or string name resolved via membership_types_module)"
16
+ },
17
+ "entity_type": {
18
+ "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
20
  },
17
21
  "permission": {
18
22
  "type": "string",
@@ -34,9 +38,7 @@ export const AuthzMembership = {
34
38
  "description": "If true, require is_owner flag"
35
39
  }
36
40
  },
37
- "required": [
38
- "membership_type"
39
- ]
41
+ "required": []
40
42
  },
41
43
  "tags": [
42
44
  "membership",
@@ -16,7 +16,11 @@ export const AuthzPeerOwnership = {
16
16
  "integer",
17
17
  "string"
18
18
  ],
19
- "description": "Scope: 1=app, 2=org, 3=group (or string name resolved via membership_types_module)"
19
+ "description": "Scope: 1=app, 2=org, 3+=dynamic entity types (or string name resolved via membership_types_module)"
20
+ },
21
+ "entity_type": {
22
+ "type": "string",
23
+ "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
24
  },
21
25
  "permission": {
22
26
  "type": "string",
@@ -16,7 +16,11 @@ export const AuthzRelatedEntityMembership = {
16
16
  "integer",
17
17
  "string"
18
18
  ],
19
- "description": "Scope: 1=app, 2=org, 3=group (or string name resolved via membership_types_module)"
19
+ "description": "Scope: 1=app, 2=org, 3+=dynamic entity types (or string name resolved via membership_types_module)"
20
+ },
21
+ "entity_type": {
22
+ "type": "string",
23
+ "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
24
  },
21
25
  "obj_table_id": {
22
26
  "type": "string",
@@ -16,7 +16,11 @@ export const AuthzRelatedPeerOwnership = {
16
16
  "integer",
17
17
  "string"
18
18
  ],
19
- "description": "Scope: 1=app, 2=org, 3=group (or string name resolved via membership_types_module)"
19
+ "description": "Scope: 1=app, 2=org, 3+=dynamic entity types (or string name resolved via membership_types_module)"
20
+ },
21
+ "entity_type": {
22
+ "type": "string",
23
+ "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
24
  },
21
25
  "obj_table_id": {
22
26
  "type": "string",
@@ -549,6 +549,29 @@ export interface BlueprintTableUniqueConstraint {
549
549
  /** Optional schema name override. */
550
550
  schema_name?: string;
551
551
  }
552
+ /** A membership type entry for Phase 0 of construct_blueprint(). Provisions a full entity type with its own entity table, membership modules, and security policies via entity_type_provision. */
553
+ export interface BlueprintMembershipType {
554
+ /** Entity type name (e.g., "data_room", "channel", "department"). Must be unique per database. */
555
+ name: string;
556
+ /** Short prefix for generated objects (e.g., "dr", "ch", "dept"). Used in table/trigger naming. */
557
+ prefix: string;
558
+ /** Human-readable description of this entity type. */
559
+ description?: string;
560
+ /** Parent entity type name. Defaults to "org". */
561
+ parent_entity?: string;
562
+ /** Custom table name for the entity table. Defaults to name-derived convention. */
563
+ table_name?: string;
564
+ /** Whether this entity type is visible in the API. Defaults to true. */
565
+ is_visible?: boolean;
566
+ /** Whether to provision a limits module for this entity type. Defaults to false. */
567
+ has_limits?: boolean;
568
+ /** Whether to provision a profiles module for this entity type. Defaults to false. */
569
+ has_profiles?: boolean;
570
+ /** Whether to provision a levels module for this entity type. Defaults to false. */
571
+ has_levels?: boolean;
572
+ /** Whether to skip creating default RLS policies on the entity table. Defaults to false. */
573
+ skip_entity_policies?: boolean;
574
+ }
552
575
  /** String shorthand -- just the node type name. */
553
576
  export type BlueprintNodeShorthand = "AuthzDirectOwner" | "AuthzDirectOwnerAny" | "AuthzMembership" | "AuthzEntityMembership" | "AuthzRelatedEntityMembership" | "AuthzOrgHierarchy" | "AuthzTemporal" | "AuthzPublishable" | "AuthzMemberList" | "AuthzRelatedMemberList" | "AuthzAllowAll" | "AuthzDenyAll" | "AuthzComposite" | "AuthzPeerOwnership" | "AuthzRelatedPeerOwnership" | "DataId" | "DataDirectOwner" | "DataEntityMembership" | "DataOwnershipInEntity" | "DataTimestamps" | "DataPeoplestamps" | "DataPublishable" | "DataSoftDelete" | "SearchVector" | "SearchFullText" | "SearchBm25" | "SearchUnified" | "SearchSpatial" | "SearchSpatialAggregate" | "DataJobTrigger" | "DataTags" | "DataStatusField" | "DataJsonb" | "SearchTrgm" | "DataSlug" | "DataInflection" | "DataOwnedFields" | "DataInheritFromParent" | "DataForceCurrentUser" | "DataImmutableFields" | "DataCompositeField" | "TableUserProfiles" | "TableOrganizationSettings" | "TableUserSettings";
554
577
  /** Object form -- { $type, data } with typed parameters. */
@@ -750,4 +773,6 @@ export interface BlueprintDefinition {
750
773
  full_text_searches?: BlueprintFullTextSearch[];
751
774
  /** Unique constraints on table columns. */
752
775
  unique_constraints?: BlueprintUniqueConstraint[];
776
+ /** Entity types to provision in Phase 0 (before tables). Each entry creates an entity table with membership modules and security. */
777
+ membership_types?: BlueprintMembershipType[];
753
778
  }
@@ -349,6 +349,20 @@ function buildBlueprintTableUniqueConstraint() {
349
349
  addJSDoc(optionalProp('schema_name', t.tsStringKeyword()), 'Optional schema name override.'),
350
350
  ]), 'A unique constraint nested inside a table definition (table_name not required).');
351
351
  }
352
+ function buildBlueprintMembershipType() {
353
+ return addJSDoc(exportInterface('BlueprintMembershipType', [
354
+ addJSDoc(requiredProp('name', t.tsStringKeyword()), 'Entity type name (e.g., "data_room", "channel", "department"). Must be unique per database.'),
355
+ addJSDoc(requiredProp('prefix', t.tsStringKeyword()), 'Short prefix for generated objects (e.g., "dr", "ch", "dept"). Used in table/trigger naming.'),
356
+ addJSDoc(optionalProp('description', t.tsStringKeyword()), 'Human-readable description of this entity type.'),
357
+ addJSDoc(optionalProp('parent_entity', t.tsStringKeyword()), 'Parent entity type name. Defaults to "org".'),
358
+ addJSDoc(optionalProp('table_name', t.tsStringKeyword()), 'Custom table name for the entity table. Defaults to name-derived convention.'),
359
+ addJSDoc(optionalProp('is_visible', t.tsBooleanKeyword()), 'Whether this entity type is visible in the API. Defaults to true.'),
360
+ addJSDoc(optionalProp('has_limits', t.tsBooleanKeyword()), 'Whether to provision a limits module for this entity type. Defaults to false.'),
361
+ addJSDoc(optionalProp('has_profiles', t.tsBooleanKeyword()), 'Whether to provision a profiles module for this entity type. Defaults to false.'),
362
+ addJSDoc(optionalProp('has_levels', t.tsBooleanKeyword()), 'Whether to provision a levels module for this entity type. Defaults to false.'),
363
+ addJSDoc(optionalProp('skip_entity_policies', t.tsBooleanKeyword()), 'Whether to skip creating default RLS policies on the entity table. Defaults to false.'),
364
+ ]), 'A membership type entry for Phase 0 of construct_blueprint(). Provisions a full entity type with its own entity table, membership modules, and security policies via entity_type_provision.');
365
+ }
352
366
  function buildBlueprintTable() {
353
367
  return addJSDoc(exportInterface('BlueprintTable', [
354
368
  addJSDoc(requiredProp('table_name', t.tsStringKeyword()), 'The PostgreSQL table name to create.'),
@@ -371,6 +385,7 @@ function buildBlueprintDefinition() {
371
385
  addJSDoc(optionalProp('indexes', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintIndex')))), 'Indexes on table columns.'),
372
386
  addJSDoc(optionalProp('full_text_searches', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintFullTextSearch')))), 'Full-text search configurations.'),
373
387
  addJSDoc(optionalProp('unique_constraints', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintUniqueConstraint')))), 'Unique constraints on table columns.'),
388
+ addJSDoc(optionalProp('membership_types', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintMembershipType')))), 'Entity types to provision in Phase 0 (before tables). Each entry creates an entity table with membership modules and security.'),
374
389
  ]), 'The complete blueprint definition -- the JSONB shape accepted by construct_blueprint().');
375
390
  }
376
391
  // ---------------------------------------------------------------------------
@@ -424,6 +439,7 @@ function buildProgram(meta) {
424
439
  statements.push(buildBlueprintTableIndex());
425
440
  statements.push(buildBlueprintUniqueConstraint());
426
441
  statements.push(buildBlueprintTableUniqueConstraint());
442
+ statements.push(buildBlueprintMembershipType());
427
443
  // -- Node types discriminated union --
428
444
  statements.push(sectionComment('Node types -- discriminated union for nodes[] entries'));
429
445
  statements.push(...buildNodeTypes(dataNodes));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-type-registry",
3
- "version": "0.10.0",
3
+ "version": "0.11.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",
@@ -48,5 +48,5 @@
48
48
  "registry",
49
49
  "graphile"
50
50
  ],
51
- "gitHead": "2128d45cd2dba727e18910a05665b1f5c7c137ae"
51
+ "gitHead": "ec793fd5de36264f5c9738732657522c1d783a6d"
52
52
  }