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.
- package/blueprint-types.generated.d.ts +132 -83
- package/blueprint-types.generated.js +1 -0
- package/codegen/generate-types.js +82 -30
- package/esm/blueprint-types.generated.d.ts +132 -83
- package/esm/blueprint-types.generated.js +1 -0
- package/esm/codegen/generate-types.js +83 -31
- package/package.json +2 -2
|
@@ -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
|
|
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
|
|
410
|
-
return addJSDoc(exportInterface('
|
|
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
|
-
|
|
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('
|
|
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(
|
|
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
|
// ---------------------------------------------------------------------------
|