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.
- package/blueprint-types.generated.d.ts +24 -17
- package/codegen/generate-types.js +8 -4
- package/esm/blueprint-types.generated.d.ts +24 -17
- package/esm/codegen/generate-types.js +8 -4
- package/esm/index.d.ts +1 -0
- package/esm/index.js +1 -0
- package/esm/module-presets/auth-email-magic.d.ts +15 -0
- package/esm/module-presets/auth-email-magic.js +55 -0
- package/esm/module-presets/auth-email.d.ts +17 -0
- package/esm/module-presets/auth-email.js +69 -0
- package/esm/module-presets/auth-hardened.d.ts +10 -0
- package/esm/module-presets/auth-hardened.js +65 -0
- package/esm/module-presets/auth-passkey.d.ts +14 -0
- package/esm/module-presets/auth-passkey.js +56 -0
- package/esm/module-presets/auth-sso.d.ts +21 -0
- package/esm/module-presets/auth-sso.js +65 -0
- package/esm/module-presets/b2b.d.ts +14 -0
- package/esm/module-presets/b2b.js +83 -0
- package/esm/module-presets/full.d.ts +15 -0
- package/esm/module-presets/full.js +38 -0
- package/esm/module-presets/index.d.ts +18 -0
- package/esm/module-presets/index.js +27 -0
- package/esm/module-presets/minimal.d.ts +14 -0
- package/esm/module-presets/minimal.js +48 -0
- package/esm/module-presets/types.d.ts +60 -0
- package/esm/module-presets/types.js +1 -0
- package/esm/relation/relation-many-to-many.js +20 -33
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/module-presets/auth-email-magic.d.ts +15 -0
- package/module-presets/auth-email-magic.js +58 -0
- package/module-presets/auth-email.d.ts +17 -0
- package/module-presets/auth-email.js +72 -0
- package/module-presets/auth-hardened.d.ts +10 -0
- package/module-presets/auth-hardened.js +68 -0
- package/module-presets/auth-passkey.d.ts +14 -0
- package/module-presets/auth-passkey.js +59 -0
- package/module-presets/auth-sso.d.ts +21 -0
- package/module-presets/auth-sso.js +68 -0
- package/module-presets/b2b.d.ts +14 -0
- package/module-presets/b2b.js +86 -0
- package/module-presets/full.d.ts +15 -0
- package/module-presets/full.js +41 -0
- package/module-presets/index.d.ts +18 -0
- package/module-presets/index.js +38 -0
- package/module-presets/minimal.d.ts +14 -0
- package/module-presets/minimal.js +51 -0
- package/module-presets/types.d.ts +60 -0
- package/module-presets/types.js +2 -0
- package/package.json +2 -2
- package/relation/relation-many-to-many.js +20 -33
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `b2b` — `auth:hardened` plus orgs, invites, permissions, levels,
|
|
3
|
+
* profiles, and hierarchy. The full multi-tenant / B2B SaaS shape.
|
|
4
|
+
*
|
|
5
|
+
* Installs both app-scoped AND org-scoped instances of the membership,
|
|
6
|
+
* permission, limit, level, profile, and invite modules. `hierarchy_module`
|
|
7
|
+
* at the org scope enables nested org/team structures.
|
|
8
|
+
*
|
|
9
|
+
* This is a large install — every B2B concept Constructive ships. Don't
|
|
10
|
+
* reach for it until you actually need orgs; moving from `auth:hardened`
|
|
11
|
+
* to `b2b` later is a provisioning step, not a schema rewrite.
|
|
12
|
+
*/
|
|
13
|
+
export const PresetB2b = {
|
|
14
|
+
name: 'b2b',
|
|
15
|
+
display_name: 'B2B SaaS (orgs + invites + permissions)',
|
|
16
|
+
summary: '`auth:hardened` + orgs, invites, fine-grained permissions, levels, profiles, hierarchy.',
|
|
17
|
+
description: 'Everything in `auth:hardened`, plus the full org/team/permission stack at both app and ' +
|
|
18
|
+
'org membership scopes. You get: `memberships_module:org` for org-scoped memberships, ' +
|
|
19
|
+
'`permissions_module:app/:org` for fine-grained RBAC, `limits_module:app/:org` for per-scope ' +
|
|
20
|
+
'quota enforcement, `levels_module:app/:org` for role bundles, `profiles_module:app/:org` ' +
|
|
21
|
+
'for per-scope user display info, `hierarchy_module:org` for nested org structures, and ' +
|
|
22
|
+
'`invites_module:app/:org` for invite flows at either scope. Choose this when the app has ' +
|
|
23
|
+
'the concept of a "workspace" / "team" / "tenant" that users belong to and act within.',
|
|
24
|
+
good_for: [
|
|
25
|
+
'B2B SaaS with multi-tenant workspaces / teams',
|
|
26
|
+
'Apps where permissions scope to an organization, not globally',
|
|
27
|
+
'Apps with an invite-based onboarding flow (admins invite members)',
|
|
28
|
+
'Apps that need nested org hierarchies (parent org / sub-org / team)'
|
|
29
|
+
],
|
|
30
|
+
not_for: [
|
|
31
|
+
'Single-tenant consumer apps — use `auth:hardened` or `auth:email`',
|
|
32
|
+
'Apps where all users see the same global dataset — orgs would add overhead with no benefit'
|
|
33
|
+
],
|
|
34
|
+
modules: [
|
|
35
|
+
'users_module',
|
|
36
|
+
'membership_types_module',
|
|
37
|
+
'memberships_module:app',
|
|
38
|
+
'memberships_module:org',
|
|
39
|
+
'sessions_module',
|
|
40
|
+
'secrets_module',
|
|
41
|
+
'encrypted_secrets_module',
|
|
42
|
+
'emails_module',
|
|
43
|
+
'rls_module',
|
|
44
|
+
'user_auth_module',
|
|
45
|
+
'session_secrets_module',
|
|
46
|
+
'rate_limits_module',
|
|
47
|
+
'connected_accounts_module',
|
|
48
|
+
'identity_providers_module',
|
|
49
|
+
'webauthn_credentials_module',
|
|
50
|
+
'webauthn_auth_module',
|
|
51
|
+
'phone_numbers_module',
|
|
52
|
+
'permissions_module:app',
|
|
53
|
+
'permissions_module:org',
|
|
54
|
+
'limits_module:app',
|
|
55
|
+
'limits_module:org',
|
|
56
|
+
'levels_module:app',
|
|
57
|
+
'levels_module:org',
|
|
58
|
+
'profiles_module:app',
|
|
59
|
+
'profiles_module:org',
|
|
60
|
+
'hierarchy_module:org',
|
|
61
|
+
'invites_module:app',
|
|
62
|
+
'invites_module:org'
|
|
63
|
+
],
|
|
64
|
+
includes_notes: {
|
|
65
|
+
'memberships_module:org': 'Org-scoped membership rows — every user in an org gets one.',
|
|
66
|
+
'permissions_module:app': 'App-wide permission grants (e.g. platform admins).',
|
|
67
|
+
'permissions_module:org': 'Org-scoped permission grants (per-workspace admins, members, viewers, ...).',
|
|
68
|
+
'limits_module:app': 'App-level quotas (e.g. max users per plan).',
|
|
69
|
+
'limits_module:org': 'Org-level quotas (e.g. per-workspace API call caps).',
|
|
70
|
+
'levels_module:app': 'Role/level bundles at the app scope.',
|
|
71
|
+
'levels_module:org': 'Role/level bundles at the org scope (admin / member / viewer, etc.).',
|
|
72
|
+
'profiles_module:app': 'App-scoped user profile (one per user).',
|
|
73
|
+
'profiles_module:org': 'Org-scoped user profile (per org a user belongs to).',
|
|
74
|
+
'hierarchy_module:org': 'Nested org structures (parent / child orgs).',
|
|
75
|
+
'invites_module:app': 'App-level invites (rare — usually platform admin adds another admin).',
|
|
76
|
+
'invites_module:org': 'Org-level invites (the common case — invite a teammate into a workspace).'
|
|
77
|
+
},
|
|
78
|
+
omits_notes: {
|
|
79
|
+
storage_module: 'Add separately if you need file uploads tied to orgs.',
|
|
80
|
+
crypto_addresses_module: 'Not a web3 preset.'
|
|
81
|
+
},
|
|
82
|
+
extends: ['auth:hardened']
|
|
83
|
+
};
|
|
@@ -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,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `full` — install everything. Equivalent to the default
|
|
3
|
+
* `provision_database_modules(v_modules => ARRAY['all'])` behavior.
|
|
4
|
+
*
|
|
5
|
+
* This is the maximalist preset: every module Constructive ships, including
|
|
6
|
+
* `storage_module` for file uploads and `crypto_addresses_module` for
|
|
7
|
+
* wallet-based sign-in. Use it for greenfield apps where you'd rather
|
|
8
|
+
* disable features via `app_settings_auth` toggles than uninstall modules,
|
|
9
|
+
* or for the "kitchen sink" example / demo databases.
|
|
10
|
+
*
|
|
11
|
+
* Prefer a more targeted preset for anything production-bound — installing
|
|
12
|
+
* a module you'll never use still costs tables, triggers, and grants.
|
|
13
|
+
*/
|
|
14
|
+
export const PresetFull = {
|
|
15
|
+
name: 'full',
|
|
16
|
+
display_name: 'Full (every module)',
|
|
17
|
+
summary: "Install every Constructive module. Equivalent to v_modules => ARRAY['all'].",
|
|
18
|
+
description: 'Installs every module in the catalog: everything in `b2b` plus `storage_module` ' +
|
|
19
|
+
'for file uploads and `crypto_addresses_module` / `crypto_auth_module` for ' +
|
|
20
|
+
'wallet-based sign-in. This matches the current default when `provision_database_modules` ' +
|
|
21
|
+
"is called without an explicit `v_modules` argument. Use it for fully-featured " +
|
|
22
|
+
'demo/example databases, kitchen-sink reference deployments, or greenfield apps that ' +
|
|
23
|
+
'would rather feature-flag at the app_settings level than uninstall modules.',
|
|
24
|
+
good_for: [
|
|
25
|
+
'Reference / demo databases that showcase every Constructive feature',
|
|
26
|
+
'Greenfield apps where the product scope is still open-ended',
|
|
27
|
+
'Keeping the provisioning call identical to the pre-preset default'
|
|
28
|
+
],
|
|
29
|
+
not_for: [
|
|
30
|
+
'Production apps with a defined feature set — pick the narrowest preset that fits',
|
|
31
|
+
'Resource-constrained environments — every module costs schema bloat, RLS policies, and grants'
|
|
32
|
+
],
|
|
33
|
+
modules: ['all'],
|
|
34
|
+
includes_notes: {
|
|
35
|
+
all: "Sentinel — the provisioner installs every known module when `modules = ['all']`."
|
|
36
|
+
},
|
|
37
|
+
extends: ['b2b']
|
|
38
|
+
};
|
|
@@ -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,27 @@
|
|
|
1
|
+
import { PresetMinimal } from './minimal';
|
|
2
|
+
import { PresetAuthEmail } from './auth-email';
|
|
3
|
+
import { PresetAuthEmailMagic } from './auth-email-magic';
|
|
4
|
+
import { PresetAuthSso } from './auth-sso';
|
|
5
|
+
import { PresetAuthPasskey } from './auth-passkey';
|
|
6
|
+
import { PresetAuthHardened } from './auth-hardened';
|
|
7
|
+
import { PresetB2b } from './b2b';
|
|
8
|
+
import { PresetFull } from './full';
|
|
9
|
+
export { PresetMinimal, PresetAuthEmail, PresetAuthEmailMagic, PresetAuthSso, PresetAuthPasskey, PresetAuthHardened, PresetB2b, PresetFull };
|
|
10
|
+
/**
|
|
11
|
+
* Ordered list of all shipped module presets, from smallest to largest
|
|
12
|
+
* module footprint. Stable ordering — CLIs / UIs can present this directly.
|
|
13
|
+
*/
|
|
14
|
+
export const allModulePresets = [
|
|
15
|
+
PresetMinimal,
|
|
16
|
+
PresetAuthEmail,
|
|
17
|
+
PresetAuthEmailMagic,
|
|
18
|
+
PresetAuthSso,
|
|
19
|
+
PresetAuthPasskey,
|
|
20
|
+
PresetAuthHardened,
|
|
21
|
+
PresetB2b,
|
|
22
|
+
PresetFull
|
|
23
|
+
];
|
|
24
|
+
/** Look up a preset by name. Returns undefined if the name isn't known. */
|
|
25
|
+
export function getModulePreset(name) {
|
|
26
|
+
return allModulePresets.find((p) => p.name === name);
|
|
27
|
+
}
|
|
@@ -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,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `minimal` — users + sessions + RLS + API keys. No auth procedures, no
|
|
3
|
+
* memberships, no orgs, no emails, no passwords.
|
|
4
|
+
*
|
|
5
|
+
* This is the barest foundation: a `users` table, a `sessions` table so
|
|
6
|
+
* something upstream can mint tokens, `rls_module` so row-level security
|
|
7
|
+
* is enforceable, and `secrets_module` so you can issue API keys. Nothing
|
|
8
|
+
* else.
|
|
9
|
+
*
|
|
10
|
+
* You still write your own identity bridge on top (or rely on a header-based
|
|
11
|
+
* user-id coming from an upstream proxy / JWT verifier).
|
|
12
|
+
*/
|
|
13
|
+
export const PresetMinimal = {
|
|
14
|
+
name: 'minimal',
|
|
15
|
+
display_name: 'Minimal (RLS only)',
|
|
16
|
+
summary: 'users + sessions + RLS + API keys. No auth procedures installed.',
|
|
17
|
+
description: 'The smallest coherent Constructive install. You get a users table, a sessions table, ' +
|
|
18
|
+
'RLS enforcement, and API-key infrastructure — but no server-side sign_up/sign_in flow. ' +
|
|
19
|
+
'Pick this when authentication lives outside the database (an upstream IdP, a header from ' +
|
|
20
|
+
'a proxy, an internal service-to-service JWT) and Constructive is just the RLS-aware data ' +
|
|
21
|
+
'layer underneath.',
|
|
22
|
+
good_for: [
|
|
23
|
+
'Internal tools where an upstream proxy supplies the user identity',
|
|
24
|
+
'Backend-of-backend services that only need RLS, not an auth surface',
|
|
25
|
+
'Prototypes that will bolt on a richer auth preset later'
|
|
26
|
+
],
|
|
27
|
+
not_for: [
|
|
28
|
+
'Any app that needs `sign_up` / `sign_in` / `reset_password` out of the box — use `auth:email` instead',
|
|
29
|
+
'Multi-tenant / org-scoped apps — use `b2b`'
|
|
30
|
+
],
|
|
31
|
+
modules: [
|
|
32
|
+
'users_module',
|
|
33
|
+
'sessions_module',
|
|
34
|
+
'rls_module',
|
|
35
|
+
'secrets_module'
|
|
36
|
+
],
|
|
37
|
+
includes_notes: {
|
|
38
|
+
users_module: 'The canonical users table. Required by every preset.',
|
|
39
|
+
sessions_module: 'Session/token storage; needed so whatever upstream auth can mint a session row.',
|
|
40
|
+
rls_module: 'RLS policy infrastructure. Without it, row-level security is not enforced.',
|
|
41
|
+
secrets_module: 'API-key storage. Optional for this preset but almost always wanted alongside upstream auth.'
|
|
42
|
+
},
|
|
43
|
+
omits_notes: {
|
|
44
|
+
user_auth_module: 'No server-side sign_up/sign_in procedures in this preset.',
|
|
45
|
+
emails_module: 'Not needed without password/magic-link flows; upstream auth handles identity.',
|
|
46
|
+
memberships_module: 'No memberships without a user_auth_module wiring them up.'
|
|
47
|
+
}
|
|
48
|
+
};
|
|
@@ -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 @@
|
|
|
1
|
+
export {};
|
|
@@ -46,46 +46,33 @@ export const RelationManyToMany = {
|
|
|
46
46
|
},
|
|
47
47
|
"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."
|
|
48
48
|
},
|
|
49
|
-
"
|
|
49
|
+
"grants": {
|
|
50
50
|
"type": "array",
|
|
51
51
|
"items": {
|
|
52
|
-
"type": "
|
|
52
|
+
"type": "object",
|
|
53
|
+
"properties": {
|
|
54
|
+
"roles": { "type": "array", "items": { "type": "string" } },
|
|
55
|
+
"privileges": { "type": "array", "items": { "type": "array", "items": { "type": "string" } } }
|
|
56
|
+
},
|
|
57
|
+
"required": ["roles", "privileges"]
|
|
53
58
|
},
|
|
54
|
-
"description": "
|
|
59
|
+
"description": "Unified grant objects for the junction table. Each entry is { roles: string[], privileges: string[][] }. Forwarded to secure_table_provision as-is. Default: []"
|
|
55
60
|
},
|
|
56
|
-
"
|
|
61
|
+
"policies": {
|
|
57
62
|
"type": "array",
|
|
58
63
|
"items": {
|
|
59
|
-
"type": "
|
|
60
|
-
"
|
|
61
|
-
"type": "string"
|
|
62
|
-
|
|
64
|
+
"type": "object",
|
|
65
|
+
"properties": {
|
|
66
|
+
"$type": { "type": "string" },
|
|
67
|
+
"data": { "type": "object" },
|
|
68
|
+
"privileges": { "type": "array", "items": { "type": "string" } },
|
|
69
|
+
"policy_role": { "type": "string" },
|
|
70
|
+
"permissive": { "type": "boolean" },
|
|
71
|
+
"policy_name": { "type": "string" }
|
|
72
|
+
},
|
|
73
|
+
"required": ["$type"]
|
|
63
74
|
},
|
|
64
|
-
"description": "
|
|
65
|
-
},
|
|
66
|
-
"policy_type": {
|
|
67
|
-
"type": "string",
|
|
68
|
-
"description": "RLS policy type for the junction table. Forwarded to secure_table_provision as-is. NULL means no policy."
|
|
69
|
-
},
|
|
70
|
-
"policy_privileges": {
|
|
71
|
-
"type": "array",
|
|
72
|
-
"items": {
|
|
73
|
-
"type": "string"
|
|
74
|
-
},
|
|
75
|
-
"description": "Privileges the policy applies to. Forwarded to secure_table_provision as-is. NULL means derived from grant_privileges verbs."
|
|
76
|
-
},
|
|
77
|
-
"policy_role": {
|
|
78
|
-
"type": "string",
|
|
79
|
-
"description": "Database role the policy targets. Forwarded to secure_table_provision as-is. NULL means falls back to first grant_role."
|
|
80
|
-
},
|
|
81
|
-
"policy_permissive": {
|
|
82
|
-
"type": "boolean",
|
|
83
|
-
"description": "Whether the policy is PERMISSIVE (true) or RESTRICTIVE (false). Forwarded to secure_table_provision as-is.",
|
|
84
|
-
"default": true
|
|
85
|
-
},
|
|
86
|
-
"policy_data": {
|
|
87
|
-
"type": "object",
|
|
88
|
-
"description": "Policy configuration forwarded to secure_table_provision as-is. Structure varies by policy_type."
|
|
75
|
+
"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: []"
|
|
89
76
|
}
|
|
90
77
|
},
|
|
91
78
|
"required": [
|
package/index.d.ts
CHANGED
|
@@ -4,5 +4,6 @@ export * from './data';
|
|
|
4
4
|
export * from './relation';
|
|
5
5
|
export * from './view';
|
|
6
6
|
export * from './blueprint-types.generated';
|
|
7
|
+
export * from './module-presets';
|
|
7
8
|
import type { NodeTypeDefinition } from './types';
|
|
8
9
|
export declare const allNodeTypes: NodeTypeDefinition[];
|
package/index.js
CHANGED
|
@@ -42,6 +42,7 @@ __exportStar(require("./data"), exports);
|
|
|
42
42
|
__exportStar(require("./relation"), exports);
|
|
43
43
|
__exportStar(require("./view"), exports);
|
|
44
44
|
__exportStar(require("./blueprint-types.generated"), exports);
|
|
45
|
+
__exportStar(require("./module-presets"), exports);
|
|
45
46
|
const authz = __importStar(require("./authz"));
|
|
46
47
|
const data = __importStar(require("./data"));
|
|
47
48
|
const relation = __importStar(require("./relation"));
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ModulePreset } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* `auth:email+magic` — `auth:email` plus passwordless email flows.
|
|
4
|
+
*
|
|
5
|
+
* Adds `session_secrets_module`, which is where one-time nonces for magic
|
|
6
|
+
* links and email OTPs are stored. Once installed, the `user_auth_module`
|
|
7
|
+
* emits `sign_up_magic_link`, `sign_in_magic_link`, and `sign_in_email_otp`
|
|
8
|
+
* procedures (gated on the equivalent `allow_*` toggles in
|
|
9
|
+
* `app_settings_auth`).
|
|
10
|
+
*
|
|
11
|
+
* Choose this over `auth:email` when you want users to be able to log in
|
|
12
|
+
* without ever setting a password — but still only over email (no SMS, no
|
|
13
|
+
* SSO).
|
|
14
|
+
*/
|
|
15
|
+
export declare const PresetAuthEmailMagic: ModulePreset;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PresetAuthEmailMagic = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* `auth:email+magic` — `auth:email` plus passwordless email flows.
|
|
6
|
+
*
|
|
7
|
+
* Adds `session_secrets_module`, which is where one-time nonces for magic
|
|
8
|
+
* links and email OTPs are stored. Once installed, the `user_auth_module`
|
|
9
|
+
* emits `sign_up_magic_link`, `sign_in_magic_link`, and `sign_in_email_otp`
|
|
10
|
+
* procedures (gated on the equivalent `allow_*` toggles in
|
|
11
|
+
* `app_settings_auth`).
|
|
12
|
+
*
|
|
13
|
+
* Choose this over `auth:email` when you want users to be able to log in
|
|
14
|
+
* without ever setting a password — but still only over email (no SMS, no
|
|
15
|
+
* SSO).
|
|
16
|
+
*/
|
|
17
|
+
exports.PresetAuthEmailMagic = {
|
|
18
|
+
name: 'auth:email+magic',
|
|
19
|
+
display_name: 'Email + Magic Link / OTP',
|
|
20
|
+
summary: 'Everything in `auth:email` plus magic-link and email-OTP passwordless flows.',
|
|
21
|
+
description: 'Same password-based auth as `auth:email`, with `session_secrets_module` added so the ' +
|
|
22
|
+
'generator emits the passwordless procedures: `sign_up_magic_link`, `sign_in_magic_link`, ' +
|
|
23
|
+
'`sign_in_email_otp`. Password flows still exist — you opt into passwordless-only by ' +
|
|
24
|
+
'flipping the `allow_password_sign_*` toggles off in `app_settings_auth` after install. ' +
|
|
25
|
+
"This is the right step up from `auth:email` when you want to ship magic links without yet " +
|
|
26
|
+
"taking on SSO or passkeys.",
|
|
27
|
+
good_for: [
|
|
28
|
+
'Consumer apps that want passwordless from day one',
|
|
29
|
+
'Apps targeting users who forget passwords (newsletters, one-off tools)',
|
|
30
|
+
'Hardening path from `auth:email` without jumping all the way to `auth:hardened`'
|
|
31
|
+
],
|
|
32
|
+
not_for: [
|
|
33
|
+
'Apps that need SSO or passkeys — use `auth:sso` or `auth:passkey`',
|
|
34
|
+
'Production at scale — use `auth:hardened` for rate limiting'
|
|
35
|
+
],
|
|
36
|
+
modules: [
|
|
37
|
+
'users_module',
|
|
38
|
+
'membership_types_module',
|
|
39
|
+
'memberships_module:app',
|
|
40
|
+
'sessions_module',
|
|
41
|
+
'secrets_module',
|
|
42
|
+
'encrypted_secrets_module',
|
|
43
|
+
'emails_module',
|
|
44
|
+
'rls_module',
|
|
45
|
+
'user_auth_module',
|
|
46
|
+
'session_secrets_module'
|
|
47
|
+
],
|
|
48
|
+
includes_notes: {
|
|
49
|
+
session_secrets_module: 'Stores nonces for magic-link and email-OTP flows. Without it those procedures are not emitted.'
|
|
50
|
+
},
|
|
51
|
+
omits_notes: {
|
|
52
|
+
rate_limits_module: 'Same reasoning as `auth:email` — add later via `auth:hardened`.',
|
|
53
|
+
connected_accounts_module: 'No OAuth / SSO in this preset.',
|
|
54
|
+
webauthn_credentials_module: 'No passkeys — add `auth:passkey`.',
|
|
55
|
+
phone_numbers_module: 'No SMS — add `auth:hardened`.'
|
|
56
|
+
},
|
|
57
|
+
extends: ['auth:email']
|
|
58
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ModulePreset } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* `auth:email` — email + password sign_up/sign_in. No orgs, no SSO, no SMS,
|
|
4
|
+
* no passkeys, no rate limits.
|
|
5
|
+
*
|
|
6
|
+
* This is the "working consumer login in one step" preset. It installs the
|
|
7
|
+
* `user_auth_module` and all the tables its insert trigger hard-requires,
|
|
8
|
+
* giving you the standard procedures: `sign_up`, `sign_in`, `sign_out`,
|
|
9
|
+
* `set_password`, `reset_password`, `forgot_password`, `verify_email`,
|
|
10
|
+
* `delete_account`, `my_sessions`, API-key CRUD. Nothing more.
|
|
11
|
+
*
|
|
12
|
+
* It deliberately excludes rate limits, connected accounts / identity
|
|
13
|
+
* providers (OAuth), WebAuthn (passkeys), phone numbers (SMS), invites,
|
|
14
|
+
* permissions, and org-scoped memberships. Bolt those on by moving to a
|
|
15
|
+
* richer preset (`auth:hardened`, `b2b`) when you actually need them.
|
|
16
|
+
*/
|
|
17
|
+
export declare const PresetAuthEmail: ModulePreset;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PresetAuthEmail = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* `auth:email` — email + password sign_up/sign_in. No orgs, no SSO, no SMS,
|
|
6
|
+
* no passkeys, no rate limits.
|
|
7
|
+
*
|
|
8
|
+
* This is the "working consumer login in one step" preset. It installs the
|
|
9
|
+
* `user_auth_module` and all the tables its insert trigger hard-requires,
|
|
10
|
+
* giving you the standard procedures: `sign_up`, `sign_in`, `sign_out`,
|
|
11
|
+
* `set_password`, `reset_password`, `forgot_password`, `verify_email`,
|
|
12
|
+
* `delete_account`, `my_sessions`, API-key CRUD. Nothing more.
|
|
13
|
+
*
|
|
14
|
+
* It deliberately excludes rate limits, connected accounts / identity
|
|
15
|
+
* providers (OAuth), WebAuthn (passkeys), phone numbers (SMS), invites,
|
|
16
|
+
* permissions, and org-scoped memberships. Bolt those on by moving to a
|
|
17
|
+
* richer preset (`auth:hardened`, `b2b`) when you actually need them.
|
|
18
|
+
*/
|
|
19
|
+
exports.PresetAuthEmail = {
|
|
20
|
+
name: 'auth:email',
|
|
21
|
+
display_name: 'Email + Password',
|
|
22
|
+
summary: 'Standard email/password auth flow. No orgs, no SSO, no MFA, no rate limits.',
|
|
23
|
+
description: "Installs `user_auth_module` with exactly the table dependencies its insert trigger " +
|
|
24
|
+
"hard-requires: users, app-scoped memberships, emails, secrets, encrypted secrets, " +
|
|
25
|
+
"sessions, plus RLS. You get the standard password-based auth procedures (sign_up, " +
|
|
26
|
+
"sign_in, reset_password, verify_email, delete_account, ...) and that's it. " +
|
|
27
|
+
"Everything else in the module catalog — SSO, passkeys, SMS, rate limits, orgs, " +
|
|
28
|
+
"invites, permissions — is deliberately omitted. This is the right shape for single-tenant " +
|
|
29
|
+
"consumer apps in the first weeks, internal tools that need a real login, or anything " +
|
|
30
|
+
"where you want the lightest possible working auth and will add complexity only when " +
|
|
31
|
+
"forced to.",
|
|
32
|
+
good_for: [
|
|
33
|
+
'Single-tenant consumer apps in the first week of development',
|
|
34
|
+
'Internal tools where one simple login is enough',
|
|
35
|
+
'Demos and hobby projects that need real password auth',
|
|
36
|
+
'B2C SaaS before org/team features are needed'
|
|
37
|
+
],
|
|
38
|
+
not_for: [
|
|
39
|
+
'Apps with org/team/workspace structure — use `b2b`',
|
|
40
|
+
'Apps that need SSO or passkeys from day one — use `auth:sso` or `auth:passkey`',
|
|
41
|
+
'Production apps at scale — use `auth:hardened` (adds rate limits, SSO, passkeys, SMS)'
|
|
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
|
+
],
|
|
54
|
+
includes_notes: {
|
|
55
|
+
'memberships_module:app': 'Required by `user_auth_module`: every user gets an app-level membership row at sign-up.',
|
|
56
|
+
membership_types_module: "Required by `memberships_module:app`; defines the 'app' scope.",
|
|
57
|
+
emails_module: 'Required by the `user_auth_module` insert trigger (`RAISE EXCEPTION REQUIRES emails_module`).',
|
|
58
|
+
encrypted_secrets_module: 'Required for password hashing; referenced by `set_password`, `verify_password`, and reset flows.',
|
|
59
|
+
secrets_module: 'API-key storage (`create_api_key`, `revoke_api_key`, `my_api_keys`).'
|
|
60
|
+
},
|
|
61
|
+
omits_notes: {
|
|
62
|
+
rate_limits_module: 'Omitted intentionally; throttle_* helpers are null-safe and the auth procs compile without it. Add later via `auth:hardened`.',
|
|
63
|
+
connected_accounts_module: 'No OAuth / SSO in this preset — add `auth:sso`.',
|
|
64
|
+
identity_providers_module: 'No OAuth provider configs without connected_accounts.',
|
|
65
|
+
webauthn_credentials_module: 'No passkeys — add `auth:passkey`.',
|
|
66
|
+
phone_numbers_module: 'No SMS login — add `auth:hardened` or the SMS-only refactor path.',
|
|
67
|
+
'memberships_module:org': 'No org/team structure — move to `b2b` when you need one.',
|
|
68
|
+
'permissions_module:app': 'No fine-grained RBAC; the `is_admin` flag on users is the only gate.',
|
|
69
|
+
invites_module: 'Self-serve signup only.',
|
|
70
|
+
session_secrets_module: 'No magic-link / email-OTP nonces; add `auth:email+magic`.'
|
|
71
|
+
}
|
|
72
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ModulePreset } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* `auth:hardened` — `auth:email` with rate limiting, SSO, passkeys, SMS,
|
|
4
|
+
* and magic-link / OTP infrastructure all installed. Production-ready
|
|
5
|
+
* consumer auth with the full identifier matrix.
|
|
6
|
+
*
|
|
7
|
+
* Still single-tenant (no orgs / teams / invites / permissions). For
|
|
8
|
+
* multi-tenant B2B, step up to `b2b`.
|
|
9
|
+
*/
|
|
10
|
+
export declare const PresetAuthHardened: ModulePreset;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PresetAuthHardened = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* `auth:hardened` — `auth:email` with rate limiting, SSO, passkeys, SMS,
|
|
6
|
+
* and magic-link / OTP infrastructure all installed. Production-ready
|
|
7
|
+
* consumer auth with the full identifier matrix.
|
|
8
|
+
*
|
|
9
|
+
* Still single-tenant (no orgs / teams / invites / permissions). For
|
|
10
|
+
* multi-tenant B2B, step up to `b2b`.
|
|
11
|
+
*/
|
|
12
|
+
exports.PresetAuthHardened = {
|
|
13
|
+
name: 'auth:hardened',
|
|
14
|
+
display_name: 'Hardened (all auth surfaces)',
|
|
15
|
+
summary: 'Rate limits + SSO + passkeys + SMS + magic links. Production-grade consumer auth.',
|
|
16
|
+
description: 'All of `auth:email`, plus every optional auth module that fits inside the single-tenant ' +
|
|
17
|
+
'model: `rate_limits_module` for throttling (protects sign-in, password reset, and ' +
|
|
18
|
+
'signup flows), `connected_accounts_module` + `identity_providers_module` for SSO, ' +
|
|
19
|
+
'`webauthn_credentials_module` + `webauthn_auth_module` for passkeys, ' +
|
|
20
|
+
'`session_secrets_module` for magic-link / email-OTP nonces, and ' +
|
|
21
|
+
'`phone_numbers_module` for SMS flows. Every login identifier is available; ' +
|
|
22
|
+
'toggle whichever ones you want off via `app_settings_auth.allow_*` columns. ' +
|
|
23
|
+
'Choose this for any production consumer app; step up to `b2b` once you need orgs.',
|
|
24
|
+
good_for: [
|
|
25
|
+
'Production consumer apps with a serious user base',
|
|
26
|
+
'Apps that need every identifier available (email, SSO, passkey, SMS) with throttling',
|
|
27
|
+
'Apps doing a progressive rollout of auth methods — everything is installed, you toggle per method'
|
|
28
|
+
],
|
|
29
|
+
not_for: [
|
|
30
|
+
'Hobby projects / demos — way too much infrastructure; use `auth:email`',
|
|
31
|
+
'Multi-tenant B2B apps — use `b2b`, which layers orgs + invites + permissions on top'
|
|
32
|
+
],
|
|
33
|
+
modules: [
|
|
34
|
+
'users_module',
|
|
35
|
+
'membership_types_module',
|
|
36
|
+
'memberships_module:app',
|
|
37
|
+
'sessions_module',
|
|
38
|
+
'secrets_module',
|
|
39
|
+
'encrypted_secrets_module',
|
|
40
|
+
'emails_module',
|
|
41
|
+
'rls_module',
|
|
42
|
+
'user_auth_module',
|
|
43
|
+
'session_secrets_module',
|
|
44
|
+
'rate_limits_module',
|
|
45
|
+
'connected_accounts_module',
|
|
46
|
+
'identity_providers_module',
|
|
47
|
+
'webauthn_credentials_module',
|
|
48
|
+
'webauthn_auth_module',
|
|
49
|
+
'phone_numbers_module'
|
|
50
|
+
],
|
|
51
|
+
includes_notes: {
|
|
52
|
+
rate_limits_module: 'Throttling for sign-in, password reset, sign-up, and IP-based gates.',
|
|
53
|
+
connected_accounts_module: 'OAuth / SSO linkage.',
|
|
54
|
+
identity_providers_module: 'OAuth provider configs (required for `connected_accounts_module`).',
|
|
55
|
+
webauthn_credentials_module: 'Per-user passkey storage.',
|
|
56
|
+
webauthn_auth_module: 'Passkey challenge + assertion runtime.',
|
|
57
|
+
session_secrets_module: 'Nonces for magic links, email OTP, and WebAuthn challenges.',
|
|
58
|
+
phone_numbers_module: 'SMS sign-in / MFA support.'
|
|
59
|
+
},
|
|
60
|
+
omits_notes: {
|
|
61
|
+
'memberships_module:org': 'No orgs / teams — use `b2b` when you need multi-tenancy.',
|
|
62
|
+
'permissions_module:app': 'No RBAC beyond the `is_admin` flag — add via `b2b`.',
|
|
63
|
+
invites_module: 'No invite flow — add via `b2b`.',
|
|
64
|
+
storage_module: 'Add separately if you need file uploads.',
|
|
65
|
+
crypto_addresses_module: 'Not a web3 preset; omit unless doing wallet sign-in.'
|
|
66
|
+
},
|
|
67
|
+
extends: ['auth:email', 'auth:email+magic', 'auth:sso', 'auth:passkey']
|
|
68
|
+
};
|