@schemavaults/auth-common 0.24.0 → 0.25.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/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { ERROR_MESSAGE_CATALOG, isValidErrorId, } from "./auth-error-message-catalog";
2
2
  export type { SchemaVaultsAuthErrorId } from "./auth-error-message-catalog";
3
3
  export { AppAlreadyConnectedToApiServerError, isAppAlreadyConnectedToApiServerError, } from "./app-to-api-connection-errors";
4
- export { userDataSchema, type UserData } from "./user_data";
4
+ export { userDataSchema, type UserData, USERNAME_MIN_LENGTH, USERNAME_MAX_LENGTH, MAX_USER_NAME_PART_LENGTH, USERNAME_REGEX, usernameFormatSchema, userNamePartSchema, userDisplayNameSchema, userProfileNamesSchema, updateUserProfileRequestSchema, userProfileResponseSchema, type Username, type UserProfileNames, type UpdateUserProfileRequest, type UserProfileResponse, } from "./user_data";
5
5
  export * from "./credentials";
6
6
  export type * from "./credentials";
7
7
  export * from "./token-data";
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export { ERROR_MESSAGE_CATALOG, isValidErrorId, } from "./auth-error-message-catalog";
2
2
  export { AppAlreadyConnectedToApiServerError, isAppAlreadyConnectedToApiServerError, } from "./app-to-api-connection-errors";
3
- export { userDataSchema } from "./user_data";
3
+ export { userDataSchema, USERNAME_MIN_LENGTH, USERNAME_MAX_LENGTH, MAX_USER_NAME_PART_LENGTH, USERNAME_REGEX, usernameFormatSchema, userNamePartSchema, userDisplayNameSchema, userProfileNamesSchema, updateUserProfileRequestSchema, userProfileResponseSchema, } from "./user_data";
4
4
  export * from "./credentials";
5
5
  // Shapes of tokens
6
6
  export * from "./token-data";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,cAAc,GACf,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EACL,mCAAmC,EACnC,qCAAqC,GACtC,MAAM,gCAAgC,CAAC;AAExC,OAAO,EAAE,cAAc,EAAiB,MAAM,aAAa,CAAC;AAE5D,cAAc,eAAe,CAAC;AAG9B,mBAAmB;AACnB,cAAc,cAAc,CAAC;AAM7B,cAAc,cAAc,CAAC;AAG7B,cAAc,QAAQ,CAAC;AAGvB,cAAc,QAAQ,CAAC;AAGvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EACL,wBAAwB,EACxB,qCAAqC,EACrC,mCAAmC,EACnC,+BAA+B,EAC/B,wCAAwC,EACxC,wBAAwB,EACxB,uBAAuB,GAOxB,MAAM,uBAAuB,CAAC;AAE/B,cAAc,OAAO,CAAC;AACtB,OAAO,EACL,+BAA+B,EAE/B,6CAA6C,GAE9C,MAAM,yBAAyB,CAAC;AAEjC,cAAc,mCAAmC,CAAC;AAGlD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAE5D,OAAO,EACL,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,sBAAsB,EACtB,0BAA0B,GAC3B,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,yBAAyB,EACzB,4BAA4B,EAC5B,gBAAgB,EAChB,gCAAgC,EAChC,yCAAyC,EACzC,kCAAkC,EAClC,2CAA2C,EAC3C,0BAA0B,EAC1B,8BAA8B,EAC9B,8BAA8B,EAC9B,sBAAsB,EACtB,sBAAsB,EACtB,iCAAiC,EACjC,kCAAkC,EAClC,4BAA4B,EAC5B,+BAA+B,EAC/B,oCAAoC,EACpC,qCAAqC,EACrC,uCAAuC,EACvC,wCAAwC,GACzC,MAAM,iBAAiB,CAAC;AAezB,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAEtE,OAAO,EACL,sBAAsB,EACtB,4BAA4B,GAC7B,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACL,qBAAqB,EACrB,2BAA2B,GAC5B,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,wCAAwC,EAAE,MAAM,4CAA4C,CAAC;AAEtG,OAAO,EAAE,kCAAkC,EAAE,MAAM,0CAA0C,CAAC;AAE9F,OAAO,EACL,uBAAuB,EACvB,6BAA6B,EAC7B,4BAA4B,EAC5B,wBAAwB,GACzB,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,OAAO,EACL,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAC;AAE/C,OAAO,EAAE,gCAAgC,EAAE,MAAM,UAAU,CAAC;AAE5D,OAAO,EACL,iBAAiB,EACjB,yBAAyB,EACzB,gBAAgB,EAChB,0BAA0B,GAC3B,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EACL,qCAAqC,EACrC,gCAAgC,GACjC,MAAM,mCAAmC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,cAAc,GACf,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EACL,mCAAmC,EACnC,qCAAqC,GACtC,MAAM,gCAAgC,CAAC;AAExC,OAAO,EACL,cAAc,EAEd,mBAAmB,EACnB,mBAAmB,EACnB,yBAAyB,EACzB,cAAc,EACd,oBAAoB,EACpB,kBAAkB,EAClB,qBAAqB,EACrB,sBAAsB,EACtB,8BAA8B,EAC9B,yBAAyB,GAK1B,MAAM,aAAa,CAAC;AAErB,cAAc,eAAe,CAAC;AAG9B,mBAAmB;AACnB,cAAc,cAAc,CAAC;AAM7B,cAAc,cAAc,CAAC;AAG7B,cAAc,QAAQ,CAAC;AAGvB,cAAc,QAAQ,CAAC;AAGvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EACL,wBAAwB,EACxB,qCAAqC,EACrC,mCAAmC,EACnC,+BAA+B,EAC/B,wCAAwC,EACxC,wBAAwB,EACxB,uBAAuB,GAOxB,MAAM,uBAAuB,CAAC;AAE/B,cAAc,OAAO,CAAC;AACtB,OAAO,EACL,+BAA+B,EAE/B,6CAA6C,GAE9C,MAAM,yBAAyB,CAAC;AAEjC,cAAc,mCAAmC,CAAC;AAGlD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAE5D,OAAO,EACL,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,sBAAsB,EACtB,0BAA0B,GAC3B,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,yBAAyB,EACzB,4BAA4B,EAC5B,gBAAgB,EAChB,gCAAgC,EAChC,yCAAyC,EACzC,kCAAkC,EAClC,2CAA2C,EAC3C,0BAA0B,EAC1B,8BAA8B,EAC9B,8BAA8B,EAC9B,sBAAsB,EACtB,sBAAsB,EACtB,iCAAiC,EACjC,kCAAkC,EAClC,4BAA4B,EAC5B,+BAA+B,EAC/B,oCAAoC,EACpC,qCAAqC,EACrC,uCAAuC,EACvC,wCAAwC,GACzC,MAAM,iBAAiB,CAAC;AAezB,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAEtE,OAAO,EACL,sBAAsB,EACtB,4BAA4B,GAC7B,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACL,qBAAqB,EACrB,2BAA2B,GAC5B,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,wCAAwC,EAAE,MAAM,4CAA4C,CAAC;AAEtG,OAAO,EAAE,kCAAkC,EAAE,MAAM,0CAA0C,CAAC;AAE9F,OAAO,EACL,uBAAuB,EACvB,6BAA6B,EAC7B,4BAA4B,EAC5B,wBAAwB,GACzB,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,OAAO,EACL,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAC;AAE/C,OAAO,EAAE,gCAAgC,EAAE,MAAM,UAAU,CAAC;AAE5D,OAAO,EACL,iBAAiB,EACjB,yBAAyB,EACzB,gBAAgB,EAChB,0BAA0B,GAC3B,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EACL,qCAAqC,EACrC,gCAAgC,GACjC,MAAM,mCAAmC,CAAC"}
@@ -3,3 +3,5 @@ export type { OidcSupportedScope, OidcScope, ParsedOidcScopes, } from "./scope";
3
3
  export { oidcNonceSchema, OIDC_NONCE_VSCHAR_REGEX, parseOidcNonce, OidcNonceValidationError, } from "./nonce";
4
4
  export type { OidcNonce } from "./nonce";
5
5
  export { OIDC_SUB_CLAIM_DELIMITER, formatOidcSubClaim, parseOidcSubClaim, } from "./sub-claim";
6
+ export { buildOidcProfileClaims } from "./profile-claims";
7
+ export type { OidcProfileClaims, OidcProfileClaimsSource, } from "./profile-claims";
@@ -1,4 +1,5 @@
1
1
  export { OIDC_OPENID_SCOPE, OIDC_SUPPORTED_SCOPES, DEFAULT_AUTH_SCOPE, OIDC_SCOPE_REGEX, oidcScopeSchema, parseAndGrantScopes, serializeOidcScopes, } from "./scope";
2
2
  export { oidcNonceSchema, OIDC_NONCE_VSCHAR_REGEX, parseOidcNonce, OidcNonceValidationError, } from "./nonce";
3
3
  export { OIDC_SUB_CLAIM_DELIMITER, formatOidcSubClaim, parseOidcSubClaim, } from "./sub-claim";
4
+ export { buildOidcProfileClaims } from "./profile-claims";
4
5
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/oidc/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,SAAS,CAAC;AAOjB,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,cAAc,EACd,wBAAwB,GACzB,MAAM,SAAS,CAAC;AAGjB,OAAO,EACL,wBAAwB,EACxB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/oidc/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,SAAS,CAAC;AAOjB,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,cAAc,EACd,wBAAwB,GACzB,MAAM,SAAS,CAAC;AAGjB,OAAO,EACL,wBAAwB,EACxB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * OIDC Core §5.1 standard claims gated by the `profile` scope, built
3
+ * from the user's stored profile name fields. Shared by every surface
4
+ * that emits profile claims — the id_token (`generateIdToken` in
5
+ * @schemavaults/jwt) and GET/POST /api/oidc/userinfo — so the two
6
+ * always agree for the same user.
7
+ */
8
+ /** The profile name fields the claims are derived from (all optional). */
9
+ export interface OidcProfileClaimsSource {
10
+ username?: string;
11
+ first_name?: string;
12
+ middle_name?: string;
13
+ last_name?: string;
14
+ display_name?: string;
15
+ }
16
+ /** The OIDC Core §5.1 claims emitted under the `profile` scope. */
17
+ export interface OidcProfileClaims {
18
+ /**
19
+ * The user's full name in displayable form: the public display name
20
+ * when set, otherwise the joined first/middle/last name parts.
21
+ */
22
+ name?: string;
23
+ given_name?: string;
24
+ middle_name?: string;
25
+ family_name?: string;
26
+ preferred_username?: string;
27
+ }
28
+ /**
29
+ * Builds the `profile`-scoped claim set from a user's stored name
30
+ * fields. Claims without a stored value are omitted entirely (OIDC Core
31
+ * §5.3.2 — absent, not null/empty). Callers are responsible for only
32
+ * emitting the result when the `profile` scope was actually granted.
33
+ */
34
+ export declare function buildOidcProfileClaims(user: OidcProfileClaimsSource): OidcProfileClaims;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * OIDC Core §5.1 standard claims gated by the `profile` scope, built
3
+ * from the user's stored profile name fields. Shared by every surface
4
+ * that emits profile claims — the id_token (`generateIdToken` in
5
+ * @schemavaults/jwt) and GET/POST /api/oidc/userinfo — so the two
6
+ * always agree for the same user.
7
+ */
8
+ /**
9
+ * Builds the `profile`-scoped claim set from a user's stored name
10
+ * fields. Claims without a stored value are omitted entirely (OIDC Core
11
+ * §5.3.2 — absent, not null/empty). Callers are responsible for only
12
+ * emitting the result when the `profile` scope was actually granted.
13
+ */
14
+ export function buildOidcProfileClaims(user) {
15
+ const claims = {};
16
+ const joined_name_parts = [
17
+ user.first_name,
18
+ user.middle_name,
19
+ user.last_name,
20
+ ]
21
+ .filter((part) => typeof part === "string" && part.length > 0)
22
+ .join(" ");
23
+ const full_name = user.display_name && user.display_name.length > 0
24
+ ? user.display_name
25
+ : joined_name_parts.length > 0
26
+ ? joined_name_parts
27
+ : undefined;
28
+ if (full_name) {
29
+ claims.name = full_name;
30
+ }
31
+ if (user.first_name) {
32
+ claims.given_name = user.first_name;
33
+ }
34
+ if (user.middle_name) {
35
+ claims.middle_name = user.middle_name;
36
+ }
37
+ if (user.last_name) {
38
+ claims.family_name = user.last_name;
39
+ }
40
+ if (user.username) {
41
+ claims.preferred_username = user.username;
42
+ }
43
+ return claims;
44
+ }
45
+ //# sourceMappingURL=profile-claims.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile-claims.js","sourceRoot":"","sources":["../../src/oidc/profile-claims.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAwBH;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CACpC,IAA6B;IAE7B,MAAM,MAAM,GAAsB,EAAE,CAAC;IAErC,MAAM,iBAAiB,GAAW;QAChC,IAAI,CAAC,UAAU;QACf,IAAI,CAAC,WAAW;QAChB,IAAI,CAAC,SAAS;KACf;SACE,MAAM,CACL,CAAC,IAAI,EAAkB,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CACtE;SACA,IAAI,CAAC,GAAG,CAAC,CAAC;IACb,MAAM,SAAS,GACb,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC;QAC/C,CAAC,CAAC,IAAI,CAAC,YAAY;QACnB,CAAC,CAAC,iBAAiB,CAAC,MAAM,GAAG,CAAC;YAC5B,CAAC,CAAC,iBAAiB;YACnB,CAAC,CAAC,SAAS,CAAC;IAElB,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,CAAC,IAAI,GAAG,SAAS,CAAC;IAC1B,CAAC;IACD,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;QACpB,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;IACtC,CAAC;IACD,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;QACrB,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;IACxC,CAAC;IACD,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC;IACtC,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,MAAM,CAAC,kBAAkB,GAAG,IAAI,CAAC,QAAQ,CAAC;IAC5C,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -371,6 +371,11 @@ export declare function createRequestTokensResultSchema(z: typeof zod, environme
371
371
  }>>;
372
372
  userData: zod.ZodOptional<zod.ZodEffects<zod.ZodObject<{
373
373
  uid: zod.ZodString;
374
+ username: zod.ZodOptional<zod.ZodString>;
375
+ first_name: zod.ZodOptional<zod.ZodString>;
376
+ middle_name: zod.ZodOptional<zod.ZodString>;
377
+ last_name: zod.ZodOptional<zod.ZodString>;
378
+ display_name: zod.ZodOptional<zod.ZodString>;
374
379
  sub: zod.ZodString;
375
380
  email: zod.ZodString;
376
381
  email_verified: zod.ZodOptional<zod.ZodBoolean>;
@@ -385,6 +390,11 @@ export declare function createRequestTokensResultSchema(z: typeof zod, environme
385
390
  sub: string;
386
391
  email: string;
387
392
  created_at: number;
393
+ username?: string | undefined;
394
+ first_name?: string | undefined;
395
+ middle_name?: string | undefined;
396
+ last_name?: string | undefined;
397
+ display_name?: string | undefined;
388
398
  email_verified?: boolean | undefined;
389
399
  admin?: boolean | undefined;
390
400
  phone_number?: string | undefined;
@@ -396,6 +406,11 @@ export declare function createRequestTokensResultSchema(z: typeof zod, environme
396
406
  sub: string;
397
407
  email: string;
398
408
  created_at: number;
409
+ username?: string | undefined;
410
+ first_name?: string | undefined;
411
+ middle_name?: string | undefined;
412
+ last_name?: string | undefined;
413
+ display_name?: string | undefined;
399
414
  email_verified?: boolean | undefined;
400
415
  admin?: boolean | undefined;
401
416
  phone_number?: string | undefined;
@@ -407,6 +422,11 @@ export declare function createRequestTokensResultSchema(z: typeof zod, environme
407
422
  sub: string;
408
423
  email: string;
409
424
  created_at: number;
425
+ username?: string | undefined;
426
+ first_name?: string | undefined;
427
+ middle_name?: string | undefined;
428
+ last_name?: string | undefined;
429
+ display_name?: string | undefined;
410
430
  email_verified?: boolean | undefined;
411
431
  admin?: boolean | undefined;
412
432
  phone_number?: string | undefined;
@@ -418,6 +438,11 @@ export declare function createRequestTokensResultSchema(z: typeof zod, environme
418
438
  sub: string;
419
439
  email: string;
420
440
  created_at: number;
441
+ username?: string | undefined;
442
+ first_name?: string | undefined;
443
+ middle_name?: string | undefined;
444
+ last_name?: string | undefined;
445
+ display_name?: string | undefined;
421
446
  email_verified?: boolean | undefined;
422
447
  admin?: boolean | undefined;
423
448
  phone_number?: string | undefined;
@@ -458,6 +483,11 @@ export declare function createRequestTokensResultSchema(z: typeof zod, environme
458
483
  sub: string;
459
484
  email: string;
460
485
  created_at: number;
486
+ username?: string | undefined;
487
+ first_name?: string | undefined;
488
+ middle_name?: string | undefined;
489
+ last_name?: string | undefined;
490
+ display_name?: string | undefined;
461
491
  email_verified?: boolean | undefined;
462
492
  admin?: boolean | undefined;
463
493
  phone_number?: string | undefined;
@@ -498,6 +528,11 @@ export declare function createRequestTokensResultSchema(z: typeof zod, environme
498
528
  sub: string;
499
529
  email: string;
500
530
  created_at: number;
531
+ username?: string | undefined;
532
+ first_name?: string | undefined;
533
+ middle_name?: string | undefined;
534
+ last_name?: string | undefined;
535
+ display_name?: string | undefined;
501
536
  email_verified?: boolean | undefined;
502
537
  admin?: boolean | undefined;
503
538
  phone_number?: string | undefined;
@@ -1 +1,2 @@
1
1
  export { userDataSchema, type UserData } from './user_data';
2
+ export { USERNAME_MIN_LENGTH, USERNAME_MAX_LENGTH, MAX_USER_NAME_PART_LENGTH, USERNAME_REGEX, usernameFormatSchema, userNamePartSchema, userDisplayNameSchema, userProfileNamesSchema, updateUserProfileRequestSchema, userProfileResponseSchema, type Username, type UserProfileNames, type UpdateUserProfileRequest, type UserProfileResponse, } from './user_profile';
@@ -1,2 +1,3 @@
1
1
  export { userDataSchema } from './user_data';
2
+ export { USERNAME_MIN_LENGTH, USERNAME_MAX_LENGTH, MAX_USER_NAME_PART_LENGTH, USERNAME_REGEX, usernameFormatSchema, userNamePartSchema, userDisplayNameSchema, userProfileNamesSchema, updateUserProfileRequestSchema, userProfileResponseSchema, } from './user_profile';
2
3
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/user_data/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,cAAc,EAEf,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/user_data/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,cAAc,EAEf,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,yBAAyB,EACzB,cAAc,EACd,oBAAoB,EACpB,kBAAkB,EAClB,qBAAqB,EACrB,sBAAsB,EACtB,8BAA8B,EAC9B,yBAAyB,GAK1B,MAAM,gBAAgB,CAAC"}
@@ -1,6 +1,11 @@
1
1
  import { z } from "zod";
2
2
  export declare const userDataSchema: z.ZodEffects<z.ZodObject<{
3
3
  uid: z.ZodString;
4
+ username: z.ZodOptional<z.ZodString>;
5
+ first_name: z.ZodOptional<z.ZodString>;
6
+ middle_name: z.ZodOptional<z.ZodString>;
7
+ last_name: z.ZodOptional<z.ZodString>;
8
+ display_name: z.ZodOptional<z.ZodString>;
4
9
  sub: z.ZodString;
5
10
  email: z.ZodString;
6
11
  email_verified: z.ZodOptional<z.ZodBoolean>;
@@ -15,6 +20,11 @@ export declare const userDataSchema: z.ZodEffects<z.ZodObject<{
15
20
  sub: string;
16
21
  email: string;
17
22
  created_at: number;
23
+ username?: string | undefined;
24
+ first_name?: string | undefined;
25
+ middle_name?: string | undefined;
26
+ last_name?: string | undefined;
27
+ display_name?: string | undefined;
18
28
  email_verified?: boolean | undefined;
19
29
  admin?: boolean | undefined;
20
30
  phone_number?: string | undefined;
@@ -26,6 +36,11 @@ export declare const userDataSchema: z.ZodEffects<z.ZodObject<{
26
36
  sub: string;
27
37
  email: string;
28
38
  created_at: number;
39
+ username?: string | undefined;
40
+ first_name?: string | undefined;
41
+ middle_name?: string | undefined;
42
+ last_name?: string | undefined;
43
+ display_name?: string | undefined;
29
44
  email_verified?: boolean | undefined;
30
45
  admin?: boolean | undefined;
31
46
  phone_number?: string | undefined;
@@ -37,6 +52,11 @@ export declare const userDataSchema: z.ZodEffects<z.ZodObject<{
37
52
  sub: string;
38
53
  email: string;
39
54
  created_at: number;
55
+ username?: string | undefined;
56
+ first_name?: string | undefined;
57
+ middle_name?: string | undefined;
58
+ last_name?: string | undefined;
59
+ display_name?: string | undefined;
40
60
  email_verified?: boolean | undefined;
41
61
  admin?: boolean | undefined;
42
62
  phone_number?: string | undefined;
@@ -48,6 +68,11 @@ export declare const userDataSchema: z.ZodEffects<z.ZodObject<{
48
68
  sub: string;
49
69
  email: string;
50
70
  created_at: number;
71
+ username?: string | undefined;
72
+ first_name?: string | undefined;
73
+ middle_name?: string | undefined;
74
+ last_name?: string | undefined;
75
+ display_name?: string | undefined;
51
76
  email_verified?: boolean | undefined;
52
77
  admin?: boolean | undefined;
53
78
  phone_number?: string | undefined;
@@ -1,4 +1,5 @@
1
1
  import { inviteCodeFormatSchema } from "../invite-code/invite-code-format";
2
+ import { usernameFormatSchema, userNamePartSchema, userDisplayNameSchema, } from "../user_data/user_profile";
2
3
  import { z } from "zod";
3
4
  const _baseUserDataSchema = z
4
5
  .object({
@@ -8,6 +9,15 @@ const _baseUserDataSchema = z
8
9
  // Email
9
10
  email: z.string().email(),
10
11
  email_verified: z.boolean().optional(),
12
+ // Profile names (user-editable; absent for accounts that never set
13
+ // them). Only present when the UserData was built from the database
14
+ // row (loadUserData) — UserData derived from a decoded token payload
15
+ // does not carry them.
16
+ username: usernameFormatSchema.optional(),
17
+ first_name: userNamePartSchema.optional(),
18
+ middle_name: userNamePartSchema.optional(),
19
+ last_name: userNamePartSchema.optional(),
20
+ display_name: userDisplayNameSchema.optional(),
11
21
  // Admin
12
22
  admin: z.boolean().optional(),
13
23
  // Phone
@@ -1 +1 @@
1
- {"version":3,"file":"user_data.js","sourceRoot":"","sources":["../../src/user_data/user_data.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,mBAAmB,GAAG,CAAC;KAC1B,MAAM,CAAC;IACN,UAAU;IACV,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE;IACtB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,mBAAmB;IAE3C,QAAQ;IACR,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE;IACzB,cAAc,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAEtC,QAAQ;IACR,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAE7B,QAAQ;IACR,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE;IACnD,cAAc,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAEtC,4BAA4B;IAC5B,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAEhC,qBAAqB;IACrB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IAEvC,cAAc;IACd,WAAW,EAAE,sBAAsB,CAAC,QAAQ,EAAE;CAC/C,CAAC;KACD,QAAQ,CAAC;IACR,GAAG,EAAE,IAAI;IACT,KAAK,EAAE,IAAI;IACX,GAAG,EAAE,IAAI;IACT,UAAU,EAAE,IAAI;CACjB,CAAC;KACD,MAAM,EAAE,CAAC;AAEZ,MAAM,CAAC,MAAM,cAAc,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;IAChE,OAAO,IAAI,CAAC,GAAG,KAAK,IAAI,CAAC,GAAG,CAAC;AAC/B,CAAC,EAAE,6BAA6B,CAAC,CAAC"}
1
+ {"version":3,"file":"user_data.js","sourceRoot":"","sources":["../../src/user_data/user_data.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,mBAAmB,GAAG,CAAC;KAC1B,MAAM,CAAC;IACN,UAAU;IACV,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE;IACtB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,mBAAmB;IAE3C,QAAQ;IACR,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE;IACzB,cAAc,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAEtC,mEAAmE;IACnE,oEAAoE;IACpE,qEAAqE;IACrE,uBAAuB;IACvB,QAAQ,EAAE,oBAAoB,CAAC,QAAQ,EAAE;IACzC,UAAU,EAAE,kBAAkB,CAAC,QAAQ,EAAE;IACzC,WAAW,EAAE,kBAAkB,CAAC,QAAQ,EAAE;IAC1C,SAAS,EAAE,kBAAkB,CAAC,QAAQ,EAAE;IACxC,YAAY,EAAE,qBAAqB,CAAC,QAAQ,EAAE;IAE9C,QAAQ;IACR,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAE7B,QAAQ;IACR,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE;IACnD,cAAc,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAEtC,4BAA4B;IAC5B,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAEhC,qBAAqB;IACrB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IAEvC,cAAc;IACd,WAAW,EAAE,sBAAsB,CAAC,QAAQ,EAAE;CAC/C,CAAC;KACD,QAAQ,CAAC;IACR,GAAG,EAAE,IAAI;IACT,KAAK,EAAE,IAAI;IACX,GAAG,EAAE,IAAI;IACT,UAAU,EAAE,IAAI;CACjB,CAAC;KACD,MAAM,EAAE,CAAC;AAEZ,MAAM,CAAC,MAAM,cAAc,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;IAChE,OAAO,IAAI,CAAC,GAAG,KAAK,IAAI,CAAC,GAAG,CAAC;AAC/B,CAAC,EAAE,6BAA6B,CAAC,CAAC"}
@@ -0,0 +1,119 @@
1
+ import { z } from "zod";
2
+ export declare const USERNAME_MIN_LENGTH: number;
3
+ export declare const USERNAME_MAX_LENGTH: number;
4
+ /**
5
+ * Maximum length for each individual person-name part (first / middle /
6
+ * last) and for the public display name.
7
+ */
8
+ export declare const MAX_USER_NAME_PART_LENGTH: number;
9
+ /**
10
+ * Usernames are unique per deployment (case-insensitively — the database
11
+ * enforces uniqueness on LOWER(username), while the stored casing is
12
+ * preserved for display). Format: alphanumeric start and end with `.`,
13
+ * `_`, and `-` permitted in between. `@` is deliberately excluded so a
14
+ * username can never be confused with an email address, and `|` can
15
+ * never appear (the OIDC sub-claim delimiter).
16
+ */
17
+ export declare const USERNAME_REGEX: RegExp;
18
+ export declare const usernameFormatSchema: z.ZodString;
19
+ export type Username = z.infer<typeof usernameFormatSchema>;
20
+ /** A single part of a user's personal name (first / middle / last). */
21
+ export declare const userNamePartSchema: z.ZodString;
22
+ /**
23
+ * The user's public display name. Shown to other users and exposed to
24
+ * OIDC relying parties as the `name` claim when the `profile` scope is
25
+ * granted.
26
+ */
27
+ export declare const userDisplayNameSchema: z.ZodString;
28
+ /**
29
+ * The user-editable profile name fields stored on the USERS row. All
30
+ * fields are optional — accounts predating this feature (and accounts
31
+ * that never fill them in) simply have none set.
32
+ */
33
+ export declare const userProfileNamesSchema: z.ZodObject<{
34
+ username: z.ZodOptional<z.ZodString>;
35
+ first_name: z.ZodOptional<z.ZodString>;
36
+ middle_name: z.ZodOptional<z.ZodString>;
37
+ last_name: z.ZodOptional<z.ZodString>;
38
+ display_name: z.ZodOptional<z.ZodString>;
39
+ }, "strict", z.ZodTypeAny, {
40
+ username?: string | undefined;
41
+ first_name?: string | undefined;
42
+ middle_name?: string | undefined;
43
+ last_name?: string | undefined;
44
+ display_name?: string | undefined;
45
+ }, {
46
+ username?: string | undefined;
47
+ first_name?: string | undefined;
48
+ middle_name?: string | undefined;
49
+ last_name?: string | undefined;
50
+ display_name?: string | undefined;
51
+ }>;
52
+ export type UserProfileNames = z.infer<typeof userProfileNamesSchema>;
53
+ /**
54
+ * PUT /api/user/profile request body. Full-replacement semantics: every
55
+ * field the user wants to keep must be present; `null` (or an omitted
56
+ * field) clears the stored value.
57
+ */
58
+ export declare const updateUserProfileRequestSchema: z.ZodObject<{
59
+ username: z.ZodOptional<z.ZodNullable<z.ZodString>>;
60
+ first_name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
61
+ middle_name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
62
+ last_name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
63
+ display_name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
64
+ }, "strict", z.ZodTypeAny, {
65
+ username?: string | null | undefined;
66
+ first_name?: string | null | undefined;
67
+ middle_name?: string | null | undefined;
68
+ last_name?: string | null | undefined;
69
+ display_name?: string | null | undefined;
70
+ }, {
71
+ username?: string | null | undefined;
72
+ first_name?: string | null | undefined;
73
+ middle_name?: string | null | undefined;
74
+ last_name?: string | null | undefined;
75
+ display_name?: string | null | undefined;
76
+ }>;
77
+ export type UpdateUserProfileRequest = z.infer<typeof updateUserProfileRequestSchema>;
78
+ /** GET/PUT /api/user/profile success response body. */
79
+ export declare const userProfileResponseSchema: z.ZodObject<{
80
+ success: z.ZodLiteral<true>;
81
+ profile: z.ZodObject<{
82
+ username: z.ZodOptional<z.ZodString>;
83
+ first_name: z.ZodOptional<z.ZodString>;
84
+ middle_name: z.ZodOptional<z.ZodString>;
85
+ last_name: z.ZodOptional<z.ZodString>;
86
+ display_name: z.ZodOptional<z.ZodString>;
87
+ }, "strict", z.ZodTypeAny, {
88
+ username?: string | undefined;
89
+ first_name?: string | undefined;
90
+ middle_name?: string | undefined;
91
+ last_name?: string | undefined;
92
+ display_name?: string | undefined;
93
+ }, {
94
+ username?: string | undefined;
95
+ first_name?: string | undefined;
96
+ middle_name?: string | undefined;
97
+ last_name?: string | undefined;
98
+ display_name?: string | undefined;
99
+ }>;
100
+ }, "strict", z.ZodTypeAny, {
101
+ success: true;
102
+ profile: {
103
+ username?: string | undefined;
104
+ first_name?: string | undefined;
105
+ middle_name?: string | undefined;
106
+ last_name?: string | undefined;
107
+ display_name?: string | undefined;
108
+ };
109
+ }, {
110
+ success: true;
111
+ profile: {
112
+ username?: string | undefined;
113
+ first_name?: string | undefined;
114
+ middle_name?: string | undefined;
115
+ last_name?: string | undefined;
116
+ display_name?: string | undefined;
117
+ };
118
+ }>;
119
+ export type UserProfileResponse = z.infer<typeof userProfileResponseSchema>;
@@ -0,0 +1,79 @@
1
+ import { z } from "zod";
2
+ export const USERNAME_MIN_LENGTH = 3;
3
+ export const USERNAME_MAX_LENGTH = 32;
4
+ /**
5
+ * Maximum length for each individual person-name part (first / middle /
6
+ * last) and for the public display name.
7
+ */
8
+ export const MAX_USER_NAME_PART_LENGTH = 64;
9
+ /**
10
+ * Usernames are unique per deployment (case-insensitively — the database
11
+ * enforces uniqueness on LOWER(username), while the stored casing is
12
+ * preserved for display). Format: alphanumeric start and end with `.`,
13
+ * `_`, and `-` permitted in between. `@` is deliberately excluded so a
14
+ * username can never be confused with an email address, and `|` can
15
+ * never appear (the OIDC sub-claim delimiter).
16
+ */
17
+ export const USERNAME_REGEX = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;
18
+ export const usernameFormatSchema = z
19
+ .string()
20
+ .min(USERNAME_MIN_LENGTH, `Username must be at least ${USERNAME_MIN_LENGTH} characters long!`)
21
+ .max(USERNAME_MAX_LENGTH, `Username may not be longer than ${USERNAME_MAX_LENGTH} characters!`)
22
+ .regex(USERNAME_REGEX, "Username may only contain letters, numbers, '.', '_', and '-', and must start and end with a letter or number.");
23
+ /**
24
+ * Rejects ASCII control characters (including CR/LF) that could pollute
25
+ * logs, headers, or rendered UI. All other unicode is permitted — names
26
+ * are human text.
27
+ */
28
+ // eslint-disable-next-line no-control-regex -- rejecting control chars is the point
29
+ const NO_CONTROL_CHARS_REGEX = /^[^\u0000-\u001F\u007F]*$/;
30
+ const namePartSchema = z
31
+ .string()
32
+ .trim()
33
+ .min(1)
34
+ .max(MAX_USER_NAME_PART_LENGTH, `Name may not be longer than ${MAX_USER_NAME_PART_LENGTH} characters!`)
35
+ .regex(NO_CONTROL_CHARS_REGEX, "Name may not contain control characters!");
36
+ /** A single part of a user's personal name (first / middle / last). */
37
+ export const userNamePartSchema = namePartSchema;
38
+ /**
39
+ * The user's public display name. Shown to other users and exposed to
40
+ * OIDC relying parties as the `name` claim when the `profile` scope is
41
+ * granted.
42
+ */
43
+ export const userDisplayNameSchema = namePartSchema;
44
+ /**
45
+ * The user-editable profile name fields stored on the USERS row. All
46
+ * fields are optional — accounts predating this feature (and accounts
47
+ * that never fill them in) simply have none set.
48
+ */
49
+ export const userProfileNamesSchema = z
50
+ .object({
51
+ username: usernameFormatSchema.optional(),
52
+ first_name: userNamePartSchema.optional(),
53
+ middle_name: userNamePartSchema.optional(),
54
+ last_name: userNamePartSchema.optional(),
55
+ display_name: userDisplayNameSchema.optional(),
56
+ })
57
+ .strict();
58
+ /**
59
+ * PUT /api/user/profile request body. Full-replacement semantics: every
60
+ * field the user wants to keep must be present; `null` (or an omitted
61
+ * field) clears the stored value.
62
+ */
63
+ export const updateUserProfileRequestSchema = z
64
+ .object({
65
+ username: usernameFormatSchema.nullable().optional(),
66
+ first_name: userNamePartSchema.nullable().optional(),
67
+ middle_name: userNamePartSchema.nullable().optional(),
68
+ last_name: userNamePartSchema.nullable().optional(),
69
+ display_name: userDisplayNameSchema.nullable().optional(),
70
+ })
71
+ .strict();
72
+ /** GET/PUT /api/user/profile success response body. */
73
+ export const userProfileResponseSchema = z
74
+ .object({
75
+ success: z.literal(true),
76
+ profile: userProfileNamesSchema,
77
+ })
78
+ .strict();
79
+ //# sourceMappingURL=user_profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user_profile.js","sourceRoot":"","sources":["../../src/user_data/user_profile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,mBAAmB,GAAW,CAAC,CAAC;AAC7C,MAAM,CAAC,MAAM,mBAAmB,GAAW,EAAE,CAAC;AAE9C;;;GAGG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAW,EAAE,CAAC;AAEpD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,cAAc,GACzB,8CAA8C,CAAC;AAEjD,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC;KAClC,MAAM,EAAE;KACR,GAAG,CACF,mBAAmB,EACnB,6BAA6B,mBAAmB,mBAAmB,CACpE;KACA,GAAG,CACF,mBAAmB,EACnB,mCAAmC,mBAAmB,cAAc,CACrE;KACA,KAAK,CACJ,cAAc,EACd,gHAAgH,CACjH,CAAC;AAIJ;;;;GAIG;AACH,oFAAoF;AACpF,MAAM,sBAAsB,GAAW,2BAA2B,CAAC;AAEnE,MAAM,cAAc,GAAG,CAAC;KACrB,MAAM,EAAE;KACR,IAAI,EAAE;KACN,GAAG,CAAC,CAAC,CAAC;KACN,GAAG,CACF,yBAAyB,EACzB,+BAA+B,yBAAyB,cAAc,CACvE;KACA,KAAK,CAAC,sBAAsB,EAAE,0CAA0C,CAAC,CAAC;AAE7E,uEAAuE;AACvE,MAAM,CAAC,MAAM,kBAAkB,GAAG,cAAc,CAAC;AAEjD;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,cAAc,CAAC;AAEpD;;;;GAIG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC;KACpC,MAAM,CAAC;IACN,QAAQ,EAAE,oBAAoB,CAAC,QAAQ,EAAE;IACzC,UAAU,EAAE,kBAAkB,CAAC,QAAQ,EAAE;IACzC,WAAW,EAAE,kBAAkB,CAAC,QAAQ,EAAE;IAC1C,SAAS,EAAE,kBAAkB,CAAC,QAAQ,EAAE;IACxC,YAAY,EAAE,qBAAqB,CAAC,QAAQ,EAAE;CAC/C,CAAC;KACD,MAAM,EAAE,CAAC;AAIZ;;;;GAIG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAAC;KAC5C,MAAM,CAAC;IACN,QAAQ,EAAE,oBAAoB,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IACpD,UAAU,EAAE,kBAAkB,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IACpD,WAAW,EAAE,kBAAkB,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IACrD,SAAS,EAAE,kBAAkB,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IACnD,YAAY,EAAE,qBAAqB,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;CAC1D,CAAC;KACD,MAAM,EAAE,CAAC;AAMZ,uDAAuD;AACvD,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC;KACvC,MAAM,CAAC;IACN,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;IACxB,OAAO,EAAE,sBAAsB;CAChC,CAAC;KACD,MAAM,EAAE,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@schemavaults/auth-common",
3
3
  "description": "Types and utility functions for authentication and authorization",
4
- "version": "0.24.0",
4
+ "version": "0.25.0",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,
7
7
  "repository": {