@grantjs/schema 1.14.2 → 1.15.0

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grantjs/schema",
3
- "version": "1.14.2",
3
+ "version": "1.15.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1505,6 +1505,22 @@ export type ProjectSyncJobsQuery = {
1505
1505
  };
1506
1506
  };
1507
1507
 
1508
+ export type RequestProjectSyncUploadUrlMutationVariables = Exact<{
1509
+ id: string | number;
1510
+ scope: Types.Scope;
1511
+ input: Types.RequestProjectSyncUploadUrlInput;
1512
+ }>;
1513
+
1514
+ export type RequestProjectSyncUploadUrlMutation = {
1515
+ requestProjectSyncUploadUrl: {
1516
+ uploadId: string;
1517
+ url: string;
1518
+ method: string;
1519
+ expiresAt: Date;
1520
+ headers: Array<{ name: string; value: string }>;
1521
+ };
1522
+ };
1523
+
1508
1524
  export type StartProjectExportMutationVariables = Exact<{
1509
1525
  id: string | number;
1510
1526
  scope: Types.Scope;
@@ -8153,6 +8169,94 @@ export const ProjectSyncJobsDocument = {
8153
8169
  },
8154
8170
  ],
8155
8171
  } as unknown as DocumentNode<ProjectSyncJobsQuery, ProjectSyncJobsQueryVariables>;
8172
+ export const RequestProjectSyncUploadUrlDocument = {
8173
+ kind: 'Document',
8174
+ definitions: [
8175
+ {
8176
+ kind: 'OperationDefinition',
8177
+ operation: 'mutation',
8178
+ name: { kind: 'Name', value: 'RequestProjectSyncUploadUrl' },
8179
+ variableDefinitions: [
8180
+ {
8181
+ kind: 'VariableDefinition',
8182
+ variable: { kind: 'Variable', name: { kind: 'Name', value: 'id' } },
8183
+ type: {
8184
+ kind: 'NonNullType',
8185
+ type: { kind: 'NamedType', name: { kind: 'Name', value: 'ID' } },
8186
+ },
8187
+ },
8188
+ {
8189
+ kind: 'VariableDefinition',
8190
+ variable: { kind: 'Variable', name: { kind: 'Name', value: 'scope' } },
8191
+ type: {
8192
+ kind: 'NonNullType',
8193
+ type: { kind: 'NamedType', name: { kind: 'Name', value: 'Scope' } },
8194
+ },
8195
+ },
8196
+ {
8197
+ kind: 'VariableDefinition',
8198
+ variable: { kind: 'Variable', name: { kind: 'Name', value: 'input' } },
8199
+ type: {
8200
+ kind: 'NonNullType',
8201
+ type: {
8202
+ kind: 'NamedType',
8203
+ name: { kind: 'Name', value: 'RequestProjectSyncUploadUrlInput' },
8204
+ },
8205
+ },
8206
+ },
8207
+ ],
8208
+ selectionSet: {
8209
+ kind: 'SelectionSet',
8210
+ selections: [
8211
+ {
8212
+ kind: 'Field',
8213
+ name: { kind: 'Name', value: 'requestProjectSyncUploadUrl' },
8214
+ arguments: [
8215
+ {
8216
+ kind: 'Argument',
8217
+ name: { kind: 'Name', value: 'id' },
8218
+ value: { kind: 'Variable', name: { kind: 'Name', value: 'id' } },
8219
+ },
8220
+ {
8221
+ kind: 'Argument',
8222
+ name: { kind: 'Name', value: 'scope' },
8223
+ value: { kind: 'Variable', name: { kind: 'Name', value: 'scope' } },
8224
+ },
8225
+ {
8226
+ kind: 'Argument',
8227
+ name: { kind: 'Name', value: 'input' },
8228
+ value: { kind: 'Variable', name: { kind: 'Name', value: 'input' } },
8229
+ },
8230
+ ],
8231
+ selectionSet: {
8232
+ kind: 'SelectionSet',
8233
+ selections: [
8234
+ { kind: 'Field', name: { kind: 'Name', value: 'uploadId' } },
8235
+ { kind: 'Field', name: { kind: 'Name', value: 'url' } },
8236
+ { kind: 'Field', name: { kind: 'Name', value: 'method' } },
8237
+ { kind: 'Field', name: { kind: 'Name', value: 'expiresAt' } },
8238
+ {
8239
+ kind: 'Field',
8240
+ name: { kind: 'Name', value: 'headers' },
8241
+ selectionSet: {
8242
+ kind: 'SelectionSet',
8243
+ selections: [
8244
+ { kind: 'Field', name: { kind: 'Name', value: 'name' } },
8245
+ { kind: 'Field', name: { kind: 'Name', value: 'value' } },
8246
+ ],
8247
+ },
8248
+ },
8249
+ ],
8250
+ },
8251
+ },
8252
+ ],
8253
+ },
8254
+ },
8255
+ ],
8256
+ } as unknown as DocumentNode<
8257
+ RequestProjectSyncUploadUrlMutation,
8258
+ RequestProjectSyncUploadUrlMutationVariables
8259
+ >;
8156
8260
  export const StartProjectExportDocument = {
8157
8261
  kind: 'Document',
8158
8262
  definitions: [
@@ -378,6 +378,7 @@ export type ResolversTypes = ResolversObject<{
378
378
  ProjectSyncJobSortInput: Types.ProjectSyncJobSortInput;
379
379
  ProjectSyncJobSortableField: Types.ProjectSyncJobSortableField;
380
380
  ProjectSyncJobStatus: Types.ProjectSyncJobStatus;
381
+ ProjectSyncUploadUrl: ResolverTypeWrapper<Types.ProjectSyncUploadUrl>;
381
382
  ProjectTag: ResolverTypeWrapper<Types.ProjectTag>;
382
383
  ProjectUser: ResolverTypeWrapper<Types.ProjectUser>;
383
384
  ProjectUserApiKey: ResolverTypeWrapper<Types.ProjectUserApiKey>;
@@ -464,6 +465,7 @@ export type ResolversTypes = ResolversObject<{
464
465
  RequestPasswordResetResponse: ResolverTypeWrapper<Types.RequestPasswordResetResponse>;
465
466
  RequestProjectAppPictureUploadUrlInput: Types.RequestProjectAppPictureUploadUrlInput;
466
467
  RequestProjectPictureUploadUrlInput: Types.RequestProjectPictureUploadUrlInput;
468
+ RequestProjectSyncUploadUrlInput: Types.RequestProjectSyncUploadUrlInput;
467
469
  RequestUserPictureUploadUrlInput: Types.RequestUserPictureUploadUrlInput;
468
470
  ResendVerificationInput: Types.ResendVerificationInput;
469
471
  ResendVerificationResponse: ResolverTypeWrapper<Types.ResendVerificationResponse>;
@@ -502,6 +504,7 @@ export type ResolversTypes = ResolversObject<{
502
504
  String: ResolverTypeWrapper<Types.Scalars['String']['output']>;
503
505
  SyncProjectInput: Types.SyncProjectInput;
504
506
  SyncProjectResult: ResolverTypeWrapper<Types.SyncProjectResult>;
507
+ SyncProjectSourceInput: Types.SyncProjectSourceInput;
505
508
  Tag: ResolverTypeWrapper<Types.Tag>;
506
509
  TagCdmInput: Types.TagCdmInput;
507
510
  TagPage: ResolverTypeWrapper<Types.TagPage>;
@@ -759,6 +762,7 @@ export type ResolversParentTypes = ResolversObject<{
759
762
  ProjectSyncJob: Types.ProjectSyncJob;
760
763
  ProjectSyncJobPage: Types.ProjectSyncJobPage;
761
764
  ProjectSyncJobSortInput: Types.ProjectSyncJobSortInput;
765
+ ProjectSyncUploadUrl: Types.ProjectSyncUploadUrl;
762
766
  ProjectTag: Types.ProjectTag;
763
767
  ProjectUser: Types.ProjectUser;
764
768
  ProjectUserApiKey: Types.ProjectUserApiKey;
@@ -845,6 +849,7 @@ export type ResolversParentTypes = ResolversObject<{
845
849
  RequestPasswordResetResponse: Types.RequestPasswordResetResponse;
846
850
  RequestProjectAppPictureUploadUrlInput: Types.RequestProjectAppPictureUploadUrlInput;
847
851
  RequestProjectPictureUploadUrlInput: Types.RequestProjectPictureUploadUrlInput;
852
+ RequestProjectSyncUploadUrlInput: Types.RequestProjectSyncUploadUrlInput;
848
853
  RequestUserPictureUploadUrlInput: Types.RequestUserPictureUploadUrlInput;
849
854
  ResendVerificationInput: Types.ResendVerificationInput;
850
855
  ResendVerificationResponse: Types.ResendVerificationResponse;
@@ -878,6 +883,7 @@ export type ResolversParentTypes = ResolversObject<{
878
883
  String: Types.Scalars['String']['output'];
879
884
  SyncProjectInput: Types.SyncProjectInput;
880
885
  SyncProjectResult: Types.SyncProjectResult;
886
+ SyncProjectSourceInput: Types.SyncProjectSourceInput;
881
887
  Tag: Types.Tag;
882
888
  TagCdmInput: Types.TagCdmInput;
883
889
  TagPage: Types.TagPage;
@@ -1839,6 +1845,12 @@ export type MutationResolvers<
1839
1845
  ContextType,
1840
1846
  RequireFields<Types.MutationRequestProjectPictureUploadUrlArgs, 'input'>
1841
1847
  >;
1848
+ requestProjectSyncUploadUrl?: Resolver<
1849
+ ResolversTypes['ProjectSyncUploadUrl'],
1850
+ ParentType,
1851
+ ContextType,
1852
+ RequireFields<Types.MutationRequestProjectSyncUploadUrlArgs, 'id' | 'input' | 'scope'>
1853
+ >;
1842
1854
  requestUserPictureUploadUrl?: Resolver<
1843
1855
  ResolversTypes['UploadUrl'],
1844
1856
  ParentType,
@@ -2733,6 +2745,18 @@ export type ProjectSyncJobPageResolvers<
2733
2745
  __isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
2734
2746
  }>;
2735
2747
 
2748
+ export type ProjectSyncUploadUrlResolvers<
2749
+ ContextType = any,
2750
+ ParentType extends ResolversParentTypes['ProjectSyncUploadUrl'] =
2751
+ ResolversParentTypes['ProjectSyncUploadUrl'],
2752
+ > = ResolversObject<{
2753
+ expiresAt?: Resolver<ResolversTypes['Date'], ParentType, ContextType>;
2754
+ headers?: Resolver<Array<ResolversTypes['UploadUrlHeader']>, ParentType, ContextType>;
2755
+ method?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
2756
+ uploadId?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
2757
+ url?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
2758
+ }>;
2759
+
2736
2760
  export type ProjectTagResolvers<
2737
2761
  ContextType = any,
2738
2762
  ParentType extends ResolversParentTypes['ProjectTag'] = ResolversParentTypes['ProjectTag'],
@@ -3760,6 +3784,7 @@ export type Resolvers<ContextType = any> = ResolversObject<{
3760
3784
  ProjectRolePermission?: ProjectRolePermissionResolvers<ContextType>;
3761
3785
  ProjectSyncJob?: ProjectSyncJobResolvers<ContextType>;
3762
3786
  ProjectSyncJobPage?: ProjectSyncJobPageResolvers<ContextType>;
3787
+ ProjectSyncUploadUrl?: ProjectSyncUploadUrlResolvers<ContextType>;
3763
3788
  ProjectTag?: ProjectTagResolvers<ContextType>;
3764
3789
  ProjectUser?: ProjectUserResolvers<ContextType>;
3765
3790
  ProjectUserApiKey?: ProjectUserApiKeyResolvers<ContextType>;
@@ -1191,6 +1191,19 @@ export type Mutation = {
1191
1191
  * is recorded against the project.
1192
1192
  */
1193
1193
  requestProjectPictureUploadUrl: UploadUrl;
1194
+ /**
1195
+ * Ask for a URL to upload a CDM import document directly to storage, so it can be
1196
+ * imported without passing through this API's request body (and its size limit).
1197
+ *
1198
+ * Requires Project sync job update permission in the given project scope, like
1199
+ * `startProjectSync`. The server derives the storage key from the project and a
1200
+ * server-minted `uploadId`; the client never supplies a path. The URL commits to exactly
1201
+ * `input.contentLength` bytes of `application/json`, up to `CDM_UPLOAD_MAX_BYTES`.
1202
+ *
1203
+ * PUT the file, then call `startProjectSync` with `input.source.uploadId`. An upload
1204
+ * that is never started is expired by the storage lifecycle rule.
1205
+ */
1206
+ requestProjectSyncUploadUrl: ProjectSyncUploadUrl;
1194
1207
  /**
1195
1208
  * Ask for a URL to upload another user's picture directly to storage.
1196
1209
  *
@@ -1519,6 +1532,12 @@ export type MutationRequestProjectPictureUploadUrlArgs = {
1519
1532
  input: RequestProjectPictureUploadUrlInput;
1520
1533
  };
1521
1534
 
1535
+ export type MutationRequestProjectSyncUploadUrlArgs = {
1536
+ id: Scalars['ID']['input'];
1537
+ input: RequestProjectSyncUploadUrlInput;
1538
+ scope: Scope;
1539
+ };
1540
+
1522
1541
  export type MutationRequestUserPictureUploadUrlArgs = {
1523
1542
  input: RequestUserPictureUploadUrlInput;
1524
1543
  };
@@ -2382,6 +2401,28 @@ export enum ProjectSyncJobStatus {
2382
2401
  Running = 'RUNNING',
2383
2402
  }
2384
2403
 
2404
+ /**
2405
+ * A bounded, time-limited URL to PUT a CDM import document to, and the id to start the
2406
+ * import from. Same commitments as `UploadUrl`: exactly `contentLength` bytes of exactly
2407
+ * `contentType`, at a path derived on the server from the project, until `expiresAt`.
2408
+ */
2409
+ export type ProjectSyncUploadUrl = {
2410
+ __typename?: 'ProjectSyncUploadUrl';
2411
+ /** Instant after which the store refuses the URL. */
2412
+ expiresAt: Scalars['Date']['output'];
2413
+ /** Headers the client must set verbatim. `Content-Length` is deliberately absent. */
2414
+ headers: Array<UploadUrlHeader>;
2415
+ /** HTTP method the client must use. Always PUT today. */
2416
+ method: Scalars['String']['output'];
2417
+ /** Pass as `source.uploadId` to `startProjectSync`. */
2418
+ uploadId: Scalars['ID']['output'];
2419
+ /**
2420
+ * Absolute for object stores; application-relative for targets this API serves
2421
+ * itself. Resolve it against the API origin before using it.
2422
+ */
2423
+ url: Scalars['String']['output'];
2424
+ };
2425
+
2385
2426
  export type ProjectTag = Auditable & {
2386
2427
  __typename?: 'ProjectTag';
2387
2428
  createdAt: Scalars['Date']['output'];
@@ -3144,6 +3185,16 @@ export type RequestProjectPictureUploadUrlInput = {
3144
3185
  scope: Scope;
3145
3186
  };
3146
3187
 
3188
+ export type RequestProjectSyncUploadUrlInput = {
3189
+ /**
3190
+ * Exact byte length of the CDM JSON file the client will PUT. The URL commits to it,
3191
+ * and it may not exceed `CDM_UPLOAD_MAX_BYTES` (default 64 MiB).
3192
+ */
3193
+ contentLength: Scalars['Int']['input'];
3194
+ /** Defaults to `application/json`, the only type accepted. */
3195
+ contentType?: InputMaybe<Scalars['String']['input']>;
3196
+ };
3197
+
3147
3198
  export type RequestUserPictureUploadUrlInput = {
3148
3199
  /**
3149
3200
  * Exact byte length the client will send. Validated against the upload policy
@@ -3499,6 +3550,13 @@ export type StartProjectExportInput = {
3499
3550
  /**
3500
3551
  * Versioned canonical project document (CDM) for export/import: roles, users,
3501
3552
  * resources, permissions, groups, and tags scoped to one project.
3553
+ *
3554
+ * Two shapes. **Inline**: `version`, `roles` and `users` are required and the document is
3555
+ * the input. **By reference**: `source` is set, `mode` still says how to apply it, and
3556
+ * `version` is optional and the entity arrays (`roles`, `users`, `resources`,
3557
+ * `permissions`, `groups`, `tags`) must be absent: the document is the file uploaded
3558
+ * through `requestProjectSyncUploadUrl`, and the worker validates it, so a schema error or
3559
+ * an over-limit entity count surfaces as a `FAILED` job, not as an error on the mutation.
3502
3560
  */
3503
3561
  export type SyncProjectInput = {
3504
3562
  groups?: InputMaybe<Array<GroupCdmInput>>;
@@ -3506,10 +3564,19 @@ export type SyncProjectInput = {
3506
3564
  mode: CdmModeInput;
3507
3565
  permissions?: InputMaybe<Array<PermissionCdmInput>>;
3508
3566
  resources?: InputMaybe<Array<ResourceCdmInput>>;
3509
- roles: Array<RoleCdmInput>;
3567
+ /** Required inline; must be absent with `source`. */
3568
+ roles?: InputMaybe<Array<RoleCdmInput>>;
3569
+ /**
3570
+ * Import the document uploaded through `requestProjectSyncUploadUrl` instead of sending
3571
+ * it inline. The entity arrays must then be absent, and `mode` (and `version`, if
3572
+ * given) must match the uploaded document.
3573
+ */
3574
+ source?: InputMaybe<SyncProjectSourceInput>;
3510
3575
  tags?: InputMaybe<Array<TagCdmInput>>;
3511
- users: Array<UserCdmInput>;
3512
- version: Scalars['Int']['input'];
3576
+ /** Required inline; must be absent with `source`. */
3577
+ users?: InputMaybe<Array<UserCdmInput>>;
3578
+ /** Required inline; optional with `source`, where the uploaded document carries it. */
3579
+ version?: InputMaybe<Scalars['Int']['input']>;
3513
3580
  };
3514
3581
 
3515
3582
  /** Counters and warnings from a completed CDM import. */
@@ -3539,6 +3606,24 @@ export type SyncProjectResult = {
3539
3606
  warnings: Array<Scalars['String']['output']>;
3540
3607
  };
3541
3608
 
3609
+ /**
3610
+ * Where the CDM document of a by-reference import is: an upload made through
3611
+ * `requestProjectSyncUploadUrl`. See `SyncProjectInput.source`.
3612
+ */
3613
+ export type SyncProjectSourceInput = {
3614
+ /**
3615
+ * How many entities (roles, users, resources, permissions, groups and tags) the
3616
+ * uploaded document holds. A hint, recorded for the job list and never trusted: the
3617
+ * worker counts the document itself.
3618
+ */
3619
+ entityCount?: InputMaybe<Scalars['Int']['input']>;
3620
+ /**
3621
+ * The `uploadId` returned by `requestProjectSyncUploadUrl`. The server derives the
3622
+ * storage key from the project and this id; the client never supplies a path.
3623
+ */
3624
+ uploadId: Scalars['ID']['input'];
3625
+ };
3626
+
3542
3627
  export type Tag = Auditable & {
3543
3628
  __typename?: 'Tag';
3544
3629
  color: Scalars['String']['output'];
@@ -0,0 +1,16 @@
1
+ mutation RequestProjectSyncUploadUrl(
2
+ $id: ID!
3
+ $scope: Scope!
4
+ $input: RequestProjectSyncUploadUrlInput!
5
+ ) {
6
+ requestProjectSyncUploadUrl(id: $id, scope: $scope, input: $input) {
7
+ uploadId
8
+ url
9
+ method
10
+ expiresAt
11
+ headers {
12
+ name
13
+ value
14
+ }
15
+ }
16
+ }
@@ -0,0 +1,9 @@
1
+ input RequestProjectSyncUploadUrlInput {
2
+ """
3
+ Exact byte length of the CDM JSON file the client will PUT. The URL commits to it,
4
+ and it may not exceed `CDM_UPLOAD_MAX_BYTES` (default 64 MiB).
5
+ """
6
+ contentLength: Int!
7
+ "Defaults to `application/json`, the only type accepted."
8
+ contentType: String
9
+ }
@@ -153,18 +153,52 @@ input UserCdmInput {
153
153
  metadata: JSON
154
154
  }
155
155
 
156
+ """
157
+ Where the CDM document of a by-reference import is: an upload made through
158
+ `requestProjectSyncUploadUrl`. See `SyncProjectInput.source`.
159
+ """
160
+ input SyncProjectSourceInput {
161
+ """
162
+ The `uploadId` returned by `requestProjectSyncUploadUrl`. The server derives the
163
+ storage key from the project and this id; the client never supplies a path.
164
+ """
165
+ uploadId: ID!
166
+ """
167
+ How many entities (roles, users, resources, permissions, groups and tags) the
168
+ uploaded document holds. A hint, recorded for the job list and never trusted: the
169
+ worker counts the document itself.
170
+ """
171
+ entityCount: Int
172
+ }
173
+
156
174
  """
157
175
  Versioned canonical project document (CDM) for export/import: roles, users,
158
176
  resources, permissions, groups, and tags scoped to one project.
177
+
178
+ Two shapes. **Inline**: `version`, `roles` and `users` are required and the document is
179
+ the input. **By reference**: `source` is set, `mode` still says how to apply it, and
180
+ `version` is optional and the entity arrays (`roles`, `users`, `resources`,
181
+ `permissions`, `groups`, `tags`) must be absent: the document is the file uploaded
182
+ through `requestProjectSyncUploadUrl`, and the worker validates it, so a schema error or
183
+ an over-limit entity count surfaces as a `FAILED` job, not as an error on the mutation.
159
184
  """
160
185
  input SyncProjectInput {
161
- version: Int!
186
+ "Required inline; optional with `source`, where the uploaded document carries it."
187
+ version: Int
162
188
  id: String
163
189
  mode: CdmModeInput!
164
- roles: [RoleCdmInput!]!
165
- users: [UserCdmInput!]!
190
+ "Required inline; must be absent with `source`."
191
+ roles: [RoleCdmInput!]
192
+ "Required inline; must be absent with `source`."
193
+ users: [UserCdmInput!]
166
194
  resources: [ResourceCdmInput!]
167
195
  permissions: [PermissionCdmInput!]
168
196
  groups: [GroupCdmInput!]
169
197
  tags: [TagCdmInput!]
198
+ """
199
+ Import the document uploaded through `requestProjectSyncUploadUrl` instead of sending
200
+ it inline. The entity arrays must then be absent, and `mode` (and `version`, if
201
+ given) must match the uploaded document.
202
+ """
203
+ source: SyncProjectSourceInput
170
204
  }
@@ -0,0 +1,19 @@
1
+ extend type Mutation {
2
+ """
3
+ Ask for a URL to upload a CDM import document directly to storage, so it can be
4
+ imported without passing through this API's request body (and its size limit).
5
+
6
+ Requires Project sync job update permission in the given project scope, like
7
+ `startProjectSync`. The server derives the storage key from the project and a
8
+ server-minted `uploadId`; the client never supplies a path. The URL commits to exactly
9
+ `input.contentLength` bytes of `application/json`, up to `CDM_UPLOAD_MAX_BYTES`.
10
+
11
+ PUT the file, then call `startProjectSync` with `input.source.uploadId`. An upload
12
+ that is never started is expired by the storage lifecycle rule.
13
+ """
14
+ requestProjectSyncUploadUrl(
15
+ id: ID!
16
+ scope: Scope!
17
+ input: RequestProjectSyncUploadUrlInput!
18
+ ): ProjectSyncUploadUrl!
19
+ }
@@ -0,0 +1,24 @@
1
+ """
2
+ A bounded, time-limited URL to PUT a CDM import document to, and the id to start the
3
+ import from. Same commitments as `UploadUrl`: exactly `contentLength` bytes of exactly
4
+ `contentType`, at a path derived on the server from the project, until `expiresAt`.
5
+ """
6
+ type ProjectSyncUploadUrl {
7
+ "Pass as `source.uploadId` to `startProjectSync`."
8
+ uploadId: ID!
9
+
10
+ """
11
+ Absolute for object stores; application-relative for targets this API serves
12
+ itself. Resolve it against the API origin before using it.
13
+ """
14
+ url: String!
15
+
16
+ "HTTP method the client must use. Always PUT today."
17
+ method: String!
18
+
19
+ "Headers the client must set verbatim. `Content-Length` is deliberately absent."
20
+ headers: [UploadUrlHeader!]!
21
+
22
+ "Instant after which the store refuses the URL."
23
+ expiresAt: Date!
24
+ }
@@ -50,10 +50,11 @@ describe('operation documents', () => {
50
50
  // project-app pictures (eight operation documents).
51
51
  // 135 after project OAuth connections: get/upsert/clear (three operation documents).
52
52
  // 136 after closed-install: AuthSignupPolicyDocument (publicSignupEnabled, bootstrapOpen).
53
+ // 137 after CDM imports by reference: RequestProjectSyncUploadUrlDocument.
53
54
  // Updating this number is the point of the pin, not a nuisance: every change
54
55
  // to it should be a line in a commit message.
55
56
  it('finds every document under src/operations', () => {
56
- expect(files).toHaveLength(136);
57
+ expect(files).toHaveLength(137);
57
58
  });
58
59
 
59
60
  it.each(files.map((f) => [relative(process.cwd(), f), f]))('%s validates', (_label, file) => {