node-type-registry 0.16.0 → 0.17.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.
Files changed (51) hide show
  1. package/blueprint-types.generated.d.ts +24 -17
  2. package/codegen/generate-types.js +8 -4
  3. package/esm/blueprint-types.generated.d.ts +24 -17
  4. package/esm/codegen/generate-types.js +8 -4
  5. package/esm/index.d.ts +1 -0
  6. package/esm/index.js +1 -0
  7. package/esm/module-presets/auth-email-magic.d.ts +15 -0
  8. package/esm/module-presets/auth-email-magic.js +55 -0
  9. package/esm/module-presets/auth-email.d.ts +17 -0
  10. package/esm/module-presets/auth-email.js +69 -0
  11. package/esm/module-presets/auth-hardened.d.ts +10 -0
  12. package/esm/module-presets/auth-hardened.js +65 -0
  13. package/esm/module-presets/auth-passkey.d.ts +14 -0
  14. package/esm/module-presets/auth-passkey.js +56 -0
  15. package/esm/module-presets/auth-sso.d.ts +21 -0
  16. package/esm/module-presets/auth-sso.js +65 -0
  17. package/esm/module-presets/b2b.d.ts +14 -0
  18. package/esm/module-presets/b2b.js +83 -0
  19. package/esm/module-presets/full.d.ts +15 -0
  20. package/esm/module-presets/full.js +38 -0
  21. package/esm/module-presets/index.d.ts +18 -0
  22. package/esm/module-presets/index.js +27 -0
  23. package/esm/module-presets/minimal.d.ts +14 -0
  24. package/esm/module-presets/minimal.js +48 -0
  25. package/esm/module-presets/types.d.ts +60 -0
  26. package/esm/module-presets/types.js +1 -0
  27. package/esm/relation/relation-many-to-many.js +20 -33
  28. package/index.d.ts +1 -0
  29. package/index.js +1 -0
  30. package/module-presets/auth-email-magic.d.ts +15 -0
  31. package/module-presets/auth-email-magic.js +58 -0
  32. package/module-presets/auth-email.d.ts +17 -0
  33. package/module-presets/auth-email.js +72 -0
  34. package/module-presets/auth-hardened.d.ts +10 -0
  35. package/module-presets/auth-hardened.js +68 -0
  36. package/module-presets/auth-passkey.d.ts +14 -0
  37. package/module-presets/auth-passkey.js +59 -0
  38. package/module-presets/auth-sso.d.ts +21 -0
  39. package/module-presets/auth-sso.js +68 -0
  40. package/module-presets/b2b.d.ts +14 -0
  41. package/module-presets/b2b.js +86 -0
  42. package/module-presets/full.d.ts +15 -0
  43. package/module-presets/full.js +41 -0
  44. package/module-presets/index.d.ts +18 -0
  45. package/module-presets/index.js +38 -0
  46. package/module-presets/minimal.d.ts +14 -0
  47. package/module-presets/minimal.js +51 -0
  48. package/module-presets/types.d.ts +60 -0
  49. package/module-presets/types.js +2 -0
  50. package/package.json +2 -2
  51. package/relation/relation-many-to-many.js +20 -33
@@ -0,0 +1,14 @@
1
+ import type { ModulePreset } from './types';
2
+ /**
3
+ * `auth:passkey` — `auth:email` plus WebAuthn / passkeys.
4
+ *
5
+ * Adds `webauthn_credentials_module` (stores each user's registered public
6
+ * keys and credential IDs), `webauthn_auth_module` (the auth-time challenge
7
+ * storage + flow), and `session_secrets_module` (where the one-time
8
+ * challenge nonces live). The generator then emits WebAuthn registration
9
+ * and assertion procedures.
10
+ *
11
+ * Password flows stay on by default as a recovery path; toggle them off in
12
+ * `app_settings_auth` if you want strictly-passkey.
13
+ */
14
+ export declare const PresetAuthPasskey: ModulePreset;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PresetAuthPasskey = void 0;
4
+ /**
5
+ * `auth:passkey` — `auth:email` plus WebAuthn / passkeys.
6
+ *
7
+ * Adds `webauthn_credentials_module` (stores each user's registered public
8
+ * keys and credential IDs), `webauthn_auth_module` (the auth-time challenge
9
+ * storage + flow), and `session_secrets_module` (where the one-time
10
+ * challenge nonces live). The generator then emits WebAuthn registration
11
+ * and assertion procedures.
12
+ *
13
+ * Password flows stay on by default as a recovery path; toggle them off in
14
+ * `app_settings_auth` if you want strictly-passkey.
15
+ */
16
+ exports.PresetAuthPasskey = {
17
+ name: 'auth:passkey',
18
+ display_name: 'Passkeys (WebAuthn)',
19
+ summary: '`auth:email` plus WebAuthn passkey registration and assertion.',
20
+ description: "Installs the three modules WebAuthn needs: `webauthn_credentials_module` for each user's " +
21
+ "registered public keys, `webauthn_auth_module` for the runtime challenge/assertion flow, " +
22
+ "and `session_secrets_module` for the one-time challenge nonces. With these installed, " +
23
+ "the generator emits WebAuthn registration/login procs. Keep password flows as a recovery " +
24
+ "path, or disable them in `app_settings_auth` for passkey-only deployments.",
25
+ good_for: [
26
+ 'Apps where you want users to adopt phishing-resistant auth',
27
+ 'Consumer apps with a tech-forward audience',
28
+ 'Internal tools protecting sensitive data where FIDO2 is a requirement'
29
+ ],
30
+ not_for: [
31
+ 'Apps that also need SSO or SMS — use `auth:hardened` for everything',
32
+ 'Apps where the end-user device mix is heavy on old browsers that lack WebAuthn'
33
+ ],
34
+ modules: [
35
+ 'users_module',
36
+ 'membership_types_module',
37
+ 'memberships_module:app',
38
+ 'sessions_module',
39
+ 'secrets_module',
40
+ 'encrypted_secrets_module',
41
+ 'emails_module',
42
+ 'rls_module',
43
+ 'user_auth_module',
44
+ 'session_secrets_module',
45
+ 'webauthn_credentials_module',
46
+ 'webauthn_auth_module'
47
+ ],
48
+ includes_notes: {
49
+ webauthn_credentials_module: 'Per-user WebAuthn credential storage. Without it, passkey registration does not compile.',
50
+ webauthn_auth_module: 'Runtime challenge + assertion flow.',
51
+ session_secrets_module: 'Challenge nonces for registration and assertion.'
52
+ },
53
+ omits_notes: {
54
+ rate_limits_module: 'Add via `auth:hardened` for production.',
55
+ connected_accounts_module: 'No OAuth / SSO — add via `auth:hardened`.',
56
+ phone_numbers_module: 'No SMS.'
57
+ },
58
+ extends: ['auth:email']
59
+ };
@@ -0,0 +1,21 @@
1
+ import type { ModulePreset } from './types';
2
+ /**
3
+ * `auth:sso` — `auth:email` plus OAuth / OpenID Connect sign-in.
4
+ *
5
+ * Adds `connected_accounts_module` (the junction table mapping a user to
6
+ * `(provider, external_id)`) and `identity_providers_module` (the provider
7
+ * config: URLs, client_id, encrypted client_secret, scopes, PKCE/nonce
8
+ * knobs). The generator then emits `sign_in_identity` / `sign_up_identity`
9
+ * procedures which rely on `encrypted_secrets_module` to decrypt the client
10
+ * secret at auth time.
11
+ *
12
+ * Password fallback stays on by default (break-glass for admins); flip the
13
+ * `allow_password_sign_*` toggles off in `app_settings_auth` for strictly
14
+ * SSO-only.
15
+ *
16
+ * Note: `emails_module` is still required — the `user_auth_module` insert
17
+ * trigger hard-requires it today. A pure SSO-only install without emails
18
+ * is a separate refactor (see `docs/architecture/module-presets.md` in
19
+ * constructive-db).
20
+ */
21
+ export declare const PresetAuthSso: ModulePreset;
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PresetAuthSso = void 0;
4
+ /**
5
+ * `auth:sso` — `auth:email` plus OAuth / OpenID Connect sign-in.
6
+ *
7
+ * Adds `connected_accounts_module` (the junction table mapping a user to
8
+ * `(provider, external_id)`) and `identity_providers_module` (the provider
9
+ * config: URLs, client_id, encrypted client_secret, scopes, PKCE/nonce
10
+ * knobs). The generator then emits `sign_in_identity` / `sign_up_identity`
11
+ * procedures which rely on `encrypted_secrets_module` to decrypt the client
12
+ * secret at auth time.
13
+ *
14
+ * Password fallback stays on by default (break-glass for admins); flip the
15
+ * `allow_password_sign_*` toggles off in `app_settings_auth` for strictly
16
+ * SSO-only.
17
+ *
18
+ * Note: `emails_module` is still required — the `user_auth_module` insert
19
+ * trigger hard-requires it today. A pure SSO-only install without emails
20
+ * is a separate refactor (see `docs/architecture/module-presets.md` in
21
+ * constructive-db).
22
+ */
23
+ exports.PresetAuthSso = {
24
+ name: 'auth:sso',
25
+ display_name: 'OAuth / OpenID Connect',
26
+ summary: '`auth:email` plus OAuth providers and connected-account linkage.',
27
+ description: "Adds the two modules that make SSO work: `identity_providers_module` (where provider " +
28
+ "definitions live — Google, GitHub, Okta, etc., with their URLs, client IDs, and " +
29
+ "encrypted client secrets) and `connected_accounts_module` (the junction mapping a " +
30
+ "Constructive user to a `(provider, external_id)` pair). The generator emits " +
31
+ "`sign_in_identity` and `sign_up_identity` procedures which decrypt the client secret " +
32
+ "through `encrypted_secrets_module` at auth time. Keep password flows as break-glass, or " +
33
+ "disable them via `app_settings_auth` toggles for strictly-SSO deployments.",
34
+ good_for: [
35
+ 'B2B apps where end users sign in via their employer IdP',
36
+ 'Consumer apps that want "Sign in with Google / GitHub"',
37
+ 'Apps that need to federate identity with a specific provider ecosystem'
38
+ ],
39
+ not_for: [
40
+ 'Apps that also need passkeys and rate limits — use `auth:hardened`',
41
+ 'Strictly-SSO apps that want NO email storage — needs the emails-optional refactor; not supported by a preset today'
42
+ ],
43
+ modules: [
44
+ 'users_module',
45
+ 'membership_types_module',
46
+ 'memberships_module:app',
47
+ 'sessions_module',
48
+ 'secrets_module',
49
+ 'encrypted_secrets_module',
50
+ 'emails_module',
51
+ 'rls_module',
52
+ 'user_auth_module',
53
+ 'connected_accounts_module',
54
+ 'identity_providers_module'
55
+ ],
56
+ includes_notes: {
57
+ connected_accounts_module: 'Junction table for (user, provider, external_id). Without it, `sign_in_identity` does not compile.',
58
+ identity_providers_module: 'Provider config table (URLs, client_id, encrypted client_secret, scopes, PKCE knobs).',
59
+ encrypted_secrets_module: 'Required by `auth:email` already; also used by SSO to decrypt the provider client_secret at auth time.'
60
+ },
61
+ omits_notes: {
62
+ webauthn_credentials_module: 'No passkeys — add `auth:passkey` or move to `auth:hardened`.',
63
+ rate_limits_module: 'Omitted; add via `auth:hardened` for production.',
64
+ session_secrets_module: "Not required for authorization-code OAuth; add if you also want magic-link flows. PKCE doesn't require it for stateless OAuth flows today.",
65
+ phone_numbers_module: 'No SMS in this preset.'
66
+ },
67
+ extends: ['auth:email']
68
+ };
@@ -0,0 +1,14 @@
1
+ import type { ModulePreset } from './types';
2
+ /**
3
+ * `b2b` — `auth:hardened` plus orgs, invites, permissions, levels,
4
+ * profiles, and hierarchy. The full multi-tenant / B2B SaaS shape.
5
+ *
6
+ * Installs both app-scoped AND org-scoped instances of the membership,
7
+ * permission, limit, level, profile, and invite modules. `hierarchy_module`
8
+ * at the org scope enables nested org/team structures.
9
+ *
10
+ * This is a large install — every B2B concept Constructive ships. Don't
11
+ * reach for it until you actually need orgs; moving from `auth:hardened`
12
+ * to `b2b` later is a provisioning step, not a schema rewrite.
13
+ */
14
+ export declare const PresetB2b: ModulePreset;
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PresetB2b = void 0;
4
+ /**
5
+ * `b2b` — `auth:hardened` plus orgs, invites, permissions, levels,
6
+ * profiles, and hierarchy. The full multi-tenant / B2B SaaS shape.
7
+ *
8
+ * Installs both app-scoped AND org-scoped instances of the membership,
9
+ * permission, limit, level, profile, and invite modules. `hierarchy_module`
10
+ * at the org scope enables nested org/team structures.
11
+ *
12
+ * This is a large install — every B2B concept Constructive ships. Don't
13
+ * reach for it until you actually need orgs; moving from `auth:hardened`
14
+ * to `b2b` later is a provisioning step, not a schema rewrite.
15
+ */
16
+ exports.PresetB2b = {
17
+ name: 'b2b',
18
+ display_name: 'B2B SaaS (orgs + invites + permissions)',
19
+ summary: '`auth:hardened` + orgs, invites, fine-grained permissions, levels, profiles, hierarchy.',
20
+ description: 'Everything in `auth:hardened`, plus the full org/team/permission stack at both app and ' +
21
+ 'org membership scopes. You get: `memberships_module:org` for org-scoped memberships, ' +
22
+ '`permissions_module:app/:org` for fine-grained RBAC, `limits_module:app/:org` for per-scope ' +
23
+ 'quota enforcement, `levels_module:app/:org` for role bundles, `profiles_module:app/:org` ' +
24
+ 'for per-scope user display info, `hierarchy_module:org` for nested org structures, and ' +
25
+ '`invites_module:app/:org` for invite flows at either scope. Choose this when the app has ' +
26
+ 'the concept of a "workspace" / "team" / "tenant" that users belong to and act within.',
27
+ good_for: [
28
+ 'B2B SaaS with multi-tenant workspaces / teams',
29
+ 'Apps where permissions scope to an organization, not globally',
30
+ 'Apps with an invite-based onboarding flow (admins invite members)',
31
+ 'Apps that need nested org hierarchies (parent org / sub-org / team)'
32
+ ],
33
+ not_for: [
34
+ 'Single-tenant consumer apps — use `auth:hardened` or `auth:email`',
35
+ 'Apps where all users see the same global dataset — orgs would add overhead with no benefit'
36
+ ],
37
+ modules: [
38
+ 'users_module',
39
+ 'membership_types_module',
40
+ 'memberships_module:app',
41
+ 'memberships_module:org',
42
+ 'sessions_module',
43
+ 'secrets_module',
44
+ 'encrypted_secrets_module',
45
+ 'emails_module',
46
+ 'rls_module',
47
+ 'user_auth_module',
48
+ 'session_secrets_module',
49
+ 'rate_limits_module',
50
+ 'connected_accounts_module',
51
+ 'identity_providers_module',
52
+ 'webauthn_credentials_module',
53
+ 'webauthn_auth_module',
54
+ 'phone_numbers_module',
55
+ 'permissions_module:app',
56
+ 'permissions_module:org',
57
+ 'limits_module:app',
58
+ 'limits_module:org',
59
+ 'levels_module:app',
60
+ 'levels_module:org',
61
+ 'profiles_module:app',
62
+ 'profiles_module:org',
63
+ 'hierarchy_module:org',
64
+ 'invites_module:app',
65
+ 'invites_module:org'
66
+ ],
67
+ includes_notes: {
68
+ 'memberships_module:org': 'Org-scoped membership rows — every user in an org gets one.',
69
+ 'permissions_module:app': 'App-wide permission grants (e.g. platform admins).',
70
+ 'permissions_module:org': 'Org-scoped permission grants (per-workspace admins, members, viewers, ...).',
71
+ 'limits_module:app': 'App-level quotas (e.g. max users per plan).',
72
+ 'limits_module:org': 'Org-level quotas (e.g. per-workspace API call caps).',
73
+ 'levels_module:app': 'Role/level bundles at the app scope.',
74
+ 'levels_module:org': 'Role/level bundles at the org scope (admin / member / viewer, etc.).',
75
+ 'profiles_module:app': 'App-scoped user profile (one per user).',
76
+ 'profiles_module:org': 'Org-scoped user profile (per org a user belongs to).',
77
+ 'hierarchy_module:org': 'Nested org structures (parent / child orgs).',
78
+ 'invites_module:app': 'App-level invites (rare — usually platform admin adds another admin).',
79
+ 'invites_module:org': 'Org-level invites (the common case — invite a teammate into a workspace).'
80
+ },
81
+ omits_notes: {
82
+ storage_module: 'Add separately if you need file uploads tied to orgs.',
83
+ crypto_addresses_module: 'Not a web3 preset.'
84
+ },
85
+ extends: ['auth:hardened']
86
+ };
@@ -0,0 +1,15 @@
1
+ import type { ModulePreset } from './types';
2
+ /**
3
+ * `full` — install everything. Equivalent to the default
4
+ * `provision_database_modules(v_modules => ARRAY['all'])` behavior.
5
+ *
6
+ * This is the maximalist preset: every module Constructive ships, including
7
+ * `storage_module` for file uploads and `crypto_addresses_module` for
8
+ * wallet-based sign-in. Use it for greenfield apps where you'd rather
9
+ * disable features via `app_settings_auth` toggles than uninstall modules,
10
+ * or for the "kitchen sink" example / demo databases.
11
+ *
12
+ * Prefer a more targeted preset for anything production-bound — installing
13
+ * a module you'll never use still costs tables, triggers, and grants.
14
+ */
15
+ export declare const PresetFull: ModulePreset;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PresetFull = void 0;
4
+ /**
5
+ * `full` — install everything. Equivalent to the default
6
+ * `provision_database_modules(v_modules => ARRAY['all'])` behavior.
7
+ *
8
+ * This is the maximalist preset: every module Constructive ships, including
9
+ * `storage_module` for file uploads and `crypto_addresses_module` for
10
+ * wallet-based sign-in. Use it for greenfield apps where you'd rather
11
+ * disable features via `app_settings_auth` toggles than uninstall modules,
12
+ * or for the "kitchen sink" example / demo databases.
13
+ *
14
+ * Prefer a more targeted preset for anything production-bound — installing
15
+ * a module you'll never use still costs tables, triggers, and grants.
16
+ */
17
+ exports.PresetFull = {
18
+ name: 'full',
19
+ display_name: 'Full (every module)',
20
+ summary: "Install every Constructive module. Equivalent to v_modules => ARRAY['all'].",
21
+ description: 'Installs every module in the catalog: everything in `b2b` plus `storage_module` ' +
22
+ 'for file uploads and `crypto_addresses_module` / `crypto_auth_module` for ' +
23
+ 'wallet-based sign-in. This matches the current default when `provision_database_modules` ' +
24
+ "is called without an explicit `v_modules` argument. Use it for fully-featured " +
25
+ 'demo/example databases, kitchen-sink reference deployments, or greenfield apps that ' +
26
+ 'would rather feature-flag at the app_settings level than uninstall modules.',
27
+ good_for: [
28
+ 'Reference / demo databases that showcase every Constructive feature',
29
+ 'Greenfield apps where the product scope is still open-ended',
30
+ 'Keeping the provisioning call identical to the pre-preset default'
31
+ ],
32
+ not_for: [
33
+ 'Production apps with a defined feature set — pick the narrowest preset that fits',
34
+ 'Resource-constrained environments — every module costs schema bloat, RLS policies, and grants'
35
+ ],
36
+ modules: ['all'],
37
+ includes_notes: {
38
+ all: "Sentinel — the provisioner installs every known module when `modules = ['all']`."
39
+ },
40
+ extends: ['b2b']
41
+ };
@@ -0,0 +1,18 @@
1
+ export type { ModulePreset } from './types';
2
+ import type { ModulePreset } from './types';
3
+ import { PresetMinimal } from './minimal';
4
+ import { PresetAuthEmail } from './auth-email';
5
+ import { PresetAuthEmailMagic } from './auth-email-magic';
6
+ import { PresetAuthSso } from './auth-sso';
7
+ import { PresetAuthPasskey } from './auth-passkey';
8
+ import { PresetAuthHardened } from './auth-hardened';
9
+ import { PresetB2b } from './b2b';
10
+ import { PresetFull } from './full';
11
+ export { PresetMinimal, PresetAuthEmail, PresetAuthEmailMagic, PresetAuthSso, PresetAuthPasskey, PresetAuthHardened, PresetB2b, PresetFull };
12
+ /**
13
+ * Ordered list of all shipped module presets, from smallest to largest
14
+ * module footprint. Stable ordering — CLIs / UIs can present this directly.
15
+ */
16
+ export declare const allModulePresets: ModulePreset[];
17
+ /** Look up a preset by name. Returns undefined if the name isn't known. */
18
+ export declare function getModulePreset(name: string): ModulePreset | undefined;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.allModulePresets = exports.PresetFull = exports.PresetB2b = exports.PresetAuthHardened = exports.PresetAuthPasskey = exports.PresetAuthSso = exports.PresetAuthEmailMagic = exports.PresetAuthEmail = exports.PresetMinimal = void 0;
4
+ exports.getModulePreset = getModulePreset;
5
+ const minimal_1 = require("./minimal");
6
+ Object.defineProperty(exports, "PresetMinimal", { enumerable: true, get: function () { return minimal_1.PresetMinimal; } });
7
+ const auth_email_1 = require("./auth-email");
8
+ Object.defineProperty(exports, "PresetAuthEmail", { enumerable: true, get: function () { return auth_email_1.PresetAuthEmail; } });
9
+ const auth_email_magic_1 = require("./auth-email-magic");
10
+ Object.defineProperty(exports, "PresetAuthEmailMagic", { enumerable: true, get: function () { return auth_email_magic_1.PresetAuthEmailMagic; } });
11
+ const auth_sso_1 = require("./auth-sso");
12
+ Object.defineProperty(exports, "PresetAuthSso", { enumerable: true, get: function () { return auth_sso_1.PresetAuthSso; } });
13
+ const auth_passkey_1 = require("./auth-passkey");
14
+ Object.defineProperty(exports, "PresetAuthPasskey", { enumerable: true, get: function () { return auth_passkey_1.PresetAuthPasskey; } });
15
+ const auth_hardened_1 = require("./auth-hardened");
16
+ Object.defineProperty(exports, "PresetAuthHardened", { enumerable: true, get: function () { return auth_hardened_1.PresetAuthHardened; } });
17
+ const b2b_1 = require("./b2b");
18
+ Object.defineProperty(exports, "PresetB2b", { enumerable: true, get: function () { return b2b_1.PresetB2b; } });
19
+ const full_1 = require("./full");
20
+ Object.defineProperty(exports, "PresetFull", { enumerable: true, get: function () { return full_1.PresetFull; } });
21
+ /**
22
+ * Ordered list of all shipped module presets, from smallest to largest
23
+ * module footprint. Stable ordering — CLIs / UIs can present this directly.
24
+ */
25
+ exports.allModulePresets = [
26
+ minimal_1.PresetMinimal,
27
+ auth_email_1.PresetAuthEmail,
28
+ auth_email_magic_1.PresetAuthEmailMagic,
29
+ auth_sso_1.PresetAuthSso,
30
+ auth_passkey_1.PresetAuthPasskey,
31
+ auth_hardened_1.PresetAuthHardened,
32
+ b2b_1.PresetB2b,
33
+ full_1.PresetFull
34
+ ];
35
+ /** Look up a preset by name. Returns undefined if the name isn't known. */
36
+ function getModulePreset(name) {
37
+ return exports.allModulePresets.find((p) => p.name === name);
38
+ }
@@ -0,0 +1,14 @@
1
+ import type { ModulePreset } from './types';
2
+ /**
3
+ * `minimal` — users + sessions + RLS + API keys. No auth procedures, no
4
+ * memberships, no orgs, no emails, no passwords.
5
+ *
6
+ * This is the barest foundation: a `users` table, a `sessions` table so
7
+ * something upstream can mint tokens, `rls_module` so row-level security
8
+ * is enforceable, and `secrets_module` so you can issue API keys. Nothing
9
+ * else.
10
+ *
11
+ * You still write your own identity bridge on top (or rely on a header-based
12
+ * user-id coming from an upstream proxy / JWT verifier).
13
+ */
14
+ export declare const PresetMinimal: ModulePreset;
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PresetMinimal = void 0;
4
+ /**
5
+ * `minimal` — users + sessions + RLS + API keys. No auth procedures, no
6
+ * memberships, no orgs, no emails, no passwords.
7
+ *
8
+ * This is the barest foundation: a `users` table, a `sessions` table so
9
+ * something upstream can mint tokens, `rls_module` so row-level security
10
+ * is enforceable, and `secrets_module` so you can issue API keys. Nothing
11
+ * else.
12
+ *
13
+ * You still write your own identity bridge on top (or rely on a header-based
14
+ * user-id coming from an upstream proxy / JWT verifier).
15
+ */
16
+ exports.PresetMinimal = {
17
+ name: 'minimal',
18
+ display_name: 'Minimal (RLS only)',
19
+ summary: 'users + sessions + RLS + API keys. No auth procedures installed.',
20
+ description: 'The smallest coherent Constructive install. You get a users table, a sessions table, ' +
21
+ 'RLS enforcement, and API-key infrastructure — but no server-side sign_up/sign_in flow. ' +
22
+ 'Pick this when authentication lives outside the database (an upstream IdP, a header from ' +
23
+ 'a proxy, an internal service-to-service JWT) and Constructive is just the RLS-aware data ' +
24
+ 'layer underneath.',
25
+ good_for: [
26
+ 'Internal tools where an upstream proxy supplies the user identity',
27
+ 'Backend-of-backend services that only need RLS, not an auth surface',
28
+ 'Prototypes that will bolt on a richer auth preset later'
29
+ ],
30
+ not_for: [
31
+ 'Any app that needs `sign_up` / `sign_in` / `reset_password` out of the box — use `auth:email` instead',
32
+ 'Multi-tenant / org-scoped apps — use `b2b`'
33
+ ],
34
+ modules: [
35
+ 'users_module',
36
+ 'sessions_module',
37
+ 'rls_module',
38
+ 'secrets_module'
39
+ ],
40
+ includes_notes: {
41
+ users_module: 'The canonical users table. Required by every preset.',
42
+ sessions_module: 'Session/token storage; needed so whatever upstream auth can mint a session row.',
43
+ rls_module: 'RLS policy infrastructure. Without it, row-level security is not enforced.',
44
+ secrets_module: 'API-key storage. Optional for this preset but almost always wanted alongside upstream auth.'
45
+ },
46
+ omits_notes: {
47
+ user_auth_module: 'No server-side sign_up/sign_in procedures in this preset.',
48
+ emails_module: 'Not needed without password/magic-link flows; upstream auth handles identity.',
49
+ memberships_module: 'No memberships without a user_auth_module wiring them up.'
50
+ }
51
+ };
@@ -0,0 +1,60 @@
1
+ /**
2
+ * A preset is a named, curated bundle of Constructive modules intended for a
3
+ * recognizable app shape (internal tool, consumer email login, SSO-only B2B,
4
+ * etc.). Presets are metadata only — passing `preset.modules` to
5
+ * `provision_database_modules(v_modules => ...)` is what actually installs
6
+ * them.
7
+ *
8
+ * Presets are NOT node types. They are a sibling concept: node types are
9
+ * reusable building blocks used inside a blueprint; presets are starting
10
+ * points for which modules to install before any blueprint is authored.
11
+ *
12
+ * All module names match the `rls_module`, `user_auth_module`, ... names in
13
+ * `metaschema_generators.provision_database_modules` in constructive-db.
14
+ *
15
+ * Naming uses snake_case for module names to match the server-side SQL
16
+ * convention, and kebab-ish `auth:email` for preset names because they're
17
+ * user-facing labels, not identifiers.
18
+ */
19
+ export interface ModulePreset {
20
+ /** Preset identifier, e.g. 'auth:email'. Stable, used as a key in CLI/codegen. */
21
+ name: string;
22
+ /** Human-readable label for UIs, e.g. 'Email + Password'. */
23
+ display_name: string;
24
+ /** One-line pitch — what this preset is in plain English. */
25
+ summary: string;
26
+ /**
27
+ * Longer narrative. Explain when you'd reach for this preset, what it
28
+ * implies architecturally, and what tradeoffs the user is accepting by
29
+ * choosing it. Keep to a few paragraphs max.
30
+ */
31
+ description: string;
32
+ /** Concrete scenarios this preset fits well. */
33
+ good_for: string[];
34
+ /** Scenarios where this preset is the wrong choice — point at alternatives. */
35
+ not_for: string[];
36
+ /**
37
+ * Flat list of module names to install. Module names must match the
38
+ * canonical list accepted by
39
+ * `metaschema_generators.provision_database_modules` in constructive-db.
40
+ * Order doesn't matter — provisioning resolves dependencies.
41
+ */
42
+ modules: string[];
43
+ /**
44
+ * Optional per-module justifications. Map from module name to a short
45
+ * "why this module is in this preset" note. Rendered in docs and CLI
46
+ * `--explain` output.
47
+ */
48
+ includes_notes?: Record<string, string>;
49
+ /**
50
+ * Optional per-module "why we deliberately leave this out" notes. Only
51
+ * list modules that a user might reasonably expect to be here; don't
52
+ * enumerate every omitted module.
53
+ */
54
+ omits_notes?: Record<string, string>;
55
+ /**
56
+ * Optional: name(s) of presets this one builds on. Purely documentary —
57
+ * not enforced at runtime, `modules` must still be the full flat list.
58
+ */
59
+ extends?: string[];
60
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-type-registry",
3
- "version": "0.16.0",
3
+ "version": "0.17.1",
4
4
  "description": "Node type definitions for the Constructive blueprint system. Single source of truth for all Authz*, Data*, Relation*, and View* node types.",
5
5
  "author": "Constructive <developers@constructive.io>",
6
6
  "main": "index.js",
@@ -47,5 +47,5 @@
47
47
  "registry",
48
48
  "graphile"
49
49
  ],
50
- "gitHead": "5094bbe92916be47234fe80c583c6957f51226e1"
50
+ "gitHead": "ad2d49ede1f962293e13d68843831897f267915d"
51
51
  }
@@ -49,46 +49,33 @@ exports.RelationManyToMany = {
49
49
  },
50
50
  "description": "Array of node objects for field creation on junction table. Each object has a $type key (e.g. DataId, DataEntityMembership) and optional data keys. Forwarded to secure_table_provision as-is. Empty array means no additional fields."
51
51
  },
52
- "grant_roles": {
52
+ "grants": {
53
53
  "type": "array",
54
54
  "items": {
55
- "type": "string"
55
+ "type": "object",
56
+ "properties": {
57
+ "roles": { "type": "array", "items": { "type": "string" } },
58
+ "privileges": { "type": "array", "items": { "type": "array", "items": { "type": "string" } } }
59
+ },
60
+ "required": ["roles", "privileges"]
56
61
  },
57
- "description": "Database roles to grant privileges to. Forwarded to secure_table_provision as-is. Default: [authenticated]"
62
+ "description": "Unified grant objects for the junction table. Each entry is { roles: string[], privileges: string[][] }. Forwarded to secure_table_provision as-is. Default: []"
58
63
  },
59
- "grant_privileges": {
64
+ "policies": {
60
65
  "type": "array",
61
66
  "items": {
62
- "type": "array",
63
- "items": {
64
- "type": "string"
65
- }
67
+ "type": "object",
68
+ "properties": {
69
+ "$type": { "type": "string" },
70
+ "data": { "type": "object" },
71
+ "privileges": { "type": "array", "items": { "type": "string" } },
72
+ "policy_role": { "type": "string" },
73
+ "permissive": { "type": "boolean" },
74
+ "policy_name": { "type": "string" }
75
+ },
76
+ "required": ["$type"]
66
77
  },
67
- "description": "Privilege grants for the junction table as [verb, columns] tuples (e.g. [['select','*'],['insert','*']]). Forwarded to secure_table_provision as-is. Default: select/insert/delete for all columns"
68
- },
69
- "policy_type": {
70
- "type": "string",
71
- "description": "RLS policy type for the junction table. Forwarded to secure_table_provision as-is. NULL means no policy."
72
- },
73
- "policy_privileges": {
74
- "type": "array",
75
- "items": {
76
- "type": "string"
77
- },
78
- "description": "Privileges the policy applies to. Forwarded to secure_table_provision as-is. NULL means derived from grant_privileges verbs."
79
- },
80
- "policy_role": {
81
- "type": "string",
82
- "description": "Database role the policy targets. Forwarded to secure_table_provision as-is. NULL means falls back to first grant_role."
83
- },
84
- "policy_permissive": {
85
- "type": "boolean",
86
- "description": "Whether the policy is PERMISSIVE (true) or RESTRICTIVE (false). Forwarded to secure_table_provision as-is.",
87
- "default": true
88
- },
89
- "policy_data": {
90
- "type": "object",
91
- "description": "Policy configuration forwarded to secure_table_provision as-is. Structure varies by policy_type."
78
+ "description": "RLS policy objects for the junction table. Each entry has $type (Authz* generator), optional data, privileges, policy_role, permissive, policy_name. Forwarded to secure_table_provision as-is. Default: []"
92
79
  }
93
80
  },
94
81
  "required": [