node-type-registry 0.17.1 → 0.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -64,7 +64,7 @@ const index_1 = require("../index");
64
64
  /** Attach a JSDoc-style leading comment to an AST node. */
65
65
  function addJSDoc(node, description) {
66
66
  node.leadingComments = [
67
- { type: 'CommentBlock', value: `* ${description} ` },
67
+ { type: 'CommentBlock', value: `* ${description} ` }
68
68
  ];
69
69
  return node;
70
70
  }
@@ -147,7 +147,7 @@ function generateParamsInterfaces(nodeTypes) {
147
147
  const astNodes = (0, schema_typescript_1.generateTypeScriptTypes)(sanitized, {
148
148
  includePropertyComments: true,
149
149
  includeTypeComments: false,
150
- strictTypeSafety: true,
150
+ strictTypeSafety: true
151
151
  });
152
152
  if (astNodes.length > 0) {
153
153
  // The last node is the main interface for the title
@@ -243,7 +243,7 @@ function buildBlueprintField(meta) {
243
243
  addJSDoc(requiredProp('type', t.tsStringKeyword()), 'The PostgreSQL type (e.g., "text", "integer", "boolean", "uuid").'),
244
244
  addJSDoc(optionalProp('is_required', t.tsBooleanKeyword()), 'Whether the column has a NOT NULL constraint.'),
245
245
  addJSDoc(optionalProp('default_value', t.tsStringKeyword()), 'SQL default value expression (e.g., "true", "now()").'),
246
- addJSDoc(optionalProp('description', t.tsStringKeyword()), 'Comment/description for this field.'),
246
+ addJSDoc(optionalProp('description', t.tsStringKeyword()), 'Comment/description for this field.')
247
247
  ]), 'A custom field (column) to add to a blueprint table.');
248
248
  }
249
249
  function buildBlueprintPolicy(authzNodes, _meta) {
@@ -260,14 +260,14 @@ function buildBlueprintPolicy(authzNodes, _meta) {
260
260
  addJSDoc(optionalProp('permissive', t.tsBooleanKeyword()), 'Whether this policy is permissive (true) or restrictive (false). Defaults to true.'),
261
261
  addJSDoc(optionalProp('policy_role', t.tsStringKeyword()), 'Role for this policy. Defaults to "authenticated".'),
262
262
  addJSDoc(optionalProp('policy_name', t.tsStringKeyword()), 'Optional custom name for this policy.'),
263
- addJSDoc(optionalProp('data', recordType(t.tsStringKeyword(), t.tsUnknownKeyword())), 'Policy-specific data (structure varies by policy type).'),
263
+ addJSDoc(optionalProp('data', recordType(t.tsStringKeyword(), t.tsUnknownKeyword())), 'Policy-specific data (structure varies by policy type).')
264
264
  ]), 'An RLS policy entry for a blueprint table. Uses $type to match the blueprint JSON convention.');
265
265
  }
266
266
  function buildBlueprintFtsSource() {
267
267
  return addJSDoc(exportInterface('BlueprintFtsSource', [
268
268
  addJSDoc(requiredProp('field', t.tsStringKeyword()), 'Column name of the source field.'),
269
269
  addJSDoc(requiredProp('weight', t.tsStringKeyword()), 'TSVector weight: "A", "B", "C", or "D".'),
270
- addJSDoc(optionalProp('lang', t.tsStringKeyword()), 'Language for text search. Defaults to "english".'),
270
+ addJSDoc(optionalProp('lang', t.tsStringKeyword()), 'Language for text search. Defaults to "english".')
271
271
  ]), 'A source field contributing to a full-text search tsvector column.');
272
272
  }
273
273
  function buildBlueprintFullTextSearch() {
@@ -275,14 +275,14 @@ function buildBlueprintFullTextSearch() {
275
275
  addJSDoc(requiredProp('table_name', t.tsStringKeyword()), 'Table name this full-text search belongs to.'),
276
276
  addJSDoc(optionalProp('schema_name', t.tsStringKeyword()), 'Optional schema name for disambiguation (falls back to top-level default).'),
277
277
  addJSDoc(requiredProp('field', t.tsStringKeyword()), 'Name of the tsvector field on the table.'),
278
- addJSDoc(requiredProp('sources', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintFtsSource')))), 'Source fields that feed into this tsvector.'),
278
+ addJSDoc(requiredProp('sources', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintFtsSource')))), 'Source fields that feed into this tsvector.')
279
279
  ]), 'A full-text search configuration for a blueprint table (top-level, requires table_name).');
280
280
  }
281
281
  function buildBlueprintTableFullTextSearch() {
282
282
  return addJSDoc(exportInterface('BlueprintTableFullTextSearch', [
283
283
  addJSDoc(requiredProp('field', t.tsStringKeyword()), 'Name of the tsvector field on the table.'),
284
284
  addJSDoc(requiredProp('sources', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintFtsSource')))), 'Source fields that feed into this tsvector.'),
285
- addJSDoc(optionalProp('schema_name', t.tsStringKeyword()), 'Optional schema name override.'),
285
+ addJSDoc(optionalProp('schema_name', t.tsStringKeyword()), 'Optional schema name override.')
286
286
  ]), 'A full-text search configuration nested inside a table definition (table_name not required).');
287
287
  }
288
288
  function buildBlueprintIndex(meta) {
@@ -292,7 +292,7 @@ function buildBlueprintIndex(meta) {
292
292
  // JSONB columns get Record<string, unknown> instead of the default
293
293
  index_params: recordType(t.tsStringKeyword(), t.tsUnknownKeyword()),
294
294
  where_clause: recordType(t.tsStringKeyword(), t.tsUnknownKeyword()),
295
- options: recordType(t.tsStringKeyword(), t.tsUnknownKeyword()),
295
+ options: recordType(t.tsStringKeyword(), t.tsUnknownKeyword())
296
296
  });
297
297
  }
298
298
  // Static fallback
@@ -305,7 +305,7 @@ function buildBlueprintIndex(meta) {
305
305
  addJSDoc(optionalProp('is_unique', t.tsBooleanKeyword()), 'Whether this is a unique index.'),
306
306
  addJSDoc(optionalProp('name', t.tsStringKeyword()), 'Optional custom name for the index.'),
307
307
  addJSDoc(optionalProp('op_classes', t.tsArrayType(t.tsStringKeyword())), 'Operator classes for the index columns.'),
308
- addJSDoc(optionalProp('options', recordType(t.tsStringKeyword(), t.tsUnknownKeyword())), 'Additional index-specific options.'),
308
+ addJSDoc(optionalProp('options', recordType(t.tsStringKeyword(), t.tsUnknownKeyword())), 'Additional index-specific options.')
309
309
  ]), 'An index definition within a blueprint (top-level, requires table_name).');
310
310
  }
311
311
  function buildBlueprintTableIndex() {
@@ -317,7 +317,7 @@ function buildBlueprintTableIndex() {
317
317
  addJSDoc(optionalProp('name', t.tsStringKeyword()), 'Optional custom name for the index.'),
318
318
  addJSDoc(optionalProp('op_classes', t.tsArrayType(t.tsStringKeyword())), 'Operator classes for the index columns.'),
319
319
  addJSDoc(optionalProp('options', recordType(t.tsStringKeyword(), t.tsUnknownKeyword())), 'Additional index-specific options.'),
320
- addJSDoc(optionalProp('schema_name', t.tsStringKeyword()), 'Optional schema name override.'),
320
+ addJSDoc(optionalProp('schema_name', t.tsStringKeyword()), 'Optional schema name override.')
321
321
  ]), 'An index definition nested inside a table definition (table_name not required).');
322
322
  }
323
323
  // ---------------------------------------------------------------------------
@@ -343,7 +343,7 @@ function buildNodeTypes(dataNodes) {
343
343
  // BlueprintNode -- shorthand | object
344
344
  results.push(addJSDoc(exportTypeAlias('BlueprintNode', t.tsUnionType([
345
345
  t.tsTypeReference(t.identifier('BlueprintNodeShorthand')),
346
- t.tsTypeReference(t.identifier('BlueprintNodeObject')),
346
+ t.tsTypeReference(t.identifier('BlueprintNodeObject'))
347
347
  ])), 'A node entry in a blueprint table. Either a string shorthand or a typed object.'));
348
348
  return results;
349
349
  }
@@ -357,7 +357,7 @@ function buildRelationTypes(relationNodes) {
357
357
  requiredProp('source_table', t.tsStringKeyword()),
358
358
  requiredProp('target_table', t.tsStringKeyword()),
359
359
  optionalProp('source_schema_name', t.tsStringKeyword()),
360
- optionalProp('target_schema_name', t.tsStringKeyword()),
360
+ optionalProp('target_schema_name', t.tsStringKeyword())
361
361
  ];
362
362
  // RelationSpatial is the only relation type that references *existing*
363
363
  // columns rather than creating FK/junction fields. Its blueprint JSON
@@ -371,11 +371,11 @@ function buildRelationTypes(relationNodes) {
371
371
  const baseType = t.tsTypeLiteral(baseMembers);
372
372
  return t.tsIntersectionType([
373
373
  baseType,
374
- partialOf(t.tsTypeReference(t.identifier(`${nt.name}Params`))),
374
+ partialOf(t.tsTypeReference(t.identifier(`${nt.name}Params`)))
375
375
  ]);
376
376
  });
377
377
  return [
378
- addJSDoc(exportTypeAlias('BlueprintRelation', t.tsUnionType(relationMembers)), 'A relation entry in a blueprint definition.'),
378
+ addJSDoc(exportTypeAlias('BlueprintRelation', t.tsUnionType(relationMembers)), 'A relation entry in a blueprint definition.')
379
379
  ];
380
380
  }
381
381
  // ---------------------------------------------------------------------------
@@ -385,15 +385,60 @@ function buildBlueprintUniqueConstraint() {
385
385
  return addJSDoc(exportInterface('BlueprintUniqueConstraint', [
386
386
  addJSDoc(requiredProp('table_name', t.tsStringKeyword()), 'Table name this unique constraint belongs to.'),
387
387
  addJSDoc(optionalProp('schema_name', t.tsStringKeyword()), 'Optional schema name for disambiguation (falls back to top-level default).'),
388
- addJSDoc(requiredProp('columns', t.tsArrayType(t.tsStringKeyword())), 'Column names that form the unique constraint.'),
388
+ addJSDoc(requiredProp('columns', t.tsArrayType(t.tsStringKeyword())), 'Column names that form the unique constraint.')
389
389
  ]), 'A unique constraint definition within a blueprint (top-level, requires table_name).');
390
390
  }
391
391
  function buildBlueprintTableUniqueConstraint() {
392
392
  return addJSDoc(exportInterface('BlueprintTableUniqueConstraint', [
393
393
  addJSDoc(requiredProp('columns', t.tsArrayType(t.tsStringKeyword())), 'Column names that form the unique constraint.'),
394
- addJSDoc(optionalProp('schema_name', t.tsStringKeyword()), 'Optional schema name override.'),
394
+ addJSDoc(optionalProp('schema_name', t.tsStringKeyword()), 'Optional schema name override.')
395
395
  ]), 'A unique constraint nested inside a table definition (table_name not required).');
396
396
  }
397
+ /**
398
+ * Build the BlueprintStoragePolicy interface.
399
+ *
400
+ * Matches the jsonb policy objects accepted by apply_storage_security():
401
+ * { "$type": "AuthzPublishable", "privileges": ["select"], "data": {...}, "tables": [...], "policy_name": "pub" }
402
+ */
403
+ function buildBlueprintStoragePolicy() {
404
+ return addJSDoc(exportInterface('BlueprintStoragePolicy', [
405
+ addJSDoc(requiredProp('$type', t.tsStringKeyword()), 'Authz* policy generator type (e.g., "AuthzPublishable", "AuthzDirectOwner", "AuthzEntityMembership").'),
406
+ addJSDoc(requiredProp('privileges', t.tsArrayType(t.tsStringKeyword())), 'Privilege array (e.g., ["select", "insert", "update", "delete"]). Intersected with each storage table\'s supported operations.'),
407
+ addJSDoc(optionalProp('data', recordType(t.tsStringKeyword(), t.tsUnknownKeyword())), 'Policy data config. Auto-derived from $type when omitted (e.g., AuthzPublishable defaults to {"is_published_field": "is_public", "require_published_at": false}).'),
408
+ addJSDoc(optionalProp('tables', t.tsArrayType(strUnion(['buckets', 'files', 'upload_requests']))), 'Which storage tables to apply this policy to. Defaults to all three when omitted. Uses logical names (not prefixed).'),
409
+ addJSDoc(optionalProp('policy_name', t.tsStringKeyword()), 'Custom RLS policy name suffix. Auto-derived from $type when omitted (pub/own/mem).')
410
+ ]), 'A storage-specific RLS policy object for apply_storage_security(). Each entry defines an Authz* policy with explicit privileges, scoped to specific storage tables.');
411
+ }
412
+ /**
413
+ * Build the BlueprintBucketSeed interface.
414
+ *
415
+ * Matches the bucket entries in storage_config.buckets[].
416
+ */
417
+ function buildBlueprintBucketSeed() {
418
+ return addJSDoc(exportInterface('BlueprintBucketSeed', [
419
+ addJSDoc(requiredProp('name', t.tsStringKeyword()), 'Bucket key name (e.g., "avatars", "documents"). Becomes the key column value.'),
420
+ addJSDoc(optionalProp('description', t.tsStringKeyword()), 'Human-readable description of this bucket.'),
421
+ addJSDoc(optionalProp('is_public', t.tsBooleanKeyword()), 'Whether the bucket is publicly readable. Defaults to false.'),
422
+ addJSDoc(optionalProp('allowed_mime_types', t.tsArrayType(t.tsStringKeyword())), 'MIME type allowlist (e.g., ["image/png", "image/jpeg"]). NULL means all types allowed.'),
423
+ addJSDoc(optionalProp('max_file_size', t.tsNumberKeyword()), 'Maximum file size in bytes for this bucket. NULL means no limit.'),
424
+ addJSDoc(optionalProp('allowed_origins', t.tsArrayType(t.tsStringKeyword())), 'CORS allowed origins for this bucket.')
425
+ ]), 'A bucket seed entry for storage_config.buckets[]. Creates an initial bucket row in the {prefix}_buckets table during entity type provisioning. Only used for app-level storage (not entity-scoped).');
426
+ }
427
+ /**
428
+ * Build the BlueprintStorageConfig interface.
429
+ *
430
+ * Matches the jsonb shape accepted by storage_config on entity_type_provision.
431
+ */
432
+ function buildBlueprintStorageConfig() {
433
+ return addJSDoc(exportInterface('BlueprintStorageConfig', [
434
+ addJSDoc(optionalProp('policies', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintStoragePolicy')))), 'Custom RLS policies for storage tables. When provided, replaces the default policy set (AuthzPublishable + membership + AuthzDirectOwner). Each entry is a policy object with $type, privileges, and optional data/tables/policy_name.'),
435
+ addJSDoc(optionalProp('buckets', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintBucketSeed')))), 'Initial bucket seed entries. Each creates a row in {prefix}_buckets during provisioning. Only used for app-level storage (not entity-scoped).'),
436
+ addJSDoc(optionalProp('upload_url_expiry_seconds', t.tsNumberKeyword()), 'Override for presigned upload URL expiry time in seconds.'),
437
+ addJSDoc(optionalProp('download_url_expiry_seconds', t.tsNumberKeyword()), 'Override for presigned download URL expiry time in seconds.'),
438
+ addJSDoc(optionalProp('default_max_file_size', t.tsNumberKeyword()), 'Default maximum file size in bytes for the storage module.'),
439
+ addJSDoc(optionalProp('allowed_origins', t.tsArrayType(t.tsStringKeyword())), 'CORS allowed origins for the storage module.')
440
+ ]), 'Storage configuration for an entity type. Controls RLS policies on storage tables, seeds initial buckets, and overrides module-level settings (expiry times, file size limits, CORS).');
441
+ }
397
442
  function buildBlueprintEntityTableProvision() {
398
443
  return addJSDoc(exportInterface('BlueprintEntityTableProvision', [
399
444
  addJSDoc(optionalProp('use_rls', t.tsBooleanKeyword()), 'Whether to enable RLS on the entity table. Forwarded to secure_table_provision. Defaults to true.'),
@@ -401,13 +446,13 @@ function buildBlueprintEntityTableProvision() {
401
446
  addJSDoc(optionalProp('fields', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintField')))), 'Custom fields (columns) to add to the entity table. Forwarded to secure_table_provision as-is.'),
402
447
  addJSDoc(optionalProp('grants', t.tsArrayType(t.tsTypeLiteral([
403
448
  requiredProp('roles', t.tsArrayType(t.tsStringKeyword())),
404
- requiredProp('privileges', t.tsArrayType(t.tsUnknownKeyword())),
449
+ requiredProp('privileges', t.tsArrayType(t.tsUnknownKeyword()))
405
450
  ]))), 'Unified grant objects for the entity table. Each entry is { roles: string[], privileges: unknown[] } where privileges are [verb, columns] tuples. Forwarded to secure_table_provision as-is. Defaults to [].'),
406
- addJSDoc(optionalProp('policies', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintPolicy')))), 'RLS policies for the entity table. When present, these policies fully replace the five default entity-table policies (is_visible becomes a no-op).'),
407
- ]), 'Override object for the entity table created by a BlueprintMembershipType. Shape mirrors BlueprintTable / secure_table_provision vocabulary. When supplied, policies[] replaces the default entity-table policies entirely.');
451
+ addJSDoc(optionalProp('policies', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintPolicy')))), 'RLS policies for the entity table. When present, these policies fully replace the five default entity-table policies (is_visible becomes a no-op).')
452
+ ]), 'Override object for the entity table created by a BlueprintEntityType. Shape mirrors BlueprintTable / secure_table_provision vocabulary. When supplied, policies[] replaces the default entity-table policies entirely.');
408
453
  }
409
- function buildBlueprintMembershipType() {
410
- return addJSDoc(exportInterface('BlueprintMembershipType', [
454
+ function buildBlueprintEntityType() {
455
+ return addJSDoc(exportInterface('BlueprintEntityType', [
411
456
  addJSDoc(requiredProp('name', t.tsStringKeyword()), 'Entity type name (e.g., "data_room", "channel", "department"). Must be unique per database.'),
412
457
  addJSDoc(requiredProp('prefix', t.tsStringKeyword()), 'Short prefix for generated objects (e.g., "dr", "ch", "dept"). Used in table/trigger naming.'),
413
458
  addJSDoc(optionalProp('description', t.tsStringKeyword()), 'Human-readable description of this entity type.'),
@@ -417,9 +462,11 @@ function buildBlueprintMembershipType() {
417
462
  addJSDoc(optionalProp('has_limits', t.tsBooleanKeyword()), 'Whether to provision a limits module for this entity type. Defaults to false.'),
418
463
  addJSDoc(optionalProp('has_profiles', t.tsBooleanKeyword()), 'Whether to provision a profiles module for this entity type. Defaults to false.'),
419
464
  addJSDoc(optionalProp('has_levels', t.tsBooleanKeyword()), 'Whether to provision a levels module for this entity type. Defaults to false.'),
465
+ addJSDoc(optionalProp('has_storage', t.tsBooleanKeyword()), 'Whether to provision a storage module (buckets, files, upload_requests tables) for this entity type. Defaults to false.'),
420
466
  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.'),
421
467
  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).'),
422
- ]), '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.');
468
+ addJSDoc(optionalProp('storage', t.tsTypeReference(t.identifier('BlueprintStorageConfig'))), 'Storage configuration. Only used when has_storage is true. Controls RLS policies on storage tables, seeds initial buckets, and overrides module-level settings (expiry times, file size limits, CORS).')
469
+ ]), 'An entity 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.');
423
470
  }
424
471
  function buildBlueprintTable() {
425
472
  return addJSDoc(exportInterface('BlueprintTable', [
@@ -430,12 +477,12 @@ function buildBlueprintTable() {
430
477
  addJSDoc(optionalProp('policies', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintPolicy')))), 'RLS policies for this table.'),
431
478
  addJSDoc(optionalProp('grants', t.tsArrayType(t.tsTypeLiteral([
432
479
  requiredProp('roles', t.tsArrayType(t.tsStringKeyword())),
433
- requiredProp('privileges', t.tsArrayType(t.tsUnknownKeyword())),
480
+ requiredProp('privileges', t.tsArrayType(t.tsUnknownKeyword()))
434
481
  ]))), 'Unified grant objects. Each entry is { roles: string[], privileges: unknown[] } where privileges are [verb, columns] tuples (e.g. [["select","*"]]). Enables per-role targeting. Defaults to [].'),
435
482
  addJSDoc(optionalProp('use_rls', t.tsBooleanKeyword()), 'Whether to enable RLS on this table. Defaults to true.'),
436
483
  addJSDoc(optionalProp('indexes', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintTableIndex')))), 'Table-level indexes (table_name inherited from parent).'),
437
484
  addJSDoc(optionalProp('full_text_searches', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintTableFullTextSearch')))), 'Table-level full-text search configurations (table_name inherited from parent).'),
438
- addJSDoc(optionalProp('unique_constraints', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintTableUniqueConstraint')))), 'Table-level unique constraints (table_name inherited from parent).'),
485
+ addJSDoc(optionalProp('unique_constraints', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintTableUniqueConstraint')))), 'Table-level unique constraints (table_name inherited from parent).')
439
486
  ]), 'A table definition within a blueprint.');
440
487
  }
441
488
  function buildBlueprintDefinition() {
@@ -445,7 +492,8 @@ function buildBlueprintDefinition() {
445
492
  addJSDoc(optionalProp('indexes', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintIndex')))), 'Indexes on table columns.'),
446
493
  addJSDoc(optionalProp('full_text_searches', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintFullTextSearch')))), 'Full-text search configurations.'),
447
494
  addJSDoc(optionalProp('unique_constraints', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintUniqueConstraint')))), 'Unique constraints on table columns.'),
448
- 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.'),
495
+ addJSDoc(optionalProp('entity_types', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintEntityType')))), 'Entity types to provision in Phase 0 (before tables). Each entry creates an entity table with membership modules and security.'),
496
+ addJSDoc(optionalProp('storage', t.tsTypeReference(t.identifier('BlueprintStorageConfig'))), 'App-level storage configuration. Creates a storage_module (membership_type = NULL) with the specified policies, seeds initial buckets, and overrides module-level settings (expiry times, file size limits, CORS). For entity-scoped storage, use entity_types[].has_storage + entity_types[].storage instead.')
449
497
  ]), 'The complete blueprint definition -- the JSONB shape accepted by construct_blueprint().');
450
498
  }
451
499
  // ---------------------------------------------------------------------------
@@ -456,8 +504,8 @@ function sectionComment(title) {
456
504
  empty.leadingComments = [
457
505
  {
458
506
  type: 'CommentBlock',
459
- value: `*\n * ===========================================================================\n * ${title}\n * ===========================================================================\n `,
460
- },
507
+ value: `*\n * ===========================================================================\n * ${title}\n * ===========================================================================\n `
508
+ }
461
509
  ];
462
510
  return empty;
463
511
  }
@@ -499,8 +547,11 @@ function buildProgram(meta) {
499
547
  statements.push(buildBlueprintTableIndex());
500
548
  statements.push(buildBlueprintUniqueConstraint());
501
549
  statements.push(buildBlueprintTableUniqueConstraint());
550
+ statements.push(buildBlueprintStoragePolicy());
551
+ statements.push(buildBlueprintBucketSeed());
552
+ statements.push(buildBlueprintStorageConfig());
502
553
  statements.push(buildBlueprintEntityTableProvision());
503
- statements.push(buildBlueprintMembershipType());
554
+ statements.push(buildBlueprintEntityType());
504
555
  // -- Node types discriminated union --
505
556
  statements.push(sectionComment('Node types -- discriminated union for nodes[] entries'));
506
557
  statements.push(...buildNodeTypes(dataNodes));
@@ -516,6 +567,7 @@ function buildProgram(meta) {
516
567
  const file = t.file(program);
517
568
  const header = [
518
569
  '// GENERATED FILE \u2014 DO NOT EDIT',
570
+ '/* eslint-disable @typescript-eslint/no-empty-object-type */',
519
571
  '//',
520
572
  '// Regenerate with:',
521
573
  '// cd graphql/node-type-registry && pnpm generate:types',
@@ -523,9 +575,9 @@ function buildProgram(meta) {
523
575
  '// These types match the JSONB shape expected by construct_blueprint().',
524
576
  '// All field names are snake_case to match the SQL convention.',
525
577
  '',
526
- '',
578
+ ''
527
579
  ].join('\n');
528
- const output = generate(file, { comments: true });
580
+ const output = generate(file, { comments: true, jsescOption: { quotes: 'single' } });
529
581
  return header + output.code + '\n';
530
582
  }
531
583
  // ---------------------------------------------------------------------------