@nextsparkjs/core 0.1.0-beta.166 → 0.1.0-beta.168

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 (50) hide show
  1. package/dist/hooks/useAuth.d.ts +2 -1
  2. package/dist/hooks/useAuth.d.ts.map +1 -1
  3. package/dist/hooks/useAuth.js +13 -8
  4. package/dist/lib/api/entity/generic-handler.d.ts.map +1 -1
  5. package/dist/lib/api/entity/generic-handler.js +23 -3
  6. package/dist/lib/auth-context.d.ts +5 -0
  7. package/dist/lib/auth-context.d.ts.map +1 -1
  8. package/dist/lib/auth.d.ts.map +1 -1
  9. package/dist/lib/auth.js +28 -5
  10. package/dist/lib/config/app.config.d.ts.map +1 -1
  11. package/dist/lib/config/app.config.js +9 -1
  12. package/dist/lib/config/types.d.ts +17 -0
  13. package/dist/lib/config/types.d.ts.map +1 -1
  14. package/dist/lib/db.d.ts +28 -5
  15. package/dist/lib/db.d.ts.map +1 -1
  16. package/dist/lib/db.js +38 -16
  17. package/dist/lib/entities/types.d.ts +20 -3
  18. package/dist/lib/entities/types.d.ts.map +1 -1
  19. package/dist/lib/services/team-member.service.d.ts.map +1 -1
  20. package/dist/lib/services/team-member.service.js +2 -1
  21. package/dist/lib/services/team.service.d.ts.map +1 -1
  22. package/dist/lib/services/team.service.js +2 -2
  23. package/dist/lib/teams/actions.d.ts.map +1 -1
  24. package/dist/lib/teams/actions.js +4 -3
  25. package/dist/migrations/001_better_auth_and_functions.sql +70 -0
  26. package/dist/migrations/002_auth_tables.sql +90 -10
  27. package/dist/migrations/007_teams_table.sql +10 -4
  28. package/dist/migrations/008_team_members_table.sql +1 -1
  29. package/dist/migrations/009_team_invitations_table.sql +1 -1
  30. package/dist/migrations/010_teams_functions_triggers.sql +6 -48
  31. package/dist/migrations/013_billing_subscriptions.sql +61 -31
  32. package/dist/migrations/016_billing_events.sql +17 -3
  33. package/dist/migrations/017_scheduled_actions_table.sql +9 -7
  34. package/dist/migrations/022_rls_runtime_roles.sql +87 -0
  35. package/dist/styles/classes.json +1 -1
  36. package/dist/templates/app/api/auth/[...all]/route.ts +14 -1
  37. package/migrations/001_better_auth_and_functions.sql +70 -0
  38. package/migrations/002_auth_tables.sql +90 -10
  39. package/migrations/007_teams_table.sql +10 -4
  40. package/migrations/008_team_members_table.sql +1 -1
  41. package/migrations/009_team_invitations_table.sql +1 -1
  42. package/migrations/010_teams_functions_triggers.sql +6 -48
  43. package/migrations/013_billing_subscriptions.sql +61 -31
  44. package/migrations/016_billing_events.sql +17 -3
  45. package/migrations/017_scheduled_actions_table.sql +9 -7
  46. package/migrations/022_rls_runtime_roles.sql +87 -0
  47. package/package.json +2 -2
  48. package/scripts/db/run-migrations.mjs +13 -2
  49. package/templates/app/api/auth/[...all]/route.ts +14 -1
  50. package/templates/next.config.mjs +1 -4
@@ -0,0 +1,87 @@
1
+ -- ============================================================================
2
+ -- 022 · RLS runtime roles — nextspark_app (non-owner runtime role) + grants
3
+ -- ============================================================================
4
+ -- Generic framework migration: creates the non-owner runtime role the app
5
+ -- connects as so RLS is actually evaluated on the app path.
6
+ --
7
+ -- WHY: by default the app connects to Postgres as the table OWNER, so RLS
8
+ -- policies are never evaluated on the app path (owner skips RLS unless FORCE).
9
+ -- This migration creates the non-owner runtime role the app connects as after
10
+ -- the runtime cutover. Until the cutover nothing changes for the running app:
11
+ -- migrations and seeds keep running as the owner.
12
+ --
13
+ -- Design decisions:
14
+ -- - nextspark_app is NOLOGIN here; the LOGIN credential is created per environment
15
+ -- at cutover time (deploy-time secret), never in a migration.
16
+ -- - nextspark_app is a member of `authenticated` (INHERIT): every existing policy
17
+ -- declared `TO authenticated` applies to it without rewriting.
18
+ -- - NO `FORCE ROW LEVEL SECURITY`: nextspark_app is not the owner so plain ENABLE
19
+ -- is enough, and FORCE would break owner-run seeds/sample-data on Supabase
20
+ -- (where `postgres` is owner but not superuser).
21
+ -- - NO `BYPASSRLS` role here: that attribute requires superuser (not available
22
+ -- on Supabase). The service context for machine actors (webhooks, scheduled
23
+ -- actions) is a CORE/environment workstream: the app uses a separate service
24
+ -- connection (DATABASE_SERVICE_URL) for system operations.
25
+ -- - `anon` gets an explicit REVOKE + default privileges revoke: on Supabase the
26
+ -- default privileges grant to anon automatically; abstaining is not enough.
27
+ --
28
+ -- Ordering: runs after all core table DDL (<= 021) so `GRANT ... ON ALL TABLES`
29
+ -- covers every existing table; `ALTER DEFAULT PRIVILEGES` covers tables created
30
+ -- later (theme/entity migrations) by the same migration owner.
31
+
32
+ -- ----------------------------------------------------------------------------
33
+ -- 1. Runtime role
34
+ -- ----------------------------------------------------------------------------
35
+ DO $$
36
+ BEGIN
37
+ IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'nextspark_app') THEN
38
+ CREATE ROLE nextspark_app NOLOGIN NOINHERIT;
39
+ END IF;
40
+ END $$;
41
+
42
+ -- INHERIT membership in `authenticated` so policies `TO authenticated` apply.
43
+ ALTER ROLE nextspark_app INHERIT;
44
+ GRANT authenticated TO nextspark_app;
45
+
46
+ -- Allow the migration/validation user to SET ROLE nextspark_app (e.g. an RLS
47
+ -- isolation test suite can run its checks as this role without a LOGIN credential).
48
+ DO $$
49
+ BEGIN
50
+ EXECUTE format('GRANT nextspark_app TO %I', current_user);
51
+ EXCEPTION WHEN OTHERS THEN
52
+ RAISE NOTICE 'GRANT nextspark_app TO current_user skipped: %', SQLERRM;
53
+ END $$;
54
+
55
+ -- ----------------------------------------------------------------------------
56
+ -- 2. Grants for nextspark_app (RLS does the row filtering; grants gate the tables)
57
+ -- ----------------------------------------------------------------------------
58
+ GRANT USAGE ON SCHEMA public TO nextspark_app;
59
+ GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO nextspark_app;
60
+ GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO nextspark_app;
61
+ GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO nextspark_app;
62
+
63
+ -- Future objects created by the migration owner inherit the same grants.
64
+ ALTER DEFAULT PRIVILEGES IN SCHEMA public
65
+ GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO nextspark_app;
66
+ ALTER DEFAULT PRIVILEGES IN SCHEMA public
67
+ GRANT USAGE, SELECT ON SEQUENCES TO nextspark_app;
68
+ ALTER DEFAULT PRIVILEGES IN SCHEMA public
69
+ GRANT EXECUTE ON FUNCTIONS TO nextspark_app;
70
+
71
+ -- ----------------------------------------------------------------------------
72
+ -- 3. anon: explicit lockdown (defense for PostgREST/Data API surfaces)
73
+ -- ----------------------------------------------------------------------------
74
+ DO $$
75
+ BEGIN
76
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'anon') THEN
77
+ REVOKE ALL ON ALL TABLES IN SCHEMA public FROM anon;
78
+ REVOKE ALL ON ALL SEQUENCES IN SCHEMA public FROM anon;
79
+ REVOKE ALL ON ALL FUNCTIONS IN SCHEMA public FROM anon;
80
+ ALTER DEFAULT PRIVILEGES IN SCHEMA public REVOKE ALL ON TABLES FROM anon;
81
+ ALTER DEFAULT PRIVILEGES IN SCHEMA public REVOKE ALL ON SEQUENCES FROM anon;
82
+ ALTER DEFAULT PRIVILEGES IN SCHEMA public REVOKE ALL ON FUNCTIONS FROM anon;
83
+ END IF;
84
+ END $$;
85
+
86
+ COMMENT ON ROLE nextspark_app IS
87
+ 'Non-owner runtime role for the NextSpark app. Member of authenticated (policies TO authenticated apply). RLS is evaluated for every query once DATABASE_URL connects as this role instead of the table owner.';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextsparkjs/core",
3
- "version": "0.1.0-beta.166",
3
+ "version": "0.1.0-beta.168",
4
4
  "description": "NextSpark - The complete SaaS framework for Next.js",
5
5
  "license": "MIT",
6
6
  "author": "NextSpark <hello@nextspark.dev>",
@@ -469,7 +469,7 @@
469
469
  "tailwind-merge": "^3.3.1",
470
470
  "uuid": "^13.0.0",
471
471
  "zod": "^4.1.5",
472
- "@nextsparkjs/testing": "0.1.0-beta.166"
472
+ "@nextsparkjs/testing": "0.1.0-beta.168"
473
473
  },
474
474
  "scripts": {
475
475
  "postinstall": "node scripts/postinstall.mjs || true",
@@ -21,6 +21,11 @@ const rootDir = projectRoot; // For backward compatibility with code below
21
21
  const envPath = path.join(projectRoot, '.env');
22
22
 
23
23
  let DATABASE_URL = process.env.DATABASE_URL ?? null;
24
+ // Migrations and seeds run as the table OWNER. After the runtime cutover the app
25
+ // connects DATABASE_URL as the non-owner `nextspark_app` role, so the owner
26
+ // credential for migrations is provided separately via MIGRATE_DATABASE_URL.
27
+ // Falls back to DATABASE_URL when unset (pre-cutover: same owner connection).
28
+ let MIGRATE_DATABASE_URL = process.env.MIGRATE_DATABASE_URL ?? null;
24
29
  let ACTIVE_THEME = process.env.NEXT_PUBLIC_ACTIVE_THEME ?? null;
25
30
 
26
31
  if (fs.existsSync(envPath)) {
@@ -35,6 +40,9 @@ if (fs.existsSync(envPath)) {
35
40
  if (key?.trim() === 'DATABASE_URL' && valueParts.length > 0) {
36
41
  DATABASE_URL = value;
37
42
  }
43
+ if (key?.trim() === 'MIGRATE_DATABASE_URL' && valueParts.length > 0) {
44
+ MIGRATE_DATABASE_URL = value;
45
+ }
38
46
  if (key?.trim() === 'NEXT_PUBLIC_ACTIVE_THEME' && valueParts.length > 0) {
39
47
  ACTIVE_THEME = value;
40
48
  }
@@ -47,6 +55,9 @@ if (!DATABASE_URL) {
47
55
  process.exit(1);
48
56
  }
49
57
 
58
+ // The URL used for the actual migration connection (owner credential).
59
+ const MIGRATION_URL = MIGRATE_DATABASE_URL || DATABASE_URL;
60
+
50
61
  if (!ACTIVE_THEME) {
51
62
  console.error("❌ NEXT_PUBLIC_ACTIVE_THEME not found in environment variables");
52
63
  process.exit(1);
@@ -54,7 +65,7 @@ if (!ACTIVE_THEME) {
54
65
 
55
66
  async function runMigrations() {
56
67
  const client = new Client({
57
- connectionString: DATABASE_URL,
68
+ connectionString: MIGRATION_URL,
58
69
  ssl: {
59
70
  rejectUnauthorized: false,
60
71
  require: true
@@ -359,7 +370,7 @@ async function executeEntityMigration(client, migration) {
359
370
  // Entity migrations runner - WordPress-like architecture with sample_data deferred execution
360
371
  async function runEntityMigrations() {
361
372
  const client = new Client({
362
- connectionString: DATABASE_URL,
373
+ connectionString: MIGRATION_URL,
363
374
  ssl: {
364
375
  rejectUnauthorized: false,
365
376
  require: true
@@ -8,6 +8,7 @@ import { isPublicSignupRestricted } from "@nextsparkjs/core/lib/teams/helpers";
8
8
  import { TeamService } from "@nextsparkjs/core/lib/services";
9
9
  import { wrapAuthHandlerWithCors, handleCorsPreflightRequest, addCorsHeaders } from "@nextsparkjs/core/lib/api/helpers";
10
10
  import { checkDistributedRateLimit } from "@nextsparkjs/core/lib/api/rate-limit";
11
+ import { withSignupContext } from "@nextsparkjs/core/lib/auth-context";
11
12
 
12
13
  const handlers = toNextJsHandler(auth);
13
14
 
@@ -137,6 +138,18 @@ export async function POST(req: NextRequest) {
137
138
  }
138
139
  }
139
140
 
141
+ // Read the optional signup intent (`x-signup-intent` header) and run the signup
142
+ // within request-scoped context so the user.create.after hook can map it to an
143
+ // initial team role (AUTH_CONFIG.signupIntent).
144
+ const signupIntent = isSignupAttempt
145
+ ? (req.headers.get('x-signup-intent') || undefined)
146
+ : undefined;
147
+
140
148
  // Wrap with CORS headers for cross-origin requests (mobile apps, etc.)
141
- return wrapAuthHandlerWithCors(() => handlers.POST(req), req);
149
+ return wrapAuthHandlerWithCors(
150
+ signupIntent
151
+ ? () => withSignupContext({ signupIntent }, () => handlers.POST(req))
152
+ : () => handlers.POST(req),
153
+ req
154
+ );
142
155
  }
@@ -16,10 +16,7 @@ const nextConfig = {
16
16
  ignoreBuildErrors: true,
17
17
  },
18
18
  transpilePackages: ['@nextsparkjs/core'],
19
- // Server-only packages that must NOT be bundled (they use Node built-ins like
20
- // async_hooks). e.g. the AI plugin's @anthropic-ai/claude-agent-sdk. Listing
21
- // a package here is harmless when it isn't installed.
22
- serverExternalPackages: ['handlebars', '@anthropic-ai/claude-agent-sdk'],
19
+ serverExternalPackages: ['handlebars'],
23
20
  turbopack: {
24
21
  root: __dirname,
25
22
  },