@pgpm/metaschema-modules 0.21.2 → 0.22.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.
Files changed (48) hide show
  1. package/README.md +7 -8
  2. package/deploy/schemas/metaschema_modules_public/tables/billing_module/table.sql +47 -0
  3. package/deploy/schemas/metaschema_modules_public/tables/billing_provider_module/table.sql +61 -0
  4. package/deploy/schemas/metaschema_modules_public/tables/devices_module/table.sql +36 -0
  5. package/deploy/schemas/metaschema_modules_public/tables/entity_type_provision/table.sql +332 -0
  6. package/deploy/schemas/metaschema_modules_public/tables/identity_providers_module/table.sql +33 -0
  7. package/deploy/schemas/metaschema_modules_public/tables/invites_module/table.sql +8 -0
  8. package/deploy/schemas/metaschema_modules_public/tables/limits_module/table.sql +38 -2
  9. package/deploy/schemas/metaschema_modules_public/tables/memberships_module/table.sql +7 -0
  10. package/deploy/schemas/metaschema_modules_public/tables/notifications_module/table.sql +66 -0
  11. package/deploy/schemas/metaschema_modules_public/tables/permissions_module/table.sql +23 -1
  12. package/deploy/schemas/metaschema_modules_public/tables/plans_module/table.sql +46 -0
  13. package/deploy/schemas/metaschema_modules_public/tables/profiles_module/table.sql +5 -0
  14. package/deploy/schemas/metaschema_modules_public/tables/realtime_module/table.sql +48 -0
  15. package/deploy/schemas/metaschema_modules_public/tables/relation_provision/table.sql +10 -45
  16. package/deploy/schemas/metaschema_modules_public/tables/secure_table_provision/table.sql +8 -39
  17. package/deploy/schemas/metaschema_modules_public/tables/session_secrets_module/table.sql +31 -0
  18. package/deploy/schemas/metaschema_modules_public/tables/storage_module/table.sql +42 -4
  19. package/deploy/schemas/metaschema_modules_public/tables/user_auth_module/table.sql +2 -2
  20. package/deploy/schemas/metaschema_modules_public/tables/webauthn_auth_module/table.sql +63 -0
  21. package/deploy/schemas/metaschema_modules_public/tables/webauthn_credentials_module/table.sql +32 -0
  22. package/package.json +5 -5
  23. package/pgpm.plan +12 -1
  24. package/revert/schemas/metaschema_modules_public/tables/billing_module/table.sql +3 -0
  25. package/revert/schemas/metaschema_modules_public/tables/billing_provider_module/table.sql +3 -0
  26. package/revert/schemas/metaschema_modules_public/tables/devices_module/table.sql +7 -0
  27. package/revert/schemas/metaschema_modules_public/tables/entity_type_provision/table.sql +7 -0
  28. package/revert/schemas/metaschema_modules_public/tables/identity_providers_module/table.sql +7 -0
  29. package/revert/schemas/metaschema_modules_public/tables/notifications_module/table.sql +7 -0
  30. package/revert/schemas/metaschema_modules_public/tables/plans_module/table.sql +7 -0
  31. package/revert/schemas/metaschema_modules_public/tables/realtime_module/table.sql +7 -0
  32. package/revert/schemas/metaschema_modules_public/tables/session_secrets_module/table.sql +7 -0
  33. package/revert/schemas/metaschema_modules_public/tables/webauthn_auth_module/table.sql +7 -0
  34. package/revert/schemas/metaschema_modules_public/tables/webauthn_credentials_module/table.sql +7 -0
  35. package/sql/metaschema-modules--0.15.5.sql +1269 -469
  36. package/verify/schemas/metaschema_modules_public/tables/billing_module/table.sql +23 -0
  37. package/verify/schemas/metaschema_modules_public/tables/billing_provider_module/table.sql +29 -0
  38. package/verify/schemas/metaschema_modules_public/tables/devices_module/table.sql +7 -0
  39. package/verify/schemas/metaschema_modules_public/tables/entity_type_provision/table.sql +7 -0
  40. package/verify/schemas/metaschema_modules_public/tables/identity_providers_module/table.sql +7 -0
  41. package/verify/schemas/metaschema_modules_public/tables/notifications_module/table.sql +7 -0
  42. package/verify/schemas/metaschema_modules_public/tables/plans_module/table.sql +13 -0
  43. package/verify/schemas/metaschema_modules_public/tables/realtime_module/table.sql +7 -0
  44. package/verify/schemas/metaschema_modules_public/tables/relation_provision/table.sql +2 -8
  45. package/verify/schemas/metaschema_modules_public/tables/secure_table_provision/table.sql +2 -8
  46. package/verify/schemas/metaschema_modules_public/tables/session_secrets_module/table.sql +7 -0
  47. package/verify/schemas/metaschema_modules_public/tables/webauthn_auth_module/table.sql +7 -0
  48. package/verify/schemas/metaschema_modules_public/tables/webauthn_credentials_module/table.sql +7 -0
@@ -20,6 +20,10 @@ CREATE TABLE metaschema_modules_public.memberships_module (
20
20
  membership_defaults_table_id uuid NOT NULL DEFAULT uuid_nil(),
21
21
  membership_defaults_table_name text NOT NULL DEFAULT '',
22
22
 
23
+ -- Nullable: only created when entity_table_id IS NOT NULL (entity-scoped membership types)
24
+ membership_settings_table_id uuid NULL,
25
+ membership_settings_table_name text NOT NULL DEFAULT '',
26
+
23
27
  grants_table_id uuid NOT NULL DEFAULT uuid_nil(),
24
28
  grants_table_name text NOT NULL DEFAULT '',
25
29
 
@@ -54,6 +58,8 @@ CREATE TABLE metaschema_modules_public.memberships_module (
54
58
  entity_ids_by_perm text NULL,
55
59
  entity_ids_function text NULL,
56
60
 
61
+ member_profiles_table_id uuid NULL,
62
+
57
63
  --
58
64
 
59
65
  CONSTRAINT db_fkey FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE,
@@ -62,6 +68,7 @@ CREATE TABLE metaschema_modules_public.memberships_module (
62
68
 
63
69
  CONSTRAINT memberships_table_fkey FOREIGN KEY (memberships_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
64
70
  CONSTRAINT membership_defaults_table_fkey FOREIGN KEY (membership_defaults_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
71
+ CONSTRAINT membership_settings_table_fkey FOREIGN KEY (membership_settings_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
65
72
  CONSTRAINT members_table_fkey FOREIGN KEY (members_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
66
73
  CONSTRAINT grants_table_fkey FOREIGN KEY (grants_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
67
74
  CONSTRAINT sprt_table_fkey FOREIGN KEY (sprt_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
@@ -0,0 +1,66 @@
1
+ -- Deploy schemas/metaschema_modules_public/tables/notifications_module/table to pg
2
+
3
+ -- requires: schemas/metaschema_modules_public/schema
4
+
5
+ BEGIN;
6
+
7
+ CREATE TABLE metaschema_modules_public.notifications_module (
8
+ id uuid PRIMARY KEY DEFAULT uuid_generate_v4 (),
9
+ database_id uuid NOT NULL,
10
+
11
+ schema_id uuid NOT NULL DEFAULT uuid_nil(),
12
+ private_schema_id uuid NOT NULL DEFAULT uuid_nil(),
13
+
14
+ notifications_table_id uuid NOT NULL DEFAULT uuid_nil(),
15
+ read_state_table_id uuid NOT NULL DEFAULT uuid_nil(),
16
+ -- Feature-gated tables: NULL when the corresponding has_* flag is off.
17
+ -- The generator returns NULL for tables it skipped; the insert trigger
18
+ -- forwards that through unchanged.
19
+ preferences_table_id uuid,
20
+ channels_table_id uuid,
21
+ delivery_log_table_id uuid,
22
+
23
+ owner_table_id uuid NOT NULL DEFAULT uuid_nil(),
24
+
25
+ -- Optional: table_template_module rows to extend with notifs_* columns.
26
+ -- Resolved at install time; NULL disables the corresponding extension.
27
+ user_settings_table_id uuid,
28
+ organization_settings_table_id uuid,
29
+
30
+ -- Sub-feature toggles. Resolved at module-generation time so the generated
31
+ -- schema has zero dead code. Validated by the BEFORE INSERT trigger; see
32
+ -- insert_notifications_module for dependency rules.
33
+ has_channels boolean NOT NULL DEFAULT true,
34
+ has_preferences boolean NOT NULL DEFAULT true,
35
+ has_settings_extension boolean NOT NULL DEFAULT false,
36
+ has_digest_metadata boolean NOT NULL DEFAULT false,
37
+ has_subscriptions boolean NOT NULL DEFAULT false,
38
+
39
+ --
40
+ CONSTRAINT db_fkey FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE,
41
+ CONSTRAINT notifications_table_fkey FOREIGN KEY (notifications_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
42
+ CONSTRAINT read_state_table_fkey FOREIGN KEY (read_state_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
43
+ CONSTRAINT preferences_table_fkey FOREIGN KEY (preferences_table_id) REFERENCES metaschema_public.table (id) ON DELETE SET NULL,
44
+ CONSTRAINT channels_table_fkey FOREIGN KEY (channels_table_id) REFERENCES metaschema_public.table (id) ON DELETE SET NULL,
45
+ CONSTRAINT delivery_log_table_fkey FOREIGN KEY (delivery_log_table_id) REFERENCES metaschema_public.table (id) ON DELETE SET NULL,
46
+ CONSTRAINT owner_table_fkey FOREIGN KEY (owner_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
47
+ CONSTRAINT user_settings_table_fkey FOREIGN KEY (user_settings_table_id) REFERENCES metaschema_public.table (id) ON DELETE SET NULL,
48
+ CONSTRAINT organization_settings_table_fkey FOREIGN KEY (organization_settings_table_id) REFERENCES metaschema_public.table (id) ON DELETE SET NULL,
49
+ CONSTRAINT schema_fkey FOREIGN KEY (schema_id) REFERENCES metaschema_public.schema (id) ON DELETE CASCADE,
50
+ CONSTRAINT private_schema_fkey FOREIGN KEY (private_schema_id) REFERENCES metaschema_public.schema (id) ON DELETE CASCADE
51
+ );
52
+
53
+ COMMENT ON CONSTRAINT schema_fkey ON metaschema_modules_public.notifications_module IS E'@omit manyToMany';
54
+ COMMENT ON CONSTRAINT private_schema_fkey ON metaschema_modules_public.notifications_module IS E'@omit manyToMany';
55
+ COMMENT ON CONSTRAINT notifications_table_fkey ON metaschema_modules_public.notifications_module IS E'@fieldName notificationsTableByNotificationsTableId\n@omit manyToMany';
56
+ COMMENT ON CONSTRAINT read_state_table_fkey ON metaschema_modules_public.notifications_module IS E'@fieldName readStateTableByReadStateTableId\n@omit manyToMany';
57
+ COMMENT ON CONSTRAINT preferences_table_fkey ON metaschema_modules_public.notifications_module IS E'@fieldName preferencesTableByPreferencesTableId\n@omit manyToMany';
58
+ COMMENT ON CONSTRAINT channels_table_fkey ON metaschema_modules_public.notifications_module IS E'@fieldName channelsTableByChannelsTableId\n@omit manyToMany';
59
+ COMMENT ON CONSTRAINT delivery_log_table_fkey ON metaschema_modules_public.notifications_module IS E'@fieldName deliveryLogTableByDeliveryLogTableId\n@omit manyToMany';
60
+ COMMENT ON CONSTRAINT owner_table_fkey ON metaschema_modules_public.notifications_module IS E'@omit manyToMany';
61
+ COMMENT ON CONSTRAINT user_settings_table_fkey ON metaschema_modules_public.notifications_module IS E'@fieldName userSettingsTableByUserSettingsTableId\n@omit manyToMany';
62
+ COMMENT ON CONSTRAINT organization_settings_table_fkey ON metaschema_modules_public.notifications_module IS E'@fieldName organizationSettingsTableByOrganizationSettingsTableId\n@omit manyToMany';
63
+ COMMENT ON CONSTRAINT db_fkey ON metaschema_modules_public.notifications_module IS E'@omit manyToMany';
64
+ CREATE INDEX notifications_module_database_id_idx ON metaschema_modules_public.notifications_module ( database_id );
65
+
66
+ COMMIT;
@@ -19,7 +19,29 @@ CREATE TABLE metaschema_modules_public.permissions_module (
19
19
  default_table_name text NOT NULL DEFAULT '',
20
20
  --
21
21
 
22
- bitlen int NOT NULL DEFAULT 24,
22
+ -- Default bit-width of the permission mask for this module.
23
+ --
24
+ -- Chosen to maximize permission headroom without costing extra storage or
25
+ -- compute. PostgreSQL lays out heap tuples to MAXALIGN (8 bytes on x86_64),
26
+ -- so the row-size bucket that holds bit(24) already extends up to bit(64):
27
+ --
28
+ -- bitlen | row bytes | heap (1M rows) | btree idx (1M rows)
29
+ -- -------+-----------+----------------+--------------------
30
+ -- 24 | 67 | 74 MB | 47 MB
31
+ -- 48 | 70 | 74 MB | 47 MB
32
+ -- 64 | 72 | 74 MB | 47 MB <-- same bucket
33
+ -- 65 | 73 | 81 MB | 47 MB <-- next bucket
34
+ --
35
+ -- Bitwise AND/OR on bit(<=64) fits in a single 64-bit machine word, so
36
+ -- permission checks at 64 cost the same as at 24. Raising the default from
37
+ -- 24 to 64 gives new modules 6.4x more permission slots before anyone has
38
+ -- to think about running update_bitlen_permissions, at identical storage
39
+ -- and compute cost. Do not raise past 64 casually -- bit(65+) jumps to the
40
+ -- next 8-byte tuple bucket (+~10% heap) and pays on every write.
41
+ --
42
+ -- Existing databases are unaffected; this only changes the default for
43
+ -- newly inserted permissions_module rows.
44
+ bitlen int NOT NULL DEFAULT 64,
23
45
  membership_type int NOT NULL,
24
46
  -- if this is NOT NULL, then we add entity_id
25
47
  -- e.g. limits to the app itself are considered global owned by app and no explicit owner
@@ -0,0 +1,46 @@
1
+ -- Deploy schemas/metaschema_modules_public/tables/plans_module/table to pg
2
+
3
+ -- requires: schemas/metaschema_modules_public/schema
4
+
5
+ BEGIN;
6
+
7
+ CREATE TABLE metaschema_modules_public.plans_module (
8
+ id uuid PRIMARY KEY DEFAULT uuidv7(),
9
+ database_id uuid NOT NULL,
10
+
11
+ schema_id uuid NOT NULL DEFAULT uuid_nil(),
12
+ private_schema_id uuid NOT NULL DEFAULT uuid_nil(),
13
+
14
+ -- Plans table: defines plan tiers (Free, Pro, Enterprise)
15
+ plans_table_id uuid NOT NULL DEFAULT uuid_nil(),
16
+ plans_table_name text NOT NULL DEFAULT '',
17
+
18
+ -- Plan limits table: maps plan → limit name → max value
19
+ plan_limits_table_id uuid NOT NULL DEFAULT uuid_nil(),
20
+ plan_limits_table_name text NOT NULL DEFAULT '',
21
+
22
+ -- Plan pricing table: billing cycles, prices, discounts per plan
23
+ plan_pricing_table_id uuid NULL,
24
+
25
+ -- Plan overrides table: per-entity custom limit overrides
26
+ plan_overrides_table_id uuid NULL,
27
+
28
+ -- Generated apply_plan functions (one per limits scope)
29
+ apply_plan_function text NOT NULL DEFAULT '',
30
+ apply_plan_aggregate_function text NOT NULL DEFAULT '',
31
+
32
+ prefix text NULL,
33
+
34
+ CONSTRAINT db_fkey FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE,
35
+ CONSTRAINT schema_fkey FOREIGN KEY (schema_id) REFERENCES metaschema_public.schema (id) ON DELETE CASCADE,
36
+ CONSTRAINT private_schema_fkey FOREIGN KEY (private_schema_id) REFERENCES metaschema_public.schema (id) ON DELETE CASCADE,
37
+ CONSTRAINT plans_table_fkey FOREIGN KEY (plans_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
38
+ CONSTRAINT plan_limits_table_fkey FOREIGN KEY (plan_limits_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
39
+ CONSTRAINT plan_pricing_table_fkey FOREIGN KEY (plan_pricing_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
40
+ CONSTRAINT plan_overrides_table_fkey FOREIGN KEY (plan_overrides_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
41
+ CONSTRAINT plans_module_database_id_unique UNIQUE (database_id)
42
+ );
43
+
44
+ CREATE INDEX plans_module_database_id_idx ON metaschema_modules_public.plans_module ( database_id );
45
+
46
+ COMMIT;
@@ -26,6 +26,10 @@ CREATE TABLE metaschema_modules_public.profiles_module (
26
26
  -- Profile definition grants audit table
27
27
  profile_definition_grants_table_id uuid NOT NULL DEFAULT uuid_nil(),
28
28
  profile_definition_grants_table_name text NOT NULL DEFAULT '',
29
+
30
+ -- Profile templates table (for seeding profiles into new entities)
31
+ profile_templates_table_id uuid NOT NULL DEFAULT uuid_nil(),
32
+ profile_templates_table_name text NOT NULL DEFAULT '',
29
33
 
30
34
  membership_type int NOT NULL,
31
35
 
@@ -47,6 +51,7 @@ CREATE TABLE metaschema_modules_public.profiles_module (
47
51
  CONSTRAINT profile_permissions_table_fkey FOREIGN KEY (profile_permissions_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
48
52
  CONSTRAINT profile_grants_table_fkey FOREIGN KEY (profile_grants_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
49
53
  CONSTRAINT profile_definition_grants_table_fkey FOREIGN KEY (profile_definition_grants_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
54
+ CONSTRAINT profile_templates_table_fkey FOREIGN KEY (profile_templates_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
50
55
  CONSTRAINT entity_table_fkey FOREIGN KEY (entity_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
51
56
  CONSTRAINT actor_table_fkey FOREIGN KEY (actor_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
52
57
  CONSTRAINT permissions_table_fkey FOREIGN KEY (permissions_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
@@ -0,0 +1,48 @@
1
+ -- Deploy schemas/metaschema_modules_public/tables/realtime_module/table to pg
2
+
3
+ -- requires: schemas/metaschema_modules_public/schema
4
+
5
+ BEGIN;
6
+
7
+ CREATE TABLE metaschema_modules_public.realtime_module (
8
+ id uuid PRIMARY KEY DEFAULT uuidv7(),
9
+ database_id uuid NOT NULL,
10
+
11
+ -- Schema references (populated by the insert trigger)
12
+ schema_id uuid NOT NULL DEFAULT uuid_nil(),
13
+ private_schema_id uuid NOT NULL DEFAULT uuid_nil(),
14
+ subscriptions_schema_id uuid NOT NULL DEFAULT uuid_nil(),
15
+
16
+ -- Generated table IDs (populated by the generator)
17
+ change_log_table_id uuid NOT NULL DEFAULT uuid_nil(),
18
+ listener_node_table_id uuid NOT NULL DEFAULT uuid_nil(),
19
+ source_registry_table_id uuid NOT NULL DEFAULT uuid_nil(),
20
+
21
+ -- Partition lifecycle configuration for change_log
22
+ retention_hours integer NOT NULL DEFAULT 168,
23
+ lookahead_hours integer NOT NULL DEFAULT 24,
24
+ partition_interval text NOT NULL DEFAULT 'hourly',
25
+
26
+ -- NOTIFY hybrid wake-up channel name (NULL = use default)
27
+ notify_channel text NULL,
28
+
29
+ -- Constraints
30
+ CONSTRAINT db_fkey FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE,
31
+ CONSTRAINT schema_fkey FOREIGN KEY (schema_id) REFERENCES metaschema_public.schema (id) ON DELETE CASCADE,
32
+ CONSTRAINT private_schema_fkey FOREIGN KEY (private_schema_id) REFERENCES metaschema_public.schema (id) ON DELETE CASCADE,
33
+ CONSTRAINT subscriptions_schema_fkey FOREIGN KEY (subscriptions_schema_id) REFERENCES metaschema_public.schema (id) ON DELETE CASCADE,
34
+ CONSTRAINT change_log_table_fkey FOREIGN KEY (change_log_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
35
+ CONSTRAINT listener_node_table_fkey FOREIGN KEY (listener_node_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
36
+ CONSTRAINT source_registry_table_fkey FOREIGN KEY (source_registry_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE
37
+ );
38
+
39
+ CREATE INDEX realtime_module_database_id_idx ON metaschema_modules_public.realtime_module ( database_id );
40
+ CREATE UNIQUE INDEX realtime_module_unique_per_db ON metaschema_modules_public.realtime_module ( database_id );
41
+ CREATE INDEX realtime_module_schema_id_idx ON metaschema_modules_public.realtime_module ( schema_id );
42
+ CREATE INDEX realtime_module_private_schema_id_idx ON metaschema_modules_public.realtime_module ( private_schema_id );
43
+ CREATE INDEX realtime_module_subscriptions_schema_id_idx ON metaschema_modules_public.realtime_module ( subscriptions_schema_id );
44
+ CREATE INDEX realtime_module_change_log_table_id_idx ON metaschema_modules_public.realtime_module ( change_log_table_id );
45
+ CREATE INDEX realtime_module_listener_node_table_id_idx ON metaschema_modules_public.realtime_module ( listener_node_table_id );
46
+ CREATE INDEX realtime_module_source_registry_table_id_idx ON metaschema_modules_public.realtime_module ( source_registry_table_id );
47
+
48
+ COMMIT;
@@ -72,28 +72,16 @@ CREATE TABLE metaschema_modules_public.relation_provision (
72
72
  nodes jsonb NOT NULL DEFAULT '[]',
73
73
 
74
74
  -- =========================================================================
75
- -- ManyToMany: grants (forwarded to secure_table_provision)
75
+ -- ManyToMany: grants (forwarded to provision_table)
76
76
  -- =========================================================================
77
77
 
78
- grant_roles text[] NOT NULL DEFAULT ARRAY['authenticated'],
79
-
80
- grant_privileges jsonb[] NOT NULL DEFAULT '{}',
78
+ grants jsonb NOT NULL DEFAULT '[]',
81
79
 
82
80
  -- =========================================================================
83
81
  -- ManyToMany: RLS policies (forwarded to secure_table_provision)
84
82
  -- =========================================================================
85
83
 
86
- policy_type text DEFAULT NULL,
87
-
88
- policy_privileges text[] DEFAULT NULL,
89
-
90
- policy_role text DEFAULT NULL,
91
-
92
- policy_permissive boolean NOT NULL DEFAULT true,
93
-
94
- policy_name text DEFAULT NULL,
95
-
96
- policy_data jsonb NOT NULL DEFAULT '{}',
84
+ policies jsonb NOT NULL DEFAULT '[]',
97
85
 
98
86
  -- =========================================================================
99
87
  -- Output columns (populated by the trigger, not set by callers)
@@ -254,41 +242,18 @@ COMMENT ON COLUMN metaschema_modules_public.relation_provision.nodes IS
254
242
  -- ManyToMany: grants (forwarded to secure_table_provision)
255
243
  -- =============================================================================
256
244
 
257
- COMMENT ON COLUMN metaschema_modules_public.relation_provision.grant_roles IS
258
- 'For RelationManyToMany: database roles to grant privileges to on the junction table. Forwarded to secure_table_provision as-is. Supports multiple roles, e.g. ARRAY[''authenticated'', ''admin'']. Each role receives all privileges defined in grant_privileges. Defaults to ARRAY[''authenticated'']. Ignored for RelationBelongsTo/RelationHasOne.';
259
-
260
- COMMENT ON COLUMN metaschema_modules_public.relation_provision.grant_privileges IS
261
- 'For RelationManyToMany: privilege grants for the junction table. Forwarded to secure_table_provision as-is. Format: PostgreSQL array of jsonb [privilege, columns] tuples. Examples: ARRAY[''["select","*"]''::jsonb, ''["insert","*"]''::jsonb] for full access, or ARRAY[''["update",["name","bio"]]''::jsonb] for column-level grants. "*" means all columns. Defaults to ''{}'' (no grants — callers must explicitly specify privileges). Ignored for RelationBelongsTo/RelationHasOne.';
245
+ COMMENT ON COLUMN metaschema_modules_public.relation_provision.grants IS
246
+ 'For RelationManyToMany: array of grant objects for the junction table. Forwarded to provision_table as-is. Each element is a jsonb object with keys: "roles" (text[], required), "privileges" (jsonb[], required array of [privilege, columns] tuples). Example: [{"roles":["authenticated"],"privileges":[["select","*"],["insert","*"],["delete","*"]]}]. Defaults to ''[]'' (no grants). Ignored for RelationBelongsTo/RelationHasOne.';
262
247
 
263
248
  -- =============================================================================
264
249
  -- ManyToMany: RLS policies (forwarded to secure_table_provision)
265
250
  -- =============================================================================
266
251
 
267
- COMMENT ON COLUMN metaschema_modules_public.relation_provision.policy_type IS
268
- 'For RelationManyToMany: RLS policy type for the junction table. Forwarded to secure_table_provision as-is. The trigger does not interpret or validate this value.
269
- Examples: AuthzEntityMembership, AuthzMembership, AuthzAllowAll, AuthzDirectOwner, AuthzOrgHierarchy.
270
- NULL means no policy is created — the junction table will have RLS enabled but no policies (unless added separately via secure_table_provision).
271
- Ignored for RelationBelongsTo/RelationHasOne.';
272
-
273
- COMMENT ON COLUMN metaschema_modules_public.relation_provision.policy_privileges IS
274
- 'For RelationManyToMany: privileges the policy applies to, e.g. ARRAY[''select'',''insert'',''delete'']. Forwarded to secure_table_provision as-is. NULL means privileges are derived from the grant_privileges verbs by secure_table_provision. Ignored for RelationBelongsTo/RelationHasOne.';
275
-
276
- COMMENT ON COLUMN metaschema_modules_public.relation_provision.policy_role IS
277
- 'For RelationManyToMany: database role the policy targets, e.g. ''authenticated''. Forwarded to secure_table_provision as-is. NULL means secure_table_provision falls back to the first role in grant_roles. Ignored for RelationBelongsTo/RelationHasOne.';
278
-
279
- COMMENT ON COLUMN metaschema_modules_public.relation_provision.policy_permissive IS
280
- 'For RelationManyToMany: whether the policy is PERMISSIVE (true) or RESTRICTIVE (false). Forwarded to secure_table_provision as-is. Defaults to true. Ignored for RelationBelongsTo/RelationHasOne.';
281
-
282
- COMMENT ON COLUMN metaschema_modules_public.relation_provision.policy_name IS
283
- 'For RelationManyToMany: custom suffix for the generated policy name. Forwarded to secure_table_provision as-is. When NULL and policy_type is set, secure_table_provision auto-derives a suffix from policy_type (e.g. AuthzDirectOwner becomes direct_owner, producing policy names like auth_sel_direct_owner). When explicitly set, used as-is. This ensures multiple policies on the same junction table do not collide. Ignored for RelationBelongsTo/RelationHasOne.';
284
-
285
- COMMENT ON COLUMN metaschema_modules_public.relation_provision.policy_data IS
286
- 'For RelationManyToMany: opaque policy configuration forwarded to secure_table_provision as-is. The trigger does not interpret or validate this value. Structure varies by policy_type. Examples:
287
- - AuthzEntityMembership: {"entity_field": "entity_id", "membership_type": 2}
288
- - AuthzDirectOwner: {"owner_field": "owner_id"}
289
- - AuthzMembership: {"membership_type": 2}
290
- Defaults to ''{}'' (empty object).
291
- Ignored for RelationBelongsTo/RelationHasOne.';
252
+ COMMENT ON COLUMN metaschema_modules_public.relation_provision.policies IS
253
+ 'For RelationManyToMany: array of policy objects for the junction table. Forwarded to provision_table as-is. Each element is a jsonb object with keys: "$type" (text, required — the Authz* policy generator type), "data" (jsonb, optional — opaque config), "privileges" (text[], optional — e.g. ["select","insert"]; if omitted, derived from grants[] privilege verbs), "policy_role" (text, optional — falls back to first role in first grants[] entry, or ''authenticated''), "permissive" (boolean, optional, defaults to true), "policy_name" (text, optional). Supports multiple policies per row.
254
+ Example: [{"$type": "AuthzEntityMembership", "data": {"entity_field": "entity_id", "membership_type": 2}, "privileges": ["select", "insert", "delete"]}].
255
+ Defaults to ''[]'' (no policies — the junction table will have RLS enabled but no policies unless added separately).
256
+ Ignored for RelationBelongsTo/RelationHasOne/RelationHasMany.';
292
257
 
293
258
  -- =============================================================================
294
259
  -- Output columns
@@ -21,21 +21,9 @@ CREATE TABLE metaschema_modules_public.secure_table_provision (
21
21
 
22
22
  fields jsonb[] NOT NULL DEFAULT '{}',
23
23
 
24
- grant_roles text[] NOT NULL DEFAULT ARRAY['authenticated'],
24
+ grants jsonb NOT NULL DEFAULT '[]',
25
25
 
26
- grant_privileges jsonb[] NOT NULL DEFAULT '{}',
27
-
28
- policy_type text DEFAULT NULL,
29
-
30
- policy_privileges text[] DEFAULT NULL,
31
-
32
- policy_role text DEFAULT NULL,
33
-
34
- policy_permissive boolean NOT NULL DEFAULT true,
35
-
36
- policy_name text DEFAULT NULL,
37
-
38
- policy_data jsonb NOT NULL DEFAULT '{}',
26
+ policies jsonb NOT NULL DEFAULT '[]',
39
27
 
40
28
  out_fields uuid[] DEFAULT NULL,
41
29
 
@@ -45,7 +33,7 @@ CREATE TABLE metaschema_modules_public.secure_table_provision (
45
33
  );
46
34
 
47
35
  COMMENT ON TABLE metaschema_modules_public.secure_table_provision IS
48
- 'Provisions security, fields, grants, and policies onto a table. Each row can independently: (1) create fields via nodes[] array (supporting multiple Data* modules per row), (2) grant privileges via grant_privileges, (3) create RLS policies via policy_type. Multiple rows can target the same table to compose different concerns. All three concerns are optional and independent.';
36
+ 'Provisions security, fields, grants, and policies onto a table. Each row can independently: (1) create fields via nodes[] array (supporting multiple Data* modules per row), (2) grant privileges via grants[] array (supporting per-role privilege targeting), (3) create RLS policies via policies[] array (supporting multiple Authz* policies per row). Multiple rows can target the same table to compose different concerns. All three concerns are optional and independent.';
49
37
 
50
38
  COMMENT ON COLUMN metaschema_modules_public.secure_table_provision.id IS
51
39
  'Unique identifier for this provision row.';
@@ -66,35 +54,16 @@ COMMENT ON COLUMN metaschema_modules_public.secure_table_provision.nodes IS
66
54
  'Array of node objects to apply to the table. Each element is a jsonb object with a required "$type" key (one of: DataId, DataDirectOwner, DataEntityMembership, DataOwnershipInEntity, DataTimestamps, DataPeoplestamps, DataPublishable, DataSoftDelete, DataEmbedding, DataFullTextSearch, DataSlug, etc.) and an optional "data" key containing generator-specific configuration. Supports multiple nodes per row, matching the blueprint definition format. Example: [{"$type": "DataId"}, {"$type": "DataTimestamps"}, {"$type": "DataDirectOwner", "data": {"owner_field_name": "author_id"}}]. Defaults to ''[]'' (no node processing).';
67
55
 
68
56
  COMMENT ON COLUMN metaschema_modules_public.secure_table_provision.use_rls IS
69
- 'If true and Row Level Security is not yet enabled on the target table, enable it. Automatically set to true by the trigger when policy_type is provided. Defaults to true.';
70
-
57
+ 'If true and Row Level Security is not yet enabled on the target table, enable it. Automatically set to true by the trigger when policies[] is non-empty. Defaults to true.';
71
58
 
72
59
  COMMENT ON COLUMN metaschema_modules_public.secure_table_provision.fields IS
73
60
  'PostgreSQL array of jsonb field definition objects to create on the target table. Each object has keys: "name" (text, required), "type" (text, required), "default" (text, optional), "is_required" (boolean, optional, defaults to false), "min" (float, optional), "max" (float, optional), "regexp" (text, optional), "index" (boolean, optional, defaults to false — creates a btree index on the field). min/max generate CHECK constraints: for text/citext they constrain character_length, for integer/float types they constrain the value. regexp generates a CHECK (col ~ pattern) constraint for text/citext. Fields are created via metaschema.create_field() after any node_type generator runs, and their IDs are appended to out_fields. Example: ARRAY[''{"name":"username","type":"citext","max":256,"regexp":"^[a-z0-9_]+$"}''::jsonb, ''{"name":"score","type":"integer","min":0,"max":100}''::jsonb]. Defaults to ''{}'' (no additional fields).';
74
61
 
75
- COMMENT ON COLUMN metaschema_modules_public.secure_table_provision.grant_roles IS
76
- 'Database roles to grant privileges to. Supports multiple roles, e.g. ARRAY[''authenticated'', ''admin'']. Each role receives all privileges defined in grant_privileges. Defaults to ARRAY[''authenticated''].';
77
-
78
- COMMENT ON COLUMN metaschema_modules_public.secure_table_provision.grant_privileges IS
79
- 'PostgreSQL array of jsonb [privilege, columns] tuples defining table grants. Examples: ARRAY[''["select","*"]''::jsonb, ''["insert","*"]''::jsonb] for full access, or ARRAY[''["update",["name","bio"]]''::jsonb] for column-level grants. "*" means all columns; an array means column-level grant. Defaults to ''{}'' (no grants — callers must explicitly specify privileges). Type safety is enforced by PostgreSQL at INSERT time.';
80
-
81
- COMMENT ON COLUMN metaschema_modules_public.secure_table_provision.policy_type IS
82
- 'Policy generator type, e.g. ''AuthzEntityMembership'', ''AuthzMembership'', ''AuthzAllowAll''. NULL means no policy is created. When set, the trigger automatically enables RLS on the target table.';
83
-
84
- COMMENT ON COLUMN metaschema_modules_public.secure_table_provision.policy_privileges IS
85
- 'Privileges the policy applies to, e.g. ARRAY[''select'',''update'']. NULL means privileges are derived from the grant_privileges verbs.';
86
-
87
- COMMENT ON COLUMN metaschema_modules_public.secure_table_provision.policy_role IS
88
- 'Role the policy targets. NULL means it falls back to the first role in grant_roles.';
89
-
90
- COMMENT ON COLUMN metaschema_modules_public.secure_table_provision.policy_permissive IS
91
- 'Whether the policy is PERMISSIVE (true) or RESTRICTIVE (false). Defaults to true.';
92
-
93
- COMMENT ON COLUMN metaschema_modules_public.secure_table_provision.policy_name IS
94
- 'Custom suffix for the generated policy name. When NULL and policy_type is set, the trigger auto-derives a suffix from policy_type by stripping the Authz prefix and underscoring the remainder (e.g. AuthzDirectOwner becomes direct_owner, producing policy names like auth_sel_direct_owner). When explicitly set, the value is passed through as-is to metaschema.create_policy name parameter. This ensures multiple policies on the same table do not collide (e.g. AuthzDirectOwner + AuthzPublishable each get unique names).';
62
+ COMMENT ON COLUMN metaschema_modules_public.secure_table_provision.grants IS
63
+ 'Array of grant objects defining table privileges. Each element is a jsonb object with keys: "roles" (text[], required — database roles to grant to, e.g. ["authenticated","admin"]), "privileges" (jsonb[], required — array of [privilege, columns] tuples, e.g. [["select","*"],["insert","*"]]). "*" means all columns; an array means column-level grant. Supports per-role privilege targeting: different grant entries can target different roles with different privileges. Example: [{"roles":["authenticated"],"privileges":[["select","*"]]},{"roles":["admin"],"privileges":[["insert","*"],["update","*"],["delete","*"]]}]. Defaults to ''[]'' (no grants). When policies[] omit explicit privileges/policy_role, they fall back to the verbs and first role from grants[].';
95
64
 
96
- COMMENT ON COLUMN metaschema_modules_public.secure_table_provision.policy_data IS
97
- 'Opaque configuration passed through to metaschema.create_policy(). Structure varies by policy_type and is not interpreted by this trigger. Defaults to ''{}''.';
65
+ COMMENT ON COLUMN metaschema_modules_public.secure_table_provision.policies IS
66
+ 'Array of policy objects to create on the target table. Each element is a jsonb object with keys: "$type" (text, required — the Authz* policy generator type, e.g. AuthzEntityMembership, AuthzMembership, AuthzDirectOwner, AuthzPublishable, AuthzAllowAll), "data" (jsonb, optional — opaque configuration passed to metaschema.create_policy(), structure varies by type), "privileges" (text[], optional privileges the policy applies to, e.g. ["select","insert"]; if omitted, derived from grants[] privilege verbs), "policy_role" (text, optional — role the policy targets; if omitted, falls back to first role in first grants[] entry, or ''authenticated'' if no grants), "permissive" (boolean, optional — PERMISSIVE or RESTRICTIVE; defaults to true), "policy_name" (text, optional — custom suffix for the generated policy name; if omitted, auto-derived from $type by stripping Authz prefix). Supports multiple policies per row. Example: [{"$type": "AuthzEntityMembership", "data": {"entity_field": "owner_id", "membership_type": 3}, "privileges": ["select", "insert"]}, {"$type": "AuthzDirectOwner", "data": {"entity_field": "actor_id"}, "privileges": ["update", "delete"]}]. Defaults to ''[]'' (no policies created). When non-empty, the trigger automatically enables RLS.';
98
67
 
99
68
  COMMENT ON COLUMN metaschema_modules_public.secure_table_provision.out_fields IS
100
69
  'Output column populated by the trigger after field creation. Contains the UUIDs of the metaschema fields created on the target table by this provision row''s nodes. NULL when nodes is empty or before the trigger runs. Callers should not set this directly.';
@@ -0,0 +1,31 @@
1
+ -- Deploy schemas/metaschema_modules_public/tables/session_secrets_module/table to pg
2
+
3
+ -- requires: schemas/metaschema_modules_public/schema
4
+
5
+ BEGIN;
6
+
7
+ CREATE TABLE metaschema_modules_public.session_secrets_module (
8
+ id uuid PRIMARY KEY DEFAULT uuidv7(),
9
+ database_id uuid NOT NULL,
10
+ --
11
+ schema_id uuid NOT NULL DEFAULT uuid_nil(),
12
+ table_id uuid NOT NULL DEFAULT uuid_nil(),
13
+ table_name text NOT NULL DEFAULT 'session_secrets',
14
+ --
15
+ sessions_table_id uuid NOT NULL DEFAULT uuid_nil(),
16
+ --
17
+ CONSTRAINT db_fkey FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE,
18
+ CONSTRAINT schema_fkey FOREIGN KEY (schema_id) REFERENCES metaschema_public.schema (id) ON DELETE CASCADE,
19
+ CONSTRAINT table_fkey FOREIGN KEY (table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
20
+ CONSTRAINT sessions_table_fkey FOREIGN KEY (sessions_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE
21
+ );
22
+
23
+ CREATE INDEX session_secrets_module_database_id_idx ON metaschema_modules_public.session_secrets_module ( database_id );
24
+ CREATE INDEX session_secrets_module_schema_id_idx ON metaschema_modules_public.session_secrets_module ( schema_id );
25
+ CREATE INDEX session_secrets_module_table_id_idx ON metaschema_modules_public.session_secrets_module ( table_id );
26
+ CREATE INDEX session_secrets_module_sessions_table_id_idx ON metaschema_modules_public.session_secrets_module ( sessions_table_id );
27
+
28
+ COMMENT ON TABLE metaschema_modules_public.session_secrets_module IS 'Config row for the session_secrets_module, which provisions a DB-private, session-scoped ephemeral key-value store for challenges, nonces, and one-time tokens that must never be readable by end users.';
29
+ COMMENT ON COLUMN metaschema_modules_public.session_secrets_module.sessions_table_id IS 'Resolved reference to sessions_module.sessions_table, used to FK session_secrets.session_id with ON DELETE CASCADE.';
30
+
31
+ COMMIT;
@@ -15,16 +15,27 @@ CREATE TABLE metaschema_modules_public.storage_module (
15
15
  -- Generated table IDs (populated by the generator)
16
16
  buckets_table_id uuid NOT NULL DEFAULT uuid_nil(),
17
17
  files_table_id uuid NOT NULL DEFAULT uuid_nil(),
18
- upload_requests_table_id uuid NOT NULL DEFAULT uuid_nil(),
19
18
 
20
19
  -- Table names (input to the generator)
21
20
  buckets_table_name text NOT NULL DEFAULT 'app_buckets',
22
21
  files_table_name text NOT NULL DEFAULT 'app_files',
23
- upload_requests_table_name text NOT NULL DEFAULT 'app_upload_requests',
24
22
 
25
23
  -- Multi-tenant storage identity
26
24
  membership_type int DEFAULT NULL, -- NULL = global gate (AuthzMembership via app_sprt), non-NULL = entity-scoped (AuthzEntityMembership)
27
25
 
26
+ -- Configurable security policies (NULL = use defaults based on membership_type).
27
+ -- When provided, replaces the default policy set in apply_storage_security.
28
+ -- Accepts a JSON array of policy objects:
29
+ -- {"$type": "AuthzEntityMembership", "privileges": ["select", "update"], "data": {...}}
30
+ policies jsonb NULL,
31
+
32
+ -- Per-table skip list for apply_storage_security default policies.
33
+ -- When a table role name ("files", "buckets") is listed here,
34
+ -- apply_storage_security skips its default policies for that table.
35
+ -- Used by entity_type_provision to mark tables whose policies are
36
+ -- supplied via provisions (secure_table_provision).
37
+ skip_default_policy_tables text[] NOT NULL DEFAULT '{}',
38
+
28
39
  -- Entity table for RLS (NULL for app-level storage, entity table for entity-scoped storage)
29
40
  entity_table_id uuid NULL,
30
41
 
@@ -36,6 +47,19 @@ CREATE TABLE metaschema_modules_public.storage_module (
36
47
  -- CORS configuration (NULL = use plugin defaults)
37
48
  allowed_origins text[] NULL, -- Default CORS origins for all buckets in this database (e.g., ARRAY['https://app.example.com']). ['*'] = open/CDN mode.
38
49
 
50
+ -- Storage permissions: when true, SELECT on files requires read_files permission
51
+ -- (opt-in restrictive mode for sensitive entity types like data rooms with confidential docs).
52
+ -- When false (default), any entity member can read all files (baseline = membership).
53
+ restrict_reads boolean NOT NULL DEFAULT false,
54
+
55
+ -- Virtual filesystem + path shares: when true, generates the ltree path column
56
+ -- on files, the file_path_shares table, and path share RLS policies.
57
+ -- Enables folder hierarchy, per-folder/file sharing, and version chains.
58
+ has_path_shares boolean NOT NULL DEFAULT false,
59
+
60
+ -- Generated table ID for file_path_shares (populated by the generator when has_path_shares=true)
61
+ path_shares_table_id uuid NULL DEFAULT NULL,
62
+
39
63
  -- Per-database configurable settings (NULL = use plugin defaults)
40
64
  upload_url_expiry_seconds integer NULL, -- Presigned PUT URL expiry (default: 900 = 15 min)
41
65
  download_url_expiry_seconds integer NULL, -- Presigned GET URL expiry (default: 3600 = 1 hour)
@@ -43,14 +67,28 @@ CREATE TABLE metaschema_modules_public.storage_module (
43
67
  max_filename_length integer NULL, -- Max filename length in chars (default: 1024)
44
68
  cache_ttl_seconds integer NULL, -- LRU cache TTL for this config (default: 300 dev / 3600 prod)
45
69
 
70
+ -- Bulk upload limits (NULL = use plugin defaults)
71
+ max_bulk_files integer NULL, -- Max files per requestBulkUploadUrls batch (default: 100)
72
+ max_bulk_total_size bigint NULL, -- Max total size per batch in bytes (default: 1GB = 1073741824)
73
+
74
+ -- Feature flags: toggleable storage capabilities (all default false for minimal footprint)
75
+ has_versioning boolean NOT NULL DEFAULT false, -- Version chains: previous_version_id, is_latest, version_history()
76
+ has_content_hash boolean NOT NULL DEFAULT false, -- Content hash column for dedup + integrity verification
77
+ has_custom_keys boolean NOT NULL DEFAULT false, -- allow_custom_keys on buckets (implies has_versioning + has_content_hash)
78
+ has_audit_log boolean NOT NULL DEFAULT false, -- File events audit table: upload, delete, move, rename, download, share events
79
+
80
+ -- Generated table ID for file_events (populated by the generator when has_audit_log=true)
81
+ file_events_table_id uuid NULL DEFAULT NULL,
82
+
46
83
  -- Constraints
47
84
  CONSTRAINT db_fkey FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE,
48
85
  CONSTRAINT schema_fkey FOREIGN KEY (schema_id) REFERENCES metaschema_public.schema (id) ON DELETE CASCADE,
49
86
  CONSTRAINT private_schema_fkey FOREIGN KEY (private_schema_id) REFERENCES metaschema_public.schema (id) ON DELETE CASCADE,
50
87
  CONSTRAINT buckets_table_fkey FOREIGN KEY (buckets_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
51
88
  CONSTRAINT files_table_fkey FOREIGN KEY (files_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
52
- CONSTRAINT upload_requests_table_fkey FOREIGN KEY (upload_requests_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
53
- CONSTRAINT entity_table_fkey FOREIGN KEY (entity_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE
89
+ CONSTRAINT entity_table_fkey FOREIGN KEY (entity_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
90
+ CONSTRAINT path_shares_table_fkey FOREIGN KEY (path_shares_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
91
+ CONSTRAINT file_events_table_fkey FOREIGN KEY (file_events_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE
54
92
  );
55
93
 
56
94
  CREATE INDEX storage_module_database_id_idx ON metaschema_modules_public.storage_module ( database_id );
@@ -38,8 +38,8 @@ CREATE TABLE metaschema_modules_public.user_auth_module (
38
38
  send_account_deletion_email_function text NOT NULL DEFAULT 'send_account_deletion_email',
39
39
  delete_account_function text NOT NULL DEFAULT 'confirm_delete_account',
40
40
 
41
- sign_in_one_time_token_function text NOT NULL DEFAULT 'sign_in_one_time_token',
42
- one_time_token_function text NOT NULL DEFAULT 'one_time_token',
41
+ sign_in_cross_origin_function text NOT NULL DEFAULT 'sign_in_cross_origin',
42
+ request_cross_origin_token_function text NOT NULL DEFAULT 'request_cross_origin_token',
43
43
  extend_token_expires text NOT NULL DEFAULT 'extend_token_expires',
44
44
 
45
45
  -- UNIQUE(api_id),
@@ -0,0 +1,63 @@
1
+ -- Deploy schemas/metaschema_modules_public/tables/webauthn_auth_module/table to pg
2
+
3
+ -- requires: schemas/metaschema_modules_public/schema
4
+
5
+ BEGIN;
6
+
7
+ -- WebAuthn / Passkey auth module config.
8
+ -- Sibling of crypto_auth_module. Registers a `webauthn_challenge` entry in
9
+ -- services_public.api_modules for every authenticated API in the database,
10
+ -- so the Node relying-party (using @simplewebauthn/server) knows where to
11
+ -- read and write passkey challenges + where the credentials table lives.
12
+ --
13
+ -- RP config (rp_id, rp_name, origin_allowlist, attestation_type,
14
+ -- require_user_verification, resident_key) lives on this row (not on
15
+ -- app_auth_settings) because RP identity varies per deployment, not per
16
+ -- user choice.
17
+ --
18
+ -- All fields default to safe passwordless-passkey values per SimpleWebAuthn's
19
+ -- consumer guidance: attestation_type='none', require_user_verification=false,
20
+ -- resident_key='required'.
21
+ CREATE TABLE metaschema_modules_public.webauthn_auth_module (
22
+ id uuid PRIMARY KEY DEFAULT uuidv7(),
23
+ database_id uuid NOT NULL,
24
+
25
+ schema_id uuid NOT NULL DEFAULT uuid_nil(),
26
+
27
+ users_table_id uuid NOT NULL DEFAULT uuid_nil(),
28
+ credentials_table_id uuid NOT NULL DEFAULT uuid_nil(),
29
+ sessions_table_id uuid NOT NULL DEFAULT uuid_nil(),
30
+ session_credentials_table_id uuid NOT NULL DEFAULT uuid_nil(),
31
+ session_secrets_table_id uuid NOT NULL DEFAULT uuid_nil(),
32
+ auth_settings_table_id uuid NOT NULL DEFAULT uuid_nil(),
33
+
34
+ -- Relying Party config. Empty defaults require the caller to populate
35
+ -- via UPDATE / ALTER on the row before the first registration.
36
+ rp_id text NOT NULL DEFAULT '',
37
+ rp_name text NOT NULL DEFAULT '',
38
+ origin_allowlist text[] NOT NULL DEFAULT '{}',
39
+
40
+ -- Consumer defaults per SimpleWebAuthn passkey guidance.
41
+ attestation_type text NOT NULL DEFAULT 'none'
42
+ CHECK (attestation_type IN ('none', 'indirect', 'direct', 'enterprise')),
43
+ require_user_verification boolean NOT NULL DEFAULT false,
44
+ resident_key text NOT NULL DEFAULT 'required'
45
+ CHECK (resident_key IN ('discouraged', 'preferred', 'required')),
46
+
47
+ -- Challenge TTL (mirrors mfa_challenge_expiry on app_auth_settings).
48
+ -- 5 minutes matches SimpleWebAuthn's recommended cookie-based TTL.
49
+ challenge_expiry interval NOT NULL DEFAULT '5 minutes',
50
+
51
+ CONSTRAINT db_fkey FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE,
52
+ CONSTRAINT schema_fkey FOREIGN KEY (schema_id) REFERENCES metaschema_public.schema (id) ON DELETE CASCADE,
53
+ CONSTRAINT users_table_fkey FOREIGN KEY (users_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
54
+ CONSTRAINT credentials_table_fkey FOREIGN KEY (credentials_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
55
+ CONSTRAINT sessions_table_fkey FOREIGN KEY (sessions_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
56
+ CONSTRAINT session_credentials_table_fkey FOREIGN KEY (session_credentials_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
57
+ CONSTRAINT session_secrets_table_fkey FOREIGN KEY (session_secrets_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE,
58
+ CONSTRAINT auth_settings_table_fkey FOREIGN KEY (auth_settings_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE
59
+ );
60
+
61
+ CREATE INDEX webauthn_auth_module_database_id_idx ON metaschema_modules_public.webauthn_auth_module ( database_id );
62
+
63
+ COMMIT;