@grantjs/schema 1.18.11 → 1.20.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.18.11",
3
+ "version": "1.20.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -151,6 +151,8 @@ export const EVENT_TYPES = [
151
151
  'user.updated',
152
152
  'user.deleted',
153
153
  'project.user_updated',
154
+ 'project.user_email_changed',
155
+ 'project.user_password_set',
154
156
  'api_key.deleted',
155
157
  'tag.created',
156
158
  'tag.updated',
@@ -226,6 +228,9 @@ export const EVENT_CATALOG: Readonly<Record<EventType, EventCatalogEntry>> = {
226
228
  'user.updated': webhookOnly('membership'),
227
229
  'user.deleted': webhookOnly('membership'),
228
230
  'project.user_updated': webhookOnly('membership'),
231
+ 'project.user_email_changed': webhookOnly('membership'),
232
+ // Every project-credential write that changes the stored hash, any source. data.after = { projectId, userId, source }: never a hash or a password.
233
+ 'project.user_password_set': webhookOnly('membership'),
229
234
  'api_key.deleted': webhookOnly('security'),
230
235
  'tag.created': webhookOnly('iam'),
231
236
  'tag.updated': webhookOnly('iam'),
@@ -1310,6 +1310,16 @@ export type UpsertProjectOAuthConnectionMutation = {
1310
1310
  };
1311
1311
  };
1312
1312
 
1313
+ export type ExportProjectUserCredentialsQueryVariables = Exact<{
1314
+ input: Types.ExportProjectUserCredentialsInput;
1315
+ }>;
1316
+
1317
+ export type ExportProjectUserCredentialsQuery = {
1318
+ exportProjectUserCredentials: {
1319
+ users: Array<{ userId: string; password: { algorithm: string; hash: string } | null }>;
1320
+ };
1321
+ };
1322
+
1313
1323
  export type CancelProjectSyncMutationVariables = Exact<{
1314
1324
  id: string | number;
1315
1325
  scope: Types.Scope;
@@ -2174,6 +2184,34 @@ export type GetUsersListQuery = {
2174
2184
  };
2175
2185
  };
2176
2186
 
2187
+ export type SetProjectUserEmailMutationVariables = Exact<{
2188
+ input: Types.SetProjectUserEmailInput;
2189
+ }>;
2190
+
2191
+ export type SetProjectUserEmailMutation = {
2192
+ setProjectUserEmail: {
2193
+ id: string;
2194
+ name: string;
2195
+ metadata: Record<string, unknown>;
2196
+ createdAt: Date;
2197
+ updatedAt: Date;
2198
+ };
2199
+ };
2200
+
2201
+ export type SetProjectUserPasswordMutationVariables = Exact<{
2202
+ input: Types.SetProjectUserPasswordInput;
2203
+ }>;
2204
+
2205
+ export type SetProjectUserPasswordMutation = {
2206
+ setProjectUserPassword: {
2207
+ id: string;
2208
+ name: string;
2209
+ metadata: Record<string, unknown>;
2210
+ createdAt: Date;
2211
+ updatedAt: Date;
2212
+ };
2213
+ };
2214
+
2177
2215
  export type UpdateUserMutationVariables = Exact<{
2178
2216
  id: string | number;
2179
2217
  input: Types.UpdateUserInput;
@@ -7453,6 +7491,74 @@ export const UpsertProjectOAuthConnectionDocument = {
7453
7491
  UpsertProjectOAuthConnectionMutation,
7454
7492
  UpsertProjectOAuthConnectionMutationVariables
7455
7493
  >;
7494
+ export const ExportProjectUserCredentialsDocument = {
7495
+ kind: 'Document',
7496
+ definitions: [
7497
+ {
7498
+ kind: 'OperationDefinition',
7499
+ operation: 'query',
7500
+ name: { kind: 'Name', value: 'ExportProjectUserCredentials' },
7501
+ variableDefinitions: [
7502
+ {
7503
+ kind: 'VariableDefinition',
7504
+ variable: { kind: 'Variable', name: { kind: 'Name', value: 'input' } },
7505
+ type: {
7506
+ kind: 'NonNullType',
7507
+ type: {
7508
+ kind: 'NamedType',
7509
+ name: { kind: 'Name', value: 'ExportProjectUserCredentialsInput' },
7510
+ },
7511
+ },
7512
+ },
7513
+ ],
7514
+ selectionSet: {
7515
+ kind: 'SelectionSet',
7516
+ selections: [
7517
+ {
7518
+ kind: 'Field',
7519
+ name: { kind: 'Name', value: 'exportProjectUserCredentials' },
7520
+ arguments: [
7521
+ {
7522
+ kind: 'Argument',
7523
+ name: { kind: 'Name', value: 'input' },
7524
+ value: { kind: 'Variable', name: { kind: 'Name', value: 'input' } },
7525
+ },
7526
+ ],
7527
+ selectionSet: {
7528
+ kind: 'SelectionSet',
7529
+ selections: [
7530
+ {
7531
+ kind: 'Field',
7532
+ name: { kind: 'Name', value: 'users' },
7533
+ selectionSet: {
7534
+ kind: 'SelectionSet',
7535
+ selections: [
7536
+ { kind: 'Field', name: { kind: 'Name', value: 'userId' } },
7537
+ {
7538
+ kind: 'Field',
7539
+ name: { kind: 'Name', value: 'password' },
7540
+ selectionSet: {
7541
+ kind: 'SelectionSet',
7542
+ selections: [
7543
+ { kind: 'Field', name: { kind: 'Name', value: 'algorithm' } },
7544
+ { kind: 'Field', name: { kind: 'Name', value: 'hash' } },
7545
+ ],
7546
+ },
7547
+ },
7548
+ ],
7549
+ },
7550
+ },
7551
+ ],
7552
+ },
7553
+ },
7554
+ ],
7555
+ },
7556
+ },
7557
+ ],
7558
+ } as unknown as DocumentNode<
7559
+ ExportProjectUserCredentialsQuery,
7560
+ ExportProjectUserCredentialsQueryVariables
7561
+ >;
7456
7562
  export const CancelProjectSyncDocument = {
7457
7563
  kind: 'Document',
7458
7564
  definitions: [
@@ -11155,6 +11261,104 @@ export const GetUsersListDocument = {
11155
11261
  },
11156
11262
  ],
11157
11263
  } as unknown as DocumentNode<GetUsersListQuery, GetUsersListQueryVariables>;
11264
+ export const SetProjectUserEmailDocument = {
11265
+ kind: 'Document',
11266
+ definitions: [
11267
+ {
11268
+ kind: 'OperationDefinition',
11269
+ operation: 'mutation',
11270
+ name: { kind: 'Name', value: 'SetProjectUserEmail' },
11271
+ variableDefinitions: [
11272
+ {
11273
+ kind: 'VariableDefinition',
11274
+ variable: { kind: 'Variable', name: { kind: 'Name', value: 'input' } },
11275
+ type: {
11276
+ kind: 'NonNullType',
11277
+ type: { kind: 'NamedType', name: { kind: 'Name', value: 'SetProjectUserEmailInput' } },
11278
+ },
11279
+ },
11280
+ ],
11281
+ selectionSet: {
11282
+ kind: 'SelectionSet',
11283
+ selections: [
11284
+ {
11285
+ kind: 'Field',
11286
+ name: { kind: 'Name', value: 'setProjectUserEmail' },
11287
+ arguments: [
11288
+ {
11289
+ kind: 'Argument',
11290
+ name: { kind: 'Name', value: 'input' },
11291
+ value: { kind: 'Variable', name: { kind: 'Name', value: 'input' } },
11292
+ },
11293
+ ],
11294
+ selectionSet: {
11295
+ kind: 'SelectionSet',
11296
+ selections: [
11297
+ { kind: 'Field', name: { kind: 'Name', value: 'id' } },
11298
+ { kind: 'Field', name: { kind: 'Name', value: 'name' } },
11299
+ { kind: 'Field', name: { kind: 'Name', value: 'metadata' } },
11300
+ { kind: 'Field', name: { kind: 'Name', value: 'createdAt' } },
11301
+ { kind: 'Field', name: { kind: 'Name', value: 'updatedAt' } },
11302
+ ],
11303
+ },
11304
+ },
11305
+ ],
11306
+ },
11307
+ },
11308
+ ],
11309
+ } as unknown as DocumentNode<SetProjectUserEmailMutation, SetProjectUserEmailMutationVariables>;
11310
+ export const SetProjectUserPasswordDocument = {
11311
+ kind: 'Document',
11312
+ definitions: [
11313
+ {
11314
+ kind: 'OperationDefinition',
11315
+ operation: 'mutation',
11316
+ name: { kind: 'Name', value: 'SetProjectUserPassword' },
11317
+ variableDefinitions: [
11318
+ {
11319
+ kind: 'VariableDefinition',
11320
+ variable: { kind: 'Variable', name: { kind: 'Name', value: 'input' } },
11321
+ type: {
11322
+ kind: 'NonNullType',
11323
+ type: {
11324
+ kind: 'NamedType',
11325
+ name: { kind: 'Name', value: 'SetProjectUserPasswordInput' },
11326
+ },
11327
+ },
11328
+ },
11329
+ ],
11330
+ selectionSet: {
11331
+ kind: 'SelectionSet',
11332
+ selections: [
11333
+ {
11334
+ kind: 'Field',
11335
+ name: { kind: 'Name', value: 'setProjectUserPassword' },
11336
+ arguments: [
11337
+ {
11338
+ kind: 'Argument',
11339
+ name: { kind: 'Name', value: 'input' },
11340
+ value: { kind: 'Variable', name: { kind: 'Name', value: 'input' } },
11341
+ },
11342
+ ],
11343
+ selectionSet: {
11344
+ kind: 'SelectionSet',
11345
+ selections: [
11346
+ { kind: 'Field', name: { kind: 'Name', value: 'id' } },
11347
+ { kind: 'Field', name: { kind: 'Name', value: 'name' } },
11348
+ { kind: 'Field', name: { kind: 'Name', value: 'metadata' } },
11349
+ { kind: 'Field', name: { kind: 'Name', value: 'createdAt' } },
11350
+ { kind: 'Field', name: { kind: 'Name', value: 'updatedAt' } },
11351
+ ],
11352
+ },
11353
+ },
11354
+ ],
11355
+ },
11356
+ },
11357
+ ],
11358
+ } as unknown as DocumentNode<
11359
+ SetProjectUserPasswordMutation,
11360
+ SetProjectUserPasswordMutationVariables
11361
+ >;
11158
11362
  export const UpdateUserDocument = {
11159
11363
  kind: 'Document',
11160
11364
  definitions: [
@@ -271,6 +271,7 @@ export type ResolversTypes = ResolversObject<{
271
271
  CreateUserSessionInput: Types.CreateUserSessionInput;
272
272
  CreateWebhookSubscriptionMutationInput: Types.CreateWebhookSubscriptionMutationInput;
273
273
  CredentialExportData: ResolverTypeWrapper<Types.CredentialExportData>;
274
+ CredentialKind: Types.CredentialKind;
274
275
  Date: ResolverTypeWrapper<Types.Scalars['Date']['output']>;
275
276
  DeleteApiKeyInput: Types.DeleteApiKeyInput;
276
277
  DeleteMyAccountsInput: Types.DeleteMyAccountsInput;
@@ -281,6 +282,9 @@ export type ResolversTypes = ResolversObject<{
281
282
  EmailVerificationProofType: Types.EmailVerificationProofType;
282
283
  ExchangeApiKeyInput: Types.ExchangeApiKeyInput;
283
284
  ExchangeApiKeyResult: ResolverTypeWrapper<Types.ExchangeApiKeyResult>;
285
+ ExportProjectUserCredentialsInput: Types.ExportProjectUserCredentialsInput;
286
+ ExportedPasswordCredential: ResolverTypeWrapper<Types.ExportedPasswordCredential>;
287
+ ExportedProjectUserCredential: ResolverTypeWrapper<Types.ExportedProjectUserCredential>;
284
288
  GenerateMyMfaRecoveryCodesInput: Types.GenerateMyMfaRecoveryCodesInput;
285
289
  GetUserAuthenticationMethodsInput: Types.GetUserAuthenticationMethodsInput;
286
290
  GetUserSessionsInput: Types.GetUserSessionsInput;
@@ -385,7 +389,9 @@ export type ResolversTypes = ResolversObject<{
385
389
  ProjectTag: ResolverTypeWrapper<Types.ProjectTag>;
386
390
  ProjectUser: ResolverTypeWrapper<Types.ProjectUser>;
387
391
  ProjectUserApiKey: ResolverTypeWrapper<Types.ProjectUserApiKey>;
392
+ ProjectUserCredentialExport: ResolverTypeWrapper<Types.ProjectUserCredentialExport>;
388
393
  ProjectUserGroup: ResolverTypeWrapper<Types.ProjectUserGroup>;
394
+ ProjectUserPasswordCredential: ResolverTypeWrapper<Types.ProjectUserPasswordCredential>;
389
395
  ProjectUserPermission: ResolverTypeWrapper<Types.ProjectUserPermission>;
390
396
  Query: ResolverTypeWrapper<Record<PropertyKey, never>>;
391
397
  QueryAccountProjectApiKeysInput: Types.QueryAccountProjectApiKeysInput;
@@ -501,6 +507,8 @@ export type ResolversTypes = ResolversObject<{
501
507
  SessionExportData: ResolverTypeWrapper<Types.SessionExportData>;
502
508
  SetMyNotificationPreferenceInput: Types.SetMyNotificationPreferenceInput;
503
509
  SetMyPrimaryMfaDeviceInput: Types.SetMyPrimaryMfaDeviceInput;
510
+ SetProjectUserEmailInput: Types.SetProjectUserEmailInput;
511
+ SetProjectUserPasswordInput: Types.SetProjectUserPasswordInput;
504
512
  SigningKey: ResolverTypeWrapper<Types.SigningKey>;
505
513
  SortOrder: Types.SortOrder;
506
514
  StartProjectExportInput: Types.StartProjectExportInput;
@@ -691,6 +699,9 @@ export type ResolversParentTypes = ResolversObject<{
691
699
  EmailVerificationProofInput: Types.EmailVerificationProofInput;
692
700
  ExchangeApiKeyInput: Types.ExchangeApiKeyInput;
693
701
  ExchangeApiKeyResult: Types.ExchangeApiKeyResult;
702
+ ExportProjectUserCredentialsInput: Types.ExportProjectUserCredentialsInput;
703
+ ExportedPasswordCredential: Types.ExportedPasswordCredential;
704
+ ExportedProjectUserCredential: Types.ExportedProjectUserCredential;
694
705
  GenerateMyMfaRecoveryCodesInput: Types.GenerateMyMfaRecoveryCodesInput;
695
706
  GetUserAuthenticationMethodsInput: Types.GetUserAuthenticationMethodsInput;
696
707
  GetUserSessionsInput: Types.GetUserSessionsInput;
@@ -771,7 +782,9 @@ export type ResolversParentTypes = ResolversObject<{
771
782
  ProjectTag: Types.ProjectTag;
772
783
  ProjectUser: Types.ProjectUser;
773
784
  ProjectUserApiKey: Types.ProjectUserApiKey;
785
+ ProjectUserCredentialExport: Types.ProjectUserCredentialExport;
774
786
  ProjectUserGroup: Types.ProjectUserGroup;
787
+ ProjectUserPasswordCredential: Types.ProjectUserPasswordCredential;
775
788
  ProjectUserPermission: Types.ProjectUserPermission;
776
789
  Query: Record<PropertyKey, never>;
777
790
  QueryAccountProjectApiKeysInput: Types.QueryAccountProjectApiKeysInput;
@@ -883,6 +896,8 @@ export type ResolversParentTypes = ResolversObject<{
883
896
  SessionExportData: Types.SessionExportData;
884
897
  SetMyNotificationPreferenceInput: Types.SetMyNotificationPreferenceInput;
885
898
  SetMyPrimaryMfaDeviceInput: Types.SetMyPrimaryMfaDeviceInput;
899
+ SetProjectUserEmailInput: Types.SetProjectUserEmailInput;
900
+ SetProjectUserPasswordInput: Types.SetProjectUserPasswordInput;
886
901
  SigningKey: Types.SigningKey;
887
902
  StartProjectExportInput: Types.StartProjectExportInput;
888
903
  String: Types.Scalars['String']['output'];
@@ -1323,6 +1338,28 @@ export type ExchangeApiKeyResultResolvers<
1323
1338
  expiresIn?: Resolver<ResolversTypes['Int'], ParentType, ContextType>;
1324
1339
  }>;
1325
1340
 
1341
+ export type ExportedPasswordCredentialResolvers<
1342
+ ContextType = any,
1343
+ ParentType extends ResolversParentTypes['ExportedPasswordCredential'] =
1344
+ ResolversParentTypes['ExportedPasswordCredential'],
1345
+ > = ResolversObject<{
1346
+ algorithm?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1347
+ hash?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1348
+ }>;
1349
+
1350
+ export type ExportedProjectUserCredentialResolvers<
1351
+ ContextType = any,
1352
+ ParentType extends ResolversParentTypes['ExportedProjectUserCredential'] =
1353
+ ResolversParentTypes['ExportedProjectUserCredential'],
1354
+ > = ResolversObject<{
1355
+ password?: Resolver<
1356
+ Types.Maybe<ResolversTypes['ExportedPasswordCredential']>,
1357
+ ParentType,
1358
+ ContextType
1359
+ >;
1360
+ userId?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
1361
+ }>;
1362
+
1326
1363
  export type GroupResolvers<
1327
1364
  ContextType = any,
1328
1365
  ParentType extends ResolversParentTypes['Group'] = ResolversParentTypes['Group'],
@@ -1960,6 +1997,18 @@ export type MutationResolvers<
1960
1997
  ContextType,
1961
1998
  RequireFields<Types.MutationSetMyPrimaryMfaDeviceArgs, 'input'>
1962
1999
  >;
2000
+ setProjectUserEmail?: Resolver<
2001
+ ResolversTypes['User'],
2002
+ ParentType,
2003
+ ContextType,
2004
+ RequireFields<Types.MutationSetProjectUserEmailArgs, 'input'>
2005
+ >;
2006
+ setProjectUserPassword?: Resolver<
2007
+ ResolversTypes['User'],
2008
+ ParentType,
2009
+ ContextType,
2010
+ RequireFields<Types.MutationSetProjectUserPasswordArgs, 'input'>
2011
+ >;
1963
2012
  setupMfa?: Resolver<ResolversTypes['MfaSetupResponse'], ParentType, ContextType>;
1964
2013
  startProjectExport?: Resolver<
1965
2014
  ResolversTypes['ProjectSyncJob'],
@@ -2838,6 +2887,14 @@ export type ProjectUserApiKeyResolvers<
2838
2887
  __isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
2839
2888
  }>;
2840
2889
 
2890
+ export type ProjectUserCredentialExportResolvers<
2891
+ ContextType = any,
2892
+ ParentType extends ResolversParentTypes['ProjectUserCredentialExport'] =
2893
+ ResolversParentTypes['ProjectUserCredentialExport'],
2894
+ > = ResolversObject<{
2895
+ users?: Resolver<Array<ResolversTypes['ExportedProjectUserCredential']>, ParentType, ContextType>;
2896
+ }>;
2897
+
2841
2898
  export type ProjectUserGroupResolvers<
2842
2899
  ContextType = any,
2843
2900
  ParentType extends ResolversParentTypes['ProjectUserGroup'] =
@@ -2853,6 +2910,16 @@ export type ProjectUserGroupResolvers<
2853
2910
  __isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
2854
2911
  }>;
2855
2912
 
2913
+ export type ProjectUserPasswordCredentialResolvers<
2914
+ ContextType = any,
2915
+ ParentType extends ResolversParentTypes['ProjectUserPasswordCredential'] =
2916
+ ResolversParentTypes['ProjectUserPasswordCredential'],
2917
+ > = ResolversObject<{
2918
+ fingerprint?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
2919
+ source?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
2920
+ updatedAt?: Resolver<ResolversTypes['Date'], ParentType, ContextType>;
2921
+ }>;
2922
+
2856
2923
  export type ProjectUserPermissionResolvers<
2857
2924
  ContextType = any,
2858
2925
  ParentType extends ResolversParentTypes['ProjectUserPermission'] =
@@ -2880,6 +2947,12 @@ export type QueryResolvers<
2880
2947
  RequireFields<Types.QueryApiKeysArgs, 'scope'>
2881
2948
  >;
2882
2949
  authSignupPolicy?: Resolver<ResolversTypes['AuthSignupPolicy'], ParentType, ContextType>;
2950
+ exportProjectUserCredentials?: Resolver<
2951
+ ResolversTypes['ProjectUserCredentialExport'],
2952
+ ParentType,
2953
+ ContextType,
2954
+ RequireFields<Types.QueryExportProjectUserCredentialsArgs, 'input'>
2955
+ >;
2883
2956
  groups?: Resolver<
2884
2957
  ResolversTypes['GroupPage'],
2885
2958
  ParentType,
@@ -3437,6 +3510,11 @@ export type UserResolvers<
3437
3510
  id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
3438
3511
  metadata?: Resolver<ResolversTypes['JSON'], ParentType, ContextType>;
3439
3512
  name?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
3513
+ passwordCredential?: Resolver<
3514
+ Types.Maybe<ResolversTypes['ProjectUserPasswordCredential']>,
3515
+ ParentType,
3516
+ ContextType
3517
+ >;
3440
3518
  permissionCount?: Resolver<ResolversTypes['Int'], ParentType, ContextType>;
3441
3519
  pictureUrl?: Resolver<Types.Maybe<ResolversTypes['String']>, ParentType, ContextType>;
3442
3520
  primaryTag?: Resolver<Types.Maybe<ResolversTypes['Tag']>, ParentType, ContextType>;
@@ -3758,6 +3836,8 @@ export type Resolvers<ContextType = any> = ResolversObject<{
3758
3836
  CredentialExportData?: CredentialExportDataResolvers<ContextType>;
3759
3837
  Date?: GraphQLScalarType;
3760
3838
  ExchangeApiKeyResult?: ExchangeApiKeyResultResolvers<ContextType>;
3839
+ ExportedPasswordCredential?: ExportedPasswordCredentialResolvers<ContextType>;
3840
+ ExportedProjectUserCredential?: ExportedProjectUserCredentialResolvers<ContextType>;
3761
3841
  Group?: GroupResolvers<ContextType>;
3762
3842
  GroupPage?: GroupPageResolvers<ContextType>;
3763
3843
  GroupPermission?: GroupPermissionResolvers<ContextType>;
@@ -3816,7 +3896,9 @@ export type Resolvers<ContextType = any> = ResolversObject<{
3816
3896
  ProjectTag?: ProjectTagResolvers<ContextType>;
3817
3897
  ProjectUser?: ProjectUserResolvers<ContextType>;
3818
3898
  ProjectUserApiKey?: ProjectUserApiKeyResolvers<ContextType>;
3899
+ ProjectUserCredentialExport?: ProjectUserCredentialExportResolvers<ContextType>;
3819
3900
  ProjectUserGroup?: ProjectUserGroupResolvers<ContextType>;
3901
+ ProjectUserPasswordCredential?: ProjectUserPasswordCredentialResolvers<ContextType>;
3820
3902
  ProjectUserPermission?: ProjectUserPermissionResolvers<ContextType>;
3821
3903
  Query?: QueryResolvers<ContextType>;
3822
3904
  RefreshSessionResponse?: RefreshSessionResponseResolvers<ContextType>;
@@ -757,6 +757,11 @@ export type CreateUserAuthenticationMethodInput = {
757
757
  };
758
758
 
759
759
  export type CreateUserInput = {
760
+ /**
761
+ * Optional. Project-scope create only. Stores an unverified Email authentication method.
762
+ * A provider can only be linked to one user account (no sharing), and a user can only have one method per provider (no duplicates).
763
+ */
764
+ email?: InputMaybe<Scalars['String']['input']>;
760
765
  groupIds?: InputMaybe<Array<Scalars['ID']['input']>>;
761
766
  metadata?: InputMaybe<Scalars['JSON']['input']>;
762
767
  name: Scalars['String']['input'];
@@ -803,6 +808,15 @@ export type CredentialExportData = {
803
808
  updatedAt: Scalars['Date']['output'];
804
809
  };
805
810
 
811
+ /**
812
+ * A kind of credential that can be exported. Extensible: a later kind is added here,
813
+ * not as a second export.
814
+ */
815
+ export enum CredentialKind {
816
+ /** The project password credential (bcrypt hash). */
817
+ Password = 'PASSWORD',
818
+ }
819
+
806
820
  export type DeleteApiKeyInput = {
807
821
  hardDelete?: InputMaybe<Scalars['Boolean']['input']>;
808
822
  id: Scalars['ID']['input'];
@@ -848,6 +862,31 @@ export type ExchangeApiKeyResult = {
848
862
  expiresIn: Scalars['Int']['output'];
849
863
  };
850
864
 
865
+ export type ExportProjectUserCredentialsInput = {
866
+ /** Credential kinds to export. Defaults to `[PASSWORD]`. */
867
+ kinds?: InputMaybe<Array<CredentialKind>>;
868
+ /** Project scope the members belong to. */
869
+ scope: Scope;
870
+ /** Project members to export. Every id must be a member of the project, otherwise the whole call fails with not found (no partial export). */
871
+ userIds: Array<Scalars['ID']['input']>;
872
+ };
873
+
874
+ /** A stored password hash in CDM shape. Secret-equivalent: handle like a credential. */
875
+ export type ExportedPasswordCredential = {
876
+ __typename?: 'ExportedPasswordCredential';
877
+ /** Hash algorithm, for example `bcrypt`. */
878
+ algorithm: Scalars['String']['output'];
879
+ /** The stored hash string. */
880
+ hash: Scalars['String']['output'];
881
+ };
882
+
883
+ export type ExportedProjectUserCredential = {
884
+ __typename?: 'ExportedProjectUserCredential';
885
+ /** `null` when the member has no project password credential. */
886
+ password?: Maybe<ExportedPasswordCredential>;
887
+ userId: Scalars['ID']['output'];
888
+ };
889
+
851
890
  export type GenerateMyMfaRecoveryCodesInput = {
852
891
  factorId?: InputMaybe<Scalars['ID']['input']>;
853
892
  };
@@ -1285,6 +1324,19 @@ export type Mutation = {
1285
1324
  setMyNotificationPreference: NotificationPreference;
1286
1325
  setMyPrimaryAuthenticationMethod: UserAuthenticationMethod;
1287
1326
  setMyPrimaryMfaDevice: MfaDevice;
1327
+ /**
1328
+ * Set or replace a project member's Email authentication method as unverified.
1329
+ * `project.user_email_changed` carries ids only, never the address.
1330
+ */
1331
+ setProjectUserEmail: User;
1332
+ /**
1333
+ * Set or replace a project member's password. Project scopes only: the operator supplies the
1334
+ * password, and the password policy is enforced server-side. Writes the project credential with
1335
+ * source `admin-set` (a later CDM import never overwrites it) and revokes the user's project-app grants.
1336
+ * The password is never returned, logged or carried by any event; `project.user_password_set`
1337
+ * carries ids and the credential source only.
1338
+ */
1339
+ setProjectUserPassword: User;
1288
1340
  setupMfa: MfaSetupResponse;
1289
1341
  /**
1290
1342
  * Enqueue an asynchronous CDM **export** job for the given project. The worker
@@ -1647,6 +1699,14 @@ export type MutationSetMyPrimaryMfaDeviceArgs = {
1647
1699
  input: SetMyPrimaryMfaDeviceInput;
1648
1700
  };
1649
1701
 
1702
+ export type MutationSetProjectUserEmailArgs = {
1703
+ input: SetProjectUserEmailInput;
1704
+ };
1705
+
1706
+ export type MutationSetProjectUserPasswordArgs = {
1707
+ input: SetProjectUserPasswordInput;
1708
+ };
1709
+
1650
1710
  export type MutationStartProjectExportArgs = {
1651
1711
  id: Scalars['ID']['input'];
1652
1712
  input: StartProjectExportInput;
@@ -2520,6 +2580,12 @@ export type ProjectUserApiKey = Auditable & {
2520
2580
  userId: Scalars['ID']['output'];
2521
2581
  };
2522
2582
 
2583
+ /** Result of `exportProjectUserCredentials`. This is the one place a credential hash leaves Grant. */
2584
+ export type ProjectUserCredentialExport = {
2585
+ __typename?: 'ProjectUserCredentialExport';
2586
+ users: Array<ExportedProjectUserCredential>;
2587
+ };
2588
+
2523
2589
  export type ProjectUserGroup = Auditable & {
2524
2590
  __typename?: 'ProjectUserGroup';
2525
2591
  createdAt: Scalars['Date']['output'];
@@ -2531,6 +2597,20 @@ export type ProjectUserGroup = Auditable & {
2531
2597
  userId: Scalars['ID']['output'];
2532
2598
  };
2533
2599
 
2600
+ /** Non-secret facts about a user's project password credential. Never contains the hash or the password. */
2601
+ export type ProjectUserPasswordCredential = {
2602
+ __typename?: 'ProjectUserPasswordCredential';
2603
+ /**
2604
+ * Lowercase hex SHA-256 of the stored hash string. A change detector, not a secret: it lets a
2605
+ * caller see that the password changed without learning anything usable from it.
2606
+ */
2607
+ fingerprint: Scalars['String']['output'];
2608
+ /** How the credential was written (for example `reset`, `cdm-import` or `admin-set`). A plain string: the schema has no credential-source enum. */
2609
+ source: Scalars['String']['output'];
2610
+ /** When the stored credential last changed. */
2611
+ updatedAt: Scalars['Date']['output'];
2612
+ };
2613
+
2534
2614
  export type ProjectUserPermission = Auditable & {
2535
2615
  __typename?: 'ProjectUserPermission';
2536
2616
  createdAt: Scalars['Date']['output'];
@@ -2548,6 +2628,14 @@ export type Query = {
2548
2628
  apiKeys: ApiKeyPage;
2549
2629
  /** Public signup policy. No authentication required. */
2550
2630
  authSignupPolicy: AuthSignupPolicy;
2631
+ /**
2632
+ * Export project members' password hashes in CDM shape, for a downstream identity mirror.
2633
+ * This is the one audited exception to "APIs expose only whether a password exists": it
2634
+ * requires `ProjectUser:ExportCredentials` (held by no standard group), every call is audited,
2635
+ * and it returns hashes. Any non-member in `userIds` fails the whole call; members without a
2636
+ * project credential are listed with `password: null`.
2637
+ */
2638
+ exportProjectUserCredentials: ProjectUserCredentialExport;
2551
2639
  groups: GroupPage;
2552
2640
  invitation?: Maybe<OrganizationInvitation>;
2553
2641
  /** Evaluate authorization for the current session or API key token. */
@@ -2616,6 +2704,10 @@ export type QueryApiKeysArgs = {
2616
2704
  sort?: InputMaybe<ApiKeySortInput>;
2617
2705
  };
2618
2706
 
2707
+ export type QueryExportProjectUserCredentialsArgs = {
2708
+ input: ExportProjectUserCredentialsInput;
2709
+ };
2710
+
2619
2711
  export type QueryGroupsArgs = {
2620
2712
  ids?: InputMaybe<Array<Scalars['ID']['input']>>;
2621
2713
  limit?: InputMaybe<Scalars['Int']['input']>;
@@ -3541,6 +3633,26 @@ export type SetMyPrimaryMfaDeviceInput = {
3541
3633
  factorId: Scalars['ID']['input'];
3542
3634
  };
3543
3635
 
3636
+ export type SetProjectUserEmailInput = {
3637
+ /**
3638
+ * Unverified Email authentication method. Project-scope only.
3639
+ * A provider can only be linked to one user account (no sharing), and a user can only have one method per provider (no duplicates).
3640
+ */
3641
+ email: Scalars['String']['input'];
3642
+ scope: Scope;
3643
+ userId: Scalars['ID']['input'];
3644
+ };
3645
+
3646
+ export type SetProjectUserPasswordInput = {
3647
+ /**
3648
+ * The new password, chosen by the operator. Project-scope only. The password policy is enforced
3649
+ * server-side; the value is never returned, logged or carried by any event.
3650
+ */
3651
+ password: Scalars['String']['input'];
3652
+ scope: Scope;
3653
+ userId: Scalars['ID']['input'];
3654
+ };
3655
+
3544
3656
  /**
3545
3657
  * Signing key for a scope (e.g. project). Used for RS256 API key tokens; public key is exposed in JWKS.
3546
3658
  * Only project scopes (accountProject, organizationProject) have manageable keys; system key is internal.
@@ -4111,6 +4223,13 @@ export type User = Auditable & {
4111
4223
  id: Scalars['ID']['output'];
4112
4224
  metadata: Scalars['JSON']['output'];
4113
4225
  name: Scalars['String']['output'];
4226
+ /**
4227
+ * Non-secret facts about the user's password credential in the request's project scope. `null` outside a
4228
+ * project scope, when the user has no project credential there, or when the caller lacks
4229
+ * `ProjectUser:ExportCredentials` (never an error). `fingerprint` is the lowercase hex SHA-256 of the
4230
+ * stored hash string: a change detector, not a secret. The password and the hash are never returned here.
4231
+ */
4232
+ passwordCredential?: Maybe<ProjectUserPasswordCredential>;
4114
4233
  permissionCount: Scalars['Int']['output'];
4115
4234
  pictureUrl?: Maybe<Scalars['String']['output']>;
4116
4235
  primaryTag?: Maybe<Tag>;
@@ -0,0 +1,11 @@
1
+ query ExportProjectUserCredentials($input: ExportProjectUserCredentialsInput!) {
2
+ exportProjectUserCredentials(input: $input) {
3
+ users {
4
+ userId
5
+ password {
6
+ algorithm
7
+ hash
8
+ }
9
+ }
10
+ }
11
+ }
@@ -0,0 +1,9 @@
1
+ mutation SetProjectUserEmail($input: SetProjectUserEmailInput!) {
2
+ setProjectUserEmail(input: $input) {
3
+ id
4
+ name
5
+ metadata
6
+ createdAt
7
+ updatedAt
8
+ }
9
+ }
@@ -0,0 +1,9 @@
1
+ mutation SetProjectUserPassword($input: SetProjectUserPasswordInput!) {
2
+ setProjectUserPassword(input: $input) {
3
+ id
4
+ name
5
+ metadata
6
+ createdAt
7
+ updatedAt
8
+ }
9
+ }
@@ -0,0 +1,8 @@
1
+ input ExportProjectUserCredentialsInput {
2
+ "Project scope the members belong to."
3
+ scope: Scope!
4
+ "Project members to export. Every id must be a member of the project, otherwise the whole call fails with not found (no partial export)."
5
+ userIds: [ID!]!
6
+ "Credential kinds to export. Defaults to `[PASSWORD]`."
7
+ kinds: [CredentialKind!] = [PASSWORD]
8
+ }
@@ -0,0 +1,12 @@
1
+ extend type Query {
2
+ """
3
+ Export project members' password hashes in CDM shape, for a downstream identity mirror.
4
+ This is the one audited exception to "APIs expose only whether a password exists": it
5
+ requires `ProjectUser:ExportCredentials` (held by no standard group), every call is audited,
6
+ and it returns hashes. Any non-member in `userIds` fails the whole call; members without a
7
+ project credential are listed with `password: null`.
8
+ """
9
+ exportProjectUserCredentials(
10
+ input: ExportProjectUserCredentialsInput!
11
+ ): ProjectUserCredentialExport!
12
+ }
@@ -0,0 +1,8 @@
1
+ """
2
+ A kind of credential that can be exported. Extensible: a later kind is added here,
3
+ not as a second export.
4
+ """
5
+ enum CredentialKind {
6
+ "The project password credential (bcrypt hash)."
7
+ PASSWORD
8
+ }
@@ -0,0 +1,22 @@
1
+ """
2
+ Result of `exportProjectUserCredentials`. This is the one place a credential hash leaves Grant.
3
+ """
4
+ type ProjectUserCredentialExport {
5
+ users: [ExportedProjectUserCredential!]!
6
+ }
7
+
8
+ type ExportedProjectUserCredential {
9
+ userId: ID!
10
+ "`null` when the member has no project password credential."
11
+ password: ExportedPasswordCredential
12
+ }
13
+
14
+ """
15
+ A stored password hash in CDM shape. Secret-equivalent: handle like a credential.
16
+ """
17
+ type ExportedPasswordCredential {
18
+ "Hash algorithm, for example `bcrypt`."
19
+ algorithm: String!
20
+ "The stored hash string."
21
+ hash: String!
22
+ }
@@ -0,0 +1,14 @@
1
+ """
2
+ Non-secret facts about a user's project password credential. Never contains the hash or the password.
3
+ """
4
+ type ProjectUserPasswordCredential {
5
+ "How the credential was written (for example `reset`, `cdm-import` or `admin-set`). A plain string: the schema has no credential-source enum."
6
+ source: String!
7
+ "When the stored credential last changed."
8
+ updatedAt: Date!
9
+ """
10
+ Lowercase hex SHA-256 of the stored hash string. A change detector, not a secret: it lets a
11
+ caller see that the password changed without learning anything usable from it.
12
+ """
13
+ fingerprint: String!
14
+ }
@@ -8,4 +8,9 @@ input CreateUserInput {
8
8
  permissionIds: [ID!]
9
9
  scope: Scope!
10
10
  primaryTagId: ID
11
+ """
12
+ Optional. Project-scope create only. Stores an unverified Email authentication method.
13
+ A provider can only be linked to one user account (no sharing), and a user can only have one method per provider (no duplicates).
14
+ """
15
+ email: String
11
16
  }
@@ -0,0 +1,9 @@
1
+ input SetProjectUserEmailInput {
2
+ userId: ID!
3
+ """
4
+ Unverified Email authentication method. Project-scope only.
5
+ A provider can only be linked to one user account (no sharing), and a user can only have one method per provider (no duplicates).
6
+ """
7
+ email: String!
8
+ scope: Scope!
9
+ }
@@ -0,0 +1,9 @@
1
+ input SetProjectUserPasswordInput {
2
+ userId: ID!
3
+ """
4
+ The new password, chosen by the operator. Project-scope only. The password policy is enforced
5
+ server-side; the value is never returned, logged or carried by any event.
6
+ """
7
+ password: String!
8
+ scope: Scope!
9
+ }
@@ -0,0 +1,7 @@
1
+ extend type Mutation {
2
+ """
3
+ Set or replace a project member's Email authentication method as unverified.
4
+ `project.user_email_changed` carries ids only, never the address.
5
+ """
6
+ setProjectUserEmail(input: SetProjectUserEmailInput!): User!
7
+ }
@@ -0,0 +1,10 @@
1
+ extend type Mutation {
2
+ """
3
+ Set or replace a project member's password. Project scopes only: the operator supplies the
4
+ password, and the password policy is enforced server-side. Writes the project credential with
5
+ source `admin-set` (a later CDM import never overwrites it) and revokes the user's project-app grants.
6
+ The password is never returned, logged or carried by any event; `project.user_password_set`
7
+ carries ids and the credential source only.
8
+ """
9
+ setProjectUserPassword(input: SetProjectUserPasswordInput!): User!
10
+ }
@@ -14,6 +14,13 @@ type User implements Auditable {
14
14
  tagCount: Int!
15
15
  authenticationMethods: [UserAuthenticationMethod!]
16
16
  accounts: [Account!]
17
+ """
18
+ Non-secret facts about the user's password credential in the request's project scope. `null` outside a
19
+ project scope, when the user has no project credential there, or when the caller lacks
20
+ `ProjectUser:ExportCredentials` (never an error). `fingerprint` is the lowercase hex SHA-256 of the
21
+ stored hash string: a change detector, not a secret. The password and the hash are never returned here.
22
+ """
23
+ passwordCredential: ProjectUserPasswordCredential
17
24
  createdAt: Date!
18
25
  updatedAt: Date!
19
26
  deletedAt: Date
@@ -51,10 +51,12 @@ describe('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
53
  // 137 after CDM imports by reference: RequestProjectSyncUploadUrlDocument.
54
+ // 138 after operator-set-email: SetProjectUserEmailDocument.
55
+ // 140 after operator-set-password: SetProjectUserPasswordDocument, ExportProjectUserCredentialsDocument.
54
56
  // Updating this number is the point of the pin, not a nuisance: every change
55
57
  // to it should be a line in a commit message.
56
58
  it('finds every document under src/operations', () => {
57
- expect(files).toHaveLength(137);
59
+ expect(files).toHaveLength(140);
58
60
  });
59
61
 
60
62
  it.each(files.map((f) => [relative(process.cwd(), f), f]))('%s validates', (_label, file) => {
@@ -67,7 +69,7 @@ describe('graph reachability', () => {
67
69
  const schema = buildMergedSchema();
68
70
 
69
71
  /**
70
- * 175 of 382 declared types cannot be reached from Query or Mutation. They are
72
+ * 175 of 389 declared types cannot be reached from Query or Mutation. They are
71
73
  * not dead: most are consumed as generated TypeScript by apps/api, and the
72
74
  * *SearchableField enums are runtime search configuration. But every one of them
73
75
  * ships in the schema `makeExecutableSchema` serves.
@@ -80,6 +82,12 @@ describe('graph reachability', () => {
80
82
  * Was 181 of 388 before pass 5 slice 4 removed six declarations that were
81
83
  * unreferenced in SDL and in all TypeScript. The reachable count did not change
82
84
  * (207 before and after), which is what makes those six safe to have deleted.
85
+ *
86
+ * operator-set-password declared seven types (382 -> 389 declared). While
87
+ * `passwordCredential` sat on `ProjectUser`, which no query or mutation returns,
88
+ * `ProjectUserPasswordCredential` was unreachable and the pin was 176. It now sits on
89
+ * `User`, so the type is reachable and the pin is back to 175; the other six new
90
+ * types are reachable through the new mutation and query.
83
91
  */
84
92
  const UNREACHABLE_FROM_ROOT = 175;
85
93