@3sixty/api-tenant-processor 0.0.0-stage → 0.20.0-next.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.
Files changed (131) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +24 -2
  3. package/dist/es/entities/tenant.js +77 -0
  4. package/dist/es/entities/tenant.js.map +1 -0
  5. package/dist/es/entities/tenantV0.js +61 -0
  6. package/dist/es/entities/tenantV0.js.map +1 -0
  7. package/dist/es/entities/tenantV1.js +77 -0
  8. package/dist/es/entities/tenantV1.js.map +1 -0
  9. package/dist/es/index.js +29 -0
  10. package/dist/es/index.js.map +1 -0
  11. package/dist/es/models/ISingleTenantProcessorConfig.js +4 -0
  12. package/dist/es/models/ISingleTenantProcessorConfig.js.map +1 -0
  13. package/dist/es/models/ISingleTenantProcessorConstructorOptions.js +2 -0
  14. package/dist/es/models/ISingleTenantProcessorConstructorOptions.js.map +1 -0
  15. package/dist/es/models/ITenantAdminServiceConfig.js +4 -0
  16. package/dist/es/models/ITenantAdminServiceConfig.js.map +1 -0
  17. package/dist/es/models/ITenantAdminServiceConstructorOptions.js +2 -0
  18. package/dist/es/models/ITenantAdminServiceConstructorOptions.js.map +1 -0
  19. package/dist/es/models/ITenantOverrideProcessorConfig.js +4 -0
  20. package/dist/es/models/ITenantOverrideProcessorConfig.js.map +1 -0
  21. package/dist/es/models/ITenantOverrideProcessorConstructorOptions.js +2 -0
  22. package/dist/es/models/ITenantOverrideProcessorConstructorOptions.js.map +1 -0
  23. package/dist/es/models/ITenantProcessorConfig.js +4 -0
  24. package/dist/es/models/ITenantProcessorConfig.js.map +1 -0
  25. package/dist/es/models/ITenantProcessorConstructorOptions.js +2 -0
  26. package/dist/es/models/ITenantProcessorConstructorOptions.js.map +1 -0
  27. package/dist/es/models/api/ITenantCreateRequest.js +2 -0
  28. package/dist/es/models/api/ITenantCreateRequest.js.map +1 -0
  29. package/dist/es/models/api/ITenantGetByApiKeyRequest.js +4 -0
  30. package/dist/es/models/api/ITenantGetByApiKeyRequest.js.map +1 -0
  31. package/dist/es/models/api/ITenantGetByIdRequest.js +4 -0
  32. package/dist/es/models/api/ITenantGetByIdRequest.js.map +1 -0
  33. package/dist/es/models/api/ITenantGetByPublicOriginRequest.js +4 -0
  34. package/dist/es/models/api/ITenantGetByPublicOriginRequest.js.map +1 -0
  35. package/dist/es/models/api/ITenantGetResponse.js +2 -0
  36. package/dist/es/models/api/ITenantGetResponse.js.map +1 -0
  37. package/dist/es/models/api/ITenantListRequest.js +4 -0
  38. package/dist/es/models/api/ITenantListRequest.js.map +1 -0
  39. package/dist/es/models/api/ITenantListResponse.js +2 -0
  40. package/dist/es/models/api/ITenantListResponse.js.map +1 -0
  41. package/dist/es/models/api/ITenantRemoveRequest.js +4 -0
  42. package/dist/es/models/api/ITenantRemoveRequest.js.map +1 -0
  43. package/dist/es/models/api/ITenantUpdateRequest.js +2 -0
  44. package/dist/es/models/api/ITenantUpdateRequest.js.map +1 -0
  45. package/dist/es/restEntryPoints.js +13 -0
  46. package/dist/es/restEntryPoints.js.map +1 -0
  47. package/dist/es/schema.js +64 -0
  48. package/dist/es/schema.js.map +1 -0
  49. package/dist/es/singleTenantProcessor.js +81 -0
  50. package/dist/es/singleTenantProcessor.js.map +1 -0
  51. package/dist/es/tenantAdminService.js +500 -0
  52. package/dist/es/tenantAdminService.js.map +1 -0
  53. package/dist/es/tenantIdContextIdHandler.js +47 -0
  54. package/dist/es/tenantIdContextIdHandler.js.map +1 -0
  55. package/dist/es/tenantOverrideProcessor.js +119 -0
  56. package/dist/es/tenantOverrideProcessor.js.map +1 -0
  57. package/dist/es/tenantProcessor.js +164 -0
  58. package/dist/es/tenantProcessor.js.map +1 -0
  59. package/dist/es/tenantRoutes.js +404 -0
  60. package/dist/es/tenantRoutes.js.map +1 -0
  61. package/dist/es/utils/tenantIdHelper.js +23 -0
  62. package/dist/es/utils/tenantIdHelper.js.map +1 -0
  63. package/dist/types/entities/tenant.d.ts +37 -0
  64. package/dist/types/entities/tenantV0.d.ts +29 -0
  65. package/dist/types/entities/tenantV1.d.ts +37 -0
  66. package/dist/types/index.d.ts +26 -0
  67. package/dist/types/models/ISingleTenantProcessorConfig.d.ts +9 -0
  68. package/dist/types/models/ISingleTenantProcessorConstructorOptions.d.ts +10 -0
  69. package/dist/types/models/ITenantAdminServiceConfig.d.ts +24 -0
  70. package/dist/types/models/ITenantAdminServiceConstructorOptions.d.ts +15 -0
  71. package/dist/types/models/ITenantOverrideProcessorConfig.d.ts +13 -0
  72. package/dist/types/models/ITenantOverrideProcessorConstructorOptions.d.ts +15 -0
  73. package/dist/types/models/ITenantProcessorConfig.d.ts +18 -0
  74. package/dist/types/models/ITenantProcessorConstructorOptions.d.ts +15 -0
  75. package/dist/types/models/api/ITenantCreateRequest.d.ts +12 -0
  76. package/dist/types/models/api/ITenantGetByApiKeyRequest.d.ts +14 -0
  77. package/dist/types/models/api/ITenantGetByIdRequest.d.ts +14 -0
  78. package/dist/types/models/api/ITenantGetByPublicOriginRequest.d.ts +14 -0
  79. package/dist/types/models/api/ITenantGetResponse.d.ts +10 -0
  80. package/dist/types/models/api/ITenantListRequest.d.ts +27 -0
  81. package/dist/types/models/api/ITenantListResponse.d.ts +17 -0
  82. package/dist/types/models/api/ITenantRemoveRequest.d.ts +14 -0
  83. package/dist/types/models/api/ITenantUpdateRequest.d.ts +19 -0
  84. package/dist/types/restEntryPoints.d.ts +5 -0
  85. package/dist/types/schema.d.ts +5 -0
  86. package/dist/types/singleTenantProcessor.d.ts +41 -0
  87. package/dist/types/tenantAdminService.d.ts +109 -0
  88. package/dist/types/tenantIdContextIdHandler.d.ts +33 -0
  89. package/dist/types/tenantOverrideProcessor.d.ts +44 -0
  90. package/dist/types/tenantProcessor.d.ts +34 -0
  91. package/dist/types/tenantRoutes.d.ts +78 -0
  92. package/dist/types/utils/tenantIdHelper.d.ts +15 -0
  93. package/docs/changelog.md +0 -0
  94. package/docs/examples.md +81 -0
  95. package/docs/reference/classes/SingleTenantProcessor.md +128 -0
  96. package/docs/reference/classes/Tenant.md +77 -0
  97. package/docs/reference/classes/TenantAdminService.md +393 -0
  98. package/docs/reference/classes/TenantIdContextIdHandler.md +123 -0
  99. package/docs/reference/classes/TenantIdHelper.md +41 -0
  100. package/docs/reference/classes/TenantOverrideProcessor.md +119 -0
  101. package/docs/reference/classes/TenantProcessor.md +101 -0
  102. package/docs/reference/functions/generateRestRoutesTenants.md +25 -0
  103. package/docs/reference/functions/initSchema.md +10 -0
  104. package/docs/reference/functions/tenantByApiKey.md +31 -0
  105. package/docs/reference/functions/tenantById.md +31 -0
  106. package/docs/reference/functions/tenantByPublicOrigin.md +31 -0
  107. package/docs/reference/functions/tenantCreate.md +37 -0
  108. package/docs/reference/functions/tenantList.md +31 -0
  109. package/docs/reference/functions/tenantRemove.md +31 -0
  110. package/docs/reference/functions/tenantUpdate.md +31 -0
  111. package/docs/reference/index.md +47 -0
  112. package/docs/reference/interfaces/ISingleTenantProcessorConfig.md +11 -0
  113. package/docs/reference/interfaces/ISingleTenantProcessorConstructorOptions.md +11 -0
  114. package/docs/reference/interfaces/ITenantAdminServiceConfig.md +49 -0
  115. package/docs/reference/interfaces/ITenantAdminServiceConstructorOptions.md +25 -0
  116. package/docs/reference/interfaces/ITenantCreateRequest.md +17 -0
  117. package/docs/reference/interfaces/ITenantGetByApiKeyRequest.md +17 -0
  118. package/docs/reference/interfaces/ITenantGetByIdRequest.md +17 -0
  119. package/docs/reference/interfaces/ITenantGetByPublicOriginRequest.md +17 -0
  120. package/docs/reference/interfaces/ITenantGetResponse.md +11 -0
  121. package/docs/reference/interfaces/ITenantListRequest.md +36 -0
  122. package/docs/reference/interfaces/ITenantListResponse.md +23 -0
  123. package/docs/reference/interfaces/ITenantOverrideProcessorConfig.md +19 -0
  124. package/docs/reference/interfaces/ITenantOverrideProcessorConstructorOptions.md +25 -0
  125. package/docs/reference/interfaces/ITenantProcessorConfig.md +33 -0
  126. package/docs/reference/interfaces/ITenantProcessorConstructorOptions.md +25 -0
  127. package/docs/reference/interfaces/ITenantRemoveRequest.md +17 -0
  128. package/docs/reference/interfaces/ITenantUpdateRequest.md +25 -0
  129. package/docs/reference/variables/tagsTenants.md +5 -0
  130. package/locales/en.json +24 -0
  131. package/package.json +57 -5
@@ -0,0 +1,11 @@
1
+ # Interface: ISingleTenantProcessorConstructorOptions
2
+
3
+ Options for the Single Tenant Processor constructor.
4
+
5
+ ## Properties
6
+
7
+ ### config? {#config}
8
+
9
+ > `optional` **config?**: [`ISingleTenantProcessorConfig`](ISingleTenantProcessorConfig.md)
10
+
11
+ Configuration for the processor.
@@ -0,0 +1,49 @@
1
+ # Interface: ITenantAdminServiceConfig
2
+
3
+ Configuration for the tenant admin service.
4
+
5
+ ## Properties
6
+
7
+ ### tenantCacheTtlMs? {#tenantcachettlms}
8
+
9
+ > `optional` **tenantCacheTtlMs?**: `number`
10
+
11
+ The time in milliseconds a tenant is kept in the in-memory lookup cache, counted from when it
12
+ was read and not extended by use, set to 0 to disable caching. Entries are invalidated when a
13
+ tenant is created, updated or removed through this service, but only in the process that made
14
+ the change, so this is also the longest another node can serve a tenant that has been edited
15
+ elsewhere.
16
+
17
+ #### Default
18
+
19
+ ```ts
20
+ 30000
21
+ ```
22
+
23
+ ***
24
+
25
+ ### tenantCacheCapacity? {#tenantcachecapacity}
26
+
27
+ > `optional` **tenantCacheCapacity?**: `number`
28
+
29
+ The maximum number of tenant lookups to hold in the in-memory cache.
30
+
31
+ #### Default
32
+
33
+ ```ts
34
+ undefined (LfuCache default)
35
+ ```
36
+
37
+ ***
38
+
39
+ ### tenantCacheMutexTimeoutMs? {#tenantcachemutextimeoutms}
40
+
41
+ > `optional` **tenantCacheMutexTimeoutMs?**: `number`
42
+
43
+ Maximum time in milliseconds to wait for the tenant cache mutex during a cache population.
44
+
45
+ #### Default
46
+
47
+ ```ts
48
+ undefined (LfuCache default)
49
+ ```
@@ -0,0 +1,25 @@
1
+ # Interface: ITenantAdminServiceConstructorOptions
2
+
3
+ Options for the Tenant Admin Service constructor.
4
+
5
+ ## Properties
6
+
7
+ ### tenantEntityStorageType? {#tenantentitystoragetype}
8
+
9
+ > `optional` **tenantEntityStorageType?**: `string`
10
+
11
+ The entity storage for the tenants.
12
+
13
+ #### Default
14
+
15
+ ```ts
16
+ tenant
17
+ ```
18
+
19
+ ***
20
+
21
+ ### config? {#config}
22
+
23
+ > `optional` **config?**: [`ITenantAdminServiceConfig`](ITenantAdminServiceConfig.md)
24
+
25
+ Configuration for the service.
@@ -0,0 +1,17 @@
1
+ # Interface: ITenantCreateRequest
2
+
3
+ The tenant to create.
4
+
5
+ ## Properties
6
+
7
+ ### body {#body}
8
+
9
+ > **body**: `Omit`\<`ITenant`, `"id"` \| `"dateCreated"` \| `"dateModified"`\> & `object`
10
+
11
+ The tenant to create.
12
+
13
+ #### Type Declaration
14
+
15
+ ##### id?
16
+
17
+ > `optional` **id?**: `string`
@@ -0,0 +1,17 @@
1
+ # Interface: ITenantGetByApiKeyRequest
2
+
3
+ The tenant to get by API key.
4
+
5
+ ## Properties
6
+
7
+ ### pathParams {#pathparams}
8
+
9
+ > **pathParams**: `object`
10
+
11
+ The path parameters.
12
+
13
+ #### apiKey
14
+
15
+ > **apiKey**: `string`
16
+
17
+ The API key of the tenant to get.
@@ -0,0 +1,17 @@
1
+ # Interface: ITenantGetByIdRequest
2
+
3
+ The tenant to get by id.
4
+
5
+ ## Properties
6
+
7
+ ### pathParams {#pathparams}
8
+
9
+ > **pathParams**: `object`
10
+
11
+ The path parameters.
12
+
13
+ #### id
14
+
15
+ > **id**: `string`
16
+
17
+ The id of the tenant to get.
@@ -0,0 +1,17 @@
1
+ # Interface: ITenantGetByPublicOriginRequest
2
+
3
+ The tenant to get by public origin.
4
+
5
+ ## Properties
6
+
7
+ ### pathParams {#pathparams}
8
+
9
+ > **pathParams**: `object`
10
+
11
+ The path parameters.
12
+
13
+ #### publicOrigin
14
+
15
+ > **publicOrigin**: `string`
16
+
17
+ The public origin of the tenant to get.
@@ -0,0 +1,11 @@
1
+ # Interface: ITenantGetResponse
2
+
3
+ The tenant get response.
4
+
5
+ ## Properties
6
+
7
+ ### body {#body}
8
+
9
+ > **body**: `ITenant`
10
+
11
+ The tenant.
@@ -0,0 +1,36 @@
1
+ # Interface: ITenantListRequest
2
+
3
+ The list of tenants.
4
+
5
+ ## Properties
6
+
7
+ ### query {#query}
8
+
9
+ > **query**: `object`
10
+
11
+ The query parameters.
12
+
13
+ #### conditions?
14
+
15
+ > `optional` **conditions?**: `string`
16
+
17
+ The condition for the query as JSON version of EntityCondition type.
18
+
19
+ #### properties?
20
+
21
+ > `optional` **properties?**: `string`
22
+
23
+ The properties to include in the returned tenants, separated by commas.
24
+ If not provided, all properties will be returned.
25
+
26
+ #### cursor?
27
+
28
+ > `optional` **cursor?**: `string`
29
+
30
+ The cursor to get the next chunk of tenants.
31
+
32
+ #### limit?
33
+
34
+ > `optional` **limit?**: `string`
35
+
36
+ The number of tenants to return.
@@ -0,0 +1,23 @@
1
+ # Interface: ITenantListResponse
2
+
3
+ The list of tenants.
4
+
5
+ ## Properties
6
+
7
+ ### headers? {#headers}
8
+
9
+ > `optional` **headers?**: `object`
10
+
11
+ The headers which can be used to include the cursor.
12
+
13
+ #### link?
14
+
15
+ > `optional` **link?**: `string` \| `string`[]
16
+
17
+ ***
18
+
19
+ ### body {#body}
20
+
21
+ > **body**: `ITenant`[]
22
+
23
+ The list of tenants.
@@ -0,0 +1,19 @@
1
+ # Interface: ITenantOverrideProcessorConfig
2
+
3
+ Configuration for the TenantOverrideProcessor.
4
+
5
+ ## Properties
6
+
7
+ ### includeErrorStack? {#includeerrorstack}
8
+
9
+ > `optional` **includeErrorStack?**: `boolean`
10
+
11
+ Include the stack with errors.
12
+
13
+ ***
14
+
15
+ ### escalatedPrivilegeScope? {#escalatedprivilegescope}
16
+
17
+ > `optional` **escalatedPrivilegeScope?**: `string`
18
+
19
+ The scope value that grants escalated privilege for cross-tenant access. Defaults to "global-admin".
@@ -0,0 +1,25 @@
1
+ # Interface: ITenantOverrideProcessorConstructorOptions
2
+
3
+ Options for the TenantOverrideProcessor constructor.
4
+
5
+ ## Properties
6
+
7
+ ### tenantAdminComponentType? {#tenantadmincomponenttype}
8
+
9
+ > `optional` **tenantAdminComponentType?**: `string`
10
+
11
+ The component used to resolve tenants, which also provides the lookup caching.
12
+
13
+ #### Default
14
+
15
+ ```ts
16
+ tenant-admin
17
+ ```
18
+
19
+ ***
20
+
21
+ ### config? {#config}
22
+
23
+ > `optional` **config?**: [`ITenantOverrideProcessorConfig`](ITenantOverrideProcessorConfig.md)
24
+
25
+ Configuration for the processor.
@@ -0,0 +1,33 @@
1
+ # Interface: ITenantProcessorConfig
2
+
3
+ Configuration for the tenant processor
4
+
5
+ ## Properties
6
+
7
+ ### apiKeyName? {#apikeyname}
8
+
9
+ > `optional` **apiKeyName?**: `string`
10
+
11
+ The key to look for in the header or query params for the api key.
12
+
13
+ #### Default
14
+
15
+ ```ts
16
+ x-api-key
17
+ ```
18
+
19
+ ***
20
+
21
+ ### apiKeyEndpoints? {#apikeyendpoints}
22
+
23
+ > `optional` **apiKeyEndpoints?**: `string`[]
24
+
25
+ The list of endpoint paths that should be checked for an api key header, can be regexp strings. Defaults to ["/login$"].
26
+
27
+ ***
28
+
29
+ ### includeErrorStack? {#includeerrorstack}
30
+
31
+ > `optional` **includeErrorStack?**: `boolean`
32
+
33
+ Include the stack with errors.
@@ -0,0 +1,25 @@
1
+ # Interface: ITenantProcessorConstructorOptions
2
+
3
+ Options for the Tenant Processor constructor.
4
+
5
+ ## Properties
6
+
7
+ ### tenantAdminComponentType? {#tenantadmincomponenttype}
8
+
9
+ > `optional` **tenantAdminComponentType?**: `string`
10
+
11
+ The component used to resolve tenants, which also provides the lookup caching.
12
+
13
+ #### Default
14
+
15
+ ```ts
16
+ tenant-admin
17
+ ```
18
+
19
+ ***
20
+
21
+ ### config? {#config}
22
+
23
+ > `optional` **config?**: [`ITenantProcessorConfig`](ITenantProcessorConfig.md)
24
+
25
+ Configuration for the processor.
@@ -0,0 +1,17 @@
1
+ # Interface: ITenantRemoveRequest
2
+
3
+ The tenant to remove by id.
4
+
5
+ ## Properties
6
+
7
+ ### pathParams {#pathparams}
8
+
9
+ > **pathParams**: `object`
10
+
11
+ The path parameters.
12
+
13
+ #### id
14
+
15
+ > **id**: `string`
16
+
17
+ The id of the tenant to remove.
@@ -0,0 +1,25 @@
1
+ # Interface: ITenantUpdateRequest
2
+
3
+ The tenant to update.
4
+
5
+ ## Properties
6
+
7
+ ### pathParams {#pathparams}
8
+
9
+ > **pathParams**: `object`
10
+
11
+ The path parameters.
12
+
13
+ #### id
14
+
15
+ > **id**: `string`
16
+
17
+ The id of the tenant to update.
18
+
19
+ ***
20
+
21
+ ### body {#body}
22
+
23
+ > **body**: `Omit`\<`ITenant`, `"id"` \| `"dateCreated"` \| `"dateModified"`\>
24
+
25
+ The tenant to update.
@@ -0,0 +1,5 @@
1
+ # Variable: tagsTenants
2
+
3
+ > `const` **tagsTenants**: `ITag`[]
4
+
5
+ The tag to associate with the routes.
@@ -0,0 +1,24 @@
1
+ {
2
+ "error": {
3
+ "tenantProcessor": {
4
+ "missingApiKey": "API key \"{keyName}\" is missing",
5
+ "missingOrganizationId": "Organization ID query parameter \"{paramName}\" is missing",
6
+ "apiKeyNotFound": "No tenant found for API key \"{key}\".",
7
+ "organizationIdNotFound": "No tenant found for organization ID \"{organizationId}\"."
8
+ },
9
+ "tenantOverrideProcessor": {
10
+ "insufficientScopeForTenantOverride": "Caller does not hold the required scope for tenant override.",
11
+ "tenantNotFound": "Tenant \"{notFoundId}\" not found."
12
+ },
13
+ "singleTenantProcessor": {
14
+ "invalidOrganizationId": "Organization ID query parameter \"{paramName}\" value \"{value}\" is not valid for this node"
15
+ },
16
+ "tenantAdminService": {
17
+ "apiKeyAlreadyInUse": "The provided API key is already in use by another tenant.",
18
+ "tenantAlreadyExists": "Tenant with ID \"{existingId}\" already exists.",
19
+ "tenantNotFound": "Tenant with ID \"{notFoundId}\" not found.",
20
+ "organizationIdAlreadyExists": "A tenant with organization ID \"{existingId}\" already exists.",
21
+ "publicOriginAlreadyExists": "A tenant with public origin \"{existingId}\" already exists."
22
+ }
23
+ }
24
+ }
package/package.json CHANGED
@@ -1,6 +1,58 @@
1
1
  {
2
- "name": "@3sixty/api-tenant-processor",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
2
+ "name": "@3sixty/api-tenant-processor",
3
+ "version": "0.20.0-next.0",
4
+ "description": "Tenant resolution services and route handlers that derive tenant context from API keys.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/3sixtyglobal/api.git",
8
+ "directory": "packages/api-tenant-processor"
9
+ },
10
+ "author": "martyn.janes@iota.org",
11
+ "license": "Apache-2.0",
12
+ "type": "module",
13
+ "engines": {
14
+ "node": ">=24.0.0"
15
+ },
16
+ "dependencies": {
17
+ "@3sixty/api-models": "0.20.0-next.0",
18
+ "@3sixty/context": "next",
19
+ "@3sixty/core": "next",
20
+ "@3sixty/crypto": "next",
21
+ "@3sixty/entity": "next",
22
+ "@3sixty/entity-storage-models": "next",
23
+ "@3sixty/nameof": "next",
24
+ "@3sixty/vault-models": "next",
25
+ "@3sixty/web": "next"
26
+ },
27
+ "main": "./dist/es/index.js",
28
+ "types": "./dist/types/index.d.ts",
29
+ "exports": {
30
+ ".": {
31
+ "types": "./dist/types/index.d.ts",
32
+ "import": "./dist/es/index.js",
33
+ "default": "./dist/es/index.js"
34
+ },
35
+ "./locales/*.json": "./locales/*.json"
36
+ },
37
+ "files": [
38
+ "dist/es",
39
+ "dist/types",
40
+ "locales",
41
+ "docs"
42
+ ],
43
+ "keywords": [
44
+ "twin",
45
+ "trade",
46
+ "iota",
47
+ "framework",
48
+ "blockchain",
49
+ "node",
50
+ "tenant",
51
+ "foundation",
52
+ "utilities"
53
+ ],
54
+ "bugs": {
55
+ "url": "git+https://github.com/3sixtyglobal/api/issues"
56
+ },
57
+ "homepage": "https://3sixty.global"
58
+ }