@grantjs/schema 1.8.0 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/generated/graphql.ts +1078 -30
- package/src/generated/resolvers.ts +184 -0
- package/src/generated/schema-types.ts +381 -0
- package/src/index.ts +9 -6
- package/src/operations/project-apps/clear-project-app-picture.graphql +7 -0
- package/src/operations/project-apps/get-project-apps.graphql +7 -0
- package/src/operations/project-apps/update-project-app.graphql +7 -0
- package/src/operations/project-apps/upload-project-app-picture.graphql +6 -0
- package/src/operations/projects/clear-project-picture.graphql +7 -0
- package/src/operations/projects/getProjects.graphql +3 -0
- package/src/operations/projects/updateProject.graphql +3 -0
- package/src/operations/projects/upload-project-picture.graphql +6 -0
- package/src/operations/uploads/confirm-my-project-membership-picture-upload.graphql +8 -0
- package/src/operations/uploads/confirm-my-user-picture-upload.graphql +6 -0
- package/src/operations/uploads/confirm-organization-picture-upload.graphql +6 -0
- package/src/operations/uploads/confirm-project-app-picture-upload.graphql +6 -0
- package/src/operations/uploads/confirm-project-picture-upload.graphql +6 -0
- package/src/operations/uploads/confirm-user-picture-upload.graphql +6 -0
- package/src/operations/uploads/request-my-project-membership-picture-upload-url.graphql +13 -0
- package/src/operations/uploads/request-my-user-picture-upload-url.graphql +11 -0
- package/src/operations/uploads/request-organization-picture-upload-url.graphql +11 -0
- package/src/operations/uploads/request-project-app-picture-upload-url.graphql +11 -0
- package/src/operations/uploads/request-project-picture-upload-url.graphql +11 -0
- package/src/operations/uploads/request-user-picture-upload-url.graphql +11 -0
- package/src/project-oauth.types.test.ts +18 -0
- package/src/project-oauth.types.ts +22 -0
- package/src/schema/me/inputs/confirm-my-project-membership-picture-upload.graphql +4 -0
- package/src/schema/me/inputs/confirm-my-user-picture-upload.graphql +8 -0
- package/src/schema/me/inputs/request-my-project-membership-picture-upload-url.graphql +11 -0
- package/src/schema/me/inputs/request-my-user-picture-upload-url.graphql +11 -0
- package/src/schema/me/mutations/confirm-my-project-membership-picture-upload.graphql +10 -0
- package/src/schema/me/mutations/confirm-my-user-picture-upload.graphql +9 -0
- package/src/schema/me/mutations/request-my-project-membership-picture-upload-url.graphql +13 -0
- package/src/schema/me/mutations/request-my-user-picture-upload-url.graphql +12 -0
- package/src/schema/organizations/inputs/confirm-organization-picture-upload.graphql +9 -0
- package/src/schema/organizations/inputs/request-organization-picture-upload-url.graphql +12 -0
- package/src/schema/organizations/mutations/confirm-organization-picture-upload.graphql +10 -0
- package/src/schema/organizations/mutations/request-organization-picture-upload-url.graphql +12 -0
- package/src/schema/project-apps/inputs/clear-project-app-picture.graphql +4 -0
- package/src/schema/project-apps/inputs/confirm-project-app-picture-upload.graphql +9 -0
- package/src/schema/project-apps/inputs/request-project-app-picture-upload-url.graphql +12 -0
- package/src/schema/project-apps/inputs/update-project-app.graphql +12 -0
- package/src/schema/project-apps/inputs/upload-project-app-picture.graphql +7 -0
- package/src/schema/project-apps/mutations/clear-project-app-picture.graphql +6 -0
- package/src/schema/project-apps/mutations/confirm-project-app-picture-upload.graphql +10 -0
- package/src/schema/project-apps/mutations/request-project-app-picture-upload-url.graphql +12 -0
- package/src/schema/project-apps/mutations/upload-project-app-picture.graphql +6 -0
- package/src/schema/project-apps/types/project-app.graphql +13 -0
- package/src/schema/project-apps/types/upload-project-app-picture-result.graphql +4 -0
- package/src/schema/projects/inputs/clear-project-picture.graphql +4 -0
- package/src/schema/projects/inputs/confirm-project-picture-upload.graphql +9 -0
- package/src/schema/projects/inputs/request-project-picture-upload-url.graphql +12 -0
- package/src/schema/projects/inputs/update-project.graphql +8 -0
- package/src/schema/projects/inputs/upload-project-picture.graphql +7 -0
- package/src/schema/projects/mutations/clear-project-picture.graphql +6 -0
- package/src/schema/projects/mutations/confirm-project-picture-upload.graphql +8 -0
- package/src/schema/projects/mutations/request-project-picture-upload-url.graphql +12 -0
- package/src/schema/projects/mutations/upload-project-picture.graphql +6 -0
- package/src/schema/projects/types/project.graphql +9 -0
- package/src/schema/projects/types/upload-project-picture-result.graphql +4 -0
- package/src/schema/uploads/types/upload-url.graphql +33 -0
- package/src/schema/users/inputs/confirm-user-picture-upload.graphql +5 -0
- package/src/schema/users/inputs/request-user-picture-upload-url.graphql +12 -0
- package/src/schema/users/mutations/confirm-user-picture-upload.graphql +8 -0
- package/src/schema/users/mutations/request-user-picture-upload-url.graphql +12 -0
- package/src/sdl-contract.test.ts +11 -2
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { isProjectOAuthThemeMode } from './project-oauth.types';
|
|
4
|
+
|
|
5
|
+
describe('isProjectOAuthThemeMode', () => {
|
|
6
|
+
it('accepts the hosted OAuth appearance values', () => {
|
|
7
|
+
expect(isProjectOAuthThemeMode('light')).toBe(true);
|
|
8
|
+
expect(isProjectOAuthThemeMode('dark')).toBe(true);
|
|
9
|
+
expect(isProjectOAuthThemeMode('system')).toBe(true);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('rejects unset or unknown values', () => {
|
|
13
|
+
expect(isProjectOAuthThemeMode(null)).toBe(false);
|
|
14
|
+
expect(isProjectOAuthThemeMode(undefined)).toBe(false);
|
|
15
|
+
expect(isProjectOAuthThemeMode('sepia')).toBe(false);
|
|
16
|
+
expect(isProjectOAuthThemeMode('DARK')).toBe(false);
|
|
17
|
+
});
|
|
18
|
+
});
|
|
@@ -3,6 +3,16 @@
|
|
|
3
3
|
* Used by project app-info and consent REST endpoints; shared by API and web client.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
/** Forced appearance on hosted OAuth pages. Null keeps the visitor's Grant theme. */
|
|
7
|
+
export const PROJECT_OAUTH_THEME_MODES = ['light', 'dark', 'system'] as const;
|
|
8
|
+
export type ProjectOAuthThemeMode = (typeof PROJECT_OAUTH_THEME_MODES)[number];
|
|
9
|
+
|
|
10
|
+
export function isProjectOAuthThemeMode(value: unknown): value is ProjectOAuthThemeMode {
|
|
11
|
+
return (
|
|
12
|
+
typeof value === 'string' && (PROJECT_OAUTH_THEME_MODES as readonly string[]).includes(value)
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
6
16
|
/** Scope label returned by project app-info and consent-info endpoints. */
|
|
7
17
|
export interface ProjectAppScopeInfo {
|
|
8
18
|
slug: string;
|
|
@@ -13,6 +23,11 @@ export interface ProjectAppScopeInfo {
|
|
|
13
23
|
/** Response from GET /api/auth/project/app-info (public app metadata and scopes). */
|
|
14
24
|
export interface ProjectAppPublicInfo {
|
|
15
25
|
name: string | null;
|
|
26
|
+
projectName: string | null;
|
|
27
|
+
pictureUrl: string | null;
|
|
28
|
+
primaryColor: string | null;
|
|
29
|
+
showHelpPanel: boolean;
|
|
30
|
+
themeMode: ProjectOAuthThemeMode | null;
|
|
16
31
|
enabledProviders: string[] | null;
|
|
17
32
|
scopes: ProjectAppScopeInfo[];
|
|
18
33
|
}
|
|
@@ -22,11 +37,18 @@ export interface ProjectConsentInfoUser {
|
|
|
22
37
|
displayName: string;
|
|
23
38
|
email: string | null;
|
|
24
39
|
pictureUrl: string | null;
|
|
40
|
+
/** Provider used for this sign-in (email, github, google). */
|
|
41
|
+
provider: string | null;
|
|
25
42
|
}
|
|
26
43
|
|
|
27
44
|
/** Response from GET /api/auth/project/consent-info (app name, granted scopes, user). */
|
|
28
45
|
export interface ProjectConsentInfo {
|
|
29
46
|
name: string | null;
|
|
47
|
+
projectName: string | null;
|
|
48
|
+
pictureUrl: string | null;
|
|
49
|
+
primaryColor: string | null;
|
|
50
|
+
showHelpPanel: boolean;
|
|
51
|
+
themeMode: ProjectOAuthThemeMode | null;
|
|
30
52
|
scopes: ProjectAppScopeInfo[];
|
|
31
53
|
user: ProjectConsentInfoUser | null;
|
|
32
54
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""
|
|
2
|
+
`filename` is repeated from the request step rather than carried in a token: the
|
|
3
|
+
storage path is re-derived server-side from the caller's identity both times, so
|
|
4
|
+
nothing the client sends can point the confirmation at another user's object.
|
|
5
|
+
"""
|
|
6
|
+
input ConfirmMyUserPictureUploadInput {
|
|
7
|
+
filename: String!
|
|
8
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
input RequestMyProjectMembershipPictureUploadUrlInput {
|
|
2
|
+
projectId: ID!
|
|
3
|
+
filename: String!
|
|
4
|
+
contentType: String!
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
Exact byte length the client will send. Validated against the upload policy
|
|
8
|
+
before a URL is issued, and committed to by the URL itself.
|
|
9
|
+
"""
|
|
10
|
+
contentLength: Int!
|
|
11
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
input RequestMyUserPictureUploadUrlInput {
|
|
2
|
+
filename: String!
|
|
3
|
+
contentType: String!
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
Exact byte length the client will send. Validated against the upload policy
|
|
7
|
+
before a URL is issued, and committed to by the URL itself — a body of any
|
|
8
|
+
other length is refused by the store.
|
|
9
|
+
"""
|
|
10
|
+
contentLength: Int!
|
|
11
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
extend type Mutation {
|
|
2
|
+
"""
|
|
3
|
+
Record a direct upload of a project-membership picture that has completed.
|
|
4
|
+
Re-checks membership and reads the object back from storage before anything is
|
|
5
|
+
written to the membership.
|
|
6
|
+
"""
|
|
7
|
+
confirmMyProjectMembershipPictureUpload(
|
|
8
|
+
input: ConfirmMyProjectMembershipPictureUploadInput!
|
|
9
|
+
): UploadUserPictureResult!
|
|
10
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
extend type Mutation {
|
|
2
|
+
"""
|
|
3
|
+
Record a direct upload that has completed. Reads the object back from storage
|
|
4
|
+
to confirm it exists and is within the size policy — what the client claimed
|
|
5
|
+
when it asked for the URL is not evidence — then points the user's picture at
|
|
6
|
+
it.
|
|
7
|
+
"""
|
|
8
|
+
confirmMyUserPictureUpload(input: ConfirmMyUserPictureUploadInput!): UploadUserPictureResult!
|
|
9
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
extend type Mutation {
|
|
2
|
+
"""
|
|
3
|
+
Ask for a URL to upload the signed-in user's picture for one project
|
|
4
|
+
membership, directly to storage.
|
|
5
|
+
|
|
6
|
+
Membership is checked before a URL exists, not only when the upload is
|
|
7
|
+
recorded: a URL is a write capability, so issuing one for a project you do not
|
|
8
|
+
belong to is the thing to prevent, not to detect afterwards.
|
|
9
|
+
"""
|
|
10
|
+
requestMyProjectMembershipPictureUploadUrl(
|
|
11
|
+
input: RequestMyProjectMembershipPictureUploadUrlInput!
|
|
12
|
+
): UploadUrl!
|
|
13
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
extend type Mutation {
|
|
2
|
+
"""
|
|
3
|
+
Ask for a URL to upload the signed-in user's picture directly to storage,
|
|
4
|
+
without the bytes passing through this API.
|
|
5
|
+
|
|
6
|
+
Validates content type, extension and size **before** issuing the URL, and
|
|
7
|
+
binds the URL to a path derived from the caller's own identity. Call
|
|
8
|
+
`confirmMyUserPictureUpload` once the PUT succeeds; until then nothing is
|
|
9
|
+
recorded against the user.
|
|
10
|
+
"""
|
|
11
|
+
requestMyUserPictureUploadUrl(input: RequestMyUserPictureUploadUrlInput!): UploadUrl!
|
|
12
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""
|
|
2
|
+
`filename` is repeated from the request step rather than carried in a token: the
|
|
3
|
+
storage path is re-derived server-side from the organization id both times.
|
|
4
|
+
"""
|
|
5
|
+
input ConfirmOrganizationPictureUploadInput {
|
|
6
|
+
scope: Scope!
|
|
7
|
+
organizationId: ID!
|
|
8
|
+
filename: String!
|
|
9
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
input RequestOrganizationPictureUploadUrlInput {
|
|
2
|
+
scope: Scope!
|
|
3
|
+
organizationId: ID!
|
|
4
|
+
filename: String!
|
|
5
|
+
contentType: String!
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
Exact byte length the client will send. Validated against the upload policy
|
|
9
|
+
before a URL is issued, and committed to by the URL itself.
|
|
10
|
+
"""
|
|
11
|
+
contentLength: Int!
|
|
12
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
extend type Mutation {
|
|
2
|
+
"""
|
|
3
|
+
Record a direct organization-logo upload that has completed. Reads the object
|
|
4
|
+
back from storage to confirm it exists and is within the size policy, then
|
|
5
|
+
stores the object key on the organization (`picture_path`).
|
|
6
|
+
"""
|
|
7
|
+
confirmOrganizationPictureUpload(
|
|
8
|
+
input: ConfirmOrganizationPictureUploadInput!
|
|
9
|
+
): UploadOrganizationPictureResult!
|
|
10
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
extend type Mutation {
|
|
2
|
+
"""
|
|
3
|
+
Ask for a URL to upload an organization logo directly to storage, without the
|
|
4
|
+
bytes passing through this API.
|
|
5
|
+
|
|
6
|
+
Validates content type, extension and size **before** issuing the URL, and
|
|
7
|
+
binds the URL to a path derived from the organization id. Call
|
|
8
|
+
`confirmOrganizationPictureUpload` once the PUT succeeds; until then nothing
|
|
9
|
+
is recorded against the organization.
|
|
10
|
+
"""
|
|
11
|
+
requestOrganizationPictureUploadUrl(input: RequestOrganizationPictureUploadUrlInput!): UploadUrl!
|
|
12
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""
|
|
2
|
+
`filename` is repeated from the request step rather than carried in a token: the
|
|
3
|
+
storage path is re-derived server-side from the project-app id both times.
|
|
4
|
+
"""
|
|
5
|
+
input ConfirmProjectAppPictureUploadInput {
|
|
6
|
+
scope: Scope!
|
|
7
|
+
projectAppId: ID!
|
|
8
|
+
filename: String!
|
|
9
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
input RequestProjectAppPictureUploadUrlInput {
|
|
2
|
+
scope: Scope!
|
|
3
|
+
projectAppId: ID!
|
|
4
|
+
filename: String!
|
|
5
|
+
contentType: String!
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
Exact byte length the client will send. Validated against the upload policy
|
|
9
|
+
before a URL is issued, and committed to by the URL itself.
|
|
10
|
+
"""
|
|
11
|
+
contentLength: Int!
|
|
12
|
+
}
|
|
@@ -5,6 +5,18 @@ input UpdateProjectAppInput {
|
|
|
5
5
|
"""
|
|
6
6
|
name: String
|
|
7
7
|
"""
|
|
8
|
+
Brand hex (`#RRGGBB`). Null inherits the project color.
|
|
9
|
+
"""
|
|
10
|
+
primaryColor: String
|
|
11
|
+
"""
|
|
12
|
+
Whether the OAuth help panel is shown. Null inherits the project setting.
|
|
13
|
+
"""
|
|
14
|
+
showHelpPanel: Boolean
|
|
15
|
+
"""
|
|
16
|
+
Forced OAuth appearance (`light`, `dark`, `system`). Null keeps the visitor's Grant theme.
|
|
17
|
+
"""
|
|
18
|
+
themeMode: String
|
|
19
|
+
"""
|
|
8
20
|
Allowed redirect URIs for OAuth callback. If provided, at least one required.
|
|
9
21
|
"""
|
|
10
22
|
redirectUris: [String!]
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
extend type Mutation {
|
|
2
|
+
"""
|
|
3
|
+
Record a direct project-app-logo upload that has completed. Reads the object
|
|
4
|
+
back from storage to confirm it exists and is within the size policy, then
|
|
5
|
+
stores the object key on the app (`picture_path`).
|
|
6
|
+
"""
|
|
7
|
+
confirmProjectAppPictureUpload(
|
|
8
|
+
input: ConfirmProjectAppPictureUploadInput!
|
|
9
|
+
): UploadProjectAppPictureResult!
|
|
10
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
extend type Mutation {
|
|
2
|
+
"""
|
|
3
|
+
Ask for a URL to upload a project-app logo directly to storage, without the
|
|
4
|
+
bytes passing through this API.
|
|
5
|
+
|
|
6
|
+
Validates content type, extension and size **before** issuing the URL, and
|
|
7
|
+
binds the URL to a path derived from the project-app id. Call
|
|
8
|
+
`confirmProjectAppPictureUpload` once the PUT succeeds; until then nothing
|
|
9
|
+
is recorded against the app.
|
|
10
|
+
"""
|
|
11
|
+
requestProjectAppPictureUploadUrl(input: RequestProjectAppPictureUploadUrlInput!): UploadUrl!
|
|
12
|
+
}
|
|
@@ -3,6 +3,19 @@ type ProjectApp implements Auditable {
|
|
|
3
3
|
projectId: ID!
|
|
4
4
|
clientId: String!
|
|
5
5
|
name: String
|
|
6
|
+
pictureUrl: String
|
|
7
|
+
"""
|
|
8
|
+
Brand hex (`#RRGGBB`). Null inherits the project color.
|
|
9
|
+
"""
|
|
10
|
+
primaryColor: String
|
|
11
|
+
"""
|
|
12
|
+
Whether the OAuth help panel is shown. Null inherits the project setting.
|
|
13
|
+
"""
|
|
14
|
+
showHelpPanel: Boolean
|
|
15
|
+
"""
|
|
16
|
+
Forced OAuth appearance (`light`, `dark`, `system`). Null keeps the visitor's Grant theme.
|
|
17
|
+
"""
|
|
18
|
+
themeMode: String
|
|
6
19
|
redirectUris: [String!]!
|
|
7
20
|
scopes: [String!]
|
|
8
21
|
"""
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""
|
|
2
|
+
`filename` is repeated from the request step rather than carried in a token: the
|
|
3
|
+
storage path is re-derived server-side from the project id both times.
|
|
4
|
+
"""
|
|
5
|
+
input ConfirmProjectPictureUploadInput {
|
|
6
|
+
scope: Scope!
|
|
7
|
+
projectId: ID!
|
|
8
|
+
filename: String!
|
|
9
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
input RequestProjectPictureUploadUrlInput {
|
|
2
|
+
scope: Scope!
|
|
3
|
+
projectId: ID!
|
|
4
|
+
filename: String!
|
|
5
|
+
contentType: String!
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
Exact byte length the client will send. Validated against the upload policy
|
|
9
|
+
before a URL is issued, and committed to by the URL itself.
|
|
10
|
+
"""
|
|
11
|
+
contentLength: Int!
|
|
12
|
+
}
|
|
@@ -2,6 +2,14 @@ input UpdateProjectInput {
|
|
|
2
2
|
scope: Scope!
|
|
3
3
|
name: String
|
|
4
4
|
description: String
|
|
5
|
+
"""
|
|
6
|
+
Brand hex (`#RRGGBB`). Null resets to Grant's default.
|
|
7
|
+
"""
|
|
8
|
+
primaryColor: String
|
|
9
|
+
"""
|
|
10
|
+
Whether the OAuth help panel is shown. Null resets to Grant's default (shown).
|
|
11
|
+
"""
|
|
12
|
+
showHelpPanel: Boolean
|
|
5
13
|
tagIds: [ID!]
|
|
6
14
|
primaryTagId: ID
|
|
7
15
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
extend type Mutation {
|
|
2
|
+
"""
|
|
3
|
+
Record a direct project-logo upload that has completed. Reads the object
|
|
4
|
+
back from storage to confirm it exists and is within the size policy, then
|
|
5
|
+
stores the object key on the project (`picture_path`).
|
|
6
|
+
"""
|
|
7
|
+
confirmProjectPictureUpload(input: ConfirmProjectPictureUploadInput!): UploadProjectPictureResult!
|
|
8
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
extend type Mutation {
|
|
2
|
+
"""
|
|
3
|
+
Ask for a URL to upload a project logo directly to storage, without the
|
|
4
|
+
bytes passing through this API.
|
|
5
|
+
|
|
6
|
+
Validates content type, extension and size **before** issuing the URL, and
|
|
7
|
+
binds the URL to a path derived from the project id. Call
|
|
8
|
+
`confirmProjectPictureUpload` once the PUT succeeds; until then nothing
|
|
9
|
+
is recorded against the project.
|
|
10
|
+
"""
|
|
11
|
+
requestProjectPictureUploadUrl(input: RequestProjectPictureUploadUrlInput!): UploadUrl!
|
|
12
|
+
}
|
|
@@ -3,6 +3,15 @@ type Project implements Auditable {
|
|
|
3
3
|
name: String!
|
|
4
4
|
slug: String!
|
|
5
5
|
description: String
|
|
6
|
+
pictureUrl: String
|
|
7
|
+
"""
|
|
8
|
+
Brand hex (`#RRGGBB`). Null uses Grant's default OAuth theme.
|
|
9
|
+
"""
|
|
10
|
+
primaryColor: String
|
|
11
|
+
"""
|
|
12
|
+
Whether the OAuth help panel is shown. Null uses Grant's default (shown).
|
|
13
|
+
"""
|
|
14
|
+
showHelpPanel: Boolean
|
|
6
15
|
roles: [Role!]
|
|
7
16
|
groups: [Group!]
|
|
8
17
|
permissions: [Permission!]
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""
|
|
2
|
+
A bounded, time-limited URL the client writes bytes to directly.
|
|
3
|
+
|
|
4
|
+
The URL is a bearer capability: it permits exactly `contentLength` bytes of
|
|
5
|
+
exactly `contentType` at exactly one server-derived path, until `expiresAt`.
|
|
6
|
+
It is not single-use and cannot be revoked, so it is short-lived by design.
|
|
7
|
+
"""
|
|
8
|
+
type UploadUrl {
|
|
9
|
+
"""
|
|
10
|
+
Absolute for object stores; application-relative for targets this API serves
|
|
11
|
+
itself. Resolve it against the API origin before using it.
|
|
12
|
+
"""
|
|
13
|
+
url: String!
|
|
14
|
+
|
|
15
|
+
"HTTP method the client must use. Always PUT today."
|
|
16
|
+
method: String!
|
|
17
|
+
|
|
18
|
+
"""
|
|
19
|
+
Headers the client must set verbatim. `Content-Length` is deliberately absent:
|
|
20
|
+
browsers set it from the body and forbid setting it by hand, even though the
|
|
21
|
+
URL commits to the value.
|
|
22
|
+
"""
|
|
23
|
+
headers: [UploadUrlHeader!]!
|
|
24
|
+
|
|
25
|
+
"Instant after which the store refuses the URL."
|
|
26
|
+
expiresAt: Date!
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
"A header the client must send with the direct upload."
|
|
30
|
+
type UploadUrlHeader {
|
|
31
|
+
name: String!
|
|
32
|
+
value: String!
|
|
33
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
input RequestUserPictureUploadUrlInput {
|
|
2
|
+
scope: Scope!
|
|
3
|
+
userId: ID!
|
|
4
|
+
filename: String!
|
|
5
|
+
contentType: String!
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
Exact byte length the client will send. Validated against the upload policy
|
|
9
|
+
before a URL is issued, and committed to by the URL itself.
|
|
10
|
+
"""
|
|
11
|
+
contentLength: Int!
|
|
12
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
extend type Mutation {
|
|
2
|
+
"""
|
|
3
|
+
Record a completed direct upload of another user's picture. Re-runs the scope
|
|
4
|
+
and permission checks, then reads the object back from storage before writing
|
|
5
|
+
the picture to the user or to their project membership, as scope dictates.
|
|
6
|
+
"""
|
|
7
|
+
confirmUserPictureUpload(input: ConfirmUserPictureUploadInput!): UploadUserPictureResult!
|
|
8
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
extend type Mutation {
|
|
2
|
+
"""
|
|
3
|
+
Ask for a URL to upload another user's picture directly to storage.
|
|
4
|
+
|
|
5
|
+
Unlike the `me` variants, the storage path here is derived from the **target**
|
|
6
|
+
user rather than the caller, so the permission check is the only thing standing
|
|
7
|
+
between a caller and another user's picture. It therefore runs before a URL is
|
|
8
|
+
issued — the same scope and self-managed-identity rules `uploadUserPicture`
|
|
9
|
+
applies — and again when the upload is confirmed.
|
|
10
|
+
"""
|
|
11
|
+
requestUserPictureUploadUrl(input: RequestUserPictureUploadUrlInput!): UploadUrl!
|
|
12
|
+
}
|
package/src/sdl-contract.test.ts
CHANGED
|
@@ -40,9 +40,18 @@ describe('operation documents', () => {
|
|
|
40
40
|
|
|
41
41
|
// Pinned, not a floor: pass 5 slice 5 removed one file and two query operations
|
|
42
42
|
// that were superseded by list queries, and a floor would have absorbed that
|
|
43
|
-
// silently. 116 before that slice, 115 after,
|
|
43
|
+
// silently. 116 before that slice, 115 after it, 117 once part D's first
|
|
44
|
+
// direct-upload pair (`requestMyUserPictureUploadUrl`,
|
|
45
|
+
// `confirmMyUserPictureUpload`) arrived, and 121 with the two remaining targets —
|
|
46
|
+
// project membership and the administrator route — each another request/confirm
|
|
47
|
+
// pair. 122 after `main` merged in, which added `upload-organization-picture`.
|
|
48
|
+
// 124 after slice 17b: organization request/confirm (the last upload target).
|
|
49
|
+
// 132 after project branding: request/confirm/upload/clear for project and
|
|
50
|
+
// project-app pictures (eight operation documents).
|
|
51
|
+
// Updating this number is the point of the pin, not a nuisance: every change
|
|
52
|
+
// to it should be a line in a commit message.
|
|
44
53
|
it('finds every document under src/operations', () => {
|
|
45
|
-
expect(files).toHaveLength(
|
|
54
|
+
expect(files).toHaveLength(132);
|
|
46
55
|
});
|
|
47
56
|
|
|
48
57
|
it.each(files.map((f) => [relative(process.cwd(), f), f]))('%s validates', (_label, file) => {
|