@tearleads/client-sdk 0.1.105 → 0.1.107

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.
Files changed (46) hide show
  1. package/Tearleads.js +5 -3
  2. package/Tearleads.js.map +1 -1
  3. package/client/blobs/index.d.ts +4 -0
  4. package/client/blobs/index.js +26 -7
  5. package/client/blobs/index.js.map +1 -1
  6. package/client/identity/index.d.ts +11 -2
  7. package/client/identity/index.js +80 -72
  8. package/client/identity/index.js.map +1 -1
  9. package/client/organizations/index.js +5 -2
  10. package/client/organizations/index.js.map +1 -1
  11. package/client/organizations/organizationMemberships.js +26 -18
  12. package/client/organizations/organizationMemberships.js.map +1 -1
  13. package/client/organizations/organizationReadModels.d.ts +9 -4
  14. package/client/organizations/organizationReadModels.js +20 -9
  15. package/client/organizations/organizationReadModels.js.map +1 -1
  16. package/client/session/index.js +6 -3
  17. package/client/session/index.js.map +1 -1
  18. package/client/session/sessionTypes.d.ts +1 -1
  19. package/client/session/sessionTypes.js.map +1 -1
  20. package/index.js +1 -1
  21. package/index.js.map +1 -1
  22. package/internal/api-client/ApiClient.d.ts +7 -0
  23. package/internal/crypto/organizationLeaveRequest.d.ts +1 -1
  24. package/internal/crypto/organizationLeaveRequest.js +9 -2
  25. package/internal/crypto/organizationLeaveRequest.js.map +1 -1
  26. package/internal/validators/operation/organizationMemberships.d.ts +7 -0
  27. package/internal/validators/operation/organizations.d.ts +56 -0
  28. package/internal/validators/response/organization.d.ts +91 -0
  29. package/internal/validators/response/organizationReadModel.d.ts +70 -0
  30. package/internal/validators/util/index.d.ts +1 -1
  31. package/internal/validators/util/index.js.map +1 -1
  32. package/internal/validators/util/organizationLeaveRequest.d.ts +25 -2
  33. package/internal/validators/util/organizationLeaveRequest.js +19 -3
  34. package/internal/validators/util/organizationLeaveRequest.js.map +1 -1
  35. package/package.json +1 -1
  36. package/workflows/organizations/memberships/leaveRequest.d.ts +6 -2
  37. package/workflows/organizations/memberships/leaveRequest.js +20 -5
  38. package/workflows/organizations/memberships/leaveRequest.js.map +1 -1
  39. package/workflows/organizations/memberships/leaveRequestMembersEvidence.js +80 -0
  40. package/workflows/organizations/memberships/leaveRequestMembersEvidence.js.map +1 -0
  41. package/workflows/organizations/memberships/leaveRequestMembership.d.ts +24 -0
  42. package/workflows/organizations/memberships/leaveRequestMembership.js +65 -0
  43. package/workflows/organizations/memberships/leaveRequestMembership.js.map +1 -0
  44. package/workflows/organizations/memberships/leaveRequestVerification.d.ts +15 -7
  45. package/workflows/organizations/memberships/leaveRequestVerification.js +18 -11
  46. package/workflows/organizations/memberships/leaveRequestVerification.js.map +1 -1
@@ -1,27 +1,34 @@
1
1
  import { isValidOrganizationLeaveRequest } from "../../../internal/crypto/index.js";
2
2
  /**
3
3
  * The user as shown, with its leave request kept only when the member signed
4
- * it. Every directory user a client presents passes through here, whether a
5
- * read model or a mutation response carried it.
4
+ * it during their current membership. Every directory user a client presents
5
+ * passes through here, whether a read model or a mutation response carried
6
+ * it.
6
7
  */
7
- export async function withVerifiedDirectoryUser(organizationId, user, resolveTrustedUserIdentity) {
8
+ export async function withVerifiedDirectoryUser(organizationId, user, verifier) {
8
9
  const request = user.leaveRequest;
9
10
  if (!request)
10
11
  return user;
11
12
  // The member's pinned identity, never the key the directory served beside
12
13
  // the request: a server that could swap both could forge any member's ask.
13
- const identity = await resolveTrustedUserIdentity(user.userId).catch(() => null);
14
- const verified = identity !== null &&
14
+ const identity = await verifier
15
+ .resolveTrustedUserIdentity(user.userId)
16
+ .catch(() => null);
17
+ const signed = identity !== null &&
15
18
  request.organizationId === organizationId &&
16
19
  request.userId === user.userId &&
17
20
  isValidOrganizationLeaveRequest(request, identity.signingPublicKey);
21
+ // A genuine request from a membership that has since ended would otherwise
22
+ // look current to an administrator once the member rejoined.
23
+ const verified = signed && (await verifier.membershipIsCurrent(request));
18
24
  return verified ? user : { ...user, leaveRequest: null };
19
25
  }
20
26
  /**
21
- * Keeps only leave requests their member signed, checked against the member's
22
- * trusted identity; any other is shown as no request at all.
27
+ * Keeps only leave requests their member signed during their current
28
+ * membership, checked against the member's trusted identity and this device's
29
+ * verified Members history; any other is shown as no request at all.
23
30
  */
24
- export async function withVerifiedLeaveRequests(result, resolveTrustedUserIdentity) {
31
+ export async function withVerifiedLeaveRequests(result, verifier) {
25
32
  if (!result?.directory.users.some((user) => user.leaveRequest)) {
26
33
  return result;
27
34
  }
@@ -30,17 +37,17 @@ export async function withVerifiedLeaveRequests(result, resolveTrustedUserIdenti
30
37
  ...result,
31
38
  directory: {
32
39
  ...result.directory,
33
- users: await Promise.all(result.directory.users.map((user) => withVerifiedDirectoryUser(organizationId, user, resolveTrustedUserIdentity))),
40
+ users: await Promise.all(result.directory.users.map((user) => withVerifiedDirectoryUser(organizationId, user, verifier))),
34
41
  },
35
42
  };
36
43
  }
37
44
  /** The user detail counterpart of withVerifiedLeaveRequests. */
38
- export async function withVerifiedUserLeaveRequest(detail, organizationId, resolveTrustedUserIdentity) {
45
+ export async function withVerifiedUserLeaveRequest(detail, organizationId, verifier) {
39
46
  if (!detail?.user.leaveRequest)
40
47
  return detail;
41
48
  return {
42
49
  ...detail,
43
- user: await withVerifiedDirectoryUser(organizationId, detail.user, resolveTrustedUserIdentity),
50
+ user: await withVerifiedDirectoryUser(organizationId, detail.user, verifier),
44
51
  };
45
52
  }
46
53
  //# sourceMappingURL=leaveRequestVerification.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"leaveRequestVerification.js","sourceRoot":"","sources":["leaveRequestVerification.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,+BAA+B,EAAE,MAAM,mBAAmB,CAAC;AAQpE;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,cAAsB,EACtB,IAA+B,EAC/B,0BAAuD;IAEvD,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC;IAClC,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,0EAA0E;IAC1E,2EAA2E;IAC3E,MAAM,QAAQ,GAAG,MAAM,0BAA0B,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,CAClE,GAAG,EAAE,CAAC,IAAI,CACX,CAAC;IACF,MAAM,QAAQ,GACZ,QAAQ,KAAK,IAAI;QACjB,OAAO,CAAC,cAAc,KAAK,cAAc;QACzC,OAAO,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM;QAC9B,+BAA+B,CAAC,OAAO,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IACtE,OAAO,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;AAC3D,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAG7C,MAAc,EACd,0BAAuD;IAEvD,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;QAC/D,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,CAAC,SAAS,CAAC;IAC5C,OAAO;QACL,GAAG,MAAM;QACT,SAAS,EAAE;YACT,GAAG,MAAM,CAAC,SAAS;YACnB,KAAK,EAAE,MAAM,OAAO,CAAC,GAAG,CACtB,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAClC,yBAAyB,CACvB,cAAc,EACd,IAAI,EACJ,0BAA0B,CAC3B,CACF,CACF;SACF;KACF,CAAC;AACJ,CAAC;AAED,gEAAgE;AAChE,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,MAAqC,EACrC,cAAsB,EACtB,0BAAuD;IAEvD,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY;QAAE,OAAO,MAAM,CAAC;IAC9C,OAAO;QACL,GAAG,MAAM;QACT,IAAI,EAAE,MAAM,yBAAyB,CACnC,cAAc,EACd,MAAM,CAAC,IAAI,EACX,0BAA0B,CAC3B;KACF,CAAC;AACJ,CAAC","sourcesContent":["import { isValidOrganizationLeaveRequest } from \"@tearleads/crypto\";\nimport type { TrustedUserIdentityResolver } from \"../../../data/trustedUserIdentity\";\nimport type {\n OrganizationDirectoryAndGroups,\n OrganizationDirectoryUser,\n OrganizationUserDetail,\n} from \"../readModel\";\n\n/**\n * The user as shown, with its leave request kept only when the member signed\n * it. Every directory user a client presents passes through here, whether a\n * read model or a mutation response carried it.\n */\nexport async function withVerifiedDirectoryUser(\n organizationId: string,\n user: OrganizationDirectoryUser,\n resolveTrustedUserIdentity: TrustedUserIdentityResolver,\n): Promise<OrganizationDirectoryUser> {\n const request = user.leaveRequest;\n if (!request) return user;\n // The member's pinned identity, never the key the directory served beside\n // the request: a server that could swap both could forge any member's ask.\n const identity = await resolveTrustedUserIdentity(user.userId).catch(\n () => null,\n );\n const verified =\n identity !== null &&\n request.organizationId === organizationId &&\n request.userId === user.userId &&\n isValidOrganizationLeaveRequest(request, identity.signingPublicKey);\n return verified ? user : { ...user, leaveRequest: null };\n}\n\n/**\n * Keeps only leave requests their member signed, checked against the member's\n * trusted identity; any other is shown as no request at all.\n */\nexport async function withVerifiedLeaveRequests<\n Result extends OrganizationDirectoryAndGroups | null | undefined,\n>(\n result: Result,\n resolveTrustedUserIdentity: TrustedUserIdentityResolver,\n): Promise<Result> {\n if (!result?.directory.users.some((user) => user.leaveRequest)) {\n return result;\n }\n const { organizationId } = result.directory;\n return {\n ...result,\n directory: {\n ...result.directory,\n users: await Promise.all(\n result.directory.users.map((user) =>\n withVerifiedDirectoryUser(\n organizationId,\n user,\n resolveTrustedUserIdentity,\n ),\n ),\n ),\n },\n };\n}\n\n/** The user detail counterpart of withVerifiedLeaveRequests. */\nexport async function withVerifiedUserLeaveRequest(\n detail: OrganizationUserDetail | null,\n organizationId: string,\n resolveTrustedUserIdentity: TrustedUserIdentityResolver,\n): Promise<OrganizationUserDetail | null> {\n if (!detail?.user.leaveRequest) return detail;\n return {\n ...detail,\n user: await withVerifiedDirectoryUser(\n organizationId,\n detail.user,\n resolveTrustedUserIdentity,\n ),\n };\n}\n"]}
1
+ {"version":3,"file":"leaveRequestVerification.js","sourceRoot":"","sources":["leaveRequestVerification.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,+BAA+B,EAAE,MAAM,mBAAmB,CAAC;AAepE;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,cAAsB,EACtB,IAA+B,EAC/B,QAA8B;IAE9B,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC;IAClC,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,0EAA0E;IAC1E,2EAA2E;IAC3E,MAAM,QAAQ,GAAG,MAAM,QAAQ;SAC5B,0BAA0B,CAAC,IAAI,CAAC,MAAM,CAAC;SACvC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IACrB,MAAM,MAAM,GACV,QAAQ,KAAK,IAAI;QACjB,OAAO,CAAC,cAAc,KAAK,cAAc;QACzC,OAAO,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM;QAC9B,+BAA+B,CAAC,OAAO,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IACtE,2EAA2E;IAC3E,6DAA6D;IAC7D,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,QAAQ,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC;IACzE,OAAO,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;AAC3D,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAE7C,MAAc,EAAE,QAA8B;IAC9C,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;QAC/D,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,CAAC,SAAS,CAAC;IAC5C,OAAO;QACL,GAAG,MAAM;QACT,SAAS,EAAE;YACT,GAAG,MAAM,CAAC,SAAS;YACnB,KAAK,EAAE,MAAM,OAAO,CAAC,GAAG,CACtB,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAClC,yBAAyB,CAAC,cAAc,EAAE,IAAI,EAAE,QAAQ,CAAC,CAC1D,CACF;SACF;KACF,CAAC;AACJ,CAAC;AAED,gEAAgE;AAChE,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,MAAqC,EACrC,cAAsB,EACtB,QAA8B;IAE9B,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY;QAAE,OAAO,MAAM,CAAC;IAC9C,OAAO;QACL,GAAG,MAAM;QACT,IAAI,EAAE,MAAM,yBAAyB,CACnC,cAAc,EACd,MAAM,CAAC,IAAI,EACX,QAAQ,CACT;KACF,CAAC;AACJ,CAAC","sourcesContent":["import { isValidOrganizationLeaveRequest } from \"@tearleads/crypto\";\nimport type { TrustedUserIdentityResolver } from \"../../../data/trustedUserIdentity\";\nimport type {\n OrganizationDirectoryAndGroups,\n OrganizationDirectoryUser,\n OrganizationUserDetail,\n} from \"../readModel\";\nimport type { LeaveRequestMembershipCheck } from \"./leaveRequestMembership\";\n\n/** What a shown leave request is checked against. */\nexport interface LeaveRequestVerifier {\n readonly resolveTrustedUserIdentity: TrustedUserIdentityResolver;\n readonly membershipIsCurrent: LeaveRequestMembershipCheck;\n}\n\n/**\n * The user as shown, with its leave request kept only when the member signed\n * it during their current membership. Every directory user a client presents\n * passes through here, whether a read model or a mutation response carried\n * it.\n */\nexport async function withVerifiedDirectoryUser(\n organizationId: string,\n user: OrganizationDirectoryUser,\n verifier: LeaveRequestVerifier,\n): Promise<OrganizationDirectoryUser> {\n const request = user.leaveRequest;\n if (!request) return user;\n // The member's pinned identity, never the key the directory served beside\n // the request: a server that could swap both could forge any member's ask.\n const identity = await verifier\n .resolveTrustedUserIdentity(user.userId)\n .catch(() => null);\n const signed =\n identity !== null &&\n request.organizationId === organizationId &&\n request.userId === user.userId &&\n isValidOrganizationLeaveRequest(request, identity.signingPublicKey);\n // A genuine request from a membership that has since ended would otherwise\n // look current to an administrator once the member rejoined.\n const verified = signed && (await verifier.membershipIsCurrent(request));\n return verified ? user : { ...user, leaveRequest: null };\n}\n\n/**\n * Keeps only leave requests their member signed during their current\n * membership, checked against the member's trusted identity and this device's\n * verified Members history; any other is shown as no request at all.\n */\nexport async function withVerifiedLeaveRequests<\n Result extends OrganizationDirectoryAndGroups | null | undefined,\n>(result: Result, verifier: LeaveRequestVerifier): Promise<Result> {\n if (!result?.directory.users.some((user) => user.leaveRequest)) {\n return result;\n }\n const { organizationId } = result.directory;\n return {\n ...result,\n directory: {\n ...result.directory,\n users: await Promise.all(\n result.directory.users.map((user) =>\n withVerifiedDirectoryUser(organizationId, user, verifier),\n ),\n ),\n },\n };\n}\n\n/** The user detail counterpart of withVerifiedLeaveRequests. */\nexport async function withVerifiedUserLeaveRequest(\n detail: OrganizationUserDetail | null,\n organizationId: string,\n verifier: LeaveRequestVerifier,\n): Promise<OrganizationUserDetail | null> {\n if (!detail?.user.leaveRequest) return detail;\n return {\n ...detail,\n user: await withVerifiedDirectoryUser(\n organizationId,\n detail.user,\n verifier,\n ),\n };\n}\n"]}