From 65719e814e28da464438e9dbfa7c1569e3542500 Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Thu, 30 Apr 2026 02:36:18 +0000 Subject: [PATCH 1/2] feat: rename storage_table_provisions -> provisions, remove storage_config.policies - Remove BlueprintStoragePolicy type (no longer needed) - Remove policies field from BlueprintStorageConfig - Rename storage_table_provisions -> provisions in BlueprintStorageConfig - Update JSDoc to reflect provisions consolidation - Regenerate blueprint-types.generated.ts --- .../src/blueprint-types.generated.ts | 23 ++----- .../src/codegen/generate-types.ts | 61 ++----------------- 2 files changed, 9 insertions(+), 75 deletions(-) diff --git a/graphql/node-type-registry/src/blueprint-types.generated.ts b/graphql/node-type-registry/src/blueprint-types.generated.ts index b01d19ab1..8b51afc49 100644 --- a/graphql/node-type-registry/src/blueprint-types.generated.ts +++ b/graphql/node-type-registry/src/blueprint-types.generated.ts @@ -831,19 +831,6 @@ export interface BlueprintTableUniqueConstraint { /** Optional schema name override. */ schema_name?: string; } -/** A storage-specific RLS policy object for apply_storage_security(). Each entry defines an Authz* policy with explicit privileges, scoped to specific storage tables. */ -export interface BlueprintStoragePolicy { - /** Authz* policy generator type (e.g., "AuthzPublishable", "AuthzDirectOwner", "AuthzEntityMembership"). */ - $type: string; - /** Privilege array (e.g., ["select", "insert", "update", "delete"]). Intersected with each storage table's supported operations. */ - privileges: string[]; - /** Policy data config. Auto-derived from $type when omitted (e.g., AuthzPublishable defaults to {"is_published_field": "is_public", "require_published_at": false}). */ - data?: Record; - /** Which storage tables to apply this policy to. Defaults to all three when omitted. Uses logical names (not prefixed). */ - tables?: ('buckets' | 'files' | 'upload_requests')[]; - /** Custom RLS policy name suffix. Auto-derived from $type when omitted (pub/own/mem). */ - policy_name?: string; -} /** 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). */ export interface BlueprintBucketSeed { /** Bucket key name (e.g., "avatars", "documents"). Becomes the key column value. */ @@ -859,10 +846,8 @@ export interface BlueprintBucketSeed { /** CORS allowed origins for this bucket. */ allowed_origins?: string[]; } -/** 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). */ +/** Storage configuration for an entity type. Seeds initial buckets, overrides module-level settings (expiry times, file size limits, CORS), and provides per-table provisioning overrides via provisions. */ export interface BlueprintStorageConfig { - /** 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. */ - policies?: BlueprintStoragePolicy[]; /** Initial bucket seed entries. Each creates a row in {prefix}_buckets during provisioning. Only used for app-level storage (not entity-scoped). */ buckets?: BlueprintBucketSeed[]; /** Override for presigned upload URL expiry time in seconds. */ @@ -873,8 +858,8 @@ export interface BlueprintStorageConfig { default_max_file_size?: number; /** CORS allowed origins for the storage module. */ allowed_origins?: string[]; - /** Per-table overrides for storage tables. Each key targets a specific storage table (files, buckets, upload_requests) and uses the same shape as table_provision: { nodes, fields, grants, use_rls, policies }. Fanned out to secure_table_provision targeting the corresponding table. */ - storage_table_provisions?: { + /** Per-table overrides for storage tables. Each key targets a specific storage table (files, buckets, upload_requests) and uses the same shape as table_provision: { nodes, fields, grants, use_rls, policies }. Fanned out to secure_table_provision targeting the corresponding table. When a key includes policies[], those REPLACE the default storage policies for that table; tables without a key still get defaults. */ + provisions?: { files?: BlueprintEntityTableProvision; buckets?: BlueprintEntityTableProvision; upload_requests?: BlueprintEntityTableProvision; @@ -1160,6 +1145,6 @@ export interface BlueprintDefinition { unique_constraints?: BlueprintUniqueConstraint[]; /** Entity types to provision in Phase 0 (before tables). Each entry creates an entity table with membership modules and security. */ entity_types?: BlueprintEntityType[]; - /** 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. */ + /** App-level storage configuration. Creates a storage_module (membership_type = NULL), seeds initial buckets, and overrides module-level settings (expiry times, file size limits, CORS). Use provisions for per-table policy overrides. For entity-scoped storage, use entity_types[].has_storage + entity_types[].storage instead. */ storage?: BlueprintStorageConfig; } diff --git a/graphql/node-type-registry/src/codegen/generate-types.ts b/graphql/node-type-registry/src/codegen/generate-types.ts index b7d17bd99..17c0f2152 100644 --- a/graphql/node-type-registry/src/codegen/generate-types.ts +++ b/graphql/node-type-registry/src/codegen/generate-types.ts @@ -620,48 +620,6 @@ function buildBlueprintTableUniqueConstraint(): t.ExportNamedDeclaration { ); } -/** - * Build the BlueprintStoragePolicy interface. - * - * Matches the jsonb policy objects accepted by apply_storage_security(): - * { "$type": "AuthzPublishable", "privileges": ["select"], "data": {...}, "tables": [...], "policy_name": "pub" } - */ -function buildBlueprintStoragePolicy(): t.ExportNamedDeclaration { - return addJSDoc( - exportInterface('BlueprintStoragePolicy', [ - addJSDoc( - requiredProp('$type', t.tsStringKeyword()), - 'Authz* policy generator type (e.g., "AuthzPublishable", "AuthzDirectOwner", "AuthzEntityMembership").' - ), - addJSDoc( - requiredProp('privileges', t.tsArrayType(t.tsStringKeyword())), - 'Privilege array (e.g., ["select", "insert", "update", "delete"]). Intersected with each storage table\'s supported operations.' - ), - 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}).' - ), - 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).' - ), - addJSDoc( - optionalProp('policy_name', t.tsStringKeyword()), - 'Custom RLS policy name suffix. Auto-derived from $type when omitted (pub/own/mem).' - ) - ]), - 'A storage-specific RLS policy object for apply_storage_security(). Each entry defines an Authz* policy with explicit privileges, scoped to specific storage tables.' - ); -} - /** * Build the BlueprintBucketSeed interface. * @@ -713,15 +671,6 @@ function buildBlueprintBucketSeed(): t.ExportNamedDeclaration { function buildBlueprintStorageConfig(): t.ExportNamedDeclaration { return addJSDoc( exportInterface('BlueprintStorageConfig', [ - 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.' - ), addJSDoc( optionalProp( 'buckets', @@ -752,7 +701,7 @@ function buildBlueprintStorageConfig(): t.ExportNamedDeclaration { ), addJSDoc( optionalProp( - 'storage_table_provisions', + 'provisions', t.tsTypeLiteral([ optionalProp( 'files', @@ -768,10 +717,10 @@ function buildBlueprintStorageConfig(): t.ExportNamedDeclaration { ) ]) ), - 'Per-table overrides for storage tables. Each key targets a specific storage table (files, buckets, upload_requests) and uses the same shape as table_provision: { nodes, fields, grants, use_rls, policies }. Fanned out to secure_table_provision targeting the corresponding table.' + 'Per-table overrides for storage tables. Each key targets a specific storage table (files, buckets, upload_requests) and uses the same shape as table_provision: { nodes, fields, grants, use_rls, policies }. Fanned out to secure_table_provision targeting the corresponding table. When a key includes policies[], those REPLACE the default storage policies for that table; tables without a key still get defaults.' ) ]), - '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).' + 'Storage configuration for an entity type. Seeds initial buckets, overrides module-level settings (expiry times, file size limits, CORS), and provides per-table provisioning overrides via provisions.' ); } @@ -1020,7 +969,7 @@ function buildBlueprintDefinition(): t.ExportNamedDeclaration { '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.' + 'App-level storage configuration. Creates a storage_module (membership_type = NULL), seeds initial buckets, and overrides module-level settings (expiry times, file size limits, CORS). Use provisions for per-table policy overrides. For entity-scoped storage, use entity_types[].has_storage + entity_types[].storage instead.' ) ]), 'The complete blueprint definition -- the JSONB shape accepted by construct_blueprint().' @@ -1093,7 +1042,7 @@ function buildProgram(meta?: MetaTableInfo[]): string { statements.push(buildBlueprintTableIndex()); statements.push(buildBlueprintUniqueConstraint()); statements.push(buildBlueprintTableUniqueConstraint()); - statements.push(buildBlueprintStoragePolicy()); + // BlueprintStoragePolicy removed — policies are now per-table via provisions statements.push(buildBlueprintBucketSeed()); statements.push(buildBlueprintStorageConfig()); statements.push(buildBlueprintEntityTableProvision()); From 854335342bb7dafe436f69358916da72a041fc99 Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Thu, 30 Apr 2026 02:52:10 +0000 Subject: [PATCH 2/2] remove diff-narrating comment --- graphql/node-type-registry/src/codegen/generate-types.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/graphql/node-type-registry/src/codegen/generate-types.ts b/graphql/node-type-registry/src/codegen/generate-types.ts index 17c0f2152..6d84c29d4 100644 --- a/graphql/node-type-registry/src/codegen/generate-types.ts +++ b/graphql/node-type-registry/src/codegen/generate-types.ts @@ -1042,7 +1042,6 @@ function buildProgram(meta?: MetaTableInfo[]): string { statements.push(buildBlueprintTableIndex()); statements.push(buildBlueprintUniqueConstraint()); statements.push(buildBlueprintTableUniqueConstraint()); - // BlueprintStoragePolicy removed — policies are now per-table via provisions statements.push(buildBlueprintBucketSeed()); statements.push(buildBlueprintStorageConfig()); statements.push(buildBlueprintEntityTableProvision());