@nextsparkjs/core 0.1.0-beta.196 → 0.1.0-beta.197
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/README.md +2 -0
- package/dist/components/auth/forms/SignupForm.d.ts.map +1 -1
- package/dist/components/auth/forms/SignupForm.js +55 -45
- package/dist/components/dashboard/block-editor/config-panel.d.ts.map +1 -1
- package/dist/components/dashboard/block-editor/config-panel.js +3 -2
- package/dist/components/dashboard/block-editor/entity-fields-sidebar.d.ts.map +1 -1
- package/dist/components/dashboard/block-editor/entity-fields-sidebar.js +3 -2
- package/dist/components/users/tables/UsersTable.d.ts.map +1 -1
- package/dist/components/users/tables/UsersTable.js +3 -4
- package/dist/hooks/useAuthReadiness.d.ts +1 -0
- package/dist/hooks/useAuthReadiness.d.ts.map +1 -1
- package/dist/hooks/useAuthReadiness.js +3 -1
- package/dist/lib/actions/entity.actions.js +2 -2
- package/dist/lib/actions/team.actions.js +2 -2
- package/dist/lib/actions/user.actions.js +4 -4
- package/dist/lib/api/auth/dual-auth.d.ts.map +1 -1
- package/dist/lib/api/auth/dual-auth.js +3 -2
- package/dist/lib/api/auth.d.ts.map +1 -1
- package/dist/lib/api/auth.js +7 -0
- package/dist/lib/api/entity/generic-handler.d.ts.map +1 -1
- package/dist/lib/api/entity/generic-handler.js +66 -12
- package/dist/lib/api/entity-handler.js +2 -2
- package/dist/lib/api/helpers.d.ts.map +1 -1
- package/dist/lib/api/helpers.js +4 -2
- package/dist/lib/api/post-categories.d.ts +29 -0
- package/dist/lib/api/post-categories.d.ts.map +1 -0
- package/dist/lib/api/post-categories.js +33 -0
- package/dist/lib/auth/auth-methods.d.ts +5 -2
- package/dist/lib/auth/auth-methods.d.ts.map +1 -1
- package/dist/lib/auth/auth-methods.js +4 -2
- package/dist/lib/auth/authorization-session.d.ts +14 -0
- package/dist/lib/auth/authorization-session.d.ts.map +1 -0
- package/dist/lib/auth/authorization-session.js +10 -0
- package/dist/lib/auth/request-session.d.ts +5 -0
- package/dist/lib/auth/request-session.d.ts.map +1 -1
- package/dist/lib/auth/request-session.js +3 -0
- package/dist/lib/auth/runtime-readiness.d.ts +7 -4
- package/dist/lib/auth/runtime-readiness.d.ts.map +1 -1
- package/dist/lib/auth/runtime-readiness.js +7 -6
- package/dist/lib/auth/sample-accounts.d.ts +2 -1
- package/dist/lib/auth/sample-accounts.d.ts.map +1 -1
- package/dist/lib/auth/sample-accounts.js +4 -1
- package/dist/lib/auth/suspension.d.ts +22 -0
- package/dist/lib/auth/suspension.d.ts.map +1 -0
- package/dist/lib/auth/suspension.js +43 -0
- package/dist/lib/auth.d.ts.map +1 -1
- package/dist/lib/auth.js +15 -15
- package/dist/lib/config/app.config.d.ts.map +1 -1
- package/dist/lib/config/app.config.js +6 -7
- package/dist/lib/config/types.d.ts +8 -6
- package/dist/lib/config/types.d.ts.map +1 -1
- package/dist/lib/db-pool.d.ts +31 -0
- package/dist/lib/db-pool.d.ts.map +1 -0
- package/dist/lib/db-pool.js +75 -0
- package/dist/lib/db.d.ts +1 -1
- package/dist/lib/db.d.ts.map +1 -1
- package/dist/lib/db.js +11 -14
- package/dist/lib/entities/api-generator.js +5 -5
- package/dist/lib/oauth/token-refresh.d.ts.map +1 -1
- package/dist/lib/oauth/token-refresh.js +3 -6
- package/dist/lib/permissions/check.d.ts +9 -0
- package/dist/lib/permissions/check.d.ts.map +1 -1
- package/dist/lib/permissions/check.js +11 -1
- package/dist/lib/services/generic-entity.service.d.ts.map +1 -1
- package/dist/lib/services/generic-entity.service.js +39 -7
- package/dist/lib/services/transactional-meta.service.d.ts.map +1 -1
- package/dist/lib/services/transactional-meta.service.js +7 -8
- package/dist/lib/validation.d.ts +5 -0
- package/dist/lib/validation.d.ts.map +1 -1
- package/dist/lib/validation.js +2 -0
- package/dist/migrations/030_taxonomies_team_writes.sql +29 -0
- package/dist/migrations/031_users_role_suspended.sql +41 -0
- package/dist/routes/(auth)/signup/page.cc.d.ts +3 -1
- package/dist/routes/(auth)/signup/page.cc.d.ts.map +1 -1
- package/dist/routes/(auth)/signup/page.cc.js +2 -2
- package/dist/routes/(auth)/signup/page.d.ts +3 -1
- package/dist/routes/(auth)/signup/page.d.ts.map +1 -1
- package/dist/routes/(auth)/signup/page.js +4 -3
- package/dist/routes/_internal/area-access.js +2 -2
- package/dist/routes/api/devtools/config/entities/route.js +2 -2
- package/dist/routes/api/devtools/config/theme/route.js +2 -2
- package/dist/routes/api/devtools/tests/[...path]/route.js +2 -2
- package/dist/routes/api/devtools/tests/route.js +2 -2
- package/dist/routes/api/superadmin/subscriptions/route.js +2 -2
- package/dist/routes/api/superadmin/teams/[teamId]/route.js +2 -2
- package/dist/routes/api/superadmin/teams/route.js +2 -2
- package/dist/routes/api/superadmin/users/[userId]/route.d.ts +5 -3
- package/dist/routes/api/superadmin/users/[userId]/route.d.ts.map +1 -1
- package/dist/routes/api/superadmin/users/[userId]/route.js +46 -23
- package/dist/routes/api/superadmin/users/route.js +2 -2
- package/dist/routes/api/user/delete-account/route.d.ts.map +1 -1
- package/dist/routes/api/user/delete-account/route.js +2 -3
- package/dist/routes/api/user/plan-flags/route.d.ts.map +1 -1
- package/dist/routes/api/user/plan-flags/route.js +5 -5
- package/dist/routes/api/user/profile/route.js +3 -3
- package/dist/routes/api/v1/auth/signup-with-invite/route.d.ts.map +1 -1
- package/dist/routes/api/v1/auth/signup-with-invite/route.js +80 -44
- package/dist/routes/api/v1/post-categories/[id]/route.d.ts.map +1 -1
- package/dist/routes/api/v1/post-categories/[id]/route.js +39 -34
- package/dist/routes/api/v1/post-categories/route.d.ts.map +1 -1
- package/dist/routes/api/v1/post-categories/route.js +18 -14
- package/dist/routes/api/v1/team-invitations/route.d.ts.map +1 -1
- package/dist/routes/api/v1/team-invitations/route.js +12 -5
- package/dist/routes/superadmin/users/page.js +2 -2
- package/dist/templates/next.config.mjs +11 -31
- package/dist/templates/projects/blog/package.json +1 -1
- package/dist/templates/projects/crm/package.json +1 -1
- package/dist/templates/projects/productivity/package.json +1 -1
- package/dist/templates/projects/starter/config/app.config.ts +8 -0
- package/dist/templates/proxy.ts +6 -3
- package/migrations/030_taxonomies_team_writes.sql +29 -0
- package/migrations/031_users_role_suspended.sql +41 -0
- package/package.json +3 -3
- package/scripts/build/registry/__tests__/build-output.test.mjs +1 -1
- package/scripts/build/registry/__tests__/project-mode-root-first.test.mjs +6 -6
- package/scripts/build/registry/__tests__/write-places.test.mjs +1 -1
- package/scripts/build/registry/contracts/__tests__/contracts-wire.test.mjs +1 -1
- package/scripts/build/registry/contracts/__tests__/contracts.test.mjs +1 -1
- package/scripts/build/registry/host/README.md +2 -2
- package/scripts/build/registry/host/__tests__/facade-emitter.test.mjs +14 -13
- package/scripts/build/registry/host/__tests__/host-mode.test.mjs +1 -1
- package/scripts/build/registry/host/__tests__/host-project-composition.test.mjs +1 -1
- package/scripts/build/registry/host/__tests__/host-project.test.mjs +2 -2
- package/scripts/build/registry/host/__tests__/host-proxy-areas.test.mjs +29 -2
- package/scripts/build/registry/host/__tests__/host-robustness.test.mjs +1 -1
- package/scripts/build/registry/host/facade-emitter.mjs +1 -1
- package/scripts/build/registry/host/next-route-exports.json +2 -2
- package/scripts/build/registry/host/proxy-areas.mjs +29 -2
- package/scripts/db/verify-theme-migrations.mjs +1 -1
- package/templates/next.config.mjs +11 -31
- package/templates/projects/blog/package.json +1 -1
- package/templates/projects/crm/package.json +1 -1
- package/templates/projects/productivity/package.json +1 -1
- package/templates/projects/starter/config/app.config.ts +8 -0
- package/templates/proxy.ts +6 -3
- package/tests/jest/__mocks__/@nextsparkjs/registries/permissions-registry.ts +5 -4
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Pool, type PoolConfig } from 'pg';
|
|
2
|
+
/**
|
|
3
|
+
* The one place core's runtime pg pools get their resilience options, so the app pool, the service pool and the
|
|
4
|
+
* Better Auth pool cannot drift. Idle connections on Neon, Supabase poolers and behind NAT/load balancers are dropped
|
|
5
|
+
* silently; without these options the next query waits for the OS TCP timeout (minutes) on a dead socket, and the
|
|
6
|
+
* socket error on an idle client surfaces as an `uncaughtException`.
|
|
7
|
+
*/
|
|
8
|
+
/** Far below the idle cutoffs seen in practice (Azure LB 4 min, AWS NLB 350 s, NAT tables 60 s and up): an idle client is closed by us long before a provider drops it, at the cost of an occasional reconnect. */
|
|
9
|
+
export declare const POOL_IDLE_TIMEOUT_MS = 10000;
|
|
10
|
+
export declare const POOL_CONNECTION_TIMEOUT_MS = 10000;
|
|
11
|
+
/** First TCP keep-alive probe 10 s after the socket goes quiet; how soon a dead peer is detected after that depends on the OS. */
|
|
12
|
+
export declare const POOL_KEEP_ALIVE_DELAY_MS = 10000;
|
|
13
|
+
/** Default for DB_QUERY_TIMEOUT_MS: long enough for a heavy report, short of the minutes a dead socket takes to fail. */
|
|
14
|
+
export declare const DEFAULT_QUERY_TIMEOUT_MS = 60000;
|
|
15
|
+
/**
|
|
16
|
+
* A timeout in milliseconds from the environment. Unset or empty gives `fallback`; `0` gives `undefined` (no limit);
|
|
17
|
+
* anything that is not a non-negative integer warns once and gives `fallback`.
|
|
18
|
+
*/
|
|
19
|
+
export declare function parseTimeoutMs(name: string, raw: string | undefined, fallback: number | undefined): number | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* DB_QUERY_TIMEOUT_MS (default 60000): the client gives up on a query that has no answer after this long. It works on
|
|
22
|
+
* every provider, pooled or not, and is what fails a query on a dead socket. 0 disables it.
|
|
23
|
+
* DB_STATEMENT_TIMEOUT_MS (default unset): also asks the server to cancel a statement after this long. Opt-in because
|
|
24
|
+
* the limit travels as a connection startup parameter, which some transaction poolers (PgBouncer) reject.
|
|
25
|
+
*/
|
|
26
|
+
export declare function poolTimeouts(env?: NodeJS.ProcessEnv): Pick<PoolConfig, 'query_timeout' | 'statement_timeout'>;
|
|
27
|
+
/** What is safe to log about a pool error: its code or class, never the message (it can carry hosts, users or databases). */
|
|
28
|
+
export declare function describePoolError(err: unknown): string;
|
|
29
|
+
/** A Pool with core's keep-alive, timeouts and error handling on top of `config`; `label` says which pool in the log. */
|
|
30
|
+
export declare function createPool(label: string, config: PoolConfig): Pool;
|
|
31
|
+
//# sourceMappingURL=db-pool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db-pool.d.ts","sourceRoot":"","sources":["../../src/lib/db-pool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAmB,KAAK,UAAU,EAAE,MAAM,IAAI,CAAC;AAE5D;;;;;GAKG;AAEH,mNAAmN;AACnN,eAAO,MAAM,oBAAoB,QAAS,CAAC;AAC3C,eAAO,MAAM,0BAA0B,QAAS,CAAC;AACjD,kIAAkI;AAClI,eAAO,MAAM,wBAAwB,QAAS,CAAC;AAC/C,yHAAyH;AACzH,eAAO,MAAM,wBAAwB,QAAS,CAAC;AAE/C;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAQtH;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,IAAI,CAAC,UAAU,EAAE,eAAe,GAAG,mBAAmB,CAAC,CAK1H;AAED,6HAA6H;AAC7H,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAGtD;AA8BD,yHAAyH;AACzH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAmBlE"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Pool } from "pg";
|
|
2
|
+
const POOL_IDLE_TIMEOUT_MS = 1e4;
|
|
3
|
+
const POOL_CONNECTION_TIMEOUT_MS = 1e4;
|
|
4
|
+
const POOL_KEEP_ALIVE_DELAY_MS = 1e4;
|
|
5
|
+
const DEFAULT_QUERY_TIMEOUT_MS = 6e4;
|
|
6
|
+
function parseTimeoutMs(name, raw, fallback) {
|
|
7
|
+
if (raw === void 0 || raw.trim() === "") return fallback;
|
|
8
|
+
const value = Number(raw);
|
|
9
|
+
if (!Number.isInteger(value) || value < 0) {
|
|
10
|
+
console.warn(`[DB] Ignoring ${name}="${raw}": expected a non-negative integer of milliseconds (0 disables).`);
|
|
11
|
+
return fallback;
|
|
12
|
+
}
|
|
13
|
+
return value === 0 ? void 0 : value;
|
|
14
|
+
}
|
|
15
|
+
function poolTimeouts(env = process.env) {
|
|
16
|
+
return {
|
|
17
|
+
query_timeout: parseTimeoutMs("DB_QUERY_TIMEOUT_MS", env.DB_QUERY_TIMEOUT_MS, DEFAULT_QUERY_TIMEOUT_MS),
|
|
18
|
+
statement_timeout: parseTimeoutMs("DB_STATEMENT_TIMEOUT_MS", env.DB_STATEMENT_TIMEOUT_MS, void 0)
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function describePoolError(err) {
|
|
22
|
+
const e = err;
|
|
23
|
+
return String((e == null ? void 0 : e.code) ?? (e == null ? void 0 : e.name) ?? "unknown");
|
|
24
|
+
}
|
|
25
|
+
const QUERY_TIMEOUT_MESSAGE = "Query read timeout";
|
|
26
|
+
function dropOnQueryTimeout(client) {
|
|
27
|
+
const query = client.query.bind(client);
|
|
28
|
+
const drop = (err) => {
|
|
29
|
+
var _a, _b;
|
|
30
|
+
if ((err == null ? void 0 : err.message) === QUERY_TIMEOUT_MESSAGE) {
|
|
31
|
+
client._queryable = false;
|
|
32
|
+
(_b = (_a = client.connection) == null ? void 0 : _a.stream) == null ? void 0 : _b.destroy();
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
client.query = (...args) => {
|
|
36
|
+
const last = args[args.length - 1];
|
|
37
|
+
if (typeof last === "function") {
|
|
38
|
+
args[args.length - 1] = (err, ...rest) => {
|
|
39
|
+
drop(err);
|
|
40
|
+
last(err, ...rest);
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const result = query(...args);
|
|
44
|
+
if (typeof (result == null ? void 0 : result.catch) === "function") result.catch(drop);
|
|
45
|
+
return result;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function createPool(label, config) {
|
|
49
|
+
const pool = new Pool({
|
|
50
|
+
max: 20,
|
|
51
|
+
idleTimeoutMillis: POOL_IDLE_TIMEOUT_MS,
|
|
52
|
+
connectionTimeoutMillis: POOL_CONNECTION_TIMEOUT_MS,
|
|
53
|
+
keepAlive: true,
|
|
54
|
+
keepAliveInitialDelayMillis: POOL_KEEP_ALIVE_DELAY_MS,
|
|
55
|
+
...poolTimeouts(),
|
|
56
|
+
...config
|
|
57
|
+
});
|
|
58
|
+
pool.on("connect", (client) => {
|
|
59
|
+
dropOnQueryTimeout(client);
|
|
60
|
+
client.on("error", (err) => console.warn(`[DB] ${label} pool: client error (${describePoolError(err)}); connection dropped.`));
|
|
61
|
+
});
|
|
62
|
+
pool.on("error", () => {
|
|
63
|
+
});
|
|
64
|
+
return pool;
|
|
65
|
+
}
|
|
66
|
+
export {
|
|
67
|
+
DEFAULT_QUERY_TIMEOUT_MS,
|
|
68
|
+
POOL_CONNECTION_TIMEOUT_MS,
|
|
69
|
+
POOL_IDLE_TIMEOUT_MS,
|
|
70
|
+
POOL_KEEP_ALIVE_DELAY_MS,
|
|
71
|
+
createPool,
|
|
72
|
+
describePoolError,
|
|
73
|
+
parseTimeoutMs,
|
|
74
|
+
poolTimeouts
|
|
75
|
+
};
|
package/dist/lib/db.d.ts
CHANGED
package/dist/lib/db.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/lib/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/lib/db.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/db.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createPool } from "./db-pool.js";
|
|
2
2
|
import { isValidUUID } from "./utils/uuid.js";
|
|
3
3
|
let activeConnections = 0;
|
|
4
4
|
let isShuttingDown = false;
|
|
@@ -57,20 +57,14 @@ function parseSSLConfig(databaseUrl2) {
|
|
|
57
57
|
}
|
|
58
58
|
const databaseUrl = process.env.DATABASE_URL || "";
|
|
59
59
|
const sslConfig = parseSSLConfig(databaseUrl);
|
|
60
|
-
const pool =
|
|
60
|
+
const pool = createPool("app", {
|
|
61
61
|
connectionString: stripSSLParams(databaseUrl),
|
|
62
|
-
ssl: sslConfig
|
|
63
|
-
max: 20,
|
|
64
|
-
idleTimeoutMillis: 3e4,
|
|
65
|
-
connectionTimeoutMillis: 1e4
|
|
62
|
+
ssl: sslConfig
|
|
66
63
|
});
|
|
67
64
|
const serviceDatabaseUrl = process.env.DATABASE_SERVICE_URL || databaseUrl;
|
|
68
|
-
const servicePool = serviceDatabaseUrl === databaseUrl ? pool :
|
|
65
|
+
const servicePool = serviceDatabaseUrl === databaseUrl ? pool : createPool("service", {
|
|
69
66
|
connectionString: stripSSLParams(serviceDatabaseUrl),
|
|
70
|
-
ssl: parseSSLConfig(serviceDatabaseUrl)
|
|
71
|
-
max: 20,
|
|
72
|
-
idleTimeoutMillis: 3e4,
|
|
73
|
-
connectionTimeoutMillis: 1e4
|
|
67
|
+
ssl: parseSSLConfig(serviceDatabaseUrl)
|
|
74
68
|
});
|
|
75
69
|
function validateUserId(userId) {
|
|
76
70
|
const isProduction = process.env.NODE_ENV === "production";
|
|
@@ -115,7 +109,8 @@ async function queryWithRLS(query2, params = [], userId, options) {
|
|
|
115
109
|
await client.query("COMMIT");
|
|
116
110
|
return result.rows;
|
|
117
111
|
} catch (error) {
|
|
118
|
-
await client.query("ROLLBACK")
|
|
112
|
+
await client.query("ROLLBACK").catch(() => {
|
|
113
|
+
});
|
|
119
114
|
throw error;
|
|
120
115
|
} finally {
|
|
121
116
|
releaseClient(client);
|
|
@@ -141,7 +136,8 @@ async function mutateWithRLS(query2, params = [], userId, options) {
|
|
|
141
136
|
rowCount: result.rowCount || 0
|
|
142
137
|
};
|
|
143
138
|
} catch (error) {
|
|
144
|
-
await client.query("ROLLBACK")
|
|
139
|
+
await client.query("ROLLBACK").catch(() => {
|
|
140
|
+
});
|
|
145
141
|
throw error;
|
|
146
142
|
} finally {
|
|
147
143
|
releaseClient(client);
|
|
@@ -169,7 +165,8 @@ async function getTransactionClient(userId, options) {
|
|
|
169
165
|
releaseClient(client);
|
|
170
166
|
},
|
|
171
167
|
rollback: async () => {
|
|
172
|
-
await client.query("ROLLBACK")
|
|
168
|
+
await client.query("ROLLBACK").catch(() => {
|
|
169
|
+
});
|
|
173
170
|
releaseClient(client);
|
|
174
171
|
}
|
|
175
172
|
};
|
|
@@ -2,7 +2,7 @@ import { NextResponse } from "next/server";
|
|
|
2
2
|
import * as z from "zod";
|
|
3
3
|
import { getEntityConfig } from "./registry.js";
|
|
4
4
|
import { executeEntityHooks } from "./hooks.js";
|
|
5
|
-
import {
|
|
5
|
+
import { getAuthorizationSession } from "../auth/authorization-session.js";
|
|
6
6
|
function generateEntityAPI(entityName, options = {}) {
|
|
7
7
|
const entityConfig = getEntityConfig(entityName);
|
|
8
8
|
if (!entityConfig) {
|
|
@@ -27,7 +27,7 @@ function createGETHandler(entityConfig, options) {
|
|
|
27
27
|
try {
|
|
28
28
|
let user = null;
|
|
29
29
|
if (options.enableAuth) {
|
|
30
|
-
const session = await
|
|
30
|
+
const session = await getAuthorizationSession(request.headers);
|
|
31
31
|
if (!session) {
|
|
32
32
|
return NextResponse.json({ error: "Authentication required" }, { status: 401 });
|
|
33
33
|
}
|
|
@@ -78,7 +78,7 @@ function createPOSTHandler(entityConfig, options) {
|
|
|
78
78
|
try {
|
|
79
79
|
let user = null;
|
|
80
80
|
if (options.enableAuth) {
|
|
81
|
-
const session = await
|
|
81
|
+
const session = await getAuthorizationSession(request.headers);
|
|
82
82
|
if (!session) {
|
|
83
83
|
return NextResponse.json({ error: "Authentication required" }, { status: 401 });
|
|
84
84
|
}
|
|
@@ -126,7 +126,7 @@ function createPATCHHandler(entityConfig, options) {
|
|
|
126
126
|
try {
|
|
127
127
|
let user = null;
|
|
128
128
|
if (options.enableAuth) {
|
|
129
|
-
const session = await
|
|
129
|
+
const session = await getAuthorizationSession(request.headers);
|
|
130
130
|
if (!session) {
|
|
131
131
|
return NextResponse.json({ error: "Authentication required" }, { status: 401 });
|
|
132
132
|
}
|
|
@@ -205,7 +205,7 @@ function createDELETEHandler(entityConfig, options) {
|
|
|
205
205
|
try {
|
|
206
206
|
let user = null;
|
|
207
207
|
if (options.enableAuth) {
|
|
208
|
-
const session = await
|
|
208
|
+
const session = await getAuthorizationSession(request.headers);
|
|
209
209
|
if (!session) {
|
|
210
210
|
return NextResponse.json({ error: "Authentication required" }, { status: 401 });
|
|
211
211
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-refresh.d.ts","sourceRoot":"","sources":["../../../src/lib/oauth/token-refresh.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,OAAO,EACL,aAAa,EAEb,kBAAkB,EAKnB,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"token-refresh.d.ts","sourceRoot":"","sources":["../../../src/lib/oauth/token-refresh.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,OAAO,EACL,aAAa,EAEb,kBAAkB,EAKnB,MAAM,SAAS,CAAC;AAoCjB;;GAEG;AACH,qBAAa,mBAAmB;IAC9B;;;;;OAKG;IACH,MAAM,CAAC,YAAY,CAAC,SAAS,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO;IAahE;;;;;;;;OAQG;WACU,YAAY,CACvB,QAAQ,EAAE,aAAa,EACvB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,kBAAkB,CAAC;IAoC9B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,kBAAkB;IA2BjC;;;;;OAKG;WACU,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAkHtE;;;;;OAKG;WACU,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA+B/D;;;;OAIG;WACU,uBAAuB,IAAI,OAAO,CAAC,MAAM,CAAC;IAqCvD;;OAEG;mBACkB,iBAAiB;IAetC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,WAAW;IAa1B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,eAAe;IAa9B;;;;;OAKG;WACU,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAmC/D;;OAEG;mBACkB,uBAAuB;CAuB7C"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createPool } from "../db-pool.js";
|
|
2
2
|
import { parseSSLConfig } from "../db.js";
|
|
3
3
|
import { TokenEncryption } from "./encryption.js";
|
|
4
4
|
import {
|
|
@@ -20,12 +20,9 @@ const REFRESH_CONFIG = {
|
|
|
20
20
|
};
|
|
21
21
|
const databaseUrl = process.env.DATABASE_URL;
|
|
22
22
|
const connectionString = databaseUrl.includes("?") ? `${databaseUrl}&pgbouncer=true` : `${databaseUrl}?pgbouncer=true`;
|
|
23
|
-
const pool =
|
|
23
|
+
const pool = createPool("oauth-token-refresh", {
|
|
24
24
|
connectionString,
|
|
25
|
-
ssl: parseSSLConfig(databaseUrl)
|
|
26
|
-
connectionTimeoutMillis: 1e4,
|
|
27
|
-
idleTimeoutMillis: 3e4,
|
|
28
|
-
max: 20
|
|
25
|
+
ssl: parseSSLConfig(databaseUrl)
|
|
29
26
|
});
|
|
30
27
|
class TokenRefreshService {
|
|
31
28
|
/**
|
|
@@ -79,4 +79,13 @@ export declare function getUserPermissions(userId: string, teamId: string): Prom
|
|
|
79
79
|
* ```
|
|
80
80
|
*/
|
|
81
81
|
export declare function hasPermissionSync(teamRole: TeamRole, permission: Permission): boolean;
|
|
82
|
+
/**
|
|
83
|
+
* The extra permission a write needs when it moves a record into or out of `published`: `<slug>.publish`, if the
|
|
84
|
+
* entity declares that action, else null. `next` is the status the write sets (undefined: not changed) and
|
|
85
|
+
* `current` the stored one (undefined on create). Every writer asks this: the REST handler (and the page builder
|
|
86
|
+
* through it), GenericEntityService and the server actions through it.
|
|
87
|
+
*/
|
|
88
|
+
export declare function publishPermissionFor(entitySlug: string, next: unknown, current?: unknown): Permission | null;
|
|
89
|
+
/** `<slug>.publish` when the entity declares that action, else null. */
|
|
90
|
+
export declare function declaredPublishPermission(entitySlug: string): Permission | null;
|
|
82
91
|
//# sourceMappingURL=check.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../../src/lib/permissions/check.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAuBnD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,OAAO,CAAC,CAuBlB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,UAAU,EAAE,GACxB,OAAO,CAAC,OAAO,CAAC,CAOlB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,UAAU,EAAE,GACxB,OAAO,CAAC,OAAO,CAAC,CAOlB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,UAAU,EAAE,CAAC,CAQvB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,QAAQ,EAClB,UAAU,EAAE,UAAU,GACrB,OAAO,CAET"}
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../../src/lib/permissions/check.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAuBnD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,OAAO,CAAC,CAuBlB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,UAAU,EAAE,GACxB,OAAO,CAAC,OAAO,CAAC,CAOlB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,UAAU,EAAE,GACxB,OAAO,CAAC,OAAO,CAAC,CAOlB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,UAAU,EAAE,CAAC,CAQvB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,QAAQ,EAClB,UAAU,EAAE,UAAU,GACrB,OAAO,CAET;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,IAAI,CAG5G;AAED,wEAAwE;AACxE,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAG/E"}
|
|
@@ -52,10 +52,20 @@ async function getUserPermissions(userId, teamId) {
|
|
|
52
52
|
function hasPermissionSync(teamRole, permission) {
|
|
53
53
|
return permissionRegistry.hasPermission(teamRole, permission);
|
|
54
54
|
}
|
|
55
|
+
function publishPermissionFor(entitySlug, next, current) {
|
|
56
|
+
if (next === void 0 || next === "published" === (current === "published")) return null;
|
|
57
|
+
return declaredPublishPermission(entitySlug);
|
|
58
|
+
}
|
|
59
|
+
function declaredPublishPermission(entitySlug) {
|
|
60
|
+
const permission = `${entitySlug}.publish`;
|
|
61
|
+
return permissionRegistry.isValidPermission(permission) ? permission : null;
|
|
62
|
+
}
|
|
55
63
|
export {
|
|
56
64
|
checkAnyPermission,
|
|
57
65
|
checkPermission,
|
|
58
66
|
checkPermissions,
|
|
67
|
+
declaredPublishPermission,
|
|
59
68
|
getUserPermissions,
|
|
60
|
-
hasPermissionSync
|
|
69
|
+
hasPermissionSync,
|
|
70
|
+
publishPermissionFor
|
|
61
71
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generic-entity.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/generic-entity.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAaH,OAAO,KAAK,EAAE,YAAY,EAAe,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"generic-entity.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/generic-entity.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { queryWithRLS, queryOneWithRLS, mutateWithRLS } from "../db.js";
|
|
1
|
+
import { queryWithRLS, queryOneWithRLS, mutateWithRLS, getTransactionClient } from "../db.js";
|
|
2
2
|
import { entityRegistry } from "../entities/registry.js";
|
|
3
3
|
import { expirePublicEntity } from "../cache/public-entity-cache.js";
|
|
4
4
|
import {
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
beforeEntityDelete,
|
|
10
10
|
afterEntityDelete
|
|
11
11
|
} from "../entities/entity-hooks.js";
|
|
12
|
+
import { checkPermission, declaredPublishPermission, publishPermissionFor } from "../permissions/check.js";
|
|
12
13
|
const SYSTEM_FIELDS = ["id", "userId", "teamId", "createdAt", "updatedAt"];
|
|
13
14
|
const DEFAULT_LIMIT = 20;
|
|
14
15
|
const DEFAULT_ORDER_BY = "createdAt";
|
|
@@ -296,6 +297,7 @@ class GenericEntityService {
|
|
|
296
297
|
* @returns Created entity
|
|
297
298
|
*/
|
|
298
299
|
static async create(entitySlug, userId, teamId, data) {
|
|
300
|
+
var _a;
|
|
299
301
|
if (!(userId == null ? void 0 : userId.trim())) {
|
|
300
302
|
throw new Error("User ID is required");
|
|
301
303
|
}
|
|
@@ -311,6 +313,13 @@ class GenericEntityService {
|
|
|
311
313
|
if (!validation.valid) {
|
|
312
314
|
throw new Error(`Validation failed: ${validation.errors.join(", ")}`);
|
|
313
315
|
}
|
|
316
|
+
const statusField = entityConfig.fields.find((f) => f.name === "status");
|
|
317
|
+
const createStatus = finalData.status ?? (statusField == null ? void 0 : statusField.defaultValue);
|
|
318
|
+
const publish = publishPermissionFor(entitySlug, createStatus);
|
|
319
|
+
if (publish && !await checkPermission(userId, teamId, publish)) {
|
|
320
|
+
throw new Error("Permission denied");
|
|
321
|
+
}
|
|
322
|
+
const storedPublish = createStatus === void 0 && statusField ? declaredPublishPermission(entitySlug) : null;
|
|
314
323
|
const tableName = getTableName(entityConfig);
|
|
315
324
|
const fieldNames = getFieldNames(entityConfig);
|
|
316
325
|
const selectClause = buildSelectClause(fieldNames);
|
|
@@ -327,13 +336,27 @@ class GenericEntityService {
|
|
|
327
336
|
}
|
|
328
337
|
}
|
|
329
338
|
const quotedFields = fields.map((f) => quoteField(f)).join(", ");
|
|
330
|
-
const
|
|
331
|
-
`INSERT INTO ${tableName} (${quotedFields})
|
|
339
|
+
const insertQuery = `INSERT INTO ${tableName} (${quotedFields})
|
|
332
340
|
VALUES (${placeholders.join(", ")})
|
|
333
|
-
RETURNING ${selectClause}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
341
|
+
RETURNING ${selectClause}`;
|
|
342
|
+
let result;
|
|
343
|
+
if (storedPublish) {
|
|
344
|
+
const tx = await getTransactionClient(userId);
|
|
345
|
+
let denied = false;
|
|
346
|
+
try {
|
|
347
|
+
result = await tx.mutate(insertQuery, values);
|
|
348
|
+
denied = ((_a = result.rows[0]) == null ? void 0 : _a.status) === "published" && !await checkPermission(userId, teamId, storedPublish);
|
|
349
|
+
if (denied) await tx.rollback();
|
|
350
|
+
else await tx.commit();
|
|
351
|
+
} catch (error) {
|
|
352
|
+
await tx.rollback().catch(() => {
|
|
353
|
+
});
|
|
354
|
+
throw error;
|
|
355
|
+
}
|
|
356
|
+
if (denied) throw new Error("Permission denied");
|
|
357
|
+
} else {
|
|
358
|
+
result = await mutateWithRLS(insertQuery, values, userId);
|
|
359
|
+
}
|
|
337
360
|
if (!result.rows[0]) {
|
|
338
361
|
throw new Error("Failed to create entity");
|
|
339
362
|
}
|
|
@@ -382,6 +405,10 @@ class GenericEntityService {
|
|
|
382
405
|
if (!validation.valid) {
|
|
383
406
|
throw new Error(`Validation failed: ${validation.errors.join(", ")}`);
|
|
384
407
|
}
|
|
408
|
+
const publish = "status" in finalData ? publishPermissionFor(entitySlug, finalData.status, currentEntity.status) : null;
|
|
409
|
+
if (publish && !await checkPermission(userId, teamId ?? currentEntity.teamId, publish)) {
|
|
410
|
+
throw new Error("Permission denied");
|
|
411
|
+
}
|
|
385
412
|
const setClauses = [];
|
|
386
413
|
const values = [];
|
|
387
414
|
let paramIndex = 1;
|
|
@@ -403,6 +430,11 @@ class GenericEntityService {
|
|
|
403
430
|
if (teamId) {
|
|
404
431
|
values.push(teamId);
|
|
405
432
|
updateWhereClause += ` AND "teamId" = $${paramIndex}`;
|
|
433
|
+
paramIndex++;
|
|
434
|
+
}
|
|
435
|
+
if ("status" in finalData && declaredPublishPermission(entitySlug)) {
|
|
436
|
+
values.push(currentEntity.status);
|
|
437
|
+
updateWhereClause += ` AND "status" IS NOT DISTINCT FROM $${paramIndex}`;
|
|
406
438
|
}
|
|
407
439
|
const result = await mutateWithRLS(
|
|
408
440
|
`UPDATE ${tableName}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transactional-meta.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/transactional-meta.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAGH,OAAO,EAAuB,UAAU,EAAE,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"transactional-meta.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/transactional-meta.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAGH,OAAO,EAAuB,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAUxE;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IAEpB;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAA;IAEzB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B;AAED;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;IAGlC,IAAI,CAAC,EAAE,MAAM;IACb,aAAa,CAAC,EAAE,KAAK;gBAF5B,OAAO,EAAE,MAAM,EACR,IAAI,CAAC,EAAE,MAAM,EACb,aAAa,CAAC,EAAE,KAAK;CAK/B;AAED;;GAEG;AACH,qBAAa,wBAAwB;IACnC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAKtC;IAED;;;;;;;;;;;;;;;OAeG;WACU,cAAc,CAAC,CAAC,GAAG,OAAO,EACrC,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI,KAAK,CAAC,EAClC,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,CAAC,CAAC;IAoIb;;;;;;;;;OASG;WACU,kBAAkB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/D,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,EACtD,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,CAAC,CAAC;IAkBb;;;;;;;;OAQG;WACU,cAAc,CACzB,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,OAAO,CAAC;CA0CpB"}
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createPool } from "../db-pool.js";
|
|
2
2
|
import { getEntityMetaConfig } from "../../types/meta.types.js";
|
|
3
3
|
import { parseSSLConfig } from "../db.js";
|
|
4
4
|
const databaseUrl = process.env.DATABASE_URL;
|
|
5
|
-
const pool =
|
|
5
|
+
const pool = createPool("transactional-meta", {
|
|
6
6
|
connectionString: databaseUrl,
|
|
7
|
-
ssl: parseSSLConfig(databaseUrl)
|
|
8
|
-
max: 20,
|
|
9
|
-
idleTimeoutMillis: 3e4,
|
|
10
|
-
connectionTimeoutMillis: 1e4
|
|
7
|
+
ssl: parseSSLConfig(databaseUrl)
|
|
11
8
|
});
|
|
12
9
|
class TransactionalError extends Error {
|
|
13
10
|
constructor(message, code, originalError) {
|
|
@@ -99,7 +96,8 @@ class TransactionalMetaService {
|
|
|
99
96
|
client.release();
|
|
100
97
|
return upsertResult.rows[0].metaValue;
|
|
101
98
|
} catch (error) {
|
|
102
|
-
await client.query("ROLLBACK")
|
|
99
|
+
await client.query("ROLLBACK").catch(() => {
|
|
100
|
+
});
|
|
103
101
|
client.release();
|
|
104
102
|
const pgError = error;
|
|
105
103
|
lastError = pgError;
|
|
@@ -185,7 +183,8 @@ class TransactionalMetaService {
|
|
|
185
183
|
client.release();
|
|
186
184
|
return (result.rowCount || 0) > 0;
|
|
187
185
|
} catch (error) {
|
|
188
|
-
await client.query("ROLLBACK")
|
|
186
|
+
await client.query("ROLLBACK").catch(() => {
|
|
187
|
+
});
|
|
189
188
|
client.release();
|
|
190
189
|
const pgError = error;
|
|
191
190
|
throw new TransactionalError(
|
package/dist/lib/validation.d.ts
CHANGED
|
@@ -9,6 +9,11 @@ export declare const baseSignupSchema: z.ZodObject<{
|
|
|
9
9
|
email: z.ZodString;
|
|
10
10
|
password: z.ZodString;
|
|
11
11
|
}, z.core.$strip>;
|
|
12
|
+
export declare const inviteSignupSchema: z.ZodObject<{
|
|
13
|
+
email: z.ZodString;
|
|
14
|
+
firstName: z.ZodString;
|
|
15
|
+
lastName: z.ZodString;
|
|
16
|
+
}, z.core.$strip>;
|
|
12
17
|
export declare const signupSchema: z.ZodObject<{
|
|
13
18
|
firstName: z.ZodString;
|
|
14
19
|
lastName: z.ZodString;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/lib/validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAEzB,eAAO,MAAM,WAAW;;;iBAGtB,CAAC;AAGH,eAAO,MAAM,gBAAgB;;;;;iBAU3B,CAAC;AAGH,eAAO,MAAM,YAAY;;;;;;iBAKvB,CAAC;AAEH,eAAO,MAAM,mBAAmB;;iBAE9B,CAAC;AAEH,eAAO,MAAM,iBAAiB;;;iBAW5B,CAAC;AAEH,eAAO,MAAM,oBAAoB;;;;;iBAgB/B,CAAC;AAEH,eAAO,MAAM,aAAa;;;;;;iBAMxB,CAAC;AAGH,eAAO,MAAM,oBAAoB;;;;;;iBAQ/B,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AACxD,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAC1D,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AACxE,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AACpE,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAC1E,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/lib/validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAEzB,eAAO,MAAM,WAAW;;;iBAGtB,CAAC;AAGH,eAAO,MAAM,gBAAgB;;;;;iBAU3B,CAAC;AAGH,eAAO,MAAM,kBAAkB;;;;iBAA4C,CAAC;AAG5E,eAAO,MAAM,YAAY;;;;;;iBAKvB,CAAC;AAEH,eAAO,MAAM,mBAAmB;;iBAE9B,CAAC;AAEH,eAAO,MAAM,iBAAiB;;;iBAW5B,CAAC;AAEH,eAAO,MAAM,oBAAoB;;;;;iBAgB/B,CAAC;AAEH,eAAO,MAAM,aAAa;;;;;;iBAMxB,CAAC;AAGH,eAAO,MAAM,oBAAoB;;;;;;iBAQ/B,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AACxD,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAC1D,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AACxE,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AACpE,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAC1E,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC"}
|
package/dist/lib/validation.js
CHANGED
|
@@ -9,6 +9,7 @@ const baseSignupSchema = z.object({
|
|
|
9
9
|
email: z.string().email("Invalid email"),
|
|
10
10
|
password: z.string().min(8, "Password must be at least 8 characters").regex(/[A-Z]/, "Must contain at least one uppercase letter").regex(/[a-z]/, "Must contain at least one lowercase letter").regex(/[0-9]/, "Must contain at least one number")
|
|
11
11
|
});
|
|
12
|
+
const inviteSignupSchema = baseSignupSchema.omit({ password: true });
|
|
12
13
|
const signupSchema = baseSignupSchema.extend({
|
|
13
14
|
confirmPassword: z.string()
|
|
14
15
|
}).refine((data) => data.password === data.confirmPassword, {
|
|
@@ -56,6 +57,7 @@ const partialProfileSchema = z.object({
|
|
|
56
57
|
export {
|
|
57
58
|
baseSignupSchema,
|
|
58
59
|
changePasswordSchema,
|
|
60
|
+
inviteSignupSchema,
|
|
59
61
|
loginSchema,
|
|
60
62
|
newPasswordSchema,
|
|
61
63
|
partialProfileSchema,
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
-- Migration: 030_taxonomies_team_writes.sql
|
|
2
|
+
-- Description: Taxonomy rows are written by members of their team; rows without a team only by a superadmin.
|
|
3
|
+
--
|
|
4
|
+
-- 021 let any authenticated user write a taxonomy row with "teamId" IS NULL. Post categories are now created in
|
|
5
|
+
-- the caller's team (lib/api/post-categories.ts), and the rows without a team that earlier releases created stay
|
|
6
|
+
-- readable by everyone but are changed only by a superadmin. This policy says the same on the RLS-enforced
|
|
7
|
+
-- connection: reads are as before, writes need the row's team (or is_superadmin()).
|
|
8
|
+
-- is_superadmin() also accepts a developer enrolled in the System Admin Team; the API (lib/api/post-categories.ts) is
|
|
9
|
+
-- stricter and lets only users.role = 'superadmin' change a row without a team.
|
|
10
|
+
-- Idempotent; the anon read policy from 006 is unchanged.
|
|
11
|
+
|
|
12
|
+
DROP POLICY IF EXISTS "taxonomies auth can do all" ON public.taxonomies;
|
|
13
|
+
DROP POLICY IF EXISTS "taxonomies auth can select" ON public.taxonomies;
|
|
14
|
+
DROP POLICY IF EXISTS "taxonomies team can write" ON public.taxonomies;
|
|
15
|
+
|
|
16
|
+
CREATE POLICY "taxonomies auth can select"
|
|
17
|
+
ON public.taxonomies
|
|
18
|
+
FOR SELECT TO authenticated
|
|
19
|
+
USING (
|
|
20
|
+
"teamId" IS NULL
|
|
21
|
+
OR "teamId" = ANY(public.get_user_team_ids())
|
|
22
|
+
OR public.is_superadmin()
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
CREATE POLICY "taxonomies team can write"
|
|
26
|
+
ON public.taxonomies
|
|
27
|
+
FOR ALL TO authenticated
|
|
28
|
+
USING ("teamId" = ANY(public.get_user_team_ids()) OR public.is_superadmin())
|
|
29
|
+
WITH CHECK ("teamId" = ANY(public.get_user_team_ids()) OR public.is_superadmin());
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
-- Migration: 031_users_role_suspended.sql
|
|
2
|
+
-- Description: users.role accepts 'suspended' (lib/auth/suspension.ts).
|
|
3
|
+
--
|
|
4
|
+
-- The superadmin "suspend" action sets users.role = 'suspended', which check_users_role (002: member, superadmin,
|
|
5
|
+
-- developer) refused. This adds 'suspended' to the roles the constraint already accepts and keeps every other one,
|
|
6
|
+
-- including roles a project added to it. Idempotent: a constraint that already accepts 'suspended' is left alone. A
|
|
7
|
+
-- constraint that is not a plain list of roles is left alone too, with a notice (add 'suspended' to it yourself).
|
|
8
|
+
|
|
9
|
+
DO $$
|
|
10
|
+
DECLARE
|
|
11
|
+
def TEXT;
|
|
12
|
+
roles TEXT[];
|
|
13
|
+
BEGIN
|
|
14
|
+
SELECT pg_get_constraintdef(c.oid) INTO def
|
|
15
|
+
FROM pg_constraint c
|
|
16
|
+
WHERE c.conrelid = 'public.users'::regclass AND c.conname = 'check_users_role';
|
|
17
|
+
|
|
18
|
+
IF def IS NULL THEN
|
|
19
|
+
ALTER TABLE public."users" ADD CONSTRAINT check_users_role
|
|
20
|
+
CHECK ("role" IN ('member', 'superadmin', 'developer', 'suspended'));
|
|
21
|
+
RETURN;
|
|
22
|
+
END IF;
|
|
23
|
+
|
|
24
|
+
IF def ~ '\msuspended\M' THEN
|
|
25
|
+
RETURN;
|
|
26
|
+
END IF;
|
|
27
|
+
|
|
28
|
+
-- "role" IN (...) is stored as: CHECK ((role = ANY (ARRAY['member'::text, ...])))
|
|
29
|
+
IF def !~ '^CHECK \(\(+"?role"?\)?(::text)? = ANY \(\(?ARRAY\[' THEN
|
|
30
|
+
RAISE NOTICE 'check_users_role is not a plain list of roles (%); add ''suspended'' to it to use the suspend action', def;
|
|
31
|
+
RETURN;
|
|
32
|
+
END IF;
|
|
33
|
+
|
|
34
|
+
SELECT array_agg(m[1]) INTO roles FROM regexp_matches(def, '''([^'']+)''', 'g') AS m;
|
|
35
|
+
|
|
36
|
+
ALTER TABLE public."users" DROP CONSTRAINT check_users_role;
|
|
37
|
+
EXECUTE format(
|
|
38
|
+
'ALTER TABLE public."users" ADD CONSTRAINT check_users_role CHECK ("role" IN (%s))',
|
|
39
|
+
(SELECT string_agg(quote_literal(r), ', ') FROM unnest(array_append(roles, 'suspended')) AS r)
|
|
40
|
+
);
|
|
41
|
+
END $$;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { metadata } from './page';
|
|
2
2
|
export { metadata };
|
|
3
|
-
export default function SignupPageCc(
|
|
3
|
+
export default function SignupPageCc({ searchParams }: {
|
|
4
|
+
searchParams: Promise<Record<string, string | string[] | undefined>>;
|
|
5
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
4
6
|
//# sourceMappingURL=page.cc.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page.cc.d.ts","sourceRoot":"","sources":["../../../../src/routes/(auth)/signup/page.cc.tsx"],"names":[],"mappings":"AAUA,OAAmB,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAE7C,OAAO,EAAE,QAAQ,EAAE,CAAA;AAEnB,MAAM,CAAC,OAAO,UAAU,YAAY,
|
|
1
|
+
{"version":3,"file":"page.cc.d.ts","sourceRoot":"","sources":["../../../../src/routes/(auth)/signup/page.cc.tsx"],"names":[],"mappings":"AAUA,OAAmB,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAE7C,OAAO,EAAE,QAAQ,EAAE,CAAA;AAEnB,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,EAAE,YAAY,EAAE,EAAE;IAAE,YAAY,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC,CAAA;CAAE,2CAM9H"}
|
|
@@ -2,6 +2,6 @@ import { jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { Suspense } from "react";
|
|
3
3
|
import SignupPage, { metadata } from "./page.js";
|
|
4
4
|
export { metadata };
|
|
5
|
-
export default function SignupPageCc() {
|
|
6
|
-
return /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(SignupPage, {}) });
|
|
5
|
+
export default function SignupPageCc({ searchParams }) {
|
|
6
|
+
return /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(SignupPage, { searchParams }) });
|
|
7
7
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { Metadata } from 'next';
|
|
2
2
|
export declare const dynamic = "force-dynamic";
|
|
3
3
|
export declare const metadata: Metadata;
|
|
4
|
-
declare function SignupPage(
|
|
4
|
+
declare function SignupPage({ searchParams }: {
|
|
5
|
+
searchParams?: Promise<Record<string, string | string[] | undefined>>;
|
|
6
|
+
}): Promise<import("react/jsx-runtime").JSX.Element>;
|
|
5
7
|
export default SignupPage;
|
|
6
8
|
//# sourceMappingURL=page.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../../src/routes/(auth)/signup/page.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAA;AASpC,eAAO,MAAM,OAAO,kBAAkB,CAAA;AAOtC,eAAO,MAAM,QAAQ,EAAE,QAA0B,CAAA;AAKjD,iBAAe,UAAU,
|
|
1
|
+
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../../src/routes/(auth)/signup/page.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAA;AASpC,eAAO,MAAM,OAAO,kBAAkB,CAAA;AAOtC,eAAO,MAAM,QAAQ,EAAE,QAA0B,CAAA;AAKjD,iBAAe,UAAU,CAAC,EAAE,YAAY,EAAE,EAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC,CAAA;CAAE,oDA8BpH;AAED,eAAe,UAAU,CAAA"}
|
|
@@ -10,10 +10,11 @@ const defaultMetadata = {
|
|
|
10
10
|
description: "Create your account to start using our platform"
|
|
11
11
|
};
|
|
12
12
|
export const metadata = defaultMetadata;
|
|
13
|
-
async function SignupPage() {
|
|
14
|
-
var _a, _b;
|
|
13
|
+
async function SignupPage({ searchParams }) {
|
|
14
|
+
var _a, _b, _c;
|
|
15
15
|
const registrationMode = ((_b = (_a = AUTH_CONFIG) == null ? void 0 : _a.registration) == null ? void 0 : _b.mode) ?? "open";
|
|
16
|
-
|
|
16
|
+
const invited = typeof ((_c = await searchParams) == null ? void 0 : _c.inviteToken) === "string";
|
|
17
|
+
if (!invited && !resolveAuthMethods(AUTH_CONFIG).includes("email-password")) {
|
|
17
18
|
redirect("/login");
|
|
18
19
|
}
|
|
19
20
|
if (registrationMode === "invitation-only") {
|