@selvajs/server 1.5.0-beta.9 → 2.0.0-beta.16
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/dist/access/guards.d.ts +0 -10
- package/dist/access/guards.d.ts.map +1 -1
- package/dist/access/guards.js +23 -26
- package/dist/access/guards.js.map +1 -1
- package/dist/api/bodies.d.ts +1 -1
- package/dist/api/bodies.d.ts.map +1 -1
- package/dist/api/bodies.js +2 -1
- package/dist/api/bodies.js.map +1 -1
- package/dist/api/idempotency.d.ts +10 -3
- package/dist/api/idempotency.d.ts.map +1 -1
- package/dist/api/idempotency.js +32 -9
- package/dist/api/idempotency.js.map +1 -1
- package/dist/api/index.d.ts +2 -2
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +2 -2
- package/dist/api/index.js.map +1 -1
- package/dist/api/request.d.ts +12 -4
- package/dist/api/request.d.ts.map +1 -1
- package/dist/api/request.js +32 -5
- package/dist/api/request.js.map +1 -1
- package/dist/api/respond.d.ts.map +1 -1
- package/dist/api/respond.js +11 -7
- package/dist/api/respond.js.map +1 -1
- package/dist/api/scope.d.ts +7 -0
- package/dist/api/scope.d.ts.map +1 -1
- package/dist/api/scope.js +15 -1
- package/dist/api/scope.js.map +1 -1
- package/dist/compute/idempotency.d.ts +8 -1
- package/dist/compute/idempotency.d.ts.map +1 -1
- package/dist/compute/idempotency.js +35 -5
- package/dist/compute/idempotency.js.map +1 -1
- package/dist/compute/index.d.ts +1 -1
- package/dist/compute/index.d.ts.map +1 -1
- package/dist/compute/index.js +1 -1
- package/dist/compute/index.js.map +1 -1
- package/dist/compute/limits.d.ts +0 -7
- package/dist/compute/limits.d.ts.map +1 -1
- package/dist/compute/limits.js +0 -1
- package/dist/compute/limits.js.map +1 -1
- package/dist/compute/server-config-write.d.ts +11 -0
- package/dist/compute/server-config-write.d.ts.map +1 -1
- package/dist/compute/server-config-write.js +34 -0
- package/dist/compute/server-config-write.js.map +1 -1
- package/dist/definitions/definition-service.d.ts.map +1 -1
- package/dist/definitions/definition-service.js +3 -2
- package/dist/definitions/definition-service.js.map +1 -1
- package/dist/definitions/index.d.ts +1 -1
- package/dist/definitions/index.d.ts.map +1 -1
- package/dist/definitions/index.js +1 -1
- package/dist/definitions/index.js.map +1 -1
- package/dist/definitions/load-for-render.d.ts +9 -0
- package/dist/definitions/load-for-render.d.ts.map +1 -1
- package/dist/definitions/load-for-render.js +1 -1
- package/dist/definitions/load-for-render.js.map +1 -1
- package/dist/definitions/visibility.d.ts.map +1 -1
- package/dist/definitions/visibility.js +7 -12
- package/dist/definitions/visibility.js.map +1 -1
- package/dist/handlers/apiTokens.d.ts.map +1 -1
- package/dist/handlers/apiTokens.js +3 -1
- package/dist/handlers/apiTokens.js.map +1 -1
- package/dist/handlers/definitionVersions.d.ts.map +1 -1
- package/dist/handlers/definitionVersions.js +2 -2
- package/dist/handlers/definitionVersions.js.map +1 -1
- package/dist/handlers/definitions.d.ts.map +1 -1
- package/dist/handlers/definitions.js +27 -15
- package/dist/handlers/definitions.js.map +1 -1
- package/dist/handlers/index.d.ts +1 -1
- package/dist/handlers/index.d.ts.map +1 -1
- package/dist/handlers/index.js +1 -1
- package/dist/handlers/index.js.map +1 -1
- package/dist/handlers/invite-lookup.d.ts.map +1 -1
- package/dist/handlers/invite-lookup.js +3 -5
- package/dist/handlers/invite-lookup.js.map +1 -1
- package/dist/handlers/invites.d.ts +4 -3
- package/dist/handlers/invites.d.ts.map +1 -1
- package/dist/handlers/invites.js +17 -3
- package/dist/handlers/invites.js.map +1 -1
- package/dist/handlers/oauthConsent.d.ts +25 -13
- package/dist/handlers/oauthConsent.d.ts.map +1 -1
- package/dist/handlers/oauthConsent.js +29 -13
- package/dist/handlers/oauthConsent.js.map +1 -1
- package/dist/handlers/orgAssets.d.ts.map +1 -1
- package/dist/handlers/orgAssets.js +2 -2
- package/dist/handlers/orgAssets.js.map +1 -1
- package/dist/handlers/orgCompute.d.ts.map +1 -1
- package/dist/handlers/orgCompute.js +4 -2
- package/dist/handlers/orgCompute.js.map +1 -1
- package/dist/handlers/orgMembers.d.ts.map +1 -1
- package/dist/handlers/orgMembers.js +76 -56
- package/dist/handlers/orgMembers.js.map +1 -1
- package/dist/handlers/ownerChanges.d.ts +8 -0
- package/dist/handlers/ownerChanges.d.ts.map +1 -0
- package/dist/handlers/ownerChanges.js +19 -0
- package/dist/handlers/ownerChanges.js.map +1 -0
- package/dist/handlers/projectMembers.d.ts.map +1 -1
- package/dist/handlers/projectMembers.js +20 -15
- package/dist/handlers/projectMembers.js.map +1 -1
- package/dist/handlers/projects.d.ts.map +1 -1
- package/dist/handlers/projects.js +10 -3
- package/dist/handlers/projects.js.map +1 -1
- package/dist/http/api-token.d.ts +17 -0
- package/dist/http/api-token.d.ts.map +1 -1
- package/dist/http/api-token.js +49 -14
- package/dist/http/api-token.js.map +1 -1
- package/dist/http/bounded-ttl-cache.d.ts +17 -0
- package/dist/http/bounded-ttl-cache.d.ts.map +1 -0
- package/dist/http/bounded-ttl-cache.js +58 -0
- package/dist/http/bounded-ttl-cache.js.map +1 -0
- package/dist/http/csrf.d.ts.map +1 -1
- package/dist/http/csrf.js +4 -2
- package/dist/http/csrf.js.map +1 -1
- package/dist/http/index.d.ts +3 -1
- package/dist/http/index.d.ts.map +1 -1
- package/dist/http/index.js +3 -1
- package/dist/http/index.js.map +1 -1
- package/dist/http/redirect.d.ts.map +1 -1
- package/dist/http/redirect.js +5 -0
- package/dist/http/redirect.js.map +1 -1
- package/dist/http/session-refresher.d.ts +14 -0
- package/dist/http/session-refresher.d.ts.map +1 -0
- package/dist/http/session-refresher.js +34 -0
- package/dist/http/session-refresher.js.map +1 -0
- package/dist/notifications/smtp-provider.d.ts.map +1 -1
- package/dist/notifications/smtp-provider.js +13 -6
- package/dist/notifications/smtp-provider.js.map +1 -1
- package/dist/oauth/index.d.ts +3 -0
- package/dist/oauth/index.d.ts.map +1 -1
- package/dist/oauth/index.js +14 -8
- package/dist/oauth/index.js.map +1 -1
- package/dist/organizations/org-asset-service.d.ts +2 -2
- package/dist/organizations/org-asset-service.js +2 -2
- package/dist/organizations/user-memberships.d.ts.map +1 -1
- package/dist/organizations/user-memberships.js +3 -7
- package/dist/organizations/user-memberships.js.map +1 -1
- package/dist/projects/delete-with-blobs.d.ts +17 -0
- package/dist/projects/delete-with-blobs.d.ts.map +1 -0
- package/dist/projects/delete-with-blobs.js +36 -0
- package/dist/projects/delete-with-blobs.js.map +1 -0
- package/dist/projects/index.d.ts +1 -0
- package/dist/projects/index.d.ts.map +1 -1
- package/dist/projects/index.js +1 -0
- package/dist/projects/index.js.map +1 -1
- package/package.json +11 -10
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The server half of an OAuth consent screen: which access levels
|
|
3
|
-
*
|
|
2
|
+
* The server half of an OAuth consent screen: which access levels the user may
|
|
3
|
+
* grant, and minting the key.
|
|
4
4
|
*
|
|
5
|
-
* A key is bound to one org at mint
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* A key is bound to one org at mint, and consent mints only in the session's
|
|
6
|
+
* acting org: the token page lists and revokes keys there alone, so a key
|
|
7
|
+
* minted elsewhere would be live with no way to see or revoke it.
|
|
8
8
|
*/
|
|
9
9
|
import { type ApiRequest } from '../api/index.js';
|
|
10
10
|
import { type ConsentChoice, type OAuthScope } from '../oauth/index.js';
|
|
@@ -14,24 +14,36 @@ export interface ConsentOrg {
|
|
|
14
14
|
name: string;
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
|
-
* The orgs the signed-in user may grant a key with `scopes` in:
|
|
18
|
-
*
|
|
17
|
+
* The orgs the signed-in user may grant a key with `scopes` in: their acting
|
|
18
|
+
* org, when they may hold such a key there. At most one.
|
|
19
19
|
*/
|
|
20
20
|
export declare function consentOrgs(req: ApiRequest, scopes: readonly string[]): Promise<ConsentOrg[]>;
|
|
21
|
-
export interface
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
/** Where the widest choice, the one the page preselects, may be granted. */
|
|
21
|
+
export interface ConsentLevel {
|
|
22
|
+
choice: ConsentChoice;
|
|
23
|
+
/** Where this level may be granted. Never empty. */
|
|
25
24
|
orgs: ConsentOrg[];
|
|
26
25
|
}
|
|
26
|
+
export interface ConsentOffer {
|
|
27
|
+
/**
|
|
28
|
+
* Narrowest first. Only levels the user may hold in at least one of their
|
|
29
|
+
* orgs; each carries its own orgs, since a narrower level can reach more.
|
|
30
|
+
*/
|
|
31
|
+
levels: ConsentLevel[];
|
|
32
|
+
}
|
|
27
33
|
/**
|
|
28
34
|
* What a consent page offers for a request's scopes, and what its approval
|
|
29
35
|
* accepts. Null when the user may grant none of it anywhere.
|
|
30
36
|
*/
|
|
31
37
|
export declare function consentOffer(req: ApiRequest, scopes: readonly OAuthScope[]): Promise<ConsentOffer | null>;
|
|
32
38
|
/**
|
|
33
|
-
* Mint the key a consent grants,
|
|
34
|
-
*
|
|
39
|
+
* Mint the key a consent grants, in `orgId`. Anything but the acting org is
|
|
40
|
+
* refused here, whatever the form said.
|
|
35
41
|
*/
|
|
36
42
|
export declare function mintConsentToken(req: ApiRequest, orgId: string, input: MintApiTokenInput): Promise<MintedApiToken>;
|
|
43
|
+
/**
|
|
44
|
+
* Revoke a consent key whose code was never redeemed, so an abandoned sign-in
|
|
45
|
+
* doesn't leave a live key nobody holds. A used key is kept: its code may have
|
|
46
|
+
* been redeemed on another replica.
|
|
47
|
+
*/
|
|
48
|
+
export declare function revokeUnredeemedConsentToken(req: ApiRequest, tokenId: string): Promise<void>;
|
|
37
49
|
//# sourceMappingURL=oauthConsent.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauthConsent.d.ts","sourceRoot":"","sources":["../../src/handlers/oauthConsent.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAyC,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAGzF,OAAO,EAGN,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAGN,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,MAAM,gBAAgB,CAAC;AAExB,MAAM,WAAW,UAAU;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACb;AAeD;;;GAGG;AACH,wBAAsB,WAAW,CAChC,GAAG,EAAE,UAAU,EACf,MAAM,EAAE,SAAS,MAAM,EAAE,GACvB,OAAO,CAAC,UAAU,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"oauthConsent.d.ts","sourceRoot":"","sources":["../../src/handlers/oauthConsent.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAyC,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAGzF,OAAO,EAGN,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAGN,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,MAAM,gBAAgB,CAAC;AAExB,MAAM,WAAW,UAAU;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACb;AAeD;;;GAGG;AACH,wBAAsB,WAAW,CAChC,GAAG,EAAE,UAAU,EACf,MAAM,EAAE,SAAS,MAAM,EAAE,GACvB,OAAO,CAAC,UAAU,EAAE,CAAC,CAavB;AAED,MAAM,WAAW,YAAY;IAC5B,MAAM,EAAE,aAAa,CAAC;IACtB,oDAAoD;IACpD,IAAI,EAAE,UAAU,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC5B;;;OAGG;IACH,MAAM,EAAE,YAAY,EAAE,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAsB,YAAY,CACjC,GAAG,EAAE,UAAU,EACf,MAAM,EAAE,SAAS,UAAU,EAAE,GAC3B,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAS9B;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACrC,GAAG,EAAE,UAAU,EACf,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,iBAAiB,GACtB,OAAO,CAAC,cAAc,CAAC,CAgBzB;AAED;;;;GAIG;AACH,wBAAsB,4BAA4B,CACjD,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAOf"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The server half of an OAuth consent screen: which access levels
|
|
3
|
-
*
|
|
2
|
+
* The server half of an OAuth consent screen: which access levels the user may
|
|
3
|
+
* grant, and minting the key.
|
|
4
4
|
*
|
|
5
|
-
* A key is bound to one org at mint
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* A key is bound to one org at mint, and consent mints only in the session's
|
|
6
|
+
* acting org: the token page lists and revokes keys there alone, so a key
|
|
7
|
+
* minted elsewhere would be live with no way to see or revoke it.
|
|
8
8
|
*/
|
|
9
9
|
import { apiError, ApiErrorCode, requireCaller } from '../api/index.js';
|
|
10
10
|
import { buildRequestContext } from '../http/request-context.js';
|
|
@@ -21,12 +21,12 @@ async function contextIn(req, member) {
|
|
|
21
21
|
return { ...pinned, adapterContext: ctx.adapterContext };
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
|
-
* The orgs the signed-in user may grant a key with `scopes` in:
|
|
25
|
-
*
|
|
24
|
+
* The orgs the signed-in user may grant a key with `scopes` in: their acting
|
|
25
|
+
* org, when they may hold such a key there. At most one.
|
|
26
26
|
*/
|
|
27
27
|
export async function consentOrgs(req, scopes) {
|
|
28
28
|
const { ctx } = requireCaller(req);
|
|
29
|
-
const memberships = await listUserMemberships(req.deps.orgs, ctx.userId);
|
|
29
|
+
const memberships = (await listUserMemberships(req.deps.orgs, ctx.userId)).filter(({ org }) => org.id === ctx.actingOrgId);
|
|
30
30
|
const allowed = await Promise.all(memberships.map(async ({ member }) => mayHoldApiTokens(req.deps, await contextIn(req, member), scopes)));
|
|
31
31
|
return memberships
|
|
32
32
|
.filter((_, i) => allowed[i])
|
|
@@ -42,16 +42,17 @@ export async function consentOffer(req, scopes) {
|
|
|
42
42
|
orgs: await consentOrgs(req, apiScopesFor(choice.scopes))
|
|
43
43
|
})));
|
|
44
44
|
const offered = levels.filter((l) => l.orgs.length > 0);
|
|
45
|
-
|
|
46
|
-
return null;
|
|
47
|
-
return { choices: offered.map((l) => l.choice), orgs: offered[offered.length - 1].orgs };
|
|
45
|
+
return offered.length ? { levels: offered } : null;
|
|
48
46
|
}
|
|
49
47
|
/**
|
|
50
|
-
* Mint the key a consent grants,
|
|
51
|
-
*
|
|
48
|
+
* Mint the key a consent grants, in `orgId`. Anything but the acting org is
|
|
49
|
+
* refused here, whatever the form said.
|
|
52
50
|
*/
|
|
53
51
|
export async function mintConsentToken(req, orgId, input) {
|
|
54
52
|
const { ctx } = requireCaller(req);
|
|
53
|
+
if (orgId !== ctx.actingOrgId) {
|
|
54
|
+
apiError(403, ApiErrorCode.FORBIDDEN, 'Apps can only be connected to your current organization.');
|
|
55
|
+
}
|
|
55
56
|
// Matched against the user's own memberships, so the posted id never reaches a store query.
|
|
56
57
|
const memberships = await listUserMemberships(req.deps.orgs, ctx.userId);
|
|
57
58
|
const picked = memberships.find(({ org }) => org.id === orgId);
|
|
@@ -60,4 +61,19 @@ export async function mintConsentToken(req, orgId, input) {
|
|
|
60
61
|
}
|
|
61
62
|
return mintApiToken({ ...req, ctx: await contextIn(req, picked.member) }, input);
|
|
62
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Revoke a consent key whose code was never redeemed, so an abandoned sign-in
|
|
66
|
+
* doesn't leave a live key nobody holds. A used key is kept: its code may have
|
|
67
|
+
* been redeemed on another replica.
|
|
68
|
+
*/
|
|
69
|
+
export async function revokeUnredeemedConsentToken(req, tokenId) {
|
|
70
|
+
const store = req.deps.data.apiTokens;
|
|
71
|
+
if (!store)
|
|
72
|
+
return;
|
|
73
|
+
const { ctx } = requireCaller(req);
|
|
74
|
+
const token = await store.get(ctx, tokenId);
|
|
75
|
+
if (!token || token.revokedAt || token.lastUsedAt)
|
|
76
|
+
return;
|
|
77
|
+
await store.revoke(ctx, tokenId, 'owner');
|
|
78
|
+
}
|
|
63
79
|
//# sourceMappingURL=oauthConsent.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauthConsent.js","sourceRoot":"","sources":["../../src/handlers/oauthConsent.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAmB,MAAM,iBAAiB,CAAC;AACzF,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAC3E,OAAO,EACN,YAAY,EACZ,cAAc,EAGd,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACN,gBAAgB,EAChB,YAAY,EAGZ,MAAM,gBAAgB,CAAC;AAOxB,KAAK,UAAU,SAAS,CAAC,GAAe,EAAE,MAAiB;IAC1D,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IACzC,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;QAClB,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC,SAAS,EAAE,2CAA2C,CAAC,CAAC;IACpF,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,mBAAmB,CACvC,EAAE,IAAI,EAAE,mBAAmB,EAAE,GAAG,CAAC,mBAAmB,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,EACxF,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CACvB,CAAC;IACF,yEAAyE;IACzE,OAAO,EAAE,GAAG,MAAM,EAAE,cAAc,EAAE,GAAG,CAAC,cAAc,EAAE,CAAC;AAC1D,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAChC,GAAe,EACf,MAAyB;IAEzB,MAAM,EAAE,GAAG,EAAE,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IACnC,MAAM,WAAW,GAAG,MAAM,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"oauthConsent.js","sourceRoot":"","sources":["../../src/handlers/oauthConsent.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orgAssets.d.ts","sourceRoot":"","sources":["../../src/handlers/orgAssets.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"orgAssets.d.ts","sourceRoot":"","sources":["../../src/handlers/orgAssets.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAMN,KAAK,UAAU,EACf,MAAM,iBAAiB,CAAC;AAmBzB,eAAO,MAAM,cAAc,EAAE,UAqB5B,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,UAO5B,CAAC"}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* surface: no vector blob is ever stored or served. The allowlist below is the
|
|
8
8
|
* HTTP gate; the rasterization is the security control.
|
|
9
9
|
*/
|
|
10
|
-
import { apiError, ApiErrorCode, noContent, requireUpload } from '../api/index.js';
|
|
10
|
+
import { apiError, ApiErrorCode, noContent, readForm, requireUpload } from '../api/index.js';
|
|
11
11
|
import { OrgAssetKindSchema } from '@selvajs/platform';
|
|
12
12
|
import { requireManageOrgMembers, requireActingOrg } from '../access/index.js';
|
|
13
13
|
import { orgAssetService } from './services.js';
|
|
@@ -32,7 +32,7 @@ export const uploadOrgAsset = async (req) => {
|
|
|
32
32
|
const org = await req.deps.orgs.getOrg(ctx, orgId);
|
|
33
33
|
if (!org)
|
|
34
34
|
apiError(404, ApiErrorCode.NOT_FOUND, 'Organization not found');
|
|
35
|
-
const { file } = requireUpload(await req.request
|
|
35
|
+
const { file } = requireUpload(await readForm(req.request), 'image', {
|
|
36
36
|
maxBytes: req.deps.uploadLimits.maxImageFileSize,
|
|
37
37
|
contentTypes: {
|
|
38
38
|
allowed: ALLOWED_CONTENT_TYPES,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orgAssets.js","sourceRoot":"","sources":["../../src/handlers/orgAssets.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"orgAssets.js","sourceRoot":"","sources":["../../src/handlers/orgAssets.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACN,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,aAAa,EAEb,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC;IACrC,WAAW;IACX,YAAY;IACZ,YAAY;IACZ,WAAW;IACX,eAAe;CACf,CAAC,CAAC;AAEH,SAAS,SAAS,CAAC,MAAyB;IAC3C,MAAM,IAAI,GAAG,kBAAkB,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACvD,IAAI,CAAC,IAAI,CAAC,OAAO;QAAE,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC,SAAS,EAAE,uBAAuB,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC;IAChG,OAAO,IAAI,CAAC,IAAI,CAAC;AAClB,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAe,KAAK,EAAE,GAAG,EAAE,EAAE;IACvD,uBAAuB,CAAC,GAAG,CAAC,CAAC;IAC7B,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACnC,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,gBAAgB,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAE/D,oEAAoE;IACpE,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACnD,IAAI,CAAC,GAAG;QAAE,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC,SAAS,EAAE,wBAAwB,CAAC,CAAC;IAE1E,MAAM,EAAE,IAAI,EAAE,GAAG,aAAa,CAAC,MAAM,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE;QACpE,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,gBAAgB;QAChD,YAAY,EAAE;YACb,OAAO,EAAE,qBAAqB;YAC9B,OAAO,EAAE,2DAA2D;SACpE;QACD,KAAK,EAAE,OAAO;KACd,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IACvD,MAAM,GAAG,GAAG,MAAM,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1F,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;AAChC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAe,KAAK,EAAE,GAAG,EAAE,EAAE;IACvD,uBAAuB,CAAC,GAAG,CAAC,CAAC;IAC7B,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACnC,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,gBAAgB,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAE/D,MAAM,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IAC9D,OAAO,SAAS,EAAE,CAAC;AACpB,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orgCompute.d.ts","sourceRoot":"","sources":["../../src/handlers/orgCompute.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAWH,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"orgCompute.d.ts","sourceRoot":"","sources":["../../src/handlers/orgCompute.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAWH,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,iBAAiB,CAAC;AA2B9D,eAAO,MAAM,aAAa,EAAE,UAiC3B,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,UA4D9B,CAAC"}
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
import { apiError, ApiErrorCode, noContent, OrgComputePatchBodySchema, OrgComputeResponseSchema, parseBody, shaped } from '../api/index.js';
|
|
14
14
|
import { isOrgServer, isPlatformServer, serversVisibleTo } from '@selvajs/platform';
|
|
15
15
|
import { requireManageOrgCompute, requireActingOrg } from '../access/index.js';
|
|
16
|
-
import { evictChangedServers, validateIncomingServers, resolveApiKey, storedKeysById } from '../compute/index.js';
|
|
16
|
+
import { assertStoredKeysReadable, evictChangedServers, validateIncomingServers, resolveApiKey, storedKeysById } from '../compute/index.js';
|
|
17
17
|
function requireFlag(req) {
|
|
18
18
|
if (!req.deps.flag('ALLOW_ORG_COMPUTE_OVERRIDE')) {
|
|
19
19
|
apiError(403, ApiErrorCode.FORBIDDEN, 'Per-org compute override is disabled on this instance (ALLOW_ORG_COMPUTE_OVERRIDE).');
|
|
@@ -59,7 +59,9 @@ export const updateOrgCompute = async (req) => {
|
|
|
59
59
|
const provider = req.deps.computeServer;
|
|
60
60
|
// Every key is needed: an unchanged server keeps its stored key across the write.
|
|
61
61
|
const existing = await provider.getConfig(ctx, { includeApiKeys: true });
|
|
62
|
-
const
|
|
62
|
+
const orgServers = existing.servers.filter((s) => isOrgServer(s) && s.ownerOrgId === orgId);
|
|
63
|
+
assertStoredKeysReadable(incoming.servers, orgServers);
|
|
64
|
+
const storedKeys = storedKeysById(orgServers);
|
|
63
65
|
const next = incoming.servers.map((s) => ({
|
|
64
66
|
id: s.id,
|
|
65
67
|
scope: 'org',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orgCompute.js","sourceRoot":"","sources":["../../src/handlers/orgCompute.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"orgCompute.js","sourceRoot":"","sources":["../../src/handlers/orgCompute.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orgMembers.d.ts","sourceRoot":"","sources":["../../src/handlers/orgMembers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAUH,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"orgMembers.d.ts","sourceRoot":"","sources":["../../src/handlers/orgMembers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAUH,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,iBAAiB,CAAC;AAqG9D;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,EAAE,UA6E7B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,UA+E7B,CAAC"}
|
|
@@ -11,9 +11,10 @@
|
|
|
11
11
|
* demoting them does.
|
|
12
12
|
*/
|
|
13
13
|
import { apiError, ApiErrorCode, noContent, parseBody, requireParams, UpdateOrgMemberBodySchema } from '../api/index.js';
|
|
14
|
-
import { MEMBER_ASSIGNABLE_PERMISSIONS, ALL_ORG_PERMISSIONS, actorOf, canChangeOrgRole } from '@selvajs/platform';
|
|
14
|
+
import { MEMBER_ASSIGNABLE_PERMISSIONS, ALL_ORG_PERMISSIONS, actorOf, canChangeOrgRole, SYSTEM_CONTEXT } from '@selvajs/platform';
|
|
15
15
|
import { requireManageOrgMembers, requireActingOrg } from '../access/index.js';
|
|
16
16
|
import { revokeUserApiTokens } from './apiTokens.js';
|
|
17
|
+
import { serializeOwnerChanges } from './ownerChanges.js';
|
|
17
18
|
const ROSTER_PAGE_LIMIT = 200;
|
|
18
19
|
// Runaway guard against an adapter returning a non-advancing cursor. Matches
|
|
19
20
|
// `listAllOrgMembers`; 100 pages is 20k members, past any real org here.
|
|
@@ -68,11 +69,15 @@ async function hasAnotherOwner(req, ctx, orgId, exceptUserId) {
|
|
|
68
69
|
*
|
|
69
70
|
* MUST be called before the removal — afterwards the rows it reads are gone.
|
|
70
71
|
*/
|
|
71
|
-
async function findProjectsLosingSoleOwner(req,
|
|
72
|
+
async function findProjectsLosingSoleOwner(req, orgId, userId) {
|
|
73
|
+
// As system: RLS hides private projects from the acting admin, and those are the
|
|
74
|
+
// likeliest to lose their only owner.
|
|
72
75
|
const projects = req.deps.projects;
|
|
73
|
-
const orgProjects = await projects.listProjects(
|
|
76
|
+
const orgProjects = await projects.listProjects(SYSTEM_CONTEXT, orgId, {
|
|
77
|
+
limit: ROSTER_PAGE_LIMIT
|
|
78
|
+
});
|
|
74
79
|
const checks = await Promise.all(orgProjects.items.map(async (project) => {
|
|
75
|
-
const members = await projects.listProjectMembers(
|
|
80
|
+
const members = await projects.listProjectMembers(SYSTEM_CONTEXT, project.id, {
|
|
76
81
|
limit: ROSTER_PAGE_LIMIT
|
|
77
82
|
});
|
|
78
83
|
const owners = members.items.filter((m) => m.role === 'owner' && !m.deletedAt);
|
|
@@ -96,42 +101,54 @@ export const updateOrgMember = async (req) => {
|
|
|
96
101
|
const { ctx, orgId } = requireActingOrg(req, req.params.orgId);
|
|
97
102
|
const patch = await parseBody(req.request, UpdateOrgMemberBodySchema);
|
|
98
103
|
const orgs = req.deps.orgs;
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
if (patch.role !== undefined && patch.role !== target.role) {
|
|
109
|
-
// Gated on both the role being granted and the one being taken away —
|
|
110
|
-
// demoting an owner is an owner-only act even though `member` is not.
|
|
111
|
-
if (!canChangeOrgRole({ actorMember, role: patch.role }) ||
|
|
112
|
-
!canChangeOrgRole({ actorMember, role: target.role })) {
|
|
113
|
-
apiError(403, ApiErrorCode.FORBIDDEN, 'Only the org owner can change roles.');
|
|
104
|
+
return serializeOwnerChanges(orgId, async () => {
|
|
105
|
+
const [actorMember, target] = await Promise.all([
|
|
106
|
+
orgs.getOrgMember(ctx, orgId, ctx.userId),
|
|
107
|
+
orgs.getOrgMember(ctx, orgId, userId)
|
|
108
|
+
]);
|
|
109
|
+
if (!target)
|
|
110
|
+
apiError(404, ApiErrorCode.NOT_FOUND, 'Member not found in this organization.');
|
|
111
|
+
if (!actorMember) {
|
|
112
|
+
apiError(403, ApiErrorCode.FORBIDDEN, 'You are not a member of this organization.');
|
|
114
113
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
114
|
+
const roleChange = patch.role !== undefined && patch.role !== target.role;
|
|
115
|
+
if (roleChange) {
|
|
116
|
+
// Gated on both the role being granted and the one being taken away —
|
|
117
|
+
// demoting an owner is an owner-only act even though `member` is not.
|
|
118
|
+
if (!canChangeOrgRole({ actorMember, role: patch.role }) ||
|
|
119
|
+
!canChangeOrgRole({ actorMember, role: target.role })) {
|
|
120
|
+
apiError(403, ApiErrorCode.FORBIDDEN, 'Only the org owner can change roles.');
|
|
121
|
+
}
|
|
122
|
+
if (target.role === 'owner' &&
|
|
123
|
+
patch.role !== 'owner' &&
|
|
124
|
+
!(await hasAnotherOwner(req, ctx, orgId, target.userId))) {
|
|
125
|
+
apiError(409, ApiErrorCode.CONFLICT, 'Cannot demote the sole owner of this organization. Promote another member to owner first.');
|
|
126
|
+
}
|
|
119
127
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
128
|
+
if (patch.permissions !== undefined) {
|
|
129
|
+
// Emptying an owner's or admin's set demotes them in all but name.
|
|
130
|
+
if (!canChangeOrgRole({ actorMember, role: target.role })) {
|
|
131
|
+
apiError(403, ApiErrorCode.FORBIDDEN, 'Only the org owner can change an owner’s or admin’s permissions.');
|
|
132
|
+
}
|
|
133
|
+
// Validate against the role the member will have, not the one they had.
|
|
134
|
+
const effectiveRole = patch.role ?? target.role;
|
|
135
|
+
const valid = effectiveRole === 'member'
|
|
136
|
+
? new Set(MEMBER_ASSIGNABLE_PERMISSIONS)
|
|
137
|
+
: new Set(ALL_ORG_PERMISSIONS);
|
|
138
|
+
const invalid = patch.permissions.filter((p) => !valid.has(p));
|
|
139
|
+
if (invalid.length > 0) {
|
|
140
|
+
apiError(400, ApiErrorCode.VALIDATION_FAILED, `Permissions [${invalid.join(', ')}] cannot be assigned to a ${effectiveRole}.`);
|
|
141
|
+
}
|
|
131
142
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
143
|
+
// Writes only after every check, so a refused permission set can't leave a
|
|
144
|
+
// role change behind.
|
|
145
|
+
if (roleChange)
|
|
146
|
+
await orgs.updateOrgMemberRole(ctx, orgId, userId, patch.role);
|
|
147
|
+
if (patch.permissions !== undefined) {
|
|
148
|
+
await orgs.updateOrgMemberPermissions(ctx, orgId, userId, patch.permissions);
|
|
149
|
+
}
|
|
150
|
+
return noContent();
|
|
151
|
+
});
|
|
135
152
|
};
|
|
136
153
|
/**
|
|
137
154
|
* Remove a member from the org. Owner/admin via `manage_org_members`, same
|
|
@@ -143,25 +160,28 @@ export const removeOrgMember = async (req) => {
|
|
|
143
160
|
requireManageOrgMembers(req);
|
|
144
161
|
const { ctx, orgId } = requireActingOrg(req, req.params.orgId);
|
|
145
162
|
const orgs = req.deps.orgs;
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
163
|
+
const orphaned = await serializeOwnerChanges(orgId, async () => {
|
|
164
|
+
const [actorMember, target] = await Promise.all([
|
|
165
|
+
orgs.getOrgMember(ctx, orgId, ctx.userId),
|
|
166
|
+
orgs.getOrgMember(ctx, orgId, userId)
|
|
167
|
+
]);
|
|
168
|
+
if (!target)
|
|
169
|
+
apiError(404, ApiErrorCode.NOT_FOUND, 'Member not found in this organization.');
|
|
170
|
+
// Same owner-only gate PATCH applies to demotion. Removing an owner ends
|
|
171
|
+
// their role just as demoting them does, so an admin got 403 on the demote
|
|
172
|
+
// and 204 on the remove — the harder-to-reverse of the two.
|
|
173
|
+
if (!canChangeOrgRole({ actorMember, role: target.role })) {
|
|
174
|
+
apiError(403, ApiErrorCode.FORBIDDEN, 'Only the org owner can remove another owner.');
|
|
175
|
+
}
|
|
176
|
+
if (target.role === 'owner' && !(await hasAnotherOwner(req, ctx, orgId, target.userId))) {
|
|
177
|
+
apiError(409, ApiErrorCode.CONFLICT, 'Cannot remove the sole owner of this organization. Promote another member to owner first.');
|
|
178
|
+
}
|
|
179
|
+
// Must run before the removal: the cascade soft-deletes the very rows this
|
|
180
|
+
// reads. Reported, not blocked — see the docblock on `findProjectsLosingSoleOwner`.
|
|
181
|
+
const losing = await findProjectsLosingSoleOwner(req, orgId, userId);
|
|
182
|
+
await orgs.removeOrgMember(ctx, orgId, userId);
|
|
183
|
+
return losing;
|
|
184
|
+
});
|
|
165
185
|
if (orphaned.length > 0) {
|
|
166
186
|
await req.deps.events.emit({
|
|
167
187
|
type: 'org_member.removed_orphaning_projects',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orgMembers.js","sourceRoot":"","sources":["../../src/handlers/orgMembers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACN,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,SAAS,EACT,aAAa,EACb,yBAAyB,EACzB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACN,6BAA6B,EAC7B,mBAAmB,EACnB,OAAO,EACP,gBAAgB,
|
|
1
|
+
{"version":3,"file":"orgMembers.js","sourceRoot":"","sources":["../../src/handlers/orgMembers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runs one org's or project's member changes one at a time. The sole-owner check
|
|
3
|
+
* reads, then writes: two owners acting on each other at once would each see the
|
|
4
|
+
* other as the survivor and leave none. Per process only; replicas still need an
|
|
5
|
+
* atomic store write to close it.
|
|
6
|
+
*/
|
|
7
|
+
export declare function serializeOwnerChanges<T>(id: string, run: () => Promise<T>): Promise<T>;
|
|
8
|
+
//# sourceMappingURL=ownerChanges.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ownerChanges.d.ts","sourceRoot":"","sources":["../../src/handlers/ownerChanges.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAStF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const ownerChangeQueues = new Map();
|
|
2
|
+
/**
|
|
3
|
+
* Runs one org's or project's member changes one at a time. The sole-owner check
|
|
4
|
+
* reads, then writes: two owners acting on each other at once would each see the
|
|
5
|
+
* other as the survivor and leave none. Per process only; replicas still need an
|
|
6
|
+
* atomic store write to close it.
|
|
7
|
+
*/
|
|
8
|
+
export function serializeOwnerChanges(id, run) {
|
|
9
|
+
const previous = ownerChangeQueues.get(id) ?? Promise.resolve();
|
|
10
|
+
const next = previous.catch(() => { }).then(run);
|
|
11
|
+
const tail = next.catch(() => { });
|
|
12
|
+
ownerChangeQueues.set(id, tail);
|
|
13
|
+
void tail.then(() => {
|
|
14
|
+
if (ownerChangeQueues.get(id) === tail)
|
|
15
|
+
ownerChangeQueues.delete(id);
|
|
16
|
+
});
|
|
17
|
+
return next;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=ownerChanges.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ownerChanges.js","sourceRoot":"","sources":["../../src/handlers/ownerChanges.ts"],"names":[],"mappings":"AAAA,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAA4B,CAAC;AAE9D;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAI,EAAU,EAAE,GAAqB;IACzE,MAAM,QAAQ,GAAG,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAChE,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAClC,iBAAiB,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAChC,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE;QACnB,IAAI,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,IAAI;YAAE,iBAAiB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IACH,OAAO,IAAI,CAAC;AACb,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projectMembers.d.ts","sourceRoot":"","sources":["../../src/handlers/projectMembers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAeH,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"projectMembers.d.ts","sourceRoot":"","sources":["../../src/handlers/projectMembers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAeH,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,iBAAiB,CAAC;AAK9D,eAAO,MAAM,kBAAkB,EAAE,UAMhC,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,UAwB9B,CAAC;AAuCF,eAAO,MAAM,uBAAuB,EAAE,UAqBrC,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,UAiBjC,CAAC"}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { AddProjectMemberBodySchema, apiError, ApiErrorCode, collection, created, noContent, parseBody, parseListOptions, requireCaller, requireParams, UpdateProjectMemberBodySchema } from '../api/index.js';
|
|
11
11
|
import { checkOwnerRemoval } from '@selvajs/platform';
|
|
12
12
|
import { requireCanManage, requireTargetIsOrgMember } from '../access/index.js';
|
|
13
|
+
import { serializeOwnerChanges } from './ownerChanges.js';
|
|
13
14
|
export const listProjectMembers = async (req) => {
|
|
14
15
|
const { id } = requireParams(req.params, 'id');
|
|
15
16
|
const { ctx } = requireCaller(req);
|
|
@@ -69,27 +70,31 @@ export const updateProjectMemberRole = async (req) => {
|
|
|
69
70
|
// it runs the same guard DELETE does. Without this a sole owner can PATCH
|
|
70
71
|
// themselves to `viewer` and lock the project — `canManage`,
|
|
71
72
|
// `canEditProjectSettings` and `canEdit` all go false at once.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
return serializeOwnerChanges(id, async () => {
|
|
74
|
+
if (role !== 'owner') {
|
|
75
|
+
const target = await req.deps.projects.getProjectMember(ctx, id, userId);
|
|
76
|
+
if (target?.role === 'owner') {
|
|
77
|
+
await assertOwnerRemovable(req, id, target, 'demote');
|
|
78
|
+
}
|
|
76
79
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
+
await req.deps.projects.updateProjectMemberRole(ctx, id, userId, role);
|
|
81
|
+
return noContent();
|
|
82
|
+
});
|
|
80
83
|
};
|
|
81
84
|
export const removeProjectMember = async (req) => {
|
|
82
85
|
const { id, userId } = requireParams(req.params, 'id', 'userId');
|
|
83
86
|
const { ctx } = requireCaller(req);
|
|
84
87
|
await requireCanManage(req, id, 'members');
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
+
return serializeOwnerChanges(id, async () => {
|
|
89
|
+
const target = await req.deps.projects.getProjectMember(ctx, id, userId);
|
|
90
|
+
// Idempotent: already gone, or never there.
|
|
91
|
+
if (!target)
|
|
92
|
+
return noContent();
|
|
93
|
+
if (target.role === 'owner') {
|
|
94
|
+
await assertOwnerRemovable(req, id, target, 'remove');
|
|
95
|
+
}
|
|
96
|
+
await req.deps.projects.removeProjectMember(ctx, id, userId);
|
|
88
97
|
return noContent();
|
|
89
|
-
|
|
90
|
-
await assertOwnerRemovable(req, id, target, 'remove');
|
|
91
|
-
}
|
|
92
|
-
await req.deps.projects.removeProjectMember(ctx, id, userId);
|
|
93
|
-
return noContent();
|
|
98
|
+
});
|
|
94
99
|
};
|
|
95
100
|
//# sourceMappingURL=projectMembers.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projectMembers.js","sourceRoot":"","sources":["../../src/handlers/projectMembers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACN,0BAA0B,EAC1B,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,OAAO,EACP,SAAS,EACT,SAAS,EACT,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,6BAA6B,EAC7B,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,iBAAiB,EAAwC,MAAM,mBAAmB,CAAC;AAC5F,OAAO,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"projectMembers.js","sourceRoot":"","sources":["../../src/handlers/projectMembers.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/handlers/projects.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAYN,KAAK,UAAU,EACf,MAAM,iBAAiB,CAAC;AAyBzB;;;;GAIG;AACH,eAAO,MAAM,YAAY,EAAE,UAgC1B,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,UAiD3B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,UAAU,EAAE,UAmCxB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,
|
|
1
|
+
{"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/handlers/projects.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAYN,KAAK,UAAU,EACf,MAAM,iBAAiB,CAAC;AAyBzB;;;;GAIG;AACH,eAAO,MAAM,YAAY,EAAE,UAgC1B,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,UAiD3B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,UAAU,EAAE,UAmCxB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,UAyE3B,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,UAe3B,CAAC"}
|