@verii/endpoints-organizations-registrar 1.0.0-pre.1752076816

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 (259) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +1 -0
  3. package/README.md +3 -0
  4. package/package.json +86 -0
  5. package/src/config/abi.json +1 -0
  6. package/src/config/config.js +261 -0
  7. package/src/controllers/consents/autohooks.js +6 -0
  8. package/src/controllers/consents/controller.js +106 -0
  9. package/src/controllers/consents/schemas/consent-response.schema.js +45 -0
  10. package/src/controllers/did-web-host/controller.js +64 -0
  11. package/src/controllers/groups/autohooks.js +10 -0
  12. package/src/controllers/groups/controller.js +172 -0
  13. package/src/controllers/groups/schemas/group.schema.json +22 -0
  14. package/src/controllers/groups/schemas/index.js +7 -0
  15. package/src/controllers/groups/schemas/modify-group.schema.json +25 -0
  16. package/src/controllers/image_upload/controller.js +48 -0
  17. package/src/controllers/invitations/controller.js +79 -0
  18. package/src/controllers/organizations/_did/autohooks.js +16 -0
  19. package/src/controllers/organizations/_did/controller.js +617 -0
  20. package/src/controllers/organizations/_did/invitations/_invitationId/autohooks.js +16 -0
  21. package/src/controllers/organizations/_did/invitations/_invitationId/controller.js +217 -0
  22. package/src/controllers/organizations/_did/invitations/controller.js +197 -0
  23. package/src/controllers/organizations/_did/keys/controller.js +141 -0
  24. package/src/controllers/organizations/_did/services/controller.js +195 -0
  25. package/src/controllers/organizations/_did/signatories/controller.js +63 -0
  26. package/src/controllers/organizations/autohooks.js +65 -0
  27. package/src/controllers/organizations/controller.js +322 -0
  28. package/src/controllers/organizations/full/controller.js +285 -0
  29. package/src/controllers/organizations/plugins.js +21 -0
  30. package/src/controllers/organizations/schemas/add-key-body.schema.json +35 -0
  31. package/src/controllers/organizations/schemas/create-did-service.schema.json +70 -0
  32. package/src/controllers/organizations/schemas/did-key.schema.json +178 -0
  33. package/src/controllers/organizations/schemas/full-organization.schema.json +35 -0
  34. package/src/controllers/organizations/schemas/index.js +33 -0
  35. package/src/controllers/organizations/schemas/invitationCodeProperty.schema.json +3 -0
  36. package/src/controllers/organizations/schemas/organization-ids.schema.json +34 -0
  37. package/src/controllers/organizations/schemas/organization-kyb-profile-creation.schema.json +26 -0
  38. package/src/controllers/organizations/schemas/organization-profile-creation.schema.json +20 -0
  39. package/src/controllers/organizations/schemas/organization-profile-update.schema.json +19 -0
  40. package/src/controllers/organizations/schemas/organization-profile-verifiable-credential.schema.json +25 -0
  41. package/src/controllers/organizations/schemas/organization-registry-service-response.schema.json +26 -0
  42. package/src/controllers/organizations/schemas/organization-service.schema.json +34 -0
  43. package/src/controllers/organizations/schemas/organization-verified-profile.schema.json +123 -0
  44. package/src/controllers/organizations/schemas/organization.search-profile.query-params.schema.json +50 -0
  45. package/src/controllers/organizations/schemas/organization.search.query-params.schema.json +42 -0
  46. package/src/controllers/reference/controller.js +103 -0
  47. package/src/controllers/resolve-did/controller.js +45 -0
  48. package/src/controllers/resolve-did/resolve-did.js +30 -0
  49. package/src/controllers/resolve-did/schemas/did-doc.schema.json +155 -0
  50. package/src/controllers/resolve-did/schemas/did-proof.schema.json +44 -0
  51. package/src/controllers/resolve-did/schemas/index.js +26 -0
  52. package/src/controllers/resolve-did/schemas/public-key.schema.json +173 -0
  53. package/src/controllers/resolve-kid/controller.js +76 -0
  54. package/src/controllers/resolve-kid/public-key-formats.js +8 -0
  55. package/src/controllers/service-types/controller.js +81 -0
  56. package/src/controllers/setup_image_upload/controller.js +99 -0
  57. package/src/controllers/signatories/controller.js +43 -0
  58. package/src/controllers/users/autohooks.js +10 -0
  59. package/src/controllers/users/controller.js +221 -0
  60. package/src/controllers/users/schemas/base-user.schema.json +55 -0
  61. package/src/controllers/users/schemas/index.js +4 -0
  62. package/src/controllers/users/schemas/modify-user.schema.js +17 -0
  63. package/src/controllers/users/schemas/user.schema.js +20 -0
  64. package/src/entities/groups/domain/constants.js +21 -0
  65. package/src/entities/groups/domain/index.js +19 -0
  66. package/src/entities/groups/factories/groups-factory.js +48 -0
  67. package/src/entities/groups/factories/index.js +17 -0
  68. package/src/entities/groups/index.js +19 -0
  69. package/src/entities/groups/repo.js +122 -0
  70. package/src/entities/images/domain/constant.js +11 -0
  71. package/src/entities/images/domain/index.js +3 -0
  72. package/src/entities/images/extension/activate.extension.js +35 -0
  73. package/src/entities/images/extension/deactivate.extension.js +27 -0
  74. package/src/entities/images/extension/find-by-url.extension.js +24 -0
  75. package/src/entities/images/extension/index.js +5 -0
  76. package/src/entities/images/factories/images-factory.js +43 -0
  77. package/src/entities/images/factories/index.js +17 -0
  78. package/src/entities/images/index.js +5 -0
  79. package/src/entities/images/repo.js +43 -0
  80. package/src/entities/images/schema/image-metadata.schema.js +58 -0
  81. package/src/entities/images/schema/index.js +3 -0
  82. package/src/entities/index.js +31 -0
  83. package/src/entities/invitations/domains/build-invitation-url.js +14 -0
  84. package/src/entities/invitations/domains/get-given-family-name-from-name.js +20 -0
  85. package/src/entities/invitations/domains/index.js +7 -0
  86. package/src/entities/invitations/domains/init-invitation-emails.js +17 -0
  87. package/src/entities/invitations/domains/is-invitation-expired.js +5 -0
  88. package/src/entities/invitations/domains/validate-invitee-email.js +18 -0
  89. package/src/entities/invitations/factories/index.js +17 -0
  90. package/src/entities/invitations/factories/invitations-factory.js +51 -0
  91. package/src/entities/invitations/index.js +6 -0
  92. package/src/entities/invitations/orchestrators/accept-invitation.js +24 -0
  93. package/src/entities/invitations/orchestrators/index.js +4 -0
  94. package/src/entities/invitations/orchestrators/send-email-invitee.js +36 -0
  95. package/src/entities/invitations/repo.js +37 -0
  96. package/src/entities/invitations/schemas/add-invitation-body.js +122 -0
  97. package/src/entities/invitations/schemas/get-invitation-response-body.js +20 -0
  98. package/src/entities/invitations/schemas/index.js +5 -0
  99. package/src/entities/invitations/schemas/invitation-response-item-body.js +61 -0
  100. package/src/entities/kms/factories/index.js +17 -0
  101. package/src/entities/kms/factories/kms-factory.js +31 -0
  102. package/src/entities/monitors/index.js +17 -0
  103. package/src/entities/monitors/orchestrators/index.js +17 -0
  104. package/src/entities/monitors/orchestrators/monitors.js +230 -0
  105. package/src/entities/oauth/domain/constants.js +23 -0
  106. package/src/entities/oauth/domain/index.js +5 -0
  107. package/src/entities/oauth/domain/roles.js +92 -0
  108. package/src/entities/oauth/domain/scopes.js +35 -0
  109. package/src/entities/oauth/index.js +4 -0
  110. package/src/entities/oauth/orchestrators/auth0-provisioner.js +293 -0
  111. package/src/entities/oauth/orchestrators/index.js +3 -0
  112. package/src/entities/organization-keys/domains/build-organization-key.js +50 -0
  113. package/src/entities/organization-keys/domains/constants.js +30 -0
  114. package/src/entities/organization-keys/domains/extract-verification-method-from-byo-did-document.js +38 -0
  115. package/src/entities/organization-keys/domains/find-key-by-purpose.js +6 -0
  116. package/src/entities/organization-keys/domains/index.js +10 -0
  117. package/src/entities/organization-keys/domains/jwk-to-hex-key-transformer.js +13 -0
  118. package/src/entities/organization-keys/domains/map-key-response.js +29 -0
  119. package/src/entities/organization-keys/domains/validate-non-custodial-key.js +11 -0
  120. package/src/entities/organization-keys/domains/validate-organization-key.js +42 -0
  121. package/src/entities/organization-keys/factories/index.js +17 -0
  122. package/src/entities/organization-keys/factories/organization-keys-factory.js +55 -0
  123. package/src/entities/organization-keys/index.js +5 -0
  124. package/src/entities/organization-keys/orchestrators/add-key-to-did-doc.js +19 -0
  125. package/src/entities/organization-keys/orchestrators/add-key.js +155 -0
  126. package/src/entities/organization-keys/orchestrators/add-operator-keys.js +46 -0
  127. package/src/entities/organization-keys/orchestrators/delete-key.js +93 -0
  128. package/src/entities/organization-keys/orchestrators/get-key.js +39 -0
  129. package/src/entities/organization-keys/orchestrators/index.js +24 -0
  130. package/src/entities/organization-keys/orchestrators/resolve-verification-method-byo-did.js +28 -0
  131. package/src/entities/organization-keys/repos/repo.js +48 -0
  132. package/src/entities/organization-services/adapters/index.js +21 -0
  133. package/src/entities/organization-services/adapters/init-provision-auth0-client-grants.js +44 -0
  134. package/src/entities/organization-services/adapters/init-provision-auth0-clients.js +56 -0
  135. package/src/entities/organization-services/adapters/update-blockchain-permissions-from-permitted-services.js +118 -0
  136. package/src/entities/organization-services/domains/activate-services.js +12 -0
  137. package/src/entities/organization-services/domains/build-organizations-services.js +38 -0
  138. package/src/entities/organization-services/domains/build-public-services.js +19 -0
  139. package/src/entities/organization-services/domains/constants.js +32 -0
  140. package/src/entities/organization-services/domains/extract-cao-service-refs.js +10 -0
  141. package/src/entities/organization-services/domains/extract-service-endpoint-did.js +10 -0
  142. package/src/entities/organization-services/domains/get-service-consent-type.js +16 -0
  143. package/src/entities/organization-services/domains/get-service-types-from-categories.js +18 -0
  144. package/src/entities/organization-services/domains/index.js +17 -0
  145. package/src/entities/organization-services/domains/is-new-node-operator-service.js +25 -0
  146. package/src/entities/organization-services/domains/is-service-category.js +31 -0
  147. package/src/entities/organization-services/domains/normalize-service-endpoint.js +6 -0
  148. package/src/entities/organization-services/domains/select-activated-services.js +8 -0
  149. package/src/entities/organization-services/domains/transform-profile-service.js +88 -0
  150. package/src/entities/organization-services/domains/validate-cao-service-refs.js +25 -0
  151. package/src/entities/organization-services/domains/validate-service-credential-type.js +47 -0
  152. package/src/entities/organization-services/domains/validate-service-endpoint.js +35 -0
  153. package/src/entities/organization-services/domains/validate-service-fields-by-service-type.js +37 -0
  154. package/src/entities/organization-services/domains/validate-service-id-uniqueness.js +19 -0
  155. package/src/entities/organization-services/domains/validate-service-key-purposes.js +56 -0
  156. package/src/entities/organization-services/domains/validate-service-type.js +12 -0
  157. package/src/entities/organization-services/domains/validate-service.js +80 -0
  158. package/src/entities/organization-services/domains/validate-services-for-delete.js +32 -0
  159. package/src/entities/organization-services/index.js +5 -0
  160. package/src/entities/organization-services/orchestrators/add-service.js +106 -0
  161. package/src/entities/organization-services/orchestrators/delete-service.js +142 -0
  162. package/src/entities/organization-services/orchestrators/get-service.js +36 -0
  163. package/src/entities/organization-services/orchestrators/index.js +8 -0
  164. package/src/entities/organization-services/orchestrators/init-add-service-to-organization.js +141 -0
  165. package/src/entities/organization-services/orchestrators/load-cao-service-refs.js +56 -0
  166. package/src/entities/organization-services/orchestrators/update-service.js +103 -0
  167. package/src/entities/organizations/adapters/index.js +6 -0
  168. package/src/entities/organizations/adapters/init-organization-registrar-emails.js +215 -0
  169. package/src/entities/organizations/adapters/init-send-activation-emails-to-caos.js +89 -0
  170. package/src/entities/organizations/adapters/send-email-invitation-accepted-to-inviter.js +70 -0
  171. package/src/entities/organizations/adapters/send-email-notifications.js +212 -0
  172. package/src/entities/organizations/domains/build-custodied-did-web.js +12 -0
  173. package/src/entities/organizations/domains/build-full-organization-response.js +40 -0
  174. package/src/entities/organizations/domains/build-organization-modifications-on-service-change.js +82 -0
  175. package/src/entities/organizations/domains/build-profile-vc-url.js +8 -0
  176. package/src/entities/organizations/domains/build-profile-verifiable-credential.js +36 -0
  177. package/src/entities/organizations/domains/build-public-profile.js +9 -0
  178. package/src/entities/organizations/domains/constants.js +54 -0
  179. package/src/entities/organizations/domains/index.js +17 -0
  180. package/src/entities/organizations/domains/organization-vc-checks.js +49 -0
  181. package/src/entities/organizations/domains/parse-profile-to-csv.js +41 -0
  182. package/src/entities/organizations/domains/prepare-profile-vc.js +28 -0
  183. package/src/entities/organizations/domains/profile-name-normalization.js +5 -0
  184. package/src/entities/organizations/domains/validate-byo-did-keys.js +28 -0
  185. package/src/entities/organizations/domains/validate-profile-name.js +48 -0
  186. package/src/entities/organizations/domains/validate-profile-website.js +17 -0
  187. package/src/entities/organizations/domains/validate-update-profile.js +11 -0
  188. package/src/entities/organizations/factories/index.js +17 -0
  189. package/src/entities/organizations/factories/organizations-factory.js +180 -0
  190. package/src/entities/organizations/index.js +6 -0
  191. package/src/entities/organizations/orchestrators/add-primary-permissions.js +28 -0
  192. package/src/entities/organizations/orchestrators/build-custodied-organization.js +92 -0
  193. package/src/entities/organizations/orchestrators/build-non-custodied-organization.js +83 -0
  194. package/src/entities/organizations/orchestrators/index.js +6 -0
  195. package/src/entities/organizations/orchestrators/init-create-organization.js +221 -0
  196. package/src/entities/organizations/orchestrators/init-provision-group.js +48 -0
  197. package/src/entities/organizations/orchestrators/verify-profile-website-unique.js +15 -0
  198. package/src/entities/organizations/repos/find-caos-extension.js +49 -0
  199. package/src/entities/organizations/repos/index.js +17 -0
  200. package/src/entities/organizations/repos/repo.js +156 -0
  201. package/src/entities/organizations/repos/search-by-aggregation-extension.js +128 -0
  202. package/src/entities/organizations/repos/transform-did-filter.js +13 -0
  203. package/src/entities/organizations/repos/transform-organization-filter.js +106 -0
  204. package/src/entities/registrar-consents/constants.js +10 -0
  205. package/src/entities/registrar-consents/factories/index.js +17 -0
  206. package/src/entities/registrar-consents/factories/registrar-consents-factory.js +38 -0
  207. package/src/entities/registrar-consents/index.js +3 -0
  208. package/src/entities/registrar-consents/repos/registrar-consent-repo-extension.js +55 -0
  209. package/src/entities/registrar-consents/repos/repo.js +31 -0
  210. package/src/entities/signatories/domain/constants.js +12 -0
  211. package/src/entities/signatories/domain/index.js +4 -0
  212. package/src/entities/signatories/domain/organization-emails.js +29 -0
  213. package/src/entities/signatories/factories/index.js +17 -0
  214. package/src/entities/signatories/factories/signatory-status-factory.js +53 -0
  215. package/src/entities/signatories/index.js +5 -0
  216. package/src/entities/signatories/orchestrators/approve-reminder.js +24 -0
  217. package/src/entities/signatories/orchestrators/index.js +6 -0
  218. package/src/entities/signatories/orchestrators/reject-reminder.js +17 -0
  219. package/src/entities/signatories/orchestrators/send-reminders.js +102 -0
  220. package/src/entities/signatories/orchestrators/validate-auth-code.js +56 -0
  221. package/src/entities/signatories/repos/index.js +3 -0
  222. package/src/entities/signatories/repos/repo.js +35 -0
  223. package/src/entities/signatories/repos/signatory-status-state-repo-extension.js +124 -0
  224. package/src/entities/users/domains/constants.js +40 -0
  225. package/src/entities/users/domains/index.js +4 -0
  226. package/src/entities/users/domains/user-registrar-emails.js +52 -0
  227. package/src/entities/users/index.js +4 -0
  228. package/src/entities/users/orchestrators/create-auth0-user.js +60 -0
  229. package/src/entities/users/orchestrators/get-or-create-auth0-user.js +63 -0
  230. package/src/entities/users/orchestrators/index.js +22 -0
  231. package/src/entities/users/orchestrators/user-management.js +157 -0
  232. package/src/fetchers/index.js +19 -0
  233. package/src/fetchers/monitoring/index.js +9 -0
  234. package/src/fetchers/monitoring/monitor-add-to-page-fetcher.js +18 -0
  235. package/src/fetchers/monitoring/monitor-create-fetcher.js +23 -0
  236. package/src/fetchers/monitoring/monitor-delete-fetcher.js +6 -0
  237. package/src/fetchers/monitoring/monitor-get-all-fetcher.js +6 -0
  238. package/src/fetchers/monitoring/section-create-fetcher.js +16 -0
  239. package/src/fetchers/monitoring/section-get-all-fetcher.js +6 -0
  240. package/src/fetchers/monitoring/service-version-fetcher.js +6 -0
  241. package/src/helpers/init-permissions-contract.js +48 -0
  242. package/src/index.js +23 -0
  243. package/src/init-server.js +91 -0
  244. package/src/organizations-registrar-endpoints.js +68 -0
  245. package/src/plugins/authorization.js +233 -0
  246. package/src/plugins/index.js +4 -0
  247. package/src/plugins/pubsub-plugin.js +82 -0
  248. package/src/subscribers/notify-caos.js +63 -0
  249. package/src/subscribers/notify-inviters.js +42 -0
  250. package/src/subscribers/notify-monitoring.js +40 -0
  251. package/src/subscribers/notify-signatory.js +51 -0
  252. package/src/subscribers/notify-support-and-groups.js +95 -0
  253. package/src/templates/invitee-invitation-email-body.hbs +13 -0
  254. package/src/templates/invitee-invitation-email-subject.hbs +1 -0
  255. package/src/templates/signatory-approval-email-body.hbs +92 -0
  256. package/src/templates/support-organization-created-body.hbs +17 -0
  257. package/src/templates/support-organization-created-subject.hbs +1 -0
  258. package/src/templates/support-signatory-max-reminders-reached-email-body.hbs +6 -0
  259. package/src/templates/support-signatory-max-reminders-reached-email-subject.hbs +1 -0
@@ -0,0 +1,27 @@
1
+ const { isEmpty } = require('lodash/fp');
2
+ const { ImageState } = require('../domain');
3
+
4
+ const deactivateExtension = (parent) => ({
5
+ deactivate: async (url) => {
6
+ const image = await parent.findOne({
7
+ filter: {
8
+ url,
9
+ },
10
+ });
11
+ if (isEmpty(image)) {
12
+ return;
13
+ }
14
+ await parent.collection().updateOne(
15
+ { url },
16
+ {
17
+ $set: {
18
+ updatedAt: new Date(),
19
+ state: ImageState.INACTIVE,
20
+ },
21
+ }
22
+ );
23
+ },
24
+ extensions: parent.extensions.concat(['deactivate']),
25
+ });
26
+
27
+ module.exports = { deactivateExtension };
@@ -0,0 +1,24 @@
1
+ const newError = require('http-errors');
2
+ const { isEmpty } = require('lodash/fp');
3
+
4
+ const findByUrlExtension = (parent) => ({
5
+ findByUrl: async (url, userId) => {
6
+ const imageData = await parent.findOne({
7
+ filter: {
8
+ url,
9
+ userId,
10
+ },
11
+ });
12
+
13
+ if (isEmpty(imageData)) {
14
+ throw newError(404, 'Image not found', {
15
+ errorCode: 'image_not_found',
16
+ });
17
+ }
18
+
19
+ return imageData;
20
+ },
21
+ extensions: parent.extensions.concat(['findByUrl']),
22
+ });
23
+
24
+ module.exports = { findByUrlExtension };
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ ...require('./find-by-url.extension'),
3
+ ...require('./activate.extension'),
4
+ ...require('./deactivate.extension'),
5
+ };
@@ -0,0 +1,43 @@
1
+ /*
2
+ * Copyright 2025 Velocity Team
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ const { register } = require('@spencejs/spence-factories');
19
+
20
+ const { testRegistrarUser } = require('@verii/tests-helpers');
21
+ const imagesRepoPlugin = require('../repo');
22
+ const { ImageState } = require('../domain');
23
+
24
+ module.exports = (app) =>
25
+ register(
26
+ 'image',
27
+ imagesRepoPlugin(app)({ config: app.config }),
28
+ async (overrides, { getOrBuild }) => {
29
+ const userId = await getOrBuild('userId', () => testRegistrarUser.sub);
30
+
31
+ return {
32
+ userId,
33
+ key: 'file-1234567.png',
34
+ url: 'http://media.localhost.test/file-1234567.png',
35
+ uploadUrl: 'http://aws.s3.test/file-1234567.png',
36
+ uploadSucceeded: false,
37
+ state: ImageState.PENDING_UPLOAD,
38
+ createdAt: new Date(),
39
+ updatedAt: new Date(),
40
+ ...overrides(),
41
+ };
42
+ }
43
+ );
@@ -0,0 +1,17 @@
1
+ /*
2
+ * Copyright 2025 Velocity Team
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+ module.exports = { ...require('./images-factory') };
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ imageRepoPlugin: require('./repo'),
3
+ ...require('./domain'),
4
+ ...require('./schema'),
5
+ };
@@ -0,0 +1,43 @@
1
+ const {
2
+ repoFactory,
3
+ autoboxIdsExtension,
4
+ } = require('@spencejs/spence-mongo-repos');
5
+ const {
6
+ findByUrlExtension,
7
+ activateExtension,
8
+ deactivateExtension,
9
+ } = require('./extension');
10
+
11
+ module.exports = (app, options, next = () => {}) => {
12
+ next();
13
+ return repoFactory(
14
+ {
15
+ name: 'images',
16
+ entityName: 'images',
17
+ defaultProjection: {
18
+ _id: 1,
19
+ key: 1,
20
+ url: 1,
21
+ uploadUrl: 1,
22
+ userId: 1,
23
+ state: 1,
24
+ uploadSucceeded: 1,
25
+ activateAt: 1,
26
+ createdAt: 1,
27
+ updatedAt: 1,
28
+ errorCode: 1,
29
+ },
30
+ timestampKeys: {
31
+ createdAt: 'createdAt',
32
+ updatedAt: 'updatedAt',
33
+ },
34
+ extensions: [
35
+ autoboxIdsExtension,
36
+ findByUrlExtension,
37
+ activateExtension,
38
+ deactivateExtension,
39
+ ],
40
+ },
41
+ app
42
+ );
43
+ };
@@ -0,0 +1,58 @@
1
+ const { values } = require('lodash/fp');
2
+ const { ImageState } = require('../domain');
3
+
4
+ const imageMetadataSchema = {
5
+ title: 'image-metadata',
6
+ $id: 'https://velocitycareerlabs.io/image-metadata.schema.json',
7
+ type: 'object',
8
+ description: 'Image metadata schema',
9
+ properties: {
10
+ imageMetadata: {
11
+ type: 'object',
12
+ properties: {
13
+ url: {
14
+ type: 'string',
15
+ },
16
+ userId: {
17
+ type: 'string',
18
+ },
19
+ uploadUrl: {
20
+ type: 'string',
21
+ },
22
+ state: {
23
+ type: 'string',
24
+ enum: values(ImageState),
25
+ },
26
+ uploadSucceeded: {
27
+ type: 'boolean',
28
+ },
29
+ errorCode: {
30
+ type: 'string',
31
+ },
32
+ createdAt: {
33
+ type: 'string',
34
+ format: 'date-time',
35
+ },
36
+ updatedAt: {
37
+ type: 'string',
38
+ format: 'date-time',
39
+ },
40
+ activateAt: {
41
+ type: 'string',
42
+ format: 'date-time',
43
+ },
44
+ },
45
+ required: [
46
+ 'url',
47
+ 'userId',
48
+ 'state',
49
+ 'uploadSucceeded',
50
+ 'createdAt',
51
+ 'updatedAt',
52
+ ],
53
+ },
54
+ },
55
+ required: ['imageMetadata'],
56
+ };
57
+
58
+ module.exports = { imageMetadataSchema };
@@ -0,0 +1,3 @@
1
+ module.exports = {
2
+ ...require('./image-metadata.schema'),
3
+ };
@@ -0,0 +1,31 @@
1
+ /*
2
+ * Copyright 2025 Velocity Team
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ module.exports = {
19
+ ...require('./groups'),
20
+ ...require('./invitations'),
21
+ ...require('./images'),
22
+ ...require('./oauth'),
23
+ ...require('./organization-services'),
24
+ ...require('./organizations'),
25
+ ...require('./organization-keys'),
26
+ ...require('./registrar-consents'),
27
+ ...require('./monitors'),
28
+ // TODO probably remove the below once broker is refactored vl-5139
29
+ ...require('./signatories'),
30
+ ...require('./users'),
31
+ };
@@ -0,0 +1,14 @@
1
+ const { sprintf } = require('sprintf-js');
2
+ const { isEmpty } = require('lodash/fp');
3
+
4
+ const buildInvitationUrl = ({ code, ticket }, { config }) => {
5
+ const url = new URL(sprintf(config.inviteUrl, [code]));
6
+ if (!isEmpty(ticket)) {
7
+ url.searchParams.append('signup_url', encodeURI(ticket));
8
+ }
9
+ return url.toString();
10
+ };
11
+
12
+ module.exports = {
13
+ buildInvitationUrl,
14
+ };
@@ -0,0 +1,20 @@
1
+ const { split, isEmpty } = require('lodash/fp');
2
+
3
+ const getGivenFamilyNameFromName = (inviteeProfileName) => {
4
+ const [givenName, familyName] = split(' ', inviteeProfileName);
5
+
6
+ if (isEmpty(familyName)) {
7
+ return {
8
+ givenName,
9
+ };
10
+ }
11
+
12
+ return {
13
+ givenName,
14
+ familyName,
15
+ };
16
+ };
17
+
18
+ module.exports = {
19
+ getGivenFamilyNameFromName,
20
+ };
@@ -0,0 +1,7 @@
1
+ module.exports = {
2
+ ...require('./build-invitation-url'),
3
+ ...require('./get-given-family-name-from-name'),
4
+ ...require('./init-invitation-emails'),
5
+ ...require('./is-invitation-expired'),
6
+ ...require('./validate-invitee-email'),
7
+ };
@@ -0,0 +1,17 @@
1
+ const inviteeInvitationEmail = async (
2
+ { inviterOrganization, inviteeEmail, uri },
3
+ context
4
+ ) => ({
5
+ subject: await context.renderTemplate('invitee-invitation-email-subject', {
6
+ inviterOrganization,
7
+ }),
8
+ message: await context.renderTemplate('invitee-invitation-email-body', {
9
+ inviterOrganization,
10
+ uri,
11
+ }),
12
+ sender: context.config.registrarSupportEmail,
13
+ recipients: [inviteeEmail],
14
+ html: true,
15
+ });
16
+
17
+ module.exports = { inviteeInvitationEmail };
@@ -0,0 +1,5 @@
1
+ const isInvitationExpired = (invitation) => invitation.expiresAt < new Date();
2
+
3
+ module.exports = {
4
+ isInvitationExpired,
5
+ };
@@ -0,0 +1,18 @@
1
+ const newError = require('http-errors');
2
+
3
+ const validateInviteeEmail = (email) => {
4
+ const re = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
5
+ if (!re.test(email)) {
6
+ throw newError(
7
+ 400,
8
+ 'The email address is invalid and the invitation was not sent',
9
+ {
10
+ errorCode: 'bad_invitee_email',
11
+ }
12
+ );
13
+ }
14
+ };
15
+
16
+ module.exports = {
17
+ validateInviteeEmail,
18
+ };
@@ -0,0 +1,17 @@
1
+ /*
2
+ * Copyright 2025 Velocity Team
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+ module.exports = { ...require('./invitations-factory') };
@@ -0,0 +1,51 @@
1
+ /*
2
+ * Copyright 2025 Velocity Team
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ const { omit } = require('lodash/fp');
19
+ const { register } = require('@spencejs/spence-factories');
20
+ const { addWeeks } = require('date-fns/fp');
21
+ const invitationsRepoPlugin = require('../repo');
22
+
23
+ module.exports = (app) =>
24
+ register(
25
+ 'invitation',
26
+ invitationsRepoPlugin(app)({ config: app.config }),
27
+ async (overrides) => {
28
+ const overridesResult = overrides();
29
+ const inviteeService =
30
+ overridesResult.inviteeOrganization?.didDoc.service;
31
+ const inviteeProfile = overridesResult.inviteeOrganization?.profile;
32
+ const inviterDid = overridesResult.inviterOrganization?.didDoc.id;
33
+
34
+ return {
35
+ inviteeEmail: 'foo@example.com',
36
+ invitationUrl: 'https://someurl.com',
37
+ inviteeService,
38
+ inviteeProfile,
39
+ inviterDid,
40
+ code: '1234567812345678',
41
+ expiresAt: addWeeks(1, new Date()),
42
+ createdAt: new Date(),
43
+ updatedAt: new Date(),
44
+ createdBy: 'sub-123',
45
+ ...omit(
46
+ ['inviterOrganization', 'inviteeOrganization'],
47
+ overridesResult
48
+ ),
49
+ };
50
+ }
51
+ );
@@ -0,0 +1,6 @@
1
+ module.exports = {
2
+ invitationsRepoPlugin: require('./repo'),
3
+ ...require('./domains'),
4
+ ...require('./orchestrators'),
5
+ ...require('./schemas'),
6
+ };
@@ -0,0 +1,24 @@
1
+ const { isInvitationExpired } = require('../domains');
2
+
3
+ const acceptInvitation = async (invitationCode, ctx) => {
4
+ const { repos, log, user } = ctx;
5
+ if (!invitationCode) {
6
+ return undefined;
7
+ }
8
+ const invitation = await repos.invitations.findOne({
9
+ filter: { code: invitationCode },
10
+ });
11
+ if (!invitation) {
12
+ log.warn({ invitationCode }, 'unable to accept invalid invitation');
13
+ return undefined;
14
+ }
15
+ if (isInvitationExpired(invitation)) {
16
+ log.warn({ invitationCode }, 'unable to accept expired invitation');
17
+ return undefined;
18
+ }
19
+ return repos.invitations.update(invitation._id, {
20
+ acceptedAt: new Date(),
21
+ acceptedBy: user.sub,
22
+ });
23
+ };
24
+ module.exports = { acceptInvitation };
@@ -0,0 +1,4 @@
1
+ module.exports = {
2
+ ...require('./accept-invitation'),
3
+ ...require('./send-email-invitee'),
4
+ };
@@ -0,0 +1,36 @@
1
+ const { buildInvitationUrl, inviteeInvitationEmail } = require('../domains');
2
+
3
+ const initSendEmailInvitee = (fastify) => {
4
+ const { sendEmail, sendError } = fastify;
5
+
6
+ return async (
7
+ { ticket, inviteeEmail, inviterOrganization, code },
8
+ context
9
+ ) => {
10
+ try {
11
+ const uri = buildInvitationUrl({ code, ticket }, context);
12
+
13
+ await sendEmail(
14
+ await inviteeInvitationEmail(
15
+ {
16
+ inviteeEmail,
17
+ inviterOrganization,
18
+ uri,
19
+ },
20
+ context
21
+ )
22
+ );
23
+ return 'invitation_sent';
24
+ } catch (error) {
25
+ const message = 'Unable to send invitation email to user';
26
+ const messageContext = { err: error, email: inviteeEmail };
27
+ context.log.error(messageContext, message);
28
+ sendError(error, { ...messageContext, message });
29
+ return 'invitation_not_sent';
30
+ }
31
+ };
32
+ };
33
+
34
+ module.exports = {
35
+ initSendEmailInvitee,
36
+ };
@@ -0,0 +1,37 @@
1
+ const {
2
+ repoFactory,
3
+ autoboxIdsExtension,
4
+ } = require('@spencejs/spence-mongo-repos');
5
+ const { deletedExtension } = require('@verii/spencer-mongo-extensions');
6
+
7
+ module.exports = (app, options, next = () => {}) => {
8
+ next();
9
+ return repoFactory(
10
+ {
11
+ name: 'invitations',
12
+ entityName: 'invitations',
13
+ defaultProjection: {
14
+ _id: 1,
15
+ acceptedAt: 1,
16
+ acceptedBy: 1,
17
+ invitationUrl: 1,
18
+ inviterDid: 1,
19
+ inviteeEmail: 1,
20
+ inviteeService: 1,
21
+ inviteeProfile: 1,
22
+ keyIndividuals: 1,
23
+ inviteeDid: 1,
24
+ code: 1,
25
+ expiresAt: 1,
26
+ createdAt: 1,
27
+ createdBy: 1,
28
+ updatedAt: 1,
29
+ updatedBy: 1,
30
+ deletedAt: 1,
31
+ deletedBy: 1,
32
+ },
33
+ extensions: [autoboxIdsExtension, deletedExtension()],
34
+ },
35
+ app
36
+ );
37
+ };
@@ -0,0 +1,122 @@
1
+ const { omit, values, pick } = require('lodash/fp');
2
+ const { organizationProfileBaseSchema } = require('@verii/common-schemas');
3
+ const {
4
+ ServiceCategories,
5
+ ServiceTypesOfServiceCategory,
6
+ } = require('@verii/organizations-registry');
7
+
8
+ const keyIndividualProperties = [
9
+ 'adminGivenName',
10
+ 'adminFamilyName',
11
+ 'adminTitle',
12
+ 'adminEmail',
13
+ 'signatoryGivenName',
14
+ 'signatoryFamilyName',
15
+ 'signatoryTitle',
16
+ 'signatoryEmail',
17
+ ];
18
+
19
+ const addInvitationBodySchema = {
20
+ title: 'add-invitation-body',
21
+ $id: 'https://velocitycareerlabs.io/add-invitation-body.json',
22
+ type: 'object',
23
+ description:
24
+ 'payload for adding a invitations to an organization in the registrar',
25
+ properties: {
26
+ inviteeEmail: {
27
+ type: 'string',
28
+ },
29
+ inviteeService: {
30
+ type: 'array',
31
+ items: {
32
+ type: 'object',
33
+ properties: {
34
+ id: {
35
+ type: 'string',
36
+ },
37
+ type: {
38
+ type: 'string',
39
+ enum: [
40
+ ...values(
41
+ ServiceTypesOfServiceCategory[
42
+ ServiceCategories.IdDocumentIssuer
43
+ ]
44
+ ),
45
+ ...values(
46
+ ServiceTypesOfServiceCategory[
47
+ ServiceCategories.NotaryIdDocumentIssuer
48
+ ]
49
+ ),
50
+ ...values(
51
+ ServiceTypesOfServiceCategory[ServiceCategories.ContactIssuer]
52
+ ),
53
+ ...values(
54
+ ServiceTypesOfServiceCategory[
55
+ ServiceCategories.NotaryContactIssuer
56
+ ]
57
+ ),
58
+ ...values(
59
+ ServiceTypesOfServiceCategory[ServiceCategories.Inspector]
60
+ ),
61
+ ...values(
62
+ ServiceTypesOfServiceCategory[ServiceCategories.Issuer]
63
+ ),
64
+ ...values(
65
+ ServiceTypesOfServiceCategory[ServiceCategories.NotaryIssuer]
66
+ ),
67
+ ...values(
68
+ ServiceTypesOfServiceCategory[ServiceCategories.IdentityIssuer]
69
+ ),
70
+ ...values(
71
+ ServiceTypesOfServiceCategory[
72
+ ServiceCategories.HolderAppProvider
73
+ ]
74
+ ),
75
+ ],
76
+ minLength: 1,
77
+ },
78
+ serviceEndpoint: {
79
+ type: 'string',
80
+ },
81
+ credentialTypes: {
82
+ type: 'array',
83
+ items: {
84
+ type: 'string',
85
+ },
86
+ },
87
+ },
88
+ required: ['id', 'type', 'serviceEndpoint'],
89
+ },
90
+ },
91
+ inviteeProfile: {
92
+ type: 'object',
93
+ properties: {
94
+ ...omit(
95
+ keyIndividualProperties,
96
+ organizationProfileBaseSchema.properties
97
+ ),
98
+ type: omit(['default'], organizationProfileBaseSchema.properties.type),
99
+ },
100
+ required: ['name'],
101
+ },
102
+ inviteeDid: {
103
+ type: 'string',
104
+ },
105
+ keyIndividuals: {
106
+ type: 'object',
107
+ properties: pick(
108
+ keyIndividualProperties,
109
+ organizationProfileBaseSchema.properties
110
+ ),
111
+ required: ['adminGivenName', 'adminFamilyName', 'adminEmail'],
112
+ },
113
+ },
114
+ required: [
115
+ 'inviteeEmail',
116
+ 'inviteeService',
117
+ 'inviteeProfile',
118
+ 'keyIndividuals',
119
+ ],
120
+ };
121
+
122
+ module.exports = { addInvitationBodySchema };