node-type-registry 0.11.0 → 0.12.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
@@ -83,14 +83,6 @@ cd graphql/node-type-registry && pnpm generate:types
83
83
 
84
84
  This produces `src/blueprint-types.generated.ts` from the TS node type source of truth.
85
85
 
86
- ## Codegen: SQL seed
87
-
88
- Generate SQL seed scripts for `node_type_registry` table:
89
-
90
- ```bash
91
- cd graphql/node-type-registry && pnpm generate:seed --pgpm ../../constructive-db/packages/metaschema
92
- ```
93
-
94
86
  ---
95
87
 
96
88
  ## Education and Tutorials
@@ -0,0 +1,2 @@
1
+ import type { NodeTypeDefinition } from '../types';
2
+ export declare const AuthzNotReadOnly: NodeTypeDefinition;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AuthzNotReadOnly = void 0;
4
+ exports.AuthzNotReadOnly = {
5
+ "name": "AuthzNotReadOnly",
6
+ "slug": "authz_not_read_only",
7
+ "category": "authz",
8
+ "display_name": "Not Read-Only",
9
+ "description": "Restrictive policy that blocks read-only members from mutations. Checks actor_id + is_read_only IS NOT TRUE on the SPRT. Designed to run as a restrictive counterpart after a permissive AuthzEntityMembership policy has already verified membership.",
10
+ "parameter_schema": {
11
+ "type": "object",
12
+ "properties": {
13
+ "entity_field": {
14
+ "type": "string",
15
+ "description": "Column name referencing the entity (e.g., entity_id, org_id)"
16
+ },
17
+ "membership_type": {
18
+ "type": [
19
+ "integer",
20
+ "string"
21
+ ],
22
+ "description": "Scope: 2=org, 3+=dynamic entity types. Must be >= 2 (entity-scoped)."
23
+ }
24
+ },
25
+ "required": [
26
+ "entity_field"
27
+ ]
28
+ },
29
+ "tags": [
30
+ "membership",
31
+ "authz",
32
+ "restrictive"
33
+ ]
34
+ };
package/authz/index.d.ts CHANGED
@@ -11,5 +11,6 @@ export { AuthzRelatedMemberList } from './authz-related-member-list';
11
11
  export { AuthzAllowAll } from './authz-allow-all';
12
12
  export { AuthzDenyAll } from './authz-deny-all';
13
13
  export { AuthzComposite } from './authz-composite';
14
+ export { AuthzNotReadOnly } from './authz-not-read-only';
14
15
  export { AuthzPeerOwnership } from './authz-peer-ownership';
15
16
  export { AuthzRelatedPeerOwnership } from './authz-related-peer-ownership';
package/authz/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AuthzRelatedPeerOwnership = exports.AuthzPeerOwnership = exports.AuthzComposite = exports.AuthzDenyAll = exports.AuthzAllowAll = exports.AuthzRelatedMemberList = exports.AuthzMemberList = exports.AuthzPublishable = exports.AuthzTemporal = exports.AuthzOrgHierarchy = exports.AuthzRelatedEntityMembership = exports.AuthzEntityMembership = exports.AuthzMembership = exports.AuthzDirectOwnerAny = exports.AuthzDirectOwner = void 0;
3
+ exports.AuthzRelatedPeerOwnership = exports.AuthzPeerOwnership = exports.AuthzNotReadOnly = exports.AuthzComposite = exports.AuthzDenyAll = exports.AuthzAllowAll = exports.AuthzRelatedMemberList = exports.AuthzMemberList = exports.AuthzPublishable = exports.AuthzTemporal = exports.AuthzOrgHierarchy = exports.AuthzRelatedEntityMembership = exports.AuthzEntityMembership = exports.AuthzMembership = exports.AuthzDirectOwnerAny = exports.AuthzDirectOwner = void 0;
4
4
  var authz_direct_owner_1 = require("./authz-direct-owner");
5
5
  Object.defineProperty(exports, "AuthzDirectOwner", { enumerable: true, get: function () { return authz_direct_owner_1.AuthzDirectOwner; } });
6
6
  var authz_direct_owner_any_1 = require("./authz-direct-owner-any");
@@ -27,6 +27,8 @@ var authz_deny_all_1 = require("./authz-deny-all");
27
27
  Object.defineProperty(exports, "AuthzDenyAll", { enumerable: true, get: function () { return authz_deny_all_1.AuthzDenyAll; } });
28
28
  var authz_composite_1 = require("./authz-composite");
29
29
  Object.defineProperty(exports, "AuthzComposite", { enumerable: true, get: function () { return authz_composite_1.AuthzComposite; } });
30
+ var authz_not_read_only_1 = require("./authz-not-read-only");
31
+ Object.defineProperty(exports, "AuthzNotReadOnly", { enumerable: true, get: function () { return authz_not_read_only_1.AuthzNotReadOnly; } });
30
32
  var authz_peer_ownership_1 = require("./authz-peer-ownership");
31
33
  Object.defineProperty(exports, "AuthzPeerOwnership", { enumerable: true, get: function () { return authz_peer_ownership_1.AuthzPeerOwnership; } });
32
34
  var authz_related_peer_ownership_1 = require("./authz-related-peer-ownership");
@@ -247,7 +247,8 @@ export interface AuthzDirectOwnerAnyParams {
247
247
  }
248
248
  /** Membership check that verifies the user has membership (optionally with specific permission) without binding to any entity from the row. Uses EXISTS subquery against SPRT table. */
249
249
  export interface AuthzMembershipParams {
250
- membership_type: number | string;
250
+ membership_type?: number | string;
251
+ entity_type?: string;
251
252
  permission?: string;
252
253
  permissions?: string[];
253
254
  is_admin?: boolean;
@@ -257,6 +258,7 @@ export interface AuthzMembershipParams {
257
258
  export interface AuthzEntityMembershipParams {
258
259
  entity_field: string;
259
260
  membership_type?: number | string;
261
+ entity_type?: string;
260
262
  permission?: string;
261
263
  permissions?: string[];
262
264
  is_admin?: boolean;
@@ -266,6 +268,7 @@ export interface AuthzEntityMembershipParams {
266
268
  export interface AuthzRelatedEntityMembershipParams {
267
269
  entity_field: string;
268
270
  membership_type?: number | string;
271
+ entity_type?: string;
269
272
  obj_table_id?: string;
270
273
  obj_schema?: string;
271
274
  obj_table?: string;
@@ -321,10 +324,16 @@ export interface AuthzCompositeParams {
321
324
  }[];
322
325
  };
323
326
  }
327
+ /** Restrictive policy that blocks read-only members from mutations. Checks actor_id + is_read_only IS NOT TRUE on the SPRT. Designed to run as a restrictive counterpart after a permissive AuthzEntityMembership policy has already verified membership. */
328
+ export interface AuthzNotReadOnlyParams {
329
+ entity_field: string;
330
+ membership_type?: number | string;
331
+ }
324
332
  /** Peer visibility through shared entity membership. Authorizes access to user-owned rows when the owner and current user are both members of the same entity. Self-joins the SPRT table to find peers. */
325
333
  export interface AuthzPeerOwnershipParams {
326
334
  owner_field: string;
327
335
  membership_type?: number | string;
336
+ entity_type?: string;
328
337
  permission?: string;
329
338
  permissions?: string[];
330
339
  is_admin?: boolean;
@@ -334,6 +343,7 @@ export interface AuthzPeerOwnershipParams {
334
343
  export interface AuthzRelatedPeerOwnershipParams {
335
344
  entity_field: string;
336
345
  membership_type?: number | string;
346
+ entity_type?: string;
337
347
  obj_table_id?: string;
338
348
  obj_schema?: string;
339
349
  obj_table?: string;
@@ -452,7 +462,7 @@ export interface BlueprintField {
452
462
  /** An RLS policy entry for a blueprint table. Uses $type to match the blueprint JSON convention. */
453
463
  export interface BlueprintPolicy {
454
464
  /** Authz* policy type name (e.g., "AuthzDirectOwner", "AuthzAllowAll"). */
455
- $type: "AuthzDirectOwner" | "AuthzDirectOwnerAny" | "AuthzMembership" | "AuthzEntityMembership" | "AuthzRelatedEntityMembership" | "AuthzOrgHierarchy" | "AuthzTemporal" | "AuthzPublishable" | "AuthzMemberList" | "AuthzRelatedMemberList" | "AuthzAllowAll" | "AuthzDenyAll" | "AuthzComposite" | "AuthzPeerOwnership" | "AuthzRelatedPeerOwnership";
465
+ $type: "AuthzDirectOwner" | "AuthzDirectOwnerAny" | "AuthzMembership" | "AuthzEntityMembership" | "AuthzRelatedEntityMembership" | "AuthzOrgHierarchy" | "AuthzTemporal" | "AuthzPublishable" | "AuthzMemberList" | "AuthzRelatedMemberList" | "AuthzAllowAll" | "AuthzDenyAll" | "AuthzComposite" | "AuthzNotReadOnly" | "AuthzPeerOwnership" | "AuthzRelatedPeerOwnership";
456
466
  /** Privileges this policy applies to (e.g., ["select"], ["insert", "update", "delete"]). */
457
467
  privileges?: string[];
458
468
  /** Whether this policy is permissive (true) or restrictive (false). Defaults to true. */
@@ -573,7 +583,7 @@ export interface BlueprintMembershipType {
573
583
  skip_entity_policies?: boolean;
574
584
  }
575
585
  /** String shorthand -- just the node type name. */
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";
586
+ export type BlueprintNodeShorthand = "AuthzDirectOwner" | "AuthzDirectOwnerAny" | "AuthzMembership" | "AuthzEntityMembership" | "AuthzRelatedEntityMembership" | "AuthzOrgHierarchy" | "AuthzTemporal" | "AuthzPublishable" | "AuthzMemberList" | "AuthzRelatedMemberList" | "AuthzAllowAll" | "AuthzDenyAll" | "AuthzComposite" | "AuthzNotReadOnly" | "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";
577
587
  /** Object form -- { $type, data } with typed parameters. */
578
588
  export type BlueprintNodeObject = {
579
589
  $type: "AuthzDirectOwner";
@@ -614,6 +624,9 @@ export type BlueprintNodeObject = {
614
624
  } | {
615
625
  $type: "AuthzComposite";
616
626
  data: AuthzCompositeParams;
627
+ } | {
628
+ $type: "AuthzNotReadOnly";
629
+ data: AuthzNotReadOnlyParams;
617
630
  } | {
618
631
  $type: "AuthzPeerOwnership";
619
632
  data: AuthzPeerOwnershipParams;
@@ -0,0 +1,2 @@
1
+ import type { NodeTypeDefinition } from '../types';
2
+ export declare const AuthzNotReadOnly: NodeTypeDefinition;
@@ -0,0 +1,31 @@
1
+ export const AuthzNotReadOnly = {
2
+ "name": "AuthzNotReadOnly",
3
+ "slug": "authz_not_read_only",
4
+ "category": "authz",
5
+ "display_name": "Not Read-Only",
6
+ "description": "Restrictive policy that blocks read-only members from mutations. Checks actor_id + is_read_only IS NOT TRUE on the SPRT. Designed to run as a restrictive counterpart after a permissive AuthzEntityMembership policy has already verified membership.",
7
+ "parameter_schema": {
8
+ "type": "object",
9
+ "properties": {
10
+ "entity_field": {
11
+ "type": "string",
12
+ "description": "Column name referencing the entity (e.g., entity_id, org_id)"
13
+ },
14
+ "membership_type": {
15
+ "type": [
16
+ "integer",
17
+ "string"
18
+ ],
19
+ "description": "Scope: 2=org, 3+=dynamic entity types. Must be >= 2 (entity-scoped)."
20
+ }
21
+ },
22
+ "required": [
23
+ "entity_field"
24
+ ]
25
+ },
26
+ "tags": [
27
+ "membership",
28
+ "authz",
29
+ "restrictive"
30
+ ]
31
+ };
@@ -11,5 +11,6 @@ export { AuthzRelatedMemberList } from './authz-related-member-list';
11
11
  export { AuthzAllowAll } from './authz-allow-all';
12
12
  export { AuthzDenyAll } from './authz-deny-all';
13
13
  export { AuthzComposite } from './authz-composite';
14
+ export { AuthzNotReadOnly } from './authz-not-read-only';
14
15
  export { AuthzPeerOwnership } from './authz-peer-ownership';
15
16
  export { AuthzRelatedPeerOwnership } from './authz-related-peer-ownership';
@@ -11,5 +11,6 @@ export { AuthzRelatedMemberList } from './authz-related-member-list';
11
11
  export { AuthzAllowAll } from './authz-allow-all';
12
12
  export { AuthzDenyAll } from './authz-deny-all';
13
13
  export { AuthzComposite } from './authz-composite';
14
+ export { AuthzNotReadOnly } from './authz-not-read-only';
14
15
  export { AuthzPeerOwnership } from './authz-peer-ownership';
15
16
  export { AuthzRelatedPeerOwnership } from './authz-related-peer-ownership';
@@ -247,7 +247,8 @@ export interface AuthzDirectOwnerAnyParams {
247
247
  }
248
248
  /** Membership check that verifies the user has membership (optionally with specific permission) without binding to any entity from the row. Uses EXISTS subquery against SPRT table. */
249
249
  export interface AuthzMembershipParams {
250
- membership_type: number | string;
250
+ membership_type?: number | string;
251
+ entity_type?: string;
251
252
  permission?: string;
252
253
  permissions?: string[];
253
254
  is_admin?: boolean;
@@ -257,6 +258,7 @@ export interface AuthzMembershipParams {
257
258
  export interface AuthzEntityMembershipParams {
258
259
  entity_field: string;
259
260
  membership_type?: number | string;
261
+ entity_type?: string;
260
262
  permission?: string;
261
263
  permissions?: string[];
262
264
  is_admin?: boolean;
@@ -266,6 +268,7 @@ export interface AuthzEntityMembershipParams {
266
268
  export interface AuthzRelatedEntityMembershipParams {
267
269
  entity_field: string;
268
270
  membership_type?: number | string;
271
+ entity_type?: string;
269
272
  obj_table_id?: string;
270
273
  obj_schema?: string;
271
274
  obj_table?: string;
@@ -321,10 +324,16 @@ export interface AuthzCompositeParams {
321
324
  }[];
322
325
  };
323
326
  }
327
+ /** Restrictive policy that blocks read-only members from mutations. Checks actor_id + is_read_only IS NOT TRUE on the SPRT. Designed to run as a restrictive counterpart after a permissive AuthzEntityMembership policy has already verified membership. */
328
+ export interface AuthzNotReadOnlyParams {
329
+ entity_field: string;
330
+ membership_type?: number | string;
331
+ }
324
332
  /** Peer visibility through shared entity membership. Authorizes access to user-owned rows when the owner and current user are both members of the same entity. Self-joins the SPRT table to find peers. */
325
333
  export interface AuthzPeerOwnershipParams {
326
334
  owner_field: string;
327
335
  membership_type?: number | string;
336
+ entity_type?: string;
328
337
  permission?: string;
329
338
  permissions?: string[];
330
339
  is_admin?: boolean;
@@ -334,6 +343,7 @@ export interface AuthzPeerOwnershipParams {
334
343
  export interface AuthzRelatedPeerOwnershipParams {
335
344
  entity_field: string;
336
345
  membership_type?: number | string;
346
+ entity_type?: string;
337
347
  obj_table_id?: string;
338
348
  obj_schema?: string;
339
349
  obj_table?: string;
@@ -452,7 +462,7 @@ export interface BlueprintField {
452
462
  /** An RLS policy entry for a blueprint table. Uses $type to match the blueprint JSON convention. */
453
463
  export interface BlueprintPolicy {
454
464
  /** Authz* policy type name (e.g., "AuthzDirectOwner", "AuthzAllowAll"). */
455
- $type: "AuthzDirectOwner" | "AuthzDirectOwnerAny" | "AuthzMembership" | "AuthzEntityMembership" | "AuthzRelatedEntityMembership" | "AuthzOrgHierarchy" | "AuthzTemporal" | "AuthzPublishable" | "AuthzMemberList" | "AuthzRelatedMemberList" | "AuthzAllowAll" | "AuthzDenyAll" | "AuthzComposite" | "AuthzPeerOwnership" | "AuthzRelatedPeerOwnership";
465
+ $type: "AuthzDirectOwner" | "AuthzDirectOwnerAny" | "AuthzMembership" | "AuthzEntityMembership" | "AuthzRelatedEntityMembership" | "AuthzOrgHierarchy" | "AuthzTemporal" | "AuthzPublishable" | "AuthzMemberList" | "AuthzRelatedMemberList" | "AuthzAllowAll" | "AuthzDenyAll" | "AuthzComposite" | "AuthzNotReadOnly" | "AuthzPeerOwnership" | "AuthzRelatedPeerOwnership";
456
466
  /** Privileges this policy applies to (e.g., ["select"], ["insert", "update", "delete"]). */
457
467
  privileges?: string[];
458
468
  /** Whether this policy is permissive (true) or restrictive (false). Defaults to true. */
@@ -573,7 +583,7 @@ export interface BlueprintMembershipType {
573
583
  skip_entity_policies?: boolean;
574
584
  }
575
585
  /** String shorthand -- just the node type name. */
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";
586
+ export type BlueprintNodeShorthand = "AuthzDirectOwner" | "AuthzDirectOwnerAny" | "AuthzMembership" | "AuthzEntityMembership" | "AuthzRelatedEntityMembership" | "AuthzOrgHierarchy" | "AuthzTemporal" | "AuthzPublishable" | "AuthzMemberList" | "AuthzRelatedMemberList" | "AuthzAllowAll" | "AuthzDenyAll" | "AuthzComposite" | "AuthzNotReadOnly" | "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";
577
587
  /** Object form -- { $type, data } with typed parameters. */
578
588
  export type BlueprintNodeObject = {
579
589
  $type: "AuthzDirectOwner";
@@ -614,6 +624,9 @@ export type BlueprintNodeObject = {
614
624
  } | {
615
625
  $type: "AuthzComposite";
616
626
  data: AuthzCompositeParams;
627
+ } | {
628
+ $type: "AuthzNotReadOnly";
629
+ data: AuthzNotReadOnlyParams;
617
630
  } | {
618
631
  $type: "AuthzPeerOwnership";
619
632
  data: AuthzPeerOwnershipParams;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-type-registry",
3
- "version": "0.11.0",
3
+ "version": "0.12.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",
@@ -27,7 +27,6 @@
27
27
  "lint": "eslint . --fix",
28
28
  "test": "jest",
29
29
  "test:watch": "jest --watch",
30
- "generate:seed": "ts-node src/codegen/generate-seed.ts",
31
30
  "generate:types": "ts-node src/codegen/generate-types.ts"
32
31
  },
33
32
  "dependencies": {
@@ -48,5 +47,5 @@
48
47
  "registry",
49
48
  "graphile"
50
49
  ],
51
- "gitHead": "ec793fd5de36264f5c9738732657522c1d783a6d"
50
+ "gitHead": "0e97757923bc862adb144cfe8a34ec7ecf7aec8a"
52
51
  }
@@ -1,32 +0,0 @@
1
- /**
2
- * Generate SQL seed scripts from TypeScript node type definitions.
3
- *
4
- * Uses pgsql-deparser to produce individual INSERT statements per node type,
5
- * suitable for use as separate pgpm migration files.
6
- *
7
- * Usage:
8
- * npx ts-node src/codegen/generate-seed.ts [--outdir <dir>] [--single] [--pgpm <dir>]
9
- *
10
- * --outdir <dir> Directory to write individual SQL files (default: stdout)
11
- * --single Emit a single combined seed.sql instead of per-node files
12
- * --pgpm <dir> Generate deploy/revert/verify files in pgpm package layout.
13
- * <dir> is the pgpm package root (e.g. packages/metaschema).
14
- * Files are written relative to this root at:
15
- * deploy/schemas/metaschema_public/tables/node_type_registry/data/seed.sql
16
- * revert/schemas/metaschema_public/tables/node_type_registry/data/seed.sql
17
- * verify/schemas/metaschema_public/tables/node_type_registry/data/seed.sql
18
- *
19
- * Examples:
20
- * # Print all INSERT statements to stdout
21
- * npx ts-node src/codegen/generate-seed.ts
22
- *
23
- * # Generate individual migration files
24
- * npx ts-node src/codegen/generate-seed.ts --outdir ./deploy/seed
25
- *
26
- * # Generate a single combined seed file
27
- * npx ts-node src/codegen/generate-seed.ts --single --outdir ./deploy
28
- *
29
- * # Generate pgpm deploy/revert/verify files
30
- * npx ts-node src/codegen/generate-seed.ts --pgpm ../../constructive-db/packages/metaschema
31
- */
32
- export {};
@@ -1,252 +0,0 @@
1
- "use strict";
2
- /**
3
- * Generate SQL seed scripts from TypeScript node type definitions.
4
- *
5
- * Uses pgsql-deparser to produce individual INSERT statements per node type,
6
- * suitable for use as separate pgpm migration files.
7
- *
8
- * Usage:
9
- * npx ts-node src/codegen/generate-seed.ts [--outdir <dir>] [--single] [--pgpm <dir>]
10
- *
11
- * --outdir <dir> Directory to write individual SQL files (default: stdout)
12
- * --single Emit a single combined seed.sql instead of per-node files
13
- * --pgpm <dir> Generate deploy/revert/verify files in pgpm package layout.
14
- * <dir> is the pgpm package root (e.g. packages/metaschema).
15
- * Files are written relative to this root at:
16
- * deploy/schemas/metaschema_public/tables/node_type_registry/data/seed.sql
17
- * revert/schemas/metaschema_public/tables/node_type_registry/data/seed.sql
18
- * verify/schemas/metaschema_public/tables/node_type_registry/data/seed.sql
19
- *
20
- * Examples:
21
- * # Print all INSERT statements to stdout
22
- * npx ts-node src/codegen/generate-seed.ts
23
- *
24
- * # Generate individual migration files
25
- * npx ts-node src/codegen/generate-seed.ts --outdir ./deploy/seed
26
- *
27
- * # Generate a single combined seed file
28
- * npx ts-node src/codegen/generate-seed.ts --single --outdir ./deploy
29
- *
30
- * # Generate pgpm deploy/revert/verify files
31
- * npx ts-node src/codegen/generate-seed.ts --pgpm ../../constructive-db/packages/metaschema
32
- */
33
- Object.defineProperty(exports, "__esModule", { value: true });
34
- const fs_1 = require("fs");
35
- const path_1 = require("path");
36
- const pgsql_deparser_1 = require("pgsql-deparser");
37
- const utils_1 = require("@pgsql/utils");
38
- const index_1 = require("../index");
39
- // ---------------------------------------------------------------------------
40
- // Constants
41
- // ---------------------------------------------------------------------------
42
- const MIGRATION_PATH = 'schemas/metaschema_public/tables/node_type_registry/data/seed';
43
- // ---------------------------------------------------------------------------
44
- // AST helpers
45
- // ---------------------------------------------------------------------------
46
- const astr = (val) => utils_1.nodes.aConst({ sval: utils_1.ast.string({ sval: val }) });
47
- const makeCast = (arg, typeName) => ({
48
- TypeCast: {
49
- arg,
50
- typeName: {
51
- names: [{ String: { sval: typeName } }],
52
- typemod: -1,
53
- },
54
- },
55
- });
56
- const makeArrayExpr = (elements) => ({
57
- A_ArrayExpr: { elements },
58
- });
59
- // ---------------------------------------------------------------------------
60
- // Build a single INSERT statement for one node type
61
- // ---------------------------------------------------------------------------
62
- function buildInsertStmt(nt) {
63
- const cols = [
64
- 'name',
65
- 'slug',
66
- 'category',
67
- 'display_name',
68
- 'description',
69
- 'parameter_schema',
70
- 'tags',
71
- ];
72
- const vals = [
73
- astr(nt.name),
74
- astr(nt.slug),
75
- astr(nt.category),
76
- astr(nt.display_name),
77
- astr(nt.description),
78
- makeCast(astr(JSON.stringify(nt.parameter_schema)), 'jsonb'),
79
- makeArrayExpr(nt.tags.map((t) => astr(t))),
80
- ];
81
- return {
82
- RawStmt: {
83
- stmt: {
84
- InsertStmt: {
85
- relation: {
86
- schemaname: 'metaschema_public',
87
- relname: 'node_type_registry',
88
- inh: true,
89
- relpersistence: 'p',
90
- },
91
- cols: cols.map((name) => utils_1.nodes.resTarget({ name })),
92
- selectStmt: {
93
- SelectStmt: {
94
- valuesLists: [
95
- {
96
- List: { items: vals },
97
- },
98
- ],
99
- op: 'SETOP_NONE',
100
- limitOption: 'LIMIT_OPTION_DEFAULT',
101
- },
102
- },
103
- onConflictClause: {
104
- action: 'ONCONFLICT_NOTHING',
105
- infer: {
106
- indexElems: [
107
- {
108
- IndexElem: {
109
- name: 'slug',
110
- ordering: 'SORTBY_DEFAULT',
111
- nulls_ordering: 'SORTBY_NULLS_DEFAULT',
112
- },
113
- },
114
- ],
115
- },
116
- },
117
- override: 'OVERRIDING_NOT_SET',
118
- },
119
- },
120
- stmt_len: 1,
121
- },
122
- };
123
- }
124
- // ---------------------------------------------------------------------------
125
- // pgpm file generators
126
- // ---------------------------------------------------------------------------
127
- const GENERATED_HEADER = [
128
- '-- GENERATED FILE — DO NOT EDIT',
129
- '--',
130
- '-- Regenerate with:',
131
- '-- cd graphql/node-type-registry && pnpm generate:seed --pgpm ../../constructive-db/packages/metaschema',
132
- '--',
133
- '',
134
- ].join('\n');
135
- async function buildDeploySql() {
136
- const header = [
137
- `-- Deploy ${MIGRATION_PATH} to pg`,
138
- '',
139
- GENERATED_HEADER,
140
- '-- requires: schemas/metaschema_public/tables/node_type_registry/table',
141
- '',
142
- ].join('\n');
143
- const stmts = index_1.allNodeTypes.map(buildInsertStmt);
144
- const body = await (0, pgsql_deparser_1.deparse)(stmts);
145
- return header + body + '\n';
146
- }
147
- function buildRevertSql() {
148
- const names = index_1.allNodeTypes.map((nt) => ` '${nt.name}'`);
149
- // Wrap names at ~4 per line for readability
150
- const chunks = [];
151
- for (let i = 0; i < names.length; i += 4) {
152
- chunks.push(names.slice(i, i + 4).join(', '));
153
- }
154
- return [
155
- `-- Revert ${MIGRATION_PATH} from pg`,
156
- '',
157
- GENERATED_HEADER,
158
- 'DELETE FROM metaschema_public.node_type_registry',
159
- 'WHERE name IN (',
160
- chunks.join(',\n'),
161
- ');',
162
- '',
163
- ].join('\n');
164
- }
165
- function buildVerifySql() {
166
- // Pick one representative from each category
167
- const categories = new Map();
168
- for (const nt of index_1.allNodeTypes) {
169
- if (!categories.has(nt.category)) {
170
- categories.set(nt.category, nt);
171
- }
172
- }
173
- const checks = Array.from(categories.values()).map((nt) => `SELECT 1 FROM metaschema_public.node_type_registry WHERE name = '${nt.name}';`);
174
- return [
175
- `-- Verify ${MIGRATION_PATH} on pg`,
176
- '',
177
- GENERATED_HEADER,
178
- ...checks,
179
- '',
180
- ].join('\n');
181
- }
182
- // ---------------------------------------------------------------------------
183
- // File writer helper
184
- // ---------------------------------------------------------------------------
185
- function writeFile(filePath, content) {
186
- const dir = (0, path_1.join)(filePath, '..');
187
- if (!(0, fs_1.existsSync)(dir))
188
- (0, fs_1.mkdirSync)(dir, { recursive: true });
189
- (0, fs_1.writeFileSync)(filePath, content);
190
- }
191
- // ---------------------------------------------------------------------------
192
- // CLI
193
- // ---------------------------------------------------------------------------
194
- async function main() {
195
- const args = process.argv.slice(2);
196
- const outdirIdx = args.indexOf('--outdir');
197
- const outdir = outdirIdx !== -1 ? args[outdirIdx + 1] : undefined;
198
- const single = args.includes('--single');
199
- const pgpmIdx = args.indexOf('--pgpm');
200
- const pgpmRoot = pgpmIdx !== -1 ? args[pgpmIdx + 1] : undefined;
201
- // --pgpm mode: generate deploy/revert/verify in pgpm package layout
202
- if (pgpmRoot) {
203
- const relPath = 'schemas/metaschema_public/tables/node_type_registry/data/seed.sql';
204
- const deployPath = (0, path_1.join)(pgpmRoot, 'deploy', relPath);
205
- const revertPath = (0, path_1.join)(pgpmRoot, 'revert', relPath);
206
- const verifyPath = (0, path_1.join)(pgpmRoot, 'verify', relPath);
207
- writeFile(deployPath, await buildDeploySql());
208
- writeFile(revertPath, buildRevertSql());
209
- writeFile(verifyPath, buildVerifySql());
210
- console.log(`Wrote ${index_1.allNodeTypes.length} node types to pgpm layout:`);
211
- console.log(` deploy: ${deployPath}`);
212
- console.log(` revert: ${revertPath}`);
213
- console.log(` verify: ${verifyPath}`);
214
- return;
215
- }
216
- if (single) {
217
- // Emit all INSERT statements as a single SQL string
218
- const stmts = index_1.allNodeTypes.map(buildInsertStmt);
219
- const sql = await (0, pgsql_deparser_1.deparse)(stmts);
220
- if (outdir) {
221
- if (!(0, fs_1.existsSync)(outdir))
222
- (0, fs_1.mkdirSync)(outdir, { recursive: true });
223
- (0, fs_1.writeFileSync)((0, path_1.join)(outdir, 'seed.sql'), sql + '\n');
224
- console.log(`Wrote ${index_1.allNodeTypes.length} node types to ${(0, path_1.join)(outdir, 'seed.sql')}`);
225
- }
226
- else {
227
- process.stdout.write(sql + '\n');
228
- }
229
- return;
230
- }
231
- // Emit individual SQL files per node type
232
- const stmts = await Promise.all(index_1.allNodeTypes.map(async (nt) => ({
233
- nt,
234
- sql: await (0, pgsql_deparser_1.deparse)([buildInsertStmt(nt)]),
235
- })));
236
- if (outdir) {
237
- if (!(0, fs_1.existsSync)(outdir))
238
- (0, fs_1.mkdirSync)(outdir, { recursive: true });
239
- for (const { nt, sql } of stmts) {
240
- const filename = `${nt.slug}.sql`;
241
- (0, fs_1.writeFileSync)((0, path_1.join)(outdir, filename), sql + '\n');
242
- }
243
- console.log(`Wrote ${stmts.length} individual migration files to ${outdir}/`);
244
- }
245
- else {
246
- for (const { nt, sql } of stmts) {
247
- console.log(`-- ${nt.name} (${nt.slug})`);
248
- console.log(sql + ';\n');
249
- }
250
- }
251
- }
252
- main();
@@ -1,32 +0,0 @@
1
- /**
2
- * Generate SQL seed scripts from TypeScript node type definitions.
3
- *
4
- * Uses pgsql-deparser to produce individual INSERT statements per node type,
5
- * suitable for use as separate pgpm migration files.
6
- *
7
- * Usage:
8
- * npx ts-node src/codegen/generate-seed.ts [--outdir <dir>] [--single] [--pgpm <dir>]
9
- *
10
- * --outdir <dir> Directory to write individual SQL files (default: stdout)
11
- * --single Emit a single combined seed.sql instead of per-node files
12
- * --pgpm <dir> Generate deploy/revert/verify files in pgpm package layout.
13
- * <dir> is the pgpm package root (e.g. packages/metaschema).
14
- * Files are written relative to this root at:
15
- * deploy/schemas/metaschema_public/tables/node_type_registry/data/seed.sql
16
- * revert/schemas/metaschema_public/tables/node_type_registry/data/seed.sql
17
- * verify/schemas/metaschema_public/tables/node_type_registry/data/seed.sql
18
- *
19
- * Examples:
20
- * # Print all INSERT statements to stdout
21
- * npx ts-node src/codegen/generate-seed.ts
22
- *
23
- * # Generate individual migration files
24
- * npx ts-node src/codegen/generate-seed.ts --outdir ./deploy/seed
25
- *
26
- * # Generate a single combined seed file
27
- * npx ts-node src/codegen/generate-seed.ts --single --outdir ./deploy
28
- *
29
- * # Generate pgpm deploy/revert/verify files
30
- * npx ts-node src/codegen/generate-seed.ts --pgpm ../../constructive-db/packages/metaschema
31
- */
32
- export {};
@@ -1,250 +0,0 @@
1
- /**
2
- * Generate SQL seed scripts from TypeScript node type definitions.
3
- *
4
- * Uses pgsql-deparser to produce individual INSERT statements per node type,
5
- * suitable for use as separate pgpm migration files.
6
- *
7
- * Usage:
8
- * npx ts-node src/codegen/generate-seed.ts [--outdir <dir>] [--single] [--pgpm <dir>]
9
- *
10
- * --outdir <dir> Directory to write individual SQL files (default: stdout)
11
- * --single Emit a single combined seed.sql instead of per-node files
12
- * --pgpm <dir> Generate deploy/revert/verify files in pgpm package layout.
13
- * <dir> is the pgpm package root (e.g. packages/metaschema).
14
- * Files are written relative to this root at:
15
- * deploy/schemas/metaschema_public/tables/node_type_registry/data/seed.sql
16
- * revert/schemas/metaschema_public/tables/node_type_registry/data/seed.sql
17
- * verify/schemas/metaschema_public/tables/node_type_registry/data/seed.sql
18
- *
19
- * Examples:
20
- * # Print all INSERT statements to stdout
21
- * npx ts-node src/codegen/generate-seed.ts
22
- *
23
- * # Generate individual migration files
24
- * npx ts-node src/codegen/generate-seed.ts --outdir ./deploy/seed
25
- *
26
- * # Generate a single combined seed file
27
- * npx ts-node src/codegen/generate-seed.ts --single --outdir ./deploy
28
- *
29
- * # Generate pgpm deploy/revert/verify files
30
- * npx ts-node src/codegen/generate-seed.ts --pgpm ../../constructive-db/packages/metaschema
31
- */
32
- import { writeFileSync, mkdirSync, existsSync } from 'fs';
33
- import { join } from 'path';
34
- import { deparse } from 'pgsql-deparser';
35
- import { ast, nodes } from '@pgsql/utils';
36
- import { allNodeTypes } from '../index';
37
- // ---------------------------------------------------------------------------
38
- // Constants
39
- // ---------------------------------------------------------------------------
40
- const MIGRATION_PATH = 'schemas/metaschema_public/tables/node_type_registry/data/seed';
41
- // ---------------------------------------------------------------------------
42
- // AST helpers
43
- // ---------------------------------------------------------------------------
44
- const astr = (val) => nodes.aConst({ sval: ast.string({ sval: val }) });
45
- const makeCast = (arg, typeName) => ({
46
- TypeCast: {
47
- arg,
48
- typeName: {
49
- names: [{ String: { sval: typeName } }],
50
- typemod: -1,
51
- },
52
- },
53
- });
54
- const makeArrayExpr = (elements) => ({
55
- A_ArrayExpr: { elements },
56
- });
57
- // ---------------------------------------------------------------------------
58
- // Build a single INSERT statement for one node type
59
- // ---------------------------------------------------------------------------
60
- function buildInsertStmt(nt) {
61
- const cols = [
62
- 'name',
63
- 'slug',
64
- 'category',
65
- 'display_name',
66
- 'description',
67
- 'parameter_schema',
68
- 'tags',
69
- ];
70
- const vals = [
71
- astr(nt.name),
72
- astr(nt.slug),
73
- astr(nt.category),
74
- astr(nt.display_name),
75
- astr(nt.description),
76
- makeCast(astr(JSON.stringify(nt.parameter_schema)), 'jsonb'),
77
- makeArrayExpr(nt.tags.map((t) => astr(t))),
78
- ];
79
- return {
80
- RawStmt: {
81
- stmt: {
82
- InsertStmt: {
83
- relation: {
84
- schemaname: 'metaschema_public',
85
- relname: 'node_type_registry',
86
- inh: true,
87
- relpersistence: 'p',
88
- },
89
- cols: cols.map((name) => nodes.resTarget({ name })),
90
- selectStmt: {
91
- SelectStmt: {
92
- valuesLists: [
93
- {
94
- List: { items: vals },
95
- },
96
- ],
97
- op: 'SETOP_NONE',
98
- limitOption: 'LIMIT_OPTION_DEFAULT',
99
- },
100
- },
101
- onConflictClause: {
102
- action: 'ONCONFLICT_NOTHING',
103
- infer: {
104
- indexElems: [
105
- {
106
- IndexElem: {
107
- name: 'slug',
108
- ordering: 'SORTBY_DEFAULT',
109
- nulls_ordering: 'SORTBY_NULLS_DEFAULT',
110
- },
111
- },
112
- ],
113
- },
114
- },
115
- override: 'OVERRIDING_NOT_SET',
116
- },
117
- },
118
- stmt_len: 1,
119
- },
120
- };
121
- }
122
- // ---------------------------------------------------------------------------
123
- // pgpm file generators
124
- // ---------------------------------------------------------------------------
125
- const GENERATED_HEADER = [
126
- '-- GENERATED FILE — DO NOT EDIT',
127
- '--',
128
- '-- Regenerate with:',
129
- '-- cd graphql/node-type-registry && pnpm generate:seed --pgpm ../../constructive-db/packages/metaschema',
130
- '--',
131
- '',
132
- ].join('\n');
133
- async function buildDeploySql() {
134
- const header = [
135
- `-- Deploy ${MIGRATION_PATH} to pg`,
136
- '',
137
- GENERATED_HEADER,
138
- '-- requires: schemas/metaschema_public/tables/node_type_registry/table',
139
- '',
140
- ].join('\n');
141
- const stmts = allNodeTypes.map(buildInsertStmt);
142
- const body = await deparse(stmts);
143
- return header + body + '\n';
144
- }
145
- function buildRevertSql() {
146
- const names = allNodeTypes.map((nt) => ` '${nt.name}'`);
147
- // Wrap names at ~4 per line for readability
148
- const chunks = [];
149
- for (let i = 0; i < names.length; i += 4) {
150
- chunks.push(names.slice(i, i + 4).join(', '));
151
- }
152
- return [
153
- `-- Revert ${MIGRATION_PATH} from pg`,
154
- '',
155
- GENERATED_HEADER,
156
- 'DELETE FROM metaschema_public.node_type_registry',
157
- 'WHERE name IN (',
158
- chunks.join(',\n'),
159
- ');',
160
- '',
161
- ].join('\n');
162
- }
163
- function buildVerifySql() {
164
- // Pick one representative from each category
165
- const categories = new Map();
166
- for (const nt of allNodeTypes) {
167
- if (!categories.has(nt.category)) {
168
- categories.set(nt.category, nt);
169
- }
170
- }
171
- const checks = Array.from(categories.values()).map((nt) => `SELECT 1 FROM metaschema_public.node_type_registry WHERE name = '${nt.name}';`);
172
- return [
173
- `-- Verify ${MIGRATION_PATH} on pg`,
174
- '',
175
- GENERATED_HEADER,
176
- ...checks,
177
- '',
178
- ].join('\n');
179
- }
180
- // ---------------------------------------------------------------------------
181
- // File writer helper
182
- // ---------------------------------------------------------------------------
183
- function writeFile(filePath, content) {
184
- const dir = join(filePath, '..');
185
- if (!existsSync(dir))
186
- mkdirSync(dir, { recursive: true });
187
- writeFileSync(filePath, content);
188
- }
189
- // ---------------------------------------------------------------------------
190
- // CLI
191
- // ---------------------------------------------------------------------------
192
- async function main() {
193
- const args = process.argv.slice(2);
194
- const outdirIdx = args.indexOf('--outdir');
195
- const outdir = outdirIdx !== -1 ? args[outdirIdx + 1] : undefined;
196
- const single = args.includes('--single');
197
- const pgpmIdx = args.indexOf('--pgpm');
198
- const pgpmRoot = pgpmIdx !== -1 ? args[pgpmIdx + 1] : undefined;
199
- // --pgpm mode: generate deploy/revert/verify in pgpm package layout
200
- if (pgpmRoot) {
201
- const relPath = 'schemas/metaschema_public/tables/node_type_registry/data/seed.sql';
202
- const deployPath = join(pgpmRoot, 'deploy', relPath);
203
- const revertPath = join(pgpmRoot, 'revert', relPath);
204
- const verifyPath = join(pgpmRoot, 'verify', relPath);
205
- writeFile(deployPath, await buildDeploySql());
206
- writeFile(revertPath, buildRevertSql());
207
- writeFile(verifyPath, buildVerifySql());
208
- console.log(`Wrote ${allNodeTypes.length} node types to pgpm layout:`);
209
- console.log(` deploy: ${deployPath}`);
210
- console.log(` revert: ${revertPath}`);
211
- console.log(` verify: ${verifyPath}`);
212
- return;
213
- }
214
- if (single) {
215
- // Emit all INSERT statements as a single SQL string
216
- const stmts = allNodeTypes.map(buildInsertStmt);
217
- const sql = await deparse(stmts);
218
- if (outdir) {
219
- if (!existsSync(outdir))
220
- mkdirSync(outdir, { recursive: true });
221
- writeFileSync(join(outdir, 'seed.sql'), sql + '\n');
222
- console.log(`Wrote ${allNodeTypes.length} node types to ${join(outdir, 'seed.sql')}`);
223
- }
224
- else {
225
- process.stdout.write(sql + '\n');
226
- }
227
- return;
228
- }
229
- // Emit individual SQL files per node type
230
- const stmts = await Promise.all(allNodeTypes.map(async (nt) => ({
231
- nt,
232
- sql: await deparse([buildInsertStmt(nt)]),
233
- })));
234
- if (outdir) {
235
- if (!existsSync(outdir))
236
- mkdirSync(outdir, { recursive: true });
237
- for (const { nt, sql } of stmts) {
238
- const filename = `${nt.slug}.sql`;
239
- writeFileSync(join(outdir, filename), sql + '\n');
240
- }
241
- console.log(`Wrote ${stmts.length} individual migration files to ${outdir}/`);
242
- }
243
- else {
244
- for (const { nt, sql } of stmts) {
245
- console.log(`-- ${nt.name} (${nt.slug})`);
246
- console.log(sql + ';\n');
247
- }
248
- }
249
- }
250
- main();