From 2828808f6a6a7221ff593cded6862cf7b0412550 Mon Sep 17 00:00:00 2001 From: Martyn Janes Date: Wed, 19 Aug 2026 12:58:46 +0800 Subject: [PATCH 01/17] feat: add authorization --- cspell.json | 2 + .../src/builders/engineEnvBuilder.ts | 49 +++++ .../src/builders/engineServerEnvBuilder.ts | 6 +- .../src/models/IEngineEnvironmentVariables.ts | 30 +++ .../models/engineEnvironmentVariableKeys.ts | 7 + packages/node-core/tests/endpoints.spec.ts | 1 + .../tests/endpoints/groups/authorization.json | 198 ++++++++++++++++++ packages/node-core/tests/endpoints/index.json | 1 + packages/node-core/tests/index.spec.ts | 29 ++- 9 files changed, 313 insertions(+), 10 deletions(-) create mode 100644 packages/node-core/tests/endpoints/groups/authorization.json diff --git a/cspell.json b/cspell.json index 7ad72742..6bd4e17d 100644 --- a/cspell.json +++ b/cspell.json @@ -63,6 +63,8 @@ "rawurl", "readyz", "reqs", + "casbin", + "Casbin", "sawtooth", "scylladb", "Stiftung", diff --git a/packages/node-core/src/builders/engineEnvBuilder.ts b/packages/node-core/src/builders/engineEnvBuilder.ts index 4fa49c1f..c25f4b13 100644 --- a/packages/node-core/src/builders/engineEnvBuilder.ts +++ b/packages/node-core/src/builders/engineEnvBuilder.ts @@ -153,6 +153,7 @@ export async function buildEngineConfiguration( await configureTelemetry(coreConfig, envVars); await configureMetricsCollector(coreConfig, envVars); await configureTracing(coreConfig, envVars); + await configureAuthorization(coreConfig, envVars); await configureMessaging(coreConfig, envVars); await configureAutomation(coreConfig, envVars); await configureHealth(coreConfig, envVars); @@ -821,6 +822,41 @@ async function configureTracing( } } +/** + * Configures the authorization. + * @param coreConfig The core config. + * @param envVars The environment variables. + * @returns A promise that resolves when the authorization configuration has been applied. + */ +async function configureAuthorization( + coreConfig: IEngineConfig, + envVars: IEngineEnvironmentVariables +): Promise { + coreConfig.types.authorizationConnector ??= []; + + if (envVars.authorizationConnector === "entity-storage") { + coreConfig.types.authorizationConnector.push({ type: "entity-storage" }); + } else if (envVars.authorizationConnector === "casbin") { + coreConfig.types.authorizationConnector.push({ + type: "casbin", + options: { + config: { + endpoint: envVars.casbinEndpoint ?? "", + clientId: envVars.casbinClientId ?? "", + clientSecret: envVars.casbinClientSecret ?? "", + enforcerId: envVars.casbinEnforcerId ?? "", + timeoutMs: envMs(envVars, "casbinTimeoutMs") + } + } + }); + } + + if (coreConfig.types.authorizationConnector.length > 0) { + coreConfig.types.authorizationComponent ??= []; + coreConfig.types.authorizationComponent.push({ type: "service" }); + } +} + /** * Configures the automation. * @param coreConfig The core config. @@ -2005,3 +2041,16 @@ export function isTracingRequired(envVars: IEngineEnvironmentVariables): boolean envVars.tracingConnector === TracingConnectorType.OpenTelemetry ); } + +/** + * Checks if the authorization subsystem is required. + * Returns true when any authorization connector is configured. + * @param envVars The environment variables. + * @returns True if authorization is enabled. + */ +export function isAuthorizationRequired(envVars: IEngineEnvironmentVariables): boolean { + return ( + envVars.authorizationConnector === "entity-storage" || + envVars.authorizationConnector === "casbin" + ); +} diff --git a/packages/node-core/src/builders/engineServerEnvBuilder.ts b/packages/node-core/src/builders/engineServerEnvBuilder.ts index fe8074fb..2e16beaa 100644 --- a/packages/node-core/src/builders/engineServerEnvBuilder.ts +++ b/packages/node-core/src/builders/engineServerEnvBuilder.ts @@ -18,7 +18,11 @@ import { } from "@twin.org/engine-server-types"; import { TraceparentHelper } from "@twin.org/tracing-models"; import { CONTEXT_ID_HANDLER_FEATURE_DID, CONTEXT_ID_HANDLER_FEATURE_TENANT } from "../defaults.js"; -import { isTelemetryRequired, isTracingRequired } from "./engineEnvBuilder.js"; +import { + isAuthorizationRequired, + isTelemetryRequired, + isTracingRequired +} from "./engineEnvBuilder.js"; import type { IEnvironmentVariables } from "../models/IEnvironmentVariables.js"; import { commaSeparatedListToArray } from "./helper/envHelpers.js"; diff --git a/packages/node-core/src/models/IEngineEnvironmentVariables.ts b/packages/node-core/src/models/IEngineEnvironmentVariables.ts index fdfaaa80..c02147f1 100644 --- a/packages/node-core/src/models/IEngineEnvironmentVariables.ts +++ b/packages/node-core/src/models/IEngineEnvironmentVariables.ts @@ -668,6 +668,36 @@ export interface IEngineEnvironmentVariables { */ tracingMutexTimeout?: string; + /** + * The type of authorization connector: entity-storage, casbin. + */ + authorizationConnector?: string; + + /** + * The base URL of the Casbin server (e.g. "http://localhost:48000"), required when using the casbin authorization connector. + */ + casbinEndpoint?: string; + + /** + * The OAuth2 client ID for authenticating with the Casbin server, required when using the casbin authorization connector. + */ + casbinClientId?: string; + + /** + * The OAuth2 client secret for authenticating with the Casbin server, required when using the casbin authorization connector. + */ + casbinClientSecret?: string; + + /** + * The enforcer identifier in "owner/name" format (e.g. "built-in/built-in"), required when using the casbin authorization connector. + */ + casbinEnforcerId?: string; + + /** + * The request timeout in milliseconds for the Casbin authorization connector. + */ + casbinTimeoutMs?: string; + /** * The type of faucet connector: entity-storage, iota. */ diff --git a/packages/node-core/src/models/engineEnvironmentVariableKeys.ts b/packages/node-core/src/models/engineEnvironmentVariableKeys.ts index f924e07f..c979b54d 100644 --- a/packages/node-core/src/models/engineEnvironmentVariableKeys.ts +++ b/packages/node-core/src/models/engineEnvironmentVariableKeys.ts @@ -163,6 +163,13 @@ const engineEnvironmentVariableKeysInternal: { openTelemetryTracingEndpoint: true, openTelemetryTracingProcessor: true, tracingMutexTimeout: true, + // authorization + authorizationConnector: true, + casbinEndpoint: true, + casbinClientId: true, + casbinClientSecret: true, + casbinEnforcerId: true, + casbinTimeoutMs: true, // DLT / identity faucetConnector: true, walletConnector: true, diff --git a/packages/node-core/tests/endpoints.spec.ts b/packages/node-core/tests/endpoints.spec.ts index be328773..c95500d5 100644 --- a/packages/node-core/tests/endpoints.spec.ts +++ b/packages/node-core/tests/endpoints.spec.ts @@ -72,6 +72,7 @@ const SHARED_ENV_VARS: { [id: string]: string } = { TWIN_LOGGING_CONNECTOR: LoggingConnectorType.EntityStorage, TWIN_TELEMETRY_CONNECTOR: TelemetryConnectorType.EntityStorage, TWIN_TRACING_CONNECTOR: TracingConnectorType.EntityStorage, + TWIN_AUTHORIZATION_CONNECTOR: "entity-storage", TWIN_VAULT_CONNECTOR: VaultConnectorType.EntityStorage, TWIN_IDENTITY_CONNECTOR: IdentityConnectorType.EntityStorage, TWIN_IDENTITY_RESOLVER_CONNECTOR: IdentityResolverConnectorType.EntityStorage, diff --git a/packages/node-core/tests/endpoints/groups/authorization.json b/packages/node-core/tests/endpoints/groups/authorization.json new file mode 100644 index 00000000..4d158da5 --- /dev/null +++ b/packages/node-core/tests/endpoints/groups/authorization.json @@ -0,0 +1,198 @@ +{ + "group": "Authorization", + "steps": [ + { + "description": "POST /authorization/check — 400 missing subject", + "method": "POST", + "path": "/authorization/check", + "body": { "object": "/data", "action": "read" }, + "expectedStatus": 400 + }, + { + "description": "POST /authorization/policy — 400 missing object", + "method": "POST", + "path": "/authorization/policy", + "body": { "subject": "test-subject", "action": "read" }, + "expectedStatus": 400 + }, + { + "description": "POST /authorization/policy — add policy", + "method": "POST", + "path": "/authorization/policy", + "body": { "subject": "test-subject", "object": "/data", "action": "read" }, + "expectedStatus": 204 + }, + { + "description": "POST /authorization/policy — add second policy", + "method": "POST", + "path": "/authorization/policy", + "body": { "subject": "test-subject", "object": "/data", "action": "write" }, + "expectedStatus": 204 + }, + { + "description": "GET /authorization/policy — list all policies", + "method": "GET", + "path": "/authorization/policy", + "expectedStatus": 200, + "assert": { "body.entities": "isDefined" } + }, + { + "description": "GET /authorization/policy/:subject — get policies for subject", + "method": "GET", + "path": "/authorization/policy/test-subject", + "expectedStatus": 200, + "assert": { "body.policies": "isDefined" } + }, + { + "description": "POST /authorization/check — allowed after policy added", + "method": "POST", + "path": "/authorization/check", + "body": { "subject": "test-subject", "object": "/data", "action": "read" }, + "expectedStatus": 200, + "assert": { "body.allowed": true } + }, + { + "description": "POST /authorization/check — not allowed for unknown action", + "method": "POST", + "path": "/authorization/check", + "body": { "subject": "test-subject", "object": "/data", "action": "delete" }, + "expectedStatus": 200, + "assert": { "body.allowed": false } + }, + { + "description": "POST /authorization/check-any — 400 missing subjects", + "method": "POST", + "path": "/authorization/check-any", + "body": { "object": "/data", "action": "read" }, + "expectedStatus": 400 + }, + { + "description": "POST /authorization/check-any — allowed for one of the subjects", + "method": "POST", + "path": "/authorization/check-any", + "body": { + "subjects": ["test-subject", "other-subject"], + "object": "/data", + "action": "read" + }, + "expectedStatus": 200, + "assert": { "body.allowed": true } + }, + { + "description": "POST /authorization/policy/remove — remove one policy", + "method": "POST", + "path": "/authorization/policy/remove", + "body": { "subject": "test-subject", "object": "/data", "action": "write" }, + "expectedStatus": 204 + }, + { + "description": "GET /authorization/roles — list all roles (empty initially)", + "method": "GET", + "path": "/authorization/roles", + "expectedStatus": 200, + "assert": { "body.roles": "isDefined" } + }, + { + "description": "POST /authorization/subject/:subject/role — 400 missing role", + "method": "POST", + "path": "/authorization/subject/test-subject/role", + "body": {}, + "expectedStatus": 400 + }, + { + "description": "POST /authorization/subject/:subject/role — add editor role", + "method": "POST", + "path": "/authorization/subject/test-subject/role", + "body": { "role": "editor" }, + "expectedStatus": 204 + }, + { + "description": "POST /authorization/subject/:subject/role — add viewer role", + "method": "POST", + "path": "/authorization/subject/test-subject/role", + "body": { "role": "viewer" }, + "expectedStatus": 204 + }, + { + "description": "GET /authorization/subject/:subject/roles — get roles for subject", + "method": "GET", + "path": "/authorization/subject/test-subject/roles", + "expectedStatus": 200, + "assert": { "body.roles": "isDefined" } + }, + { + "description": "GET /authorization/subject/:subject/role/:role — has editor role", + "method": "GET", + "path": "/authorization/subject/test-subject/role/editor", + "expectedStatus": 200, + "assert": { "body.hasRole": true } + }, + { + "description": "GET /authorization/subject/:subject/role/:role — does not have admin role", + "method": "GET", + "path": "/authorization/subject/test-subject/role/admin", + "expectedStatus": 200, + "assert": { "body.hasRole": false } + }, + { + "description": "GET /authorization/role/:role/subjects — get subjects for editor role", + "method": "GET", + "path": "/authorization/role/editor/subjects", + "expectedStatus": 200, + "assert": { "body.subjects": "isDefined" } + }, + { + "description": "DELETE /authorization/subject/:subject/role/:role — remove viewer role", + "method": "DELETE", + "path": "/authorization/subject/test-subject/role/viewer", + "expectedStatus": 204 + }, + { + "description": "GET /authorization/subject/:subject/role/:role — no longer has viewer role", + "method": "GET", + "path": "/authorization/subject/test-subject/role/viewer", + "expectedStatus": 200, + "assert": { "body.hasRole": false } + }, + { + "description": "POST /authorization/role/:role/inherit — add inheritance editor inherits viewer", + "method": "POST", + "path": "/authorization/role/editor/inherit", + "body": { "parentRole": "viewer" }, + "expectedStatus": 204 + }, + { + "description": "GET /authorization/role/:role/parents — get parent roles for editor", + "method": "GET", + "path": "/authorization/role/editor/parents", + "expectedStatus": 200, + "assert": { "body.roles": "isDefined" } + }, + { + "description": "GET /authorization/role/:role/children — get child roles for viewer", + "method": "GET", + "path": "/authorization/role/viewer/children", + "expectedStatus": 200, + "assert": { "body.roles": "isDefined" } + }, + { + "description": "DELETE /authorization/role/:role/inherit/:parentRole — remove inheritance", + "method": "DELETE", + "path": "/authorization/role/editor/inherit/viewer", + "expectedStatus": 204 + }, + { + "description": "DELETE /authorization/subject/:subject/roles — remove all roles for subject", + "method": "DELETE", + "path": "/authorization/subject/test-subject/roles", + "expectedStatus": 204 + }, + { + "description": "GET /authorization/subject/:subject/roles — empty after remove all", + "method": "GET", + "path": "/authorization/subject/test-subject/roles", + "expectedStatus": 200, + "assert": { "body.roles": "isDefined" } + } + ] +} diff --git a/packages/node-core/tests/endpoints/index.json b/packages/node-core/tests/endpoints/index.json index e3c26c3b..35c298d5 100644 --- a/packages/node-core/tests/endpoints/index.json +++ b/packages/node-core/tests/endpoints/index.json @@ -4,6 +4,7 @@ "logging", "telemetry", "tracing", + "authorization", "blob", "identity", "nft", diff --git a/packages/node-core/tests/index.spec.ts b/packages/node-core/tests/index.spec.ts index 6f5cb168..bc890ba6 100644 --- a/packages/node-core/tests/index.spec.ts +++ b/packages/node-core/tests/index.spec.ts @@ -371,6 +371,7 @@ describe("node-core", () => { TWIN_LOGGING_CONNECTOR: LoggingConnectorType.EntityStorage, TWIN_TELEMETRY_CONNECTOR: TelemetryConnectorType.EntityStorage, TWIN_TRACING_CONNECTOR: TracingConnectorType.EntityStorage, + TWIN_AUTHORIZATION_CONNECTOR: "entity-storage", TWIN_VAULT_CONNECTOR: VaultConnectorType.EntityStorage, TWIN_IDENTITY_CONNECTOR: IdentityConnectorType.EntityStorage, TWIN_IDENTITY_RESOLVER_CONNECTOR: IdentityResolverConnectorType.EntityStorage, @@ -443,15 +444,6 @@ describe("node-core", () => { expect(startResult).toBeDefined(); - // Wait a second for the server to start - await new Promise(resolve => setTimeout(resolve, 1500)); - - const res = await fetch(`http://localhost:${port}/info`); - expect(await res.json()).toEqual({ - name: "foo", - version: "0.0.0" - }); - expect(ComponentFactory.names()).toEqual([ "engine-logging-service", "schema-version-service", @@ -463,6 +455,7 @@ describe("node-core", () => { "telemetry-service", "tracing-service", "metrics-collector-service", + "authorization-service", "automation-service", "messaging-admin-service", "messaging-service", @@ -541,6 +534,23 @@ describe("node-core", () => { "PUT /tracing/:spanId", "GET /tracing", "GET /tracing/trace/:traceId", + "POST /authorization/check", + "POST /authorization/check-any", + "POST /authorization/policy", + "POST /authorization/policy/remove", + "GET /authorization/policy", + "GET /authorization/roles", + "GET /authorization/policy/:subject", + "POST /authorization/subject/:subject/role", + "DELETE /authorization/subject/:subject/role/:role", + "DELETE /authorization/subject/:subject/roles", + "GET /authorization/subject/:subject/roles", + "GET /authorization/subject/:subject/role/:role", + "GET /authorization/role/:role/subjects", + "POST /authorization/role/:role/inherit", + "DELETE /authorization/role/:role/inherit/:parentRole", + "GET /authorization/role/:role/parents", + "GET /authorization/role/:role/children", "POST /automation/trigger/:trigger", "POST /automation", "DELETE /automation/:actionId", @@ -730,6 +740,7 @@ describe("node-core", () => { TWIN_LOGGING_CONNECTOR: LoggingConnectorType.EntityStorage, TWIN_TELEMETRY_CONNECTOR: TelemetryConnectorType.EntityStorage, TWIN_TRACING_CONNECTOR: TracingConnectorType.EntityStorage, + TWIN_AUTHORIZATION_CONNECTOR: "entity-storage", TWIN_VAULT_CONNECTOR: VaultConnectorType.EntityStorage, TWIN_IDENTITY_CONNECTOR: IdentityConnectorType.EntityStorage, TWIN_IDENTITY_RESOLVER_CONNECTOR: IdentityResolverConnectorType.EntityStorage, From 50b9835bfeb4831ddacc37a4d507dbaa5e0a7b23 Mon Sep 17 00:00:00 2001 From: Martyn Janes Date: Fri, 21 Aug 2026 07:34:05 +0800 Subject: [PATCH 02/17] feat: authorization defaults --- apps/node/.env.example-aws-ec2 | 21 ++ apps/node/.env.example-federated-catalogue | 21 ++ apps/node/.env.example-iota-testnet | 21 ++ apps/node/.env.example-local-entity-storage | 21 ++ .../defaults/defaultAuthorizationRules.json | 72 +++++++ docs/architecture/node-env-variables.mdx | 9 + packages/node-core/package.json | 1 + .../src/builders/engineEnvBuilder.ts | 25 ++- .../src/builders/engineServerEnvBuilder.ts | 6 +- .../src/builders/helper/envHelpers.ts | 192 ++++++++++++++++-- .../src/models/IEngineEnvironmentVariables.ts | 15 ++ .../models/engineEnvironmentVariableKeys.ts | 3 + packages/node-core/src/start.ts | 11 +- .../tests/builders/helper/envHelpers.spec.ts | 185 ++++++++++++++++- .../tests/endpoints/groups/authorization.json | 4 +- packages/node-core/tests/index.spec.ts | 2 +- 16 files changed, 566 insertions(+), 43 deletions(-) create mode 100644 apps/node/defaults/defaultAuthorizationRules.json diff --git a/apps/node/.env.example-aws-ec2 b/apps/node/.env.example-aws-ec2 index eb859019..825d09c6 100644 --- a/apps/node/.env.example-aws-ec2 +++ b/apps/node/.env.example-aws-ec2 @@ -301,6 +301,27 @@ TWIN_TELEMETRY_CONNECTOR="entity-storage" # TWIN_OPEN_TELEMETRY_TRACING_ENDPOINT="" # TWIN_OPEN_TELEMETRY_TRACING_PROCESSOR="batch" +# Authorization Connector + +## Authorization Connector [entity-storage, casbin] +# TWIN_AUTHORIZATION_CONNECTOR="entity-storage" + +## Maximum number of cached authorisation check results. +# TWIN_AUTHORIZATION_CHECK_CACHE_CAPACITY="" + +## Time-to-idle in milliseconds for cached authorisation check results. +# TWIN_AUTHORIZATION_CHECK_CACHE_TTI_MS="" + +## Default policy rules to seed the authorisation service, as a path to a JSON file. +# TWIN_AUTHORIZATION_DEFAULT_RULES="@json:authorization-rules.json" + +# Casbin runtime settings, used when TWIN_AUTHORIZATION_CONNECTOR="casbin". +# TWIN_CASBIN_ENDPOINT="" +# TWIN_CASBIN_CLIENT_ID="" +# TWIN_CASBIN_CLIENT_SECRET="" +# TWIN_CASBIN_ENFORCER_ID="" +# TWIN_CASBIN_TIMEOUT_MS="" + # Faucet Connector ## Faucet Connector Connector [entity-storage, iota] diff --git a/apps/node/.env.example-federated-catalogue b/apps/node/.env.example-federated-catalogue index a042730a..2dde8de3 100644 --- a/apps/node/.env.example-federated-catalogue +++ b/apps/node/.env.example-federated-catalogue @@ -323,6 +323,27 @@ TWIN_TELEMETRY_CONNECTOR="entity-storage" # TWIN_OPEN_TELEMETRY_TRACING_ENDPOINT="" # TWIN_OPEN_TELEMETRY_TRACING_PROCESSOR="batch" +# Authorization Connector + +## Authorization Connector [entity-storage, casbin] +# TWIN_AUTHORIZATION_CONNECTOR="entity-storage" + +## Maximum number of cached authorisation check results. +# TWIN_AUTHORIZATION_CHECK_CACHE_CAPACITY="" + +## Time-to-idle in milliseconds for cached authorisation check results. +# TWIN_AUTHORIZATION_CHECK_CACHE_TTI_MS="" + +## Default policy rules to seed the authorisation service, as a path to a JSON file. +# TWIN_AUTHORIZATION_DEFAULT_RULES="@json:authorization-rules.json" + +# Casbin runtime settings, used when TWIN_AUTHORIZATION_CONNECTOR="casbin". +# TWIN_CASBIN_ENDPOINT="" +# TWIN_CASBIN_CLIENT_ID="" +# TWIN_CASBIN_CLIENT_SECRET="" +# TWIN_CASBIN_ENFORCER_ID="" +# TWIN_CASBIN_TIMEOUT_MS="" + # Faucet Connector # Not applicable for a standalone catalogue node. diff --git a/apps/node/.env.example-iota-testnet b/apps/node/.env.example-iota-testnet index 285af6b3..2c3eece4 100644 --- a/apps/node/.env.example-iota-testnet +++ b/apps/node/.env.example-iota-testnet @@ -303,6 +303,27 @@ TWIN_TELEMETRY_CONNECTOR="entity-storage" # TWIN_OPEN_TELEMETRY_TRACING_ENDPOINT="" # TWIN_OPEN_TELEMETRY_TRACING_PROCESSOR="batch" +# Authorization Connector + +## Authorization Connector [entity-storage, casbin] +# TWIN_AUTHORIZATION_CONNECTOR="entity-storage" + +## Maximum number of cached authorisation check results. +# TWIN_AUTHORIZATION_CHECK_CACHE_CAPACITY="" + +## Time-to-idle in milliseconds for cached authorisation check results. +# TWIN_AUTHORIZATION_CHECK_CACHE_TTI_MS="" + +## Default policy rules to seed the authorisation service, as a path to a JSON file. +# TWIN_AUTHORIZATION_DEFAULT_RULES="@json:authorization-rules.json" + +# Casbin runtime settings, used when TWIN_AUTHORIZATION_CONNECTOR="casbin". +# TWIN_CASBIN_ENDPOINT="" +# TWIN_CASBIN_CLIENT_ID="" +# TWIN_CASBIN_CLIENT_SECRET="" +# TWIN_CASBIN_ENFORCER_ID="" +# TWIN_CASBIN_TIMEOUT_MS="" + # Faucet Connector ## Faucet Connector Connector [entity-storage, iota] diff --git a/apps/node/.env.example-local-entity-storage b/apps/node/.env.example-local-entity-storage index 37827e7e..24180caf 100644 --- a/apps/node/.env.example-local-entity-storage +++ b/apps/node/.env.example-local-entity-storage @@ -301,6 +301,27 @@ TWIN_TELEMETRY_CONNECTOR="entity-storage" # TWIN_OPEN_TELEMETRY_TRACING_ENDPOINT="" # TWIN_OPEN_TELEMETRY_TRACING_PROCESSOR="batch" +# Authorization Connector + +## Authorization Connector [entity-storage, casbin] +# TWIN_AUTHORIZATION_CONNECTOR="entity-storage" + +## Maximum number of cached authorisation check results. +# TWIN_AUTHORIZATION_CHECK_CACHE_CAPACITY="" + +## Time-to-idle in milliseconds for cached authorisation check results. +# TWIN_AUTHORIZATION_CHECK_CACHE_TTI_MS="" + +## Default policy rules to seed the authorisation service, as a path to a JSON file. +# TWIN_AUTHORIZATION_DEFAULT_RULES="@json:authorization-rules.json" + +# Casbin runtime settings, used when TWIN_AUTHORIZATION_CONNECTOR="casbin". +# TWIN_CASBIN_ENDPOINT="" +# TWIN_CASBIN_CLIENT_ID="" +# TWIN_CASBIN_CLIENT_SECRET="" +# TWIN_CASBIN_ENFORCER_ID="" +# TWIN_CASBIN_TIMEOUT_MS="" + # Faucet Connector ## Faucet Connector Connector [entity-storage, iota] diff --git a/apps/node/defaults/defaultAuthorizationRules.json b/apps/node/defaults/defaultAuthorizationRules.json new file mode 100644 index 00000000..0a213100 --- /dev/null +++ b/apps/node/defaults/defaultAuthorizationRules.json @@ -0,0 +1,72 @@ +{ + "policies": [ + { + "subject": "order-viewer", + "object": "readOrder", + "action": "execute" + }, + { + "subject": "user-viewer", + "object": "readUser", + "action": "execute" + }, + { + "subject": "order-admin", + "object": "createOrder", + "action": "execute" + }, + { + "subject": "order-admin", + "object": "updateOrder", + "action": "execute" + }, + { + "subject": "order-admin", + "object": "deleteOrder", + "action": "execute" + }, + { + "subject": "user-admin", + "object": "createUser", + "action": "execute" + }, + { + "subject": "user-admin", + "object": "updateUser", + "action": "execute" + }, + { + "subject": "user-admin", + "object": "deleteUser", + "action": "execute" + } + ], + "roleAssignments": [ + { + "subject": "Admin1234", + "role": "order-admin" + }, + { + "subject": "Admin1234", + "role": "user-admin" + }, + { + "subject": "User5678", + "role": "user-viewer" + }, + { + "subject": "User1357", + "role": "order-viewer" + } + ], + "roleInheritances": [ + { + "role": "order-admin", + "inheritsFrom": "order-viewer" + }, + { + "role": "user-admin", + "inheritsFrom": "user-viewer" + } + ] +} diff --git a/docs/architecture/node-env-variables.mdx b/docs/architecture/node-env-variables.mdx index 7002926a..a2c68377 100644 --- a/docs/architecture/node-env-variables.mdx +++ b/docs/architecture/node-env-variables.mdx @@ -96,6 +96,10 @@ These variables are only read when running the `bootstrap-dev` CLI command. They | `TWIN_TELEMETRY_SILENT_COMPONENTS` | Comma-separated list of component class names | None | A list of components to exclude from telemetry. | | `TWIN_TRACING_CONNECTOR` | `entity-storage`, `open-telemetry` | None | Tracing connector type. | | `TWIN_TRACING_SILENT_COMPONENTS` | Comma-separated list of component class names | None | A list of components to exclude from tracing. | +| `TWIN_AUTHORIZATION_CONNECTOR` | `entity-storage`, `casbin` | None | Authorization connector type. | +| `TWIN_AUTHORIZATION_CHECK_CACHE_CAPACITY` | Integer | None | Maximum number of cached authorisation check results. | +| `TWIN_AUTHORIZATION_CHECK_CACHE_TTI_MS` | Integer | None | Time-to-idle in milliseconds for cached authorisation check results. | +| `TWIN_AUTHORIZATION_DEFAULT_RULES` | JSON array or `@json:` | None | Default policy rules to seed the authorisation service. Use `@json:authorization-rules.json` to load from a file. | | `TWIN_FAUCET_CONNECTOR` | `entity-storage`, `iota` | None | Faucet connector type. | | `TWIN_WALLET_CONNECTOR` | `entity-storage`, `iota` | None | Wallet connector type. | | `TWIN_NFT_CONNECTOR` | `entity-storage`, `iota` | None | NFT connector type. | @@ -354,3 +358,8 @@ TWIN_ENV_ALLOW_LIST=restPath* | `TWIN_OPEN_TELEMETRY_TRACING_TRACER_VERSION` | String | `1.0.0` | OpenTelemetry tracing specification version. Only used when `TWIN_TRACING_CONNECTOR=open-telemetry`. | | `TWIN_OPEN_TELEMETRY_TRACING_ENDPOINT` | URL | None | OTLP HTTP endpoint to push spans to, for example `http://localhost:4318/v1/traces`. Required when `TWIN_TRACING_CONNECTOR=open-telemetry`. | | `TWIN_OPEN_TELEMETRY_TRACING_PROCESSOR` | `batch`, `simple` | `batch` | Span processor. Use `simple` for local development; `batch` for production. Only used when `TWIN_TRACING_CONNECTOR=open-telemetry`. | +| `TWIN_CASBIN_ENDPOINT` | URL | None | Base URL of the Casbin server, for example `http://localhost:48000`. Required when `TWIN_AUTHORIZATION_CONNECTOR=casbin`. | +| `TWIN_CASBIN_CLIENT_ID` | String | None | OAuth2 client ID for authenticating with the Casbin server. Required when `TWIN_AUTHORIZATION_CONNECTOR=casbin`. | +| `TWIN_CASBIN_CLIENT_SECRET` | String | None | OAuth2 client secret for authenticating with the Casbin server. Required when `TWIN_AUTHORIZATION_CONNECTOR=casbin`. | +| `TWIN_CASBIN_ENFORCER_ID` | String | None | Enforcer identifier in `owner/name` format, for example `built-in/built-in`. Required when `TWIN_AUTHORIZATION_CONNECTOR=casbin`. | +| `TWIN_CASBIN_TIMEOUT_MS` | Integer | None | Request timeout in milliseconds for the Casbin connector. Only used when `TWIN_AUTHORIZATION_CONNECTOR=casbin`. | diff --git a/packages/node-core/package.json b/packages/node-core/package.json index 2bde9b8b..edb732b2 100644 --- a/packages/node-core/package.json +++ b/packages/node-core/package.json @@ -33,6 +33,7 @@ "@twin.org/api-auth-entity-storage-service": "next", "@twin.org/api-models": "next", "@twin.org/api-tenant-processor": "next", + "@twin.org/authorization-models": "next", "@twin.org/cli-core": "next", "@twin.org/context": "next", "@twin.org/core": "next", diff --git a/packages/node-core/src/builders/engineEnvBuilder.ts b/packages/node-core/src/builders/engineEnvBuilder.ts index f8c89e97..cf1c6581 100644 --- a/packages/node-core/src/builders/engineEnvBuilder.ts +++ b/packages/node-core/src/builders/engineEnvBuilder.ts @@ -8,6 +8,7 @@ import { AttestationConnectorType, AuditableItemGraphComponentType, AuditableItemStreamComponentType, + AuthorizationComponentType, type AutomationActionConfig, type AutomationActionType, AutomationComponentType, @@ -98,6 +99,7 @@ import { CONTEXT_ID_HANDLER_FEATURE_DID, CONTEXT_ID_HANDLER_FEATURE_TENANT } fro import { isAuthEntityStorageRequired } from "./engineServerEnvBuilder.js"; import { commaSeparatedListToArray, + envArray, envBoolean, envCount, envDateTime, @@ -105,6 +107,7 @@ import { envMinToMs, envMinutes, envMs, + envObject, envSecToMs, envSeconds } from "./helper/envHelpers.js"; @@ -863,7 +866,17 @@ async function configureAuthorization( if (coreConfig.types.authorizationConnector.length > 0) { coreConfig.types.authorizationComponent ??= []; - coreConfig.types.authorizationComponent.push({ type: "service" }); + + coreConfig.types.authorizationComponent.push({ + type: AuthorizationComponentType.Service, + options: { + config: { + checkCacheCapacity: envInteger(envVars, "authorizationCheckCacheCapacity"), + checkCacheTtiMs: envMs(envVars, "authorizationCheckCacheTtiMs"), + defaultRules: envObject(envVars, "authorizationDefaultRules") + } + } + }); } } @@ -1075,14 +1088,6 @@ async function configureMessaging( } else if ( envVars.messagingPushNotificationConnector === MessagingPushNotificationConnectorType.Aws ) { - let messagingApps; - if (Is.stringValue(envVars.awsMessagingPushNotificationApplications)) { - try { - messagingApps = JSON.parse(envVars.awsMessagingPushNotificationApplications); - } catch {} - } else if (Is.array(envVars.awsMessagingPushNotificationApplications)) { - messagingApps = envVars.awsMessagingPushNotificationApplications; - } coreConfig.types.messagingPushNotificationConnector.push({ type: MessagingPushNotificationConnectorType.Aws, options: { @@ -1092,7 +1097,7 @@ async function configureMessaging( accessKeyId: envVars.awsSesAccessKeyId, secretAccessKey: envVars.awsSesSecretAccessKey, endpoint: envVars.awsSesEndpoint, - applicationsSettings: messagingApps ?? [] + applicationsSettings: envArray(envVars, "awsMessagingPushNotificationApplications", []) } } }); diff --git a/packages/node-core/src/builders/engineServerEnvBuilder.ts b/packages/node-core/src/builders/engineServerEnvBuilder.ts index 2e16beaa..fe8074fb 100644 --- a/packages/node-core/src/builders/engineServerEnvBuilder.ts +++ b/packages/node-core/src/builders/engineServerEnvBuilder.ts @@ -18,11 +18,7 @@ import { } from "@twin.org/engine-server-types"; import { TraceparentHelper } from "@twin.org/tracing-models"; import { CONTEXT_ID_HANDLER_FEATURE_DID, CONTEXT_ID_HANDLER_FEATURE_TENANT } from "../defaults.js"; -import { - isAuthorizationRequired, - isTelemetryRequired, - isTracingRequired -} from "./engineEnvBuilder.js"; +import { isTelemetryRequired, isTracingRequired } from "./engineEnvBuilder.js"; import type { IEnvironmentVariables } from "../models/IEnvironmentVariables.js"; import { commaSeparatedListToArray } from "./helper/envHelpers.js"; diff --git a/packages/node-core/src/builders/helper/envHelpers.ts b/packages/node-core/src/builders/helper/envHelpers.ts index 7102849a..bf0d1a49 100644 --- a/packages/node-core/src/builders/helper/envHelpers.ts +++ b/packages/node-core/src/builders/helper/envHelpers.ts @@ -40,16 +40,27 @@ export function envBoolean( * Coerces an env var that is already in milliseconds to an integer. * @param envVars The environment variables object. * @param key The property name of the env var to coerce. - * @returns The millisecond value, or undefined when not set. + * @param defaultValue The value to return when the env var is absent. Omit to return undefined when absent. + * @returns The millisecond value, the default, or undefined when absent and no default given. * @throws GeneralError if the value is set but cannot be coerced to an integer. */ +export function envMs( + envVars: IEngineEnvironmentVariables, + key: keyof IEngineEnvironmentVariables, + defaultValue: number +): number; export function envMs( envVars: IEngineEnvironmentVariables, key: keyof IEngineEnvironmentVariables +): number | undefined; +export function envMs( + envVars: IEngineEnvironmentVariables, + key: keyof IEngineEnvironmentVariables, + defaultValue?: number ): number | undefined { const value = envVars[key]; if (!Is.stringValue(value)) { - return undefined; + return defaultValue; } const result = Coerce.integer(value); if (Is.empty(result)) { @@ -62,16 +73,27 @@ export function envMs( * Coerces an env var that represents an integer count or size to an integer. * @param envVars The environment variables object. * @param key The property name of the env var to coerce. - * @returns The count, or undefined when not set. + * @param defaultValue The value to return when the env var is absent. Omit to return undefined when absent. + * @returns The count, the default, or undefined when absent and no default given. * @throws GeneralError if the value is set but cannot be coerced to an integer. */ +export function envCount( + envVars: IEngineEnvironmentVariables, + key: keyof IEngineEnvironmentVariables, + defaultValue: number +): number; export function envCount( envVars: IEngineEnvironmentVariables, key: keyof IEngineEnvironmentVariables +): number | undefined; +export function envCount( + envVars: IEngineEnvironmentVariables, + key: keyof IEngineEnvironmentVariables, + defaultValue?: number ): number | undefined { const value = envVars[key]; if (!Is.stringValue(value)) { - return undefined; + return defaultValue; } const result = Coerce.integer(value); if (Is.empty(result)) { @@ -84,16 +106,27 @@ export function envCount( * Coerces an env var that represents an integer to an actual integer. * @param envVars The environment variables object. * @param key The property name of the env var to coerce. - * @returns The integer, or undefined when not set. + * @param defaultValue The value to return when the env var is absent. Omit to return undefined when absent. + * @returns The integer, the default, or undefined when absent and no default given. * @throws GeneralError if the value is set but cannot be coerced to an integer. */ +export function envInteger( + envVars: IEngineEnvironmentVariables, + key: keyof IEngineEnvironmentVariables, + defaultValue: number +): number; export function envInteger( envVars: IEngineEnvironmentVariables, key: keyof IEngineEnvironmentVariables +): number | undefined; +export function envInteger( + envVars: IEngineEnvironmentVariables, + key: keyof IEngineEnvironmentVariables, + defaultValue?: number ): number | undefined { const value = envVars[key]; if (!Is.stringValue(value)) { - return undefined; + return defaultValue; } const result = Coerce.integer(value); if (Is.empty(result)) { @@ -102,20 +135,103 @@ export function envInteger( return result; } +/** + * Returns an env var as a typed object. Accepts a pre-parsed object, an inline JSON object string, + * or a value already expanded from a @json: file reference. + * @param envVars The environment variables object. + * @param key The property name of the env var to coerce. + * @param defaultValue The value to return when the env var is absent or cannot be parsed. + * @returns The parsed object, or the default when absent or the value cannot be parsed. + */ +export function envObject( + envVars: IEngineEnvironmentVariables, + key: keyof IEngineEnvironmentVariables, + defaultValue: T +): T; +/** + * Returns an env var as a typed object. Accepts a pre-parsed object, an inline JSON object string, + * or a value already expanded from a @json: file reference. + * @param envVars The environment variables object. + * @param key The property name of the env var to coerce. + * @returns The parsed object, or undefined when the var is absent or the value cannot be parsed. + */ +export function envObject( + envVars: IEngineEnvironmentVariables, + key: keyof IEngineEnvironmentVariables +): T | undefined; +export function envObject( + envVars: IEngineEnvironmentVariables, + key: keyof IEngineEnvironmentVariables, + defaultValue?: T +): T | undefined { + const value: unknown = envVars[key]; + if (Is.undefined(value)) { + return defaultValue; + } + return Coerce.object(value) ?? defaultValue; +} + +/** + * Returns an env var as a typed array. Accepts a pre-parsed array, an inline JSON array string, + * or a value already expanded from a @json: file reference. + * @param envVars The environment variables object. + * @param key The property name of the env var to coerce. + * @param defaultValue The value to return when the env var is absent or cannot be parsed. + * @returns The parsed array, or the default when absent or the value cannot be parsed. + */ +export function envArray( + envVars: IEngineEnvironmentVariables, + key: keyof IEngineEnvironmentVariables, + defaultValue: T[] +): T[]; +/** + * Returns an env var as a typed array. Accepts a pre-parsed array, an inline JSON array string, + * or a value already expanded from a @json: file reference. + * @param envVars The environment variables object. + * @param key The property name of the env var to coerce. + * @returns The parsed array, or undefined when the var is absent or the value cannot be parsed. + */ +export function envArray( + envVars: IEngineEnvironmentVariables, + key: keyof IEngineEnvironmentVariables +): T[] | undefined; +export function envArray( + envVars: IEngineEnvironmentVariables, + key: keyof IEngineEnvironmentVariables, + defaultValue?: T[] +): T[] | undefined { + const value: unknown = envVars[key]; + if (Is.undefined(value)) { + return defaultValue; + } + return Coerce.array(value) ?? defaultValue; +} + /** * Coerces an env var that is already in seconds to an integer. * @param envVars The environment variables object. * @param key The property name of the env var to coerce. - * @returns The second value, or undefined when not set. + * @param defaultValue The value to return when the env var is absent. Omit to return undefined when absent. + * @returns The second value, the default, or undefined when absent and no default given. * @throws GeneralError if the value is set but cannot be coerced to an integer. */ +export function envSeconds( + envVars: IEngineEnvironmentVariables, + key: keyof IEngineEnvironmentVariables, + defaultValue: number +): number; export function envSeconds( envVars: IEngineEnvironmentVariables, key: keyof IEngineEnvironmentVariables +): number | undefined; +export function envSeconds( + envVars: IEngineEnvironmentVariables, + key: keyof IEngineEnvironmentVariables, + defaultValue?: number ): number | undefined { const value = envVars[key]; if (!Is.stringValue(value)) { - return undefined; + return defaultValue; } const result = Coerce.integer(value); if (Is.empty(result)) { @@ -128,16 +244,27 @@ export function envSeconds( * Coerces an env var that is already in minutes to an integer. * @param envVars The environment variables object. * @param key The property name of the env var to coerce. - * @returns The minute value, or undefined when not set. + * @param defaultValue The value to return when the env var is absent. Omit to return undefined when absent. + * @returns The minute value, the default, or undefined when absent and no default given. * @throws GeneralError if the value is set but cannot be coerced to an integer. */ +export function envMinutes( + envVars: IEngineEnvironmentVariables, + key: keyof IEngineEnvironmentVariables, + defaultValue: number +): number; export function envMinutes( envVars: IEngineEnvironmentVariables, key: keyof IEngineEnvironmentVariables +): number | undefined; +export function envMinutes( + envVars: IEngineEnvironmentVariables, + key: keyof IEngineEnvironmentVariables, + defaultValue?: number ): number | undefined { const value = envVars[key]; if (!Is.stringValue(value)) { - return undefined; + return defaultValue; } const result = Coerce.integer(value); if (Is.empty(result)) { @@ -150,16 +277,27 @@ export function envMinutes( * Coerces an env var that is a datetime string, throwing when the value is set but not a valid datetime. * @param envVars The environment variables object. * @param key The property name of the env var to coerce. - * @returns The datetime string, or undefined when not set. + * @param defaultValue The value to return when the env var is absent. Omit to return undefined when absent. + * @returns The datetime ISO string, the default, or undefined when absent and no default given. * @throws GeneralError if the value is set but cannot be coerced to a datetime. */ +export function envDateTime( + envVars: IEngineEnvironmentVariables, + key: keyof IEngineEnvironmentVariables, + defaultValue: string +): string; export function envDateTime( envVars: IEngineEnvironmentVariables, key: keyof IEngineEnvironmentVariables +): string | undefined; +export function envDateTime( + envVars: IEngineEnvironmentVariables, + key: keyof IEngineEnvironmentVariables, + defaultValue?: string ): string | undefined { const value = envVars[key]; if (!Is.stringValue(value)) { - return undefined; + return defaultValue; } const result = Coerce.dateTime(value) ?? Coerce.date(value); if (Is.empty(result)) { @@ -172,16 +310,27 @@ export function envDateTime( * Coerces an env var to an integer and converts from seconds to milliseconds. * @param envVars The environment variables object. * @param key The property name of the env var to coerce. - * @returns The value in milliseconds, or undefined when not set. + * @param defaultValue The value to return when the env var is absent. Omit to return undefined when absent. + * @returns The value in milliseconds, the default, or undefined when absent and no default given. * @throws GeneralError if the value is set but cannot be coerced to an integer. */ +export function envSecToMs( + envVars: IEngineEnvironmentVariables, + key: keyof IEngineEnvironmentVariables, + defaultValue: number +): number; export function envSecToMs( envVars: IEngineEnvironmentVariables, key: keyof IEngineEnvironmentVariables +): number | undefined; +export function envSecToMs( + envVars: IEngineEnvironmentVariables, + key: keyof IEngineEnvironmentVariables, + defaultValue?: number ): number | undefined { const value = envVars[key]; if (!Is.stringValue(value)) { - return undefined; + return defaultValue; } const n = Coerce.integer(value); if (Is.empty(n)) { @@ -194,16 +343,27 @@ export function envSecToMs( * Coerces an env var to an integer and converts from minutes to milliseconds. * @param envVars The environment variables object. * @param key The property name of the env var to coerce. - * @returns The value in milliseconds, or undefined when not set. + * @param defaultValue The value to return when the env var is absent. Omit to return undefined when absent. + * @returns The value in milliseconds, the default, or undefined when absent and no default given. * @throws GeneralError if the value is set but cannot be coerced to an integer. */ +export function envMinToMs( + envVars: IEngineEnvironmentVariables, + key: keyof IEngineEnvironmentVariables, + defaultValue: number +): number; export function envMinToMs( envVars: IEngineEnvironmentVariables, key: keyof IEngineEnvironmentVariables +): number | undefined; +export function envMinToMs( + envVars: IEngineEnvironmentVariables, + key: keyof IEngineEnvironmentVariables, + defaultValue?: number ): number | undefined { const value = envVars[key]; if (!Is.stringValue(value)) { - return undefined; + return defaultValue; } const n = Coerce.integer(value); if (Is.empty(n)) { diff --git a/packages/node-core/src/models/IEngineEnvironmentVariables.ts b/packages/node-core/src/models/IEngineEnvironmentVariables.ts index 9232f72c..c12c6c35 100644 --- a/packages/node-core/src/models/IEngineEnvironmentVariables.ts +++ b/packages/node-core/src/models/IEngineEnvironmentVariables.ts @@ -724,6 +724,21 @@ export interface IEngineEnvironmentVariables { */ casbinTimeoutMs?: string; + /** + * The maximum number of cached authorisation check results. + */ + authorizationCheckCacheCapacity?: string; + + /** + * The time-to-idle in milliseconds for cached authorisation check results. + */ + authorizationCheckCacheTtiMs?: string; + + /** + * Default policy rules to seed the authorisation service, as a JSON array or a path to a JSON file using the @json: prefix. + */ + authorizationDefaultRules?: string; + /** * The type of faucet connector: entity-storage, iota. */ diff --git a/packages/node-core/src/models/engineEnvironmentVariableKeys.ts b/packages/node-core/src/models/engineEnvironmentVariableKeys.ts index db51b4b7..76aad581 100644 --- a/packages/node-core/src/models/engineEnvironmentVariableKeys.ts +++ b/packages/node-core/src/models/engineEnvironmentVariableKeys.ts @@ -174,6 +174,9 @@ const engineEnvironmentVariableKeysInternal: { casbinClientSecret: true, casbinEnforcerId: true, casbinTimeoutMs: true, + authorizationCheckCacheCapacity: true, + authorizationCheckCacheTtiMs: true, + authorizationDefaultRules: true, tracingSilentComponents: true, // DLT / identity faucetConnector: true, diff --git a/packages/node-core/src/start.ts b/packages/node-core/src/start.ts index 2ac9057e..10a02d73 100644 --- a/packages/node-core/src/start.ts +++ b/packages/node-core/src/start.ts @@ -1,6 +1,7 @@ // Copyright 2024 IOTA Stiftung. // SPDX-License-Identifier: Apache-2.0. -import type { ITenantAdminComponent } from "@twin.org/api-models"; +import type { IRestRoute, ITenantAdminComponent } from "@twin.org/api-models"; +import { RulesHelper } from "@twin.org/authorization-models"; import { ContextIdKeys, ContextIdStore } from "@twin.org/context"; import { Coerce, ComponentFactory, GeneralError, I18n, Is } from "@twin.org/core"; import { Engine } from "@twin.org/engine"; @@ -122,6 +123,14 @@ export async function start( await executeCommand(engine, envVars, cliCommand); } else { try { + const routes = server.getRestRoutes(); + + RulesHelper.buildRules(routes.map(route => ({ + id: route.operationId, + permissions: route.defaultPermissions ?? [], + roles: route.defaultRoles ?? [] + }))); + // Start the server, which also starts the engine. await server.start(); diff --git a/packages/node-core/tests/builders/helper/envHelpers.spec.ts b/packages/node-core/tests/builders/helper/envHelpers.spec.ts index a250cdb7..0f2cd741 100644 --- a/packages/node-core/tests/builders/helper/envHelpers.spec.ts +++ b/packages/node-core/tests/builders/helper/envHelpers.spec.ts @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0. import { commaSeparatedListToArray, + envArray, envBoolean, envCount, envDateTime, @@ -9,6 +10,7 @@ import { envMinToMs, envMinutes, envMs, + envObject, envSecToMs, envSeconds } from "../../../src/builders/helper/envHelpers.js"; @@ -49,14 +51,24 @@ describe("envBoolean", () => { }); describe("envMs", () => { - test("returns undefined when env var is undefined", () => { + test("returns undefined when env var is absent and no default given", () => { expect(envMs({}, "entityStorageMutexTimeout")).toBeUndefined(); }); + test("returns defaultValue when env var is absent", () => { + expect(envMs({}, "entityStorageMutexTimeout", 1000)).toBe(1000); + }); + test("returns integer value for a valid numeric string", () => { expect(envMs({ entityStorageMutexTimeout: "5000" }, "entityStorageMutexTimeout")).toBe(5000); }); + test("returns integer value for a valid numeric string when default given", () => { + expect(envMs({ entityStorageMutexTimeout: "5000" }, "entityStorageMutexTimeout", 1000)).toBe( + 5000 + ); + }); + test("throws GeneralError for a non-numeric string", () => { expect(() => envMs({ entityStorageMutexTimeout: "bad" }, "entityStorageMutexTimeout") @@ -65,42 +77,68 @@ describe("envMs", () => { }); describe("envCount", () => { - test("returns undefined when env var is undefined", () => { + test("returns undefined when env var is absent and no default given", () => { expect(envCount({}, "loggingBatchSize")).toBeUndefined(); }); + test("returns defaultValue when env var is absent", () => { + expect(envCount({}, "loggingBatchSize", 50)).toBe(50); + }); + test("returns integer value for a valid numeric string", () => { expect(envCount({ loggingBatchSize: "100" }, "loggingBatchSize")).toBe(100); }); + test("returns integer value for a valid numeric string when default given", () => { + expect(envCount({ loggingBatchSize: "100" }, "loggingBatchSize", 50)).toBe(100); + }); + test("throws GeneralError for a non-numeric string", () => { expect(() => envCount({ loggingBatchSize: "xyz" }, "loggingBatchSize")).toThrow(); }); }); describe("envInteger", () => { - test("returns undefined when env var is undefined", () => { + test("returns undefined when env var is absent and no default given", () => { expect(envInteger({}, "mySqlPort")).toBeUndefined(); }); + test("returns defaultValue when env var is absent", () => { + expect(envInteger({}, "mySqlPort", 5432)).toBe(5432); + }); + test("returns integer value for a valid numeric string", () => { expect(envInteger({ mySqlPort: "3306" }, "mySqlPort")).toBe(3306); }); + test("returns integer value for a valid numeric string when default given", () => { + expect(envInteger({ mySqlPort: "3306" }, "mySqlPort", 5432)).toBe(3306); + }); + test("throws GeneralError for a non-numeric string", () => { expect(() => envInteger({ mySqlPort: "not-a-port" }, "mySqlPort")).toThrow(); }); }); describe("envSeconds", () => { - test("returns undefined when env var is undefined", () => { + test("returns undefined when env var is absent and no default given", () => { expect(envSeconds({}, "iotaGasReservationDuration")).toBeUndefined(); }); + test("returns defaultValue when env var is absent", () => { + expect(envSeconds({}, "iotaGasReservationDuration", 60)).toBe(60); + }); + test("returns raw seconds value for a valid numeric string", () => { expect(envSeconds({ iotaGasReservationDuration: "30" }, "iotaGasReservationDuration")).toBe(30); }); + test("returns raw seconds value for a valid numeric string when default given", () => { + expect(envSeconds({ iotaGasReservationDuration: "30" }, "iotaGasReservationDuration", 60)).toBe( + 30 + ); + }); + test("throws GeneralError for a non-numeric string", () => { expect(() => envSeconds({ iotaGasReservationDuration: "thirty" }, "iotaGasReservationDuration") @@ -109,16 +147,26 @@ describe("envSeconds", () => { }); describe("envMinutes", () => { - test("returns undefined when env var is undefined", () => { + test("returns undefined when env var is absent and no default given", () => { expect(envMinutes({}, "immutableProofSweepInterval")).toBeUndefined(); }); + test("returns defaultValue when env var is absent", () => { + expect(envMinutes({}, "immutableProofSweepInterval", 5)).toBe(5); + }); + test("returns raw minutes value for a valid numeric string", () => { expect(envMinutes({ immutableProofSweepInterval: "15" }, "immutableProofSweepInterval")).toBe( 15 ); }); + test("returns raw minutes value for a valid numeric string when default given", () => { + expect( + envMinutes({ immutableProofSweepInterval: "15" }, "immutableProofSweepInterval", 5) + ).toBe(15); + }); + test("throws GeneralError for a non-numeric string", () => { expect(() => envMinutes({ immutableProofSweepInterval: "fifteen" }, "immutableProofSweepInterval") @@ -127,10 +175,16 @@ describe("envMinutes", () => { }); describe("envDateTime", () => { - test("returns undefined when env var is undefined", () => { + test("returns undefined when env var is absent and no default given", () => { expect(envDateTime({}, "immutableProofSweepAssumeRetryableBefore")).toBeUndefined(); }); + test("returns defaultValue when env var is absent", () => { + expect( + envDateTime({}, "immutableProofSweepAssumeRetryableBefore", "2020-01-01T00:00:00.000Z") + ).toBe("2020-01-01T00:00:00.000Z"); + }); + test("returns the ISO string for a valid datetime input", () => { expect( envDateTime( @@ -160,14 +214,24 @@ describe("envDateTime", () => { }); describe("envSecToMs", () => { - test("returns undefined when env var is undefined", () => { + test("returns undefined when env var is absent and no default given", () => { expect(envSecToMs({}, "loggingBatchFlushInterval")).toBeUndefined(); }); + test("returns defaultValue when env var is absent", () => { + expect(envSecToMs({}, "loggingBatchFlushInterval", 3000)).toBe(3000); + }); + test("converts seconds to milliseconds", () => { expect(envSecToMs({ loggingBatchFlushInterval: "5" }, "loggingBatchFlushInterval")).toBe(5000); }); + test("converts seconds to milliseconds when default given", () => { + expect(envSecToMs({ loggingBatchFlushInterval: "5" }, "loggingBatchFlushInterval", 3000)).toBe( + 5000 + ); + }); + test("throws GeneralError for a non-numeric string", () => { expect(() => envSecToMs({ loggingBatchFlushInterval: "five" }, "loggingBatchFlushInterval") @@ -176,14 +240,24 @@ describe("envSecToMs", () => { }); describe("envMinToMs", () => { - test("returns undefined when env var is undefined", () => { + test("returns undefined when env var is absent and no default given", () => { expect(envMinToMs({}, "loggingRetentionInterval")).toBeUndefined(); }); + test("returns defaultValue when env var is absent", () => { + expect(envMinToMs({}, "loggingRetentionInterval", 60_000)).toBe(60_000); + }); + test("converts minutes to milliseconds", () => { expect(envMinToMs({ loggingRetentionInterval: "2" }, "loggingRetentionInterval")).toBe(120_000); }); + test("converts minutes to milliseconds when default given", () => { + expect(envMinToMs({ loggingRetentionInterval: "2" }, "loggingRetentionInterval", 60_000)).toBe( + 120_000 + ); + }); + test("throws GeneralError for a non-numeric string", () => { expect(() => envMinToMs({ loggingRetentionInterval: "two" }, "loggingRetentionInterval") @@ -191,6 +265,101 @@ describe("envMinToMs", () => { }); }); +describe("envObject", () => { + test("returns undefined when env var is absent and no default given", () => { + expect(envObject({}, "authorizationDefaultRules")).toBeUndefined(); + }); + + test("returns defaultValue when env var is absent", () => { + const def = { allow: [] }; + expect(envObject({}, "authorizationDefaultRules", def)).toBe(def); + }); + + test("returns the parsed object when the var holds a pre-parsed object", () => { + const rules = { allow: ["read"] }; + expect( + envObject( + { authorizationDefaultRules: rules as unknown as string }, + "authorizationDefaultRules" + ) + ).toEqual(rules); + }); + + test("parses a JSON object string", () => { + expect( + envObject<{ x: number }>( + { authorizationDefaultRules: '{"x":1}' }, + "authorizationDefaultRules" + ) + ).toEqual({ x: 1 }); + }); + + test("returns undefined for a non-object string when no default given", () => { + expect( + envObject({ authorizationDefaultRules: "not-json" }, "authorizationDefaultRules") + ).toBeUndefined(); + }); + + test("returns defaultValue for a non-object string when default given", () => { + const def = { allow: [] }; + expect( + envObject({ authorizationDefaultRules: "not-json" }, "authorizationDefaultRules", def) + ).toBe(def); + }); +}); + +describe("envArray", () => { + test("returns undefined when env var is absent and no default given", () => { + expect(envArray({}, "awsMessagingPushNotificationApplications")).toBeUndefined(); + }); + + test("returns defaultValue when env var is absent", () => { + const def = [{ name: "default" }]; + expect( + envArray({}, "awsMessagingPushNotificationApplications", def as unknown as never[]) + ).toBe(def); + }); + + test("returns the parsed array when the var holds a pre-parsed array", () => { + const apps = [{ name: "app1" }]; + expect( + envArray( + { awsMessagingPushNotificationApplications: apps as unknown as string }, + "awsMessagingPushNotificationApplications" + ) + ).toEqual(apps); + }); + + test("parses a JSON array string", () => { + expect( + envArray( + { awsMessagingPushNotificationApplications: "[1,2,3]" }, + "awsMessagingPushNotificationApplications" + ) + ).toEqual([1, 2, 3]); + }); + + test("returns undefined for a non-array string when no default given", () => { + expect( + envArray( + { awsMessagingPushNotificationApplications: "not-an-array" }, + "awsMessagingPushNotificationApplications" + ) + ).toBeUndefined(); + }); + + test("returns defaultValue for a non-array string when default given", () => { + const def = [{ name: "fallback" }]; + expect( + envArray( + { awsMessagingPushNotificationApplications: "not-an-array" }, + "awsMessagingPushNotificationApplications", + def as unknown as never[] + ) + ).toBe(def); + }); +}); + describe("commaSeparatedListToArray", () => { test("returns empty array for undefined", () => { expect(commaSeparatedListToArray(undefined)).toEqual([]); diff --git a/packages/node-core/tests/endpoints/groups/authorization.json b/packages/node-core/tests/endpoints/groups/authorization.json index 4d158da5..0648c302 100644 --- a/packages/node-core/tests/endpoints/groups/authorization.json +++ b/packages/node-core/tests/endpoints/groups/authorization.json @@ -158,7 +158,7 @@ "description": "POST /authorization/role/:role/inherit — add inheritance editor inherits viewer", "method": "POST", "path": "/authorization/role/editor/inherit", - "body": { "parentRole": "viewer" }, + "body": { "inheritsFrom": "viewer" }, "expectedStatus": 204 }, { @@ -176,7 +176,7 @@ "assert": { "body.roles": "isDefined" } }, { - "description": "DELETE /authorization/role/:role/inherit/:parentRole — remove inheritance", + "description": "DELETE /authorization/role/:role/inherit/:inheritsFrom — remove inheritance", "method": "DELETE", "path": "/authorization/role/editor/inherit/viewer", "expectedStatus": 204 diff --git a/packages/node-core/tests/index.spec.ts b/packages/node-core/tests/index.spec.ts index bc890ba6..014fee73 100644 --- a/packages/node-core/tests/index.spec.ts +++ b/packages/node-core/tests/index.spec.ts @@ -548,7 +548,7 @@ describe("node-core", () => { "GET /authorization/subject/:subject/role/:role", "GET /authorization/role/:role/subjects", "POST /authorization/role/:role/inherit", - "DELETE /authorization/role/:role/inherit/:parentRole", + "DELETE /authorization/role/:role/inherit/:inheritsFrom", "GET /authorization/role/:role/parents", "GET /authorization/role/:role/children", "POST /automation/trigger/:trigger", From f18c79af29d9788a07d22cd56acb3da137158a66 Mon Sep 17 00:00:00 2001 From: Martyn Janes Date: Wed, 26 Aug 2026 12:00:46 +0800 Subject: [PATCH 03/17] feat: migrate scope to roles --- apps/node/.env.example-aws-ec2 | 1 - apps/node/.env.example-federated-catalogue | 1 - apps/node/.env.example-iota-testnet | 1 - apps/node/.env.example-local-entity-storage | 1 - docs/architecture/node-env-variables.mdx | 1 - .../src/builders/engineEnvBuilder.ts | 15 +- .../src/builders/engineServerEnvBuilder.ts | 16 +- .../src/builders/helper/envHelpers.ts | 14 + .../node-core/src/commands/bootstrapDev.ts | 34 +- packages/node-core/src/commands/userCreate.ts | 14 +- packages/node-core/src/commands/userGet.ts | 7 +- packages/node-core/src/commands/userUpdate.ts | 21 +- packages/node-core/src/defaults.ts | 8 +- .../src/models/IEngineEnvironmentVariables.ts | 15 +- .../models/engineEnvironmentVariableKeys.ts | 3 +- .../builders/engineServerEnvBuilder.spec.ts | 28 ++ .../tests/builders/helper/envHelpers.spec.ts | 25 +- packages/node-core/tests/endpoints.spec.ts | 2 +- .../tests/endpoints/groups/authorization.json | 71 ++-- packages/node-core/tests/index.spec.ts | 35 +- packages/node-core/tests/migration.spec.ts | 356 ++++++++++++++++++ 21 files changed, 556 insertions(+), 113 deletions(-) diff --git a/apps/node/.env.example-aws-ec2 b/apps/node/.env.example-aws-ec2 index 5bd31a0d..bf033394 100644 --- a/apps/node/.env.example-aws-ec2 +++ b/apps/node/.env.example-aws-ec2 @@ -328,7 +328,6 @@ TWIN_TELEMETRY_CONNECTOR="entity-storage" # TWIN_CASBIN_ENDPOINT="" # TWIN_CASBIN_CLIENT_ID="" # TWIN_CASBIN_CLIENT_SECRET="" -# TWIN_CASBIN_ENFORCER_ID="" # TWIN_CASBIN_TIMEOUT_MS="" # Faucet Connector diff --git a/apps/node/.env.example-federated-catalogue b/apps/node/.env.example-federated-catalogue index 43531a2d..55eef71e 100644 --- a/apps/node/.env.example-federated-catalogue +++ b/apps/node/.env.example-federated-catalogue @@ -350,7 +350,6 @@ TWIN_TELEMETRY_CONNECTOR="entity-storage" # TWIN_CASBIN_ENDPOINT="" # TWIN_CASBIN_CLIENT_ID="" # TWIN_CASBIN_CLIENT_SECRET="" -# TWIN_CASBIN_ENFORCER_ID="" # TWIN_CASBIN_TIMEOUT_MS="" # Faucet Connector diff --git a/apps/node/.env.example-iota-testnet b/apps/node/.env.example-iota-testnet index 3a6bdd43..e89ae9c6 100644 --- a/apps/node/.env.example-iota-testnet +++ b/apps/node/.env.example-iota-testnet @@ -330,7 +330,6 @@ TWIN_TELEMETRY_CONNECTOR="entity-storage" # TWIN_CASBIN_ENDPOINT="" # TWIN_CASBIN_CLIENT_ID="" # TWIN_CASBIN_CLIENT_SECRET="" -# TWIN_CASBIN_ENFORCER_ID="" # TWIN_CASBIN_TIMEOUT_MS="" # Faucet Connector diff --git a/apps/node/.env.example-local-entity-storage b/apps/node/.env.example-local-entity-storage index 55937794..e3b8bcdc 100644 --- a/apps/node/.env.example-local-entity-storage +++ b/apps/node/.env.example-local-entity-storage @@ -328,7 +328,6 @@ TWIN_TELEMETRY_CONNECTOR="entity-storage" # TWIN_CASBIN_ENDPOINT="" # TWIN_CASBIN_CLIENT_ID="" # TWIN_CASBIN_CLIENT_SECRET="" -# TWIN_CASBIN_ENFORCER_ID="" # TWIN_CASBIN_TIMEOUT_MS="" # Faucet Connector diff --git a/docs/architecture/node-env-variables.mdx b/docs/architecture/node-env-variables.mdx index 6a294040..ecb670ae 100644 --- a/docs/architecture/node-env-variables.mdx +++ b/docs/architecture/node-env-variables.mdx @@ -364,5 +364,4 @@ TWIN_ENV_ALLOW_LIST=restPath* | `TWIN_CASBIN_ENDPOINT` | URL | None | Base URL of the Casbin server, for example `http://localhost:48000`. Required when `TWIN_AUTHORIZATION_CONNECTOR=casbin`. | | `TWIN_CASBIN_CLIENT_ID` | String | None | OAuth2 client ID for authenticating with the Casbin server. Required when `TWIN_AUTHORIZATION_CONNECTOR=casbin`. | | `TWIN_CASBIN_CLIENT_SECRET` | String | None | OAuth2 client secret for authenticating with the Casbin server. Required when `TWIN_AUTHORIZATION_CONNECTOR=casbin`. | -| `TWIN_CASBIN_ENFORCER_ID` | String | None | Enforcer identifier in `owner/name` format, for example `built-in/built-in`. Required when `TWIN_AUTHORIZATION_CONNECTOR=casbin`. | | `TWIN_CASBIN_TIMEOUT_MS` | Integer | None | Request timeout in milliseconds for the Casbin connector. Only used when `TWIN_AUTHORIZATION_CONNECTOR=casbin`. | diff --git a/packages/node-core/src/builders/engineEnvBuilder.ts b/packages/node-core/src/builders/engineEnvBuilder.ts index 97f0bcbf..4669e3a3 100644 --- a/packages/node-core/src/builders/engineEnvBuilder.ts +++ b/packages/node-core/src/builders/engineEnvBuilder.ts @@ -97,7 +97,11 @@ import { type IOpenTelemetryTracingConnectorConfig, OpenTelemetryProcessorTypes } from "@twin.org/tracing-connector-opentelemetry"; -import { CONTEXT_ID_HANDLER_FEATURE_DID, CONTEXT_ID_HANDLER_FEATURE_TENANT } from "../defaults.js"; +import { + AUTHORIZATION_MODEL_ID, + CONTEXT_ID_HANDLER_FEATURE_DID, + CONTEXT_ID_HANDLER_FEATURE_TENANT +} from "../defaults.js"; import { isAuthEntityStorageRequired } from "./engineServerEnvBuilder.js"; import type { IEngineEnvironmentVariables } from "../models/IEngineEnvironmentVariables.js"; import { @@ -110,9 +114,9 @@ import { envMinToMs, envMinutes, envMs, - envObject, envSeconds, - envSecToMs + envSecToMs, + envString } from "./helper/envHelpers.js"; /** @@ -922,7 +926,6 @@ async function configureAuthorization( endpoint: envVars.casbinEndpoint ?? "", clientId: envVars.casbinClientId ?? "", clientSecret: envVars.casbinClientSecret ?? "", - enforcerId: envVars.casbinEnforcerId ?? "", timeoutMs: envMs(envVars, "casbinTimeoutMs") } } @@ -936,9 +939,9 @@ async function configureAuthorization( type: AuthorizationComponentType.Service, options: { config: { + migrationModelId: envString(envVars, "authorizationModelId", AUTHORIZATION_MODEL_ID), checkCacheCapacity: envInteger(envVars, "authorizationCheckCacheCapacity"), - checkCacheTtiMs: envMs(envVars, "authorizationCheckCacheTtiMs"), - defaultRules: envObject(envVars, "authorizationDefaultRules") + checkCacheTtiMs: envMs(envVars, "authorizationCheckCacheTtiMs") } } }); diff --git a/packages/node-core/src/builders/engineServerEnvBuilder.ts b/packages/node-core/src/builders/engineServerEnvBuilder.ts index 439173f0..b689b1a6 100644 --- a/packages/node-core/src/builders/engineServerEnvBuilder.ts +++ b/packages/node-core/src/builders/engineServerEnvBuilder.ts @@ -17,14 +17,18 @@ import { SocketRouteProcessorType } from "@twin.org/engine-server-types"; import { TraceparentHelper } from "@twin.org/tracing-models"; -import { CONTEXT_ID_HANDLER_FEATURE_DID, CONTEXT_ID_HANDLER_FEATURE_TENANT } from "../defaults.js"; +import { + AUTHORIZATION_MODEL_ID, + CONTEXT_ID_HANDLER_FEATURE_DID, + CONTEXT_ID_HANDLER_FEATURE_TENANT +} from "../defaults.js"; import { isAuthorizationRequired, isTelemetryEnabled, isTracingEnabled } from "./engineEnvBuilder.js"; import type { IEnvironmentVariables } from "../models/IEnvironmentVariables.js"; -import { commaSeparatedListToArray, envKeyIntegerPairs } from "./helper/envHelpers.js"; +import { commaSeparatedListToArray, envKeyIntegerPairs, envString } from "./helper/envHelpers.js"; /** * Handles the configuration of the server. @@ -267,13 +271,17 @@ export async function buildEngineServerConfiguration( serverConfig.types.restRouteProcessor.push({ type: RestRouteProcessorType.TenantOverride, options: { - config: {} + config: { + authorizationModelId: envString(envVars, "authorizationModelId", AUTHORIZATION_MODEL_ID) + } } }); serverConfig.types.socketRouteProcessor.push({ type: SocketRouteProcessorType.TenantOverride, options: { - config: {} + config: { + authorizationModelId: envString(envVars, "authorizationModelId", AUTHORIZATION_MODEL_ID) + } } }); } diff --git a/packages/node-core/src/builders/helper/envHelpers.ts b/packages/node-core/src/builders/helper/envHelpers.ts index fcae9895..ca7c27e7 100644 --- a/packages/node-core/src/builders/helper/envHelpers.ts +++ b/packages/node-core/src/builders/helper/envHelpers.ts @@ -2,6 +2,20 @@ // SPDX-License-Identifier: Apache-2.0. import { Coerce, GeneralError, Is } from "@twin.org/core"; +/** + * Returns an env var as a string when it holds a non-empty value, falling back to the supplied default. + * @param envVars The environment variables object. + * @param key The property name of the env var to read. + * @param defaultValue The value to return when the env var is absent or empty. Omit to return undefined when absent. + * @returns The string value, the default, or undefined when absent and no default given. + */ +export function envString(envVars: T, key: keyof T, defaultValue: string): string; +export function envString(envVars: T, key: keyof T): string | undefined; +export function envString(envVars: T, key: keyof T, defaultValue?: string): string | undefined { + const value = envVars[key]; + return Is.stringValue(value) ? value : defaultValue; +} + /** * Coerces an env var to a boolean, falling back to the supplied default when not set. * @param envVars The environment variables object. diff --git a/packages/node-core/src/commands/bootstrapDev.ts b/packages/node-core/src/commands/bootstrapDev.ts index 87e56df1..41703a77 100644 --- a/packages/node-core/src/commands/bootstrapDev.ts +++ b/packages/node-core/src/commands/bootstrapDev.ts @@ -9,6 +9,7 @@ import { Coerce, ComponentFactory, GeneralError, I18n, Is } from "@twin.org/core import type { IEngineCore } from "@twin.org/engine-models"; import { commaSeparatedListToArray } from "../builders/helper/envHelpers.js"; import { + AUTHORIZATION_MODEL_ID, DEFAULT_ESCALATED_PRIVILEGE_ROLE, DEFAULT_TENANT_ADMIN_ROLE, DEFAULT_USER_ADMIN_ROLE @@ -237,7 +238,10 @@ export async function bootstrapDev( await ContextIdStore.run( { [ContextIdKeys.Node]: nodeId, [ContextIdKeys.Tenant]: tenant?.id }, async () => { - await bootstrapAuthorization(engineCore); + await bootstrapAuthorization( + engineCore, + envVars.authorizationModelId ?? AUTHORIZATION_MODEL_ID + ); } ); @@ -297,11 +301,13 @@ export async function bootstrapDev( /** * Seed default roles into the authorization system so they can be assigned to users. * @param engineCore The engine core. + * @param authorizationModelId The model identifier for authorization. * @returns A promise that resolves when the default roles have been seeded. * @internal */ async function bootstrapAuthorization( - engineCore: IEngineCore + engineCore: IEngineCore, + authorizationModelId: string ): Promise { CLIDisplay.break(); CLIDisplay.section( @@ -314,22 +320,26 @@ async function bootstrapAuthorization( defaultAuthorizationComponentType ); - await authorizationComponent.addPolicy({ - subject: DEFAULT_TENANT_ADMIN_ROLE, - object: "tenantCreate", - action: "execute" - }); - await authorizationComponent.addPolicy({ - subject: DEFAULT_USER_ADMIN_ROLE, - object: "authenticationAdminCreateUser", - action: "execute" - }); + await authorizationComponent.addPolicy( + authorizationModelId, + DEFAULT_TENANT_ADMIN_ROLE, + "tenantCreate", + "execute" + ); + await authorizationComponent.addPolicy( + authorizationModelId, + DEFAULT_USER_ADMIN_ROLE, + "authenticationAdminCreateUser", + "execute" + ); await authorizationComponent.addRoleInheritance( + authorizationModelId, DEFAULT_ESCALATED_PRIVILEGE_ROLE, DEFAULT_TENANT_ADMIN_ROLE ); await authorizationComponent.addRoleInheritance( + authorizationModelId, DEFAULT_ESCALATED_PRIVILEGE_ROLE, DEFAULT_USER_ADMIN_ROLE ); diff --git a/packages/node-core/src/commands/userCreate.ts b/packages/node-core/src/commands/userCreate.ts index d6b2cbce..cba7ad60 100644 --- a/packages/node-core/src/commands/userCreate.ts +++ b/packages/node-core/src/commands/userCreate.ts @@ -13,6 +13,7 @@ import type { IEngineCore } from "@twin.org/engine-models"; import { Did, IdentityProfileConnectorFactory } from "@twin.org/identity-models"; import type { Person, WithContext } from "schema-dts"; import { commaSeparatedListToArray } from "../builders/helper/envHelpers.js"; +import { AUTHORIZATION_MODEL_ID } from "../defaults.js"; import type { ICliCommandDefinition } from "../models/ICliCommandDefinition.js"; import type { IEnvironmentVariables } from "../models/IEnvironmentVariables.js"; @@ -196,6 +197,7 @@ export async function userCreate( const paramsEmail = params.email; const paramsUserIdentity = params.userIdentity; const paramsOrganizationIdentity = params.organizationIdentity; + const authorizationModelId = envVars.authorizationModelId ?? AUTHORIZATION_MODEL_ID; Guards.email("userCreate", "email", paramsEmail); Did.guard("userCreate", "user-identity", paramsUserIdentity); Did.guard("userCreate", "organization-identity", paramsOrganizationIdentity); @@ -285,9 +287,13 @@ export async function userCreate( await authenticationAdminComponent.create(user); } - await verifyRoles(authorizationComponent, roles); + await verifyRoles(authorizationComponent, authorizationModelId, roles); for (const role of roles) { - await authorizationComponent.addRoleForSubject(paramsUserIdentity, role); + await authorizationComponent.addRoleForSubject( + authorizationModelId, + paramsUserIdentity, + role + ); } } ); @@ -366,15 +372,17 @@ export async function userCreate( /** * Verify that the specified roles exist in the system. * @param authorizationComponent The authorization component. + * @param authorizationModelId The model identifier for authorization. * @param roles The roles to verify. * @returns A promise that resolves when all roles have been verified. * @throws GeneralError if any of the specified roles do not exist. */ export async function verifyRoles( authorizationComponent: IAuthorizationComponent, + authorizationModelId: string, roles: string[] ): Promise { - const results = await authorizationComponent.hasRoles(roles); + const results = await authorizationComponent.hasRoles(authorizationModelId, roles); const missingRoles = roles.filter((role, i) => !results[i]); if (missingRoles.length > 0) { throw new GeneralError("userCreate", "rolesNotFound", { diff --git a/packages/node-core/src/commands/userGet.ts b/packages/node-core/src/commands/userGet.ts index af024f65..4ec819c4 100644 --- a/packages/node-core/src/commands/userGet.ts +++ b/packages/node-core/src/commands/userGet.ts @@ -9,6 +9,7 @@ import { CLIDisplay } from "@twin.org/cli-core"; import { ContextIdKeys, ContextIdStore } from "@twin.org/context"; import { Coerce, ComponentFactory, GeneralError, Guards, I18n, Is } from "@twin.org/core"; import type { IEngineCore } from "@twin.org/engine-models"; +import { AUTHORIZATION_MODEL_ID } from "../defaults.js"; import type { ICliCommandDefinition } from "../models/ICliCommandDefinition.js"; import type { IEnvironmentVariables } from "../models/IEnvironmentVariables.js"; @@ -85,6 +86,7 @@ export async function userGet( const defaultAuthenticationAdminComponentType = engineCore.getRegisteredInstanceType( "authenticationAdminComponent" ); + const authorizationModelId = envVars.authorizationModelId ?? AUTHORIZATION_MODEL_ID; const authenticationAdminComponent = ComponentFactory.get( defaultAuthenticationAdminComponentType ); @@ -104,7 +106,10 @@ export async function userGet( let foundRoles: string[] | undefined; if (Is.stringValue(foundUser.userIdentity)) { - foundRoles = await authorizationComponent.getRolesForSubject(foundUser.userIdentity); + foundRoles = await authorizationComponent.getRolesForSubject( + authorizationModelId, + foundUser.userIdentity + ); } return { user: foundUser, diff --git a/packages/node-core/src/commands/userUpdate.ts b/packages/node-core/src/commands/userUpdate.ts index d0c4dfe6..3a74ce06 100644 --- a/packages/node-core/src/commands/userUpdate.ts +++ b/packages/node-core/src/commands/userUpdate.ts @@ -13,6 +13,7 @@ import { Did, IdentityProfileConnectorFactory } from "@twin.org/identity-models" import type { Person, WithContext } from "schema-dts"; import { verifyRoles } from "./userCreate.js"; import { commaSeparatedListToArray } from "../builders/helper/envHelpers.js"; +import { AUTHORIZATION_MODEL_ID } from "../defaults.js"; import type { ICliCommandDefinition } from "../models/ICliCommandDefinition.js"; import type { IEnvironmentVariables } from "../models/IEnvironmentVariables.js"; @@ -146,6 +147,7 @@ export async function userUpdate( const paramsEmail = params.email; const paramsUserIdentity = params.userIdentity; const paramsOrganizationIdentity = params.organizationIdentity; + const authorizationModelId = envVars.authorizationModelId ?? AUTHORIZATION_MODEL_ID; Guards.email("userUpdate", "email", paramsEmail); if (Is.stringValue(paramsUserIdentity)) { @@ -196,21 +198,32 @@ export async function userUpdate( const existingUser = await authenticationAdminComponent.get(paramsEmail); await authenticationAdminComponent.update(user); - let currentRoles = await authorizationComponent.getRolesForSubject(existingUser.userIdentity); + let currentRoles = await authorizationComponent.getRolesForSubject( + authorizationModelId, + existingUser.userIdentity + ); if (Is.stringValue(params.roles)) { const roles = commaSeparatedListToArray(params.roles); - await verifyRoles(authorizationComponent, roles); + await verifyRoles(authorizationComponent, authorizationModelId, roles); const rolesToAdd = roles.filter(role => !currentRoles.includes(role)); const rolesToRemove = currentRoles.filter(role => !roles.includes(role)); for (const role of rolesToAdd) { - await authorizationComponent.addRoleForSubject(existingUser.userIdentity, role); + await authorizationComponent.addRoleForSubject( + authorizationModelId, + existingUser.userIdentity, + role + ); } for (const role of rolesToRemove) { - await authorizationComponent.removeRoleForSubject(existingUser.userIdentity, role); + await authorizationComponent.removeRoleForSubject( + authorizationModelId, + existingUser.userIdentity, + role + ); } currentRoles = roles; diff --git a/packages/node-core/src/defaults.ts b/packages/node-core/src/defaults.ts index 22302622..75922852 100644 --- a/packages/node-core/src/defaults.ts +++ b/packages/node-core/src/defaults.ts @@ -26,6 +26,11 @@ export const TRUST_VERIFICATION_METHOD_ID = "trust-assertion"; */ export const AUTH_SIGNING_KEY_ID = "auth-signing"; +/** + * Default model identifier for authorization. + */ +export const AUTHORIZATION_MODEL_ID = "rest"; + /** * Feature tag identifying the DID context ID handler. */ @@ -62,7 +67,8 @@ export function getEnvDefaults(envPrefix: string): { [key: string]: string } { [`${envPrefix}IMMUTABLE_PROOF_VERIFICATION_METHOD_ID`]: IMMUTABLE_PROOF_VERIFICATION_METHOD_ID, [`${envPrefix}BLOB_STORAGE_ENCRYPTION_KEY_ID`]: BLOB_STORAGE_ENCRYPTION_KEY_ID, [`${envPrefix}TRUST_VERIFICATION_METHOD_ID`]: TRUST_VERIFICATION_METHOD_ID, - [`${envPrefix}AUTH_SIGNING_KEY_ID`]: AUTH_SIGNING_KEY_ID + [`${envPrefix}AUTH_SIGNING_KEY_ID`]: AUTH_SIGNING_KEY_ID, + [`${envPrefix}AUTHORIZATION_MODEL_ID`]: AUTHORIZATION_MODEL_ID }; return envVars; } diff --git a/packages/node-core/src/models/IEngineEnvironmentVariables.ts b/packages/node-core/src/models/IEngineEnvironmentVariables.ts index 1581dc06..aba673ca 100644 --- a/packages/node-core/src/models/IEngineEnvironmentVariables.ts +++ b/packages/node-core/src/models/IEngineEnvironmentVariables.ts @@ -711,6 +711,11 @@ export interface IEngineEnvironmentVariables { */ authorizationConnector?: string; + /** + * The model identifier to use for authorization. + */ + authorizationModelId?: string; + /** * The base URL of the Casbin server (e.g. "http://localhost:48000"), required when using the casbin authorization connector. */ @@ -726,11 +731,6 @@ export interface IEngineEnvironmentVariables { */ casbinClientSecret?: string; - /** - * The enforcer identifier in "owner/name" format (e.g. "built-in/built-in"), required when using the casbin authorization connector. - */ - casbinEnforcerId?: string; - /** * The request timeout in milliseconds for the Casbin authorization connector. */ @@ -746,11 +746,6 @@ export interface IEngineEnvironmentVariables { */ authorizationCheckCacheTtiMs?: string; - /** - * Default policy rules to seed the authorisation service, as a JSON array or a path to a JSON file using the @json: prefix. - */ - authorizationDefaultRules?: string; - /** * The type of faucet connector: entity-storage, iota. */ diff --git a/packages/node-core/src/models/engineEnvironmentVariableKeys.ts b/packages/node-core/src/models/engineEnvironmentVariableKeys.ts index 7031f48e..fafddb94 100644 --- a/packages/node-core/src/models/engineEnvironmentVariableKeys.ts +++ b/packages/node-core/src/models/engineEnvironmentVariableKeys.ts @@ -171,14 +171,13 @@ const engineEnvironmentVariableKeysInternal: { tracingMutexTimeout: true, // authorization authorizationConnector: true, + authorizationModelId: true, casbinEndpoint: true, casbinClientId: true, casbinClientSecret: true, - casbinEnforcerId: true, casbinTimeoutMs: true, authorizationCheckCacheCapacity: true, authorizationCheckCacheTtiMs: true, - authorizationDefaultRules: true, tracingSilentComponents: true, // DLT / identity faucetConnector: true, diff --git a/packages/node-core/tests/builders/engineServerEnvBuilder.spec.ts b/packages/node-core/tests/builders/engineServerEnvBuilder.spec.ts index ae8eb6b0..546292b3 100644 --- a/packages/node-core/tests/builders/engineServerEnvBuilder.spec.ts +++ b/packages/node-core/tests/builders/engineServerEnvBuilder.spec.ts @@ -32,6 +32,34 @@ describe("buildEngineServerConfiguration - TenantOverride processors", () => { expect(restTypes).toContain(RestRouteProcessorType.TenantOverride); expect(socketTypes).toContain(SocketRouteProcessorType.TenantOverride); + expect( + config.types.restRouteProcessor?.find(p => p.type === RestRouteProcessorType.TenantOverride) + ).toMatchObject({ options: { config: { authorizationModelId: "rest" } } }); + }); + + test("passes the configured authorization model to TenantOverride processors", async () => { + const contextKeys: { key: string; requiredHandlerFeatures: string[] }[] = []; + const config = await buildEngineServerConfiguration( + { + ...BASE_VARS, + tenantEnabled: "true", + authProcessorType: AuthenticationComponentType.EntityStorage, + authorizationConnector: AuthorizationConnectorType.EntityStorage, + authorizationModelId: "custom" + }, + contextKeys, + { types: {} }, + SERVER_INFO + ); + + expect( + config.types.restRouteProcessor?.find(p => p.type === RestRouteProcessorType.TenantOverride) + ).toMatchObject({ options: { config: { authorizationModelId: "custom" } } }); + expect( + config.types.socketRouteProcessor?.find( + p => p.type === SocketRouteProcessorType.TenantOverride + ) + ).toMatchObject({ options: { config: { authorizationModelId: "custom" } } }); }); test("TenantOverride processor is registered after AuthHeader processor", async () => { diff --git a/packages/node-core/tests/builders/helper/envHelpers.spec.ts b/packages/node-core/tests/builders/helper/envHelpers.spec.ts index 26b73017..7b5e3143 100644 --- a/packages/node-core/tests/builders/helper/envHelpers.spec.ts +++ b/packages/node-core/tests/builders/helper/envHelpers.spec.ts @@ -13,7 +13,8 @@ import { envMs, envObject, envSecToMs, - envSeconds + envSeconds, + envString } from "../../../src/builders/helper/envHelpers.js"; describe("envBoolean", () => { @@ -582,3 +583,25 @@ describe("envKeyIntegerPairs", () => { ); }); }); + +describe("envString", () => { + test("returns undefined when env var is absent and no default given", () => { + expect(envString<{ modelId?: string }>({}, "modelId")).toBeUndefined(); + }); + + test("returns defaultValue when env var is absent", () => { + expect(envString<{ modelId?: string }>({}, "modelId", "rest")).toBe("rest"); + }); + + test("returns defaultValue when env var is an empty string", () => { + expect(envString({ modelId: "" }, "modelId", "rest")).toBe("rest"); + }); + + test("returns the string value when set", () => { + expect(envString({ modelId: "custom" }, "modelId", "rest")).toBe("custom"); + }); + + test("returns the string value with no default", () => { + expect(envString({ modelId: "custom" }, "modelId")).toBe("custom"); + }); +}); diff --git a/packages/node-core/tests/endpoints.spec.ts b/packages/node-core/tests/endpoints.spec.ts index 180eb500..78e7c1d5 100644 --- a/packages/node-core/tests/endpoints.spec.ts +++ b/packages/node-core/tests/endpoints.spec.ts @@ -73,7 +73,7 @@ const SHARED_ENV_VARS: { [id: string]: string } = { TWIN_LOGGING_CONNECTOR: LoggingConnectorType.EntityStorage, TWIN_TELEMETRY_CONNECTOR: TelemetryConnectorType.EntityStorage, TWIN_TRACING_CONNECTOR: TracingConnectorType.EntityStorage, - TWIN_AUTHORIZATION_CONNECTOR: "entity-storage", + TWIN_AUTHORIZATION_CONNECTOR: AuthorizationConnectorType.EntityStorage, TWIN_VAULT_CONNECTOR: VaultConnectorType.EntityStorage, TWIN_IDENTITY_CONNECTOR: IdentityConnectorType.EntityStorage, TWIN_IDENTITY_RESOLVER_CONNECTOR: IdentityResolverConnectorType.EntityStorage, diff --git a/packages/node-core/tests/endpoints/groups/authorization.json b/packages/node-core/tests/endpoints/groups/authorization.json index 0648c302..ba124913 100644 --- a/packages/node-core/tests/endpoints/groups/authorization.json +++ b/packages/node-core/tests/endpoints/groups/authorization.json @@ -4,49 +4,49 @@ { "description": "POST /authorization/check — 400 missing subject", "method": "POST", - "path": "/authorization/check", + "path": "/authorization/rest/check", "body": { "object": "/data", "action": "read" }, "expectedStatus": 400 }, { "description": "POST /authorization/policy — 400 missing object", "method": "POST", - "path": "/authorization/policy", + "path": "/authorization/rest/policy", "body": { "subject": "test-subject", "action": "read" }, "expectedStatus": 400 }, { "description": "POST /authorization/policy — add policy", "method": "POST", - "path": "/authorization/policy", + "path": "/authorization/rest/policy", "body": { "subject": "test-subject", "object": "/data", "action": "read" }, "expectedStatus": 204 }, { "description": "POST /authorization/policy — add second policy", "method": "POST", - "path": "/authorization/policy", + "path": "/authorization/rest/policy", "body": { "subject": "test-subject", "object": "/data", "action": "write" }, "expectedStatus": 204 }, { "description": "GET /authorization/policy — list all policies", "method": "GET", - "path": "/authorization/policy", + "path": "/authorization/rest/policy", "expectedStatus": 200, "assert": { "body.entities": "isDefined" } }, { "description": "GET /authorization/policy/:subject — get policies for subject", "method": "GET", - "path": "/authorization/policy/test-subject", + "path": "/authorization/rest/policy/test-subject", "expectedStatus": 200, - "assert": { "body.policies": "isDefined" } + "assert": { "body.entities": "isDefined" } }, { "description": "POST /authorization/check — allowed after policy added", "method": "POST", - "path": "/authorization/check", + "path": "/authorization/rest/check", "body": { "subject": "test-subject", "object": "/data", "action": "read" }, "expectedStatus": 200, "assert": { "body.allowed": true } @@ -54,143 +54,124 @@ { "description": "POST /authorization/check — not allowed for unknown action", "method": "POST", - "path": "/authorization/check", + "path": "/authorization/rest/check", "body": { "subject": "test-subject", "object": "/data", "action": "delete" }, "expectedStatus": 200, "assert": { "body.allowed": false } }, - { - "description": "POST /authorization/check-any — 400 missing subjects", - "method": "POST", - "path": "/authorization/check-any", - "body": { "object": "/data", "action": "read" }, - "expectedStatus": 400 - }, - { - "description": "POST /authorization/check-any — allowed for one of the subjects", - "method": "POST", - "path": "/authorization/check-any", - "body": { - "subjects": ["test-subject", "other-subject"], - "object": "/data", - "action": "read" - }, - "expectedStatus": 200, - "assert": { "body.allowed": true } - }, { "description": "POST /authorization/policy/remove — remove one policy", "method": "POST", - "path": "/authorization/policy/remove", + "path": "/authorization/rest/policy/remove", "body": { "subject": "test-subject", "object": "/data", "action": "write" }, "expectedStatus": 204 }, { "description": "GET /authorization/roles — list all roles (empty initially)", "method": "GET", - "path": "/authorization/roles", + "path": "/authorization/rest/roles", "expectedStatus": 200, "assert": { "body.roles": "isDefined" } }, { "description": "POST /authorization/subject/:subject/role — 400 missing role", "method": "POST", - "path": "/authorization/subject/test-subject/role", + "path": "/authorization/rest/subject/test-subject/role", "body": {}, "expectedStatus": 400 }, { "description": "POST /authorization/subject/:subject/role — add editor role", "method": "POST", - "path": "/authorization/subject/test-subject/role", + "path": "/authorization/rest/subject/test-subject/role", "body": { "role": "editor" }, "expectedStatus": 204 }, { "description": "POST /authorization/subject/:subject/role — add viewer role", "method": "POST", - "path": "/authorization/subject/test-subject/role", + "path": "/authorization/rest/subject/test-subject/role", "body": { "role": "viewer" }, "expectedStatus": 204 }, { "description": "GET /authorization/subject/:subject/roles — get roles for subject", "method": "GET", - "path": "/authorization/subject/test-subject/roles", + "path": "/authorization/rest/subject/test-subject/roles", "expectedStatus": 200, "assert": { "body.roles": "isDefined" } }, { "description": "GET /authorization/subject/:subject/role/:role — has editor role", "method": "GET", - "path": "/authorization/subject/test-subject/role/editor", + "path": "/authorization/rest/subject/test-subject/role/editor", "expectedStatus": 200, "assert": { "body.hasRole": true } }, { "description": "GET /authorization/subject/:subject/role/:role — does not have admin role", "method": "GET", - "path": "/authorization/subject/test-subject/role/admin", + "path": "/authorization/rest/subject/test-subject/role/admin", "expectedStatus": 200, "assert": { "body.hasRole": false } }, { "description": "GET /authorization/role/:role/subjects — get subjects for editor role", "method": "GET", - "path": "/authorization/role/editor/subjects", + "path": "/authorization/rest/role/editor/subjects", "expectedStatus": 200, "assert": { "body.subjects": "isDefined" } }, { "description": "DELETE /authorization/subject/:subject/role/:role — remove viewer role", "method": "DELETE", - "path": "/authorization/subject/test-subject/role/viewer", + "path": "/authorization/rest/subject/test-subject/role/viewer", "expectedStatus": 204 }, { "description": "GET /authorization/subject/:subject/role/:role — no longer has viewer role", "method": "GET", - "path": "/authorization/subject/test-subject/role/viewer", + "path": "/authorization/rest/subject/test-subject/role/viewer", "expectedStatus": 200, "assert": { "body.hasRole": false } }, { "description": "POST /authorization/role/:role/inherit — add inheritance editor inherits viewer", "method": "POST", - "path": "/authorization/role/editor/inherit", + "path": "/authorization/rest/role/editor/inherit", "body": { "inheritsFrom": "viewer" }, "expectedStatus": 204 }, { "description": "GET /authorization/role/:role/parents — get parent roles for editor", "method": "GET", - "path": "/authorization/role/editor/parents", + "path": "/authorization/rest/role/editor/parents", "expectedStatus": 200, "assert": { "body.roles": "isDefined" } }, { "description": "GET /authorization/role/:role/children — get child roles for viewer", "method": "GET", - "path": "/authorization/role/viewer/children", + "path": "/authorization/rest/role/viewer/children", "expectedStatus": 200, "assert": { "body.roles": "isDefined" } }, { "description": "DELETE /authorization/role/:role/inherit/:inheritsFrom — remove inheritance", "method": "DELETE", - "path": "/authorization/role/editor/inherit/viewer", + "path": "/authorization/rest/role/editor/inherit/viewer", "expectedStatus": 204 }, { "description": "DELETE /authorization/subject/:subject/roles — remove all roles for subject", "method": "DELETE", - "path": "/authorization/subject/test-subject/roles", + "path": "/authorization/rest/subject/test-subject/roles", "expectedStatus": 204 }, { "description": "GET /authorization/subject/:subject/roles — empty after remove all", "method": "GET", - "path": "/authorization/subject/test-subject/roles", + "path": "/authorization/rest/subject/test-subject/roles", "expectedStatus": 200, "assert": { "body.roles": "isDefined" } } diff --git a/packages/node-core/tests/index.spec.ts b/packages/node-core/tests/index.spec.ts index eca3f3ec..7ed4a230 100644 --- a/packages/node-core/tests/index.spec.ts +++ b/packages/node-core/tests/index.spec.ts @@ -534,24 +534,23 @@ describe("node-core", () => { "PUT /tracing/:spanId", "GET /tracing", "GET /tracing/trace/:traceId", - "POST /authorization/check", - "POST /authorization/check-any", - "POST /authorization/policy", - "POST /authorization/policy/remove", - "GET /authorization/policy", - "GET /authorization/roles", - "POST /authorization/roles/has", - "GET /authorization/policy/:subject", - "POST /authorization/subject/:subject/role", - "DELETE /authorization/subject/:subject/role/:role", - "DELETE /authorization/subject/:subject/roles", - "GET /authorization/subject/:subject/roles", - "GET /authorization/subject/:subject/role/:role", - "GET /authorization/role/:role/subjects", - "POST /authorization/role/:role/inherit", - "DELETE /authorization/role/:role/inherit/:inheritsFrom", - "GET /authorization/role/:role/parents", - "GET /authorization/role/:role/children", + "POST /authorization/:modelId/check", + "POST /authorization/:modelId/policy", + "POST /authorization/:modelId/policy/remove", + "GET /authorization/:modelId/policy", + "GET /authorization/:modelId/roles", + "POST /authorization/:modelId/roles/has", + "GET /authorization/:modelId/policy/:subject", + "POST /authorization/:modelId/subject/:subject/role", + "DELETE /authorization/:modelId/subject/:subject/role/:role", + "DELETE /authorization/:modelId/subject/:subject/roles", + "GET /authorization/:modelId/subject/:subject/roles", + "GET /authorization/:modelId/subject/:subject/role/:role", + "GET /authorization/:modelId/role/:role/subjects", + "POST /authorization/:modelId/role/:role/inherit", + "DELETE /authorization/:modelId/role/:role/inherit/:inheritsFrom", + "GET /authorization/:modelId/role/:role/parents", + "GET /authorization/:modelId/role/:role/children", "POST /automation/trigger/:trigger", "POST /automation", "DELETE /automation/:actionId", diff --git a/packages/node-core/tests/migration.spec.ts b/packages/node-core/tests/migration.spec.ts index d47239db..40145371 100644 --- a/packages/node-core/tests/migration.spec.ts +++ b/packages/node-core/tests/migration.spec.ts @@ -3,7 +3,9 @@ import { ContextIdStore } from "@twin.org/context"; import { Factory } from "@twin.org/core"; import { MemoryStateStorage } from "@twin.org/engine-core"; +import { AuthenticationAdminComponentType } from "@twin.org/engine-server-types"; import { + AuthorizationConnectorType, BackgroundTaskComponentType, EntityStorageComponentType, EntityStorageConnectorType, @@ -751,3 +753,357 @@ describe("migration - multi-tenant", () => { } }); }); + +describe("migration - scope to roles", () => { + beforeAll(async () => { + const storage = await ContextIdStore.getStorage(); + const realGetStore = storage.getStore.bind(storage); + vi.spyOn(storage, "getStore").mockImplementation(() => { + const ctx = realGetStore(); + return !ctx || Object.keys(ctx).length === 0 ? { node: TEST_NODE_ID } : ctx; + }); + }); + + afterAll(() => { + vi.restoreAllMocks(); + }); + + beforeEach(() => { + Factory.clearFactories(); + }); + + test("Migrates V0 user scope to authorization role assignments on node start", async () => { + await ContextIdStore.run({ node: TEST_NODE_ID }, async () => { + const PORT_1 = 31000 + Math.floor(Math.random() * 200); + const PORT_2 = PORT_1 + 300; + + const AUTH_ENV: { [id: string]: string } = { + ...BASE_ENV, + TWIN_AUTH_ADMIN_PROCESSOR_TYPE: AuthenticationAdminComponentType.EntityStorage, + TWIN_AUTHORIZATION_CONNECTOR: AuthorizationConnectorType.EntityStorage + }; + + // Run 1: initialise schema-version records. After startup, back-date + // AuthenticationUser to v0 and seed V0 users that carry a scope field. + const run1 = await run({ + localesDirectory: LOCALES_DIR, + stateStorage: new MemoryStateStorage(false, { + nodeId: TEST_NODE_ID, + nodeOrganizationId: TEST_NODE_ORG_ID + }), + disableProcessExitOnFailure: true, + envVars: { ...AUTH_ENV, TWIN_PORT: String(PORT_1) }, + extendConfig: async (unusedEnvVars, config) => { + config.types.schemaVersionMigrationComponent = [ + { type: SchemaVersionMigrationComponentType.Service } + ]; + config.types.backgroundTaskComponent = [{ type: BackgroundTaskComponentType.Service }]; + } + }); + + // Back-date the AuthenticationUser schema-version record to v0 so run 2 + // detects it as needing migration. + const svConnector = + EntityStorageConnectorFactory.get< + MemoryEntityStorageConnector<{ schemaName: string; version: number }> + >("schema-version"); + const svRecords = await svConnector.getStore(); + const svRecord = svRecords.find(r => r.schemaName === "AuthenticationUser"); + if (svRecord) { + await svConnector.set({ ...svRecord, version: 0 }); + } + + // Seed two V0 users with comma-separated scope fields. The V0 schema is used + // so schema validation does not strip the scope property. + // partitionContextIds must match the engine-created connector (["node"] in single-tenant). + const seedConnector = new MemoryEntityStorageConnector<{ + email: string; + password: string; + salt: string; + identity: string; + organization: string; + scope: string; + }>({ + entitySchema: "AuthenticationUserV0", + partitionContextIds: ["node"], + config: { storageKey: "authentication-user" } + }); + await seedConnector.setBatch([ + { + email: "user1@test.com", + password: "hashed1", + salt: "salt1", + identity: "did:twin:user1", + organization: TEST_NODE_ORG_ID, + scope: "global-admin,user-admin" + }, + { + email: "user2@test.com", + password: "hashed2", + salt: "salt2", + identity: "did:twin:user2", + organization: TEST_NODE_ORG_ID, + scope: "tenant-admin" + }, + { + email: "user3@test.com", + password: "hashed3", + salt: "salt3", + identity: "did:twin:user3", + organization: TEST_NODE_ORG_ID, + scope: "" + } + ]); + + await run1?.shutdown(); + + // Run 2: restart. SchemaVersionService detects AuthenticationUser v0 → v1. + // The removeEntityProperty handler splits scope into roles and writes them to + // SharedStore["migrationUserRoles"]. AuthorizationService.start() then consumes + // that store and calls addRoleForSubject for each entry. + let run2; + try { + run2 = await run({ + localesDirectory: LOCALES_DIR, + stateStorage: new MemoryStateStorage(false, { + nodeId: TEST_NODE_ID, + nodeOrganizationId: TEST_NODE_ORG_ID + }), + disableProcessExitOnFailure: true, + envVars: { ...AUTH_ENV, TWIN_PORT: String(PORT_2) }, + extendConfig: async (unusedEnvVars2, config) => { + config.types.schemaVersionMigrationComponent = [ + { type: SchemaVersionMigrationComponentType.Service } + ]; + config.types.backgroundTaskComponent = [{ type: BackgroundTaskComponentType.Service }]; + } + }); + + // AuthenticationUser schema version must have advanced to 1. + const versionConnector = EntityStorageConnectorFactory.get("schema-version"); + const { entities: versionRecords } = await versionConnector.query(); + const migrationRecord = (versionRecords ?? []).find( + r => (r as { schemaName: string }).schemaName === "AuthenticationUser" + ) as { version: number } | undefined; + expect(migrationRecord?.version).toBe(1); + + // Migrated users must not carry the scope field. + const userConnector = EntityStorageConnectorFactory.get("authentication-user"); + const { entities: users } = await userConnector.query(); + expect(users).toHaveLength(3); + for (const user of users ?? []) { + expect((user as { scope?: unknown }).scope).toBeUndefined(); + } + + // Authorization role assignments must have been created for every scope entry. + // user1: "global-admin,user-admin" → 2 assignments + // user2: "tenant-admin" → 1 assignment + // user3: "" (empty scope) → falls back to "user" → 1 assignment + const roleConnector = EntityStorageConnectorFactory.get("authorization-role-assignment"); + const { entities: assignments } = await roleConnector.query(); + const rows = (assignments ?? []) as { + id: string; + modelId: string; + subject: string; + role: string; + }[]; + + const findAssignment = ( + identity: string, + role: string + ): { id: string; modelId: string; subject: string; role: string } | undefined => + rows.find(r => r.subject === identity && r.role === role); + + expect(rows).toHaveLength(4); + expect(findAssignment("did:twin:user1", "global-admin")).toBeDefined(); + expect(findAssignment("did:twin:user1", "user-admin")).toBeDefined(); + expect(findAssignment("did:twin:user2", "tenant-admin")).toBeDefined(); + expect(findAssignment("did:twin:user3", "user")).toBeDefined(); + + // All assignments must use the default migration model ID. + expect(rows.every(r => r.modelId === "rest")).toBe(true); + } finally { + await run2?.shutdown(); + } + }); + }); +}); + +describe("migration - scope to roles multi-tenant", () => { + beforeAll(async () => { + const storage = await ContextIdStore.getStorage(); + const realGetStore = storage.getStore.bind(storage); + vi.spyOn(storage, "getStore").mockImplementation(() => { + const ctx = realGetStore(); + return !ctx || Object.keys(ctx).length === 0 + ? { node: TEST_NODE_ID, tenant: TEST_TENANT_ID_A } + : ctx; + }); + }); + + afterAll(() => { + vi.restoreAllMocks(); + }); + + beforeEach(() => { + Factory.clearFactories(); + }); + + test("Migrates V0 user scope to role assignments isolated by tenant partition", async () => { + const PORT_1 = 31600 + Math.floor(Math.random() * 200); + const PORT_2 = PORT_1 + 300; + + const AUTH_MT_ENV: { [id: string]: string } = { + ...MULTI_TENANT_BASE_ENV, + TWIN_AUTH_ADMIN_PROCESSOR_TYPE: AuthenticationAdminComponentType.EntityStorage, + TWIN_AUTHORIZATION_CONNECTOR: AuthorizationConnectorType.EntityStorage + }; + + // Run 1: initialise schema-version records then back-date AuthenticationUser to v0. + const run1 = await run({ + localesDirectory: LOCALES_DIR, + stateStorage: new MemoryStateStorage(false, { + nodeId: TEST_NODE_ID, + nodeOrganizationId: TEST_NODE_ORG_ID + }), + disableProcessExitOnFailure: true, + envVars: { ...AUTH_MT_ENV, TWIN_PORT: String(PORT_1) }, + extendConfig: async (unusedEnvVars, config) => { + config.types.schemaVersionMigrationComponent = [ + { type: SchemaVersionMigrationComponentType.Service } + ]; + config.types.backgroundTaskComponent = [{ type: BackgroundTaskComponentType.Service }]; + } + }); + + const svConnector = + EntityStorageConnectorFactory.get< + MemoryEntityStorageConnector<{ schemaName: string; version: number }> + >("schema-version"); + const svRecords = await svConnector.getStore(); + const svRecord = svRecords.find(r => r.schemaName === "AuthenticationUser"); + if (svRecord) { + await svConnector.set({ ...svRecord, version: 0 }); + } + + // Seed one user per tenant using its own partition context so the migration + // handler captures the correct contextIds for each and replays them into the + // right authorization partition. + await ContextIdStore.run({ node: TEST_NODE_ID, tenant: TEST_TENANT_ID_A }, async () => { + const seedA = new MemoryEntityStorageConnector<{ + email: string; + password: string; + salt: string; + identity: string; + organization: string; + scope: string; + }>({ + entitySchema: "AuthenticationUserV0", + partitionContextIds: ["node", "tenant"], + config: { storageKey: "authentication-user" } + }); + await seedA.setBatch([ + { + email: "userA@test.com", + password: "hashedA", + salt: "saltA", + identity: "did:twin:userA", + organization: TEST_NODE_ORG_ID, + scope: "global-admin" + } + ]); + }); + + await ContextIdStore.run({ node: TEST_NODE_ID, tenant: TEST_TENANT_ID_B }, async () => { + const seedB = new MemoryEntityStorageConnector<{ + email: string; + password: string; + salt: string; + identity: string; + organization: string; + scope: string; + }>({ + entitySchema: "AuthenticationUserV0", + partitionContextIds: ["node", "tenant"], + config: { storageKey: "authentication-user" } + }); + await seedB.setBatch([ + { + email: "userB@test.com", + password: "hashedB", + salt: "saltB", + identity: "did:twin:userB", + organization: TEST_NODE_ORG_ID, + scope: "tenant-admin" + } + ]); + }); + + await run1?.shutdown(); + + // Run 2: restart. Migration runs once per tenant partition. The contextIds captured + // during each partition's removeEntityProperty call include the tenant ID, so + // AuthorizationService.start() writes each role assignment into the correct partition. + let run2; + try { + run2 = await run({ + localesDirectory: LOCALES_DIR, + stateStorage: new MemoryStateStorage(false, { + nodeId: TEST_NODE_ID, + nodeOrganizationId: TEST_NODE_ORG_ID + }), + disableProcessExitOnFailure: true, + envVars: { ...AUTH_MT_ENV, TWIN_PORT: String(PORT_2) }, + extendConfig: async (unusedEnvVars2, config) => { + config.types.schemaVersionMigrationComponent = [ + { type: SchemaVersionMigrationComponentType.Service } + ]; + config.types.backgroundTaskComponent = [{ type: BackgroundTaskComponentType.Service }]; + } + }); + + // Schema version must have advanced to 1. + const versionConnector = EntityStorageConnectorFactory.get("schema-version"); + const { entities: versionRecords } = await versionConnector.query(); + const migrationRecord = (versionRecords ?? []).find( + r => (r as { schemaName: string }).schemaName === "AuthenticationUser" + ) as { version: number } | undefined; + expect(migrationRecord?.version).toBe(1); + + // Tenant A: user must have global-admin role, isolated to tenant A's partition. + const roleConnector = EntityStorageConnectorFactory.get("authorization-role-assignment"); + const { entities: assignmentsA } = await ContextIdStore.run( + { node: TEST_NODE_ID, tenant: TEST_TENANT_ID_A }, + async () => roleConnector.query() + ); + const rowsA = (assignmentsA ?? []) as { + id: string; + modelId: string; + subject: string; + role: string; + }[]; + expect(rowsA).toHaveLength(1); + expect(rowsA[0].subject).toBe("did:twin:userA"); + expect(rowsA[0].role).toBe("global-admin"); + expect(rowsA[0].modelId).toBe("rest"); + + // Tenant B: user must have tenant-admin role, isolated to tenant B's partition. + const { entities: assignmentsB } = await ContextIdStore.run( + { node: TEST_NODE_ID, tenant: TEST_TENANT_ID_B }, + async () => roleConnector.query() + ); + const rowsB = (assignmentsB ?? []) as { + id: string; + modelId: string; + subject: string; + role: string; + }[]; + expect(rowsB).toHaveLength(1); + expect(rowsB[0].subject).toBe("did:twin:userB"); + expect(rowsB[0].role).toBe("tenant-admin"); + expect(rowsB[0].modelId).toBe("rest"); + } finally { + await run2?.shutdown(); + } + }); +}); From 793dbe51cceb8085fb199b803723a9c75b304679 Mon Sep 17 00:00:00 2001 From: Martyn Janes Date: Wed, 26 Aug 2026 16:33:27 +0800 Subject: [PATCH 04/17] feat: authorization model initialization --- apps/node/.env.example-aws-ec2 | 9 +- apps/node/.env.example-federated-catalogue | 9 +- apps/node/.env.example-iota-testnet | 9 +- apps/node/.env.example-local-entity-storage | 9 +- .../defaults/defaultAuthorizationRules.json | 72 ----- docs/architecture/node-env-variables.mdx | 111 +++---- packages/node-core/locales/en.json | 4 +- .../builders/helper/authorizationSeeder.ts | 117 ++++++++ .../node-core/src/commands/bootstrapDev.ts | 61 ---- packages/node-core/src/commands/userCreate.ts | 34 +-- packages/node-core/src/commands/userUpdate.ts | 8 +- packages/node-core/src/defaults.ts | 5 + .../src/models/IEngineEnvironmentVariables.ts | 16 + .../models/engineEnvironmentVariableKeys.ts | 2 + packages/node-core/src/start.ts | 3 + .../tests/authorizationSeeder.spec.ts | 281 ++++++++++++++++++ .../tests/builders/helper/envHelpers.spec.ts | 27 +- packages/node-core/tests/index.spec.ts | 1 + 18 files changed, 525 insertions(+), 253 deletions(-) delete mode 100644 apps/node/defaults/defaultAuthorizationRules.json create mode 100644 packages/node-core/src/builders/helper/authorizationSeeder.ts create mode 100644 packages/node-core/tests/authorizationSeeder.spec.ts diff --git a/apps/node/.env.example-aws-ec2 b/apps/node/.env.example-aws-ec2 index bf033394..ad293c71 100644 --- a/apps/node/.env.example-aws-ec2 +++ b/apps/node/.env.example-aws-ec2 @@ -313,7 +313,7 @@ TWIN_TELEMETRY_CONNECTOR="entity-storage" # Authorization Connector ## Authorization Connector [entity-storage, casbin] -# TWIN_AUTHORIZATION_CONNECTOR="entity-storage" +TWIN_AUTHORIZATION_CONNECTOR="entity-storage" ## Maximum number of cached authorisation check results. # TWIN_AUTHORIZATION_CHECK_CACHE_CAPACITY="" @@ -321,8 +321,11 @@ TWIN_TELEMETRY_CONNECTOR="entity-storage" ## Time-to-idle in milliseconds for cached authorisation check results. # TWIN_AUTHORIZATION_CHECK_CACHE_TTI_MS="" -## Default policy rules to seed the authorisation service, as a path to a JSON file. -# TWIN_AUTHORIZATION_DEFAULT_RULES="@json:authorization-rules.json" +## Path to a JSON file containing the authorization model (policies and roleInheritances) to seed at startup. +# TWIN_AUTHORIZATION_MODEL="@json:authorization-model.json" + +## How to combine the authorization model with route-derived policies: merge (default) or replace. +# TWIN_AUTHORIZATION_MODEL_MODE="merge" # Casbin runtime settings, used when TWIN_AUTHORIZATION_CONNECTOR="casbin". # TWIN_CASBIN_ENDPOINT="" diff --git a/apps/node/.env.example-federated-catalogue b/apps/node/.env.example-federated-catalogue index 55eef71e..65bf99ec 100644 --- a/apps/node/.env.example-federated-catalogue +++ b/apps/node/.env.example-federated-catalogue @@ -335,7 +335,7 @@ TWIN_TELEMETRY_CONNECTOR="entity-storage" # Authorization Connector ## Authorization Connector [entity-storage, casbin] -# TWIN_AUTHORIZATION_CONNECTOR="entity-storage" +TWIN_AUTHORIZATION_CONNECTOR="entity-storage" ## Maximum number of cached authorisation check results. # TWIN_AUTHORIZATION_CHECK_CACHE_CAPACITY="" @@ -343,8 +343,11 @@ TWIN_TELEMETRY_CONNECTOR="entity-storage" ## Time-to-idle in milliseconds for cached authorisation check results. # TWIN_AUTHORIZATION_CHECK_CACHE_TTI_MS="" -## Default policy rules to seed the authorisation service, as a path to a JSON file. -# TWIN_AUTHORIZATION_DEFAULT_RULES="@json:authorization-rules.json" +## Path to a JSON file containing the authorization model (policies and roleInheritances) to seed at startup. +# TWIN_AUTHORIZATION_MODEL="@json:authorization-model.json" + +## How to combine the authorization model with route-derived policies: merge (default) or replace. +# TWIN_AUTHORIZATION_MODEL_MODE="merge" # Casbin runtime settings, used when TWIN_AUTHORIZATION_CONNECTOR="casbin". # TWIN_CASBIN_ENDPOINT="" diff --git a/apps/node/.env.example-iota-testnet b/apps/node/.env.example-iota-testnet index e89ae9c6..0c0d9ff3 100644 --- a/apps/node/.env.example-iota-testnet +++ b/apps/node/.env.example-iota-testnet @@ -315,7 +315,7 @@ TWIN_TELEMETRY_CONNECTOR="entity-storage" # Authorization Connector ## Authorization Connector [entity-storage, casbin] -# TWIN_AUTHORIZATION_CONNECTOR="entity-storage" +TWIN_AUTHORIZATION_CONNECTOR="entity-storage" ## Maximum number of cached authorisation check results. # TWIN_AUTHORIZATION_CHECK_CACHE_CAPACITY="" @@ -323,8 +323,11 @@ TWIN_TELEMETRY_CONNECTOR="entity-storage" ## Time-to-idle in milliseconds for cached authorisation check results. # TWIN_AUTHORIZATION_CHECK_CACHE_TTI_MS="" -## Default policy rules to seed the authorisation service, as a path to a JSON file. -# TWIN_AUTHORIZATION_DEFAULT_RULES="@json:authorization-rules.json" +## Path to a JSON file containing the authorization model (policies and roleInheritances) to seed at startup. +# TWIN_AUTHORIZATION_MODEL="@json:authorization-model.json" + +## How to combine the authorization model with route-derived policies: merge (default) or replace. +# TWIN_AUTHORIZATION_MODEL_MODE="merge" # Casbin runtime settings, used when TWIN_AUTHORIZATION_CONNECTOR="casbin". # TWIN_CASBIN_ENDPOINT="" diff --git a/apps/node/.env.example-local-entity-storage b/apps/node/.env.example-local-entity-storage index e3b8bcdc..b2c2b3c6 100644 --- a/apps/node/.env.example-local-entity-storage +++ b/apps/node/.env.example-local-entity-storage @@ -313,7 +313,7 @@ TWIN_TELEMETRY_CONNECTOR="entity-storage" # Authorization Connector ## Authorization Connector [entity-storage, casbin] -# TWIN_AUTHORIZATION_CONNECTOR="entity-storage" +TWIN_AUTHORIZATION_CONNECTOR="entity-storage" ## Maximum number of cached authorisation check results. # TWIN_AUTHORIZATION_CHECK_CACHE_CAPACITY="" @@ -321,8 +321,11 @@ TWIN_TELEMETRY_CONNECTOR="entity-storage" ## Time-to-idle in milliseconds for cached authorisation check results. # TWIN_AUTHORIZATION_CHECK_CACHE_TTI_MS="" -## Default policy rules to seed the authorisation service, as a path to a JSON file. -# TWIN_AUTHORIZATION_DEFAULT_RULES="@json:authorization-rules.json" +## Path to a JSON file containing the authorization model (policies and roleInheritances) to seed at startup. +# TWIN_AUTHORIZATION_MODEL="@json:authorization-model.json" + +## How to combine the authorization model with route-derived policies: merge (default) or replace. +# TWIN_AUTHORIZATION_MODEL_MODE="merge" # Casbin runtime settings, used when TWIN_AUTHORIZATION_CONNECTOR="casbin". # TWIN_CASBIN_ENDPOINT="" diff --git a/apps/node/defaults/defaultAuthorizationRules.json b/apps/node/defaults/defaultAuthorizationRules.json deleted file mode 100644 index 0a213100..00000000 --- a/apps/node/defaults/defaultAuthorizationRules.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "policies": [ - { - "subject": "order-viewer", - "object": "readOrder", - "action": "execute" - }, - { - "subject": "user-viewer", - "object": "readUser", - "action": "execute" - }, - { - "subject": "order-admin", - "object": "createOrder", - "action": "execute" - }, - { - "subject": "order-admin", - "object": "updateOrder", - "action": "execute" - }, - { - "subject": "order-admin", - "object": "deleteOrder", - "action": "execute" - }, - { - "subject": "user-admin", - "object": "createUser", - "action": "execute" - }, - { - "subject": "user-admin", - "object": "updateUser", - "action": "execute" - }, - { - "subject": "user-admin", - "object": "deleteUser", - "action": "execute" - } - ], - "roleAssignments": [ - { - "subject": "Admin1234", - "role": "order-admin" - }, - { - "subject": "Admin1234", - "role": "user-admin" - }, - { - "subject": "User5678", - "role": "user-viewer" - }, - { - "subject": "User1357", - "role": "order-viewer" - } - ], - "roleInheritances": [ - { - "role": "order-admin", - "inheritsFrom": "order-viewer" - }, - { - "role": "user-admin", - "inheritsFrom": "user-viewer" - } - ] -} diff --git a/docs/architecture/node-env-variables.mdx b/docs/architecture/node-env-variables.mdx index ecb670ae..8ab2981c 100644 --- a/docs/architecture/node-env-variables.mdx +++ b/docs/architecture/node-env-variables.mdx @@ -68,61 +68,62 @@ These variables are only read when running the `bootstrap-dev` CLI command. They ## Connector and Component Selection Variables -| Variable | Possible Values | Default | Notes | -| ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------- | --------------------- | --------------------------------------------------------------------------------------------------------------------------- | -| `TWIN_ENTITY_STORAGE_CONNECTOR_TYPE` | `file`, `memory`, `aws-dynamodb`, `azure-cosmosdb`, `gcp-firestoredb`, `scylladb`, `mysql`, `mongodb`, `postgresql` | None | Comma-separated list allowed. | -| `TWIN_ENTITY_STORAGE_CONNECTOR_DEFAULT` | Any configured entity storage type | First configured type | Default entity storage connector. | -| `TWIN_BLOB_STORAGE_CONNECTOR_TYPE` | `memory`, `file`, `ipfs`, `aws-s3`, `azure-storage`, `gcp-storage` | None | Comma-separated list allowed. | -| `TWIN_BLOB_STORAGE_CONNECTOR_DEFAULT` | Any configured blob storage type | First configured type | Default blob storage connector. | -| `TWIN_VAULT_CONNECTOR` | `entity-storage`, `hashicorp` | None | Selects vault backend. | -| `TWIN_LOGGING_CONNECTOR` | `console`, `entity-storage`, `otel`, `file` | None | Comma-separated list allowed. | -| `TWIN_LOGGING_BATCH_SIZE` | Integer | None | Logging batch size. Set to `1` to disable batching. | -| `TWIN_LOGGING_SILENT_COMPONENTS` | Comma-separated list of component class names | None | A list of components to exclude from logging. | -| `TWIN_LOGGING_BATCH_FLUSH_INTERVAL` | Integer seconds | `5` | Logging batch flush interval. | -| `TWIN_LOGGING_RETAIN_FOR` | Integer minutes | `2880` | Age-based retention window for `entity-storage` logging. Set to `0` to disable age-based retention. | -| `TWIN_LOGGING_MAX_ENTRIES` | Integer | `10000` | Count-based retention limit for `entity-storage` logging. Set to `0` to disable count-based retention. | -| `TWIN_LOGGING_RETENTION_INTERVAL` | Integer minutes | `5` | How often retention cleanup runs for `entity-storage` logging. Set to `0` to disable periodic cleanup. | -| `TWIN_LOGGING_RETENTION_BATCH_SIZE` | Integer | `1000` | Maximum entries deleted per retention cleanup batch for `entity-storage` logging. | -| `TWIN_LOGGING_FILE_DIRECTORY` | Directory path | None | Directory to write log files into. Required when `TWIN_LOGGING_CONNECTOR` includes `file`. | -| `TWIN_LOGGING_FILE_FILENAME` | String | `app.log` | Log filename. Only used when `TWIN_LOGGING_CONNECTOR` includes `file`. | -| `TWIN_LOGGING_FILE_MAX_FILE_SIZE_BYTES` | Integer bytes | `10485760` | Max log file size before rotation. Set to `0` to disable rotation. Only used when `TWIN_LOGGING_CONNECTOR` includes `file`. | -| `TWIN_LOGGING_FILE_MAX_RETAINED_FILES` | Integer | `5` | Number of rotated log files to retain. Set to `0` to keep all. Only used when `TWIN_LOGGING_CONNECTOR` includes `file`. | -| `TWIN_EVENT_BUS_CONNECTOR` | `local` | None | Selects event bus connector. | -| `TWIN_EVENT_BUS_COMPONENT` | `service` | None | Selects event bus component implementation. | -| `TWIN_MESSAGING_EMAIL_CONNECTOR` | `entity-storage`, `aws` | None | Messaging email connector type. | -| `TWIN_MESSAGING_SMS_CONNECTOR` | `entity-storage`, `aws` | None | Messaging SMS connector type. | -| `TWIN_MESSAGING_PUSH_NOTIFICATION_CONNECTOR` | `entity-storage`, `aws` | None | Messaging push connector type. | -| `TWIN_TELEMETRY_CONNECTOR` | `entity-storage`, `open-telemetry`, `silent` (comma-separated for multiple) | None | Telemetry connector type. When multiple values are provided, a multi-connector is created automatically as the default. | -| `TWIN_TELEMETRY_METRICS_PRODUCERS` | `system`, `process` (comma-separated) | `system,process` | Metrics producer types to enable. | -| `TWIN_TELEMETRY_SILENT_COMPONENTS` | Comma-separated list of component class names | None | A list of components to exclude from telemetry. | -| `TWIN_TRACING_CONNECTOR` | `entity-storage`, `open-telemetry`, `silent` (comma-separated for multiple) | None | Tracing connector type. When multiple values are provided, a multi-connector is created automatically as the default. | -| `TWIN_TRACING_SILENT_COMPONENTS` | Comma-separated list of component class names | None | A list of components to exclude from tracing. | -| `TWIN_AUTHORIZATION_CONNECTOR` | `entity-storage`, `casbin` | None | Authorization connector type. | -| `TWIN_AUTHORIZATION_CHECK_CACHE_CAPACITY` | Integer | None | Maximum number of cached authorisation check results. | -| `TWIN_AUTHORIZATION_CHECK_CACHE_TTI_MS` | Integer | None | Time-to-idle in milliseconds for cached authorisation check results. | -| `TWIN_AUTHORIZATION_DEFAULT_RULES` | JSON array or `@json:` | None | Default policy rules to seed the authorisation service. Use `@json:authorization-rules.json` to load from a file. | -| `TWIN_FAUCET_CONNECTOR` | `entity-storage`, `iota` | None | Faucet connector type. | -| `TWIN_WALLET_CONNECTOR` | `entity-storage`, `iota` | None | Wallet connector type. | -| `TWIN_NFT_CONNECTOR` | `entity-storage`, `iota` | None | NFT connector type. | -| `TWIN_NFT_PACKAGE_ID` | String | None | Custom deployed package id for the NFT contract. | -| `TWIN_NOTARIZATION_CONNECTOR` | `entity-storage`, `iota` | None | Notarization connector type. | -| `TWIN_IDENTITY_CONNECTOR` | `entity-storage`, `iota` | None | Identity connector type. | -| `TWIN_IDENTITY_RESOLVER_CONNECTOR` | `entity-storage`, `iota`, `universal` | None | Identity resolver connector type. | -| `TWIN_IDENTITY_PROFILE_CONNECTOR` | `entity-storage` | None | Identity profile connector type. | -| `TWIN_ATTESTATION_CONNECTOR` | `nft` | None | Attestation connector type. | -| `TWIN_DATA_CONVERTER_CONNECTORS` | `json`, `xml` | None | Comma-separated list allowed. | -| `TWIN_DATA_EXTRACTOR_CONNECTORS` | `json-path` | None | Comma-separated list allowed. | -| `TWIN_AUTOMATION_ACTION_TYPES` | `fetch` | None | Automation action types to register. | -| `TWIN_FEDERATED_CATALOGUE_FILTERS` | `filter-by-metadata` | None | Federated catalogue filters. | -| `TWIN_TRUST_GENERATORS` | `jwt-verifiable-credential` | None | Trust generator registrations. | -| `TWIN_TRUST_VERIFIERS` | `jwt-verifiable-credential` | None | Trust verifier registrations. | -| `TWIN_RIGHTS_MANAGEMENT_POLICY_ARBITERS` | `pass-through`, `default` | None | Rights policy arbiter registrations. | -| `TWIN_RIGHTS_MANAGEMENT_POLICY_ENFORCEMENT_PROCESSORS` | `pass-through`, `default` | None | Rights policy enforcement processor registrations. | -| `TWIN_RIGHTS_MANAGEMENT_POLICY_EXECUTION_ACTIONS` | `logging` | None | Rights policy execution action registrations. | -| `TWIN_RIGHTS_MANAGEMENT_POLICY_INFORMATION_SOURCES` | `identity`, `static`, `identity-profile` | None | Rights policy information source registrations. | -| `TWIN_RIGHTS_MANAGEMENT_POLICY_NEGOTIATORS` | `pass-through` | None | Rights policy negotiator registrations. | -| `TWIN_RIGHTS_MANAGEMENT_POLICY_OBLIGATION_ENFORCERS` | `pass-through` | None | Rights policy obligation enforcer registrations. | -| `TWIN_RIGHTS_MANAGEMENT_POLICY_REQUESTERS` | `pass-through` | None | Rights policy requester registrations. | +| Variable | Possible Values | Default | Notes | +| ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | +| `TWIN_ENTITY_STORAGE_CONNECTOR_TYPE` | `file`, `memory`, `aws-dynamodb`, `azure-cosmosdb`, `gcp-firestoredb`, `scylladb`, `mysql`, `mongodb`, `postgresql` | None | Comma-separated list allowed. | +| `TWIN_ENTITY_STORAGE_CONNECTOR_DEFAULT` | Any configured entity storage type | First configured type | Default entity storage connector. | +| `TWIN_BLOB_STORAGE_CONNECTOR_TYPE` | `memory`, `file`, `ipfs`, `aws-s3`, `azure-storage`, `gcp-storage` | None | Comma-separated list allowed. | +| `TWIN_BLOB_STORAGE_CONNECTOR_DEFAULT` | Any configured blob storage type | First configured type | Default blob storage connector. | +| `TWIN_VAULT_CONNECTOR` | `entity-storage`, `hashicorp` | None | Selects vault backend. | +| `TWIN_LOGGING_CONNECTOR` | `console`, `entity-storage`, `otel`, `file` | None | Comma-separated list allowed. | +| `TWIN_LOGGING_BATCH_SIZE` | Integer | None | Logging batch size. Set to `1` to disable batching. | +| `TWIN_LOGGING_SILENT_COMPONENTS` | Comma-separated list of component class names | None | A list of components to exclude from logging. | +| `TWIN_LOGGING_BATCH_FLUSH_INTERVAL` | Integer seconds | `5` | Logging batch flush interval. | +| `TWIN_LOGGING_RETAIN_FOR` | Integer minutes | `2880` | Age-based retention window for `entity-storage` logging. Set to `0` to disable age-based retention. | +| `TWIN_LOGGING_MAX_ENTRIES` | Integer | `10000` | Count-based retention limit for `entity-storage` logging. Set to `0` to disable count-based retention. | +| `TWIN_LOGGING_RETENTION_INTERVAL` | Integer minutes | `5` | How often retention cleanup runs for `entity-storage` logging. Set to `0` to disable periodic cleanup. | +| `TWIN_LOGGING_RETENTION_BATCH_SIZE` | Integer | `1000` | Maximum entries deleted per retention cleanup batch for `entity-storage` logging. | +| `TWIN_LOGGING_FILE_DIRECTORY` | Directory path | None | Directory to write log files into. Required when `TWIN_LOGGING_CONNECTOR` includes `file`. | +| `TWIN_LOGGING_FILE_FILENAME` | String | `app.log` | Log filename. Only used when `TWIN_LOGGING_CONNECTOR` includes `file`. | +| `TWIN_LOGGING_FILE_MAX_FILE_SIZE_BYTES` | Integer bytes | `10485760` | Max log file size before rotation. Set to `0` to disable rotation. Only used when `TWIN_LOGGING_CONNECTOR` includes `file`. | +| `TWIN_LOGGING_FILE_MAX_RETAINED_FILES` | Integer | `5` | Number of rotated log files to retain. Set to `0` to keep all. Only used when `TWIN_LOGGING_CONNECTOR` includes `file`. | +| `TWIN_EVENT_BUS_CONNECTOR` | `local` | None | Selects event bus connector. | +| `TWIN_EVENT_BUS_COMPONENT` | `service` | None | Selects event bus component implementation. | +| `TWIN_MESSAGING_EMAIL_CONNECTOR` | `entity-storage`, `aws` | None | Messaging email connector type. | +| `TWIN_MESSAGING_SMS_CONNECTOR` | `entity-storage`, `aws` | None | Messaging SMS connector type. | +| `TWIN_MESSAGING_PUSH_NOTIFICATION_CONNECTOR` | `entity-storage`, `aws` | None | Messaging push connector type. | +| `TWIN_TELEMETRY_CONNECTOR` | `entity-storage`, `open-telemetry`, `silent` (comma-separated for multiple) | None | Telemetry connector type. When multiple values are provided, a multi-connector is created automatically as the default. | +| `TWIN_TELEMETRY_METRICS_PRODUCERS` | `system`, `process` (comma-separated) | `system,process` | Metrics producer types to enable. | +| `TWIN_TELEMETRY_SILENT_COMPONENTS` | Comma-separated list of component class names | None | A list of components to exclude from telemetry. | +| `TWIN_TRACING_CONNECTOR` | `entity-storage`, `open-telemetry`, `silent` (comma-separated for multiple) | None | Tracing connector type. When multiple values are provided, a multi-connector is created automatically as the default. | +| `TWIN_TRACING_SILENT_COMPONENTS` | Comma-separated list of component class names | None | A list of components to exclude from tracing. | +| `TWIN_AUTHORIZATION_CONNECTOR` | `entity-storage`, `casbin` | None | Authorization connector type. | +| `TWIN_AUTHORIZATION_CHECK_CACHE_CAPACITY` | Integer | None | Maximum number of cached authorisation check results. | +| `TWIN_AUTHORIZATION_CHECK_CACHE_TTI_MS` | Integer | None | Time-to-idle in milliseconds for cached authorisation check results. | +| `TWIN_AUTHORIZATION_MODEL` | `@json:` | None | Path to a JSON file containing the authorization model to seed at startup, with `policies` and `roleInheritances` arrays. | +| `TWIN_AUTHORIZATION_MODEL_MODE` | `merge`, `replace` | `merge` | How to combine `TWIN_AUTHORIZATION_MODEL` with route-derived policies. `merge` applies both; `replace` uses only the custom model. | +| `TWIN_FAUCET_CONNECTOR` | `entity-storage`, `iota` | None | Faucet connector type. | +| `TWIN_WALLET_CONNECTOR` | `entity-storage`, `iota` | None | Wallet connector type. | +| `TWIN_NFT_CONNECTOR` | `entity-storage`, `iota` | None | NFT connector type. | +| `TWIN_NFT_PACKAGE_ID` | String | None | Custom deployed package id for the NFT contract. | +| `TWIN_NOTARIZATION_CONNECTOR` | `entity-storage`, `iota` | None | Notarization connector type. | +| `TWIN_IDENTITY_CONNECTOR` | `entity-storage`, `iota` | None | Identity connector type. | +| `TWIN_IDENTITY_RESOLVER_CONNECTOR` | `entity-storage`, `iota`, `universal` | None | Identity resolver connector type. | +| `TWIN_IDENTITY_PROFILE_CONNECTOR` | `entity-storage` | None | Identity profile connector type. | +| `TWIN_ATTESTATION_CONNECTOR` | `nft` | None | Attestation connector type. | +| `TWIN_DATA_CONVERTER_CONNECTORS` | `json`, `xml` | None | Comma-separated list allowed. | +| `TWIN_DATA_EXTRACTOR_CONNECTORS` | `json-path` | None | Comma-separated list allowed. | +| `TWIN_AUTOMATION_ACTION_TYPES` | `fetch` | None | Automation action types to register. | +| `TWIN_FEDERATED_CATALOGUE_FILTERS` | `filter-by-metadata` | None | Federated catalogue filters. | +| `TWIN_TRUST_GENERATORS` | `jwt-verifiable-credential` | None | Trust generator registrations. | +| `TWIN_TRUST_VERIFIERS` | `jwt-verifiable-credential` | None | Trust verifier registrations. | +| `TWIN_RIGHTS_MANAGEMENT_POLICY_ARBITERS` | `pass-through`, `default` | None | Rights policy arbiter registrations. | +| `TWIN_RIGHTS_MANAGEMENT_POLICY_ENFORCEMENT_PROCESSORS` | `pass-through`, `default` | None | Rights policy enforcement processor registrations. | +| `TWIN_RIGHTS_MANAGEMENT_POLICY_EXECUTION_ACTIONS` | `logging` | None | Rights policy execution action registrations. | +| `TWIN_RIGHTS_MANAGEMENT_POLICY_INFORMATION_SOURCES` | `identity`, `static`, `identity-profile` | None | Rights policy information source registrations. | +| `TWIN_RIGHTS_MANAGEMENT_POLICY_NEGOTIATORS` | `pass-through` | None | Rights policy negotiator registrations. | +| `TWIN_RIGHTS_MANAGEMENT_POLICY_OBLIGATION_ENFORCERS` | `pass-through` | None | Rights policy obligation enforcer registrations. | +| `TWIN_RIGHTS_MANAGEMENT_POLICY_REQUESTERS` | `pass-through` | None | Rights policy requester registrations. | ## Feature Toggle and Behaviour Variables diff --git a/packages/node-core/locales/en.json b/packages/node-core/locales/en.json index cd5557a6..ffdf7209 100644 --- a/packages/node-core/locales/en.json +++ b/packages/node-core/locales/en.json @@ -49,8 +49,7 @@ "userCreate": { "passwordTooShort": "The password provided is too short, it must be at least {minLength} characters long.", "userAlreadyExists": "The user with ID already exists and overwriteMode is set to \"error\".", - "tenantIdRequired": "The tenant ID is required when multi-tenancy is enabled.", - "rolesNotFound": "The following roles were not found: {roles}" + "tenantIdRequired": "The tenant ID is required when multi-tenancy is enabled." }, "userGet": { "tenantIdRequired": "The tenant ID is required when multi-tenancy is enabled." @@ -155,7 +154,6 @@ "nodeOrganizationIdSet": "Setting node organisation ID", "adminIdentityCreate": "Creating admin user identity", "adminUserCreate": "Creating admin user", - "authorizationBootstrap": "Seeding default authorization roles", "tenantFallback": "No Node-labelled tenant found; using first available tenant" } }, diff --git a/packages/node-core/src/builders/helper/authorizationSeeder.ts b/packages/node-core/src/builders/helper/authorizationSeeder.ts new file mode 100644 index 00000000..21d443ce --- /dev/null +++ b/packages/node-core/src/builders/helper/authorizationSeeder.ts @@ -0,0 +1,117 @@ +// Copyright 2026 IOTA Stiftung. +// SPDX-License-Identifier: Apache-2.0. +import type { IPlatformComponent, IRestRoute, IRouteAuthorization } from "@twin.org/api-models"; +import type { + IAuthorizationComponent, + IAuthorizationInheritance, + IAuthorizationModel, + IAuthorizationPolicy +} from "@twin.org/authorization-models"; +import { ContextIdStore } from "@twin.org/context"; +import { ComponentFactory, Is } from "@twin.org/core"; +import type { IEngineCore } from "@twin.org/engine-models"; +import { envObject, envString } from "./envHelpers.js"; +import { AUTHORIZATION_MODEL_ID, DEFAULT_ESCALATED_PRIVILEGE_ROLE } from "../../defaults.js"; +import type { IEngineEnvironmentVariables } from "../../models/IEngineEnvironmentVariables.js"; + +/** + * Seed default authorization policies and role inheritances after the engine has started. + * Uses the platform component to execute across all tenants in multi-tenant mode. + * @param engineCore The running engine core. + * @param envVars The environment variables. + * @param routes The REST routes to derive default policies from. + */ +export async function seedAuthorizationDefaults( + engineCore: IEngineCore, + envVars: IEngineEnvironmentVariables, + routes: IRestRoute[] +): Promise { + const nodeContextIds = engineCore.getContextIds() ?? {}; + if (!Is.stringValue(nodeContextIds.node)) { + return; + } + + const authComponentType = engineCore.getRegisteredInstanceTypeOptional("authorizationComponent"); + const platformComponentType = engineCore.getRegisteredInstanceTypeOptional("platformComponent"); + + if (!Is.stringValue(authComponentType) || !Is.stringValue(platformComponentType)) { + return; + } + + const platformComponent = ComponentFactory.get(platformComponentType); + const authorizationComponent = ComponentFactory.get(authComponentType); + + const modelId = envString(envVars, "authorizationModelId", AUTHORIZATION_MODEL_ID); + const rulesMode = envVars.authorizationModelMode ?? "merge"; + + const customModel = envObject( + envVars, + "authorizationModel" + ); + + const policies: IAuthorizationPolicy[] = []; + const roleInheritances: IAuthorizationInheritance[] = []; + + if (Is.objectValue(customModel)) { + policies.push(...(customModel.policies ?? [])); + + const escalatedRoles = new Set(); + for (const inheritance of customModel.roleInheritances ?? []) { + roleInheritances.push(inheritance); + escalatedRoles.add(inheritance.role); + } + for (const role of escalatedRoles) { + roleInheritances.push({ role: DEFAULT_ESCALATED_PRIVILEGE_ROLE, inheritsFrom: role }); + } + } + + if (!Is.objectValue(customModel) || rulesMode === "merge") { + const policyKeys = new Set(); + const inheritanceKeys = new Set(); + const roles = new Set(); + + for (const route of routes) { + const auth = route.defaultAuthorization; + if (Is.objectValue(auth)) { + const policyKey = `${auth.permission}|${route.operationId}`; + if (!policyKeys.has(policyKey)) { + policyKeys.add(policyKey); + policies.push({ + subject: auth.permission, + object: route.operationId, + action: "execute" + }); + } + if (Is.stringValue(auth.role)) { + const inheritKey = `${auth.role}|${auth.permission}`; + if (!inheritanceKeys.has(inheritKey)) { + inheritanceKeys.add(inheritKey); + roleInheritances.push({ role: auth.role, inheritsFrom: auth.permission }); + } + roles.add(auth.role); + } + if (Is.arrayValue(auth.inherits)) { + for (const inheritsFrom of auth.inherits) { + const inheritKey = `${auth.permission}|${inheritsFrom}`; + if (!inheritanceKeys.has(inheritKey)) { + inheritanceKeys.add(inheritKey); + roleInheritances.push({ role: auth.permission, inheritsFrom }); + } + } + } + } + } + + for (const role of roles) { + roleInheritances.push({ role: DEFAULT_ESCALATED_PRIVILEGE_ROLE, inheritsFrom: role }); + } + } + + const model: IAuthorizationModel = { policies, roleInheritances }; + + await ContextIdStore.run(nodeContextIds, async () => { + await platformComponent.execute(async () => { + await authorizationComponent.build(modelId, model); + }); + }); +} diff --git a/packages/node-core/src/commands/bootstrapDev.ts b/packages/node-core/src/commands/bootstrapDev.ts index 41703a77..c78e2cbf 100644 --- a/packages/node-core/src/commands/bootstrapDev.ts +++ b/packages/node-core/src/commands/bootstrapDev.ts @@ -2,14 +2,12 @@ // SPDX-License-Identifier: Apache-2.0. import type { IAuthenticationAdminComponent } from "@twin.org/api-auth-entity-storage-models"; import type { ITenantAdminComponent } from "@twin.org/api-models"; -import type { IAuthorizationComponent } from "@twin.org/authorization-models"; import { CLIDisplay } from "@twin.org/cli-core"; import { ContextIdKeys, ContextIdStore } from "@twin.org/context"; import { Coerce, ComponentFactory, GeneralError, I18n, Is } from "@twin.org/core"; import type { IEngineCore } from "@twin.org/engine-models"; import { commaSeparatedListToArray } from "../builders/helper/envHelpers.js"; import { - AUTHORIZATION_MODEL_ID, DEFAULT_ESCALATED_PRIVILEGE_ROLE, DEFAULT_TENANT_ADMIN_ROLE, DEFAULT_USER_ADMIN_ROLE @@ -235,16 +233,6 @@ export async function bootstrapDev( }); } - await ContextIdStore.run( - { [ContextIdKeys.Node]: nodeId, [ContextIdKeys.Tenant]: tenant?.id }, - async () => { - await bootstrapAuthorization( - engineCore, - envVars.authorizationModelId ?? AUTHORIZATION_MODEL_ID - ); - } - ); - if (features.includes("admin-user")) { await ContextIdStore.run( { [ContextIdKeys.Node]: nodeId, [ContextIdKeys.Tenant]: tenant?.id }, @@ -298,55 +286,6 @@ export async function bootstrapDev( } } -/** - * Seed default roles into the authorization system so they can be assigned to users. - * @param engineCore The engine core. - * @param authorizationModelId The model identifier for authorization. - * @returns A promise that resolves when the default roles have been seeded. - * @internal - */ -async function bootstrapAuthorization( - engineCore: IEngineCore, - authorizationModelId: string -): Promise { - CLIDisplay.break(); - CLIDisplay.section( - I18n.formatMessage("node.cli.commands.bootstrap-dev.labels.authorizationBootstrap") - ); - - const defaultAuthorizationComponentType = - engineCore.getRegisteredInstanceType("authorizationComponent"); - const authorizationComponent = ComponentFactory.get( - defaultAuthorizationComponentType - ); - - await authorizationComponent.addPolicy( - authorizationModelId, - DEFAULT_TENANT_ADMIN_ROLE, - "tenantCreate", - "execute" - ); - await authorizationComponent.addPolicy( - authorizationModelId, - DEFAULT_USER_ADMIN_ROLE, - "authenticationAdminCreateUser", - "execute" - ); - - await authorizationComponent.addRoleInheritance( - authorizationModelId, - DEFAULT_ESCALATED_PRIVILEGE_ROLE, - DEFAULT_TENANT_ADMIN_ROLE - ); - await authorizationComponent.addRoleInheritance( - authorizationModelId, - DEFAULT_ESCALATED_PRIVILEGE_ROLE, - DEFAULT_USER_ADMIN_ROLE - ); - - CLIDisplay.done(); -} - /** * Resolve the organisation DID from node state (single-tenant) or the tenant entry (multi-tenant). * @param engineCore The engine core. diff --git a/packages/node-core/src/commands/userCreate.ts b/packages/node-core/src/commands/userCreate.ts index cba7ad60..aa1b8c01 100644 --- a/packages/node-core/src/commands/userCreate.ts +++ b/packages/node-core/src/commands/userCreate.ts @@ -12,8 +12,8 @@ import { PasswordGenerator } from "@twin.org/crypto"; import type { IEngineCore } from "@twin.org/engine-models"; import { Did, IdentityProfileConnectorFactory } from "@twin.org/identity-models"; import type { Person, WithContext } from "schema-dts"; -import { commaSeparatedListToArray } from "../builders/helper/envHelpers.js"; -import { AUTHORIZATION_MODEL_ID } from "../defaults.js"; +import { commaSeparatedListToArray, envString } from "../builders/helper/envHelpers.js"; +import { AUTHORIZATION_MODEL_ID, DEFAULT_USER_ROLE } from "../defaults.js"; import type { ICliCommandDefinition } from "../models/ICliCommandDefinition.js"; import type { IEnvironmentVariables } from "../models/IEnvironmentVariables.js"; @@ -197,7 +197,7 @@ export async function userCreate( const paramsEmail = params.email; const paramsUserIdentity = params.userIdentity; const paramsOrganizationIdentity = params.organizationIdentity; - const authorizationModelId = envVars.authorizationModelId ?? AUTHORIZATION_MODEL_ID; + const authorizationModelId = envString(envVars, "authorizationModelId", AUTHORIZATION_MODEL_ID); Guards.email("userCreate", "email", paramsEmail); Did.guard("userCreate", "user-identity", paramsUserIdentity); Did.guard("userCreate", "organization-identity", paramsOrganizationIdentity); @@ -232,6 +232,9 @@ export async function userCreate( let createUser = true; const roles = commaSeparatedListToArray(params.roles); + if (roles.length === 0) { + roles.push(DEFAULT_USER_ROLE); + } const currentContextIds = (await ContextIdStore.getContextIds()) ?? {}; const returnJson = await ContextIdStore.run( @@ -287,7 +290,6 @@ export async function userCreate( await authenticationAdminComponent.create(user); } - await verifyRoles(authorizationComponent, authorizationModelId, roles); for (const role of roles) { await authorizationComponent.addRoleForSubject( authorizationModelId, @@ -334,7 +336,7 @@ export async function userCreate( organizationDid: paramsOrganizationIdentity, email: paramsEmail, password: user.password, - roles: commaSeparatedListToArray(params.roles), + roles, givenName: params.givenName ?? "", familyName: params.familyName ?? "" }; @@ -368,25 +370,3 @@ export async function userCreate( return returnJson; } - -/** - * Verify that the specified roles exist in the system. - * @param authorizationComponent The authorization component. - * @param authorizationModelId The model identifier for authorization. - * @param roles The roles to verify. - * @returns A promise that resolves when all roles have been verified. - * @throws GeneralError if any of the specified roles do not exist. - */ -export async function verifyRoles( - authorizationComponent: IAuthorizationComponent, - authorizationModelId: string, - roles: string[] -): Promise { - const results = await authorizationComponent.hasRoles(authorizationModelId, roles); - const missingRoles = roles.filter((role, i) => !results[i]); - if (missingRoles.length > 0) { - throw new GeneralError("userCreate", "rolesNotFound", { - roles: missingRoles.join(", ") - }); - } -} diff --git a/packages/node-core/src/commands/userUpdate.ts b/packages/node-core/src/commands/userUpdate.ts index 3a74ce06..af9f368e 100644 --- a/packages/node-core/src/commands/userUpdate.ts +++ b/packages/node-core/src/commands/userUpdate.ts @@ -11,9 +11,8 @@ import { Coerce, ComponentFactory, GeneralError, Guards, I18n, Is } from "@twin. import type { IEngineCore } from "@twin.org/engine-models"; import { Did, IdentityProfileConnectorFactory } from "@twin.org/identity-models"; import type { Person, WithContext } from "schema-dts"; -import { verifyRoles } from "./userCreate.js"; import { commaSeparatedListToArray } from "../builders/helper/envHelpers.js"; -import { AUTHORIZATION_MODEL_ID } from "../defaults.js"; +import { AUTHORIZATION_MODEL_ID, DEFAULT_USER_ROLE } from "../defaults.js"; import type { ICliCommandDefinition } from "../models/ICliCommandDefinition.js"; import type { IEnvironmentVariables } from "../models/IEnvironmentVariables.js"; @@ -205,8 +204,9 @@ export async function userUpdate( if (Is.stringValue(params.roles)) { const roles = commaSeparatedListToArray(params.roles); - - await verifyRoles(authorizationComponent, authorizationModelId, roles); + if (roles.length === 0) { + roles.push(DEFAULT_USER_ROLE); + } const rolesToAdd = roles.filter(role => !currentRoles.includes(role)); const rolesToRemove = currentRoles.filter(role => !roles.includes(role)); diff --git a/packages/node-core/src/defaults.ts b/packages/node-core/src/defaults.ts index 75922852..fd160d46 100644 --- a/packages/node-core/src/defaults.ts +++ b/packages/node-core/src/defaults.ts @@ -56,6 +56,11 @@ export const DEFAULT_TENANT_ADMIN_ROLE = "tenant-admin"; */ export const DEFAULT_USER_ADMIN_ROLE = "user-admin"; +/** + * Default role for users. + */ +export const DEFAULT_USER_ROLE = "user"; + /** * Get the default environment variables for the node. * @param envPrefix The environment variable prefix. diff --git a/packages/node-core/src/models/IEngineEnvironmentVariables.ts b/packages/node-core/src/models/IEngineEnvironmentVariables.ts index aba673ca..1863a0ef 100644 --- a/packages/node-core/src/models/IEngineEnvironmentVariables.ts +++ b/packages/node-core/src/models/IEngineEnvironmentVariables.ts @@ -746,6 +746,22 @@ export interface IEngineEnvironmentVariables { */ authorizationCheckCacheTtiMs?: string; + /** + * Path to a JSON file containing the authorization model to seed at startup. + * Use the @json: prefix to load the file, e.g. @json:./authorization-model.json. + * The file must contain an object with policies and roleInheritances arrays. + * Combined with or replaces the route-derived defaults depending on authorizationModelMode. + */ + authorizationModel?: string; + + /** + * Controls how authorizationModel is combined with route-derived policies at startup. + * "merge" (default): authorizationModel is applied in addition to route-derived rules. + * "replace": authorizationModel replaces route-derived rules entirely. + * @default "merge" + */ + authorizationModelMode?: string; + /** * The type of faucet connector: entity-storage, iota. */ diff --git a/packages/node-core/src/models/engineEnvironmentVariableKeys.ts b/packages/node-core/src/models/engineEnvironmentVariableKeys.ts index fafddb94..9cf0b382 100644 --- a/packages/node-core/src/models/engineEnvironmentVariableKeys.ts +++ b/packages/node-core/src/models/engineEnvironmentVariableKeys.ts @@ -178,6 +178,8 @@ const engineEnvironmentVariableKeysInternal: { casbinTimeoutMs: true, authorizationCheckCacheCapacity: true, authorizationCheckCacheTtiMs: true, + authorizationModel: true, + authorizationModelMode: true, tracingSilentComponents: true, // DLT / identity faucetConnector: true, diff --git a/packages/node-core/src/start.ts b/packages/node-core/src/start.ts index df81ab0b..d2efbea3 100644 --- a/packages/node-core/src/start.ts +++ b/packages/node-core/src/start.ts @@ -19,6 +19,7 @@ import { extensionsInitialiseEngineServer, shutdownExtensions } from "./builders/extensionsBuilder.js"; +import { seedAuthorizationDefaults } from "./builders/helper/authorizationSeeder.js"; import { commaSeparatedListToArray } from "./builders/helper/envHelpers.js"; import { executeCommand } from "./cli.js"; import type { ICliCommand } from "./models/ICliCommand.js"; @@ -126,6 +127,8 @@ export async function start( // Start the server, which also starts the engine. await server.start(); + await seedAuthorizationDefaults(engine, envVars, server.getRestRoutes()); + return { engine, server, diff --git a/packages/node-core/tests/authorizationSeeder.spec.ts b/packages/node-core/tests/authorizationSeeder.spec.ts new file mode 100644 index 00000000..6fd361f3 --- /dev/null +++ b/packages/node-core/tests/authorizationSeeder.spec.ts @@ -0,0 +1,281 @@ +// Copyright 2026 IOTA Stiftung. +// SPDX-License-Identifier: Apache-2.0. +import type { IPlatformComponent } from "@twin.org/api-models"; +import type { IAuthorizationComponent } from "@twin.org/authorization-models"; +import { ContextIdStore } from "@twin.org/context"; +import { ComponentFactory, Factory } from "@twin.org/core"; +import { MemoryStateStorage } from "@twin.org/engine-core"; +import { + AuthenticationAdminComponentType, + AuthenticationComponentType +} from "@twin.org/engine-server-types"; +import { + BlobStorageConnectorType, + EntityStorageConnectorType, + IdentityConnectorType, + IdentityProfileConnectorType, + IdentityResolverConnectorType, + VaultConnectorType +} from "@twin.org/engine-types"; +import { CI_ENV_VARS } from "./setupTestEnv.js"; +import { AUTHORIZATION_MODEL_ID, DEFAULT_ESCALATED_PRIVILEGE_ROLE } from "../src/defaults.js"; +import type { INodeEngineState } from "../src/models/INodeEngineState.js"; +import type { INodeOptions } from "../src/models/INodeOptions.js"; +import { buildConfiguration } from "../src/node.js"; +import { start } from "../src/start.js"; +import { initialiseLocales } from "../src/utils.js"; + +const TEST_NODE_ID = + "did:iota:testnet:0x8f7b71cedde408974606e404bce76980fd17a570d03ec319788fefd5eabbe9e8"; +const TEST_NODE_ORG_ID = + "did:iota:testnet:0x7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f7a6b"; + +const basePort = Math.floor(Math.random() * 1000); +let port = 17000 + basePort; + +describe("seedAuthorizationDefaults", () => { + beforeEach(() => { + port++; + Factory.clearFactories(); + }); + + afterEach(() => { + const twin = (globalThis as { [key: string]: unknown }).__TWIN_SHARED__ as + { [key: string]: unknown } | undefined; + if (twin) { + twin.sharedObjectBuffers = {}; + } + }); + + async function startServer(envVars: { [key: string]: string }): ReturnType { + await initialiseLocales("./dist/locales/"); + const nodeOptions: INodeOptions = { + envPrefix: "TWIN_", + stateStorage: new MemoryStateStorage(false, { + nodeId: TEST_NODE_ID, + nodeOrganizationId: TEST_NODE_ORG_ID + }) + }; + const { nodeEngineConfig, nodeEnvVars } = await buildConfiguration(envVars, nodeOptions, { + name: "test", + version: "0.0.0" + }); + return start(nodeOptions, nodeEngineConfig, nodeEnvVars); + } + + const baseMinimalEnvVars: { [key: string]: string } = { + TWIN_DEBUG: "true", + TWIN_SILENT: "true", + TWIN_ENTITY_STORAGE_CONNECTOR_TYPE: EntityStorageConnectorType.Memory, + TWIN_SCHEMA_MIGRATION_ENABLED: "false", + TWIN_ENV_ALLOW_LIST: CI_ENV_VARS + }; + + const baseAuthEnvVars: { [key: string]: string } = { + ...baseMinimalEnvVars, + TWIN_BLOB_STORAGE_CONNECTOR_TYPE: BlobStorageConnectorType.Memory, + TWIN_AUTHORIZATION_CONNECTOR: "entity-storage", + TWIN_VAULT_CONNECTOR: VaultConnectorType.EntityStorage, + TWIN_IDENTITY_CONNECTOR: IdentityConnectorType.EntityStorage, + TWIN_IDENTITY_RESOLVER_CONNECTOR: IdentityResolverConnectorType.EntityStorage, + TWIN_IDENTITY_PROFILE_CONNECTOR: IdentityProfileConnectorType.EntityStorage, + TWIN_AUTH_ADMIN_PROCESSOR_TYPE: AuthenticationAdminComponentType.EntityStorage, + TWIN_AUTH_PROCESSOR_TYPE: AuthenticationComponentType.EntityStorage + }; + + test("skips seeding when authorization component is not registered", async () => { + const startResult = await startServer({ + ...baseMinimalEnvVars, + TWIN_PORT: port.toString() + }); + expect(startResult).toBeDefined(); + await startResult?.shutdown(); + }, 30000); + + test("seeds route-derived policies for all routes with defaultAuthorization on startup", async () => { + const startResult = await startServer({ + ...baseAuthEnvVars, + TWIN_PORT: port.toString() + }); + expect(startResult).toBeDefined(); + if (!startResult) { + return; + } + + const authType = startResult.engine.getRegisteredInstanceType("authorizationComponent"); + const authComponent = ComponentFactory.get(authType); + const platformType = startResult.engine.getRegisteredInstanceType("platformComponent"); + const platformComponent = ComponentFactory.get(platformType); + const nodeContextIds = startResult.engine.getContextIds() ?? {}; + + const routes = startResult.server.getRestRoutes(); + const protectedRoutes = routes.filter(r => r.defaultAuthorization && r.operationId); + expect(protectedRoutes.length).toBeGreaterThan(0); + + await ContextIdStore.run(nodeContextIds, async () => { + await platformComponent.execute(async () => { + const { entities: policies } = await authComponent.getAllPolicies(AUTHORIZATION_MODEL_ID); + for (const route of protectedRoutes) { + const auth = route.defaultAuthorization; + const operationId = route.operationId; + if (auth && operationId) { + const hasPolicy = policies.some( + p => + p.subject === auth.permission && p.object === operationId && p.action === "execute" + ); + expect(hasPolicy).toBe(true); + } + } + }); + }); + + await startResult.shutdown(); + }, 30000); + + test("global-admin inherits all roles derived from route defaultAuthorization", async () => { + const startResult = await startServer({ + ...baseAuthEnvVars, + TWIN_PORT: port.toString() + }); + expect(startResult).toBeDefined(); + if (!startResult) { + return; + } + + const authType = startResult.engine.getRegisteredInstanceType("authorizationComponent"); + const authComponent = ComponentFactory.get(authType); + const platformType = startResult.engine.getRegisteredInstanceType("platformComponent"); + const platformComponent = ComponentFactory.get(platformType); + const nodeContextIds = startResult.engine.getContextIds() ?? {}; + + const routes = startResult.server.getRestRoutes(); + const uniqueRoles = new Set(); + for (const route of routes) { + const role = route.defaultAuthorization?.role; + if (role) { + uniqueRoles.add(role); + } + } + expect(uniqueRoles.size).toBeGreaterThan(0); + + await ContextIdStore.run(nodeContextIds, async () => { + await platformComponent.execute(async () => { + const parentRoles = await authComponent.getParentRoles( + AUTHORIZATION_MODEL_ID, + DEFAULT_ESCALATED_PRIVILEGE_ROLE + ); + for (const role of uniqueRoles) { + expect(parentRoles).toContain(role); + } + }); + }); + + await startResult.shutdown(); + }, 30000); + + test("seeds only custom rules when authorizationModelMode is replace", async () => { + const customRules = { + policies: [{ subject: "custom-role", object: "custom-op", action: "execute" }], + roleInheritances: [] + }; + + const startResult = await startServer({ + ...baseAuthEnvVars, + TWIN_PORT: port.toString(), + TWIN_AUTHORIZATION_MODEL: JSON.stringify(customRules), + TWIN_AUTHORIZATION_MODEL_MODE: "replace" + }); + expect(startResult).toBeDefined(); + if (!startResult) { + return; + } + + const authType = startResult.engine.getRegisteredInstanceType("authorizationComponent"); + const authComponent = ComponentFactory.get(authType); + const platformType = startResult.engine.getRegisteredInstanceType("platformComponent"); + const platformComponent = ComponentFactory.get(platformType); + const nodeContextIds = startResult.engine.getContextIds() ?? {}; + + const routes = startResult.server.getRestRoutes(); + const protectedRoute = routes.find(r => r.defaultAuthorization && r.operationId); + expect(protectedRoute).toBeDefined(); + if (!protectedRoute) { + return; + } + + await ContextIdStore.run(nodeContextIds, async () => { + await platformComponent.execute(async () => { + const { entities: policies } = await authComponent.getAllPolicies(AUTHORIZATION_MODEL_ID); + + const hasCustomPolicy = policies.some( + p => p.subject === "custom-role" && p.object === "custom-op" + ); + expect(hasCustomPolicy).toBe(true); + + const auth = protectedRoute.defaultAuthorization; + const operationId = protectedRoute.operationId; + if (auth && operationId) { + const hasRoutePolicy = policies.some( + p => p.subject === auth.permission && p.object === operationId + ); + expect(hasRoutePolicy).toBe(false); + } + }); + }); + + await startResult.shutdown(); + }, 30000); + + test("merges custom rules with route-derived policies when authorizationModelMode is merge", async () => { + const customRules = { + policies: [{ subject: "custom-role", object: "custom-op", action: "execute" }], + roleInheritances: [] + }; + + const startResult = await startServer({ + ...baseAuthEnvVars, + TWIN_PORT: port.toString(), + TWIN_AUTHORIZATION_MODEL: JSON.stringify(customRules), + TWIN_AUTHORIZATION_MODEL_MODE: "merge" + }); + expect(startResult).toBeDefined(); + if (!startResult) { + return; + } + + const authType = startResult.engine.getRegisteredInstanceType("authorizationComponent"); + const authComponent = ComponentFactory.get(authType); + const platformType = startResult.engine.getRegisteredInstanceType("platformComponent"); + const platformComponent = ComponentFactory.get(platformType); + const nodeContextIds = startResult.engine.getContextIds() ?? {}; + + const routes = startResult.server.getRestRoutes(); + const protectedRoute = routes.find(r => r.defaultAuthorization && r.operationId); + expect(protectedRoute).toBeDefined(); + if (!protectedRoute) { + return; + } + + await ContextIdStore.run(nodeContextIds, async () => { + await platformComponent.execute(async () => { + const { entities: policies } = await authComponent.getAllPolicies(AUTHORIZATION_MODEL_ID); + + const hasCustomPolicy = policies.some( + p => p.subject === "custom-role" && p.object === "custom-op" + ); + expect(hasCustomPolicy).toBe(true); + + const auth = protectedRoute.defaultAuthorization; + const operationId = protectedRoute.operationId; + if (auth && operationId) { + const hasRoutePolicy = policies.some( + p => p.subject === auth.permission && p.object === operationId + ); + expect(hasRoutePolicy).toBe(true); + } + }); + }); + + await startResult.shutdown(); + }, 30000); +}); diff --git a/packages/node-core/tests/builders/helper/envHelpers.spec.ts b/packages/node-core/tests/builders/helper/envHelpers.spec.ts index 7b5e3143..c6be21a7 100644 --- a/packages/node-core/tests/builders/helper/envHelpers.spec.ts +++ b/packages/node-core/tests/builders/helper/envHelpers.spec.ts @@ -383,51 +383,40 @@ describe("envArray", () => { describe("envObject", () => { test("returns undefined when env var is absent and no default given", () => { expect( - envObject<{ authorizationDefaultRules?: string }, {}>({}, "authorizationDefaultRules") + envObject<{ authorizationModel?: string }, {}>({}, "authorizationModel") ).toBeUndefined(); }); test("returns defaultValue when env var is absent", () => { const def = { allow: [] }; expect( - envObject<{ authorizationDefaultRules?: string }, { allow: never[] }>( - {}, - "authorizationDefaultRules", - def - ) + envObject<{ authorizationModel?: string }, { allow: never[] }>({}, "authorizationModel", def) ).toBe(def); }); test("returns the parsed object when the var holds a pre-parsed object", () => { const rules = { allow: ["read"] }; expect( - envObject( - { authorizationDefaultRules: rules as unknown as string }, - "authorizationDefaultRules" - ) + envObject({ authorizationModel: rules as unknown as string }, "authorizationModel") ).toEqual(rules); }); test("parses a JSON object string", () => { expect( - envObject<{ authorizationDefaultRules?: string }, { x: number }>( - { authorizationDefaultRules: '{"x":1}' }, - "authorizationDefaultRules" + envObject<{ authorizationModel?: string }, { x: number }>( + { authorizationModel: '{"x":1}' }, + "authorizationModel" ) ).toEqual({ x: 1 }); }); test("returns undefined for a non-object string when no default given", () => { - expect( - envObject({ authorizationDefaultRules: "not-json" }, "authorizationDefaultRules") - ).toBeUndefined(); + expect(envObject({ authorizationModel: "not-json" }, "authorizationModel")).toBeUndefined(); }); test("returns defaultValue for a non-object string when default given", () => { const def = { allow: [] }; - expect( - envObject({ authorizationDefaultRules: "not-json" }, "authorizationDefaultRules", def) - ).toBe(def); + expect(envObject({ authorizationModel: "not-json" }, "authorizationModel", def)).toBe(def); }); }); diff --git a/packages/node-core/tests/index.spec.ts b/packages/node-core/tests/index.spec.ts index 7ed4a230..ea7da8ab 100644 --- a/packages/node-core/tests/index.spec.ts +++ b/packages/node-core/tests/index.spec.ts @@ -534,6 +534,7 @@ describe("node-core", () => { "PUT /tracing/:spanId", "GET /tracing", "GET /tracing/trace/:traceId", + "POST /authorization/:modelId", "POST /authorization/:modelId/check", "POST /authorization/:modelId/policy", "POST /authorization/:modelId/policy/remove", From c1e4dc334d6863e9469052020bc37d119cf6021d Mon Sep 17 00:00:00 2001 From: Martyn Janes Date: Thu, 27 Aug 2026 11:46:00 +0800 Subject: [PATCH 05/17] feat: default authorization generation --- docs/architecture/node-env-variables.mdx | 102 +++++------ .../builders/helper/authorizationSeeder.ts | 69 +++++-- .../tests/authorizationSeeder.spec.ts | 171 +++++++++++++++++- 3 files changed, 277 insertions(+), 65 deletions(-) diff --git a/docs/architecture/node-env-variables.mdx b/docs/architecture/node-env-variables.mdx index 2459bfd9..5ee1323d 100644 --- a/docs/architecture/node-env-variables.mdx +++ b/docs/architecture/node-env-variables.mdx @@ -68,62 +68,62 @@ These variables are only read when running the `bootstrap-dev` CLI command. They ## Connector and Component Selection Variables -| Variable | Possible Values | Default | Notes | -| ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------- | --------------------- | --------------------------------------------------------------------------------------------------------------------------- | -| `TWIN_ENTITY_STORAGE_CONNECTOR_TYPE` | `file`, `memory`, `aws-dynamodb`, `azure-cosmosdb`, `gcp-firestoredb`, `scylladb`, `mysql`, `mongodb`, `postgresql` | None | Comma-separated list allowed. | -| `TWIN_ENTITY_STORAGE_CONNECTOR_DEFAULT` | Any configured entity storage type | First configured type | Default entity storage connector. | -| `TWIN_BLOB_STORAGE_CONNECTOR_TYPE` | `memory`, `file`, `ipfs`, `aws-s3`, `azure-storage`, `gcp-storage` | None | Comma-separated list allowed. | -| `TWIN_BLOB_STORAGE_CONNECTOR_DEFAULT` | Any configured blob storage type | First configured type | Default blob storage connector. | -| `TWIN_VAULT_CONNECTOR` | `entity-storage`, `hashicorp` | None | Selects vault backend. | -| `TWIN_LOGGING_CONNECTOR` | `console`, `entity-storage`, `otel`, `file` | None | Comma-separated list allowed. | -| `TWIN_LOGGING_BATCH_SIZE` | Integer | None | Logging batch size. Set to `1` to disable batching. | -| `TWIN_LOGGING_SILENT_COMPONENTS` | Comma-separated list of component class names | None | A list of components to exclude from logging. | -| `TWIN_LOGGING_BATCH_FLUSH_INTERVAL` | Integer seconds | `5` | Logging batch flush interval. | -| `TWIN_LOGGING_RETAIN_FOR` | Integer minutes | `2880` | Age-based retention window for `entity-storage` logging. Set to `0` to disable age-based retention. | -| `TWIN_LOGGING_MAX_ENTRIES` | Integer | `10000` | Count-based retention limit for `entity-storage` logging. Set to `0` to disable count-based retention. | -| `TWIN_LOGGING_RETENTION_INTERVAL` | Integer minutes | `5` | How often retention cleanup runs for `entity-storage` logging. Set to `0` to disable periodic cleanup. | -| `TWIN_LOGGING_RETENTION_BATCH_SIZE` | Integer | `1000` | Maximum entries deleted per retention cleanup batch for `entity-storage` logging. | -| `TWIN_LOGGING_FILE_DIRECTORY` | Directory path | None | Directory to write log files into. Required when `TWIN_LOGGING_CONNECTOR` includes `file`. | -| `TWIN_LOGGING_FILE_FILENAME` | String | `app.log` | Log filename. Only used when `TWIN_LOGGING_CONNECTOR` includes `file`. | -| `TWIN_LOGGING_FILE_MAX_FILE_SIZE_BYTES` | Integer bytes | `10485760` | Max log file size before rotation. Set to `0` to disable rotation. Only used when `TWIN_LOGGING_CONNECTOR` includes `file`. | -| `TWIN_LOGGING_FILE_MAX_RETAINED_FILES` | Integer | `5` | Number of rotated log files to retain. Set to `0` to keep all. Only used when `TWIN_LOGGING_CONNECTOR` includes `file`. | -| `TWIN_EVENT_BUS_CONNECTOR` | `local` | None | Selects event bus connector. | -| `TWIN_EVENT_BUS_COMPONENT` | `service` | None | Selects event bus component implementation. | -| `TWIN_MESSAGING_EMAIL_CONNECTOR` | `entity-storage`, `aws` | None | Messaging email connector type. | -| `TWIN_MESSAGING_SMS_CONNECTOR` | `entity-storage`, `aws` | None | Messaging SMS connector type. | -| `TWIN_MESSAGING_PUSH_NOTIFICATION_CONNECTOR` | `entity-storage`, `aws` | None | Messaging push connector type. | -| `TWIN_TELEMETRY_CONNECTOR` | `entity-storage`, `open-telemetry`, `silent` (comma-separated for multiple) | None | Telemetry connector type. When multiple values are provided, a multi-connector is created automatically as the default. | -| `TWIN_TELEMETRY_METRICS_PRODUCERS` | `system`, `process` (comma-separated) | `system,process` | Metrics producer types to enable. | -| `TWIN_TELEMETRY_SILENT_COMPONENTS` | Comma-separated list of component class names | None | A list of components to exclude from telemetry. | -| `TWIN_TRACING_CONNECTOR` | `entity-storage`, `open-telemetry`, `console`, `silent` (comma-separated for multiple) | None | Tracing connector type. When multiple values are provided, a multi-connector is created automatically as the default. | -| `TWIN_TRACING_SILENT_COMPONENTS` | Comma-separated list of component class names | None | A list of components to exclude from tracing. | +| Variable | Possible Values | Default | Notes | +| ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | +| `TWIN_ENTITY_STORAGE_CONNECTOR_TYPE` | `file`, `memory`, `aws-dynamodb`, `azure-cosmosdb`, `gcp-firestoredb`, `scylladb`, `mysql`, `mongodb`, `postgresql` | None | Comma-separated list allowed. | +| `TWIN_ENTITY_STORAGE_CONNECTOR_DEFAULT` | Any configured entity storage type | First configured type | Default entity storage connector. | +| `TWIN_BLOB_STORAGE_CONNECTOR_TYPE` | `memory`, `file`, `ipfs`, `aws-s3`, `azure-storage`, `gcp-storage` | None | Comma-separated list allowed. | +| `TWIN_BLOB_STORAGE_CONNECTOR_DEFAULT` | Any configured blob storage type | First configured type | Default blob storage connector. | +| `TWIN_VAULT_CONNECTOR` | `entity-storage`, `hashicorp` | None | Selects vault backend. | +| `TWIN_LOGGING_CONNECTOR` | `console`, `entity-storage`, `otel`, `file` | None | Comma-separated list allowed. | +| `TWIN_LOGGING_BATCH_SIZE` | Integer | None | Logging batch size. Set to `1` to disable batching. | +| `TWIN_LOGGING_SILENT_COMPONENTS` | Comma-separated list of component class names | None | A list of components to exclude from logging. | +| `TWIN_LOGGING_BATCH_FLUSH_INTERVAL` | Integer seconds | `5` | Logging batch flush interval. | +| `TWIN_LOGGING_RETAIN_FOR` | Integer minutes | `2880` | Age-based retention window for `entity-storage` logging. Set to `0` to disable age-based retention. | +| `TWIN_LOGGING_MAX_ENTRIES` | Integer | `10000` | Count-based retention limit for `entity-storage` logging. Set to `0` to disable count-based retention. | +| `TWIN_LOGGING_RETENTION_INTERVAL` | Integer minutes | `5` | How often retention cleanup runs for `entity-storage` logging. Set to `0` to disable periodic cleanup. | +| `TWIN_LOGGING_RETENTION_BATCH_SIZE` | Integer | `1000` | Maximum entries deleted per retention cleanup batch for `entity-storage` logging. | +| `TWIN_LOGGING_FILE_DIRECTORY` | Directory path | None | Directory to write log files into. Required when `TWIN_LOGGING_CONNECTOR` includes `file`. | +| `TWIN_LOGGING_FILE_FILENAME` | String | `app.log` | Log filename. Only used when `TWIN_LOGGING_CONNECTOR` includes `file`. | +| `TWIN_LOGGING_FILE_MAX_FILE_SIZE_BYTES` | Integer bytes | `10485760` | Max log file size before rotation. Set to `0` to disable rotation. Only used when `TWIN_LOGGING_CONNECTOR` includes `file`. | +| `TWIN_LOGGING_FILE_MAX_RETAINED_FILES` | Integer | `5` | Number of rotated log files to retain. Set to `0` to keep all. Only used when `TWIN_LOGGING_CONNECTOR` includes `file`. | +| `TWIN_EVENT_BUS_CONNECTOR` | `local` | None | Selects event bus connector. | +| `TWIN_EVENT_BUS_COMPONENT` | `service` | None | Selects event bus component implementation. | +| `TWIN_MESSAGING_EMAIL_CONNECTOR` | `entity-storage`, `aws` | None | Messaging email connector type. | +| `TWIN_MESSAGING_SMS_CONNECTOR` | `entity-storage`, `aws` | None | Messaging SMS connector type. | +| `TWIN_MESSAGING_PUSH_NOTIFICATION_CONNECTOR` | `entity-storage`, `aws` | None | Messaging push connector type. | +| `TWIN_TELEMETRY_CONNECTOR` | `entity-storage`, `open-telemetry`, `silent` (comma-separated for multiple) | None | Telemetry connector type. When multiple values are provided, a multi-connector is created automatically as the default. | +| `TWIN_TELEMETRY_METRICS_PRODUCERS` | `system`, `process` (comma-separated) | `system,process` | Metrics producer types to enable. | +| `TWIN_TELEMETRY_SILENT_COMPONENTS` | Comma-separated list of component class names | None | A list of components to exclude from telemetry. | +| `TWIN_TRACING_CONNECTOR` | `entity-storage`, `open-telemetry`, `console`, `silent` (comma-separated for multiple) | None | Tracing connector type. When multiple values are provided, a multi-connector is created automatically as the default. | +| `TWIN_TRACING_SILENT_COMPONENTS` | Comma-separated list of component class names | None | A list of components to exclude from tracing. | | `TWIN_AUTHORIZATION_CONNECTOR` | `entity-storage`, `casbin` | None | Authorization connector type. | | `TWIN_AUTHORIZATION_CHECK_CACHE_CAPACITY` | Integer | None | Maximum number of cached authorisation check results. | | `TWIN_AUTHORIZATION_CHECK_CACHE_TTI_MS` | Integer | None | Time-to-idle in milliseconds for cached authorisation check results. | | `TWIN_AUTHORIZATION_MODEL` | `@json:` | None | Path to a JSON file containing the authorization model to seed at startup, with `policies` and `roleInheritances` arrays. | | `TWIN_AUTHORIZATION_MODEL_MODE` | `merge`, `replace` | `merge` | How to combine `TWIN_AUTHORIZATION_MODEL` with route-derived policies. `merge` applies both; `replace` uses only the custom model. | -| `TWIN_FAUCET_CONNECTOR` | `entity-storage`, `iota` | None | Faucet connector type. | -| `TWIN_WALLET_CONNECTOR` | `entity-storage`, `iota` | None | Wallet connector type. | -| `TWIN_NFT_CONNECTOR` | `entity-storage`, `iota` | None | NFT connector type. | -| `TWIN_NFT_PACKAGE_ID` | String | None | Custom deployed package id for the NFT contract. | -| `TWIN_NOTARIZATION_CONNECTOR` | `entity-storage`, `iota` | None | Notarization connector type. | -| `TWIN_IDENTITY_CONNECTOR` | `entity-storage`, `iota` | None | Identity connector type. | -| `TWIN_IDENTITY_RESOLVER_CONNECTOR` | `entity-storage`, `iota`, `universal` | None | Identity resolver connector type. | -| `TWIN_IDENTITY_PROFILE_CONNECTOR` | `entity-storage` | None | Identity profile connector type. | -| `TWIN_ATTESTATION_CONNECTOR` | `nft` | None | Attestation connector type. | -| `TWIN_DATA_CONVERTER_CONNECTORS` | `json`, `xml` | None | Comma-separated list allowed. | -| `TWIN_DATA_EXTRACTOR_CONNECTORS` | `json-path` | None | Comma-separated list allowed. | -| `TWIN_AUTOMATION_ACTION_TYPES` | `fetch` | None | Automation action types to register. | -| `TWIN_FEDERATED_CATALOGUE_FILTERS` | `filter-by-metadata` | None | Federated catalogue filters. | -| `TWIN_TRUST_GENERATORS` | `jwt-verifiable-credential` | None | Trust generator registrations. | -| `TWIN_TRUST_VERIFIERS` | `jwt-verifiable-credential` | None | Trust verifier registrations. | -| `TWIN_RIGHTS_MANAGEMENT_POLICY_ARBITERS` | `pass-through`, `default` | None | Rights policy arbiter registrations. | -| `TWIN_RIGHTS_MANAGEMENT_POLICY_ENFORCEMENT_PROCESSORS` | `pass-through`, `default` | None | Rights policy enforcement processor registrations. | -| `TWIN_RIGHTS_MANAGEMENT_POLICY_EXECUTION_ACTIONS` | `logging` | None | Rights policy execution action registrations. | -| `TWIN_RIGHTS_MANAGEMENT_POLICY_INFORMATION_SOURCES` | `identity`, `static`, `identity-profile` | None | Rights policy information source registrations. | -| `TWIN_RIGHTS_MANAGEMENT_POLICY_NEGOTIATORS` | `pass-through` | None | Rights policy negotiator registrations. | -| `TWIN_RIGHTS_MANAGEMENT_POLICY_OBLIGATION_ENFORCERS` | `pass-through` | None | Rights policy obligation enforcer registrations. | -| `TWIN_RIGHTS_MANAGEMENT_POLICY_REQUESTERS` | `pass-through` | None | Rights policy requester registrations. | +| `TWIN_FAUCET_CONNECTOR` | `entity-storage`, `iota` | None | Faucet connector type. | +| `TWIN_WALLET_CONNECTOR` | `entity-storage`, `iota` | None | Wallet connector type. | +| `TWIN_NFT_CONNECTOR` | `entity-storage`, `iota` | None | NFT connector type. | +| `TWIN_NFT_PACKAGE_ID` | String | None | Custom deployed package id for the NFT contract. | +| `TWIN_NOTARIZATION_CONNECTOR` | `entity-storage`, `iota` | None | Notarization connector type. | +| `TWIN_IDENTITY_CONNECTOR` | `entity-storage`, `iota` | None | Identity connector type. | +| `TWIN_IDENTITY_RESOLVER_CONNECTOR` | `entity-storage`, `iota`, `universal` | None | Identity resolver connector type. | +| `TWIN_IDENTITY_PROFILE_CONNECTOR` | `entity-storage` | None | Identity profile connector type. | +| `TWIN_ATTESTATION_CONNECTOR` | `nft` | None | Attestation connector type. | +| `TWIN_DATA_CONVERTER_CONNECTORS` | `json`, `xml` | None | Comma-separated list allowed. | +| `TWIN_DATA_EXTRACTOR_CONNECTORS` | `json-path` | None | Comma-separated list allowed. | +| `TWIN_AUTOMATION_ACTION_TYPES` | `fetch` | None | Automation action types to register. | +| `TWIN_FEDERATED_CATALOGUE_FILTERS` | `filter-by-metadata` | None | Federated catalogue filters. | +| `TWIN_TRUST_GENERATORS` | `jwt-verifiable-credential` | None | Trust generator registrations. | +| `TWIN_TRUST_VERIFIERS` | `jwt-verifiable-credential` | None | Trust verifier registrations. | +| `TWIN_RIGHTS_MANAGEMENT_POLICY_ARBITERS` | `pass-through`, `default` | None | Rights policy arbiter registrations. | +| `TWIN_RIGHTS_MANAGEMENT_POLICY_ENFORCEMENT_PROCESSORS` | `pass-through`, `default` | None | Rights policy enforcement processor registrations. | +| `TWIN_RIGHTS_MANAGEMENT_POLICY_EXECUTION_ACTIONS` | `logging` | None | Rights policy execution action registrations. | +| `TWIN_RIGHTS_MANAGEMENT_POLICY_INFORMATION_SOURCES` | `identity`, `static`, `identity-profile` | None | Rights policy information source registrations. | +| `TWIN_RIGHTS_MANAGEMENT_POLICY_NEGOTIATORS` | `pass-through` | None | Rights policy negotiator registrations. | +| `TWIN_RIGHTS_MANAGEMENT_POLICY_OBLIGATION_ENFORCERS` | `pass-through` | None | Rights policy obligation enforcer registrations. | +| `TWIN_RIGHTS_MANAGEMENT_POLICY_REQUESTERS` | `pass-through` | None | Rights policy requester registrations. | ## Feature Toggle and Behaviour Variables diff --git a/packages/node-core/src/builders/helper/authorizationSeeder.ts b/packages/node-core/src/builders/helper/authorizationSeeder.ts index 21d443ce..214e3e99 100644 --- a/packages/node-core/src/builders/helper/authorizationSeeder.ts +++ b/packages/node-core/src/builders/helper/authorizationSeeder.ts @@ -10,10 +10,26 @@ import type { import { ContextIdStore } from "@twin.org/context"; import { ComponentFactory, Is } from "@twin.org/core"; import type { IEngineCore } from "@twin.org/engine-models"; +import { HttpMethod } from "@twin.org/web"; import { envObject, envString } from "./envHelpers.js"; -import { AUTHORIZATION_MODEL_ID, DEFAULT_ESCALATED_PRIVILEGE_ROLE } from "../../defaults.js"; +import { + AUTHORIZATION_MODEL_ID, + DEFAULT_ESCALATED_PRIVILEGE_ROLE, + DEFAULT_USER_ROLE +} from "../../defaults.js"; import type { IEngineEnvironmentVariables } from "../../models/IEngineEnvironmentVariables.js"; +const DEFAULT_AUTHORIZATION_READER: IRouteAuthorization = { + permission: "user:read", + role: DEFAULT_USER_ROLE +}; + +const DEFAULT_AUTHORIZATION_WRITER: IRouteAuthorization = { + permission: "user:write", + role: DEFAULT_USER_ROLE, + inherits: [DEFAULT_AUTHORIZATION_READER.permission] +}; + /** * Seed default authorization policies and role inheritances after the engine has started. * Uses the platform component to execute across all tenants in multi-tenant mode. @@ -62,6 +78,9 @@ export async function seedAuthorizationDefaults( } for (const role of escalatedRoles) { roleInheritances.push({ role: DEFAULT_ESCALATED_PRIVILEGE_ROLE, inheritsFrom: role }); + if (role !== DEFAULT_USER_ROLE) { + roleInheritances.push({ role, inheritsFrom: DEFAULT_USER_ROLE }); + } } } @@ -71,31 +90,52 @@ export async function seedAuthorizationDefaults( const roles = new Set(); for (const route of routes) { - const auth = route.defaultAuthorization; - if (Is.objectValue(auth)) { - const policyKey = `${auth.permission}|${route.operationId}`; + const requiresAuthorization = + route.requiresAuthorization !== false && route.skipAuth !== true; + let authorization: IRouteAuthorization | undefined = route.defaultAuthorization; + + // If there are no specific default permissions we provide + // a fallback based on the HTTP method for the default "user" role. + if (!Is.objectValue(authorization) && requiresAuthorization) { + if (route.method === HttpMethod.GET) { + authorization = DEFAULT_AUTHORIZATION_READER; + } else if ( + route.method === HttpMethod.PUT || + route.method === HttpMethod.POST || + route.method === HttpMethod.PATCH || + route.method === HttpMethod.DELETE + ) { + authorization = DEFAULT_AUTHORIZATION_WRITER; + } + } + + if (Is.objectValue(authorization)) { + const policyKey = `${authorization.permission}|${route.operationId}`; if (!policyKeys.has(policyKey)) { policyKeys.add(policyKey); policies.push({ - subject: auth.permission, + subject: authorization.permission, object: route.operationId, action: "execute" }); } - if (Is.stringValue(auth.role)) { - const inheritKey = `${auth.role}|${auth.permission}`; + if (Is.stringValue(authorization.role)) { + const inheritKey = `${authorization.role}|${authorization.permission}`; if (!inheritanceKeys.has(inheritKey)) { inheritanceKeys.add(inheritKey); - roleInheritances.push({ role: auth.role, inheritsFrom: auth.permission }); + roleInheritances.push({ + role: authorization.role, + inheritsFrom: authorization.permission + }); } - roles.add(auth.role); + roles.add(authorization.role); } - if (Is.arrayValue(auth.inherits)) { - for (const inheritsFrom of auth.inherits) { - const inheritKey = `${auth.permission}|${inheritsFrom}`; + if (Is.arrayValue(authorization.inherits)) { + for (const inheritsFrom of authorization.inherits) { + const inheritKey = `${authorization.permission}|${inheritsFrom}`; if (!inheritanceKeys.has(inheritKey)) { inheritanceKeys.add(inheritKey); - roleInheritances.push({ role: auth.permission, inheritsFrom }); + roleInheritances.push({ role: authorization.permission, inheritsFrom }); } } } @@ -104,6 +144,9 @@ export async function seedAuthorizationDefaults( for (const role of roles) { roleInheritances.push({ role: DEFAULT_ESCALATED_PRIVILEGE_ROLE, inheritsFrom: role }); + if (role !== DEFAULT_USER_ROLE) { + roleInheritances.push({ role, inheritsFrom: DEFAULT_USER_ROLE }); + } } } diff --git a/packages/node-core/tests/authorizationSeeder.spec.ts b/packages/node-core/tests/authorizationSeeder.spec.ts index 6fd361f3..16775174 100644 --- a/packages/node-core/tests/authorizationSeeder.spec.ts +++ b/packages/node-core/tests/authorizationSeeder.spec.ts @@ -18,7 +18,11 @@ import { VaultConnectorType } from "@twin.org/engine-types"; import { CI_ENV_VARS } from "./setupTestEnv.js"; -import { AUTHORIZATION_MODEL_ID, DEFAULT_ESCALATED_PRIVILEGE_ROLE } from "../src/defaults.js"; +import { + AUTHORIZATION_MODEL_ID, + DEFAULT_ESCALATED_PRIVILEGE_ROLE, + DEFAULT_USER_ROLE +} from "../src/defaults.js"; import type { INodeEngineState } from "../src/models/INodeEngineState.js"; import type { INodeOptions } from "../src/models/INodeOptions.js"; import { buildConfiguration } from "../src/node.js"; @@ -173,6 +177,44 @@ describe("seedAuthorizationDefaults", () => { await startResult.shutdown(); }, 30000); + test("non-user roles derived from route defaultAuthorization inherit the user role", async () => { + const startResult = await startServer({ + ...baseAuthEnvVars, + TWIN_PORT: port.toString() + }); + expect(startResult).toBeDefined(); + if (!startResult) { + return; + } + + const authType = startResult.engine.getRegisteredInstanceType("authorizationComponent"); + const authComponent = ComponentFactory.get(authType); + const platformType = startResult.engine.getRegisteredInstanceType("platformComponent"); + const platformComponent = ComponentFactory.get(platformType); + const nodeContextIds = startResult.engine.getContextIds() ?? {}; + + const routes = startResult.server.getRestRoutes(); + const nonUserRoles = new Set(); + for (const route of routes) { + const role = route.defaultAuthorization?.role; + if (role && role !== DEFAULT_USER_ROLE) { + nonUserRoles.add(role); + } + } + expect(nonUserRoles.size).toBeGreaterThan(0); + + await ContextIdStore.run(nodeContextIds, async () => { + await platformComponent.execute(async () => { + for (const role of nonUserRoles) { + const parentRoles = await authComponent.getParentRoles(AUTHORIZATION_MODEL_ID, role); + expect(parentRoles).toContain(DEFAULT_USER_ROLE); + } + }); + }); + + await startResult.shutdown(); + }, 30000); + test("seeds only custom rules when authorizationModelMode is replace", async () => { const customRules = { policies: [{ subject: "custom-role", object: "custom-op", action: "execute" }], @@ -226,6 +268,133 @@ describe("seedAuthorizationDefaults", () => { await startResult.shutdown(); }, 30000); + test("auto-derives user:read policy for GET routes without explicit defaultAuthorization", async () => { + const startResult = await startServer({ + ...baseAuthEnvVars, + TWIN_PORT: port.toString() + }); + expect(startResult).toBeDefined(); + if (!startResult) { + return; + } + + const authType = startResult.engine.getRegisteredInstanceType("authorizationComponent"); + const authComponent = ComponentFactory.get(authType); + const platformType = startResult.engine.getRegisteredInstanceType("platformComponent"); + const platformComponent = ComponentFactory.get(platformType); + const nodeContextIds = startResult.engine.getContextIds() ?? {}; + + const routes = startResult.server.getRestRoutes(); + const fallbackGetRoutes = routes.filter( + r => + r.requiresAuthorization !== false && + !r.skipAuth && + !r.defaultAuthorization && + r.method.toUpperCase() === "GET" + ); + + await ContextIdStore.run(nodeContextIds, async () => { + await platformComponent.execute(async () => { + const { entities: policies } = await authComponent.getAllPolicies( + AUTHORIZATION_MODEL_ID, + "user:read" + ); + for (const route of fallbackGetRoutes) { + const hasPolicy = policies.some( + p => + p.subject === "user:read" && p.object === route.operationId && p.action === "execute" + ); + expect( + hasPolicy, + `Expected user:read policy for route ${route.operationId} (method: ${route.method})` + ).toBe(true); + } + }); + }); + + await startResult.shutdown(); + }, 30000); + + test("auto-derives user:write policy for PUT/POST/PATCH/DELETE routes without explicit defaultAuthorization", async () => { + const startResult = await startServer({ + ...baseAuthEnvVars, + TWIN_PORT: port.toString() + }); + expect(startResult).toBeDefined(); + if (!startResult) { + return; + } + + const authType = startResult.engine.getRegisteredInstanceType("authorizationComponent"); + const authComponent = ComponentFactory.get(authType); + const platformType = startResult.engine.getRegisteredInstanceType("platformComponent"); + const platformComponent = ComponentFactory.get(platformType); + const nodeContextIds = startResult.engine.getContextIds() ?? {}; + + const routes = startResult.server.getRestRoutes(); + const fallbackWriteRoutes = routes.filter(r => { + const method = r.method.toUpperCase(); + return ( + r.requiresAuthorization !== false && + !r.skipAuth && + !r.defaultAuthorization && + (method === "PUT" || method === "POST" || method === "PATCH" || method === "DELETE") + ); + }); + + await ContextIdStore.run(nodeContextIds, async () => { + await platformComponent.execute(async () => { + const { entities: policies } = await authComponent.getAllPolicies( + AUTHORIZATION_MODEL_ID, + "user:write" + ); + for (const route of fallbackWriteRoutes) { + const hasPolicy = policies.some( + p => + p.subject === "user:write" && p.object === route.operationId && p.action === "execute" + ); + expect(hasPolicy).toBe(true); + } + }); + }); + + await startResult.shutdown(); + }, 30000); + + test("does not seed policy for route with requiresAuthorization false and no defaultAuthorization", async () => { + const startResult = await startServer({ + ...baseAuthEnvVars, + TWIN_PORT: port.toString() + }); + expect(startResult).toBeDefined(); + if (!startResult) { + return; + } + + const authType = startResult.engine.getRegisteredInstanceType("authorizationComponent"); + const authComponent = ComponentFactory.get(authType); + const platformType = startResult.engine.getRegisteredInstanceType("platformComponent"); + const platformComponent = ComponentFactory.get(platformType); + const nodeContextIds = startResult.engine.getContextIds() ?? {}; + + const routes = startResult.server.getRestRoutes(); + const skippedRoutes = routes.filter( + r => r.requiresAuthorization === false && !r.defaultAuthorization + ); + + await ContextIdStore.run(nodeContextIds, async () => { + await platformComponent.execute(async () => { + const { entities: policies } = await authComponent.getAllPolicies(AUTHORIZATION_MODEL_ID); + for (const route of skippedRoutes) { + const hasPolicy = policies.some(p => p.object === route.operationId); + expect(hasPolicy).toBe(false); + } + }); + }); + + await startResult.shutdown(); + }, 30000); + test("merges custom rules with route-derived policies when authorizationModelMode is merge", async () => { const customRules = { policies: [{ subject: "custom-role", object: "custom-op", action: "execute" }], From 0cd65bc7c565af79fad7a96529fa98b08052bfbf Mon Sep 17 00:00:00 2001 From: Martyn Janes Date: Thu, 27 Aug 2026 11:48:01 +0800 Subject: [PATCH 06/17] feat: route permissions --- packages/node-core/tests/index.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/node-core/tests/index.spec.ts b/packages/node-core/tests/index.spec.ts index ea7da8ab..68f16c82 100644 --- a/packages/node-core/tests/index.spec.ts +++ b/packages/node-core/tests/index.spec.ts @@ -575,8 +575,8 @@ describe("node-core", () => { "POST /identity/:identity/verifiable-credential/:verificationMethodId", "POST /identity/verifiable-credential/verify/document", "GET /identity/verifiable-credential/verify", - "GET /identity/:identity/verifiable-credential/revoke/:revocationIndex", - "GET /identity/:identity/verifiable-credential/unrevoke/:revocationIndex", + "POST /identity/:identity/verifiable-credential/revoke/:revocationIndex", + "POST /identity/:identity/verifiable-credential/unrevoke/:revocationIndex", "POST /identity/:identity/verifiable-presentation/:verificationMethodId", "POST /identity/verifiable-presentation/verify/document", "GET /identity/verifiable-presentation/verify", From 1b1e78e63289033fb5a5b4687f4828f176feead1 Mon Sep 17 00:00:00 2001 From: Martyn Janes Date: Thu, 27 Aug 2026 12:20:10 +0800 Subject: [PATCH 07/17] docs: add auth defaults --- .../authorization-defaults-diagrams.jsx | 391 ++++++++++++++++++ docs/architecture/authorization-defaults.mdx | 121 ++++++ 2 files changed, 512 insertions(+) create mode 100644 docs/architecture/authorization-defaults-diagrams.jsx create mode 100644 docs/architecture/authorization-defaults.mdx diff --git a/docs/architecture/authorization-defaults-diagrams.jsx b/docs/architecture/authorization-defaults-diagrams.jsx new file mode 100644 index 00000000..718075d7 --- /dev/null +++ b/docs/architecture/authorization-defaults-diagrams.jsx @@ -0,0 +1,391 @@ +const bg = '#F8F9FB'; +const surface = '#FFFFFF'; +const border = '#E2E8F0'; +const textPrimary = '#1E293B'; +const textMuted = '#64748B'; + +const roles = { + globalAdmin: { label: 'global-admin', bg: '#EDE9FE', color: '#5B21B6', border: '#C4B5FD' }, + identityAdmin:{ label: 'identity-admin', bg: '#E0F2FE', color: '#0369A1', border: '#BAE6FD' }, + userAdmin: { label: 'user-admin', bg: '#CCFBF1', color: '#0F766E', border: '#99F6E4' }, + devops: { label: 'devops', bg: '#FEF3C7', color: '#92400E', border: '#FDE68A' }, + tenantAdmin: { label: 'tenant-admin', bg: '#F3E8FF', color: '#6D28D9', border: '#DDD6FE' }, + user: { label: 'user', bg: '#F1F5F9', color: '#475569', border: '#CBD5E1' }, +}; + +const perms = { + identity: { color: '#0369A1', bg: 'rgba(3,105,161,0.08)' }, + user: { color: '#475569', bg: 'rgba(71,85,105,0.08)' }, + auth: { color: '#0F766E', bg: 'rgba(15,118,110,0.08)' }, + devops: { color: '#92400E', bg: 'rgba(146,64,14,0.08)' }, + tenant: { color: '#6D28D9', bg: 'rgba(109,40,217,0.08)' }, +}; + +function RoleChip({ role, small }) { + const r = roles[role]; + return ( + + {r.label} + + ); +} + +function PermChip({ ns, label }) { + const p = perms[ns]; + return ( + + {label} + + ); +} + +export function RoleHierarchyDiagram() { + const rowStyle = { + display: 'flex', + alignItems: 'center', + gap: '10px', + padding: '8px 0', + }; + + const connectorCol = { + width: '32px', + flexShrink: 0, + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + }; + + const rows = [ + { role: 'identityAdmin', last: false }, + { role: 'userAdmin', last: false }, + { role: 'devops', last: false, note: null }, + { role: 'tenantAdmin', last: false, note: 'multi-tenant mode only' }, + { role: 'user', last: true, note: 'base authenticated role' }, + ]; + + return ( +
+

+ Role Hierarchy +

+ + {/* global-admin root */} +
+ + + inherits all roles below + +
+ + {/* rows */} + {rows.map(({ role, last, note }, i) => ( +
+ {/* tree connector */} +
+ {!last && ( +
+ )} + {last && ( +
+ )} +
+
+ +
+ + {role !== 'user' && ( + + → inherits + + )} + {note && ( + + {note} + + )} +
+
+ ))} +
+ ); +} + +export function PermissionNamespacesDiagram() { + const namespaces = [ + { + ns: 'identity', + label: 'identity:*', + desc: 'Identity and credential management', + role: 'identityAdmin', + items: [ + { perm: 'identity:write', note: 'Create/remove DIDs, VCs, proofs; revoke/unrevoke credentials' }, + { perm: 'user:read', note: 'Verify VC/presentation, resolve DID (verb fallback)', fallback: true }, + ], + }, + { + ns: 'user', + label: 'user:*', + desc: 'Authenticated user operations and user administration', + roles: ['user', 'userAdmin'], + items: [ + { perm: 'user:read', note: 'Standard GET operations (verb fallback)', fallback: true }, + { perm: 'user:write', note: 'Standard POST/PUT/PATCH/DELETE (verb fallback); inherits user:read', fallback: true }, + { perm: 'user:read', note: 'Admin get user, get by identity, profile admin get, audit query', role: 'userAdmin' }, + { perm: 'user:write', note: 'Admin create/update/remove user, password reset, profile admin, audit; inherits user:read', role: 'userAdmin' }, + ], + }, + { + ns: 'auth', + label: 'authorization:*', + desc: 'Authorization policy management', + role: 'userAdmin', + items: [ + { perm: 'authorization:read', note: 'Get policies, roles, role assignments, inheritances, check access' }, + { perm: 'authorization:write', note: 'Build model, add/remove policies, role assignments, inheritances; inherits authorization:read' }, + ], + }, + { + ns: 'devops', + label: 'health:* / logging:* / tracing:* / telemetry:*', + desc: 'Observability and infrastructure', + role: 'devops', + items: [ + { perm: 'health:read', note: 'Server health status' }, + { perm: 'logging:read', note: 'List log entries' }, + { perm: 'logging:write', note: 'Create log entries; inherits logging:read' }, + { perm: 'tracing:read', note: 'List spans, get traces' }, + { perm: 'tracing:write', note: 'Start and end spans; inherits tracing:read' }, + { perm: 'telemetry:read', note: 'Get metrics, list entries, get values' }, + { perm: 'telemetry:write', note: 'Create/update/remove metrics, add values; inherits telemetry:read' }, + ], + }, + { + ns: 'tenant', + label: 'tenant:*', + desc: 'Tenant administration', + role: 'tenantAdmin', + note: 'Seeded only when TWIN_TENANT_ENABLED=true', + items: [ + { perm: 'tenant:read', note: 'List and get tenants' }, + { perm: 'tenant:write', note: 'Create, update, and remove tenants; inherits tenant:read' }, + ], + }, + ]; + + return ( +
+ {namespaces.map(({ ns, label, desc, role, roles: multiRoles, items, note }) => { + const p = perms[ns]; + return ( +
+ {/* header */} +
+ + {label} + + {desc} + {note && ( + {note} + )} +
+ {multiRoles + ? multiRoles.map(r => ) + : + } +
+
+ + {/* permission rows */} +
+ {items.map((item, i) => ( +
+
+ + {item.fallback && ( + + verb fallback + + )} + {item.role && !item.fallback && ( + + )} +
+ {item.note} +
+ ))} +
+
+ ); + })} +
+ ); +} + +export function VerbFallbackDiagram() { + const methods = [ + { method: 'GET', perm: 'user:read', role: 'user', inherits: null }, + { method: 'POST / PUT / PATCH / DELETE', perm: 'user:write', role: 'user', inherits: 'user:read' }, + ]; + + return ( +
+
+ {['HTTP Method', 'Permission', 'Role'].map(h => ( +
+ {h} +
+ ))} +
+ {methods.map(({ method, perm, role, inherits }, i) => ( +
+
+ {method} +
+
+ + {inherits && ( + + inherits {inherits} + + )} +
+
+ +
+
+ ))} +
+ ); +} diff --git a/docs/architecture/authorization-defaults.mdx b/docs/architecture/authorization-defaults.mdx new file mode 100644 index 00000000..f92c3072 --- /dev/null +++ b/docs/architecture/authorization-defaults.mdx @@ -0,0 +1,121 @@ +--- +category: node +order: 10 +--- + +import { RoleHierarchyDiagram, PermissionNamespacesDiagram, VerbFallbackDiagram } from './authorization-defaults-diagrams.jsx' + +# Default Authorization Seeding + +On startup, `seedAuthorizationDefaults` derives RBAC policies from the registered REST routes and writes them to the authorization store via the authorization component. This happens once, after the engine server has fully started. + +The function processes every route returned by `server.getRestRoutes()` and builds a set of policies and role inheritances. Routes with `skipAuth: true` or `requiresAuthorization: false` are excluded. + +## Role Hierarchy + +{RoleHierarchyDiagram()} + +`global-admin` inherits every role. Every non-`user` role inherits `user`, giving all elevated roles the baseline authenticated-user permissions. + +`tenant-admin` is only seeded when the node is running in multi-tenant mode (`TWIN_TENANT_ENABLED=true`). + +## Permission Namespaces + +Each permission namespace is seeded from the routes that belong to that namespace. Write permissions inherit their read counterpart within the same namespace. + +{PermissionNamespacesDiagram()} + +### `user` - authenticated user operations + +Seeded from the verb-based fallback for routes that do not declare an explicit `defaultAuthorization`. + +| Permission | Role | Notes | +|---|---|---| +| `user:read` | `user` | GET routes (verb fallback) | +| `user:write` | `user` | POST / PUT / PATCH / DELETE routes (verb fallback), inherits `user:read` | + +### `identity` - identity and credential management + +Seeded from the identity service routes. + +| Permission | Role | Notes | +|---|---|---| +| `identity:write` | `identity-admin` | Create/remove DIDs, verification methods, services, also-known-as entries, VCs, presentations, proofs; revoke/unrevoke VCs | + +Verify and resolve operations fall back to verb-based `user:read`. They require authentication but no elevated role. + +### `user:read` / `user:write` - user administration + +Also used by the user admin and identity profile admin routes. Same permission strings as the verb fallback but bound to the `user-admin` role, giving user admins access to all standard user operations and the admin-scoped routes. + +| Permission | Role | Notes | +|---|---|---| +| `user:read` | `user-admin` | Admin get user, admin get by identity, profile admin get, audit query | +| `user:write` | `user-admin` | Admin create/update/remove user, password reset, profile admin update/remove/list, audit create/update/remove; inherits `user:read` | + +### `authorization` - authorization policy management + +Seeded from the authorization service routes. + +| Permission | Role | Notes | +|---|---|---| +| `authorization:read` | `user-admin` | Get policies, roles, role assignments, inheritance | +| `authorization:write` | `user-admin` | Build model, add/remove policies, role assignments, inheritance; inherits `authorization:read` | + +### `health` - server health + +Seeded from the health route. + +| Permission | Role | Notes | +|---|---|---| +| `health:read` | `devops` | Server health status | + +### `logging` - log entry management + +Seeded from the logging service routes. + +| Permission | Role | Notes | +|---|---|---| +| `logging:read` | `devops` | List log entries | +| `logging:write` | `devops` | Create log entries; inherits `logging:read` | + +### `tracing` - distributed tracing + +Seeded from the tracing service routes. + +| Permission | Role | Notes | +|---|---|---| +| `tracing:read` | `devops` | List spans, get traces | +| `tracing:write` | `devops` | Start/end spans; inherits `tracing:read` | + +### `telemetry` - metrics and telemetry + +Seeded from the telemetry service routes. + +| Permission | Role | Notes | +|---|---|---| +| `telemetry:read` | `devops` | Get metrics, list entries, get values | +| `telemetry:write` | `devops` | Create/update/remove metrics, add values; inherits `telemetry:read` | + +### `tenant` - tenant administration (multi-tenant only) + +Seeded from the tenant processor routes when `TWIN_TENANT_ENABLED=true`. + +| Permission | Role | Notes | +|---|---|---| +| `tenant:read` | `tenant-admin` | List and get tenants | +| `tenant:write` | `tenant-admin` | Create, update, and remove tenants; inherits `tenant:read` | + +## Public Routes + +Routes with `skipAuth: true` are excluded from seeding entirely. No token is required to call them. Examples include the information routes (`serverInformation`, `serverSpec`, `serverLivez`, `serverReadyz`) and the public identity profile endpoint (`identityProfileGetPublic`). + +## Verb-Based Fallback + +Routes that require authentication but declare no `defaultAuthorization` receive authorization rules derived from their HTTP method: + +{VerbFallbackDiagram()} + +## Custom Model + +The seeded defaults can be extended or replaced via the `TWIN_AUTHORIZATION_MODEL` environment variable (a JSON object conforming to `IAuthorizationModel`). Set `TWIN_AUTHORIZATION_MODEL_MODE` to `merge` (default) to add custom rules on top of the defaults, or `replace` to use only the custom rules. From 188802d74fddcf5559c2f72436532c9d45356bad Mon Sep 17 00:00:00 2001 From: Martyn Janes Date: Fri, 28 Aug 2026 15:43:01 +0800 Subject: [PATCH 08/17] feat: pr comments --- apps/node/ts-to-openapi.json | 18 +- .../authorization-defaults-diagrams.jsx | 551 +++++++++++------- docs/architecture/authorization-defaults.mdx | 85 +-- packages/node-core/locales/en.json | 3 +- .../src/builders/engineEnvBuilder.ts | 14 +- .../src/builders/engineServerEnvBuilder.ts | 44 +- .../src/builders/helper/migrationHelper.ts | 119 ++++ ...uthorizationSeeder.ts => seedingHelper.ts} | 36 +- .../node-core/src/commands/bootstrapDev.ts | 15 +- packages/node-core/src/defaults.ts | 10 + packages/node-core/src/start.ts | 8 +- .../tests/authorizationSeeder.spec.ts | 9 - .../tests/builders/engineEnvBuilder.spec.ts | 37 +- .../builders/helper/migrationHelper.spec.ts | 301 ++++++++++ packages/node-core/tests/cli.spec.ts | 42 +- .../tests/endpoints/groups/identity.json | 8 +- packages/node-core/tests/index.spec.ts | 180 ++++-- packages/node-core/tests/migration.spec.ts | 1 + 18 files changed, 1113 insertions(+), 368 deletions(-) create mode 100644 packages/node-core/src/builders/helper/migrationHelper.ts rename packages/node-core/src/builders/helper/{authorizationSeeder.ts => seedingHelper.ts} (85%) create mode 100644 packages/node-core/tests/builders/helper/migrationHelper.spec.ts diff --git a/apps/node/ts-to-openapi.json b/apps/node/ts-to-openapi.json index 2fc98330..87877a69 100644 --- a/apps/node/ts-to-openapi.json +++ b/apps/node/ts-to-openapi.json @@ -12,6 +12,9 @@ { "package": "@twin.org/api-auth-entity-storage-service" }, + { + "package": "@twin.org/api-auth-service" + }, { "package": "@twin.org/identity-service" }, @@ -63,23 +66,26 @@ } ] }, - { - "package": "@twin.org/document-management-service" - }, { "package": "@twin.org/federated-catalogue-service" }, { "package": "@twin.org/dataspace-data-plane-service" }, - { - "package": "@twin.org/dataspace-data-plane-service" - }, { "package": "@twin.org/dataspace-control-plane-service" }, { "package": "@twin.org/rights-management-service" + }, + { + "package": "@twin.org/tracing-service" + }, + { + "package": "@twin.org/authorization-service" + }, + { + "package": "@twin.org/api-tenant-processor" } ], "authMethods": ["jwtBearer"], diff --git a/docs/architecture/authorization-defaults-diagrams.jsx b/docs/architecture/authorization-defaults-diagrams.jsx index 718075d7..07b05157 100644 --- a/docs/architecture/authorization-defaults-diagrams.jsx +++ b/docs/architecture/authorization-defaults-diagrams.jsx @@ -5,38 +5,48 @@ const textPrimary = '#1E293B'; const textMuted = '#64748B'; const roles = { - globalAdmin: { label: 'global-admin', bg: '#EDE9FE', color: '#5B21B6', border: '#C4B5FD' }, - identityAdmin:{ label: 'identity-admin', bg: '#E0F2FE', color: '#0369A1', border: '#BAE6FD' }, - userAdmin: { label: 'user-admin', bg: '#CCFBF1', color: '#0F766E', border: '#99F6E4' }, - devops: { label: 'devops', bg: '#FEF3C7', color: '#92400E', border: '#FDE68A' }, - tenantAdmin: { label: 'tenant-admin', bg: '#F3E8FF', color: '#6D28D9', border: '#DDD6FE' }, - user: { label: 'user', bg: '#F1F5F9', color: '#475569', border: '#CBD5E1' }, + globalAdmin: { label: 'global-admin', bg: '#EDE9FE', color: '#5B21B6', border: '#C4B5FD' }, + identityAdmin: { label: 'identity-admin', bg: '#E0F2FE', color: '#0369A1', border: '#BAE6FD' }, + userAdmin: { label: 'user-admin', bg: '#CCFBF1', color: '#0F766E', border: '#99F6E4' }, + identityProfileAdmin: { + label: 'identity-profile-admin', + bg: '#FCE7F3', + color: '#BE185D', + border: '#FBCFE8' + }, + devops: { label: 'devops', bg: '#FEF3C7', color: '#92400E', border: '#FDE68A' }, + tenantAdmin: { label: 'tenant-admin', bg: '#F3E8FF', color: '#6D28D9', border: '#DDD6FE' }, + user: { label: 'user', bg: '#F1F5F9', color: '#475569', border: '#CBD5E1' } }; const perms = { identity: { color: '#0369A1', bg: 'rgba(3,105,161,0.08)' }, - user: { color: '#475569', bg: 'rgba(71,85,105,0.08)' }, - auth: { color: '#0F766E', bg: 'rgba(15,118,110,0.08)' }, - devops: { color: '#92400E', bg: 'rgba(146,64,14,0.08)' }, - tenant: { color: '#6D28D9', bg: 'rgba(109,40,217,0.08)' }, + user: { color: '#475569', bg: 'rgba(71,85,105,0.08)' }, + userAdmin: { color: '#15803D', bg: 'rgba(21,128,61,0.08)' }, + identityProfile: { color: '#BE185D', bg: 'rgba(190,24,93,0.08)' }, + auth: { color: '#0F766E', bg: 'rgba(15,118,110,0.08)' }, + devops: { color: '#92400E', bg: 'rgba(146,64,14,0.08)' }, + tenant: { color: '#6D28D9', bg: 'rgba(109,40,217,0.08)' } }; function RoleChip({ role, small }) { const r = roles[role]; return ( - + {r.label} ); @@ -45,18 +55,20 @@ function RoleChip({ role, small }) { function PermChip({ ns, label }) { const p = perms[ns]; return ( - + {label} ); @@ -67,7 +79,7 @@ export function RoleHierarchyDiagram() { display: 'flex', alignItems: 'center', gap: '10px', - padding: '8px 0', + padding: '8px 0' }; const connectorCol = { @@ -75,34 +87,57 @@ export function RoleHierarchyDiagram() { flexShrink: 0, display: 'flex', flexDirection: 'column', - alignItems: 'center', + alignItems: 'center' }; const rows = [ { role: 'identityAdmin', last: false }, - { role: 'userAdmin', last: false }, - { role: 'devops', last: false, note: null }, - { role: 'tenantAdmin', last: false, note: 'multi-tenant mode only' }, - { role: 'user', last: true, note: 'base authenticated role' }, + { role: 'userAdmin', last: false }, + { role: 'identityProfileAdmin', last: false }, + { role: 'devops', last: false, note: null }, + { role: 'tenantAdmin', last: false, note: 'multi-tenant mode only' }, + { role: 'user', last: true, note: 'base authenticated role' } ]; return ( -
-

+

+

Role Hierarchy

{/* global-admin root */} -
+
- + inherits all roles below
@@ -113,41 +148,56 @@ export function RoleHierarchyDiagram() { {/* tree connector */}
{!last && ( -
+
)} {last && ( -
+ )} +
- )} -
+ top: '50%', + width: '14px', + height: '1px', + background: border + }} + />
{role !== 'user' && ( - + → inherits )} @@ -171,21 +221,61 @@ export function PermissionNamespacesDiagram() { desc: 'Identity and credential management', role: 'identityAdmin', items: [ - { perm: 'identity:write', note: 'Create/remove DIDs, VCs, proofs; revoke/unrevoke credentials' }, - { perm: 'user:read', note: 'Verify VC/presentation, resolve DID (verb fallback)', fallback: true }, - ], + { + perm: 'identity:write', + note: 'Create/remove DIDs, VCs, proofs; revoke and reinstate credentials' + }, + { + perm: 'user:read', + note: 'Resolve DID (GET, verb fallback)', + fallback: true + }, + { + perm: 'user:write', + note: 'Verify VC/VP/proof (POST, verb fallback)', + fallback: true + } + ] }, { ns: 'user', label: 'user:*', - desc: 'Authenticated user operations and user administration', - roles: ['user', 'userAdmin'], + desc: 'Authenticated user operations', + role: 'user', + items: [ + { perm: 'user:read', note: 'Standard GET operations (verb fallback)', fallback: true }, + { + perm: 'user:write', + note: 'Standard POST/PUT/PATCH/DELETE (verb fallback); inherits user:read', + fallback: true + } + ] + }, + { + ns: 'userAdmin', + label: 'user-admin:*', + desc: 'User administration', + role: 'userAdmin', + items: [ + { perm: 'user-admin:read', note: 'Get user, get by identity, get and query audit' }, + { + perm: 'user-admin:write', + note: 'Create/update/remove user, password reset, create/update/remove audit; inherits user-admin:read' + } + ] + }, + { + ns: 'identityProfile', + label: 'identity-profile:*', + desc: 'Identity profile administration', + role: 'identityProfileAdmin', items: [ - { perm: 'user:read', note: 'Standard GET operations (verb fallback)', fallback: true }, - { perm: 'user:write', note: 'Standard POST/PUT/PATCH/DELETE (verb fallback); inherits user:read', fallback: true }, - { perm: 'user:read', note: 'Admin get user, get by identity, profile admin get, audit query', role: 'userAdmin' }, - { perm: 'user:write', note: 'Admin create/update/remove user, password reset, profile admin, audit; inherits user:read', role: 'userAdmin' }, - ], + { perm: 'identity-profile:read', note: 'Get and list identity profiles' }, + { + perm: 'identity-profile:write', + note: 'Update and remove identity profiles; inherits identity-profile:read' + } + ] }, { ns: 'auth', @@ -193,9 +283,15 @@ export function PermissionNamespacesDiagram() { desc: 'Authorization policy management', role: 'userAdmin', items: [ - { perm: 'authorization:read', note: 'Get policies, roles, role assignments, inheritances, check access' }, - { perm: 'authorization:write', note: 'Build model, add/remove policies, role assignments, inheritances; inherits authorization:read' }, - ], + { + perm: 'authorization:read', + note: 'Get policies, roles, role assignments, inheritances, check access' + }, + { + perm: 'authorization:write', + note: 'Build model, add/remove policies, role assignments, inheritances; inherits authorization:read' + } + ] }, { ns: 'devops', @@ -203,14 +299,17 @@ export function PermissionNamespacesDiagram() { desc: 'Observability and infrastructure', role: 'devops', items: [ - { perm: 'health:read', note: 'Server health status' }, - { perm: 'logging:read', note: 'List log entries' }, - { perm: 'logging:write', note: 'Create log entries; inherits logging:read' }, - { perm: 'tracing:read', note: 'List spans, get traces' }, - { perm: 'tracing:write', note: 'Start and end spans; inherits tracing:read' }, - { perm: 'telemetry:read', note: 'Get metrics, list entries, get values' }, - { perm: 'telemetry:write', note: 'Create/update/remove metrics, add values; inherits telemetry:read' }, - ], + { perm: 'health:read', note: 'Server health status' }, + { perm: 'logging:read', note: 'List log entries' }, + { perm: 'logging:write', note: 'Create log entries; inherits logging:read' }, + { perm: 'tracing:read', note: 'List spans, get traces' }, + { perm: 'tracing:write', note: 'Start and end spans; inherits tracing:read' }, + { perm: 'telemetry:read', note: 'Get metrics, list entries, get values' }, + { + perm: 'telemetry:write', + note: 'Create/update/remove metrics, add values; inherits telemetry:read' + } + ] }, { ns: 'tenant', @@ -219,88 +318,103 @@ export function PermissionNamespacesDiagram() { role: 'tenantAdmin', note: 'Seeded only when TWIN_TENANT_ENABLED=true', items: [ - { perm: 'tenant:read', note: 'List and get tenants' }, - { perm: 'tenant:write', note: 'Create, update, and remove tenants; inherits tenant:read' }, - ], - }, + { perm: 'tenant:read', note: 'List and get tenants' }, + { perm: 'tenant:write', note: 'Create, update, and remove tenants; inherits tenant:read' } + ] + } ]; return ( -
+
{namespaces.map(({ ns, label, desc, role, roles: multiRoles, items, note }) => { const p = perms[ns]; return ( -
+
{/* header */} -
- +
+ {label} {desc} {note && ( - {note} + + {note} + )}
- {multiRoles - ? multiRoles.map(r => ) - : - } + {multiRoles ? ( + multiRoles.map(r => ) + ) : ( + + )}
{/* permission rows */}
{items.map((item, i) => ( -
+
{item.fallback && ( - + verb fallback )} - {item.role && !item.fallback && ( - - )} + {item.role && !item.fallback && }
{item.note}
@@ -315,68 +429,95 @@ export function PermissionNamespacesDiagram() { export function VerbFallbackDiagram() { const methods = [ - { method: 'GET', perm: 'user:read', role: 'user', inherits: null }, - { method: 'POST / PUT / PATCH / DELETE', perm: 'user:write', role: 'user', inherits: 'user:read' }, + { method: 'GET', perm: 'user:read', role: 'user', inherits: null }, + { + method: 'POST / PUT / PATCH / DELETE', + perm: 'user:write', + role: 'user', + inherits: 'user:read' + } ]; return ( -
-
+
+
{['HTTP Method', 'Permission', 'Role'].map(h => ( -
+
{h}
))}
{methods.map(({ method, perm, role, inherits }, i) => ( -
-
+
+
{method}
-
+
{inherits && ( - + inherits {inherits} )} diff --git a/docs/architecture/authorization-defaults.mdx b/docs/architecture/authorization-defaults.mdx index f92c3072..f0934695 100644 --- a/docs/architecture/authorization-defaults.mdx +++ b/docs/architecture/authorization-defaults.mdx @@ -3,13 +3,17 @@ category: node order: 10 --- -import { RoleHierarchyDiagram, PermissionNamespacesDiagram, VerbFallbackDiagram } from './authorization-defaults-diagrams.jsx' +import { + RoleHierarchyDiagram, + PermissionNamespacesDiagram, + VerbFallbackDiagram +} from './authorization-defaults-diagrams.jsx'; # Default Authorization Seeding -On startup, `seedAuthorizationDefaults` derives RBAC policies from the registered REST routes and writes them to the authorization store via the authorization component. This happens once, after the engine server has fully started. +On every startup, `seedAuthorizationDefaults` derives RBAC policies from the registered REST routes and writes them to the authorization store via the authorization component. Seeding is additive - policies for operations that no longer exist are not removed, so renaming an operation leaves its old policy in the store. -The function processes every route returned by `server.getRestRoutes()` and builds a set of policies and role inheritances. Routes with `skipAuth: true` or `requiresAuthorization: false` are excluded. +The function processes every route returned by `server.getRestRoutes()`. Routes with an explicit `defaultAuthorization` are always seeded. The verb-based fallback is only applied to routes that both require authentication (`skipAuth` is not `true` and `requiresAuthorization` is not `false`) and declare no `defaultAuthorization`. ## Role Hierarchy @@ -29,86 +33,95 @@ Each permission namespace is seeded from the routes that belong to that namespac Seeded from the verb-based fallback for routes that do not declare an explicit `defaultAuthorization`. -| Permission | Role | Notes | -|---|---|---| -| `user:read` | `user` | GET routes (verb fallback) | +| Permission | Role | Notes | +| ------------ | ------ | ------------------------------------------------------------------------ | +| `user:read` | `user` | GET routes (verb fallback) | | `user:write` | `user` | POST / PUT / PATCH / DELETE routes (verb fallback), inherits `user:read` | ### `identity` - identity and credential management Seeded from the identity service routes. -| Permission | Role | Notes | -|---|---|---| -| `identity:write` | `identity-admin` | Create/remove DIDs, verification methods, services, also-known-as entries, VCs, presentations, proofs; revoke/unrevoke VCs | +| Permission | Role | Notes | +| ---------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------- | +| `identity:write` | `identity-admin` | Create/remove DIDs, verification methods, services, also-known-as entries, VCs, presentations, proofs; revoke and reinstate VCs | -Verify and resolve operations fall back to verb-based `user:read`. They require authentication but no elevated role. +The resolve operation falls back to verb-based `user:read`; verify operations (POST) fall back to `user:write`. Neither requires an elevated role beyond authentication. -### `user:read` / `user:write` - user administration +### `user-admin` - user administration -Also used by the user admin and identity profile admin routes. Same permission strings as the verb fallback but bound to the `user-admin` role, giving user admins access to all standard user operations and the admin-scoped routes. +Seeded from the authentication admin and audit routes. -| Permission | Role | Notes | -|---|---|---| -| `user:read` | `user-admin` | Admin get user, admin get by identity, profile admin get, audit query | -| `user:write` | `user-admin` | Admin create/update/remove user, password reset, profile admin update/remove/list, audit create/update/remove; inherits `user:read` | +| Permission | Role | Notes | +| ------------------ | ------------ | ------------------------------------------------------------------------------------------------- | +| `user-admin:read` | `user-admin` | Get user, get by identity, get and query audit | +| `user-admin:write` | `user-admin` | Create/update/remove user, password reset, create/update/remove audit; inherits `user-admin:read` | + +### `identity-profile` - identity profile administration + +Seeded from the identity profile admin routes. + +| Permission | Role | Notes | +| ------------------------ | ------------------------ | --------------------------------------------------------------------- | +| `identity-profile:read` | `identity-profile-admin` | Get and list identity profiles | +| `identity-profile:write` | `identity-profile-admin` | Update and remove identity profiles; inherits `identity-profile:read` | ### `authorization` - authorization policy management Seeded from the authorization service routes. -| Permission | Role | Notes | -|---|---|---| -| `authorization:read` | `user-admin` | Get policies, roles, role assignments, inheritance | +| Permission | Role | Notes | +| --------------------- | ------------ | ---------------------------------------------------------------------------------------------- | +| `authorization:read` | `user-admin` | Check authorization, get policies, roles, role assignments, inheritance | | `authorization:write` | `user-admin` | Build model, add/remove policies, role assignments, inheritance; inherits `authorization:read` | ### `health` - server health Seeded from the health route. -| Permission | Role | Notes | -|---|---|---| +| Permission | Role | Notes | +| ------------- | -------- | -------------------- | | `health:read` | `devops` | Server health status | ### `logging` - log entry management Seeded from the logging service routes. -| Permission | Role | Notes | -|---|---|---| -| `logging:read` | `devops` | List log entries | +| Permission | Role | Notes | +| --------------- | -------- | ------------------------------------------- | +| `logging:read` | `devops` | List log entries | | `logging:write` | `devops` | Create log entries; inherits `logging:read` | ### `tracing` - distributed tracing Seeded from the tracing service routes. -| Permission | Role | Notes | -|---|---|---| -| `tracing:read` | `devops` | List spans, get traces | +| Permission | Role | Notes | +| --------------- | -------- | ---------------------------------------- | +| `tracing:read` | `devops` | List spans, get traces | | `tracing:write` | `devops` | Start/end spans; inherits `tracing:read` | ### `telemetry` - metrics and telemetry Seeded from the telemetry service routes. -| Permission | Role | Notes | -|---|---|---| -| `telemetry:read` | `devops` | Get metrics, list entries, get values | +| Permission | Role | Notes | +| ----------------- | -------- | ------------------------------------------------------------------- | +| `telemetry:read` | `devops` | Get metrics, list entries, get values | | `telemetry:write` | `devops` | Create/update/remove metrics, add values; inherits `telemetry:read` | ### `tenant` - tenant administration (multi-tenant only) Seeded from the tenant processor routes when `TWIN_TENANT_ENABLED=true`. -| Permission | Role | Notes | -|---|---|---| -| `tenant:read` | `tenant-admin` | List and get tenants | +| Permission | Role | Notes | +| -------------- | -------------- | ---------------------------------------------------------- | +| `tenant:read` | `tenant-admin` | List and get tenants | | `tenant:write` | `tenant-admin` | Create, update, and remove tenants; inherits `tenant:read` | ## Public Routes -Routes with `skipAuth: true` are excluded from seeding entirely. No token is required to call them. Examples include the information routes (`serverInformation`, `serverSpec`, `serverLivez`, `serverReadyz`) and the public identity profile endpoint (`identityProfileGetPublic`). +Routes with `skipAuth: true` are excluded from the verb-based fallback only. If such a route also declares an explicit `defaultAuthorization`, that policy is still seeded. A route that is purely public - `skipAuth: true` with no `defaultAuthorization` - receives no seeded policy. Examples of purely public routes include the information routes (`serverInformation`, `serverSpec`, `serverLivez`, `serverReadyz`) and the public identity profile endpoint (`identityProfileGetPublic`). ## Verb-Based Fallback @@ -118,4 +131,6 @@ Routes that require authentication but declare no `defaultAuthorization` receive ## Custom Model -The seeded defaults can be extended or replaced via the `TWIN_AUTHORIZATION_MODEL` environment variable (a JSON object conforming to `IAuthorizationModel`). Set `TWIN_AUTHORIZATION_MODEL_MODE` to `merge` (default) to add custom rules on top of the defaults, or `replace` to use only the custom rules. +The seeded defaults can be extended or replaced via the `TWIN_AUTHORIZATION_MODEL` environment variable (a JSON object conforming to `IAuthorizationModel`). Set `TWIN_AUTHORIZATION_MODEL_MODE` to `merge` (default) to add custom rules on top of the defaults, or `replace` to skip the route-derived defaults and use only the custom rules. + +Because seeding is additive, `replace` mode only controls what is passed on the current startup - it cannot remove policies already written to the store in a previous run. diff --git a/packages/node-core/locales/en.json b/packages/node-core/locales/en.json index ffdf7209..b64a113a 100644 --- a/packages/node-core/locales/en.json +++ b/packages/node-core/locales/en.json @@ -16,7 +16,8 @@ "cliEnvVarMissing": "Environment variable \"{envVar}\" does not exist", "invalidEnvVarValue": "Environment variable \"{key}\" has an invalid value \"{value}\", expected {type} type", "invalidEnvVarPair": "Environment variable \"{key}\" has an invalid entry \"{value}\", expected unique name=integer pairs", - "unknownEnvVars": "Unknown environment variable properties [{keys}]. Check for typos in variable names, for custom variables use the {prefix}ENV_ALLOW_LIST." + "unknownEnvVars": "Unknown environment variable properties [{keys}]. Check for typos in variable names, for custom variables use the {prefix}ENV_ALLOW_LIST.", + "migrationAuthorizationComponent": "Authorization is now a required component, please add it to your configuration." }, "bootstrapDev": { "noFeaturesEnabled": "No features are enabled, at least one feature must be enabled.", diff --git a/packages/node-core/src/builders/engineEnvBuilder.ts b/packages/node-core/src/builders/engineEnvBuilder.ts index 3a727fdf..5d121d95 100644 --- a/packages/node-core/src/builders/engineEnvBuilder.ts +++ b/packages/node-core/src/builders/engineEnvBuilder.ts @@ -1,7 +1,7 @@ // Copyright 2024 IOTA Stiftung. // SPDX-License-Identifier: Apache-2.0. import path from "node:path"; -import { Is, Mutex } from "@twin.org/core"; +import { GeneralError, Is, Mutex } from "@twin.org/core"; import type { IIotaConfig } from "@twin.org/dlt-iota"; import { EngineCloneMode } from "@twin.org/engine-models"; import { @@ -97,11 +97,7 @@ import { type IOpenTelemetryTracingConnectorConfig, OpenTelemetryProcessorTypes } from "@twin.org/tracing-connector-opentelemetry"; -import { - AUTHORIZATION_MODEL_ID, - CONTEXT_ID_HANDLER_FEATURE_DID, - CONTEXT_ID_HANDLER_FEATURE_TENANT -} from "../defaults.js"; +import { CONTEXT_ID_HANDLER_FEATURE_DID, CONTEXT_ID_HANDLER_FEATURE_TENANT } from "../defaults.js"; import { isAuthEntityStorageRequired } from "./engineServerEnvBuilder.js"; import type { IEngineEnvironmentVariables } from "../models/IEngineEnvironmentVariables.js"; import { @@ -115,8 +111,7 @@ import { envMinutes, envMs, envSeconds, - envSecToMs, - envString + envSecToMs } from "./helper/envHelpers.js"; /** @@ -935,6 +930,8 @@ async function configureAuthorization( } } }); + } else { + throw new GeneralError("node", "migrationAuthorizationComponent"); } if (coreConfig.types.authorizationConnector.length > 0) { @@ -944,7 +941,6 @@ async function configureAuthorization( type: AuthorizationComponentType.Service, options: { config: { - migrationModelId: envString(envVars, "authorizationModelId", AUTHORIZATION_MODEL_ID), checkCacheCapacity: envInteger(envVars, "authorizationCheckCacheCapacity"), checkCacheTtiMs: envMs(envVars, "authorizationCheckCacheTtiMs") } diff --git a/packages/node-core/src/builders/engineServerEnvBuilder.ts b/packages/node-core/src/builders/engineServerEnvBuilder.ts index b689b1a6..3cd0105f 100644 --- a/packages/node-core/src/builders/engineServerEnvBuilder.ts +++ b/packages/node-core/src/builders/engineServerEnvBuilder.ts @@ -267,26 +267,42 @@ export async function buildEngineServerConfiguration( } } }); - if (tenantEnabled && isAuthorizationRequired(envVars)) { + if (isAuthorizationRequired(envVars)) { serverConfig.types.restRouteProcessor.push({ - type: RestRouteProcessorType.TenantOverride, - options: { - config: { - authorizationModelId: envString(envVars, "authorizationModelId", AUTHORIZATION_MODEL_ID) - } - } + type: RestRouteProcessorType.Authorization }); serverConfig.types.socketRouteProcessor.push({ - type: SocketRouteProcessorType.TenantOverride, - options: { - config: { - authorizationModelId: envString(envVars, "authorizationModelId", AUTHORIZATION_MODEL_ID) - } - } + type: SocketRouteProcessorType.Authorization }); + + if (tenantEnabled) { + serverConfig.types.restRouteProcessor.push({ + type: RestRouteProcessorType.TenantOverride, + options: { + config: { + authorizationModelId: envString( + envVars, + "authorizationModelId", + AUTHORIZATION_MODEL_ID + ) + } + } + }); + serverConfig.types.socketRouteProcessor.push({ + type: SocketRouteProcessorType.TenantOverride, + options: { + config: { + authorizationModelId: envString( + envVars, + "authorizationModelId", + AUTHORIZATION_MODEL_ID + ) + } + } + }); + } } } - if (isTelemetryEnabled(envVars)) { serverConfig.types.restRouteProcessor.push({ type: RestRouteProcessorType.Metrics, diff --git a/packages/node-core/src/builders/helper/migrationHelper.ts b/packages/node-core/src/builders/helper/migrationHelper.ts new file mode 100644 index 00000000..3a625a76 --- /dev/null +++ b/packages/node-core/src/builders/helper/migrationHelper.ts @@ -0,0 +1,119 @@ +// Copyright 2026 IOTA Stiftung. +// SPDX-License-Identifier: Apache-2.0. +import type { + AuthenticationUser, + AuthenticationUserV0 +} from "@twin.org/api-auth-entity-storage-service"; +import type { IAuthorizationComponent } from "@twin.org/authorization-models"; +import { ContextIdStore, type IContextIds } from "@twin.org/context"; +import { Is, ComponentFactory } from "@twin.org/core"; +import type { IEngineCore } from "@twin.org/engine-models"; +import type { IEntitySchemaProperty } from "@twin.org/entity"; +import type { ISchemaMigration } from "@twin.org/entity-storage-models"; +import { SchemaMigrationFactory } from "@twin.org/entity-storage-models"; +import { nameof } from "@twin.org/nameof"; +import { envBoolean, envString } from "./envHelpers.js"; +import { + AUTHORIZATION_MODEL_ID, + DEFAULT_DEVOPS_ROLE, + DEFAULT_TENANT_ADMIN_ROLE, + DEFAULT_USER_ADMIN_ROLE, + DEFAULT_IDENTITY_PROFILE_ADMIN_ROLE, + DEFAULT_USER_ROLE +} from "../../defaults.js"; +import type { IEnvironmentVariables } from "../../models/IEnvironmentVariables.js"; + +const migrateRoles: { identity: string; roles: string[]; contextIds: IContextIds | undefined }[] = + []; + +/** + * Initialise schema migrations for the engine. + * @param engineCore The engine core instance. + * @param envVars The environment variables. + */ +export function initialiseMigrations( + engineCore: IEngineCore, + envVars: IEnvironmentVariables +): void { + if (!envBoolean(envVars, "schemaMigrationEnabled", true)) { + return; + } + + const migrationV0V1: ISchemaMigration = { + removeEntityProperty: async ( + entity: AuthenticationUserV0, + removedProperties: IEntitySchemaProperty[] + ): Promise => { + // If the scope property is not being removed, we don't need to do anything + if (removedProperties.find(prop => prop.property === "scope") === undefined) { + return; + } + + let roles: string[] = []; + if (Is.stringValue(entity.scope)) { + roles = entity.scope + .split(",") + .map(role => role.trim().toLocaleLowerCase()) + .filter(role => role.length > 0); + } + if (roles.length === 0) { + roles.push(DEFAULT_USER_ROLE); + } + + // If the user has both tenant-admin and user-admin roles, we also add the new roles + // to provide access to everything they had before + if (roles.includes(DEFAULT_TENANT_ADMIN_ROLE) && roles.includes(DEFAULT_USER_ADMIN_ROLE)) { + roles.push(DEFAULT_DEVOPS_ROLE); + roles.push(DEFAULT_IDENTITY_PROFILE_ADMIN_ROLE); + } + + // We need to store the old roles in here if a migration is performed + // they will be picked up by the start method of the AuthenticationService + // and used to populate the new roles table in the correct partition. + // The same identity can exist across multiple partitions so we accumulate + // entries as an array keyed by contextIds rather than by identity alone. + const contextIds: IContextIds | undefined = await ContextIdStore.getContextIds(); + migrateRoles.push({ + identity: entity.identity, + roles, + contextIds + }); + } + }; + SchemaMigrationFactory.register( + `${nameof()}_0_1`, + () => migrationV0V1 as ISchemaMigration + ); +} + +/** + * Finalize schema migrations by clearing any temporary data stored in the shared store. + * This should be called after all migrations have been processed to ensure that + * any temporary data used during the migration process is removed. + * @param engineCore The engine core instance. + * @param envVars The environment variables. + */ +export async function finalizeMigrations( + engineCore: IEngineCore, + envVars: IEnvironmentVariables +): Promise { + if (Is.arrayValue(migrateRoles)) { + // If a migration of the roles from the old authenticated users has just happened + // the old roles will be stored in the SharedStore, if they exist then we need + // to populate them in the authorization service. + const authComponentType = engineCore.getRegisteredInstanceType("authorizationComponent"); + + const authorizationComponent = ComponentFactory.get(authComponentType); + + const migrationModelId = envString(envVars, "authorizationModelId", AUTHORIZATION_MODEL_ID); + + for (const entry of migrateRoles) { + await ContextIdStore.run(entry.contextIds ?? {}, async () => { + for (const role of entry.roles) { + await authorizationComponent.addRoleForSubject(migrationModelId, entry.identity, role); + } + }); + } + migrateRoles.length = 0; + } +} diff --git a/packages/node-core/src/builders/helper/authorizationSeeder.ts b/packages/node-core/src/builders/helper/seedingHelper.ts similarity index 85% rename from packages/node-core/src/builders/helper/authorizationSeeder.ts rename to packages/node-core/src/builders/helper/seedingHelper.ts index 214e3e99..2298e6b2 100644 --- a/packages/node-core/src/builders/helper/authorizationSeeder.ts +++ b/packages/node-core/src/builders/helper/seedingHelper.ts @@ -1,15 +1,15 @@ // Copyright 2026 IOTA Stiftung. // SPDX-License-Identifier: Apache-2.0. -import type { IPlatformComponent, IRestRoute, IRouteAuthorization } from "@twin.org/api-models"; +import type { IPlatformComponent, IRouteAuthorization } from "@twin.org/api-models"; import type { IAuthorizationComponent, IAuthorizationInheritance, IAuthorizationModel, IAuthorizationPolicy } from "@twin.org/authorization-models"; -import { ContextIdStore } from "@twin.org/context"; +import { ContextIdKeys, ContextIdStore } from "@twin.org/context"; import { ComponentFactory, Is } from "@twin.org/core"; -import type { IEngineCore } from "@twin.org/engine-models"; +import type { IEngineCore, IEngineServer } from "@twin.org/engine-models"; import { HttpMethod } from "@twin.org/web"; import { envObject, envString } from "./envHelpers.js"; import { @@ -34,26 +34,21 @@ const DEFAULT_AUTHORIZATION_WRITER: IRouteAuthorization = { * Seed default authorization policies and role inheritances after the engine has started. * Uses the platform component to execute across all tenants in multi-tenant mode. * @param engineCore The running engine core. + * @param engineServer The running engine server. * @param envVars The environment variables. - * @param routes The REST routes to derive default policies from. */ export async function seedAuthorizationDefaults( engineCore: IEngineCore, - envVars: IEngineEnvironmentVariables, - routes: IRestRoute[] + engineServer: IEngineServer, + envVars: IEngineEnvironmentVariables ): Promise { const nodeContextIds = engineCore.getContextIds() ?? {}; if (!Is.stringValue(nodeContextIds.node)) { return; } - const authComponentType = engineCore.getRegisteredInstanceTypeOptional("authorizationComponent"); - const platformComponentType = engineCore.getRegisteredInstanceTypeOptional("platformComponent"); - - if (!Is.stringValue(authComponentType) || !Is.stringValue(platformComponentType)) { - return; - } - + const authComponentType = engineCore.getRegisteredInstanceType("authorizationComponent"); + const platformComponentType = engineCore.getRegisteredInstanceType("platformComponent"); const platformComponent = ComponentFactory.get(platformComponentType); const authorizationComponent = ComponentFactory.get(authComponentType); @@ -89,6 +84,7 @@ export async function seedAuthorizationDefaults( const inheritanceKeys = new Set(); const roles = new Set(); + const routes = engineServer.getRestRoutes(); for (const route of routes) { const requiresAuthorization = route.requiresAuthorization !== false && route.skipAuth !== true; @@ -157,4 +153,18 @@ export async function seedAuthorizationDefaults( await authorizationComponent.build(modelId, model); }); }); + + platformComponent.registerTenantEventCallback( + "seedAuthorizationDefaults", + async (tenantId, eventType) => { + if (eventType === "created") { + await ContextIdStore.run( + { ...nodeContextIds, [ContextIdKeys.Tenant]: tenantId }, + async () => { + await authorizationComponent.build(modelId, model); + } + ); + } + } + ); } diff --git a/packages/node-core/src/commands/bootstrapDev.ts b/packages/node-core/src/commands/bootstrapDev.ts index c78e2cbf..0c145caf 100644 --- a/packages/node-core/src/commands/bootstrapDev.ts +++ b/packages/node-core/src/commands/bootstrapDev.ts @@ -8,9 +8,11 @@ import { Coerce, ComponentFactory, GeneralError, I18n, Is } from "@twin.org/core import type { IEngineCore } from "@twin.org/engine-models"; import { commaSeparatedListToArray } from "../builders/helper/envHelpers.js"; import { + DEFAULT_DEVOPS_ROLE, DEFAULT_ESCALATED_PRIVILEGE_ROLE, DEFAULT_TENANT_ADMIN_ROLE, - DEFAULT_USER_ADMIN_ROLE + DEFAULT_USER_ADMIN_ROLE, + DEFAULT_IDENTITY_PROFILE_ADMIN_ROLE } from "../defaults.js"; import { identityCreate } from "./identityCreate.js"; import { identityVerificationMethodCreate } from "./identityVerificationMethodCreate.js"; @@ -273,9 +275,16 @@ export async function bootstrapDev( ? [ DEFAULT_ESCALATED_PRIVILEGE_ROLE, DEFAULT_TENANT_ADMIN_ROLE, - DEFAULT_USER_ADMIN_ROLE + DEFAULT_USER_ADMIN_ROLE, + DEFAULT_IDENTITY_PROFILE_ADMIN_ROLE, + DEFAULT_DEVOPS_ROLE + ] + : [ + DEFAULT_ESCALATED_PRIVILEGE_ROLE, + DEFAULT_USER_ADMIN_ROLE, + DEFAULT_IDENTITY_PROFILE_ADMIN_ROLE, + DEFAULT_DEVOPS_ROLE ] - : [DEFAULT_ESCALATED_PRIVILEGE_ROLE, DEFAULT_USER_ADMIN_ROLE] ).join(","), givenName: tenantEnabled ? "Tenant" : "Node", familyName: "Admin", diff --git a/packages/node-core/src/defaults.ts b/packages/node-core/src/defaults.ts index fd160d46..c9292da5 100644 --- a/packages/node-core/src/defaults.ts +++ b/packages/node-core/src/defaults.ts @@ -56,6 +56,16 @@ export const DEFAULT_TENANT_ADMIN_ROLE = "tenant-admin"; */ export const DEFAULT_USER_ADMIN_ROLE = "user-admin"; +/** + * Default role for identity profile admins. + */ +export const DEFAULT_IDENTITY_PROFILE_ADMIN_ROLE = "identity-profile-admin"; + +/** + * Default role for devops. + */ +export const DEFAULT_DEVOPS_ROLE = "devops"; + /** * Default role for users. */ diff --git a/packages/node-core/src/start.ts b/packages/node-core/src/start.ts index d2efbea3..0d1e8e4a 100644 --- a/packages/node-core/src/start.ts +++ b/packages/node-core/src/start.ts @@ -19,8 +19,9 @@ import { extensionsInitialiseEngineServer, shutdownExtensions } from "./builders/extensionsBuilder.js"; -import { seedAuthorizationDefaults } from "./builders/helper/authorizationSeeder.js"; import { commaSeparatedListToArray } from "./builders/helper/envHelpers.js"; +import { finalizeMigrations, initialiseMigrations } from "./builders/helper/migrationHelper.js"; +import { seedAuthorizationDefaults } from "./builders/helper/seedingHelper.js"; import { executeCommand } from "./cli.js"; import type { ICliCommand } from "./models/ICliCommand.js"; import type { IEngineEnvironmentVariables } from "./models/IEngineEnvironmentVariables.js"; @@ -124,10 +125,13 @@ export async function start( await executeCommand(engine, envVars, cliCommand); } else { try { + initialiseMigrations(engine, envVars); + // Start the server, which also starts the engine. await server.start(); - await seedAuthorizationDefaults(engine, envVars, server.getRestRoutes()); + await seedAuthorizationDefaults(engine, server, envVars); + await finalizeMigrations(engine, envVars); return { engine, diff --git a/packages/node-core/tests/authorizationSeeder.spec.ts b/packages/node-core/tests/authorizationSeeder.spec.ts index 16775174..b3afda67 100644 --- a/packages/node-core/tests/authorizationSeeder.spec.ts +++ b/packages/node-core/tests/authorizationSeeder.spec.ts @@ -87,15 +87,6 @@ describe("seedAuthorizationDefaults", () => { TWIN_AUTH_PROCESSOR_TYPE: AuthenticationComponentType.EntityStorage }; - test("skips seeding when authorization component is not registered", async () => { - const startResult = await startServer({ - ...baseMinimalEnvVars, - TWIN_PORT: port.toString() - }); - expect(startResult).toBeDefined(); - await startResult?.shutdown(); - }, 30000); - test("seeds route-derived policies for all routes with defaultAuthorization on startup", async () => { const startResult = await startServer({ ...baseAuthEnvVars, diff --git a/packages/node-core/tests/builders/engineEnvBuilder.spec.ts b/packages/node-core/tests/builders/engineEnvBuilder.spec.ts index 369653fb..1a41f603 100644 --- a/packages/node-core/tests/builders/engineEnvBuilder.spec.ts +++ b/packages/node-core/tests/builders/engineEnvBuilder.spec.ts @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0. import type { IIotaConfig } from "@twin.org/dlt-iota"; import { + AuthorizationConnectorType, DataspaceControlPlaneComponentType, DltConfigType, EntityStorageConnectorType, @@ -15,9 +16,11 @@ import { } from "@twin.org/engine-types"; import { buildEngineConfiguration } from "../../src/builders/engineEnvBuilder.js"; +const AUTH = { authorizationConnector: AuthorizationConnectorType.EntityStorage } as const; + describe("buildEngineConfiguration - schemaMigrationEnabled", () => { test("schema migration service is registered when schemaMigrationEnabled is unset (default true)", async () => { - const config = await buildEngineConfiguration({}); + const config = await buildEngineConfiguration({ ...AUTH }); expect(config.types.schemaVersionMigrationComponent).toEqual( expect.arrayContaining([ @@ -27,7 +30,7 @@ describe("buildEngineConfiguration - schemaMigrationEnabled", () => { }); test("schema migration service is registered when schemaMigrationEnabled is 'true'", async () => { - const config = await buildEngineConfiguration({ schemaMigrationEnabled: "true" }); + const config = await buildEngineConfiguration({ ...AUTH, schemaMigrationEnabled: "true" }); expect(config.types.schemaVersionMigrationComponent).toEqual( expect.arrayContaining([ @@ -37,7 +40,7 @@ describe("buildEngineConfiguration - schemaMigrationEnabled", () => { }); test("schema migration service is registered with enabled:false when schemaMigrationEnabled is 'false'", async () => { - const config = await buildEngineConfiguration({ schemaMigrationEnabled: "false" }); + const config = await buildEngineConfiguration({ ...AUTH, schemaMigrationEnabled: "false" }); expect(config.types.schemaVersionMigrationComponent).toEqual( expect.arrayContaining([ @@ -52,7 +55,7 @@ describe("buildEngineConfiguration - schemaMigrationEnabled", () => { describe("buildEngineConfiguration - task scheduler requirement", () => { test("task scheduler is registered when only auditableItemGraphEnabled is set", async () => { - const config = await buildEngineConfiguration({ auditableItemGraphEnabled: "true" }); + const config = await buildEngineConfiguration({ ...AUTH, auditableItemGraphEnabled: "true" }); expect(config.types.taskSchedulerComponent).toEqual( expect.arrayContaining([ @@ -62,7 +65,7 @@ describe("buildEngineConfiguration - task scheduler requirement", () => { }); test("task scheduler is not registered when no dependent component is enabled", async () => { - const config = await buildEngineConfiguration({}); + const config = await buildEngineConfiguration({ ...AUTH }); expect(config.types.taskSchedulerComponent).toBeUndefined(); }); @@ -71,6 +74,7 @@ describe("buildEngineConfiguration - task scheduler requirement", () => { describe("buildEngineConfiguration - IOTA DLT gas config", () => { test("iotaGasBudget and iotaGasReservationDuration env vars are wired through to the resolved config", async () => { const config = await buildEngineConfiguration({ + ...AUTH, iotaNodeEndpoint: "https://api.testnet.iota.cafe", iotaNetwork: "testnet", iotaGasBudget: "123456789", @@ -88,6 +92,7 @@ describe("buildEngineConfiguration - IOTA DLT gas config", () => { test("leaving both env vars unset preserves today's behavior (fields stay undefined)", async () => { const config = await buildEngineConfiguration({ + ...AUTH, iotaNodeEndpoint: "https://api.testnet.iota.cafe", iotaNetwork: "testnet" }); @@ -103,6 +108,7 @@ describe("buildEngineConfiguration - IOTA DLT gas config", () => { test("existing coinType and gasStation fields still resolve correctly alongside the new ones", async () => { const config = await buildEngineConfiguration({ + ...AUTH, iotaNodeEndpoint: "https://api.testnet.iota.cafe", iotaNetwork: "testnet", iotaCoinType: "4218", @@ -130,6 +136,7 @@ describe("buildEngineConfiguration - IOTA DLT gas config", () => { describe("buildEngineConfiguration - dataspace provider idle transfer policy", () => { test("provider idle policy values are wired in seconds and converted to milliseconds", async () => { const config = await buildEngineConfiguration({ + ...AUTH, dataspaceEnabled: "true", dataspaceProviderTransferIdleTimeout: "120", dataspaceProviderTransferPolicySweepInterval: "15" @@ -150,6 +157,7 @@ describe("buildEngineConfiguration - dataspace provider idle transfer policy", ( test("unset provider idle policy values keep existing behaviour unchanged", async () => { const config = await buildEngineConfiguration({ + ...AUTH, dataspaceEnabled: "true" }); @@ -170,6 +178,7 @@ describe("buildEngineConfiguration - dataspace provider idle transfer policy", ( describe("buildEngineConfiguration - entity storage shared mutex timeout", () => { test("entity storage mutex timeout applies to both memory and file connectors", async () => { const config = await buildEngineConfiguration({ + ...AUTH, entityStorageConnectorType: "memory,file", entityStorageMutexTimeout: "4321", storageFileRoot: "." @@ -194,6 +203,7 @@ describe("buildEngineConfiguration - entity storage shared mutex timeout", () => test("entity storage mutex timeout is unset when the env var is empty", async () => { const config = await buildEngineConfiguration({ + ...AUTH, entityStorageConnectorType: "memory,file", storageFileRoot: "." }); @@ -228,6 +238,7 @@ describe("buildEngineConfiguration - entity storage pool options", () => { test("postgresql pool env vars are wired to the connector config", async () => { const config = await buildEngineConfiguration({ + ...AUTH, entityStorageConnectorType: "postgresql", postgreSqlHost: "localhost", postgreSqlUser: "u", @@ -245,6 +256,7 @@ describe("buildEngineConfiguration - entity storage pool options", () => { test("postgresql pool fields are undefined when pool env vars are not set", async () => { const config = await buildEngineConfiguration({ + ...AUTH, entityStorageConnectorType: "postgresql", postgreSqlHost: "localhost", postgreSqlUser: "u", @@ -261,6 +273,7 @@ describe("buildEngineConfiguration - entity storage pool options", () => { test("mysql pool env vars are wired to the connector config", async () => { const config = await buildEngineConfiguration({ + ...AUTH, entityStorageConnectorType: "mysql", mySqlHost: "localhost", mySqlUser: "u", @@ -287,6 +300,7 @@ describe("buildEngineConfiguration - entity storage pool options", () => { test("mysql pool fields are undefined when pool env vars are not set", async () => { const config = await buildEngineConfiguration({ + ...AUTH, entityStorageConnectorType: "mysql", mySqlHost: "localhost", mySqlUser: "u", @@ -301,6 +315,7 @@ describe("buildEngineConfiguration - entity storage pool options", () => { test("mongodb pool env vars are wired to the connector config", async () => { const config = await buildEngineConfiguration({ + ...AUTH, entityStorageConnectorType: "mongodb", mongoDbHost: "localhost", mongoDbDatabase: "db", @@ -321,6 +336,7 @@ describe("buildEngineConfiguration - entity storage pool options", () => { test("mongodb pool fields are undefined when pool env vars are not set", async () => { const config = await buildEngineConfiguration({ + ...AUTH, entityStorageConnectorType: "mongodb", mongoDbHost: "localhost", mongoDbDatabase: "db" @@ -333,6 +349,7 @@ describe("buildEngineConfiguration - entity storage pool options", () => { test("scylladb pool env vars are wired to the connector config", async () => { const config = await buildEngineConfiguration({ + ...AUTH, entityStorageConnectorType: "scylladb", scylladbHosts: "localhost", scylladbLocalDataCenter: "dc1", @@ -347,6 +364,7 @@ describe("buildEngineConfiguration - entity storage pool options", () => { test("scylladb pool fields are undefined when pool env vars are not set", async () => { const config = await buildEngineConfiguration({ + ...AUTH, entityStorageConnectorType: "scylladb", scylladbHosts: "localhost", scylladbLocalDataCenter: "dc1", @@ -361,7 +379,7 @@ describe("buildEngineConfiguration - entity storage pool options", () => { describe("buildEngineConfiguration - logging multi-connector", () => { test("single logging connector is marked as default", async () => { - const config = await buildEngineConfiguration({ loggingConnector: "console" }); + const config = await buildEngineConfiguration({ ...AUTH, loggingConnector: "console" }); const connectors = config.types.loggingConnector ?? []; const consoleConnector = connectors.find(c => c.type === LoggingConnectorType.Console); @@ -374,6 +392,7 @@ describe("buildEngineConfiguration - logging multi-connector", () => { test("two logging connectors produce a multi connector set as the default", async () => { const config = await buildEngineConfiguration({ + ...AUTH, loggingConnector: "console,entity-storage" }); @@ -394,6 +413,7 @@ describe("buildEngineConfiguration - logging multi-connector", () => { describe("buildEngineConfiguration - telemetry multi-connector", () => { test("single telemetry connector is marked as default and service component is registered", async () => { const config = await buildEngineConfiguration({ + ...AUTH, telemetryConnector: TelemetryConnectorType.EntityStorage }); @@ -411,6 +431,7 @@ describe("buildEngineConfiguration - telemetry multi-connector", () => { test("two telemetry connectors produce a multi connector set as the default", async () => { const config = await buildEngineConfiguration({ + ...AUTH, telemetryConnector: `${TelemetryConnectorType.EntityStorage},${TelemetryConnectorType.OpenTelemetry}` }); @@ -432,6 +453,7 @@ describe("buildEngineConfiguration - telemetry multi-connector", () => { test("silent telemetry connector is marked as default and service component is registered", async () => { const config = await buildEngineConfiguration({ + ...AUTH, telemetryConnector: TelemetryConnectorType.Silent }); @@ -451,6 +473,7 @@ describe("buildEngineConfiguration - telemetry multi-connector", () => { describe("buildEngineConfiguration - tracing multi-connector", () => { test("single tracing connector is marked as default and service component is registered", async () => { const config = await buildEngineConfiguration({ + ...AUTH, tracingConnector: TracingConnectorType.EntityStorage }); @@ -468,6 +491,7 @@ describe("buildEngineConfiguration - tracing multi-connector", () => { test("two tracing connectors produce a multi connector set as the default", async () => { const config = await buildEngineConfiguration({ + ...AUTH, tracingConnector: `${TracingConnectorType.EntityStorage},${TracingConnectorType.OpenTelemetry}` }); @@ -489,6 +513,7 @@ describe("buildEngineConfiguration - tracing multi-connector", () => { test("silent tracing connector is marked as default and service component is registered", async () => { const config = await buildEngineConfiguration({ + ...AUTH, tracingConnector: TracingConnectorType.Silent }); diff --git a/packages/node-core/tests/builders/helper/migrationHelper.spec.ts b/packages/node-core/tests/builders/helper/migrationHelper.spec.ts new file mode 100644 index 00000000..584e0925 --- /dev/null +++ b/packages/node-core/tests/builders/helper/migrationHelper.spec.ts @@ -0,0 +1,301 @@ +// Copyright 2026 IOTA Stiftung. +// SPDX-License-Identifier: Apache-2.0. +import type { IAuthorizationComponent } from "@twin.org/authorization-models"; +import { ContextIdStore } from "@twin.org/context"; +import { ComponentFactory, GeneralError } from "@twin.org/core"; +import type { IEngineCore } from "@twin.org/engine-models"; +import type { IEntitySchemaProperty } from "@twin.org/entity"; +import type { ISchemaMigration } from "@twin.org/entity-storage-models"; +import { SchemaMigrationFactory } from "@twin.org/entity-storage-models"; +import { + finalizeMigrations, + initialiseMigrations +} from "../../../src/builders/helper/migrationHelper.js"; +import { AUTHORIZATION_MODEL_ID } from "../../../src/defaults.js"; + +const MIGRATION_KEY = "AuthenticationUser_0_1"; +const AUTH_COMPONENT_TYPE = "test-authorization-component"; + +type RemoveEntityPropertyFn = NonNullable; + +const SCOPE_PROP = [{ property: "scope" } as unknown as IEntitySchemaProperty]; + +describe("initialiseMigrations", () => { + let callRemoveEntityProperty: RemoveEntityPropertyFn; + let mockEngineCore: IEngineCore; + let mockAddRoleForSubject: ReturnType; + let getRegisteredInstanceTypeOptional: ReturnType; + + beforeAll(() => { + getRegisteredInstanceTypeOptional = vi.fn().mockReturnValue(AUTH_COMPONENT_TYPE); + mockEngineCore = { + getRegisteredInstanceTypeOptional, + getRegisteredInstanceType: vi.fn().mockReturnValue(AUTH_COMPONENT_TYPE) + } as unknown as IEngineCore; + + mockAddRoleForSubject = vi.fn().mockResolvedValue(undefined); + ComponentFactory.register( + AUTH_COMPONENT_TYPE, + () => + ({ + addRoleForSubject: mockAddRoleForSubject + }) as unknown as IAuthorizationComponent + ); + + initialiseMigrations(mockEngineCore, {}); + const migration = SchemaMigrationFactory.get(MIGRATION_KEY); + const { removeEntityProperty } = migration; + if (!removeEntityProperty) { + throw new Error("removeEntityProperty not registered on migration"); + } + callRemoveEntityProperty = removeEntityProperty; + }); + + afterAll(() => { + try { + SchemaMigrationFactory.unregister(MIGRATION_KEY); + } catch { + // Ignore if already removed. + } + try { + ComponentFactory.unregister(AUTH_COMPONENT_TYPE); + } catch { + // Ignore if already removed. + } + }); + + afterEach(async () => { + // Drain any queued roles accumulated during the test to prevent cross-test pollution. + await finalizeMigrations(mockEngineCore, {}); + mockAddRoleForSubject.mockClear(); + }); + + test("registers the AuthenticationUser_0_1 migration with SchemaMigrationFactory", () => { + expect(typeof callRemoveEntityProperty).toBe("function"); + }); + + test("removeEntityProperty is a no-op when scope is not in removedProperties", async () => { + await callRemoveEntityProperty({ identity: "did:twin:user1", scope: "admin" }, []); + await finalizeMigrations(mockEngineCore, {}); + expect(mockAddRoleForSubject).not.toHaveBeenCalled(); + }); + + test("removeEntityProperty is a no-op when removedProperties contains other fields but not scope", async () => { + await callRemoveEntityProperty({ identity: "did:twin:user1", scope: "admin" }, [ + { property: "password" } as unknown as IEntitySchemaProperty + ]); + await finalizeMigrations(mockEngineCore, {}); + expect(mockAddRoleForSubject).not.toHaveBeenCalled(); + }); + + test("initialiseMigrations is a no-op when schema migration is disabled", () => { + SchemaMigrationFactory.clear(); + initialiseMigrations(mockEngineCore, { schemaMigrationEnabled: "false" }); + expect(SchemaMigrationFactory.names()).toHaveLength(0); + }); + + test("removeEntityProperty splits comma-separated scope into individual roles", async () => { + await ContextIdStore.run({ node: "test-node" }, async () => { + await callRemoveEntityProperty( + { identity: "did:twin:user1", scope: "global-admin,user-admin" }, + SCOPE_PROP + ); + }); + await finalizeMigrations(mockEngineCore, {}); + expect(mockAddRoleForSubject).toHaveBeenCalledTimes(2); + expect(mockAddRoleForSubject).toHaveBeenCalledWith( + AUTHORIZATION_MODEL_ID, + "did:twin:user1", + "global-admin" + ); + expect(mockAddRoleForSubject).toHaveBeenCalledWith( + AUTHORIZATION_MODEL_ID, + "did:twin:user1", + "user-admin" + ); + }); + + test("removeEntityProperty trims whitespace and lowercases roles", async () => { + await ContextIdStore.run({ node: "test-node" }, async () => { + await callRemoveEntityProperty( + { identity: "did:twin:user1", scope: " ADMIN , User " }, + SCOPE_PROP + ); + }); + await finalizeMigrations(mockEngineCore, {}); + expect(mockAddRoleForSubject).toHaveBeenCalledTimes(2); + expect(mockAddRoleForSubject).toHaveBeenCalledWith( + AUTHORIZATION_MODEL_ID, + "did:twin:user1", + "admin" + ); + expect(mockAddRoleForSubject).toHaveBeenCalledWith( + AUTHORIZATION_MODEL_ID, + "did:twin:user1", + "user" + ); + }); + + test("removeEntityProperty falls back to user role when scope is an empty string", async () => { + await ContextIdStore.run({ node: "test-node" }, async () => { + await callRemoveEntityProperty({ identity: "did:twin:user1", scope: "" }, SCOPE_PROP); + }); + await finalizeMigrations(mockEngineCore, {}); + expect(mockAddRoleForSubject).toHaveBeenCalledTimes(1); + expect(mockAddRoleForSubject).toHaveBeenCalledWith( + AUTHORIZATION_MODEL_ID, + "did:twin:user1", + "user" + ); + }); + + test("removeEntityProperty falls back to user role when scope contains only whitespace", async () => { + await ContextIdStore.run({ node: "test-node" }, async () => { + await callRemoveEntityProperty({ identity: "did:twin:user1", scope: " , " }, SCOPE_PROP); + }); + await finalizeMigrations(mockEngineCore, {}); + expect(mockAddRoleForSubject).toHaveBeenCalledTimes(1); + expect(mockAddRoleForSubject).toHaveBeenCalledWith( + AUTHORIZATION_MODEL_ID, + "did:twin:user1", + "user" + ); + }); +}); + +describe("finalizeMigrations", () => { + let callRemoveEntityProperty: RemoveEntityPropertyFn; + let mockEngineCore: IEngineCore; + let mockAddRoleForSubject: ReturnType; + + beforeAll(() => { + mockAddRoleForSubject = vi.fn().mockResolvedValue(undefined); + ComponentFactory.register( + `${AUTH_COMPONENT_TYPE}-finalize`, + () => + ({ + addRoleForSubject: mockAddRoleForSubject + }) as unknown as IAuthorizationComponent + ); + + const getRegisteredInstanceTypeOptional = vi + .fn() + .mockReturnValue(`${AUTH_COMPONENT_TYPE}-finalize`); + mockEngineCore = { + getRegisteredInstanceTypeOptional, + getRegisteredInstanceType: vi.fn().mockReturnValue(`${AUTH_COMPONENT_TYPE}-finalize`) + } as unknown as IEngineCore; + + initialiseMigrations(mockEngineCore, {}); + const migration = SchemaMigrationFactory.get(MIGRATION_KEY); + const { removeEntityProperty } = migration; + if (!removeEntityProperty) { + throw new Error("removeEntityProperty not registered on migration"); + } + callRemoveEntityProperty = removeEntityProperty; + }); + + afterAll(() => { + try { + SchemaMigrationFactory.unregister(MIGRATION_KEY); + } catch { + // Ignore if already removed. + } + try { + ComponentFactory.unregister(`${AUTH_COMPONENT_TYPE}-finalize`); + } catch { + // Ignore if already removed. + } + }); + + afterEach(async () => { + // Drain any leftover queued roles. + await finalizeMigrations(mockEngineCore, {}); + mockAddRoleForSubject.mockClear(); + }); + + test("throws when roles are queued but no authorization component is registered", async () => { + await ContextIdStore.run({ node: "test-node" }, async () => { + await callRemoveEntityProperty({ identity: "did:twin:user1", scope: "admin" }, SCOPE_PROP); + }); + const engineCoreNoAuth: IEngineCore = { + getRegisteredInstanceTypeOptional: vi.fn().mockReturnValue(undefined), + getRegisteredInstanceType: vi.fn().mockImplementation(() => { + throw new GeneralError("node", "componentNotFound"); + }) + } as unknown as IEngineCore; + await expect(finalizeMigrations(engineCoreNoAuth, {})).rejects.toBeInstanceOf(GeneralError); + }); + + test("is a no-op when no roles have been queued", async () => { + // migrateRoles is empty - drained by afterEach from the previous test. + await finalizeMigrations(mockEngineCore, {}); + expect(mockAddRoleForSubject).not.toHaveBeenCalled(); + }); + + test("calls addRoleForSubject for every queued role", async () => { + await ContextIdStore.run({ node: "test-node" }, async () => { + await callRemoveEntityProperty( + { identity: "did:twin:user1", scope: "admin,user" }, + SCOPE_PROP + ); + }); + await finalizeMigrations(mockEngineCore, {}); + expect(mockAddRoleForSubject).toHaveBeenCalledTimes(2); + expect(mockAddRoleForSubject).toHaveBeenCalledWith( + AUTHORIZATION_MODEL_ID, + "did:twin:user1", + "admin" + ); + expect(mockAddRoleForSubject).toHaveBeenCalledWith( + AUTHORIZATION_MODEL_ID, + "did:twin:user1", + "user" + ); + }); + + test("processes roles for multiple identities", async () => { + await ContextIdStore.run({ node: "test-node" }, async () => { + await callRemoveEntityProperty( + { identity: "did:twin:user1", scope: "global-admin" }, + SCOPE_PROP + ); + await callRemoveEntityProperty( + { identity: "did:twin:user2", scope: "tenant-admin" }, + SCOPE_PROP + ); + }); + await finalizeMigrations(mockEngineCore, {}); + expect(mockAddRoleForSubject).toHaveBeenCalledTimes(2); + expect(mockAddRoleForSubject).toHaveBeenCalledWith( + AUTHORIZATION_MODEL_ID, + "did:twin:user1", + "global-admin" + ); + expect(mockAddRoleForSubject).toHaveBeenCalledWith( + AUTHORIZATION_MODEL_ID, + "did:twin:user2", + "tenant-admin" + ); + }); + + test("uses the authorizationModelId env var when provided", async () => { + await ContextIdStore.run({ node: "test-node" }, async () => { + await callRemoveEntityProperty({ identity: "did:twin:user1", scope: "admin" }, SCOPE_PROP); + }); + await finalizeMigrations(mockEngineCore, { authorizationModelId: "custom-model" }); + expect(mockAddRoleForSubject).toHaveBeenCalledWith("custom-model", "did:twin:user1", "admin"); + }); + + test("drains the queue so a second call is a no-op", async () => { + await ContextIdStore.run({ node: "test-node" }, async () => { + await callRemoveEntityProperty({ identity: "did:twin:user1", scope: "admin" }, SCOPE_PROP); + }); + await finalizeMigrations(mockEngineCore, {}); + expect(mockAddRoleForSubject).toHaveBeenCalledTimes(1); + + mockAddRoleForSubject.mockClear(); + await finalizeMigrations(mockEngineCore, {}); + expect(mockAddRoleForSubject).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/node-core/tests/cli.spec.ts b/packages/node-core/tests/cli.spec.ts index bcb8a214..99aa20b9 100644 --- a/packages/node-core/tests/cli.spec.ts +++ b/packages/node-core/tests/cli.spec.ts @@ -342,7 +342,9 @@ describe("node-core", () => { "authorization-role-assignment" ); expect(roleAssignments.map(r => r.role).sort()).toEqual([ + "devops", "global-admin", + "identity-profile-admin", "tenant-admin", "user-admin" ]); @@ -400,7 +402,12 @@ describe("node-core", () => { dbDir, "authorization-role-assignment" ); - expect(roleAssignments.map(r => r.role).sort()).toEqual(["global-admin", "user-admin"]); + expect(roleAssignments.map(r => r.role).sort()).toEqual([ + "devops", + "global-admin", + "identity-profile-admin", + "user-admin" + ]); // Verify identity documents contain both node and org DIDs stored in state interface IdentityDocRecord { @@ -552,7 +559,12 @@ describe("node-core", () => { dbDir, "authorization-role-assignment" ); - expect(roleAssignments.map(r => r.role).sort()).toEqual(["global-admin", "user-admin"]); + expect(roleAssignments.map(r => r.role).sort()).toEqual([ + "devops", + "global-admin", + "identity-profile-admin", + "user-admin" + ]); interface ProfileRecord { privateProfile: { givenName: string; familyName: string; email: string }; @@ -608,7 +620,9 @@ describe("node-core", () => { "authorization-role-assignment" ); expect(roleAssignments.map(r => r.role).sort()).toEqual([ + "devops", "global-admin", + "identity-profile-admin", "tenant-admin", "user-admin" ]); @@ -1237,30 +1251,6 @@ describe("node-core", () => { ).rejects.toThrow(); }); - test("user-create throws when an invalid role is specified", async () => { - const envParts = [ - `${OUTPUT_TMP_DIR}organization-identity.env`, - `${OUTPUT_TMP_DIR}user-identity.env`, - `${OUTPUT_TMP_DIR}node-tenant.env` - ]; - await expect( - executeCliCommand( - [ - "user-create", - `--load-env=${envParts.join(",")}`, - "--user-identity=!USER_DID", - "--organization-identity=!ORGANIZATION_DID", - "--tenant-id=!NODE_TENANT_ID", - "--email=invalid-role@node", - "--roles=not-a-real-role" - ], - { nodeId: nodeIdentityJson?.did }, - undefined, - { disableProcessExitOnFailure: true } - ) - ).rejects.toThrow(); - }); - test("user-create works when multi-tenancy is enabled and tenant-id is provided", async () => { const envParts = [ `${OUTPUT_TMP_DIR}organization-identity.env`, diff --git a/packages/node-core/tests/endpoints/groups/identity.json b/packages/node-core/tests/endpoints/groups/identity.json index db65a5de..3fc30de4 100644 --- a/packages/node-core/tests/endpoints/groups/identity.json +++ b/packages/node-core/tests/endpoints/groups/identity.json @@ -87,14 +87,14 @@ "capture": { "proofData": "body" } }, { - "description": "GET /identity/:identity/verifiable-credential/revoke/1", - "method": "GET", + "description": "POST /identity/:identity/verifiable-credential/revoke/1", + "method": "POST", "path": "/identity/{{testIdentity}}/verifiable-credential/revoke/1", "expectedStatus": 204 }, { - "description": "GET /identity/:identity/verifiable-credential/unrevoke/1", - "method": "GET", + "description": "POST /identity/:identity/verifiable-credential/unrevoke/1", + "method": "POST", "path": "/identity/{{testIdentity}}/verifiable-credential/unrevoke/1", "expectedStatus": 204 }, diff --git a/packages/node-core/tests/index.spec.ts b/packages/node-core/tests/index.spec.ts index 68f16c82..15090aed 100644 --- a/packages/node-core/tests/index.spec.ts +++ b/packages/node-core/tests/index.spec.ts @@ -85,6 +85,7 @@ describe("node-core", () => { TWIN_SILENT: "true", TWIN_ENTITY_STORAGE_CONNECTOR_TYPE: EntityStorageConnectorType.Memory, TWIN_SCHEMA_MIGRATION_ENABLED: "false", + TWIN_AUTHORIZATION_CONNECTOR: "entity-storage", TWIN_ENV_ALLOW_LIST: CI_ENV_VARS } }); @@ -131,6 +132,7 @@ describe("node-core", () => { TWIN_AUTOMATION_ACTION_TYPES: "fetch", TWIN_HEALTH_ENABLED: "true", TWIN_SCHEMA_MIGRATION_ENABLED: "false", + TWIN_AUTHORIZATION_CONNECTOR: "entity-storage", TWIN_ENV_ALLOW_LIST: CI_ENV_VARS } }); @@ -173,6 +175,7 @@ describe("node-core", () => { TWIN_AUDITABLE_ITEM_STREAM_ENABLED: "true", TWIN_AUTH_ADMIN_PROCESSOR_TYPE: AuthenticationAdminComponentType.EntityStorage, TWIN_AUTH_PROCESSOR_TYPE: AuthenticationComponentType.EntityStorage, + TWIN_AUTHORIZATION_CONNECTOR: "entity-storage", TWIN_BLOB_STORAGE_ENABLE_ENCRYPTION: "true", TWIN_DOCUMENT_MANAGEMENT_ENABLED: "true", TWIN_TRUST_GENERATORS: "jwt-verifiable-credential", @@ -233,6 +236,7 @@ describe("node-core", () => { TWIN_AUDITABLE_ITEM_STREAM_ENABLED: "true", TWIN_AUTH_ADMIN_PROCESSOR_TYPE: AuthenticationAdminComponentType.EntityStorage, TWIN_AUTH_PROCESSOR_TYPE: AuthenticationComponentType.EntityStorage, + TWIN_AUTHORIZATION_CONNECTOR: "entity-storage", TWIN_BLOB_STORAGE_ENABLE_ENCRYPTION: "true", TWIN_DOCUMENT_MANAGEMENT_ENABLED: "true", TWIN_TRUST_GENERATORS: "jwt-verifiable-credential", @@ -281,6 +285,7 @@ describe("node-core", () => { TWIN_EVENT_BUS_CONNECTOR: EventBusConnectorType.Local, TWIN_AUTH_ADMIN_PROCESSOR_TYPE: AuthenticationAdminComponentType.EntityStorage, TWIN_AUTH_PROCESSOR_TYPE: AuthenticationComponentType.EntityStorage, + TWIN_AUTHORIZATION_CONNECTOR: "entity-storage", TWIN_TRUST_GENERATORS: "jwt-verifiable-credential", TWIN_TRUST_VERIFIERS: "jwt-verifiable-credential", TWIN_TRUST_VERIFICATION_METHOD_ID: "trust-assertion", @@ -310,6 +315,7 @@ describe("node-core", () => { TWIN_SILENT: "true", TWIN_PORT: port.toString(), TWIN_ENTITY_STORAGE_CONNECTOR_TYPE: EntityStorageConnectorType.Memory, + TWIN_AUTHORIZATION_CONNECTOR: "entity-storage", TWIN_SCHEMA_MIGRATION_ENABLED: "false" }; @@ -344,18 +350,37 @@ describe("node-core", () => { "engine-logging-service", "schema-version-service", "platform-service", + "authorization-service", "did-context-id-handler", "information-service" ]); const buildRestRoutes = startResult?.server?.getRestRoutes() ?? []; - expect(buildRestRoutes.map(r => r.path)).toEqual([ - "/", - "/favicon.ico", - "/info", - "/livez", - "/readyz", - "/spec" + expect(buildRestRoutes.map(r => `${r.method.padEnd(8, " ")} ${r.path}`)).toEqual([ + "GET /", + "GET /favicon.ico", + "GET /info", + "GET /livez", + "GET /readyz", + "GET /spec", + "POST /authorization/:modelId", + "POST /authorization/:modelId/check", + "POST /authorization/:modelId/policy", + "POST /authorization/:modelId/policy/remove", + "GET /authorization/:modelId/policy", + "GET /authorization/:modelId/roles", + "POST /authorization/:modelId/roles/has", + "GET /authorization/:modelId/policy/:subject", + "POST /authorization/:modelId/subject/:subject/role", + "DELETE /authorization/:modelId/subject/:subject/role/:role", + "DELETE /authorization/:modelId/subject/:subject/roles", + "GET /authorization/:modelId/subject/:subject/roles", + "GET /authorization/:modelId/subject/:subject/role/:role", + "GET /authorization/:modelId/role/:role/subjects", + "POST /authorization/:modelId/role/:role/inherit", + "DELETE /authorization/:modelId/role/:role/inherit/:inheritsFrom", + "GET /authorization/:modelId/role/:role/parents", + "GET /authorization/:modelId/role/:role/children" ]); await startResult?.shutdown(); @@ -829,6 +854,7 @@ describe("node-core", () => { TWIN_SILENT: "true", TWIN_PORT: port.toString(), TWIN_ENTITY_STORAGE_CONNECTOR_TYPE: EntityStorageConnectorType.Memory, + TWIN_AUTHORIZATION_CONNECTOR: "entity-storage", TWIN_SCHEMA_MIGRATION_ENABLED: "false" }; @@ -888,18 +914,37 @@ describe("node-core", () => { "engine-logging-service", "schema-version-service", "platform-service", + "authorization-service", "did-context-id-handler", "information-service" ]); const buildRestRoutes = startResult?.server?.getRestRoutes() ?? []; - expect(buildRestRoutes.map(r => r.path)).toEqual([ - "/", - "/favicon.ico", - "/info", - "/livez", - "/readyz", - "/spec" + expect(buildRestRoutes.map(r => `${r.method.padEnd(8, " ")} ${r.path}`)).toEqual([ + "GET /", + "GET /favicon.ico", + "GET /info", + "GET /livez", + "GET /readyz", + "GET /spec", + "POST /authorization/:modelId", + "POST /authorization/:modelId/check", + "POST /authorization/:modelId/policy", + "POST /authorization/:modelId/policy/remove", + "GET /authorization/:modelId/policy", + "GET /authorization/:modelId/roles", + "POST /authorization/:modelId/roles/has", + "GET /authorization/:modelId/policy/:subject", + "POST /authorization/:modelId/subject/:subject/role", + "DELETE /authorization/:modelId/subject/:subject/role/:role", + "DELETE /authorization/:modelId/subject/:subject/roles", + "GET /authorization/:modelId/subject/:subject/roles", + "GET /authorization/:modelId/subject/:subject/role/:role", + "GET /authorization/:modelId/role/:role/subjects", + "POST /authorization/:modelId/role/:role/inherit", + "DELETE /authorization/:modelId/role/:role/inherit/:inheritsFrom", + "GET /authorization/:modelId/role/:role/parents", + "GET /authorization/:modelId/role/:role/children" ]); await startResult?.shutdown(); @@ -911,6 +956,7 @@ describe("node-core", () => { TWIN_SILENT: "true", TWIN_PORT: port.toString(), TWIN_ENTITY_STORAGE_CONNECTOR_TYPE: EntityStorageConnectorType.Memory, + TWIN_AUTHORIZATION_CONNECTOR: "entity-storage", TWIN_SCHEMA_MIGRATION_ENABLED: "false" }; @@ -951,18 +997,37 @@ describe("node-core", () => { "engine-logging-service", "schema-version-service", "platform-service", + "authorization-service", "did-context-id-handler", "information-service" ]); const buildRestRoutes = startResult?.server?.getRestRoutes() ?? []; - expect(buildRestRoutes.map(r => r.path)).toEqual([ - "/", - "/favicon.ico", - "/info", - "/livez", - "/readyz", - "/spec" + expect(buildRestRoutes.map(r => `${r.method.padEnd(8, " ")} ${r.path}`)).toEqual([ + "GET /", + "GET /favicon.ico", + "GET /info", + "GET /livez", + "GET /readyz", + "GET /spec", + "POST /authorization/:modelId", + "POST /authorization/:modelId/check", + "POST /authorization/:modelId/policy", + "POST /authorization/:modelId/policy/remove", + "GET /authorization/:modelId/policy", + "GET /authorization/:modelId/roles", + "POST /authorization/:modelId/roles/has", + "GET /authorization/:modelId/policy/:subject", + "POST /authorization/:modelId/subject/:subject/role", + "DELETE /authorization/:modelId/subject/:subject/role/:role", + "DELETE /authorization/:modelId/subject/:subject/roles", + "GET /authorization/:modelId/subject/:subject/roles", + "GET /authorization/:modelId/subject/:subject/role/:role", + "GET /authorization/:modelId/role/:role/subjects", + "POST /authorization/:modelId/role/:role/inherit", + "DELETE /authorization/:modelId/role/:role/inherit/:inheritsFrom", + "GET /authorization/:modelId/role/:role/parents", + "GET /authorization/:modelId/role/:role/children" ]); await startResult?.shutdown(); @@ -974,6 +1039,7 @@ describe("node-core", () => { TWIN_SILENT: "true", TWIN_PORT: port.toString(), TWIN_ENTITY_STORAGE_CONNECTOR_TYPE: EntityStorageConnectorType.Memory, + TWIN_AUTHORIZATION_CONNECTOR: "entity-storage", TWIN_SCHEMA_MIGRATION_ENABLED: "false" }; @@ -1014,18 +1080,37 @@ describe("node-core", () => { "engine-logging-service", "schema-version-service", "platform-service", + "authorization-service", "did-context-id-handler", "information-service" ]); const buildRestRoutes = startResult?.server?.getRestRoutes() ?? []; - expect(buildRestRoutes.map(r => r.path)).toEqual([ - "/", - "/favicon.ico", - "/info", - "/livez", - "/readyz", - "/spec" + expect(buildRestRoutes.map(r => `${r.method.padEnd(8, " ")} ${r.path}`)).toEqual([ + "GET /", + "GET /favicon.ico", + "GET /info", + "GET /livez", + "GET /readyz", + "GET /spec", + "POST /authorization/:modelId", + "POST /authorization/:modelId/check", + "POST /authorization/:modelId/policy", + "POST /authorization/:modelId/policy/remove", + "GET /authorization/:modelId/policy", + "GET /authorization/:modelId/roles", + "POST /authorization/:modelId/roles/has", + "GET /authorization/:modelId/policy/:subject", + "POST /authorization/:modelId/subject/:subject/role", + "DELETE /authorization/:modelId/subject/:subject/role/:role", + "DELETE /authorization/:modelId/subject/:subject/roles", + "GET /authorization/:modelId/subject/:subject/roles", + "GET /authorization/:modelId/subject/:subject/role/:role", + "GET /authorization/:modelId/role/:role/subjects", + "POST /authorization/:modelId/role/:role/inherit", + "DELETE /authorization/:modelId/role/:role/inherit/:inheritsFrom", + "GET /authorization/:modelId/role/:role/parents", + "GET /authorization/:modelId/role/:role/children" ]); await startResult?.shutdown(); @@ -1037,6 +1122,7 @@ describe("node-core", () => { TWIN_SILENT: "true", TWIN_PORT: port.toString(), TWIN_ENTITY_STORAGE_CONNECTOR_TYPE: EntityStorageConnectorType.Memory, + TWIN_AUTHORIZATION_CONNECTOR: "entity-storage", TWIN_SCHEMA_MIGRATION_ENABLED: "false", TWIN_TEST_EMBEDDED: "@text:tests/fixtures/embedded.txt", TWIN_ENV_ALLOW_LIST: [CI_ENV_VARS, "TWIN_TEST_EMBEDDED"].filter(Boolean).join(",") @@ -1073,6 +1159,7 @@ describe("node-core", () => { TWIN_DEBUG: "true", TWIN_SILENT: "true", TWIN_ENTITY_STORAGE_CONNECTOR_TYPE: EntityStorageConnectorType.Memory, + TWIN_AUTHORIZATION_CONNECTOR: "entity-storage", TWIN_SCHEMA_MIGRATION_ENABLED: "false", TWIN_TEST_EMBEDDED: "@json:tests/fixtures/embedded.json", TWIN_ENV_ALLOW_LIST: [CI_ENV_VARS, "TWIN_TEST_EMBEDDED"].filter(Boolean).join(",") @@ -1112,6 +1199,7 @@ describe("node-core", () => { TWIN_SILENT: "true", TWIN_PORT: port.toString(), TWIN_ENTITY_STORAGE_CONNECTOR_TYPE: EntityStorageConnectorType.Memory, + TWIN_AUTHORIZATION_CONNECTOR: "entity-storage", TWIN_SCHEMA_MIGRATION_ENABLED: "false", TWIN_EXTENSIONS: "./tests/fixtures//myExtension.js" }; @@ -1150,18 +1238,37 @@ describe("node-core", () => { "engine-logging-service", "schema-version-service", "platform-service", + "authorization-service", "did-context-id-handler", "information-service" ]); const buildRestRoutes = startResult?.server?.getRestRoutes() ?? []; - expect(buildRestRoutes.map(r => r.path)).toEqual([ - "/", - "/favicon.ico", - "/info", - "/livez", - "/readyz", - "/spec" + expect(buildRestRoutes.map(r => `${r.method.padEnd(8, " ")} ${r.path}`)).toEqual([ + "GET /", + "GET /favicon.ico", + "GET /info", + "GET /livez", + "GET /readyz", + "GET /spec", + "POST /authorization/:modelId", + "POST /authorization/:modelId/check", + "POST /authorization/:modelId/policy", + "POST /authorization/:modelId/policy/remove", + "GET /authorization/:modelId/policy", + "GET /authorization/:modelId/roles", + "POST /authorization/:modelId/roles/has", + "GET /authorization/:modelId/policy/:subject", + "POST /authorization/:modelId/subject/:subject/role", + "DELETE /authorization/:modelId/subject/:subject/role/:role", + "DELETE /authorization/:modelId/subject/:subject/roles", + "GET /authorization/:modelId/subject/:subject/roles", + "GET /authorization/:modelId/subject/:subject/role/:role", + "GET /authorization/:modelId/role/:role/subjects", + "POST /authorization/:modelId/role/:role/inherit", + "DELETE /authorization/:modelId/role/:role/inherit/:inheritsFrom", + "GET /authorization/:modelId/role/:role/parents", + "GET /authorization/:modelId/role/:role/children" ]); await startResult?.shutdown(); @@ -1255,6 +1362,7 @@ describe("node-core", () => { TWIN_SILENT: "true", TWIN_PORT: port.toString(), TWIN_ENTITY_STORAGE_CONNECTOR_TYPE: EntityStorageConnectorType.Memory, + TWIN_AUTHORIZATION_CONNECTOR: "entity-storage", TWIN_SCHEMA_MIGRATION_ENABLED: "false", TWIN_EXTENSIONS: "./tests/.tmp/first-extension.js,./tests/.tmp/second-extension.js" }; @@ -1346,6 +1454,7 @@ describe("node-core", () => { TWIN_SILENT: "true", TWIN_PORT: port.toString(), TWIN_ENTITY_STORAGE_CONNECTOR_TYPE: EntityStorageConnectorType.Memory, + TWIN_AUTHORIZATION_CONNECTOR: "entity-storage", TWIN_SCHEMA_MIGRATION_ENABLED: "false", TWIN_EXTENSIONS: "./tests/.tmp/lifecycle-test.js" }; @@ -1462,6 +1571,7 @@ describe("node-core", () => { TWIN_SILENT: "true", TWIN_PORT: port.toString(), TWIN_ENTITY_STORAGE_CONNECTOR_TYPE: EntityStorageConnectorType.Memory, + TWIN_AUTHORIZATION_CONNECTOR: "entity-storage", TWIN_SCHEMA_MIGRATION_ENABLED: "false", TWIN_EXTENSIONS: "./tests/.tmp/cache-test.js", TWIN_EXTENSIONS_CACHE_DIRECTORY: customCacheDir diff --git a/packages/node-core/tests/migration.spec.ts b/packages/node-core/tests/migration.spec.ts index 40145371..a4aecec7 100644 --- a/packages/node-core/tests/migration.spec.ts +++ b/packages/node-core/tests/migration.spec.ts @@ -104,6 +104,7 @@ const TEST_TENANT_ID_B = "b2222222222222222222222222222222"; const BASE_ENV: { [id: string]: string } = { TWIN_SILENT: "true", TWIN_ENTITY_STORAGE_CONNECTOR_TYPE: EntityStorageConnectorType.Memory, + TWIN_AUTHORIZATION_CONNECTOR: AuthorizationConnectorType.EntityStorage, TWIN_ENV_ALLOW_LIST: CI_ENV_VARS }; From 4ee4bc87b61ca8387232f2e500bcc1a066657d0d Mon Sep 17 00:00:00 2001 From: Martyn Janes Date: Fri, 28 Aug 2026 16:16:38 +0800 Subject: [PATCH 09/17] feat: additional default roles --- .../src/builders/helper/migrationHelper.ts | 4 +- .../node-core/src/commands/bootstrapDev.ts | 3 ++ packages/node-core/src/defaults.ts | 5 +++ .../IBootstrapDevEnvironmentVariables.ts | 2 +- .../tests/authorizationSeeder.spec.ts | 36 ++++++++++++++--- packages/node-core/tests/cli.spec.ts | 2 + packages/node-core/tests/endpoints.spec.ts | 39 +++++++++++++++++-- packages/node-core/tests/startup.spec.ts | 3 +- 8 files changed, 81 insertions(+), 13 deletions(-) diff --git a/packages/node-core/src/builders/helper/migrationHelper.ts b/packages/node-core/src/builders/helper/migrationHelper.ts index 3a625a76..a71d684b 100644 --- a/packages/node-core/src/builders/helper/migrationHelper.ts +++ b/packages/node-core/src/builders/helper/migrationHelper.ts @@ -19,7 +19,8 @@ import { DEFAULT_TENANT_ADMIN_ROLE, DEFAULT_USER_ADMIN_ROLE, DEFAULT_IDENTITY_PROFILE_ADMIN_ROLE, - DEFAULT_USER_ROLE + DEFAULT_USER_ROLE, + DEFAULT_IDENTITY_ADMIN_ROLE } from "../../defaults.js"; import type { IEnvironmentVariables } from "../../models/IEnvironmentVariables.js"; @@ -64,6 +65,7 @@ export function initialiseMigrations( // to provide access to everything they had before if (roles.includes(DEFAULT_TENANT_ADMIN_ROLE) && roles.includes(DEFAULT_USER_ADMIN_ROLE)) { roles.push(DEFAULT_DEVOPS_ROLE); + roles.push(DEFAULT_IDENTITY_ADMIN_ROLE); roles.push(DEFAULT_IDENTITY_PROFILE_ADMIN_ROLE); } diff --git a/packages/node-core/src/commands/bootstrapDev.ts b/packages/node-core/src/commands/bootstrapDev.ts index 0c145caf..03566d57 100644 --- a/packages/node-core/src/commands/bootstrapDev.ts +++ b/packages/node-core/src/commands/bootstrapDev.ts @@ -10,6 +10,7 @@ import { commaSeparatedListToArray } from "../builders/helper/envHelpers.js"; import { DEFAULT_DEVOPS_ROLE, DEFAULT_ESCALATED_PRIVILEGE_ROLE, + DEFAULT_IDENTITY_ADMIN_ROLE, DEFAULT_TENANT_ADMIN_ROLE, DEFAULT_USER_ADMIN_ROLE, DEFAULT_IDENTITY_PROFILE_ADMIN_ROLE @@ -276,12 +277,14 @@ export async function bootstrapDev( DEFAULT_ESCALATED_PRIVILEGE_ROLE, DEFAULT_TENANT_ADMIN_ROLE, DEFAULT_USER_ADMIN_ROLE, + DEFAULT_IDENTITY_ADMIN_ROLE, DEFAULT_IDENTITY_PROFILE_ADMIN_ROLE, DEFAULT_DEVOPS_ROLE ] : [ DEFAULT_ESCALATED_PRIVILEGE_ROLE, DEFAULT_USER_ADMIN_ROLE, + DEFAULT_IDENTITY_ADMIN_ROLE, DEFAULT_IDENTITY_PROFILE_ADMIN_ROLE, DEFAULT_DEVOPS_ROLE ] diff --git a/packages/node-core/src/defaults.ts b/packages/node-core/src/defaults.ts index c9292da5..d9fe6bb6 100644 --- a/packages/node-core/src/defaults.ts +++ b/packages/node-core/src/defaults.ts @@ -56,6 +56,11 @@ export const DEFAULT_TENANT_ADMIN_ROLE = "tenant-admin"; */ export const DEFAULT_USER_ADMIN_ROLE = "user-admin"; +/** + * Default role for identity administration. + */ +export const DEFAULT_IDENTITY_ADMIN_ROLE = "identity-admin"; + /** * Default role for identity profile admins. */ diff --git a/packages/node-core/src/models/IBootstrapDevEnvironmentVariables.ts b/packages/node-core/src/models/IBootstrapDevEnvironmentVariables.ts index 74527e01..f5c47f7e 100644 --- a/packages/node-core/src/models/IBootstrapDevEnvironmentVariables.ts +++ b/packages/node-core/src/models/IBootstrapDevEnvironmentVariables.ts @@ -64,7 +64,7 @@ export interface IBootstrapDevEnvironmentVariables { /** * If the admin-user feature is enabled, this is a comma-separated list of roles for the user. - * @default global-admin,tenant-admin,user-admin (tenant-admin only when tenant enabled) + * @default global-admin,tenant-admin,user-admin,identity-admin,identity-profile-admin,devops (tenant-admin only when tenant enabled) */ adminUserRoles?: string; } diff --git a/packages/node-core/tests/authorizationSeeder.spec.ts b/packages/node-core/tests/authorizationSeeder.spec.ts index b3afda67..5c5cc582 100644 --- a/packages/node-core/tests/authorizationSeeder.spec.ts +++ b/packages/node-core/tests/authorizationSeeder.spec.ts @@ -109,7 +109,12 @@ describe("seedAuthorizationDefaults", () => { await ContextIdStore.run(nodeContextIds, async () => { await platformComponent.execute(async () => { - const { entities: policies } = await authComponent.getAllPolicies(AUTHORIZATION_MODEL_ID); + const { entities: policies } = await authComponent.getAllPolicies( + AUTHORIZATION_MODEL_ID, + undefined, + undefined, + 1000 + ); for (const route of protectedRoutes) { const auth = route.defaultAuthorization; const operationId = route.operationId; @@ -238,7 +243,12 @@ describe("seedAuthorizationDefaults", () => { await ContextIdStore.run(nodeContextIds, async () => { await platformComponent.execute(async () => { - const { entities: policies } = await authComponent.getAllPolicies(AUTHORIZATION_MODEL_ID); + const { entities: policies } = await authComponent.getAllPolicies( + AUTHORIZATION_MODEL_ID, + undefined, + undefined, + 1000 + ); const hasCustomPolicy = policies.some( p => p.subject === "custom-role" && p.object === "custom-op" @@ -288,7 +298,9 @@ describe("seedAuthorizationDefaults", () => { await platformComponent.execute(async () => { const { entities: policies } = await authComponent.getAllPolicies( AUTHORIZATION_MODEL_ID, - "user:read" + "user:read", + undefined, + 1000 ); for (const route of fallbackGetRoutes) { const hasPolicy = policies.some( @@ -337,7 +349,9 @@ describe("seedAuthorizationDefaults", () => { await platformComponent.execute(async () => { const { entities: policies } = await authComponent.getAllPolicies( AUTHORIZATION_MODEL_ID, - "user:write" + "user:write", + undefined, + 1000 ); for (const route of fallbackWriteRoutes) { const hasPolicy = policies.some( @@ -375,7 +389,12 @@ describe("seedAuthorizationDefaults", () => { await ContextIdStore.run(nodeContextIds, async () => { await platformComponent.execute(async () => { - const { entities: policies } = await authComponent.getAllPolicies(AUTHORIZATION_MODEL_ID); + const { entities: policies } = await authComponent.getAllPolicies( + AUTHORIZATION_MODEL_ID, + undefined, + undefined, + 1000 + ); for (const route of skippedRoutes) { const hasPolicy = policies.some(p => p.object === route.operationId); expect(hasPolicy).toBe(false); @@ -418,7 +437,12 @@ describe("seedAuthorizationDefaults", () => { await ContextIdStore.run(nodeContextIds, async () => { await platformComponent.execute(async () => { - const { entities: policies } = await authComponent.getAllPolicies(AUTHORIZATION_MODEL_ID); + const { entities: policies } = await authComponent.getAllPolicies( + AUTHORIZATION_MODEL_ID, + undefined, + undefined, + 1000 + ); const hasCustomPolicy = policies.some( p => p.subject === "custom-role" && p.object === "custom-op" diff --git a/packages/node-core/tests/cli.spec.ts b/packages/node-core/tests/cli.spec.ts index 99aa20b9..aa7a372b 100644 --- a/packages/node-core/tests/cli.spec.ts +++ b/packages/node-core/tests/cli.spec.ts @@ -344,6 +344,7 @@ describe("node-core", () => { expect(roleAssignments.map(r => r.role).sort()).toEqual([ "devops", "global-admin", + "identity-admin", "identity-profile-admin", "tenant-admin", "user-admin" @@ -405,6 +406,7 @@ describe("node-core", () => { expect(roleAssignments.map(r => r.role).sort()).toEqual([ "devops", "global-admin", + "identity-admin", "identity-profile-admin", "user-admin" ]); diff --git a/packages/node-core/tests/endpoints.spec.ts b/packages/node-core/tests/endpoints.spec.ts index 78e7c1d5..46138700 100644 --- a/packages/node-core/tests/endpoints.spec.ts +++ b/packages/node-core/tests/endpoints.spec.ts @@ -33,6 +33,13 @@ import { import type { ITrustComponent } from "@twin.org/trust-models"; import { loadAndRunGroups } from "./endpoints/runner.js"; import { CI_ENV_VARS } from "./setupTestEnv.js"; +import { + DEFAULT_DEVOPS_ROLE, + DEFAULT_IDENTITY_ADMIN_ROLE, + DEFAULT_TENANT_ADMIN_ROLE, + DEFAULT_USER_ADMIN_ROLE, + DEFAULT_IDENTITY_PROFILE_ADMIN_ROLE +} from "../src/defaults.js"; import type { INodeEngineState } from "../src/models/INodeEngineState.js"; import { run } from "../src/node.js"; @@ -176,7 +183,13 @@ describe("node-core", () => { TWIN_FEATURES: "admin-user", TWIN_ADMIN_USER_NAME: TEST_ADMIN_EMAIL, TWIN_ADMIN_USER_PASSWORD: TEST_ADMIN_PASSWORD, - TWIN_ADMIN_USER_ROLES: "tenant-admin,user-admin", + TWIN_ADMIN_USER_ROLES: [ + DEFAULT_TENANT_ADMIN_ROLE, + DEFAULT_USER_ADMIN_ROLE, + DEFAULT_IDENTITY_ADMIN_ROLE, + DEFAULT_IDENTITY_PROFILE_ADMIN_ROLE, + DEFAULT_DEVOPS_ROLE + ].join(","), TWIN_HEALTH_STARTUP_INTERVAL: "1" } }, @@ -253,7 +266,13 @@ describe("node-core", () => { TWIN_TENANT_ID: TEST_TENANT_ID, TWIN_ADMIN_USER_NAME: TEST_ADMIN_EMAIL, TWIN_ADMIN_USER_PASSWORD: TEST_ADMIN_PASSWORD, - TWIN_ADMIN_USER_ROLES: "tenant-admin,user-admin", + TWIN_ADMIN_USER_ROLES: [ + DEFAULT_TENANT_ADMIN_ROLE, + DEFAULT_USER_ADMIN_ROLE, + DEFAULT_IDENTITY_ADMIN_ROLE, + DEFAULT_IDENTITY_PROFILE_ADMIN_ROLE, + DEFAULT_DEVOPS_ROLE + ].join(","), TWIN_HEALTH_STARTUP_INTERVAL: "500" } }, @@ -374,7 +393,13 @@ describe("node-core", () => { TWIN_TENANT_API_KEY: TEST_TENANT_API_KEY, TWIN_ADMIN_USER_NAME: TEST_ADMIN_EMAIL, TWIN_ADMIN_USER_PASSWORD: TEST_ADMIN_PASSWORD, - TWIN_ADMIN_USER_ROLES: "tenant-admin,user-admin", + TWIN_ADMIN_USER_ROLES: [ + DEFAULT_TENANT_ADMIN_ROLE, + DEFAULT_USER_ADMIN_ROLE, + DEFAULT_IDENTITY_ADMIN_ROLE, + DEFAULT_IDENTITY_PROFILE_ADMIN_ROLE, + DEFAULT_DEVOPS_ROLE + ].join(","), TWIN_HEALTH_STARTUP_INTERVAL: "500" } }, @@ -576,7 +601,13 @@ describe("node-core", () => { TWIN_TENANT_API_KEY: TEST_TENANT_API_KEY, TWIN_ADMIN_USER_NAME: TEST_ADMIN_EMAIL, TWIN_ADMIN_USER_PASSWORD: TEST_ADMIN_PASSWORD, - TWIN_ADMIN_USER_ROLES: "tenant-admin,user-admin", + TWIN_ADMIN_USER_ROLES: [ + DEFAULT_TENANT_ADMIN_ROLE, + DEFAULT_USER_ADMIN_ROLE, + DEFAULT_IDENTITY_ADMIN_ROLE, + DEFAULT_IDENTITY_PROFILE_ADMIN_ROLE, + DEFAULT_DEVOPS_ROLE + ].join(","), TWIN_HEALTH_STARTUP_INTERVAL: "500" } }, diff --git a/packages/node-core/tests/startup.spec.ts b/packages/node-core/tests/startup.spec.ts index 0368fd50..fea71152 100644 --- a/packages/node-core/tests/startup.spec.ts +++ b/packages/node-core/tests/startup.spec.ts @@ -4,7 +4,7 @@ import type { ITenantAdminComponent } from "@twin.org/api-models"; import { ContextIdStore } from "@twin.org/context"; import { ComponentFactory, Factory } from "@twin.org/core"; import { MemoryStateStorage } from "@twin.org/engine-core"; -import { EntityStorageConnectorType } from "@twin.org/engine-types"; +import { AuthorizationConnectorType, EntityStorageConnectorType } from "@twin.org/engine-types"; import { entity, EntitySchemaFactory, EntitySchemaHelper, property } from "@twin.org/entity"; import { MemoryEntityStorageConnector } from "@twin.org/entity-storage-connector-memory"; import { CI_ENV_VARS } from "./setupTestEnv.js"; @@ -44,6 +44,7 @@ const TEST_API_KEY_B = "d0000000000000000000000000000002"; const BASE_ENV: { [id: string]: string } = { TWIN_SILENT: "true", TWIN_ENTITY_STORAGE_CONNECTOR_TYPE: EntityStorageConnectorType.Memory, + TWIN_AUTHORIZATION_CONNECTOR: AuthorizationConnectorType.EntityStorage, TWIN_TENANT_ENABLED: "true", TWIN_ENV_ALLOW_LIST: CI_ENV_VARS }; From 860120998eb1d09e7604822f2ebf0baa3fde8aba Mon Sep 17 00:00:00 2001 From: Martyn Janes Date: Fri, 28 Aug 2026 16:23:29 +0800 Subject: [PATCH 10/17] feat: additional default roles --- packages/node-core/tests/cli.spec.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/node-core/tests/cli.spec.ts b/packages/node-core/tests/cli.spec.ts index aa7a372b..7559fd33 100644 --- a/packages/node-core/tests/cli.spec.ts +++ b/packages/node-core/tests/cli.spec.ts @@ -564,6 +564,7 @@ describe("node-core", () => { expect(roleAssignments.map(r => r.role).sort()).toEqual([ "devops", "global-admin", + "identity-admin", "identity-profile-admin", "user-admin" ]); @@ -624,6 +625,7 @@ describe("node-core", () => { expect(roleAssignments.map(r => r.role).sort()).toEqual([ "devops", "global-admin", + "identity-admin", "identity-profile-admin", "tenant-admin", "user-admin" From a2f753144d6f48fcb57c79a791b108ca0015a68a Mon Sep 17 00:00:00 2001 From: Martyn Janes Date: Fri, 28 Aug 2026 16:35:50 +0800 Subject: [PATCH 11/17] feat: additional default roles --- .../groups/global-admin-unauthorized.json | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/node-core/tests/endpoints/groups/global-admin-unauthorized.json b/packages/node-core/tests/endpoints/groups/global-admin-unauthorized.json index e95ef0e1..23be8a60 100644 --- a/packages/node-core/tests/endpoints/groups/global-admin-unauthorized.json +++ b/packages/node-core/tests/endpoints/groups/global-admin-unauthorized.json @@ -10,20 +10,26 @@ "capture": { "regularUserDid": "body.id" } }, { - "description": "POST /authentication/admin/users — create user without global-admin scope", + "description": "POST /authentication/admin/users — create user without global-admin role", "method": "POST", "path": "/authentication/admin/users", "body": { "email": "regular-user@node", "password": "Regular@Node12345!", "userIdentity": "{{regularUserDid}}", - "organizationIdentity": "{{adminOrgIdentity}}", - "scope": ["tenant-admin"] + "organizationIdentity": "{{adminOrgIdentity}}" }, "expectedStatus": 201 }, { - "description": "POST /authentication/login — login as regular user (no global-admin scope)", + "description": "POST /authorization/rest/subject/:subject/role — assign tenant-admin role", + "method": "POST", + "path": "/authorization/rest/subject/{{regularUserDid}}/role", + "body": { "role": "tenant-admin" }, + "expectedStatus": 204 + }, + { + "description": "POST /authentication/login — login as regular user (no global-admin role)", "method": "POST", "path": "/authentication/login", "apiKey": true, @@ -32,7 +38,7 @@ "capture": { "authToken": "cookie:access_token" } }, { - "description": "POST /aig?override-tenant — rejected without global-admin scope", + "description": "POST /aig?override-tenant — rejected without global-admin role", "method": "POST", "path": "/aig?override-tenant={{secondTenantId}}", "body": { From dfb5332d4d4b9bf59cb9acafcff3567cd486ae5d Mon Sep 17 00:00:00 2001 From: Martyn Janes Date: Fri, 28 Aug 2026 16:46:20 +0800 Subject: [PATCH 12/17] feat: additional default roles --- packages/node-core/tests/systemMetrics.spec.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/node-core/tests/systemMetrics.spec.ts b/packages/node-core/tests/systemMetrics.spec.ts index 41972535..d5e93a85 100644 --- a/packages/node-core/tests/systemMetrics.spec.ts +++ b/packages/node-core/tests/systemMetrics.spec.ts @@ -3,7 +3,7 @@ import { ContextIdKeys, ContextIdStore } from "@twin.org/context"; import { ComponentFactory, Factory } from "@twin.org/core"; import { MemoryStateStorage } from "@twin.org/engine-core"; -import { EntityStorageConnectorType } from "@twin.org/engine-types"; +import { AuthorizationConnectorType, EntityStorageConnectorType } from "@twin.org/engine-types"; import type { ITelemetryComponent } from "@twin.org/telemetry-models"; import { CI_ENV_VARS } from "./setupTestEnv.js"; import { run } from "../src/node.js"; @@ -43,6 +43,7 @@ describe("System metrics E2E", () => { envVars: { TWIN_SILENT: "true", TWIN_PORT: BASE_PORT.toString(), + TWIN_AUTHORIZATION_CONNECTOR: AuthorizationConnectorType.EntityStorage, TWIN_ENTITY_STORAGE_CONNECTOR_TYPE: EntityStorageConnectorType.Memory, TWIN_TELEMETRY_CONNECTOR: "entity-storage", // Large interval so only the startup tick fires during the test From 3a0b52774fec5b4e7d507fc854264e5469172b5b Mon Sep 17 00:00:00 2001 From: Martyn Janes Date: Wed, 2 Sep 2026 13:23:08 +0800 Subject: [PATCH 13/17] feat: pr comments --- .../src/builders/engineServerEnvBuilder.ts | 14 +- .../src/builders/helper/envHelpers.ts | 40 +++++ .../src/builders/helper/migrationHelper.ts | 3 - .../src/builders/helper/seedingHelper.ts | 148 +++++++++++------- packages/node-core/src/defaults.ts | 2 +- packages/node-core/src/index.ts | 1 + .../src/models/authorizationModelMode.ts | 24 +++ .../builders/engineServerEnvBuilder.spec.ts | 2 +- .../tests/builders/helper/envHelpers.spec.ts | 37 ++++- .../groups/global-admin-unauthorized.json | 2 +- packages/node-core/tests/migration.spec.ts | 132 +++++++++++++++- 11 files changed, 335 insertions(+), 70 deletions(-) create mode 100644 packages/node-core/src/models/authorizationModelMode.ts diff --git a/packages/node-core/src/builders/engineServerEnvBuilder.ts b/packages/node-core/src/builders/engineServerEnvBuilder.ts index 3cd0105f..714f658e 100644 --- a/packages/node-core/src/builders/engineServerEnvBuilder.ts +++ b/packages/node-core/src/builders/engineServerEnvBuilder.ts @@ -269,10 +269,20 @@ export async function buildEngineServerConfiguration( }); if (isAuthorizationRequired(envVars)) { serverConfig.types.restRouteProcessor.push({ - type: RestRouteProcessorType.Authorization + type: RestRouteProcessorType.Authorization, + options: { + config: { + authorizationModelId: envString(envVars, "authorizationModelId", AUTHORIZATION_MODEL_ID) + } + } }); serverConfig.types.socketRouteProcessor.push({ - type: SocketRouteProcessorType.Authorization + type: SocketRouteProcessorType.Authorization, + options: { + config: { + authorizationModelId: envString(envVars, "authorizationModelId", AUTHORIZATION_MODEL_ID) + } + } }); if (tenantEnabled) { diff --git a/packages/node-core/src/builders/helper/envHelpers.ts b/packages/node-core/src/builders/helper/envHelpers.ts index ca7c27e7..f52a2060 100644 --- a/packages/node-core/src/builders/helper/envHelpers.ts +++ b/packages/node-core/src/builders/helper/envHelpers.ts @@ -16,6 +16,46 @@ export function envString(envVars: T, key: keyof T, defaultValue?: string): s return Is.stringValue(value) ? value : defaultValue; } +/** + * Returns an env var constrained to one of the supplied choices, falling back to the supplied default. + * @param envVars The environment variables object. + * @param key The property name of the env var to read. + * @param choices The permitted values for the env var. + * @param defaultValue The value to return when the env var is absent or empty. Omit to return undefined when absent. + * @returns The matching choice, the default, or undefined when absent and no default given. + * @throws GeneralError if the value is set but is not one of the choices. + */ +export function envChoice( + envVars: T, + key: keyof T, + choices: readonly U[], + defaultValue: U +): U; +export function envChoice( + envVars: T, + key: keyof T, + choices: readonly U[] +): U | undefined; +export function envChoice( + envVars: T, + key: keyof T, + choices: readonly U[], + defaultValue?: U +): U | undefined { + const value = envVars[key]; + if (!Is.stringValue(value)) { + return defaultValue; + } + if (!choices.includes(value as U)) { + throw new GeneralError("node", "invalidEnvVarValue", { + key, + value, + type: choices.join(" | ") + }); + } + return value as U; +} + /** * Coerces an env var to a boolean, falling back to the supplied default when not set. * @param envVars The environment variables object. diff --git a/packages/node-core/src/builders/helper/migrationHelper.ts b/packages/node-core/src/builders/helper/migrationHelper.ts index a71d684b..6d6d3e41 100644 --- a/packages/node-core/src/builders/helper/migrationHelper.ts +++ b/packages/node-core/src/builders/helper/migrationHelper.ts @@ -100,9 +100,6 @@ export async function finalizeMigrations( envVars: IEnvironmentVariables ): Promise { if (Is.arrayValue(migrateRoles)) { - // If a migration of the roles from the old authenticated users has just happened - // the old roles will be stored in the SharedStore, if they exist then we need - // to populate them in the authorization service. const authComponentType = engineCore.getRegisteredInstanceType("authorizationComponent"); const authorizationComponent = ComponentFactory.get(authComponentType); diff --git a/packages/node-core/src/builders/helper/seedingHelper.ts b/packages/node-core/src/builders/helper/seedingHelper.ts index 2298e6b2..6ef500af 100644 --- a/packages/node-core/src/builders/helper/seedingHelper.ts +++ b/packages/node-core/src/builders/helper/seedingHelper.ts @@ -1,6 +1,6 @@ // Copyright 2026 IOTA Stiftung. // SPDX-License-Identifier: Apache-2.0. -import type { IPlatformComponent, IRouteAuthorization } from "@twin.org/api-models"; +import type { IBaseRoute, IPlatformComponent, IRouteAuthorization } from "@twin.org/api-models"; import type { IAuthorizationComponent, IAuthorizationInheritance, @@ -11,12 +11,13 @@ import { ContextIdKeys, ContextIdStore } from "@twin.org/context"; import { ComponentFactory, Is } from "@twin.org/core"; import type { IEngineCore, IEngineServer } from "@twin.org/engine-models"; import { HttpMethod } from "@twin.org/web"; -import { envObject, envString } from "./envHelpers.js"; +import { envChoice, envObject, envString } from "./envHelpers.js"; import { AUTHORIZATION_MODEL_ID, DEFAULT_ESCALATED_PRIVILEGE_ROLE, DEFAULT_USER_ROLE } from "../../defaults.js"; +import { AuthorizationModelMode } from "../../models/authorizationModelMode.js"; import type { IEngineEnvironmentVariables } from "../../models/IEngineEnvironmentVariables.js"; const DEFAULT_AUTHORIZATION_READER: IRouteAuthorization = { @@ -53,7 +54,12 @@ export async function seedAuthorizationDefaults( const authorizationComponent = ComponentFactory.get(authComponentType); const modelId = envString(envVars, "authorizationModelId", AUTHORIZATION_MODEL_ID); - const rulesMode = envVars.authorizationModelMode ?? "merge"; + const rulesMode = envChoice( + envVars, + "authorizationModelMode", + Object.values(AuthorizationModelMode), + AuthorizationModelMode.Merge + ); const customModel = envObject( envVars, @@ -79,63 +85,38 @@ export async function seedAuthorizationDefaults( } } - if (!Is.objectValue(customModel) || rulesMode === "merge") { + if (!Is.objectValue(customModel) || rulesMode === AuthorizationModelMode.Merge) { const policyKeys = new Set(); const inheritanceKeys = new Set(); const roles = new Set(); - const routes = engineServer.getRestRoutes(); - for (const route of routes) { - const requiresAuthorization = - route.requiresAuthorization !== false && route.skipAuth !== true; - let authorization: IRouteAuthorization | undefined = route.defaultAuthorization; - - // If there are no specific default permissions we provide - // a fallback based on the HTTP method for the default "user" role. - if (!Is.objectValue(authorization) && requiresAuthorization) { - if (route.method === HttpMethod.GET) { - authorization = DEFAULT_AUTHORIZATION_READER; - } else if ( - route.method === HttpMethod.PUT || - route.method === HttpMethod.POST || - route.method === HttpMethod.PATCH || - route.method === HttpMethod.DELETE - ) { - authorization = DEFAULT_AUTHORIZATION_WRITER; - } + for (const route of engineServer.getRestRoutes()) { + // Determine verb fallback: GET → reader, mutating methods → writer. + let fallback: IRouteAuthorization | undefined; + if (route.method === HttpMethod.GET) { + fallback = DEFAULT_AUTHORIZATION_READER; + } else if ( + route.method === HttpMethod.PUT || + route.method === HttpMethod.POST || + route.method === HttpMethod.PATCH || + route.method === HttpMethod.DELETE + ) { + fallback = DEFAULT_AUTHORIZATION_WRITER; } + seedRoute(route, fallback, policies, roleInheritances, policyKeys, inheritanceKeys, roles); + } - if (Is.objectValue(authorization)) { - const policyKey = `${authorization.permission}|${route.operationId}`; - if (!policyKeys.has(policyKey)) { - policyKeys.add(policyKey); - policies.push({ - subject: authorization.permission, - object: route.operationId, - action: "execute" - }); - } - if (Is.stringValue(authorization.role)) { - const inheritKey = `${authorization.role}|${authorization.permission}`; - if (!inheritanceKeys.has(inheritKey)) { - inheritanceKeys.add(inheritKey); - roleInheritances.push({ - role: authorization.role, - inheritsFrom: authorization.permission - }); - } - roles.add(authorization.role); - } - if (Is.arrayValue(authorization.inherits)) { - for (const inheritsFrom of authorization.inherits) { - const inheritKey = `${authorization.permission}|${inheritsFrom}`; - if (!inheritanceKeys.has(inheritKey)) { - inheritanceKeys.add(inheritKey); - roleInheritances.push({ role: authorization.permission, inheritsFrom }); - } - } - } - } + for (const route of engineServer.getSocketRoutes()) { + // Socket routes have no HTTP method, so fall back to reader for all authenticated routes. + seedRoute( + route, + DEFAULT_AUTHORIZATION_READER, + policies, + roleInheritances, + policyKeys, + inheritanceKeys, + roles + ); } for (const role of roles) { @@ -168,3 +149,62 @@ export async function seedAuthorizationDefaults( } ); } + +/** + * Merges a single route's authorization declaration into the shared accumulator sets. + * @param route The route to seed authorization for. + * @param fallbackAuthorization Authorization to apply when the route declares none. + * @param policies The policy accumulator. + * @param roleInheritances The role inheritance accumulator. + * @param policyKeys Deduplication set for policies. + * @param inheritanceKeys Deduplication set for role inheritances. + * @param roles Roles collected for escalation processing. + */ +function seedRoute( + route: IBaseRoute, + fallbackAuthorization: IRouteAuthorization | undefined, + policies: IAuthorizationPolicy[], + roleInheritances: IAuthorizationInheritance[], + policyKeys: Set, + inheritanceKeys: Set, + roles: Set +): void { + const requiresAuthorization = route.requiresAuthorization !== false && route.skipAuth !== true; + let authorization: IRouteAuthorization | undefined = route.defaultAuthorization; + + if (!Is.objectValue(authorization) && requiresAuthorization) { + authorization = fallbackAuthorization; + } + + if (Is.objectValue(authorization)) { + const policyKey = `${authorization.permission}|${route.operationId}`; + if (!policyKeys.has(policyKey)) { + policyKeys.add(policyKey); + policies.push({ + subject: authorization.permission, + object: route.operationId, + action: "execute" + }); + } + if (Is.stringValue(authorization.role)) { + const inheritKey = `${authorization.role}|${authorization.permission}`; + if (!inheritanceKeys.has(inheritKey)) { + inheritanceKeys.add(inheritKey); + roleInheritances.push({ + role: authorization.role, + inheritsFrom: authorization.permission + }); + } + roles.add(authorization.role); + } + if (Is.arrayValue(authorization.inherits)) { + for (const inheritsFrom of authorization.inherits) { + const inheritKey = `${authorization.permission}|${inheritsFrom}`; + if (!inheritanceKeys.has(inheritKey)) { + inheritanceKeys.add(inheritKey); + roleInheritances.push({ role: authorization.permission, inheritsFrom }); + } + } + } + } +} diff --git a/packages/node-core/src/defaults.ts b/packages/node-core/src/defaults.ts index d9fe6bb6..c17337ec 100644 --- a/packages/node-core/src/defaults.ts +++ b/packages/node-core/src/defaults.ts @@ -29,7 +29,7 @@ export const AUTH_SIGNING_KEY_ID = "auth-signing"; /** * Default model identifier for authorization. */ -export const AUTHORIZATION_MODEL_ID = "rest"; +export const AUTHORIZATION_MODEL_ID = "system"; /** * Feature tag identifying the DID context ID handler. diff --git a/packages/node-core/src/index.ts b/packages/node-core/src/index.ts index fa710e23..a810f605 100644 --- a/packages/node-core/src/index.ts +++ b/packages/node-core/src/index.ts @@ -5,6 +5,7 @@ export * from "./builders/engineServerEnvBuilder.js"; export * from "./builders/extensionsBuilder.js"; export * from "./cli.js"; export * from "./defaults.js"; +export * from "./models/authorizationModelMode.js"; export * from "./models/cliCommandParamType.js"; export * from "./models/IBootstrapDevEnvironmentVariables.js"; export * from "./models/ICacheMetadata.js"; diff --git a/packages/node-core/src/models/authorizationModelMode.ts b/packages/node-core/src/models/authorizationModelMode.ts new file mode 100644 index 00000000..5d855679 --- /dev/null +++ b/packages/node-core/src/models/authorizationModelMode.ts @@ -0,0 +1,24 @@ +// Copyright 2026 IOTA Stiftung. +// SPDX-License-Identifier: Apache-2.0. + +/** + * The protocol types for modules. + */ +// eslint-disable-next-line @typescript-eslint/naming-convention +export const AuthorizationModelMode = { + /** + * Merge the roles with the defaults. + */ + Merge: "merge", + + /** + * Replace the default roles. + */ + Replace: "replace" +} as const; + +/** + * The protocol type for a module. + */ +export type AuthorizationModelMode = + (typeof AuthorizationModelMode)[keyof typeof AuthorizationModelMode]; diff --git a/packages/node-core/tests/builders/engineServerEnvBuilder.spec.ts b/packages/node-core/tests/builders/engineServerEnvBuilder.spec.ts index 546292b3..0fcb8dd5 100644 --- a/packages/node-core/tests/builders/engineServerEnvBuilder.spec.ts +++ b/packages/node-core/tests/builders/engineServerEnvBuilder.spec.ts @@ -34,7 +34,7 @@ describe("buildEngineServerConfiguration - TenantOverride processors", () => { expect(socketTypes).toContain(SocketRouteProcessorType.TenantOverride); expect( config.types.restRouteProcessor?.find(p => p.type === RestRouteProcessorType.TenantOverride) - ).toMatchObject({ options: { config: { authorizationModelId: "rest" } } }); + ).toMatchObject({ options: { config: { authorizationModelId: "system" } } }); }); test("passes the configured authorization model to TenantOverride processors", async () => { diff --git a/packages/node-core/tests/builders/helper/envHelpers.spec.ts b/packages/node-core/tests/builders/helper/envHelpers.spec.ts index c6be21a7..9f670f4e 100644 --- a/packages/node-core/tests/builders/helper/envHelpers.spec.ts +++ b/packages/node-core/tests/builders/helper/envHelpers.spec.ts @@ -4,6 +4,7 @@ import { commaSeparatedListToArray, envArray, envBoolean, + envChoice, envCount, envDateTime, envInteger, @@ -579,18 +580,48 @@ describe("envString", () => { }); test("returns defaultValue when env var is absent", () => { - expect(envString<{ modelId?: string }>({}, "modelId", "rest")).toBe("rest"); + expect(envString<{ modelId?: string }>({}, "modelId", "system")).toBe("system"); }); test("returns defaultValue when env var is an empty string", () => { - expect(envString({ modelId: "" }, "modelId", "rest")).toBe("rest"); + expect(envString({ modelId: "" }, "modelId", "system")).toBe("system"); }); test("returns the string value when set", () => { - expect(envString({ modelId: "custom" }, "modelId", "rest")).toBe("custom"); + expect(envString({ modelId: "custom" }, "modelId", "system")).toBe("custom"); }); test("returns the string value with no default", () => { expect(envString({ modelId: "custom" }, "modelId")).toBe("custom"); }); }); + +describe("envChoice", () => { + const choices = ["merge", "replace"] as const; + + test("returns undefined when env var is absent and no default given", () => { + expect(envChoice<{ mode?: string }, "merge" | "replace">({}, "mode", choices)).toBeUndefined(); + }); + + test("returns defaultValue when env var is absent", () => { + expect(envChoice<{ mode?: string }, "merge" | "replace">({}, "mode", choices, "merge")).toBe( + "merge" + ); + }); + + test("returns defaultValue when env var is an empty string", () => { + expect(envChoice({ mode: "" }, "mode", choices, "merge")).toBe("merge"); + }); + + test("returns the matching choice when set", () => { + expect(envChoice({ mode: "replace" }, "mode", choices, "merge")).toBe("replace"); + }); + + test("returns the matching choice with no default", () => { + expect(envChoice({ mode: "replace" }, "mode", choices)).toBe("replace"); + }); + + test("throws GeneralError when the value is not one of the choices", () => { + expect(() => envChoice({ mode: "unknown" }, "mode", choices, "merge")).toThrow(); + }); +}); diff --git a/packages/node-core/tests/endpoints/groups/global-admin-unauthorized.json b/packages/node-core/tests/endpoints/groups/global-admin-unauthorized.json index 23be8a60..7ef9e011 100644 --- a/packages/node-core/tests/endpoints/groups/global-admin-unauthorized.json +++ b/packages/node-core/tests/endpoints/groups/global-admin-unauthorized.json @@ -24,7 +24,7 @@ { "description": "POST /authorization/rest/subject/:subject/role — assign tenant-admin role", "method": "POST", - "path": "/authorization/rest/subject/{{regularUserDid}}/role", + "path": "/authorization/system/subject/{{regularUserDid}}/role", "body": { "role": "tenant-admin" }, "expectedStatus": 204 }, diff --git a/packages/node-core/tests/migration.spec.ts b/packages/node-core/tests/migration.spec.ts index a4aecec7..621054c6 100644 --- a/packages/node-core/tests/migration.spec.ts +++ b/packages/node-core/tests/migration.spec.ts @@ -860,8 +860,6 @@ describe("migration - scope to roles", () => { // Run 2: restart. SchemaVersionService detects AuthenticationUser v0 → v1. // The removeEntityProperty handler splits scope into roles and writes them to - // SharedStore["migrationUserRoles"]. AuthorizationService.start() then consumes - // that store and calls addRoleForSubject for each entry. let run2; try { run2 = await run({ @@ -922,7 +920,131 @@ describe("migration - scope to roles", () => { expect(findAssignment("did:twin:user3", "user")).toBeDefined(); // All assignments must use the default migration model ID. - expect(rows.every(r => r.modelId === "rest")).toBe(true); + expect(rows.every(r => r.modelId === "system")).toBe(true); + } finally { + await run2?.shutdown(); + } + }); + }); + + test("Adds devops, identity-admin and identity-profile-admin when user has both tenant-admin and user-admin", async () => { + await ContextIdStore.run({ node: TEST_NODE_ID }, async () => { + const PORT_1 = 32200 + Math.floor(Math.random() * 200); + const PORT_2 = PORT_1 + 300; + + const AUTH_ENV: { [id: string]: string } = { + ...BASE_ENV, + TWIN_AUTH_ADMIN_PROCESSOR_TYPE: AuthenticationAdminComponentType.EntityStorage, + TWIN_AUTHORIZATION_CONNECTOR: AuthorizationConnectorType.EntityStorage + }; + + const run1 = await run({ + localesDirectory: LOCALES_DIR, + stateStorage: new MemoryStateStorage(false, { + nodeId: TEST_NODE_ID, + nodeOrganizationId: TEST_NODE_ORG_ID + }), + disableProcessExitOnFailure: true, + envVars: { ...AUTH_ENV, TWIN_PORT: String(PORT_1) }, + extendConfig: async (unusedEnvVars, config) => { + config.types.schemaVersionMigrationComponent = [ + { type: SchemaVersionMigrationComponentType.Service } + ]; + config.types.backgroundTaskComponent = [{ type: BackgroundTaskComponentType.Service }]; + } + }); + + // Clear stores from the previous test so migration only processes the user + // seeded in this test and the assertion on role-assignment count is exact. + const prevAuthConnector = EntityStorageConnectorFactory.get("authentication-user"); + const { entities: prevUsers } = await prevAuthConnector.query(); + for (const user of prevUsers ?? []) { + await prevAuthConnector.remove((user as { email: string }).email); + } + const prevRoleConnector = EntityStorageConnectorFactory.get("authorization-role-assignment"); + const { entities: prevRoles } = await prevRoleConnector.query(); + for (const role of prevRoles ?? []) { + await prevRoleConnector.remove((role as { id: string }).id); + } + + const svConnector = + EntityStorageConnectorFactory.get< + MemoryEntityStorageConnector<{ schemaName: string; version: number }> + >("schema-version"); + const svRecords = await svConnector.getStore(); + const svRecord = svRecords.find(r => r.schemaName === "AuthenticationUser"); + if (svRecord) { + await svConnector.set({ ...svRecord, version: 0 }); + } + + // Seed one user with both tenant-admin and user-admin to trigger the promotion branch. + const seedConnector = new MemoryEntityStorageConnector<{ + email: string; + password: string; + salt: string; + identity: string; + organization: string; + scope: string; + }>({ + entitySchema: "AuthenticationUserV0", + partitionContextIds: ["node"], + config: { storageKey: "authentication-user" } + }); + await seedConnector.setBatch([ + { + email: "combo@test.com", + password: "hashed", + salt: "salt", + identity: "did:twin:combo", + organization: TEST_NODE_ORG_ID, + scope: "tenant-admin,user-admin" + } + ]); + + await run1?.shutdown(); + + let run2; + try { + run2 = await run({ + localesDirectory: LOCALES_DIR, + stateStorage: new MemoryStateStorage(false, { + nodeId: TEST_NODE_ID, + nodeOrganizationId: TEST_NODE_ORG_ID + }), + disableProcessExitOnFailure: true, + envVars: { ...AUTH_ENV, TWIN_PORT: String(PORT_2) }, + extendConfig: async (unusedEnvVars2, config) => { + config.types.schemaVersionMigrationComponent = [ + { type: SchemaVersionMigrationComponentType.Service } + ]; + config.types.backgroundTaskComponent = [{ type: BackgroundTaskComponentType.Service }]; + } + }); + + const roleConnector = EntityStorageConnectorFactory.get("authorization-role-assignment"); + const { entities: assignments } = await roleConnector.query(); + const rows = (assignments ?? []) as { + id: string; + modelId: string; + subject: string; + role: string; + }[]; + + // tenant-admin + user-admin → 2 original + 3 promoted = 5 total + expect(rows).toHaveLength(5); + for (const role of [ + "tenant-admin", + "user-admin", + "devops", + "identity-admin", + "identity-profile-admin" + ]) { + expect( + rows.some(r => r.subject === "did:twin:combo" && r.role === role), + `expected role "${role}"` + ).toBe(true); + } + expect(rows.every(r => r.modelId === "system")).toBe(true); } finally { await run2?.shutdown(); } @@ -1086,7 +1208,7 @@ describe("migration - scope to roles multi-tenant", () => { expect(rowsA).toHaveLength(1); expect(rowsA[0].subject).toBe("did:twin:userA"); expect(rowsA[0].role).toBe("global-admin"); - expect(rowsA[0].modelId).toBe("rest"); + expect(rowsA[0].modelId).toBe("system"); // Tenant B: user must have tenant-admin role, isolated to tenant B's partition. const { entities: assignmentsB } = await ContextIdStore.run( @@ -1102,7 +1224,7 @@ describe("migration - scope to roles multi-tenant", () => { expect(rowsB).toHaveLength(1); expect(rowsB[0].subject).toBe("did:twin:userB"); expect(rowsB[0].role).toBe("tenant-admin"); - expect(rowsB[0].modelId).toBe("rest"); + expect(rowsB[0].modelId).toBe("system"); } finally { await run2?.shutdown(); } From 6ed30a6f48144655e2a43cb924ab843449182aa8 Mon Sep 17 00:00:00 2001 From: Martyn Janes Date: Wed, 2 Sep 2026 15:47:48 +0800 Subject: [PATCH 14/17] feat: pr comments --- packages/node-core/src/builders/helper/seedingHelper.ts | 9 +++++++-- .../endpoints/groups/global-admin-unauthorized.json | 6 ++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/node-core/src/builders/helper/seedingHelper.ts b/packages/node-core/src/builders/helper/seedingHelper.ts index 6ef500af..bacc6a5d 100644 --- a/packages/node-core/src/builders/helper/seedingHelper.ts +++ b/packages/node-core/src/builders/helper/seedingHelper.ts @@ -1,6 +1,11 @@ // Copyright 2026 IOTA Stiftung. // SPDX-License-Identifier: Apache-2.0. -import type { IBaseRoute, IPlatformComponent, IRouteAuthorization } from "@twin.org/api-models"; +import { + TenantEventType, + type IBaseRoute, + type IPlatformComponent, + type IRouteAuthorization +} from "@twin.org/api-models"; import type { IAuthorizationComponent, IAuthorizationInheritance, @@ -138,7 +143,7 @@ export async function seedAuthorizationDefaults( platformComponent.registerTenantEventCallback( "seedAuthorizationDefaults", async (tenantId, eventType) => { - if (eventType === "created") { + if (eventType === TenantEventType.Created) { await ContextIdStore.run( { ...nodeContextIds, [ContextIdKeys.Tenant]: tenantId }, async () => { diff --git a/packages/node-core/tests/endpoints/groups/global-admin-unauthorized.json b/packages/node-core/tests/endpoints/groups/global-admin-unauthorized.json index 7ef9e011..f7f7d6d7 100644 --- a/packages/node-core/tests/endpoints/groups/global-admin-unauthorized.json +++ b/packages/node-core/tests/endpoints/groups/global-admin-unauthorized.json @@ -37,6 +37,12 @@ "expectedStatus": 200, "capture": { "authToken": "cookie:access_token" } }, + { + "description": "GET /authentication/admin/users — rejected for user-only role", + "method": "GET", + "path": "/authentication/admin/users", + "expectedStatus": 401 + }, { "description": "POST /aig?override-tenant — rejected without global-admin role", "method": "POST", From 50d71a519328183859caa3c0681e72f42102fd93 Mon Sep 17 00:00:00 2001 From: Martyn Janes Date: Thu, 3 Sep 2026 09:57:59 +0800 Subject: [PATCH 15/17] feat: add password length env vars --- apps/node/.env.example-aws-ec2 | 6 +++ apps/node/.env.example-federated-catalogue | 6 +++ apps/node/.env.example-iota-testnet | 6 +++ apps/node/.env.example-local-entity-storage | 6 +++ docs/architecture/node-env-variables.mdx | 2 + .../src/builders/engineServerEnvBuilder.ts | 11 +++- .../IEngineServerEnvironmentVariables.ts | 10 ++++ .../engineServerEnvironmentVariableKeys.ts | 2 + .../tests/endpoints/groups/authorization.json | 50 +++++++++---------- .../groups/global-admin-unauthorized.json | 6 +-- packages/node-core/tests/index.spec.ts | 1 + 11 files changed, 76 insertions(+), 30 deletions(-) diff --git a/apps/node/.env.example-aws-ec2 b/apps/node/.env.example-aws-ec2 index e2f9d85d..dfd79747 100644 --- a/apps/node/.env.example-aws-ec2 +++ b/apps/node/.env.example-aws-ec2 @@ -446,6 +446,12 @@ TWIN_AUTH_PROCESSOR_TYPE="entity-storage" ## The HTTP header name used to pass the API key on requests, defaults to x-api-key. # TWIN_AUTH_API_KEY_HEADER="x-api-key" +## The minimum password length for new password validation, defaults to 15. +# TWIN_AUTH_MIN_PASSWORD_LENGTH="15" + +## The maximum password length for new password validation, defaults to 128. +# TWIN_AUTH_MAX_PASSWORD_LENGTH="128" + # Messaging ## Enable messaging, defaults to false. diff --git a/apps/node/.env.example-federated-catalogue b/apps/node/.env.example-federated-catalogue index 946b0223..880da6ca 100644 --- a/apps/node/.env.example-federated-catalogue +++ b/apps/node/.env.example-federated-catalogue @@ -474,6 +474,12 @@ TWIN_AUTH_PROCESSOR_TYPE="entity-storage" ## The HTTP header name used to pass the API key on requests, defaults to x-api-key. # TWIN_AUTH_API_KEY_HEADER="x-api-key" +## The minimum password length for new password validation, defaults to 15. +# TWIN_AUTH_MIN_PASSWORD_LENGTH="15" + +## The maximum password length for new password validation, defaults to 128. +# TWIN_AUTH_MAX_PASSWORD_LENGTH="128" + # Messaging # Not applicable for a standalone catalogue node. diff --git a/apps/node/.env.example-iota-testnet b/apps/node/.env.example-iota-testnet index 4032f4ba..3175b1dd 100644 --- a/apps/node/.env.example-iota-testnet +++ b/apps/node/.env.example-iota-testnet @@ -448,6 +448,12 @@ TWIN_AUTH_PROCESSOR_TYPE="entity-storage" ## The HTTP header name used to pass the API key on requests, defaults to x-api-key. # TWIN_AUTH_API_KEY_HEADER="x-api-key" +## The minimum password length for new password validation, defaults to 15. +# TWIN_AUTH_MIN_PASSWORD_LENGTH="15" + +## The maximum password length for new password validation, defaults to 128. +# TWIN_AUTH_MAX_PASSWORD_LENGTH="128" + # Messaging ## Enable messaging, defaults to false. diff --git a/apps/node/.env.example-local-entity-storage b/apps/node/.env.example-local-entity-storage index 1e963ab4..9b470249 100644 --- a/apps/node/.env.example-local-entity-storage +++ b/apps/node/.env.example-local-entity-storage @@ -446,6 +446,12 @@ TWIN_AUTH_PROCESSOR_TYPE="entity-storage" ## The HTTP header name used to pass the API key on requests, defaults to x-api-key. # TWIN_AUTH_API_KEY_HEADER="x-api-key" +## The minimum password length for new password validation, defaults to 15. +# TWIN_AUTH_MIN_PASSWORD_LENGTH="15" + +## The maximum password length for new password validation, defaults to 128. +# TWIN_AUTH_MAX_PASSWORD_LENGTH="128" + # Messaging ## Enable messaging, defaults to false. diff --git a/docs/architecture/node-env-variables.mdx b/docs/architecture/node-env-variables.mdx index 5ee1323d..116eaef2 100644 --- a/docs/architecture/node-env-variables.mdx +++ b/docs/architecture/node-env-variables.mdx @@ -200,6 +200,8 @@ These variables are only read when running the `bootstrap-dev` CLI command. They | `TWIN_AUTH_PROCESSOR_TYPE` | `entity-storage` | None | Authentication processor type. | | `TWIN_AUTH_SIGNING_KEY_ID` | Vault key identifier | `auth-signing` | Key used for auth signing operations. | | `TWIN_AUTH_API_KEY_HEADER` | Header name string | `x-api-key` | HTTP header name for the API key on requests. | +| `TWIN_AUTH_MIN_PASSWORD_LENGTH` | Integer | `15` | Minimum password length for new password validation. | +| `TWIN_AUTH_MAX_PASSWORD_LENGTH` | Integer | `128` | Maximum password length for new password validation. | | `TWIN_MIME_TYPE_PROCESSORS` | Comma-separated processor types | None | Additional MIME processor registrations. | | `TWIN_ROUTE_LOGGING_INCLUDE_BODY` | `true`, `false` | Uses debug value | Includes body in route logging. | | `TWIN_ROUTE_LOGGING_FULL_BASE64` | `true`, `false` | `false` | Includes full base64 payloads in route logging. | diff --git a/packages/node-core/src/builders/engineServerEnvBuilder.ts b/packages/node-core/src/builders/engineServerEnvBuilder.ts index 714f658e..0390b1f6 100644 --- a/packages/node-core/src/builders/engineServerEnvBuilder.ts +++ b/packages/node-core/src/builders/engineServerEnvBuilder.ts @@ -28,7 +28,12 @@ import { isTracingEnabled } from "./engineEnvBuilder.js"; import type { IEnvironmentVariables } from "../models/IEnvironmentVariables.js"; -import { commaSeparatedListToArray, envKeyIntegerPairs, envString } from "./helper/envHelpers.js"; +import { + commaSeparatedListToArray, + envInteger, + envKeyIntegerPairs, + envString +} from "./helper/envHelpers.js"; /** * Handles the configuration of the server. @@ -247,7 +252,9 @@ export async function buildEngineServerConfiguration( type: AuthenticationComponentType.EntityStorage, options: { config: { - signingKeyName: envVars.authSigningKeyId + signingKeyName: envVars.authSigningKeyId, + minPasswordLength: envInteger(envVars, "authMinPasswordLength"), + maxPasswordLength: envInteger(envVars, "authMaxPasswordLength") } } }); diff --git a/packages/node-core/src/models/IEngineServerEnvironmentVariables.ts b/packages/node-core/src/models/IEngineServerEnvironmentVariables.ts index f6a6a9df..ace5f65f 100644 --- a/packages/node-core/src/models/IEngineServerEnvironmentVariables.ts +++ b/packages/node-core/src/models/IEngineServerEnvironmentVariables.ts @@ -65,6 +65,16 @@ export interface IEngineServerEnvironmentVariables { */ authApiKeyHeader?: string; + /** + * The minimum password length for new password validation. + */ + authMinPasswordLength?: string; + + /** + * The maximum password length for new password validation. + */ + authMaxPasswordLength?: string; + /** * Additional MIME type processors to include, comma separated. */ diff --git a/packages/node-core/src/models/engineServerEnvironmentVariableKeys.ts b/packages/node-core/src/models/engineServerEnvironmentVariableKeys.ts index 323016d9..b91b0c73 100644 --- a/packages/node-core/src/models/engineServerEnvironmentVariableKeys.ts +++ b/packages/node-core/src/models/engineServerEnvironmentVariableKeys.ts @@ -23,6 +23,8 @@ const engineServerEnvironmentVariableKeysInternal: { authProcessorType: true, authSigningKeyId: true, authApiKeyHeader: true, + authMinPasswordLength: true, + authMaxPasswordLength: true, // IEngineServerEnvironmentVariables - routing mimeTypeProcessors: true, routeLoggingIncludeBody: true, diff --git a/packages/node-core/tests/endpoints/groups/authorization.json b/packages/node-core/tests/endpoints/groups/authorization.json index ba124913..6a6c9234 100644 --- a/packages/node-core/tests/endpoints/groups/authorization.json +++ b/packages/node-core/tests/endpoints/groups/authorization.json @@ -4,49 +4,49 @@ { "description": "POST /authorization/check — 400 missing subject", "method": "POST", - "path": "/authorization/rest/check", + "path": "/authorization/system/check", "body": { "object": "/data", "action": "read" }, "expectedStatus": 400 }, { "description": "POST /authorization/policy — 400 missing object", "method": "POST", - "path": "/authorization/rest/policy", + "path": "/authorization/system/policy", "body": { "subject": "test-subject", "action": "read" }, "expectedStatus": 400 }, { "description": "POST /authorization/policy — add policy", "method": "POST", - "path": "/authorization/rest/policy", + "path": "/authorization/system/policy", "body": { "subject": "test-subject", "object": "/data", "action": "read" }, "expectedStatus": 204 }, { "description": "POST /authorization/policy — add second policy", "method": "POST", - "path": "/authorization/rest/policy", + "path": "/authorization/system/policy", "body": { "subject": "test-subject", "object": "/data", "action": "write" }, "expectedStatus": 204 }, { "description": "GET /authorization/policy — list all policies", "method": "GET", - "path": "/authorization/rest/policy", + "path": "/authorization/system/policy", "expectedStatus": 200, "assert": { "body.entities": "isDefined" } }, { "description": "GET /authorization/policy/:subject — get policies for subject", "method": "GET", - "path": "/authorization/rest/policy/test-subject", + "path": "/authorization/system/policy/test-subject", "expectedStatus": 200, "assert": { "body.entities": "isDefined" } }, { "description": "POST /authorization/check — allowed after policy added", "method": "POST", - "path": "/authorization/rest/check", + "path": "/authorization/system/check", "body": { "subject": "test-subject", "object": "/data", "action": "read" }, "expectedStatus": 200, "assert": { "body.allowed": true } @@ -54,7 +54,7 @@ { "description": "POST /authorization/check — not allowed for unknown action", "method": "POST", - "path": "/authorization/rest/check", + "path": "/authorization/system/check", "body": { "subject": "test-subject", "object": "/data", "action": "delete" }, "expectedStatus": 200, "assert": { "body.allowed": false } @@ -62,116 +62,116 @@ { "description": "POST /authorization/policy/remove — remove one policy", "method": "POST", - "path": "/authorization/rest/policy/remove", + "path": "/authorization/system/policy/remove", "body": { "subject": "test-subject", "object": "/data", "action": "write" }, "expectedStatus": 204 }, { "description": "GET /authorization/roles — list all roles (empty initially)", "method": "GET", - "path": "/authorization/rest/roles", + "path": "/authorization/system/roles", "expectedStatus": 200, "assert": { "body.roles": "isDefined" } }, { "description": "POST /authorization/subject/:subject/role — 400 missing role", "method": "POST", - "path": "/authorization/rest/subject/test-subject/role", + "path": "/authorization/system/subject/test-subject/role", "body": {}, "expectedStatus": 400 }, { "description": "POST /authorization/subject/:subject/role — add editor role", "method": "POST", - "path": "/authorization/rest/subject/test-subject/role", + "path": "/authorization/system/subject/test-subject/role", "body": { "role": "editor" }, "expectedStatus": 204 }, { "description": "POST /authorization/subject/:subject/role — add viewer role", "method": "POST", - "path": "/authorization/rest/subject/test-subject/role", + "path": "/authorization/system/subject/test-subject/role", "body": { "role": "viewer" }, "expectedStatus": 204 }, { "description": "GET /authorization/subject/:subject/roles — get roles for subject", "method": "GET", - "path": "/authorization/rest/subject/test-subject/roles", + "path": "/authorization/system/subject/test-subject/roles", "expectedStatus": 200, "assert": { "body.roles": "isDefined" } }, { "description": "GET /authorization/subject/:subject/role/:role — has editor role", "method": "GET", - "path": "/authorization/rest/subject/test-subject/role/editor", + "path": "/authorization/system/subject/test-subject/role/editor", "expectedStatus": 200, "assert": { "body.hasRole": true } }, { "description": "GET /authorization/subject/:subject/role/:role — does not have admin role", "method": "GET", - "path": "/authorization/rest/subject/test-subject/role/admin", + "path": "/authorization/system/subject/test-subject/role/admin", "expectedStatus": 200, "assert": { "body.hasRole": false } }, { "description": "GET /authorization/role/:role/subjects — get subjects for editor role", "method": "GET", - "path": "/authorization/rest/role/editor/subjects", + "path": "/authorization/system/role/editor/subjects", "expectedStatus": 200, "assert": { "body.subjects": "isDefined" } }, { "description": "DELETE /authorization/subject/:subject/role/:role — remove viewer role", "method": "DELETE", - "path": "/authorization/rest/subject/test-subject/role/viewer", + "path": "/authorization/system/subject/test-subject/role/viewer", "expectedStatus": 204 }, { "description": "GET /authorization/subject/:subject/role/:role — no longer has viewer role", "method": "GET", - "path": "/authorization/rest/subject/test-subject/role/viewer", + "path": "/authorization/system/subject/test-subject/role/viewer", "expectedStatus": 200, "assert": { "body.hasRole": false } }, { "description": "POST /authorization/role/:role/inherit — add inheritance editor inherits viewer", "method": "POST", - "path": "/authorization/rest/role/editor/inherit", + "path": "/authorization/system/role/editor/inherit", "body": { "inheritsFrom": "viewer" }, "expectedStatus": 204 }, { "description": "GET /authorization/role/:role/parents — get parent roles for editor", "method": "GET", - "path": "/authorization/rest/role/editor/parents", + "path": "/authorization/system/role/editor/parents", "expectedStatus": 200, "assert": { "body.roles": "isDefined" } }, { "description": "GET /authorization/role/:role/children — get child roles for viewer", "method": "GET", - "path": "/authorization/rest/role/viewer/children", + "path": "/authorization/system/role/viewer/children", "expectedStatus": 200, "assert": { "body.roles": "isDefined" } }, { "description": "DELETE /authorization/role/:role/inherit/:inheritsFrom — remove inheritance", "method": "DELETE", - "path": "/authorization/rest/role/editor/inherit/viewer", + "path": "/authorization/system/role/editor/inherit/viewer", "expectedStatus": 204 }, { "description": "DELETE /authorization/subject/:subject/roles — remove all roles for subject", "method": "DELETE", - "path": "/authorization/rest/subject/test-subject/roles", + "path": "/authorization/system/subject/test-subject/roles", "expectedStatus": 204 }, { "description": "GET /authorization/subject/:subject/roles — empty after remove all", "method": "GET", - "path": "/authorization/rest/subject/test-subject/roles", + "path": "/authorization/system/subject/test-subject/roles", "expectedStatus": 200, "assert": { "body.roles": "isDefined" } } diff --git a/packages/node-core/tests/endpoints/groups/global-admin-unauthorized.json b/packages/node-core/tests/endpoints/groups/global-admin-unauthorized.json index f7f7d6d7..2fc83c2a 100644 --- a/packages/node-core/tests/endpoints/groups/global-admin-unauthorized.json +++ b/packages/node-core/tests/endpoints/groups/global-admin-unauthorized.json @@ -22,7 +22,7 @@ "expectedStatus": 201 }, { - "description": "POST /authorization/rest/subject/:subject/role — assign tenant-admin role", + "description": "POST /authorization/system/subject/:subject/role — assign tenant-admin role", "method": "POST", "path": "/authorization/system/subject/{{regularUserDid}}/role", "body": { "role": "tenant-admin" }, @@ -38,9 +38,9 @@ "capture": { "authToken": "cookie:access_token" } }, { - "description": "GET /authentication/admin/users — rejected for user-only role", + "description": "GET /authentication/admin/users/:email — rejected for user-only role", "method": "GET", - "path": "/authentication/admin/users", + "path": "/authentication/admin/users/{{adminEmail}}", "expectedStatus": 401 }, { diff --git a/packages/node-core/tests/index.spec.ts b/packages/node-core/tests/index.spec.ts index 15090aed..53fc107a 100644 --- a/packages/node-core/tests/index.spec.ts +++ b/packages/node-core/tests/index.spec.ts @@ -534,6 +534,7 @@ describe("node-core", () => { "POST /authentication/logout", "POST /authentication/refresh", "PUT /authentication/password", + "GET /authentication/policy", "POST /authentication/admin/users", "PUT /authentication/admin/users/:email", "PUT /authentication/admin/users/:email/password", From d167751b99e3105f76935443c9967bf215aa3b8c Mon Sep 17 00:00:00 2001 From: Martyn Janes Date: Fri, 23 Oct 2026 13:37:53 +0800 Subject: [PATCH 16/17] Merge branch 'next' into feature/authorization --- .../src/builders/engineEnvBuilder.ts | 8 + .../tests/builders/engineEnvBuilder.spec.ts | 18 +- pnpm-lock.yaml | 2515 ++++++++--------- 3 files changed, 1248 insertions(+), 1293 deletions(-) diff --git a/packages/node-core/src/builders/engineEnvBuilder.ts b/packages/node-core/src/builders/engineEnvBuilder.ts index 44d13266..042d67ed 100644 --- a/packages/node-core/src/builders/engineEnvBuilder.ts +++ b/packages/node-core/src/builders/engineEnvBuilder.ts @@ -111,9 +111,11 @@ import { } from "@3sixty/tracing-connector-opentelemetry"; import { type ITracingFacadeConfig, TracingFacade } from "@3sixty/tracing-facades"; import { + AUTHORIZATION_MODEL_ID, CONTEXT_ID_HANDLER_FEATURE_DID, CONTEXT_ID_HANDLER_FEATURE_TENANT, COMPONENT_FACTORY_TYPE_NAME, + DEFAULT_ESCALATED_PRIVILEGE_ROLE, DEFAULT_HEALTH_EXCLUDE_CLONE_COMPONENTS, DEFAULT_TRACING_FACADE_COMPONENT_EXCLUDE_TYPES, DEFAULT_TRACING_FACADE_FACTORIES, @@ -1836,6 +1838,12 @@ async function configureIdentityProfile( type: IdentityProfileComponentType.Service, options: { config: { + authorizationModelId: EnvHelper.envString( + envVars, + "authorizationModelId", + AUTHORIZATION_MODEL_ID + ), + escalatedPrivilegeRole: DEFAULT_ESCALATED_PRIVILEGE_ROLE, selfUpdateDeniedProperties: EnvHelper.envListToArray( envVars, "identityProfileSelfUpdateDeniedProperties", diff --git a/packages/node-core/tests/builders/engineEnvBuilder.spec.ts b/packages/node-core/tests/builders/engineEnvBuilder.spec.ts index 5576a6c0..4bd9977e 100644 --- a/packages/node-core/tests/builders/engineEnvBuilder.spec.ts +++ b/packages/node-core/tests/builders/engineEnvBuilder.spec.ts @@ -1388,9 +1388,14 @@ describe("buildEngineConfiguration - identity profile", () => { * @param config The built engine configuration. * @returns The service config, or undefined when the service component is not configured. */ - function identityProfileConfig( - config: Awaited> - ): { selfUpdateDeniedProperties?: string[]; adminScopes?: string[] } | undefined { + function identityProfileConfig(config: Awaited>): + | { + authorizationModelId?: string; + escalatedPrivilegeRole?: string; + selfUpdateDeniedProperties?: string[]; + adminScopes?: string[]; + } + | undefined { const entry = config.types.identityProfileComponent?.[0]; return entry?.type === IdentityProfileComponentType.Service ? entry.options?.config : undefined; } @@ -1401,19 +1406,24 @@ describe("buildEngineConfiguration - identity profile", () => { }); expect(identityProfileConfig(config)).toEqual({ + authorizationModelId: "system", + escalatedPrivilegeRole: "global-admin", selfUpdateDeniedProperties: undefined, adminScopes: undefined }); }); - test("uses the self update denied properties and admin scopes from the env vars", async () => { + test("uses the authorization model, self update denied properties and admin scopes from the env vars", async () => { const config = await buildEngineConfiguration({ identityProfileConnector: IdentityProfileConnectorType.EntityStorage, + authorizationModelId: "custom", identityProfileSelfUpdateDeniedProperties: "email, jobTitle", identityProfileAdminScopes: "profile-admin" }); expect(identityProfileConfig(config)).toEqual({ + authorizationModelId: "custom", + escalatedPrivilegeRole: "global-admin", selfUpdateDeniedProperties: ["email", "jobTitle"], adminScopes: ["profile-admin"] }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7ad8f2ad..f810b50e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -247,7 +247,7 @@ importers: devDependencies: '@3sixty/entity-storage-connector-memory': specifier: next - version: 0.20.0-next.0 + version: 0.20.0-next.1 '@3sixty/merge-locales': specifier: next version: 0.20.0-next.2 @@ -298,19 +298,22 @@ importers: dependencies: '@3sixty/api-auth-entity-storage-models': specifier: next - version: 0.20.0-next.0 + version: 0.20.0-next.1 '@3sixty/api-auth-entity-storage-service': specifier: next - version: 0.20.0-next.0(supports-color@10.2.2) + version: 0.20.0-next.1 '@3sixty/api-models': specifier: next - version: 0.20.0-next.0 + version: 0.20.0-next.1 '@3sixty/api-tenant-processor': specifier: next - version: 0.20.0-next.0 + version: 0.20.0-next.1 '@3sixty/auditable-item-graph-service': specifier: next version: 0.20.0-next.0 + '@3sixty/authorization-models': + specifier: next + version: 0.20.0-next.1 '@3sixty/cli-core': specifier: next version: 0.20.0-next.2 @@ -325,16 +328,16 @@ importers: version: 0.20.0-next.2 '@3sixty/data-core': specifier: next - version: 0.20.0-next.2 + version: 0.20.0-next.3 '@3sixty/data-json-ld': specifier: next - version: 0.20.0-next.2 + version: 0.20.0-next.3 '@3sixty/dlt-account': specifier: next - version: 0.20.0-next.0 + version: 0.20.0-next.1 '@3sixty/dlt-iota': specifier: next - version: 0.20.0-next.0(typescript@6.0.3) + version: 0.20.0-next.1(typescript@6.0.3) '@3sixty/engine': specifier: next version: 0.20.0-next.1(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(buffer@6.0.3)(socks@2.8.10)(supports-color@10.2.2)(typescript@6.0.3) @@ -358,7 +361,7 @@ importers: version: 0.20.0-next.2 '@3sixty/entity-storage-models': specifier: next - version: 0.20.0-next.0 + version: 0.20.0-next.1 '@3sixty/identity-connector-entity-storage': specifier: next version: 0.20.0-next.0 @@ -367,10 +370,10 @@ importers: version: 0.20.0-next.0 '@3sixty/logging-connector-opentelemetry': specifier: next - version: 0.20.0-next.0(@opentelemetry/api@1.9.1) + version: 0.20.0-next.1(@opentelemetry/api@1.9.1) '@3sixty/logging-models': specifier: next - version: 0.20.0-next.0 + version: 0.20.0-next.1 '@3sixty/modules': specifier: next version: 0.20.0-next.2 @@ -382,31 +385,31 @@ importers: version: 0.20.0-next.0 '@3sixty/standards-w3c-did': specifier: next - version: 0.20.0-next.1 + version: 0.20.0-next.2 '@3sixty/standards-w3c-odrl': specifier: next - version: 0.20.0-next.1 + version: 0.20.0-next.2 '@3sixty/telemetry-connector-opentelemetry': specifier: next - version: 0.20.0-next.0 + version: 0.20.0-next.1 '@3sixty/tracing-connector-opentelemetry': specifier: next - version: 0.20.0-next.0 + version: 0.20.0-next.1 '@3sixty/tracing-facades': specifier: next - version: 0.20.0-next.0 + version: 0.20.0-next.1 '@3sixty/tracing-models': specifier: next - version: 0.20.0-next.0 + version: 0.20.0-next.1 '@3sixty/vault-models': specifier: next - version: 0.20.0-next.0 + version: 0.20.0-next.1 '@3sixty/wallet-connector-entity-storage': specifier: next - version: 0.20.0-next.0 + version: 0.20.0-next.1 '@3sixty/wallet-models': specifier: next - version: 0.20.0-next.0 + version: 0.20.0-next.1 '@3sixty/web': specifier: next version: 0.20.0-next.2 @@ -419,13 +422,13 @@ importers: devDependencies: '@3sixty/automation-models': specifier: next - version: 0.20.0-next.0 + version: 0.20.0-next.1 '@3sixty/dataspace-models': specifier: next version: 0.20.0-next.0 '@3sixty/entity-storage-connector-memory': specifier: next - version: 0.20.0-next.0 + version: 0.20.0-next.1 '@3sixty/federated-catalogue-models': specifier: next version: 0.20.0-next.0 @@ -443,7 +446,7 @@ importers: version: 0.20.0-next.0 '@3sixty/telemetry-models': specifier: next - version: 0.20.0-next.0 + version: 0.20.0-next.1 '@3sixty/trust-models': specifier: next version: 0.20.0-next.0 @@ -500,44 +503,52 @@ packages: graphql: ^15.5.0 || ^16.0.0 || ^17.0.0 typescript: ^5.0.0 || ^6.0.0 - '@3sixty/api-auth-entity-storage-models@0.20.0-next.0': - resolution: {integrity: sha512-eJENhp2tXu35W4TxLYCZy06mT2T07FPQUeACi9v842YQdI/Gzt3cA60kcRW+EBKSLXYnuTkD1G8sexT/BJHryw==} + '@3sixty/api-auth-entity-storage-models@0.20.0-next.1': + resolution: {integrity: sha512-dM0GiVdtk98PpxnqqNjySpma9qEvtjsbYw1OZm14GLznUs9I/rgf6UI2RAYotACjMXMRKcljewIiIC0RRFZa3Q==} + engines: {node: '>=24.0.0'} + + '@3sixty/api-auth-entity-storage-rest-client@0.20.0-next.1': + resolution: {integrity: sha512-yA295aQfFj68Bd/edQm1LfjqE0AaiSIfPw+lMh85d4G1r/YzxpkTGSFqzUwkCP7xFdYA+bZhFUAWW9pYrpqz6Q==} engines: {node: '>=24.0.0'} - '@3sixty/api-auth-entity-storage-rest-client@0.20.0-next.0': - resolution: {integrity: sha512-QdeKN37n/A/4zMfFKlxer3v47C/07cK7k9AvmLzDYJRekIUVNDDlHBtFPVqKJyu4jQwfmn7akwa0Gr3M0YBP8A==} + '@3sixty/api-auth-entity-storage-service@0.20.0-next.1': + resolution: {integrity: sha512-yRcyDHhcaanu4q2DjwsSSZ4C/cUMwbZ48a5AxCmyqdc2PB7RA+2AU6ak3ciPGCz1NlJUZbyzhzJfyDZwzI9UHA==} engines: {node: '>=24.0.0'} - '@3sixty/api-auth-entity-storage-service@0.20.0-next.0': - resolution: {integrity: sha512-t8R1uHbF2WpphJE7dJje8YHSE1LcaNCNDVdXa7avUY2MdO5n8MFB2Z51LZ819c3miJ1j//TsP4ERCrjTt4C5Gw==} + '@3sixty/api-auth-models@0.20.0-next.1': + resolution: {integrity: sha512-KbzkoxveWHguZufLUPD6DnosHxqVQQvR4nPCzKZ8bey4oWPeJmviDvso3KXjYRk0pb2BtP8N1eTl9XgTuibB2Q==} engines: {node: '>=24.0.0'} - '@3sixty/api-core@0.20.0-next.0': - resolution: {integrity: sha512-tPyKJpr7Odcaa99U1dfCvy0UUiV7sZH7rBsFBJ5obXdlSXd0/aC6Sh2iFJpMShkr0NLTB7v4PhKE75BDvz/Qyw==} + '@3sixty/api-core-server@0.20.0-next.1': + resolution: {integrity: sha512-WfiTBDTLcuKo81MRzRxHDpo3v9euRvltJVA7lXT80mDpIbu1BBl55whSRsma/dcQ9JjqU3Jr5Q4b9uaRwCoWNQ==} engines: {node: '>=24.0.0'} - '@3sixty/api-models@0.20.0-next.0': - resolution: {integrity: sha512-AShxxmk3JR5dvLyC3zXYsBb4FZbtoNYsRlB2TUynLk4epOSZcZN+p8Ya+cMM+vsbLT8joA/Jk8TC9fPSEKSk3g==} + '@3sixty/api-core@0.20.0-next.1': + resolution: {integrity: sha512-gd6IJEufB6C7Sjv3G+BRPKP7UiZ1NTSUdJqD2nD5JSU9mJ41PwhkZ1PArV5PODUXUI8A/f93g463WxTlYf8Vgw==} engines: {node: '>=24.0.0'} - '@3sixty/api-processors@0.20.0-next.0': - resolution: {integrity: sha512-3LWV6EcdXXYoo5zNeLgOJbGanC/ezHr4vlM4CUC9CXeeYw2V4EL22IoVjehWqvTBuCCNdngcr9gOjM7xdhVZNg==} + '@3sixty/api-models@0.20.0-next.1': + resolution: {integrity: sha512-1KmZs1JOKJKqo1UEpIgWblBcnefBQ/L027HPcck7gqYp/pDJT93/OOPPv0VwHccDY4C/UN0ZhC1oD4TPv+2k3Q==} engines: {node: '>=24.0.0'} - '@3sixty/api-rest-client@0.20.0-next.0': - resolution: {integrity: sha512-3ka4h3Lq+SjZmH9Ud43m1DvAEBjcCgjDlUy6XHt1lTfDjYMVKdw4N2xDSRVGO9QqpOxXv91+489pQd097Tvihg==} + '@3sixty/api-processors@0.20.0-next.1': + resolution: {integrity: sha512-4AHoJH0ptvEMloN12KkZKyeHePnHUaNE0V/+IyT90WO+JzY1mJFD8U4nN8oq9uVlLSrY9BJK+xIXLOYIp1dd4w==} engines: {node: '>=24.0.0'} - '@3sixty/api-server-fastify@0.20.0-next.0': - resolution: {integrity: sha512-5D4A+tWpaK6vehufvUZu8FWExvPU8s6Lx2F7o6fHmX1YuW/ZfBGL+sxc/gR1/PlS6T8e8/iEIhNWjojPsrVUyw==} + '@3sixty/api-rest-client@0.20.0-next.1': + resolution: {integrity: sha512-kqwK5t6hUsn3zpOCkmxFLM4ydfszXgGfNw0kCp17shkvywwED5VGltSUcBWtzoEPkVEqJ7azji9YZ6n1zYw7Ow==} engines: {node: '>=24.0.0'} - '@3sixty/api-service@0.20.0-next.0': - resolution: {integrity: sha512-9ifuIEDau6NsxD0BSPUVmyFayJNtx8icePZ3DDT2QZopqwWj0qkHxyMYtfnFWAP/g6WaKgNTn3KcvHpJTyXPTA==} + '@3sixty/api-server-fastify@0.20.0-next.1': + resolution: {integrity: sha512-y1D5Mr8odZHvikxRjst0upGuXMb+dow5dB6FfUgwJ2hiBzEGOedIkz4lsc+mr1p/bWGyIH8WHWMNlT8l28v7hA==} engines: {node: '>=24.0.0'} - '@3sixty/api-tenant-processor@0.20.0-next.0': - resolution: {integrity: sha512-WG2QQwQg4SwlRmgmxAzGKhAYliw6BgsHRdb8AQ3oNdiQg7vC4UJayRzQT3T2NwXkNgsc6pu8LlhQAeWr/rjyVg==} + '@3sixty/api-service@0.20.0-next.1': + resolution: {integrity: sha512-trp2PbbfaPRkiE8/nLtS+tWGiu7lxzsCc19YSz3PARAzpwGLMy1gDFtGVz5O4qJbpY0kNv1+ujPUD+dkuXWuiQ==} + engines: {node: '>=24.0.0'} + + '@3sixty/api-tenant-processor@0.20.0-next.1': + resolution: {integrity: sha512-KKFguJ2wC6o1BOkuIoKbBwMck2D2T/Xil61gi++CFtMdcSS2tMbkvYpGYkngrpSwwnaGwtihAJ+UDO7DbjYSyA==} engines: {node: '>=24.0.0'} '@3sixty/attestation-connector-nft@0.20.0-next.0': @@ -580,68 +591,72 @@ packages: resolution: {integrity: sha512-pfAb97XXrn7TVFuf5DKo7cPrbucfNxIGpk5TKml8oCOU3p0FkpCSWOZ3tqZP6rTSebuATRkYW6Ul6hZeGJfiWg==} engines: {node: '>=24.0.0'} - '@3sixty/automation-actions@0.20.0-next.0': - resolution: {integrity: sha512-1xMrF/xnRTWIqDQaI/j6C6spIqTCdDibFwnnqqGNWNhqujkBY1gOVDRm9lo1FjgHR7f0QKegB6D5q2SWj/BvRA==} + '@3sixty/authorization-models@0.20.0-next.1': + resolution: {integrity: sha512-t8MsVzRm6AmlNUtENJLym7bW0zR8dwqZ920gErKRFGknbNH4eoh5fmxLH+4zA1EOmgohn//xSKP8UR9uxdRHNA==} engines: {node: '>=24.0.0'} - '@3sixty/automation-models@0.20.0-next.0': - resolution: {integrity: sha512-z64CRqJPClNurLHGT85ZCccQ98LqzmteB61MwMuih9LWQNrPgTfkM6/mSiy1cXanUvll8loBFfUnHJ7YchqsIg==} + '@3sixty/automation-actions@0.20.0-next.1': + resolution: {integrity: sha512-1kRe8G+3LgHZiHFMdc4BpIADkF3pYAgdgD0StggcYtBUQ1wGY9ElNBNEVTkM0rx4dGFAw8BwtOBMVlaHmR07Jg==} engines: {node: '>=24.0.0'} - '@3sixty/automation-rest-client@0.20.0-next.0': - resolution: {integrity: sha512-y81kN/Do/bSoT4tz2qpG2iJnU8/bMCdXetuncb6vqAhs98kdG/0HIwJq7h+05M7Yj3fBrbCWJSA0fXARgCnebw==} + '@3sixty/automation-models@0.20.0-next.1': + resolution: {integrity: sha512-o6+fYcrLu7CyyJn/zyM3E1sxeXMZhd3F7i7T6s6TFsV//BrQB/agfW5v9Vn8c3VHgI0BO2kQxzc1cK6LZT6P+Q==} engines: {node: '>=24.0.0'} - '@3sixty/automation-service@0.20.0-next.0': - resolution: {integrity: sha512-8gI8K5Tc8DaRSx0v01zFdEC4EZIkuHa8Kc5cxUa1HBU2drvmIvbQQDsSmnDmT2ptDTiYu2GeznLr2z+e56waMA==} + '@3sixty/automation-rest-client@0.20.0-next.1': + resolution: {integrity: sha512-JaTsKYtrd1xLhZDdv2g0nR7kd6Hqq5g6hL5qbhrF14HIeaeYd0nAhJIoTgA6Yb7QNd2/k9JTmyVvGxbNzOV++g==} engines: {node: '>=24.0.0'} - '@3sixty/background-task-models@0.20.0-next.0': - resolution: {integrity: sha512-CDLBSjZaTb81FFCV5OscA5G4gEAQb5zaKK4H9BcQiJnTf1k8U1BGeU+O5U+H9PM1v3Trm3h7eEqFhMbXKLonIQ==} + '@3sixty/automation-service@0.20.0-next.1': + resolution: {integrity: sha512-9P0USiWzjmgq+kuBdiTQ+j2O1Sc90vCnsQXcr6A7qYI60pc789cAh8sooS+FnWmmaVh/Co8Q+r0mgnPvOPDbyg==} engines: {node: '>=24.0.0'} - '@3sixty/background-task-scheduler@0.20.0-next.0': - resolution: {integrity: sha512-SRpka5SP6woyPBGJaPCiXTHJf3a4ob2RpVTEu/iOOcaW2kaFOilf9g5UAmslM4+NVLmgNHZGuL4f18pqLV/2zg==} + '@3sixty/background-task-models@0.20.0-next.1': + resolution: {integrity: sha512-GUfVa5aIINeKCU7FOFiFj433BlkY5LF+mNN6ZrlPCGFE2n68bzHL8romVw1RJxb6ocVIXgt7nJ0XWMO2+ALHXA==} engines: {node: '>=24.0.0'} - '@3sixty/background-task-service@0.20.0-next.0': - resolution: {integrity: sha512-NlJX4ooiPhaDfhhYNwfT+dBz6z2tsZQDgwutz4T2DNWng9fIlArXorESLXP9yn1UqR0+tI7hK9P5QguU8JHVzw==} + '@3sixty/background-task-scheduler@0.20.0-next.1': + resolution: {integrity: sha512-ws2B5tWslCdVKqUkGz9/WlURu4Fiq5ai51PPL1IIc3/n41TIeUF/tDxrMTxLmllX8QzkqWKH+1JMxl9bnNpkEA==} engines: {node: '>=24.0.0'} - '@3sixty/blob-storage-connector-aws-s3@0.20.0-next.0': - resolution: {integrity: sha512-S4HEabKD1CNtDCyXGe6/Xq+Z7xQndpAtTqsjIFs2eYpMl81vGLy0RE6M804WqZxAig6H5/8KB1ceQJkNQJjlBA==} + '@3sixty/background-task-service@0.20.0-next.1': + resolution: {integrity: sha512-Z/88zoVrtBtFr7dCvxOY2N5qGYT9sXLP0LyWWbQHJ6DAieuDi2QjN0GF2IqmOagKdzD3nA23JPp0o+Hs6n70/g==} engines: {node: '>=24.0.0'} - '@3sixty/blob-storage-connector-azure@0.20.0-next.0': - resolution: {integrity: sha512-CulApdbMFJ57y6sklrAEhTBhthuLTyKWcN+d2qNKJDzg3eJDlrxRQbrYvtVxkwYIlkcM3Eq3x50SJkWX2dnmuw==} + '@3sixty/blob-storage-connector-aws-s3@0.20.0-next.1': + resolution: {integrity: sha512-72/qu/3mkqx5grlp02aCVGsiDZlM0qpBGPMSjaFuFEE++rcawowUOSQubG8D8iMoYKYD1/WOrD6WXhhqRaufGw==} engines: {node: '>=24.0.0'} - '@3sixty/blob-storage-connector-file@0.20.0-next.0': - resolution: {integrity: sha512-i7Gi1DwRIww5Qh+0JVPNOM1OQsZO7yjaRUKxP+VSraqHrv3u831bn5sv0ZXTur+GqVIJ2SMNwMGBP2r5NUwADg==} + '@3sixty/blob-storage-connector-azure@0.20.0-next.1': + resolution: {integrity: sha512-mb4Zu7dsBeVReu09yMsiRIUb7+sQLxv3lcqPMlfYX4fRYGD2tzHjPp4+0/3nmC+g1wwbg7v4M/Oia0f1El0rNA==} engines: {node: '>=24.0.0'} - '@3sixty/blob-storage-connector-gcp@0.20.0-next.0': - resolution: {integrity: sha512-VTbC3uAzquJ/KJusTdqie9HrEFS88sS7ZBMwrcsypE1ZZI4bPILP19VNwEZWGUO+FW72w4dhb7ApJewnQBnA+g==} + '@3sixty/blob-storage-connector-file@0.20.0-next.1': + resolution: {integrity: sha512-QU2IuKbror23ITP0Qz+bk2LanS9OoM6FRSF6UqwPIM3vcbJSz/rEM1l0CCZMVo75O2uGU6uOgijPd9C615DXtw==} engines: {node: '>=24.0.0'} - '@3sixty/blob-storage-connector-ipfs@0.20.0-next.0': - resolution: {integrity: sha512-yUWF6a/1NbAE1gfy29jj5EwqUt2d89d3xY0I4p6zv4aAUvm9qBks3vKTWTJUOrlz1l/0vKZDIDVFUS+wscQ3cg==} + '@3sixty/blob-storage-connector-gcp@0.20.0-next.1': + resolution: {integrity: sha512-0rQYkapog3HN7nb2CGSBqqg55n79jYLljur+CyKeFXKGWIY9thYkEJeCPXvIrCX5qmBFI8a/KfX7EosjBYvQEQ==} engines: {node: '>=24.0.0'} - '@3sixty/blob-storage-connector-memory@0.20.0-next.0': - resolution: {integrity: sha512-fBZ+gU6Qhjy4/+odyEYJRvQeKnW9ERQ6/QHJt9dwCZ9DvYzvSIk2vRedpLeS9CFE7iOCfttI38RnT+0yyeVwHA==} + '@3sixty/blob-storage-connector-ipfs@0.20.0-next.1': + resolution: {integrity: sha512-BTh0ztLJqyXMZsnTkHgMfYiNrqFKA8vDB7nrLloaCjFlYEUuySXGoc34DqC7Fj23bvFThUrec7IOOhizlG0D0w==} engines: {node: '>=24.0.0'} - '@3sixty/blob-storage-models@0.20.0-next.0': - resolution: {integrity: sha512-GYfbemjn7jH04Kgn+2AeLbQ3jZyi595g5q/cBRXMDK46L8CG34VlBCdN6G9oiHU6Ub588ar8zvn5JMyi4DJrnw==} + '@3sixty/blob-storage-connector-memory@0.20.0-next.1': + resolution: {integrity: sha512-/d0TTgK20he1XuVYPMbtrd8EyiGaZA92EurgTtpGuj85hiy5/Ctb9/tE4PHOImwaYdAWxGY9MVx5jlQc9m6jBg==} engines: {node: '>=24.0.0'} - '@3sixty/blob-storage-rest-client@0.20.0-next.0': - resolution: {integrity: sha512-6Nv741s+TkRHOMLrnUQL/g0MV/Svx3nFbbsEC2hTa2W2cqzauIuFFyt3ShaW2q9LrZIb1ufU1YTac0mFs7gWOg==} + '@3sixty/blob-storage-models@0.20.0-next.1': + resolution: {integrity: sha512-pqm+iTR0YsRmXT03zi2m0CfEfG9/WCh9UFKi8Bi9jjPGZGzBOKXnMk3r2CIO7hecjdWq/o95q2M5Nqb1qphREg==} engines: {node: '>=24.0.0'} - '@3sixty/blob-storage-service@0.20.0-next.0': - resolution: {integrity: sha512-HXz7e5YNid+iKz63nxt791a9x9IMVBN5J8R74VeylWPaan0Jpc55d6vmvois0nUvM2v7EdRfoMXxXzl8gNDO3Q==} + '@3sixty/blob-storage-rest-client@0.20.0-next.1': + resolution: {integrity: sha512-BtURwjeJ1DhRhUpbyOjf3iJ1Jb33xqEyGYiF7KMPb6XuFxAtzN3O8mtOPgZjMOvrMdf9U1lBBOPxSp+2p9GkBQ==} + engines: {node: '>=24.0.0'} + + '@3sixty/blob-storage-service@0.20.0-next.1': + resolution: {integrity: sha512-fsu2h6H116+NBUoiQgmzeEaqWY9cvvJd6cUeBmum2b9HkGj0N3gRjGYRJYBd79GJxjZFGx+yTkGwXUL9KNGTkQ==} engines: {node: '>=24.0.0'} '@3sixty/cli-core@0.20.0-next.2': @@ -660,36 +675,36 @@ packages: resolution: {integrity: sha512-0tLDaAs5j3NDob9PcmTGP7SBBr2BUnmmgj7/EuvGZNXB1qDV9+ZlYbI2R6KSf8FtGs+S1VsOohgRoqIIBoGvgQ==} engines: {node: '>=24.0.0'} - '@3sixty/data-core@0.20.0-next.2': - resolution: {integrity: sha512-xn/powX6C5rDZs9jl3y4urvzyx07UcUwDFqKv+zoBMr4XKx599n4z3Adb+/gk0bkreEjXHomeo8zkel7HEatJw==} + '@3sixty/data-core@0.20.0-next.3': + resolution: {integrity: sha512-lqV/EM9n/O5U7Wuq1SNSJQPtpTiiKKL1QlmrekO78aLS6qLiolxQv5cRiN55eGdU/46hBxl7akvvzgtTa9HeJQ==} engines: {node: '>=24.0.0'} - '@3sixty/data-json-ld@0.20.0-next.2': - resolution: {integrity: sha512-1wjE0SrC71K7wk4hH4CLYwnPvLhXnTMpJNNm4/Y760htmf/2to6mE58O5RLsUEQPOPa0okvtwPSZTXj8RkVftw==} + '@3sixty/data-json-ld@0.20.0-next.3': + resolution: {integrity: sha512-YdmQ1h1DYVTCq+IZ2kG6p5M5ht0+Lc/Ij54tU3MkCgarA0jgRkCSaC6i37KVeMEMsslOJlhwaNhzxG4QoszPOQ==} engines: {node: '>=24.0.0'} - '@3sixty/data-json-path@0.20.0-next.2': - resolution: {integrity: sha512-VGXfIxzmwfsDt4b/hb7mymbpp1grcMSVvcOfGR9as7QDcazMYXO76lJWrOpcx0nwXbFwylurpzc8CycVqWe6cw==} + '@3sixty/data-json-path@0.20.0-next.3': + resolution: {integrity: sha512-5FguKap+8vsQk6mMCV2WCt+BQR8xTS39y7mXxaXk7W1IwDy59B4K7AZsB38ZmuqSBRHWZMdHr0tXvTcuix/WlQ==} engines: {node: '>=24.0.0'} - '@3sixty/data-processing-converters@0.20.0-next.0': - resolution: {integrity: sha512-P58ucje1vgEHW/uVcPNSg3JE/e/dvejvzfDo4FSB2rYbWDSY5wlpab3ymwjMSInO+3RkqbeD7rSO9BAnQZDLJA==} + '@3sixty/data-processing-converters@0.20.0-next.1': + resolution: {integrity: sha512-iGqCvxwx9s2Z/Z0dzmOSA5J5EpaFKnlZ/3iUXsujrIOKxgU05uAz++oBuz4RdBqyRgBa+fHDeEKOuFokU2afnw==} engines: {node: '>=24.0.0'} - '@3sixty/data-processing-extractors@0.20.0-next.0': - resolution: {integrity: sha512-LDT2zb8fywnBrV3EDyQ9Qe60fJ5hTGTy3DoCyV27SJ/2DrwtraMfzYp6V5GXHxErZ/cTzuD69lplE3T/kvQg3w==} + '@3sixty/data-processing-extractors@0.20.0-next.1': + resolution: {integrity: sha512-E3G1gbFSyILIE7f1U04X/S36QgU9O5/3oeetcd46d2ljVXI3mq4MuuhYCaHgPc+UHM8GnfYiiH/iUjoAlnvWiA==} engines: {node: '>=24.0.0'} - '@3sixty/data-processing-models@0.20.0-next.0': - resolution: {integrity: sha512-lagm3n6yxQAzNAte/xxDylnKjgst1KIYSVvAm1D5q9YV5z0DCuimWlSIbDRRibtmIwhXMshs5jifU0Ip0U/UIw==} + '@3sixty/data-processing-models@0.20.0-next.1': + resolution: {integrity: sha512-UTpOJwHYLtSOEHm70TFalaWbSbiN3+5nnOuxGDN9nnMecbW83CDwllmbDGfv52LDKK1B9Mjq2hv0siOZnDejfQ==} engines: {node: '>=24.0.0'} - '@3sixty/data-processing-rest-client@0.20.0-next.0': - resolution: {integrity: sha512-QqZtb62vWJyQGv2257mmq4U94WFTfWxQjUEngmRiBAaCCWn+DHT/A+vsB4Z1f7PskIR6KLPRLr4q3J1XOA0Maw==} + '@3sixty/data-processing-rest-client@0.20.0-next.1': + resolution: {integrity: sha512-IFVLGzDqwerrG4Gfes18uhy7qt8lc7ySA8k+LDXtzZUnDyWmOkJchRlx8CsmSNa5+YOKReoOCrIfz/eWf+z4Uw==} engines: {node: '>=24.0.0'} - '@3sixty/data-processing-service@0.20.0-next.0': - resolution: {integrity: sha512-fkdV2/regfE+/nFzqWgCZO1Le23gPXBOHXL+TG5kUJWf/Ehm87OVrKEeeECljXaH5iTqIo2O6xL/GkTIkBo9hQ==} + '@3sixty/data-processing-service@0.20.0-next.1': + resolution: {integrity: sha512-VTWTTimL5q7Sd/VLuaaQss0lLkV4PwBaWDFR2reOQG+SNjFmVZnqGb7fSnFff13cEPuQlHV0QeAshsLi2Qrhtw==} engines: {node: '>=24.0.0'} '@3sixty/dataspace-app-runner@0.20.0-next.0': @@ -720,12 +735,12 @@ packages: resolution: {integrity: sha512-okG6GnJvwvFLh4zLu9B1wbYmIoYaE3AaK+wlWfIGiuvBPFACxUkdlAHyhTkwiK1+St5rNzgZDpXocFx/OnjA/Q==} engines: {node: '>=24.0.0'} - '@3sixty/dlt-account@0.20.0-next.0': - resolution: {integrity: sha512-D4C5H51ogS+QzhOegcYLcnk608cJtdAZEZ199BSHKbTz9r35YetSuOdHn0FeHm6fHsGf9mF7SIbId1LCUlTlZQ==} + '@3sixty/dlt-account@0.20.0-next.1': + resolution: {integrity: sha512-vmI5iL3p2y0AqsRr/P+r5jLF7PADe39L67OnR/aEka6iOo5Kd+p+APKE3Rsb/NbKFW2YFaaULPv9e30/W0KVDA==} engines: {node: '>=24.0.0'} - '@3sixty/dlt-iota@0.20.0-next.0': - resolution: {integrity: sha512-6BJnJ0tQ+MjNIbUewjYV/n0gIq2/zx7VnHQIi5K0qPTvoD94WtdQ2zz2crh8Pe1Mv5NMqYjjAS52kVs07qOGFw==} + '@3sixty/dlt-iota@0.20.0-next.1': + resolution: {integrity: sha512-X3GEK1xTuQIYvMoZ7/s9Y1pShb9NLbzy/gwDVgNkdc28rGOKg5iFJnNHXuK4qVBSi1vgsNy+VNwYJI2oiZjSkA==} engines: {node: '>=24.0.0'} '@3sixty/document-management-models@0.20.0-next.0': @@ -764,72 +779,72 @@ packages: resolution: {integrity: sha512-g9e9HlOja1qdGdB+evf5lNV93s7GgYfqhAcwJ5eEE+D+BvBEpImVfFbxOzvZibhdddVfs4LC/WU57iA5RROitQ==} engines: {node: '>=24.0.0'} - '@3sixty/entity-storage-connector-cosmosdb@0.20.0-next.0': - resolution: {integrity: sha512-04Vdbcp5leblBPwlUBN94CbAY2TjAbvNMRe4eX0xym0I/imw+8QwpVaYyvyzWGZU+NDX1GZ8Je2y7kt3hpJbaA==} + '@3sixty/entity-storage-connector-cosmosdb@0.20.0-next.1': + resolution: {integrity: sha512-rZoKR9S76zBLNnrt/0/gRfuhItbb0fiFRQQ9kj/0M2YmGXCyQHVdZ31+h2ZraRKqH+RevVz1YhRHmWsd7QKVaA==} engines: {node: '>=24.0.0'} - '@3sixty/entity-storage-connector-dynamodb@0.20.0-next.0': - resolution: {integrity: sha512-cTtg5d7cPQHX4h+vtMYWDANluvpvb/3zOPwRvAcxy6+o01MZfntqsykWgSuo4nJxJm5a6qUpNzrqzqRjiCUqWA==} + '@3sixty/entity-storage-connector-dynamodb@0.20.0-next.1': + resolution: {integrity: sha512-GHE/upaBOWXug/bBwJCNJrujP9gfGZ7PuvKn1mTcmzURGVvZYWaRY7m+MRq0Ap9YeD4RH933D3oO6y7TvkchPg==} engines: {node: '>=24.0.0'} - '@3sixty/entity-storage-connector-file@0.20.0-next.0': - resolution: {integrity: sha512-4KJz/rgmgf7z49rj8l/MQ48tNwla1EWT7Wn/T22qeeukM9eBUYlcPb4M1RyoSn2fOhFNaT0Dc+tFU5j+zPpWQA==} + '@3sixty/entity-storage-connector-file@0.20.0-next.1': + resolution: {integrity: sha512-Px5iaUsoK5Bxxq6bdS6uq0iPJqSJonytsrtQBPgGg8kJc4dndvT2y6a9jRREd3gep+RYWVX9hvySMcSr07Gl7g==} engines: {node: '>=24.0.0'} - '@3sixty/entity-storage-connector-gcp-firestore@0.20.0-next.0': - resolution: {integrity: sha512-gQy6eGMI/Ak/c2x/qj7G6Hvj1ZhkJ6FHsziek7vMeCr4LjMjTwWYMeymyWTx+hC9BxaH0SveOvStjHtS8KDOYw==} + '@3sixty/entity-storage-connector-gcp-firestore@0.20.0-next.1': + resolution: {integrity: sha512-1hHzWjpH7fZAr8bmiaKmMFeve40P5e3ddwPL/PLsuqZpZP9AZiWftk+PmlLQ4tnJgKW8MFk09TWIRv4yFuDkrg==} engines: {node: '>=24.0.0'} - '@3sixty/entity-storage-connector-memory@0.20.0-next.0': - resolution: {integrity: sha512-jN76Ljx3Xmqx6sng1aBR6WE66mcxUxEwWON5CzBjBRq21PvJdS7jFmXz6JPJH387dRzy5ar76W9yenrES5ajrQ==} + '@3sixty/entity-storage-connector-memory@0.20.0-next.1': + resolution: {integrity: sha512-IEDnCJGk/DlH3jHajIG+s5SQ36ZhR0Mjo38ISXJKmXbQlcl4CtNfh3Ac/1isBt7cbL2FU4ZeJGOL1pVFAa4xlQ==} engines: {node: '>=24.0.0'} - '@3sixty/entity-storage-connector-mongodb@0.20.0-next.0': - resolution: {integrity: sha512-F9hzwup/pFZqmUHJfAlM32HdQwEca69M4u5a8d5ldP62VPcfTtNvUfekLdbO1nuqNHL5oa4/lkyvsaYBCtN4Qg==} + '@3sixty/entity-storage-connector-mongodb@0.20.0-next.1': + resolution: {integrity: sha512-NEfIyCDfkG2zteUIYT4zLJU7Gbo7Ue6yMfZl9f7erHL1y/tri1zT8v7Q2lTMRrlGj3Hj93IZcRW963ncZorGGg==} engines: {node: '>=24.0.0'} - '@3sixty/entity-storage-connector-mysql@0.20.0-next.0': - resolution: {integrity: sha512-gV869EI6shFASdsnfqZQzS0BYbSZqkJQN5yjrAGXLdAJC7ZNorVdIfwnAjg92AiGnLvxaIKqK+Gx2lo3QuRVfw==} + '@3sixty/entity-storage-connector-mysql@0.20.0-next.1': + resolution: {integrity: sha512-eqzg1Hi5p6ILDrkqG/k/WeWdeA0qXL64SZb1gs660hOrPf9gJymXNr7Df3WznAUTe6aia7ranV4pBVaqsF+ovg==} engines: {node: '>=24.0.0'} - '@3sixty/entity-storage-connector-postgresql@0.20.0-next.0': - resolution: {integrity: sha512-1sKRntmf9R2pCXKaSV+g5jKmkDDd7R1GiGuq+nQZYZ7yFJuUqgbEeNfugfXKWouX3fXn7stsB+B7RRsbrzyaTg==} + '@3sixty/entity-storage-connector-postgresql@0.20.0-next.1': + resolution: {integrity: sha512-mDzH+EB+T8NV+KW1w6K3lljsC/Exj/zConNK4JuvVYECk9oIK7v0vFszLix6JD0neykY18ZsN/mE27TvHbhBuA==} engines: {node: '>=24.0.0'} - '@3sixty/entity-storage-connector-scylladb@0.20.0-next.0': - resolution: {integrity: sha512-uW9VQXr4WgkIJcyz8w+KtofPypOxtGFXSLiZ9AUPzzhlx9s6juUalfHLx8qQ0Sf8laqFr3rm1MvLprVYABbppw==} + '@3sixty/entity-storage-connector-scylladb@0.20.0-next.1': + resolution: {integrity: sha512-2YOSx9Zl3ibF6v2Qj5kXSRhdwiU6YoBigKgNBDZXldj+Q6ISAqdzGi79zepm//sj8wqX87jYL/GJSH6FWVy4oA==} engines: {node: '>=24.0.0'} - '@3sixty/entity-storage-models@0.20.0-next.0': - resolution: {integrity: sha512-IG5JgBzpNScXF2+XExjFYLnSSbsFfYGCERXMx6JpB1NRzD7XvwmUWUkvBxGjcXhayEqnE0eEiEdXRp7Xevt3Iw==} + '@3sixty/entity-storage-models@0.20.0-next.1': + resolution: {integrity: sha512-Ruf3cG2VOipevsG1WnZjxya/MIu0M4XNaEwZ7O/inbje+vkdf0PHDyHqxcFXMXOTX+U8dvD+z7SPitfsBp/Tvg==} engines: {node: '>=24.0.0'} - '@3sixty/entity-storage-rest-client@0.20.0-next.0': - resolution: {integrity: sha512-V9H1JoWYdQcIQUJSuidknBpztDsh1BO5K6JVAzL9TdxPZQunvE3MffNCl/kIlw3CKM2o/n9/nbecFZbr5kaESA==} + '@3sixty/entity-storage-rest-client@0.20.0-next.1': + resolution: {integrity: sha512-QC/3vspO+LW9C6u8rKEM76X14Xg8qG8Z37Lcidv7kNDa7K0UHUmTw/71NOd+3uwgDuv7okN7bH4VcqoKvwAagw==} engines: {node: '>=24.0.0'} - '@3sixty/entity-storage-service@0.20.0-next.0': - resolution: {integrity: sha512-wOCoLXIUujtVCeROTwScf3kYp4BqNC1/R3BC5JZinp8i9NDVSRxHb9/ekU3EZaKTezVcsIUnBkJ1EPgN7rNElA==} + '@3sixty/entity-storage-service@0.20.0-next.1': + resolution: {integrity: sha512-H3LoZjV0jjFeh3nS3V5NHSWTsNo5/KCrr+TBOf9kr4Kh6+knS9Z4fJo3f6Gwg5u2kvlY8Lk4jqFof01nIjAsiA==} engines: {node: '>=24.0.0'} '@3sixty/entity@0.20.0-next.2': resolution: {integrity: sha512-iq8T0sVI+FGheo7SXmoEPtUAgSIvej7NSy06vD3od5a84WyHzTHsf4nlvV97VDegFyUxXjAhKS5WjLK8tbjFdA==} engines: {node: '>=24.0.0'} - '@3sixty/event-bus-connector-local@0.20.0-next.0': - resolution: {integrity: sha512-dyMWj6AJQ0e1l73LxWo7S6BorLWOzQVH2MvIfitmLwP7MJvsqJvwJlpJvWPtXNB3Kab5RQSoIkmqBDLbihbxbA==} + '@3sixty/event-bus-connector-local@0.20.0-next.1': + resolution: {integrity: sha512-LEtlZd6/eXk2XXGd2BDxLC5OXfuh7MUNCL47/wVNLsSKdf8Qt8uYRZTdtvW080id9YHixg+ZYyQvt2Yd8C7MdQ==} engines: {node: '>=24.0.0'} - '@3sixty/event-bus-models@0.20.0-next.0': - resolution: {integrity: sha512-6M+HJD0/lSuep58x4R3uv3DGTV3btQDwrbI2fJXJFW7OQ3BEQ0eyty9wGg6zlrctBgRh4HFguAqpwz3kTkLYkw==} + '@3sixty/event-bus-models@0.20.0-next.1': + resolution: {integrity: sha512-Yfn3diA7WXr2sxPc8KPGJotfv4OsVWnD682Iwg0NC3qYRvK7yLfRGLoTBAnCeGvNWgmPQm89ns98W4mLDPjaxA==} engines: {node: '>=24.0.0'} - '@3sixty/event-bus-service@0.20.0-next.0': - resolution: {integrity: sha512-kj0eRfyL+ldPyy2j0/wuQLxYtTfXmUDUzQWp2vjb1o6fkAqe++x6B0U4LiJG8gS2RBjD+VL3U1jfl7lAoUxUHw==} + '@3sixty/event-bus-service@0.20.0-next.1': + resolution: {integrity: sha512-EAbstJEk+1Qxb84CSRIRxqA7PsQwvOgzJJpjJ3JxUydD4akpZ8nKyCdDimK87bP3aU7HA24oSO1xWdXH9OOWfA==} engines: {node: '>=24.0.0'} - '@3sixty/event-bus-socket-client@0.20.0-next.0': - resolution: {integrity: sha512-KUWDLKEYF9PQzVg4XKMCpCiaAeqeGzAjlia+AyeFrqxnBJHChXpSZuIWvymsH1INPG/dWy6DxGosvje3NP5HeQ==} + '@3sixty/event-bus-socket-client@0.20.0-next.1': + resolution: {integrity: sha512-9QTnsDPfoGxg5Q3CzyGO9jvwvyvRfURFhy2GJAfxx01K9fBkchTE08Hh/Cc4ZbcnLxsxJ2771eqZ52m+uu5a2A==} engines: {node: '>=24.0.0'} '@3sixty/federated-catalogue-filters@0.20.0-next.0': @@ -888,64 +903,64 @@ packages: resolution: {integrity: sha512-ktfTt/wBGN2VRRXXs3nyiNcQg6EzBKe0OU6/Uiz9LkKmIeMBhL4Ph72SyxETJrdEXfhv3YKAs6kBWc0PIZz3jA==} engines: {node: '>=24.0.0'} - '@3sixty/logging-connector-console@0.20.0-next.0': - resolution: {integrity: sha512-UKVLVwRAyn0ItxAeajLUtZuoYVTC2Md6+QQa54/gyA7ntuTWzbIKY2HSft+ioWPbCXcAQ5WVnRp6xT+L64nMyQ==} + '@3sixty/logging-connector-console@0.20.0-next.1': + resolution: {integrity: sha512-y1sbV+BmE3mm+dkMyXZ74stqx8RXahNpEQaYNnCCL+pgnSjkXaKf8VM83YVY09qEraxQmCDp9G1lUWjj7Ctmmg==} engines: {node: '>=24.0.0'} - '@3sixty/logging-connector-elk@0.20.0-next.0': - resolution: {integrity: sha512-JfninvySpZsjdlk9oDcfA/YKIm99PM6+RdGVhOITZv/nE88IgQ08uKjEubpGp2r9diQN3E48rtKt2KmdfEbj4Q==} + '@3sixty/logging-connector-elk@0.20.0-next.1': + resolution: {integrity: sha512-WWDc0+gU4TrVvDRdns4SrxmL+NVJPVa2TknqKZzDfEmgg0sPI1WiGSA35uLoEUOkK0uvw6QewB3ZwIlgnFy2sQ==} engines: {node: '>=24.0.0'} - '@3sixty/logging-connector-entity-storage@0.20.0-next.0': - resolution: {integrity: sha512-sb3hUaMjjGS7cRjfCBjulpG4korFKIQTrjiPOQ0hKjvQBge1hFpxdAftBo3Ml2kRJHAOxdUffvR3LQRGKwZDxw==} + '@3sixty/logging-connector-entity-storage@0.20.0-next.1': + resolution: {integrity: sha512-sYmwxTkQxdRE3O6KPEiJfix2HuY/aJysAHW/Do5U/x4FYffC9Bf0keBHNR5pyKAgBqsUuV2SfQMn5haW+SSbRg==} engines: {node: '>=24.0.0'} - '@3sixty/logging-connector-file@0.20.0-next.0': - resolution: {integrity: sha512-CFMrxdmSfl1n44O7tctXWNMQUANKWbRQzxfpq+K210zNggbZJ6BCba0jO0ePUB0uIQqWnx7ipEMZD7XHjZ/ECw==} + '@3sixty/logging-connector-file@0.20.0-next.1': + resolution: {integrity: sha512-R8wxbhdGBn0hzjFAeFdJs5GbKJrJvR7n4KeSiI22LGKh1GsJfBAMKbbPsuMI4Gr4jhq9fXfWuKtyy0Dg/8PSKg==} engines: {node: '>=24.0.0'} - '@3sixty/logging-connector-opentelemetry@0.20.0-next.0': - resolution: {integrity: sha512-dAN0fdhDMT/UgcuXl3vjBvluS3cRLqpBMik/xoINPavalsHtLdRI3/RQSxrv5LZ6ciR9QWF1SREQ8aI1p6SPbg==} + '@3sixty/logging-connector-opentelemetry@0.20.0-next.1': + resolution: {integrity: sha512-sLxpDBlwCY9ex+d1MQk7S2waXNq5NanYZZwyBOkBcsbDBu/guR7BUoCvTkq2ebxmOAf/+vRzEUyucSaDaQpl5g==} engines: {node: '>=24.0.0'} - '@3sixty/logging-models@0.20.0-next.0': - resolution: {integrity: sha512-I4EunSdIs/pHPAM0uGw9T8KDWluGFtWJ5n+jYCW9Vwgk/OF4Vszila/IdSt0NN2kVYzGj4sCD6CvPtJOcT+FXw==} + '@3sixty/logging-models@0.20.0-next.1': + resolution: {integrity: sha512-PvrnZSBuws7TML96voAcKN7jZqMSbMKyq3IXh3dZ1zpgU6U7iBsqT5ynfOln2P3vkVdD29ohFOrX1zr5NPsX8Q==} engines: {node: '>=24.0.0'} - '@3sixty/logging-rest-client@0.20.0-next.0': - resolution: {integrity: sha512-kEDwffjCbZ13HMgOugnw68Rk2MbWNIIzV40XPnBF3MKb41JnjK5q2hnxNPZY02LINEvqX1jCZ/6oK2Fw5rVj8g==} + '@3sixty/logging-rest-client@0.20.0-next.1': + resolution: {integrity: sha512-edK7RsIUqIbbq/8ld3qzPIp2CA5Kn5UY5/7am8nta9R4aFBM6aPaivGWsshFBq79USf15v3o+AzQnFSBe2Tqog==} engines: {node: '>=24.0.0'} - '@3sixty/logging-service@0.20.0-next.0': - resolution: {integrity: sha512-9+78YukossYtOsfmBWsc0jj0Aeq5hsyarJpI/XjwAhdZJCA39ztj1OKhEShXa5D2JN4FrTDTxY6F/ZTX4/MYuA==} + '@3sixty/logging-service@0.20.0-next.1': + resolution: {integrity: sha512-dIq6p2rYwmg7A3DjGXCmHpVmEbuxpqNDd6AmHtyUrqr5+IJm+Dxr34LsR2N1/k8GVy3ugK0indujS81gQ07thA==} engines: {node: '>=24.0.0'} - '@3sixty/mailbox-connector-gmail@0.20.0-next.0': - resolution: {integrity: sha512-3khqSkiy1FtZ4S5JXZSYC/XAE9i6MeA4FoiqpF/cVkHLuWz9R+4ybJX9w7pZG9DcnZKIaPzP8uaadw5TtIzb3A==} + '@3sixty/mailbox-connector-gmail@0.20.0-next.1': + resolution: {integrity: sha512-JdBqxMwqPnhDSfy/HHwJ8/OU4c06xlccE6AD1VDUvhDrzaHCyWb44jkWkWfrBVL4+mEtsJgKSEOys4v5ByrGXQ==} engines: {node: '>=24.0.0'} - '@3sixty/mailbox-connector-imap@0.20.0-next.0': - resolution: {integrity: sha512-qYBWryUHUt7AippK920cac/ylv+pN6Lp1p1MtRN70RQFz8atZnjWDMITKTVr98wrXM7ZsFQL63OXIyLOvj16PA==} + '@3sixty/mailbox-connector-imap@0.20.0-next.1': + resolution: {integrity: sha512-Ja6uCy+8feyyhWm2NpqSyMIfdGMmzWbbBA8OIZf+BALAtMNlezdzc7GmCurl4DlISaQwQiaCJlX6Zo+oCfQtPQ==} engines: {node: '>=24.0.0'} - '@3sixty/mailbox-connector-outlook@0.20.0-next.0': - resolution: {integrity: sha512-Go+D4/L/EwiBiDpfl/N+Ry0YWYlTzoGlJKwkbduye0x3UCmSaYSKqFRab+NIYlzEcB9E4Adev2UJUgpr6i9ibg==} + '@3sixty/mailbox-connector-outlook@0.20.0-next.1': + resolution: {integrity: sha512-NGk0CS1KyFrFWnQx+urTL46uAJq+3UajXxdewomPddh5n+iHhdfnCm0URF/ccWk77jCS8PXnbDHlICn1B0tnpg==} engines: {node: '>=24.0.0'} - '@3sixty/mailbox-connector-pop3@0.20.0-next.0': - resolution: {integrity: sha512-vhoWn/yUzc7eUGvmW43XtimtMlHYNAOPjb8tPko9blYCbZEhGgsMYv6cf2y1Rlt/XE3/NoBZ6UexkYm3sV0LPg==} + '@3sixty/mailbox-connector-pop3@0.20.0-next.1': + resolution: {integrity: sha512-11tSyn+xHRPwrl2B0z8ijxom8uuX0GUpC4KFqVQxshPFVVZa9e5ae6V91dfcOmEn97hdck1XEzJZjFm4XO59TA==} engines: {node: '>=24.0.0'} - '@3sixty/mailbox-models@0.20.0-next.0': - resolution: {integrity: sha512-UUy/12/3qawt9HTiXpWyiUjN/yYVsJ7fa3ft+BGxw/fbn8yZIMNQgdJ4Xp47P2IPC213tIB/SeXq1RTnF5yVmQ==} + '@3sixty/mailbox-models@0.20.0-next.1': + resolution: {integrity: sha512-b1MUnRP8IvrOgoRg08X3/Qiyg09TzlFc4y13U8yHBWZ0s36Tn4ZuP5qkL8GRjYUCoZKZf2CBOshnEFIN2aN7Vg==} engines: {node: '>=24.0.0'} - '@3sixty/mailbox-rest-client@0.20.0-next.0': - resolution: {integrity: sha512-06t7QMakWa2g+otq7IZGyrKz14cPv5omBDD1C9QLmbBnpR7SZfulkq3OyczKskKWw9Y0pLZEo25ynIiQEqGnVQ==} + '@3sixty/mailbox-rest-client@0.20.0-next.1': + resolution: {integrity: sha512-vL4r9ifOHJnMze8KTvYOkkG1uz+edvcxPJMpzonQfCXVMdmPis9Ho1WaAb/0OB88M1vsCzNE2hRtFJro2v1kaA==} engines: {node: '>=24.0.0'} - '@3sixty/mailbox-service@0.20.0-next.0': - resolution: {integrity: sha512-WXvNCtyh4bKr+vK+bflPl0jAOzuJPco2g5WSY2kf+OnlFDgqlxLqxMz2/1F8MIf0SCkmglXqbH4ph5qraXJEgQ==} + '@3sixty/mailbox-service@0.20.0-next.1': + resolution: {integrity: sha512-sdxujaV/7o/otz++Kkm1HlTuez+BH3Og2a4b5vAxY9fO5JZYHAPN2rmHh6T8aBOHeFfr4vtQLT69nCepXnLTIA==} engines: {node: '>=24.0.0'} '@3sixty/merge-locales@0.20.0-next.2': @@ -953,24 +968,24 @@ packages: engines: {node: '>=24.0.0'} hasBin: true - '@3sixty/messaging-connector-aws@0.20.0-next.0': - resolution: {integrity: sha512-uMOXkjXanqSOil9wFADL0kzc6I4JHgX3IrMyhHrwf1R32Iz4JTcsRUqQxkgARIIfbLkx+NIEDvjFFSj8QA5ywA==} + '@3sixty/messaging-connector-aws@0.20.0-next.1': + resolution: {integrity: sha512-gkn/ygYQdKjit4fesPx5olj6RQUwJVsivMpqeTQk/c7hn6rus2xIvZ1nJz5IJEdVXVotCz7GHtULv2+9O966fQ==} engines: {node: '>=24.0.0'} - '@3sixty/messaging-connector-entity-storage@0.20.0-next.0': - resolution: {integrity: sha512-ClXIW+aekvNXHMoshJXdvR5TEWIsE50flgLkc8ttsu//TWTe26SnQZ5hCB9dwkILxD9JRqgcJ1OYf8gOC/lL+g==} + '@3sixty/messaging-connector-entity-storage@0.20.0-next.1': + resolution: {integrity: sha512-CfFUR5A+XcimMnTusD+8QtD1iGt6TO/bwdSG5cdGD0h9b9Fe02jGmH1/kxb6KmgGXESKkebaopqSHYScM5qPyQ==} engines: {node: '>=24.0.0'} - '@3sixty/messaging-connector-smtp@0.20.0-next.0': - resolution: {integrity: sha512-tFA7tEbYGbkS7wN58M0VW24jiAgu1YY0bJRzN02MGYmCgFH2J/q9gJX2QqcoitqeeEBtas9TYqxpVfCog0awrQ==} + '@3sixty/messaging-connector-smtp@0.20.0-next.1': + resolution: {integrity: sha512-alvqU9CTL2zOXsVGWFT0HPJKcqGNKlMY8eybm3KG7wOCQJ/iWNVcgTxgeaj+lzrAnKvIFGOdZ4FaMF+pPK1xpA==} engines: {node: '>=24.0.0'} - '@3sixty/messaging-models@0.20.0-next.0': - resolution: {integrity: sha512-3yOJAC8Pbay1bFxvS9KyYTTlDoMBLuyBYeAFTUYaOCGYnBpbDYqWoV4oMvZJTA3DQlQX+RkC49tPLT6g/u/G4A==} + '@3sixty/messaging-models@0.20.0-next.1': + resolution: {integrity: sha512-Lt4vKJq3SYEBmMRHMzGxK0EkR/PbWN6EY4vqYhZbjwpJ6JVOF+DP1kRiLjeWyxe+h7ud3/NtUyX+cawYtLey1g==} engines: {node: '>=24.0.0'} - '@3sixty/messaging-service@0.20.0-next.0': - resolution: {integrity: sha512-4NjNAQRdkPH7kUkggYI4JNt0kHVCkjH0s4W4oxHVq8IbbnxDBMCNUjYRgb0t7hHGAVk2YWY73rlSFhH7ytgO5Q==} + '@3sixty/messaging-service@0.20.0-next.1': + resolution: {integrity: sha512-ebp+5jQUNTLIdTMWWg06WMD6ZsvQ22l3fgiMEX710iWXRvMyQcsfa/ZXm1/IwsqMgsqLwqA82Xky5qtttxH2RA==} engines: {node: '>=24.0.0'} '@3sixty/modules@0.20.0-next.2': @@ -1074,68 +1089,68 @@ packages: resolution: {integrity: sha512-TmvamUtd6yI3XiKO2SKRsI5RSwAbonuJiHG36qOoqoZTBHAPjhIF5iLc739OOitKTqYxZ+ano1gD7QyV2aq/DQ==} engines: {node: '>=24.0.0'} - '@3sixty/standards-dataspace-protocol@0.20.0-next.1': - resolution: {integrity: sha512-TjsF4seaUjqWLMf0gzdVWqi8IHTnIb5hpin95a3iVCwd0VOVUYhY0QGm4ZAbCiX7NXg9Vs3Ck1RpxPsy4Fogvw==} + '@3sixty/standards-dataspace-protocol@0.20.0-next.2': + resolution: {integrity: sha512-LUDiYQfjbFFKUsIWZVeoS7c9YNX0S/S1wPboZbpXBoPqfCFqFYmWyLigdwFS7fwKV6f2J07SXMHkW0g9TYte9Q==} engines: {node: '>=24.0.0'} - '@3sixty/standards-dublin-core@0.20.0-next.1': - resolution: {integrity: sha512-EgKsqGSnUytAF/uBrJqvfa2+EMDLlHQmGTEeS55eYPs/kdDIVlDWJRYmXd2js+A/aYUSaPAFb4Z6GVtzaG4Qlw==} + '@3sixty/standards-dublin-core@0.20.0-next.2': + resolution: {integrity: sha512-uyuOoeaqBI+lDv/yH0uyBb1o4dWyRIJ9YQhlPqqQoBWABIpiaK0XoGJqfbVgxzF4bZlLh2JD1oiJrkdYKuZZQg==} engines: {node: '>=24.0.0'} - '@3sixty/standards-foaf@0.20.0-next.1': - resolution: {integrity: sha512-/pVyDNDxd9cBcjnLjsKhj0b5rCaoA52WDtw78ySrM+vQT57Ong7kf9EVvtgFe7JYBiQr0dSxT8XroFHlS42blw==} + '@3sixty/standards-foaf@0.20.0-next.2': + resolution: {integrity: sha512-vasSgW2fqGlZFtiFgv2KzF0+I4EYqq1llsmtDRWgpbgGa/vmYJfcfD8zDXMrIxJGTE8r11DRCqG/ZACALFcZTA==} engines: {node: '>=24.0.0'} - '@3sixty/standards-schema-org@0.20.0-next.1': - resolution: {integrity: sha512-q5ai+swNqOsp96ZVLysgR6fpHjFHCrFOr/DsCwfn4nRhJ7d1it3fqiXonCuJBRJuh1gV9WWm1JbJ1upPrp996g==} + '@3sixty/standards-schema-org@0.20.0-next.2': + resolution: {integrity: sha512-u0t76+kisicB102D70/33ZiPs7eAoxe4+YCiJ3uzovvFGCbFyrSzaPvHaXG4hSAdx8Jl5v5GwRM7zO8ePS3OlA==} engines: {node: '>=24.0.0'} - '@3sixty/standards-unece@0.20.0-next.1': - resolution: {integrity: sha512-nBl3o7iQ7uWYHyp/wmIg18nV92YE1y0ogObYLAsm3G6jncRXfti9/ciLcg5KYM860c274YOPEyms2PBc+1QEVw==} + '@3sixty/standards-unece@0.20.0-next.2': + resolution: {integrity: sha512-vh0h7rJRpxZpdNaO2sS3PWTPf+LZme9j5aMNVCTli9NdjT0A5EWNFKNfhBR+2bifZ0H6S2Cr5tFrNRUpCwzwdw==} engines: {node: '>=24.0.0'} - '@3sixty/standards-w3c-activity-streams@0.20.0-next.1': - resolution: {integrity: sha512-rW25GvypSQZcPq2ODTGHgyRYnZ8VFicUHmZgFnC37NROPV8HnrSKhouColVFNbTaJsKFw7gNTqIvUhToT5KcUA==} + '@3sixty/standards-w3c-activity-streams@0.20.0-next.2': + resolution: {integrity: sha512-cUfmfjm3FBr/voqzrflMuFaGVKv0YGbCM4UChrMrCjKERD/74gCV4e1i6rYT2UTvrmNNqRAtvlgwYDjhnqmYxQ==} engines: {node: '>=24.0.0'} - '@3sixty/standards-w3c-dcat@0.20.0-next.1': - resolution: {integrity: sha512-75+QAJybPWBWO7scW7J/cbsOPWnLlgyuTk7LLeUHdiDlGfOuYakQ0i8QdKf2tV73yfcrYLGmzGJN0hR5MEwE2A==} + '@3sixty/standards-w3c-dcat@0.20.0-next.2': + resolution: {integrity: sha512-ega9YpK5EMpXVm04nnR1sI6aPW5nq4RQShVRRLbBGlH3NDz6mbPwsk/ugDYpZLxOUJP8D1MLj72nov+aOVU/aA==} engines: {node: '>=24.0.0'} - '@3sixty/standards-w3c-did@0.20.0-next.1': - resolution: {integrity: sha512-mbnRB507N5McgPrbwQeOHH2ZN0Kuh1u6Sez4UqXoCGfPb0OKuvvTN1BJx6o5R7EwWS2wpSmXs0iU2MlKetokVw==} + '@3sixty/standards-w3c-did@0.20.0-next.2': + resolution: {integrity: sha512-TcOW4CN/nOWB/tOybAwxkwyqvHNVOOY+XWxeSTlAwEpQHTE6aNqo77E3dPoRVfFRUZb2nvHCggPUydbWpNNLfg==} engines: {node: '>=24.0.0'} - '@3sixty/standards-w3c-odrl@0.20.0-next.1': - resolution: {integrity: sha512-e3Izjd632M+Ieu1LQrJj2DaYKKSeCIwbGrDj6VHt2vSvUXBXFhJKdh1+4shhcMa5ywP59y23Tq107muqGqGfzA==} + '@3sixty/standards-w3c-odrl@0.20.0-next.2': + resolution: {integrity: sha512-HUZEMqZ/5Mv2uQZ9ppVzOzzs6CBfJm5OalNF1deq2EeMUZawlVRyIKBgl/0/airCLmh5qKBGjvIdzphDkVgGQw==} engines: {node: '>=24.0.0'} - '@3sixty/telemetry-connector-entity-storage@0.20.0-next.0': - resolution: {integrity: sha512-QnLH5wPXCnD3uMlqIt9QL8JJRBqILmP8BSSyppJY3qL4raFm/lIhEQy9irJT067KUgtR4NfQe6XQAlRWHQJKqw==} + '@3sixty/telemetry-connector-entity-storage@0.20.0-next.1': + resolution: {integrity: sha512-dyzO1OYtvjgnubx/esju1iDfGDXBfwA6/dyViijzRVy3EqkWlemOL6pnZfD071FZc2kLKT+RRLGb/zEtwyhjiA==} engines: {node: '>=24.0.0'} - '@3sixty/telemetry-connector-opentelemetry@0.20.0-next.0': - resolution: {integrity: sha512-BlF8t9pCWnBCVien5Sw3Ovdxqus8DJzwUjhPjVbAJpDf/XbD4K47C7eJfyp6AvsCT3P1iTkHear9DGfP5kZC9w==} + '@3sixty/telemetry-connector-opentelemetry@0.20.0-next.1': + resolution: {integrity: sha512-VsFQ1xQ/CVZqD8Tb+nq9lGruVhEQAtcO+mAYyh0h46us+CIQMkHEb2I8rUZWI6Kd7B+43pn5jQMtBizqF4fpEQ==} engines: {node: '>=24.0.0'} - '@3sixty/telemetry-models@0.20.0-next.0': - resolution: {integrity: sha512-upL9ip2c2JZvtL3KrNwPgAQxugm7z8fEr8LJhlNxwcYc9gL8fGzxx1kC7TEDLSaBQrVmQq74aeSHWdLsZ0VOyg==} + '@3sixty/telemetry-models@0.20.0-next.1': + resolution: {integrity: sha512-yqK3nWrqe4GCmo+mmLXytI+FWVm0d8CPIV9tw5OAtOVe9y6d7qKU63CR00mZGI6V/E/VTJmCv+Rm3ABRMVvwHQ==} engines: {node: '>=24.0.0'} - '@3sixty/telemetry-processors@0.20.0-next.0': - resolution: {integrity: sha512-BrBfeOWvjayzjSa63QeaM6ALiuSLPllnWSPFPqvJxKKfhZKLijXv4AO7ysfxC8rfMlNMKmgp75TGCi+dyDoySg==} + '@3sixty/telemetry-processors@0.20.0-next.1': + resolution: {integrity: sha512-rmo+CHxA5EvsiZZupO3/rOa2Ki20sfG0klthDIp/YbUMZ+AM2w5K0cmtGb35BfcO6VN5iBz5B1M1p2Zh7LRubw==} engines: {node: '>=24.0.0'} - '@3sixty/telemetry-producers@0.20.0-next.0': - resolution: {integrity: sha512-K7b/ULwW80BD4MTA0j75G7a3UX6h9fxyD6hR+2jFmkrPVbKPxZQyHHBYOsdDLO52L6OXHr6b+MLBcICQ2YCiQg==} + '@3sixty/telemetry-producers@0.20.0-next.1': + resolution: {integrity: sha512-zCsf83+6PKuX3Dvadv9StYm13qPZgtWv1gBmjEzP/8MWQuUqGXgj1sMFaCpqW76klzShjonoT5fXfihyWOY4vQ==} engines: {node: '>=24.0.0'} - '@3sixty/telemetry-rest-client@0.20.0-next.0': - resolution: {integrity: sha512-vpHEFAqWmYWrPi1kP81j+ox5FAKBZpAw8OG0LsyV7XLLsLPUExmBYd/NGpRGvoiH0BO7Qce8IJbZ77C0lc1ahA==} + '@3sixty/telemetry-rest-client@0.20.0-next.1': + resolution: {integrity: sha512-M8OsOlsol6ta4Asb8tw4p+YPbbCoBXiYbnwmVPgdXJCRjEdzx4+4QByZ6ko8CcngFEdHD2gKjMUJM47yeT0PHQ==} engines: {node: '>=24.0.0'} - '@3sixty/telemetry-service@0.20.0-next.0': - resolution: {integrity: sha512-7C1/oTzW2N8kY8gbrscboARw1v9Fn6Iut09apUXP9b+g1JmIRcw7bg+Dv7ZVkVEwB7Q20dMPo4sWV2H6DhrvuQ==} + '@3sixty/telemetry-service@0.20.0-next.1': + resolution: {integrity: sha512-6VngnwM4x6k4xlamkkThwIWv6H4wUauhgACVsCUl5YjTJ8vpAH5RDSmrzi38NFOnUb4q5VeAZe8tOCWbTVxYzw==} engines: {node: '>=24.0.0'} '@3sixty/tools-core@0.20.0-next.4': @@ -1146,36 +1161,36 @@ packages: resolution: {integrity: sha512-/Ehlhy4Hy5IArm9WJEMs8P42jFBuOwu3YSDiqKl3iAZulgcGrX9AHmIEWgx9nUuWNAZ8646sQwcIQdMNTcwsxQ==} engines: {node: '>=24.0.0'} - '@3sixty/tracing-connector-console@0.20.0-next.0': - resolution: {integrity: sha512-MlHa3R5IZz+jmFML3UIcf9YStfe3zZLEKKZ1ooDaabYKMi3OSmZvcYiSsKqchSNzx7isEHnPMKaJmnPI//c3Wg==} + '@3sixty/tracing-connector-console@0.20.0-next.1': + resolution: {integrity: sha512-R33R3sRaQipsfQmjwp4VZUqwVCwesFYOQV/abvyKk/e5livc4IEnxQhk32cNqEATcj6Ud0HTqEJzrdjdwRPbzQ==} engines: {node: '>=24.0.0'} - '@3sixty/tracing-connector-entity-storage@0.20.0-next.0': - resolution: {integrity: sha512-h7xW5sEfFt6xX56nWnNc+WXDFweN8DlVhemQlNdRIzFVTI2bv2+Tbws3RI7D0pnUcgAV4QFfZXp/x247DYwAGA==} + '@3sixty/tracing-connector-entity-storage@0.20.0-next.1': + resolution: {integrity: sha512-NveJrZukIuKlrpiFFUyk/0GVwK/wmSwp+9rM1SUrivNs7S9RtEEg1Ytl+3qOiK5llB/Q8KRxQRXN1nhpVLXbVA==} engines: {node: '>=24.0.0'} - '@3sixty/tracing-connector-opentelemetry@0.20.0-next.0': - resolution: {integrity: sha512-1lLkScz0FmoPI8UNF16+xux3aovXg6lig3OopMZ3EoQMw5jejZQtyU8iTVPhPwWXaUkgxZudQCHlRuu0kLrwXg==} + '@3sixty/tracing-connector-opentelemetry@0.20.0-next.1': + resolution: {integrity: sha512-eM2YjumyXko7UkX3++WAg42XXVy3r2kJaMdnPiroMuDLRbYXF4SXYeZNPanxNQRPFvySSMbcRfSZldBwN+z0EA==} engines: {node: '>=24.0.0'} - '@3sixty/tracing-facades@0.20.0-next.0': - resolution: {integrity: sha512-uZ8bluTR7HlnxpjVJ7JZiH8pTAGDzkb/OkrZk7/n4fIei2pQv8sW5cJwgQ+rS0fEXhaEi1FlY/3I3RsrhyAFWg==} + '@3sixty/tracing-facades@0.20.0-next.1': + resolution: {integrity: sha512-T3e7AC+SV9npGh13cH8KTaaTbqNXJjY0X9uY6+Cjen7s+eEuq+okoUNJYY5ibRsdU6FY0+/gXzO5nx1PFyulGA==} engines: {node: '>=24.0.0'} - '@3sixty/tracing-models@0.20.0-next.0': - resolution: {integrity: sha512-4BJLTsJXBB+k+S+1j4By3O+2MztnpOqBRkLU2dXp0B+S2r3NXeX4/GxoyS5eTUj2ICIdU/sdrdK3uyKQeJ7CyQ==} + '@3sixty/tracing-models@0.20.0-next.1': + resolution: {integrity: sha512-2Jj2ixWxKhE/IdYU1cQkcxZOmjaGdBvMhrjIUWz0uXbym2kUFtycFjHgLekKT+GrYmK2ZFXsNCwUopLjseScUA==} engines: {node: '>=24.0.0'} - '@3sixty/tracing-processors@0.20.0-next.0': - resolution: {integrity: sha512-jQ23Rj/J0nlZyt5tNNZ5cnQSK5IeaX1vOcl7WQSc+pw3nXFuFtPswIaPcCz1uYqaon3tj4Jl34RZpp11GJZA+g==} + '@3sixty/tracing-processors@0.20.0-next.1': + resolution: {integrity: sha512-uxJ6eu94xO2Wze/Agyaw+RD92HsJy4fdWyVPsGDJnN/SdRmn7URpgwGhUCLacX5UUm1gGTmA21Ljmwi08PGKfA==} engines: {node: '>=24.0.0'} - '@3sixty/tracing-rest-client@0.20.0-next.0': - resolution: {integrity: sha512-RBmMmDbzzPLUpuPPr/hiDiHvY5Xou9yKVPpqbDHaGyrfxcBVCeKWLK9a9fk38+RppHNdjBxqoQ9TKHKXV35wWg==} + '@3sixty/tracing-rest-client@0.20.0-next.1': + resolution: {integrity: sha512-tvKccelILh6lYypJdnQDaeEJ5rl7VbrZ5eP04X8c7GGHEpmTonywkOMhdEz4twzBnmh4Nzuipf5Py2Knots/Sg==} engines: {node: '>=24.0.0'} - '@3sixty/tracing-service@0.20.0-next.0': - resolution: {integrity: sha512-rxzXRWFqS+hBPmaqhmPh4GuwNZtYD/saIXY9M56ygkh5RCtMYmMHFAABDexeAssv1r+j5BBQlqDVTABtm62jpQ==} + '@3sixty/tracing-service@0.20.0-next.1': + resolution: {integrity: sha512-13/bqqort+zFS5MlCIcyNqhp8P2GoWo25vpA2Dm1OyMqMBWFjniBspEgqO+w671A6Ymr77l98UMPYxByqRosfw==} engines: {node: '>=24.0.0'} '@3sixty/trust-generators@0.20.0-next.0': @@ -1204,28 +1219,28 @@ packages: engines: {node: '>=24.0.0'} hasBin: true - '@3sixty/vault-connector-entity-storage@0.20.0-next.0': - resolution: {integrity: sha512-W1SgX1nFgDZYd5Dbjib4KtNK9dkwjMTfTztQqCiDq4kGiRoYo5oqbGazZ8edSXInawGiU+/FwauYjwh5/B+XeQ==} + '@3sixty/vault-connector-entity-storage@0.20.0-next.1': + resolution: {integrity: sha512-gPF8l3jxXihS7s+pvZKUsDHIEMiBAZC3nrAbrnTHvPBY6o3501qwww2q1wbGRc16RWdqC1AkmOAhusakPiMQ0Q==} engines: {node: '>=24.0.0'} - '@3sixty/vault-connector-hashicorp@0.20.0-next.0': - resolution: {integrity: sha512-rgl5hBcLjxSpXDpl2D57AIW+91s5cT0j8zDg2axta08kmb1V8v8EzL4YH5x16eoJZfm3lnTkkAtUz7pf2m94pA==} + '@3sixty/vault-connector-hashicorp@0.20.0-next.1': + resolution: {integrity: sha512-2OVTWif56zSEQ7Yjd4Fh0s++RDO9aL00jYfbaTh92S+mNM5Okiqcr1TMsf65oW5ZQZlgiKU9QPidLmcMZ925oA==} engines: {node: '>=24.0.0'} - '@3sixty/vault-models@0.20.0-next.0': - resolution: {integrity: sha512-6XQPJ+IKkiue0xTLCD2VtZP+HjokVEklkZuMYiOTFmFDGX1H5Ai+Qx3F4jO9jXvfP5bNjce4b5byhuPKC49N0A==} + '@3sixty/vault-models@0.20.0-next.1': + resolution: {integrity: sha512-w3rNruwfhaiNpkIopMuD3Yn/5vTyfCWntJ2sJu/xT5nrUyqGm3GkgvbkTZeF7q9Q3nuvQRt3nWkdSjUM3cZoTw==} engines: {node: '>=24.0.0'} - '@3sixty/wallet-connector-entity-storage@0.20.0-next.0': - resolution: {integrity: sha512-LpL4GU3ZQsDBbNHpyzTU2pGvW1lxroASa1ZnnB8vwdaBAr7drGXytXFiIjZg4wC21zPRMNrabTFOGGN46nxO2g==} + '@3sixty/wallet-connector-entity-storage@0.20.0-next.1': + resolution: {integrity: sha512-X0xXzl5uWhJExq8k+woATBVFY4J48MypAgOE3J6nkDd+45AGb+X6B/XzPq+3J8ApHTsC3QZZ5MwZyrditmqing==} engines: {node: '>=24.0.0'} - '@3sixty/wallet-connector-iota@0.20.0-next.0': - resolution: {integrity: sha512-DnL75QM5ChMF8bMNILsyXpWbCoE2OWrS2+krulwd1PgfbOCIk0uEWSYbGeJhwn2bqtc0k9gnHFQT0SApMR/3yw==} + '@3sixty/wallet-connector-iota@0.20.0-next.1': + resolution: {integrity: sha512-TNLVTDDxtRB6ffQiP5R8FKglbKYDDwzCdCixahfHTfSUpALoO3kyeVGK244a6e4rW7kDX/itenSrOkQF4DqIFA==} engines: {node: '>=24.0.0'} - '@3sixty/wallet-models@0.20.0-next.0': - resolution: {integrity: sha512-bkCKbHnyrIF/gfvNRRRi/HZVzNUpv4dXvApO4IIJ60ZQzVJL1EA/ojLyXi8CHEHR0cpfN6P6m/BQrt1ZbBJ1DQ==} + '@3sixty/wallet-models@0.20.0-next.1': + resolution: {integrity: sha512-TBML2KotQxdAU6FREheMZsuXIKBuzpujtNfugxtrSLZ7BeiRt8KlQxBJ5vH7F6R/1/bAKGokfTvHMnTZsnORJg==} engines: {node: '>=24.0.0'} '@3sixty/web@0.20.0-next.2': @@ -1236,20 +1251,20 @@ packages: resolution: {integrity: sha512-H8BiG/2DnfwydVxD1uDPLa1s1sfhRnVTbD2OwzfTr3WlJzgbIzICDXxBTlTMjbWNNCe4VS9X55fco+JI34L9kw==} engines: {node: '>=20.0.0'} - '@aws-sdk/client-dynamodb@3.1137.0': - resolution: {integrity: sha512-KBSA5fw7cJaEiTOQem4NF0StMf8tSIt40uMqmTtW39JOTKvXG851FSXLLNnsN+xupnrFt6LMUKErOtUY3Ip2FA==} + '@aws-sdk/client-dynamodb@3.1153.0': + resolution: {integrity: sha512-VLltvPCGtzBIskdvOY6MDkCM5igTCAY4KUpFTFh/ak1DuvrJ8R9H0hiSfPBj8meqyJkc+dzc2oACVnwT9JMjvg==} engines: {node: '>=20.0.0'} - '@aws-sdk/client-s3@3.1137.0': - resolution: {integrity: sha512-ppiYnDyy2qCDT3PIV83XJwAi0BhVUZ/jOHxUgC5tlMCaFeKRL8PVVub8A0pUMkF1yvZtzNOp3ClbmTCcIa9w3g==} + '@aws-sdk/client-s3@3.1153.0': + resolution: {integrity: sha512-h0VScQZPfBApg1Qi4AedsOUSMZ7m758kZIg0JO0B5HtwSzQhB7Tgh6h1JoGEXELgrWADPusYMpMBDmrRAEx2yw==} engines: {node: '>=20.0.0'} - '@aws-sdk/client-ses@3.1137.0': - resolution: {integrity: sha512-Jc1rSvHYW78ElD1z4fXCw0YNF6eExMWvCIFi23OcC0qbsznSXH9utDx98Ula0mWs9UzC0Qk93AqReCl5qXy+Qw==} + '@aws-sdk/client-ses@3.1153.0': + resolution: {integrity: sha512-znAL7AX9JJN9QRRziqmdtAQnO9qB4w97xcJHxuWoDIiUexbeAesxQ3kafw/KHFKE84LUlUaJf5EcRpDBhM2aeQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/client-sns@3.1137.0': - resolution: {integrity: sha512-Tm/jSr8SLjE7PnV8oTKB5byLTuqbWfZmm1BZprgbhASmyE/nvPiWHNkWuaHWwRspUVle/CFEeoH7XkT0wl1d+A==} + '@aws-sdk/client-sns@3.1153.0': + resolution: {integrity: sha512-QZpScoOcw4/DZhF5EB/emNkaii7FpL353yf/9CvFdQ5+ubAniHaQkcjGnwvKAbNF3EWf9aOQxBQjFr9m+woekw==} engines: {node: '>=20.0.0'} '@aws-sdk/core@3.978.4': @@ -1296,11 +1311,11 @@ packages: resolution: {integrity: sha512-8q1ICxcDjHId3bBryuu/j+1L9y5/3uQnwzLDt5j2ElcjZSoWmFtymdJy7OjLrluSMe0Z4mq5bcH4fxBXvlEHfw==} engines: {node: '>=20.0.0'} - '@aws-sdk/lib-dynamodb@3.1137.0': - resolution: {integrity: sha512-Ct0gRkFyxq5Uev59IMjUoJH5J+82OXCGxmwUIJzOD1xmqutX0EJf7co7l7mp/61MDH7Z+9n9I42Gf1OcPlh2Bw==} + '@aws-sdk/lib-dynamodb@3.1153.0': + resolution: {integrity: sha512-sKfv+zV5dLg7MgBOHWBSdF/lmEfK/SOkmOS/nbYy2ocA5FOx6p+v0STz38pCpVaWKRHxrNbJNjk1yWXLB2d88g==} engines: {node: '>=20.0.0'} peerDependencies: - '@aws-sdk/client-dynamodb': ^3.1137.0 + '@aws-sdk/client-dynamodb': ^3.1153.0 '@aws-sdk/middleware-endpoint-discovery@3.972.33': resolution: {integrity: sha512-0ed2hDcj2bAQviyydVAWtu63Bl2R0fsvQgw3SK+X9ei7EpFegUdhpdRW/N7cJZIl4YPJXhMnmaq32wDcvUtacA==} @@ -1403,16 +1418,16 @@ packages: resolution: {integrity: sha512-rbAE25KUfjU/s3XHUdJgceoCP5dEOpMx85J04kF+QMdta73XkuG9JGHHinch+XIoKpBdqljin+KqURpJriSzLA==} engines: {node: '>=22.0.0'} - '@azure/msal-common@16.14.1': - resolution: {integrity: sha512-Or6xhPNyi4zHW25158yxBoyxuCqNSPa5YBVqfF1J5Ks4MJWBo/USXdp05DQIPu1Zli00YZu6t0+h6KvHJealxQ==} + '@azure/msal-common@16.14.2': + resolution: {integrity: sha512-HOBR0Gfo39TMrkxNG8k6cfjRkrRjXZc3JQs3ebMWQc9S4cihuknMYra3sgmzbZB752oQBqBN9+WF7c826p2vIQ==} engines: {node: '>=0.8.0'} - '@azure/msal-node@6.0.1': - resolution: {integrity: sha512-ixSO1Y/kCVRthRs+hSx/5qkwaunX1/RAePhlMN0wIpIQ4WEZ6AREGGnGd1AP0qspHVsAwzWQKGubpjh50JyJIQ==} + '@azure/msal-node@7.1.0': + resolution: {integrity: sha512-s1O6hSY/C/dmqykTmmeHY6GhSkDuY8N1gxyhuLyaCwbY7N+UBvU2Wu4flas7+NxZiAPcXNPVpgt3n/HP/5yL+w==} engines: {node: '>=20'} - '@azure/storage-blob@12.33.0': - resolution: {integrity: sha512-2SX8oP8PyblUcAFZSg39c8Ls+tFjavM6sBeV+qpw33mRzRhI/5hrFJmJ/x0H9xx5l6ECPvgSP8uPxqTeVbHNIA==} + '@azure/storage-blob@12.34.0': + resolution: {integrity: sha512-cXDTCAMwDx8Ng9yUe82kOOd2kPnZ8AQqe4FkLMcpaQ3Mvr3/PXVdvRhyP0FtY5/U5Oh6JGk3EcEibaFOymRLFw==} engines: {node: '>=22.0.0'} '@azure/storage-common@12.5.0': @@ -1853,11 +1868,11 @@ packages: '@fastify/ajv-compiler@4.0.7': resolution: {integrity: sha512-VP0yIfwlc1ohj733keYDqyHm1VWeP9VQxYomunhr90jkC4aNNibbkrRiaNgPgqj1ORxUenILR4qzA/ppYBNAtQ==} - '@fastify/compress@9.2.0': - resolution: {integrity: sha512-35VL33PIEt/UbD/ZMlRNaICd2BQz0IaG7en74Dv7tI+MHIQkedibS1+9JfekWH4I1g+Y8RbbZD4Zsk9h4XTItg==} + '@fastify/compress@9.2.2': + resolution: {integrity: sha512-FF1CSw1ED4f2lZmYDXmpHgDJLj752JBr7Tdv6Z5SYkZmbvwzlagWwKvF3OGWPzbL7pRFgoki6rNyh/yu8tb92w==} - '@fastify/cors@11.3.0': - resolution: {integrity: sha512-ggQGua+xHv1MvePbPr0v//xLYEsCXbWspquXCJS9Ot5YoRXq8J8ZWzHnxDBVnbtXosvistXo6LtNzOJswf64Fw==} + '@fastify/cors@11.3.1': + resolution: {integrity: sha512-gZXNzd6FLHzOIfvoK4+Az3Wko2V6Y0MIsLxpyo4AEYl7a9q1JBPwPaxLea4nkr++8FCiJiPpYYo6E02uZW0dqw==} '@fastify/deepmerge@3.2.2': resolution: {integrity: sha512-155eqA/WMQdN6gUD4RrhS2K0Pcz2Ou9pQ86L0sipOpP9ONbTA6oYw/hW4VdBjR4egcDHqmWUK9x80oUX7S1mDQ==} @@ -1897,8 +1912,8 @@ packages: resolution: {integrity: sha512-wfHJPZmLqzpy6FN6U+7HkkP/AKhGsbHSpEy/qL2TyI3/pKRAvpamQxZ2qvps5hMRgAjfuHCim+oeJj9RveCaqg==} engines: {node: '>=18'} - '@google-cloud/firestore@9.2.0': - resolution: {integrity: sha512-4BI2686ygMkef0Pe4QnX9hnWeGCUjaAP5m+Ow5/yNWwGxGadO741Ct28MRXW9czg0pnvz919INKbQdCgUMcfeA==} + '@google-cloud/firestore@9.3.1': + resolution: {integrity: sha512-ofGTiSpfXrHrrS3KaDOmsupSzCHr4WVl1+s6Ke0F8rPBRyb/OuZSC8u1NjCKtt/fO7A1GvqASQGhdAwVsnGpQA==} engines: {node: '>=22'} '@google-cloud/paginator@7.2.0': @@ -1913,8 +1928,8 @@ packages: resolution: {integrity: sha512-0i3JkkwAdGGk6AlMnFm1Vf+XtpIL73ki/MZWvXDPoN37nABf/9LFHtYeo8tW77vHSQS00ykC2ygHnUL1gkYAXg==} engines: {node: '>=22'} - '@google-cloud/storage@8.2.0': - resolution: {integrity: sha512-7ckgSjeEprV92VrlLjpYFA3PFerflvFtF7Ea86oQXGNCprGZq5rtpAVK0zgWnCy+44mLjms42M7MiWa433gz2A==} + '@google-cloud/storage@8.4.0': + resolution: {integrity: sha512-M3kA6UA2Tjp5aznCrgKcm9CzOjiQyRMnquqalqXAeS5wvkqqZxN8wpNjjHafOSYs6lQ82U7f2i8we4eTfIrpkA==} engines: {node: '>=22'} '@gql.tada/cli-utils@1.9.4': @@ -2174,76 +2189,76 @@ packages: '@octokit/types@13.10.0': resolution: {integrity: sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==} - '@opentelemetry/api-logs@0.222.0': - resolution: {integrity: sha512-9mb1If+IF6u0ZVXkHQ6ogEae5HwA6ajIVUgpSDQyRASxft6BSXHvBvPooRle3yFN/fKnCdSOnuu0OC3PLcF6+g==} + '@opentelemetry/api-logs@0.223.0': + resolution: {integrity: sha512-Oepm6etVPFCn0VWB1t833iOTgz1eYBDUPxcrOR/XvwzD1+Ag9VzSPSrrKAFNJ/haatj+8CXbG47pZXvdNQKDJw==} engines: {node: '>=8.0.0'} '@opentelemetry/api@1.9.1': resolution: {integrity: sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==} engines: {node: '>=8.0.0'} - '@opentelemetry/core@2.11.0': - resolution: {integrity: sha512-7YP44XH0tV6+Mb54x2YGf84i7yi+31MBZlE8JwvozkxyTvXbSp10X7cI7YE49ChJ3shMJoBmCJF3+1QFBJctGA==} + '@opentelemetry/core@2.12.0': + resolution: {integrity: sha512-1HsSAuvT4/my0QrXWsyXFdWjKaPeCHsismKZgEEIb8NK13LP6DrMRlsUbvD/0F9mDWK3xDom9AMv3IscxgOnOQ==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/exporter-logs-otlp-http@0.222.0': - resolution: {integrity: sha512-GqwLZohJTf/sttYlOpT1oFTJ9ScYaKnk0sOx4Qe/+KmXYVOa+v94cfnkUkFKDuvTODWhCL50Hz3gvsZD6ngQpg==} + '@opentelemetry/exporter-logs-otlp-http@0.223.0': + resolution: {integrity: sha512-YQh9+t/JmV9OeRkoLhPb4yvcrWCX6lAOmXFos/JKoD+KITZYZoxf0acnwAk6YDI9O7fX68O2ka38hx1G9exl8w==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-metrics-otlp-http@0.222.0': - resolution: {integrity: sha512-6Ko+0bgNP6V4G/RsmNBSk5lO1B/lo9z6tvLpFY3ykPPevXNzFmOW3C9hEmTt0zKCvHovyrol3TYlg4HVb5gwjg==} + '@opentelemetry/exporter-metrics-otlp-http@0.223.0': + resolution: {integrity: sha512-hNC8yai/+xCNyTuiOy6JFepXXA/sb/2jCzQRY7c2cUWz6owaidihlHUpO20B9/dj8JKPNo8rcn7ikTy7Cj+JaQ==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-prometheus@0.222.0': - resolution: {integrity: sha512-I7nalnnBZrhlTgjlqsVeEjJGcQCFK5kKAYVk7XTz/cbubvj5fvjLOal/Many0taHF2GIkOWmegsbQ8vbQJjhFg==} + '@opentelemetry/exporter-prometheus@0.223.0': + resolution: {integrity: sha512-HhbN3/B8vG+JNKH2oLMynFFrz2O/o+WFklfwiVq3ffdRWOEZx1zHeYe6r86fn9BUSpQ2U5cXfQja+otTdzi5qQ==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-trace-otlp-proto@0.222.0': - resolution: {integrity: sha512-imLrLzNhnABJt3tUyT63h6MqfZrG3Gdv3TE7+OUQTvwD088RfCUx3rF01lcgfu2KXBFk13vwi0yKZLvFEalkIA==} + '@opentelemetry/exporter-trace-otlp-proto@0.223.0': + resolution: {integrity: sha512-hCFhPuROokNpwLibKmeMRuBNjPtbL+Ja5y/e/KBl5p3QcaH7xBjkj8roIGgKwCNJ4WChRLBzfoaNM3QksogfWw==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/otlp-exporter-base@0.222.0': - resolution: {integrity: sha512-YbywG3veEm2Fb6TbdxRkuquWob6eVWXuA8/Ba1tXz9jHfUqpdE3keilOHEtPboC4CvS1bjeeVfNkWGOOrLj+lw==} + '@opentelemetry/otlp-exporter-base@0.223.0': + resolution: {integrity: sha512-HlJMrJXjOqdQeoYNDHEvFTpaY2p9uWDK1GPl5AZ4wI5easzfoppTduOv47M8eiF+4ew42vfI/Xvt7THYgESnRw==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/otlp-transformer@0.222.0': - resolution: {integrity: sha512-/F3BZ89+CJQnZkMh2tCrtcdB+XT2Dxhj4FFE+WPQ//413hmFL0/RfEX6vgOIWGhiSzrkHWTK3+6SiT7K5/g/jQ==} + '@opentelemetry/otlp-transformer@0.223.0': + resolution: {integrity: sha512-oxmmPL5/MbSsO8K588V9n/XLIe7FZTK30Fo+/U/lAnt0ZIK/hoPM03n2WpSTZVbUBGTUE7aLyxnAzh7nE2PD4Q==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/resources@2.11.0': - resolution: {integrity: sha512-Ie7+8q8MDF4FAEQCKVMTx3ReUvxiIAgIiiW3c9JdmP8+HMcDy20puT+AHjexnExgnbvBxjQ9fjkFDWrikJ2jQA==} + '@opentelemetry/resources@2.12.0': + resolution: {integrity: sha512-+rSRoOdln6NhXTVcBdHSlZxJDNzwxadeweK2ltZO3tVtfp6aklABc06xclDk6ovRR+EiGgIcSbh/6NgjFhnb3A==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' - '@opentelemetry/sdk-logs@0.222.0': - resolution: {integrity: sha512-+19YHODIjaUCArxleaJtuufFZVpz/xvvK+VllQqE+W8hHolxdoRwHfK/s667zezwh1hkx6FFF+oYzetYgqK+Bg==} + '@opentelemetry/sdk-logs@0.223.0': + resolution: {integrity: sha512-ApiAfUiUh6fmJt1GbsBuoeDn8D8IL42UvGyPUr8o1Z89ZeIiOCE1rZ78KkIUjEX3OV8Oorl9ez5Qjo43ZynDyw==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.4.0 <1.10.0' - '@opentelemetry/sdk-metrics@2.11.0': - resolution: {integrity: sha512-7GXXcObyHyDUUSG+L+kJoquty01bzm7ivE7+SSgXXJcHuPzGviptxwARmI2c+bnnxjexGQbJnyNlN8HxBP/Y7A==} + '@opentelemetry/sdk-metrics@2.12.0': + resolution: {integrity: sha512-mVMaEHwCUJuY3S4Esn+nT0yQA3qCEGh+SOPJsXygU0Gl453WcsDNjtEa8EfdewMwoLyr1tlofB4fXytVpiXuow==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.9.0 <1.10.0' - '@opentelemetry/sdk-trace@2.11.0': - resolution: {integrity: sha512-fFnTqGm8/G73GQVnxYi7LXa1ZVYEUvgL6XI1LpvV0bPC7WQ/ZGgKxCSl8FnlZBKto9JHHEFTO6s6CUpvvtwFrA==} + '@opentelemetry/sdk-trace@2.12.0': + resolution: {integrity: sha512-ImVuRQ6faOsTi1Wna88s2avgrrf/iDgXPigIeynkUhjstMuoQUDOJXgkez2j1mlU4btjXcXBGa+q7qKFYR3GsA==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' @@ -2525,8 +2540,8 @@ packages: '@types/node-fetch@2.6.13': resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==} - '@types/node@20.19.43': - resolution: {integrity: sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==} + '@types/node@25.9.9': + resolution: {integrity: sha512-b4e2xxj/yMeT2hNlD6x7zNFiQK2Dlmkb9CQ6v3/1G2RezKN4YS2lcEv8lzGm1mhs4f2lM4yNAMI/zUDBZBBt7w==} '@types/node@26.6.5': resolution: {integrity: sha512-uMzsv9stDdofIZBx4UGh4Z9ZgXnGC9seRDscilBcTHAeOFk67MZg/k9bWVfO+bk4qZmG+l52hRnLwUiH2LnJTg==} @@ -2896,8 +2911,9 @@ packages: resolution: {integrity: sha512-/5NV/vDALVFDXgLmfsy9TRCBlKwO2LNBFzpzvb9iIj+jR+eSc6DLYYvVOdivT/jm7MtU6TebYuRmzEOI7w40UA==} engines: {node: '>=10.0.0'} - '@zone-eu/mailsplit@5.4.17': - resolution: {integrity: sha512-LOMzdrKRVgaghLaezIPdHRhsGpfDiWNQo1RptWc84CRllI4dWLwqX/L4x1iTt1CaeyvyUfMXM/6mjIsEisT3Tg==} + '@zone-eu/mailsplit@5.4.27': + resolution: {integrity: sha512-9008ddFqqKk7lMF2S1sLU7ExfJZP9zPw5tkZy24EVt45Ryme2x85f/5vJZZqQ+vCJkKcCY78dJ5yuEVG3ZrVZA==} + engines: {node: '>=20.0.0'} abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} @@ -2920,9 +2936,9 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - adm-zip@0.5.18: - resolution: {integrity: sha512-ufJnssQGbxzLNS1Ho9bCtX4rQKCCvoVuDLHoJyc3F9dOGDB4BkWs2Ci0kv53lqocAEQ/Cbi+I2XCsNYGqVYqng==} - engines: {node: '>=12.0'} + adm-zip@0.6.1: + resolution: {integrity: sha512-Xwrja8nx9e5o2N1my4DsKCeKpdrnACyr1wtbPxBDgGzKzKyE9kRtBFA8mWldI+RVlD7CBZNWY/wQ2+ydwOR6kQ==} + engines: {node: '>=14.0'} agent-base@7.1.4: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} @@ -2965,6 +2981,10 @@ packages: anynum@1.0.1: resolution: {integrity: sha512-N6//FLET/tXYNM/F6ABca1oH6fWB+KlTt909Le28WMDBk8oaT4vY17DCrwg2MvmuqUKt3Ni4N5dGJ/EoBgcO6A==} + apache-arrow@21.2.0: + resolution: {integrity: sha512-Hxe6Agq26gQOM954qpzYSllJBPJl+e16U5CkfuMUhLrNba+5nKkttIVlflaovN6oaTratqMGAO8H5u/aNhmHWQ==} + hasBin: true + are-docs-informative@0.1.1: resolution: {integrity: sha512-sqRsNQBwbKLRX0jV5Cu5uzmtflf892n4Vukz7T659ebL4pz3mpOqCMU7lxMoBTFwnp10E3YB5ZcyHM41W5bcDA==} engines: {node: '>=18'} @@ -3027,10 +3047,6 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - base64id@2.0.0: - resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==} - engines: {node: ^4.5.0 || >= 5.9} - baseline-browser-mapping@2.11.30: resolution: {integrity: sha512-YJs6Pz17RMNv8HoyKREtCY38E3BV1nPkWVmIb+XN1uHC1Vqt3KZCH/uJH9ZKRoiKb/icZ6tvehyee6RZNbFfRA==} engines: {node: '>=6.0.0'} @@ -3115,8 +3131,8 @@ packages: resolution: {integrity: sha512-F705O3xrsUtgt98j7leetNhTWPe+5S72rlL5O4jA1pKqBVQ/dT1O1D6PFxmSXvc0SUOinWS57DKx0I3CHrXJHQ==} hasBin: true - cassandra-driver@4.9.0: - resolution: {integrity: sha512-svYpdkLIGjD0WmuuwkkeYbfBdPX1zksK2cDyT1mWjX53OVTzuWBOVy54K6PPij8GgYpIG+K82OryrBv/xNeuWg==} + cassandra-driver@4.10.0: + resolution: {integrity: sha512-DHyFC6RMK28nvndZfecbGUozoYbb5NjFmlniczao8zA1IplurcshR2i6rvxpEu3Q9G45tjin4yU+iKwA10ZUtA==} engines: {node: '>=20'} chai@6.3.0: @@ -3700,8 +3716,11 @@ packages: fastify-plugin@6.0.0: resolution: {integrity: sha512-fZOty7z3O7vOliF6d8bHE3wiEh1KcNnKEQensSgTk9C1DvN6nRLS++XVd86v33Hw/8u9Un8A1zDrQ8ujcQDHEg==} - fastify@5.12.5: - resolution: {integrity: sha512-OB2k1dlxs5/NAABqeKV2FUHkSD2BbENsCak8yULVcymn3fHIPDVa9TI3SDnJSWYSllZmSYuZXy2gTnsT+Sut1A==} + fastify-plugin@6.0.1: + resolution: {integrity: sha512-4wW4RxSmvPXLrh5mgQEiu43qU3bw44N2ss4FTkTkQIbprUhE+/s43QX0j/ttcztdWK7PEkHqVthdc5GdEGDvjA==} + + fastify@5.12.7: + resolution: {integrity: sha512-v4pEPsTRPuqlDIYiQFB+BHjVN4SdHX9u0ABk0ZDUKbbdY1vsNryUd1j4Z+jQEZajvYIVk047Kimva9/AJ79GYw==} fastq@1.20.3: resolution: {integrity: sha512-XKv5nnLs6nLF71NgiKJLIZFLkPyIEuOselLG7ujZnGrRfQK8HpvY+WqKhAJUAdLomwVHErVS4LfxFlPq0/FTAw==} @@ -3749,6 +3768,9 @@ packages: flat-cache@6.1.23: resolution: {integrity: sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA==} + flatbuffers@25.9.23: + resolution: {integrity: sha512-MI1qs7Lo4Syw0EOzUl0xjs2lsoeqFku44KpngfIduHBYvzm8h2+7K8YMQh1JtVVVrUvhLpNwqVi4DERegUJhPQ==} + flatted@3.4.4: resolution: {integrity: sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==} @@ -3778,10 +3800,6 @@ packages: functional-red-black-tree@1.0.1: resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} - gaxios@6.7.1: - resolution: {integrity: sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==} - engines: {node: '>=14'} - gaxios@7.1.3: resolution: {integrity: sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ==} engines: {node: '>=18'} @@ -3794,10 +3812,6 @@ packages: resolution: {integrity: sha512-h4/R7ay7JFXU5kmAkp/Y4Y4Vmm7m83tD579GUgfQQsRRGQ4TzSedyHla6XgTWohQuVffT3ldN4FF6uCqlRGaEA==} engines: {node: '>=22'} - gcp-metadata@6.1.1: - resolution: {integrity: sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==} - engines: {node: '>=14'} - gcp-metadata@8.1.4: resolution: {integrity: sha512-iJ9KMsiu+xKtNRX0PmGLSaIU3bUBAyzWTyqKemKPzNPsmmsBCQYmlNg+brEbES7IHSXtdVwzBPzx1vz3FAaipw==} engines: {node: '>=18'} @@ -3873,18 +3887,10 @@ packages: resolution: {integrity: sha512-7ABviyMOlX5hIVD60YOfHw4/CxOfBhyduaYB+wbFWCWoni4N7SLcV46hrVRktuBbZjFC9ONyqamZITN7q3n32w==} engines: {node: '>=18'} - google-auth-library@11.1.0: - resolution: {integrity: sha512-YIBq5KNoHQrZ9PM4PeodDBqqBGlSTIxh1zibN8u3zNIO9UJg8gvKuCpdKV7fWXhsZ2zRkU6FhGrgKNgLJ2IRgw==} - engines: {node: '>=22'} - google-auth-library@11.3.1: resolution: {integrity: sha512-mQS0R2Ev/DKkzuWSYtDeq15uhDeaWuT2qzLYqJ41LmooxVKHmn5ut3pc6dlHY6wfHW/D7FBmOYjAtkjaD1A7qA==} engines: {node: '>=22'} - google-auth-library@9.15.1: - resolution: {integrity: sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==} - engines: {node: '>=14'} - google-gax@5.0.8: resolution: {integrity: sha512-M4vpZcXQIC1gqIVGQ7eaU3jXQA6zecStyTXu514TYfThlgSurYJOxHZo9fzU6hAgwPWvuEynAVHWyaIk80VeEA==} engines: {node: '>=18'} @@ -3893,10 +3899,6 @@ packages: resolution: {integrity: sha512-U/OUrt4+aUiELB8sgaPJAdVfPzFOPjo1ngXVOwbR1NcCHV7ZcPOW0Ecwdbp8J86NmxBwLMJUOj8AgRSOZm5iJQ==} engines: {node: '>=22'} - google-logging-utils@0.0.2: - resolution: {integrity: sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==} - engines: {node: '>=14'} - google-logging-utils@1.1.3: resolution: {integrity: sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==} engines: {node: '>=14'} @@ -3909,8 +3911,8 @@ packages: resolution: {integrity: sha512-wtv/e7JYgmtpIPcSez2EFD/Wx49DPsRX2rj15D7hTwc7tDsP82dcwoX/I4+zE38mu6S9PcghizzzADLf+ZMunA==} engines: {node: '>=22'} - googleapis@181.0.0: - resolution: {integrity: sha512-fCzsqaVjA5FrA9DdXn4WlnmnLUvqjWx0JGZzcHbSC9iMfb8PK1lTxsvYpnaRf0j4b6usfKlW+YHSKjHnkgqmjQ==} + googleapis@186.0.0: + resolution: {integrity: sha512-ljnYwbM1IX6xM0q5tQHqAtnFdHBC9rPa5jidpoQB7wRiqBYOs5hOQPUPidF454tNLO5LCwB06EvkPg/93E1OJw==} engines: {node: '>=22.0.0'} gopd@1.2.0: @@ -3927,10 +3929,6 @@ packages: resolution: {integrity: sha512-Chq1s4CY7jmh8gO2qvLIJyfCDIN+EHLFW/9iShnp1z8FjBQMoodWP1kDC36VAMXXIvAjj4ARa7ntfAV2BrjsbA==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} - gtoken@7.1.0: - resolution: {integrity: sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==} - engines: {node: '>=14.0.0'} - gtoken@8.0.0: resolution: {integrity: sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw==} engines: {node: '>=18'} @@ -4018,8 +4016,8 @@ packages: resolution: {integrity: sha512-2E8Q6rh+1RRSq/YdaGsNfXsEZy9FVqv6BSSrkmZJP7BnaoPnRfKL+YaofPvP+5rzdk144qSm6i4+hvPgUcbV4Q==} engines: {node: '>= 4'} - imapflow@2.0.5: - resolution: {integrity: sha512-YG666DWbx0iXDpS4UghDmai1I0XF4w0eZYNEX2iMk3L98GGKxjogIe4RrKgqWzR0RNKJtOXwUgTDbPJIBgbReg==} + imapflow@2.5.8: + resolution: {integrity: sha512-uFnRQVgpBWP1KV2pqGxjvcMejc6x6eskqoaGbOLNIr5Xt5lp6DYrUgk2NaEgtpSNMMxCZeN1GHJNd4nUmc4Cpw==} engines: {node: '>=20.0.0'} import-fresh@3.3.1: @@ -4133,10 +4131,6 @@ packages: resolution: {integrity: sha512-4SrR7AdnY11LHfDKTZY1u6Ga3RuxZdl3YKWWShO5iyuG5h8QS4GD2tOb04peBJ5I7pXbR+CGBNEhTcwK+FzN3g==} engines: {node: '>=20'} - is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} - is-unsafe@2.0.2: resolution: {integrity: sha512-HgbIHPBH0KHHCcjLfGsCvhtPTVxjaAZlXjwdz7/GQC40SjSe4sfQsar8J5VFo8JOSbarkpV0OLG95bbaNd9aAQ==} @@ -4213,6 +4207,9 @@ packages: json-stringify-safe@5.0.1: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + json-with-bigint@3.5.12: + resolution: {integrity: sha512-uwbF/wSSuOgC7qqlq27Xp5B6a2MHVug3t0idZdTqu0JnlFvgJuH7ju+KAk/J06C7GfhoYy2gnb9wz2INqcne7w==} + jsonc-parser@3.3.1: resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} @@ -4258,14 +4255,17 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - libbase64@1.3.0: - resolution: {integrity: sha512-GgOXd0Eo6phYgh0DJtjQ2tO8dc0IVINtZJeARPeiIJqge+HdsWSuaDTe8ztQ7j/cONByDZ3zeB325AHiv5O0dg==} + libbase64@1.4.1: + resolution: {integrity: sha512-Nyh3H90B3gRtrcxIe56Ayy7635J0jmh6AbxbQgQae8wrSPQMH5wFqJChiMTB13yKG512L3YspbA5DzumhFTITA==} + engines: {node: '>=20.0.0'} - libmime@5.4.4: - resolution: {integrity: sha512-d3zZ2k8s6iO+8u9Vfkl6HfhD5lSVocGcmOViTz/i0CJcwhJADyubEJ/+TkBhuLDUSIBOiG+D8G5kJKwXwKbXXA==} + libmime@5.5.2: + resolution: {integrity: sha512-Byw3CchK4eSqbgzpttsUoC4hx2VPP+hnveAuYAYZNipEc+0WlDFjVb1ISNscjq/idvyDP/Xjg8mnBcdgbsgvzg==} + engines: {node: '>=20.0.0'} - libqp@2.1.1: - resolution: {integrity: sha512-0Wd+GPz1O134cP62YU2GTOPNA7Qgl09XwCqM5zpBv87ERCXdfDtyKXvV7c9U22yWJh44QZqBocFnXN11K96qow==} + libqp@3.0.1: + resolution: {integrity: sha512-7QZxpPX25pga1WiMueduWxmrHMVBFrZPH6ZUaozGYa/H98JH6NVBSET3qVw+4NxzoraIW7rJ81YxSU9IalvCpg==} + engines: {node: '>=20.0.0'} light-my-request@6.8.0: resolution: {integrity: sha512-5Q8PjoSEdtGIB8fikZsTem5vgRo4F2mR6vUKTDW/H1g6MtAt8e3duQbg/QxL5yzg6BZhor2KOUm3hhWMWLTZwg==} @@ -4621,8 +4621,8 @@ packages: resolution: {integrity: sha512-ZoS07RoFqpKYQwAk59qmrx8+jJHNHU30UjlU96QktiGn1ltvDr+vCznLX5DiUBLEpMAHatHNWV1nM/74ul66kA==} engines: {node: '>=20.19.0'} - mongodb@7.6.0: - resolution: {integrity: sha512-WbZ6OCjYw2c53LOjfkQa+reXr7kIiOVpXXglnASFuiMtif0BvsMwHe3ClJHLm1/r7wJFwaasfFtD6iYIktB01g==} + mongodb@7.7.0: + resolution: {integrity: sha512-XG1xXEqyouAV8GCb3PuRaujofeXKpAJAPvXYWZgHl6Dz4QHSJ1nRLl0+GpqaLTwKvC0RFE9truOur34RNFY1nw==} engines: {node: '>=20.19.0'} peerDependencies: '@aws-sdk/credential-providers': ^3.806.0 @@ -4655,8 +4655,8 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - mysql2@3.24.4: - resolution: {integrity: sha512-A2olluVlj0mvgyIRRISMEzXc51m+21mRtcMVjJyIpt2GG98+XrC9m9HzsqcMsX2LcnfccJvY5NB22g8fENBnOA==} + mysql2@3.24.6: + resolution: {integrity: sha512-enu73KhbAua2L3dIxjc6qg6ZJ7H3pt1BImZASWNWY5xSsmJ1ZuUPULTDGXgmJbI61vb+nJAG19IZclIq19UidQ==} engines: {node: '>= 8.0'} peerDependencies: '@types/node': '>= 8' @@ -4715,8 +4715,8 @@ packages: resolution: {integrity: sha512-5qr2okC4ItAI0hG5SaV0HoYMpnM/Y6+Oqr7AmPYy/2uEoGvS+GbSKLeRxSS1uAdu59yz0ouzcuXievSgg///WA==} engines: {node: '>=18'} - nodemailer@10.0.10: - resolution: {integrity: sha512-He9XskOFms62SyAKkLu8CcGcYHAo+BSHSsORI8s4PJH8qZgZY4L4lDfvyN0twvmbpyG+eGrxpyBlskj9d9rJ8A==} + nodemailer@10.1.7: + resolution: {integrity: sha512-OQa6FDln5fLttmqSbjDiRYvFDOFNrBqfiOwHPlEbURil3b+vPB1v8xpi+Sp46drzNDlsTnNsS502vthmz56r4w==} engines: {node: '>=20.0.0'} nodemon@3.1.14: @@ -4879,8 +4879,9 @@ packages: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} - postal-mime@3.0.0: - resolution: {integrity: sha512-Z4a9ar2Bv3YpK3IXag+Yda30k7bMZfpRuUGyqtHnZ2pjHG8Bl62EhZIk4n1dzv00gfzP9g+94e9kd8+XmjVWLA==} + postal-mime@4.0.11: + resolution: {integrity: sha512-T0zAqYnuSB8s+zL9WdiGj/2DeWeObEjqrcw2LWq+hgwpCSbLt7xujsFXn6Kgr1wsLl8DJh+v+lG9GQSQfMcUyA==} + engines: {node: '>=20'} postcss@8.5.31: resolution: {integrity: sha512-YUbWYCgErwnMAVkjUnYa+KlMBzGpHwiIt/DE7f0G33AuX2LH9UcTk6KgWxd3zRU+pN3u/C+Xl3EnMLM4Hea7Sg==} @@ -4912,10 +4913,6 @@ packages: process-warning@5.1.1: resolution: {integrity: sha512-oCkNVj4OKnKEcocVBcDfiIugN1/cE6rgfT3nCtzeqZPA8+rIxMaQ0xXzIkGP8Gj2qUaP1UR7uhJ1VD8lUCpzCg==} - process@0.11.10: - resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} - engines: {node: '>= 0.6.0'} - proto3-json-serializer@3.0.4: resolution: {integrity: sha512-E1sbAYg3aEbXrq0n1ojJkRHQJGE1kaE/O6GLA94y8rnJBfgvOPTOd1b9hOceQK1FFZI9qMh1vBERCyO2ifubcw==} engines: {node: '>=18'} @@ -4988,10 +4985,6 @@ packages: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} - readable-stream@4.8.0: - resolution: {integrity: sha512-2jhTTU3Eilp/2DMT71gbcoqC35eQHasMJH0RHkYxwlxIv3+FR6Y5xAFZIwEGLxKkjZYEFlsiMNIdwUqjK2lLHQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -5122,9 +5115,6 @@ packages: resolution: {integrity: sha512-Nx00FDPHDimSENMznVpADeYUJDsqlMiO9wcs2S+giggNTm5+ruNkM4m9z9qCk6xUJT+ThDM3NxxpwfHfFk1G+Q==} engines: {node: '>=14.0.0'} - schema-dts@2.0.0: - resolution: {integrity: sha512-t7NoCy3Rn5GHGx6p7s1qIYK/AeIb8ZxJNR9WUNFkwMv2CiiGZBmqqYWc2FlZVm5ZbiHMY4OvBWhj7QtyrFO2Jw==} - schema-dts@2.1.0: resolution: {integrity: sha512-Y/NvOvuJUZwrm+EmNqJF3M+bRufERJs1h5GJPLilUuK5D5b53ttU+XZgIjEFaAVRToh+ib+cQawFmxKC5Jt9ow==} @@ -5205,16 +5195,16 @@ packages: socket.io-adapter@2.5.8: resolution: {integrity: sha512-6Oy52pbg+kvdCVvjcN+FnY7BvxZ7cIHNScbvztT/It5d0vbwoJoVZmF2gjJmnV0/4WlXRfG15zc45ySk9Ah8bw==} - socket.io-client@4.8.3: - resolution: {integrity: sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g==} + socket.io-client@4.8.4: + resolution: {integrity: sha512-7wjKAvVXYOJsbmUgkWbnhPD4bFpkqrUR0++XOjpGFmqDqsqV1CI93VTraeExLxpjxEqrWgFoSRZu1ihjLWfkAA==} engines: {node: '>=10.0.0'} socket.io-parser@4.2.7: resolution: {integrity: sha512-IH/iSeO9T6gz1KkFleGDWkG9N3dl4jXVYUtMhIqH10Md0ttMer8nUNWiP1DKuNrybD2xBrixLJdCC9J6ECoYkg==} engines: {node: '>=10.0.0'} - socket.io@4.8.3: - resolution: {integrity: sha512-2Dd78bqzzjE6KPkD5fHZmDAKRNe3J15q+YHDrIsy9WEkqttc7GY+kT9OBLSMaPbQaEd0x1BjcmtMtXkfpc+T5A==} + socket.io@4.8.4: + resolution: {integrity: sha512-9ZV9zg8vN8hO3Y25DhR7nUkJ1VDnBhq5O/JrXhFT9s6+F0gqytSASTHVfCFc2mJXaTfARroErplXlzFWwETZqQ==} engines: {node: '>=10.2.0'} socks@2.8.10: @@ -5485,8 +5475,8 @@ packages: undefsafe@2.0.5: resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==} - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + undici-types@7.24.6: + resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} undici-types@8.9.0: resolution: {integrity: sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==} @@ -5533,11 +5523,6 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - uuid@9.0.1: - resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} - deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). - hasBin: true - valibot@1.5.0: resolution: {integrity: sha512-nil6AkP2TChWL43Z5uJ6GTxX01CUA+g8LWUM+N/rB9NBbkUMaUsi9PUNzlUPgoKASgmx9f7eGOYpJ04/fSa6FQ==} peerDependencies: @@ -5793,17 +5778,17 @@ snapshots: graphql: 16.14.2 typescript: 6.0.3 - '@3sixty/api-auth-entity-storage-models@0.20.0-next.0': + '@3sixty/api-auth-entity-storage-models@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 - '@3sixty/api-auth-entity-storage-rest-client@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/api-auth-entity-storage-rest-client@0.20.0-next.1(supports-color@10.2.2)': dependencies: - '@3sixty/api-auth-entity-storage-models': 0.20.0-next.0 - '@3sixty/api-core': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-auth-entity-storage-models': 0.20.0-next.1 + '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 @@ -5812,39 +5797,49 @@ snapshots: - supports-color - utf-8-validate - '@3sixty/api-auth-entity-storage-service@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/api-auth-entity-storage-service@0.20.0-next.1': dependencies: - '@3sixty/api-auth-entity-storage-models': 0.20.0-next.0 - '@3sixty/api-core': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-models': 0.20.0-next.0 - '@3sixty/background-task-models': 0.20.0-next.0 + '@3sixty/api-auth-entity-storage-models': 0.20.0-next.1 + '@3sixty/api-auth-models': 0.20.0-next.1 + '@3sixty/api-models': 0.20.0-next.1 + '@3sixty/authorization-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/nameof': 0.20.0-next.2 + '@3sixty/vault-models': 0.20.0-next.1 + '@3sixty/web': 0.20.0-next.2 + + '@3sixty/api-auth-models@0.20.0-next.1': + dependencies: + '@3sixty/core': 0.20.0-next.2 + '@3sixty/nameof': 0.20.0-next.2 + + '@3sixty/api-core-server@0.20.0-next.1': + dependencies: + '@3sixty/api-models': 0.20.0-next.1 + '@3sixty/api-processors': 0.20.0-next.1 + '@3sixty/context': 0.20.0-next.2 + '@3sixty/core': 0.20.0-next.2 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/vault-models': 0.20.0-next.0 '@3sixty/web': 0.20.0-next.2 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - '@3sixty/api-core@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/api-core@0.20.0-next.1(supports-color@10.2.2)': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 - socket.io-client: 4.8.3(supports-color@10.2.2) + socket.io-client: 4.8.4(supports-color@10.2.2) transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate - '@3sixty/api-models@0.20.0-next.0': + '@3sixty/api-models@0.20.0-next.1': dependencies: '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 @@ -5852,19 +5847,19 @@ snapshots: '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 - '@3sixty/api-processors@0.20.0-next.0': + '@3sixty/api-processors@0.20.0-next.1': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 - '@3sixty/api-rest-client@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/api-rest-client@0.20.0-next.1(supports-color@10.2.2)': dependencies: - '@3sixty/api-core': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 transitivePeerDependencies: @@ -5872,85 +5867,84 @@ snapshots: - supports-color - utf-8-validate - '@3sixty/api-server-fastify@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/api-server-fastify@0.20.0-next.1(supports-color@10.2.2)': dependencies: - '@3sixty/api-core': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-models': 0.20.0-next.0 - '@3sixty/api-processors': 0.20.0-next.0 + '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-core-server': 0.20.0-next.1 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 - '@fastify/compress': 9.2.0 - '@fastify/cors': 11.3.0 - fastify: 5.12.5 - fastify-plugin: 6.0.0 - socket.io: 4.8.3(supports-color@10.2.2) + '@fastify/compress': 9.2.2 + '@fastify/cors': 11.3.1 + fastify: 5.12.7 + fastify-plugin: 6.0.1 + socket.io: 4.8.4(supports-color@10.2.2) transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate - '@3sixty/api-service@0.20.0-next.0': + '@3sixty/api-service@0.20.0-next.1': dependencies: - '@3sixty/api-models': 0.20.0-next.0 - '@3sixty/background-task-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 + '@3sixty/background-task-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/modules': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/vault-models': 0.20.0-next.0 + '@3sixty/vault-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/api-tenant-processor@0.20.0-next.0': + '@3sixty/api-tenant-processor@0.20.0-next.1': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/vault-models': 0.20.0-next.0 + '@3sixty/vault-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 '@3sixty/attestation-connector-nft@0.20.0-next.0': dependencies: '@3sixty/attestation-models': 0.20.0-next.0 '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 '@3sixty/identity-models': 0.20.0-next.0 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/nft-models': 0.20.0-next.0 - '@3sixty/standards-schema-org': 0.20.0-next.1 - '@3sixty/standards-w3c-did': 0.20.0-next.1 + '@3sixty/standards-schema-org': 0.20.0-next.2 + '@3sixty/standards-w3c-did': 0.20.0-next.2 '@3sixty/attestation-models@0.20.0-next.0': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-core': 0.20.0-next.3 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/standards-schema-org': 0.20.0-next.1 - '@3sixty/standards-w3c-did': 0.20.0-next.1 - '@3sixty/telemetry-models': 0.20.0-next.0 + '@3sixty/standards-schema-org': 0.20.0-next.2 + '@3sixty/standards-w3c-did': 0.20.0-next.2 + '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 '@3sixty/attestation-rest-client@0.20.0-next.0(supports-color@10.2.2)': dependencies: - '@3sixty/api-core': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/attestation-models': 0.20.0-next.0 '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/standards-w3c-did': 0.20.0-next.1 + '@3sixty/standards-w3c-did': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 transitivePeerDependencies: - bufferutil @@ -5959,37 +5953,37 @@ snapshots: '@3sixty/attestation-service@0.20.0-next.0': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/attestation-models': 0.20.0-next.0 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/standards-schema-org': 0.20.0-next.1 - '@3sixty/telemetry-models': 0.20.0-next.0 - '@3sixty/wallet-models': 0.20.0-next.0 + '@3sixty/standards-schema-org': 0.20.0-next.2 + '@3sixty/telemetry-models': 0.20.0-next.1 + '@3sixty/wallet-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 '@3sixty/auditable-item-graph-models@0.20.0-next.0': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-core': 0.20.0-next.3 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 '@3sixty/immutable-proof-models': 0.20.0-next.0 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/standards-schema-org': 0.20.0-next.1 - '@3sixty/telemetry-models': 0.20.0-next.0 + '@3sixty/standards-schema-org': 0.20.0-next.2 + '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 '@3sixty/auditable-item-graph-rest-client@0.20.0-next.0(supports-color@10.2.2)': dependencies: - '@3sixty/api-core': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/auditable-item-graph-models': 0.20.0-next.0 '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 '@3sixty/immutable-proof-models': 0.20.0-next.0 '@3sixty/nameof': 0.20.0-next.2 @@ -6001,42 +5995,42 @@ snapshots: '@3sixty/auditable-item-graph-service@0.20.0-next.0': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/auditable-item-graph-models': 0.20.0-next.0 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 - '@3sixty/data-core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-core': 0.20.0-next.3 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/event-bus-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/event-bus-models': 0.20.0-next.1 '@3sixty/immutable-proof-models': 0.20.0-next.0 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/standards-schema-org': 0.20.0-next.1 - '@3sixty/standards-w3c-did': 0.20.0-next.1 - '@3sixty/telemetry-models': 0.20.0-next.0 + '@3sixty/standards-schema-org': 0.20.0-next.2 + '@3sixty/standards-w3c-did': 0.20.0-next.2 + '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 '@3sixty/auditable-item-stream-models@0.20.0-next.0': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-core': 0.20.0-next.3 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 '@3sixty/immutable-proof-models': 0.20.0-next.0 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/standards-schema-org': 0.20.0-next.1 - '@3sixty/telemetry-models': 0.20.0-next.0 + '@3sixty/standards-schema-org': 0.20.0-next.2 + '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 '@3sixty/auditable-item-stream-rest-client@0.20.0-next.0(supports-color@10.2.2)': dependencies: - '@3sixty/api-core': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/auditable-item-stream-models': 0.20.0-next.0 '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 @@ -6047,42 +6041,48 @@ snapshots: '@3sixty/auditable-item-stream-service@0.20.0-next.0': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/auditable-item-stream-models': 0.20.0-next.0 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-core': 0.20.0-next.3 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/event-bus-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/event-bus-models': 0.20.0-next.1 '@3sixty/immutable-proof-models': 0.20.0-next.0 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/standards-schema-org': 0.20.0-next.1 - '@3sixty/standards-w3c-did': 0.20.0-next.1 - '@3sixty/telemetry-models': 0.20.0-next.0 + '@3sixty/standards-schema-org': 0.20.0-next.2 + '@3sixty/standards-w3c-did': 0.20.0-next.2 + '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/automation-actions@0.20.0-next.0': + '@3sixty/authorization-models@0.20.0-next.1': dependencies: - '@3sixty/api-models': 0.20.0-next.0 - '@3sixty/automation-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 + '@3sixty/core': 0.20.0-next.2 + '@3sixty/telemetry-models': 0.20.0-next.1 + + '@3sixty/automation-actions@0.20.0-next.1': + dependencies: + '@3sixty/api-models': 0.20.0-next.1 + '@3sixty/automation-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 - '@3sixty/automation-models@0.20.0-next.0': + '@3sixty/automation-models@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/automation-rest-client@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/automation-rest-client@0.20.0-next.1(supports-color@10.2.2)': dependencies: - '@3sixty/api-core': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-models': 0.20.0-next.0 - '@3sixty/automation-models': 0.20.0-next.0 + '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-models': 0.20.0-next.1 + '@3sixty/automation-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 @@ -6092,134 +6092,133 @@ snapshots: - supports-color - utf-8-validate - '@3sixty/automation-service@0.20.0-next.0': + '@3sixty/automation-service@0.20.0-next.1': dependencies: - '@3sixty/api-models': 0.20.0-next.0 - '@3sixty/automation-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 + '@3sixty/automation-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 - '@3sixty/background-task-models@0.20.0-next.0': + '@3sixty/background-task-models@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/background-task-scheduler@0.20.0-next.0': + '@3sixty/background-task-scheduler@0.20.0-next.1': dependencies: - '@3sixty/background-task-models': 0.20.0-next.0 + '@3sixty/background-task-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/background-task-service@0.20.0-next.0': + '@3sixty/background-task-service@0.20.0-next.1': dependencies: - '@3sixty/api-models': 0.20.0-next.0 - '@3sixty/background-task-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 + '@3sixty/background-task-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/modules': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/blob-storage-connector-aws-s3@0.20.0-next.0': + '@3sixty/blob-storage-connector-aws-s3@0.20.0-next.1': dependencies: - '@3sixty/api-models': 0.20.0-next.0 - '@3sixty/blob-storage-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 + '@3sixty/blob-storage-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@aws-sdk/client-s3': 3.1137.0 + '@aws-sdk/client-s3': 3.1153.0 - '@3sixty/blob-storage-connector-azure@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/blob-storage-connector-azure@0.20.0-next.1(supports-color@10.2.2)': dependencies: - '@3sixty/api-models': 0.20.0-next.0 - '@3sixty/blob-storage-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 + '@3sixty/blob-storage-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@azure/storage-blob': 12.33.0(supports-color@10.2.2) + '@azure/storage-blob': 12.34.0(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@3sixty/blob-storage-connector-file@0.20.0-next.0': + '@3sixty/blob-storage-connector-file@0.20.0-next.1': dependencies: - '@3sixty/api-models': 0.20.0-next.0 - '@3sixty/blob-storage-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 + '@3sixty/blob-storage-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/blob-storage-connector-gcp@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/blob-storage-connector-gcp@0.20.0-next.1(supports-color@10.2.2)': dependencies: - '@3sixty/api-models': 0.20.0-next.0 - '@3sixty/blob-storage-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 + '@3sixty/blob-storage-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 - '@google-cloud/storage': 8.2.0(supports-color@10.2.2) - google-auth-library: 11.1.0(supports-color@10.2.2) + '@google-cloud/storage': 8.4.0(supports-color@10.2.2) + google-auth-library: 11.3.1(supports-color@10.2.2) transitivePeerDependencies: - - encoding - supports-color - '@3sixty/blob-storage-connector-ipfs@0.20.0-next.0': + '@3sixty/blob-storage-connector-ipfs@0.20.0-next.1': dependencies: - '@3sixty/api-models': 0.20.0-next.0 - '@3sixty/blob-storage-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 + '@3sixty/blob-storage-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 - '@3sixty/blob-storage-connector-memory@0.20.0-next.0': + '@3sixty/blob-storage-connector-memory@0.20.0-next.1': dependencies: - '@3sixty/api-models': 0.20.0-next.0 - '@3sixty/blob-storage-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 + '@3sixty/blob-storage-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/blob-storage-models@0.20.0-next.0': + '@3sixty/blob-storage-models@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-core': 0.20.0-next.3 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/standards-schema-org': 0.20.0-next.1 - '@3sixty/telemetry-models': 0.20.0-next.0 + '@3sixty/standards-schema-org': 0.20.0-next.2 + '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/blob-storage-rest-client@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/blob-storage-rest-client@0.20.0-next.1(supports-color@10.2.2)': dependencies: - '@3sixty/api-core': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 @@ -6228,20 +6227,20 @@ snapshots: - supports-color - utf-8-validate - '@3sixty/blob-storage-service@0.20.0-next.0': + '@3sixty/blob-storage-service@0.20.0-next.1': dependencies: - '@3sixty/api-models': 0.20.0-next.0 - '@3sixty/blob-storage-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 + '@3sixty/blob-storage-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/standards-schema-org': 0.20.0-next.1 - '@3sixty/telemetry-models': 0.20.0-next.0 - '@3sixty/vault-models': 0.20.0-next.0 + '@3sixty/standards-schema-org': 0.20.0-next.2 + '@3sixty/telemetry-models': 0.20.0-next.1 + '@3sixty/vault-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 '@3sixty/cli-core@0.20.0-next.2': @@ -6275,7 +6274,7 @@ snapshots: '@scure/bip39': 2.4.0 micro-key-producer: 0.10.2 - '@3sixty/data-core@0.20.0-next.2': + '@3sixty/data-core@0.20.0-next.3': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 @@ -6285,48 +6284,48 @@ snapshots: ajv: 8.20.0 ajv-formats: 3.0.1(ajv@8.20.0) - '@3sixty/data-json-ld@0.20.0-next.2': + '@3sixty/data-json-ld@0.20.0-next.3': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-core': 0.20.0-next.2 + '@3sixty/data-core': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 '@types/jsonld': 1.5.15 jsonld: 9.0.0 - '@3sixty/data-json-path@0.20.0-next.2': + '@3sixty/data-json-path@0.20.0-next.3': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 json-p3: 2.3.1 - '@3sixty/data-processing-converters@0.20.0-next.0': + '@3sixty/data-processing-converters@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-processing-models': 0.20.0-next.0 + '@3sixty/data-processing-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 xml2js: 0.6.2 - '@3sixty/data-processing-extractors@0.20.0-next.0': + '@3sixty/data-processing-extractors@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-json-path': 0.20.0-next.2 - '@3sixty/data-processing-models': 0.20.0-next.0 + '@3sixty/data-json-path': 0.20.0-next.3 + '@3sixty/data-processing-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 - '@3sixty/data-processing-models@0.20.0-next.0': + '@3sixty/data-processing-models@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-processing-rest-client@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/data-processing-rest-client@0.20.0-next.1(supports-color@10.2.2)': dependencies: - '@3sixty/api-core': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-processing-models': 0.20.0-next.0 + '@3sixty/data-processing-models': 0.20.0-next.1 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 @@ -6335,13 +6334,13 @@ snapshots: - supports-color - utf-8-validate - '@3sixty/data-processing-service@0.20.0-next.0': + '@3sixty/data-processing-service@0.20.0-next.1': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-processing-models': 0.20.0-next.0 + '@3sixty/data-processing-models': 0.20.0-next.1 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 @@ -6350,24 +6349,24 @@ snapshots: '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/dataspace-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/modules': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/rights-management-models': 0.20.0-next.0 - '@3sixty/standards-w3c-activity-streams': 0.20.0-next.1 + '@3sixty/standards-w3c-activity-streams': 0.20.0-next.2 '@3sixty/trust-models': 0.20.0-next.0 '@3sixty/web': 0.20.0-next.2 '@3sixty/dataspace-control-plane-rest-client@0.20.0-next.0(supports-color@10.2.2)': dependencies: - '@3sixty/api-core': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/dataspace-models': 0.20.0-next.0 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/standards-dataspace-protocol': 0.20.0-next.1 + '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 transitivePeerDependencies: - bufferutil @@ -6376,36 +6375,36 @@ snapshots: '@3sixty/dataspace-control-plane-service@0.20.0-next.0': dependencies: - '@3sixty/api-models': 0.20.0-next.0 - '@3sixty/api-tenant-processor': 0.20.0-next.0 - '@3sixty/background-task-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 + '@3sixty/api-tenant-processor': 0.20.0-next.1 + '@3sixty/background-task-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/dataspace-models': 0.20.0-next.0 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 '@3sixty/federated-catalogue-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/rights-management-models': 0.20.0-next.0 - '@3sixty/standards-dataspace-protocol': 0.20.0-next.1 - '@3sixty/standards-w3c-dcat': 0.20.0-next.1 - '@3sixty/standards-w3c-odrl': 0.20.0-next.1 - '@3sixty/telemetry-models': 0.20.0-next.0 + '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 + '@3sixty/standards-w3c-dcat': 0.20.0-next.2 + '@3sixty/standards-w3c-odrl': 0.20.0-next.2 + '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/trust-models': 0.20.0-next.0 - '@3sixty/vault-models': 0.20.0-next.0 + '@3sixty/vault-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 '@3sixty/dataspace-data-plane-rest-client@0.20.0-next.0(supports-color@10.2.2)': dependencies: - '@3sixty/api-core': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/standards-w3c-activity-streams': 0.20.0-next.1 + '@3sixty/standards-w3c-activity-streams': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 transitivePeerDependencies: - bufferutil @@ -6414,40 +6413,40 @@ snapshots: '@3sixty/dataspace-data-plane-service@0.20.0-next.0': dependencies: - '@3sixty/api-models': 0.20.0-next.0 - '@3sixty/background-task-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 + '@3sixty/background-task-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 - '@3sixty/data-core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-core': 0.20.0-next.3 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/dataspace-app-runner': 0.20.0-next.0 '@3sixty/dataspace-models': 0.20.0-next.0 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/modules': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/rights-management-models': 0.20.0-next.0 - '@3sixty/standards-dataspace-protocol': 0.20.0-next.1 - '@3sixty/standards-schema-org': 0.20.0-next.1 - '@3sixty/standards-w3c-activity-streams': 0.20.0-next.1 - '@3sixty/standards-w3c-dcat': 0.20.0-next.1 - '@3sixty/standards-w3c-odrl': 0.20.0-next.1 - '@3sixty/telemetry-models': 0.20.0-next.0 + '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 + '@3sixty/standards-schema-org': 0.20.0-next.2 + '@3sixty/standards-w3c-activity-streams': 0.20.0-next.2 + '@3sixty/standards-w3c-dcat': 0.20.0-next.2 + '@3sixty/standards-w3c-odrl': 0.20.0-next.2 + '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/trust-models': 0.20.0-next.0 '@3sixty/web': 0.20.0-next.2 '@3sixty/dataspace-data-plane-socket-client@0.20.0-next.0(supports-color@10.2.2)': dependencies: - '@3sixty/api-core': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/dataspace-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/standards-w3c-activity-streams': 0.20.0-next.1 + '@3sixty/standards-w3c-activity-streams': 0.20.0-next.2 transitivePeerDependencies: - bufferutil - supports-color @@ -6455,37 +6454,37 @@ snapshots: '@3sixty/dataspace-models@0.20.0-next.0': dependencies: - '@3sixty/background-task-models': 0.20.0-next.0 + '@3sixty/background-task-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-core': 0.20.0-next.3 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/rights-management-models': 0.20.0-next.0 - '@3sixty/standards-dataspace-protocol': 0.20.0-next.1 - '@3sixty/standards-schema-org': 0.20.0-next.1 - '@3sixty/standards-w3c-activity-streams': 0.20.0-next.1 - '@3sixty/standards-w3c-dcat': 0.20.0-next.1 - '@3sixty/standards-w3c-odrl': 0.20.0-next.1 - '@3sixty/telemetry-models': 0.20.0-next.0 + '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 + '@3sixty/standards-schema-org': 0.20.0-next.2 + '@3sixty/standards-w3c-activity-streams': 0.20.0-next.2 + '@3sixty/standards-w3c-dcat': 0.20.0-next.2 + '@3sixty/standards-w3c-odrl': 0.20.0-next.2 + '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/dlt-account@0.20.0-next.0': + '@3sixty/dlt-account@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/vault-models': 0.20.0-next.0 + '@3sixty/vault-models': 0.20.0-next.1 - '@3sixty/dlt-iota@0.20.0-next.0(typescript@6.0.3)': + '@3sixty/dlt-iota@0.20.0-next.1(typescript@6.0.3)': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 - '@3sixty/dlt-account': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/dlt-account': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/vault-models': 0.20.0-next.0 - '@3sixty/wallet-models': 0.20.0-next.0 + '@3sixty/vault-models': 0.20.0-next.1 + '@3sixty/wallet-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 '@iota/bcs': 1.6.0 '@iota/identity-wasm': 1.9.7-beta.1(@iota/iota-sdk@1.15.0(typescript@6.0.3)) @@ -6500,23 +6499,23 @@ snapshots: dependencies: '@3sixty/attestation-models': 0.20.0-next.0 '@3sixty/auditable-item-graph-models': 0.20.0-next.0 - '@3sixty/blob-storage-models': 0.20.0-next.0 + '@3sixty/blob-storage-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-core': 0.20.0-next.3 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/standards-schema-org': 0.20.0-next.1 - '@3sixty/standards-unece': 0.20.0-next.1 - '@3sixty/telemetry-models': 0.20.0-next.0 + '@3sixty/standards-schema-org': 0.20.0-next.2 + '@3sixty/standards-unece': 0.20.0-next.2 + '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 '@3sixty/document-management-rest-client@0.20.0-next.0(supports-color@10.2.2)': dependencies: - '@3sixty/api-core': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/auditable-item-graph-models': 0.20.0-next.0 '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 @@ -6527,21 +6526,21 @@ snapshots: '@3sixty/document-management-service@0.20.0-next.0': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/attestation-models': 0.20.0-next.0 '@3sixty/auditable-item-graph-models': 0.20.0-next.0 - '@3sixty/blob-storage-models': 0.20.0-next.0 + '@3sixty/blob-storage-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 - '@3sixty/data-processing-models': 0.20.0-next.0 + '@3sixty/data-json-ld': 0.20.0-next.3 + '@3sixty/data-processing-models': 0.20.0-next.1 '@3sixty/document-management-models': 0.20.0-next.0 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/standards-schema-org': 0.20.0-next.1 - '@3sixty/standards-unece': 0.20.0-next.1 - '@3sixty/telemetry-models': 0.20.0-next.0 + '@3sixty/standards-schema-org': 0.20.0-next.2 + '@3sixty/standards-unece': 0.20.0-next.2 + '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 '@3sixty/engine-core@0.20.0-next.1': @@ -6549,12 +6548,12 @@ snapshots: '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 - '@3sixty/data-core': 0.20.0-next.2 + '@3sixty/data-core': 0.20.0-next.3 '@3sixty/engine-models': 0.20.0-next.1 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/logging-connector-console': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 - '@3sixty/logging-service': 0.20.0-next.0 + '@3sixty/logging-connector-console': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 + '@3sixty/logging-service': 0.20.0-next.1 '@3sixty/modules': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 @@ -6567,23 +6566,23 @@ snapshots: '@3sixty/engine-server-types@0.20.0-next.1(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(buffer@6.0.3)(socks@2.8.10)(supports-color@10.2.2)(typescript@6.0.3)': dependencies: - '@3sixty/api-auth-entity-storage-rest-client': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-auth-entity-storage-service': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-core': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-models': 0.20.0-next.0 - '@3sixty/api-processors': 0.20.0-next.0 - '@3sixty/api-rest-client': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-server-fastify': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-service': 0.20.0-next.0 - '@3sixty/api-tenant-processor': 0.20.0-next.0 + '@3sixty/api-auth-entity-storage-rest-client': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-auth-entity-storage-service': 0.20.0-next.1 + '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-models': 0.20.0-next.1 + '@3sixty/api-processors': 0.20.0-next.1 + '@3sixty/api-rest-client': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-server-fastify': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-service': 0.20.0-next.1 + '@3sixty/api-tenant-processor': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/engine-models': 0.20.0-next.1 '@3sixty/engine-types': 0.20.0-next.1(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(buffer@6.0.3)(socks@2.8.10)(supports-color@10.2.2)(typescript@6.0.3) '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/telemetry-processors': 0.20.0-next.0 - '@3sixty/tracing-processors': 0.20.0-next.0 + '@3sixty/telemetry-processors': 0.20.0-next.1 + '@3sixty/tracing-processors': 0.20.0-next.1 transitivePeerDependencies: - '@aws-sdk/credential-providers' - '@azure/identity' @@ -6608,8 +6607,8 @@ snapshots: '@3sixty/engine-server@0.20.0-next.1(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(buffer@6.0.3)(socks@2.8.10)(supports-color@10.2.2)(typescript@6.0.3)': dependencies: - '@3sixty/api-models': 0.20.0-next.0 - '@3sixty/api-server-fastify': 0.20.0-next.0(supports-color@10.2.2) + '@3sixty/api-models': 0.20.0-next.1 + '@3sixty/api-server-fastify': 0.20.0-next.1(supports-color@10.2.2) '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/engine-models': 0.20.0-next.1 @@ -6640,10 +6639,10 @@ snapshots: '@3sixty/engine-types@0.20.0-next.1(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(buffer@6.0.3)(socks@2.8.10)(supports-color@10.2.2)(typescript@6.0.3)': dependencies: - '@3sixty/api-models': 0.20.0-next.0 - '@3sixty/api-rest-client': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-service': 0.20.0-next.0 - '@3sixty/api-tenant-processor': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 + '@3sixty/api-rest-client': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-service': 0.20.0-next.1 + '@3sixty/api-tenant-processor': 0.20.0-next.1 '@3sixty/attestation-connector-nft': 0.20.0-next.0 '@3sixty/attestation-models': 0.20.0-next.0 '@3sixty/attestation-rest-client': 0.20.0-next.0(supports-color@10.2.2) @@ -6654,60 +6653,60 @@ snapshots: '@3sixty/auditable-item-stream-models': 0.20.0-next.0 '@3sixty/auditable-item-stream-rest-client': 0.20.0-next.0(supports-color@10.2.2) '@3sixty/auditable-item-stream-service': 0.20.0-next.0 - '@3sixty/automation-actions': 0.20.0-next.0 - '@3sixty/automation-models': 0.20.0-next.0 - '@3sixty/automation-rest-client': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/automation-service': 0.20.0-next.0 - '@3sixty/background-task-models': 0.20.0-next.0 - '@3sixty/background-task-scheduler': 0.20.0-next.0 - '@3sixty/background-task-service': 0.20.0-next.0 - '@3sixty/blob-storage-connector-aws-s3': 0.20.0-next.0 - '@3sixty/blob-storage-connector-azure': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/blob-storage-connector-file': 0.20.0-next.0 - '@3sixty/blob-storage-connector-gcp': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/blob-storage-connector-ipfs': 0.20.0-next.0 - '@3sixty/blob-storage-connector-memory': 0.20.0-next.0 - '@3sixty/blob-storage-models': 0.20.0-next.0 - '@3sixty/blob-storage-rest-client': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/blob-storage-service': 0.20.0-next.0 + '@3sixty/automation-actions': 0.20.0-next.1 + '@3sixty/automation-models': 0.20.0-next.1 + '@3sixty/automation-rest-client': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/automation-service': 0.20.0-next.1 + '@3sixty/background-task-models': 0.20.0-next.1 + '@3sixty/background-task-scheduler': 0.20.0-next.1 + '@3sixty/background-task-service': 0.20.0-next.1 + '@3sixty/blob-storage-connector-aws-s3': 0.20.0-next.1 + '@3sixty/blob-storage-connector-azure': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/blob-storage-connector-file': 0.20.0-next.1 + '@3sixty/blob-storage-connector-gcp': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/blob-storage-connector-ipfs': 0.20.0-next.1 + '@3sixty/blob-storage-connector-memory': 0.20.0-next.1 + '@3sixty/blob-storage-models': 0.20.0-next.1 + '@3sixty/blob-storage-rest-client': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/blob-storage-service': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 - '@3sixty/data-core': 0.20.0-next.2 - '@3sixty/data-processing-converters': 0.20.0-next.0 - '@3sixty/data-processing-extractors': 0.20.0-next.0 - '@3sixty/data-processing-models': 0.20.0-next.0 - '@3sixty/data-processing-rest-client': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/data-processing-service': 0.20.0-next.0 + '@3sixty/data-core': 0.20.0-next.3 + '@3sixty/data-processing-converters': 0.20.0-next.1 + '@3sixty/data-processing-extractors': 0.20.0-next.1 + '@3sixty/data-processing-models': 0.20.0-next.1 + '@3sixty/data-processing-rest-client': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/data-processing-service': 0.20.0-next.1 '@3sixty/dataspace-control-plane-rest-client': 0.20.0-next.0(supports-color@10.2.2) '@3sixty/dataspace-control-plane-service': 0.20.0-next.0 '@3sixty/dataspace-data-plane-rest-client': 0.20.0-next.0(supports-color@10.2.2) '@3sixty/dataspace-data-plane-service': 0.20.0-next.0 '@3sixty/dataspace-data-plane-socket-client': 0.20.0-next.0(supports-color@10.2.2) '@3sixty/dataspace-models': 0.20.0-next.0 - '@3sixty/dlt-iota': 0.20.0-next.0(typescript@6.0.3) + '@3sixty/dlt-iota': 0.20.0-next.1(typescript@6.0.3) '@3sixty/document-management-models': 0.20.0-next.0 '@3sixty/document-management-rest-client': 0.20.0-next.0(supports-color@10.2.2) '@3sixty/document-management-service': 0.20.0-next.0 '@3sixty/engine-core': 0.20.0-next.1 '@3sixty/engine-models': 0.20.0-next.1 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-connector-cosmosdb': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/entity-storage-connector-dynamodb': 0.20.0-next.0 - '@3sixty/entity-storage-connector-file': 0.20.0-next.0 - '@3sixty/entity-storage-connector-gcp-firestore': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/entity-storage-connector-memory': 0.20.0-next.0 - '@3sixty/entity-storage-connector-mongodb': 0.20.0-next.0(socks@2.8.10) - '@3sixty/entity-storage-connector-mysql': 0.20.0-next.0(@types/node@26.6.5) - '@3sixty/entity-storage-connector-postgresql': 0.20.0-next.0 - '@3sixty/entity-storage-connector-scylladb': 0.20.0-next.0 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/entity-storage-rest-client': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/entity-storage-service': 0.20.0-next.0 - '@3sixty/event-bus-connector-local': 0.20.0-next.0 - '@3sixty/event-bus-models': 0.20.0-next.0 - '@3sixty/event-bus-service': 0.20.0-next.0 - '@3sixty/event-bus-socket-client': 0.20.0-next.0(supports-color@10.2.2) + '@3sixty/entity-storage-connector-cosmosdb': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/entity-storage-connector-dynamodb': 0.20.0-next.1 + '@3sixty/entity-storage-connector-file': 0.20.0-next.1 + '@3sixty/entity-storage-connector-gcp-firestore': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/entity-storage-connector-memory': 0.20.0-next.1 + '@3sixty/entity-storage-connector-mongodb': 0.20.0-next.1(socks@2.8.10) + '@3sixty/entity-storage-connector-mysql': 0.20.0-next.1(@types/node@26.6.5) + '@3sixty/entity-storage-connector-postgresql': 0.20.0-next.1 + '@3sixty/entity-storage-connector-scylladb': 0.20.0-next.1 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/entity-storage-rest-client': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/entity-storage-service': 0.20.0-next.1 + '@3sixty/event-bus-connector-local': 0.20.0-next.1 + '@3sixty/event-bus-models': 0.20.0-next.1 + '@3sixty/event-bus-service': 0.20.0-next.1 + '@3sixty/event-bus-socket-client': 0.20.0-next.1(supports-color@10.2.2) '@3sixty/federated-catalogue-filters': 0.20.0-next.0 '@3sixty/federated-catalogue-models': 0.20.0-next.0 '@3sixty/federated-catalogue-rest-client': 0.20.0-next.0(supports-color@10.2.2) @@ -6721,26 +6720,26 @@ snapshots: '@3sixty/immutable-proof-models': 0.20.0-next.0 '@3sixty/immutable-proof-rest-client': 0.20.0-next.0(supports-color@10.2.2) '@3sixty/immutable-proof-service': 0.20.0-next.0 - '@3sixty/logging-connector-console': 0.20.0-next.0 - '@3sixty/logging-connector-elk': 0.20.0-next.0 - '@3sixty/logging-connector-entity-storage': 0.20.0-next.0 - '@3sixty/logging-connector-file': 0.20.0-next.0 - '@3sixty/logging-connector-opentelemetry': 0.20.0-next.0(@opentelemetry/api@1.9.1) - '@3sixty/logging-models': 0.20.0-next.0 - '@3sixty/logging-rest-client': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/logging-service': 0.20.0-next.0 - '@3sixty/mailbox-connector-gmail': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/mailbox-connector-imap': 0.20.0-next.0 - '@3sixty/mailbox-connector-outlook': 0.20.0-next.0(buffer@6.0.3) - '@3sixty/mailbox-connector-pop3': 0.20.0-next.0 - '@3sixty/mailbox-models': 0.20.0-next.0 - '@3sixty/mailbox-rest-client': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/mailbox-service': 0.20.0-next.0 - '@3sixty/messaging-connector-aws': 0.20.0-next.0 - '@3sixty/messaging-connector-entity-storage': 0.20.0-next.0 - '@3sixty/messaging-connector-smtp': 0.20.0-next.0 - '@3sixty/messaging-models': 0.20.0-next.0 - '@3sixty/messaging-service': 0.20.0-next.0 + '@3sixty/logging-connector-console': 0.20.0-next.1 + '@3sixty/logging-connector-elk': 0.20.0-next.1 + '@3sixty/logging-connector-entity-storage': 0.20.0-next.1 + '@3sixty/logging-connector-file': 0.20.0-next.1 + '@3sixty/logging-connector-opentelemetry': 0.20.0-next.1(@opentelemetry/api@1.9.1) + '@3sixty/logging-models': 0.20.0-next.1 + '@3sixty/logging-rest-client': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/logging-service': 0.20.0-next.1 + '@3sixty/mailbox-connector-gmail': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/mailbox-connector-imap': 0.20.0-next.1 + '@3sixty/mailbox-connector-outlook': 0.20.0-next.1(buffer@6.0.3) + '@3sixty/mailbox-connector-pop3': 0.20.0-next.1 + '@3sixty/mailbox-models': 0.20.0-next.1 + '@3sixty/mailbox-rest-client': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/mailbox-service': 0.20.0-next.1 + '@3sixty/messaging-connector-aws': 0.20.0-next.1 + '@3sixty/messaging-connector-entity-storage': 0.20.0-next.1 + '@3sixty/messaging-connector-smtp': 0.20.0-next.1 + '@3sixty/messaging-models': 0.20.0-next.1 + '@3sixty/messaging-service': 0.20.0-next.1 '@3sixty/modules': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/nft-connector-entity-storage': 0.20.0-next.0 @@ -6764,30 +6763,30 @@ snapshots: '@3sixty/rights-management-pxp-service': 0.20.0-next.0 '@3sixty/rights-management-rest-client': 0.20.0-next.0(supports-color@10.2.2) '@3sixty/rights-management-service': 0.20.0-next.0 - '@3sixty/telemetry-connector-entity-storage': 0.20.0-next.0 - '@3sixty/telemetry-connector-opentelemetry': 0.20.0-next.0 - '@3sixty/telemetry-models': 0.20.0-next.0 - '@3sixty/telemetry-producers': 0.20.0-next.0 - '@3sixty/telemetry-rest-client': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/telemetry-service': 0.20.0-next.0 - '@3sixty/tracing-connector-console': 0.20.0-next.0 - '@3sixty/tracing-connector-entity-storage': 0.20.0-next.0 - '@3sixty/tracing-connector-opentelemetry': 0.20.0-next.0 - '@3sixty/tracing-facades': 0.20.0-next.0 - '@3sixty/tracing-models': 0.20.0-next.0 - '@3sixty/tracing-processors': 0.20.0-next.0 - '@3sixty/tracing-rest-client': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/tracing-service': 0.20.0-next.0 + '@3sixty/telemetry-connector-entity-storage': 0.20.0-next.1 + '@3sixty/telemetry-connector-opentelemetry': 0.20.0-next.1 + '@3sixty/telemetry-models': 0.20.0-next.1 + '@3sixty/telemetry-producers': 0.20.0-next.1 + '@3sixty/telemetry-rest-client': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/telemetry-service': 0.20.0-next.1 + '@3sixty/tracing-connector-console': 0.20.0-next.1 + '@3sixty/tracing-connector-entity-storage': 0.20.0-next.1 + '@3sixty/tracing-connector-opentelemetry': 0.20.0-next.1 + '@3sixty/tracing-facades': 0.20.0-next.1 + '@3sixty/tracing-models': 0.20.0-next.1 + '@3sixty/tracing-processors': 0.20.0-next.1 + '@3sixty/tracing-rest-client': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/tracing-service': 0.20.0-next.1 '@3sixty/trust-generators': 0.20.0-next.0 '@3sixty/trust-models': 0.20.0-next.0 '@3sixty/trust-service': 0.20.0-next.0 '@3sixty/trust-verifiers': 0.20.0-next.0 - '@3sixty/vault-connector-entity-storage': 0.20.0-next.0 - '@3sixty/vault-connector-hashicorp': 0.20.0-next.0 - '@3sixty/vault-models': 0.20.0-next.0 - '@3sixty/wallet-connector-entity-storage': 0.20.0-next.0 - '@3sixty/wallet-connector-iota': 0.20.0-next.0(typescript@6.0.3) - '@3sixty/wallet-models': 0.20.0-next.0 + '@3sixty/vault-connector-entity-storage': 0.20.0-next.1 + '@3sixty/vault-connector-hashicorp': 0.20.0-next.1 + '@3sixty/vault-models': 0.20.0-next.1 + '@3sixty/wallet-connector-entity-storage': 0.20.0-next.1 + '@3sixty/wallet-connector-iota': 0.20.0-next.1(typescript@6.0.3) + '@3sixty/wallet-models': 0.20.0-next.1 transitivePeerDependencies: - '@aws-sdk/credential-providers' - '@azure/identity' @@ -6841,76 +6840,76 @@ snapshots: - typescript - utf-8-validate - '@3sixty/entity-storage-connector-cosmosdb@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/entity-storage-connector-cosmosdb@0.20.0-next.1(supports-color@10.2.2)': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@azure/cosmos': 4.10.1(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@3sixty/entity-storage-connector-dynamodb@0.20.0-next.0': + '@3sixty/entity-storage-connector-dynamodb@0.20.0-next.1': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@aws-sdk/client-dynamodb': 3.1137.0 - '@aws-sdk/lib-dynamodb': 3.1137.0(@aws-sdk/client-dynamodb@3.1137.0) - '@aws-sdk/util-dynamodb': 3.996.9(@aws-sdk/client-dynamodb@3.1137.0) + '@aws-sdk/client-dynamodb': 3.1153.0 + '@aws-sdk/lib-dynamodb': 3.1153.0(@aws-sdk/client-dynamodb@3.1153.0) + '@aws-sdk/util-dynamodb': 3.996.9(@aws-sdk/client-dynamodb@3.1153.0) - '@3sixty/entity-storage-connector-file@0.20.0-next.0': + '@3sixty/entity-storage-connector-file@0.20.0-next.1': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/entity-storage-connector-gcp-firestore@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/entity-storage-connector-gcp-firestore@0.20.0-next.1(supports-color@10.2.2)': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@google-cloud/firestore': 9.2.0(supports-color@10.2.2) - google-auth-library: 11.1.0(supports-color@10.2.2) + '@google-cloud/firestore': 9.3.1(supports-color@10.2.2) + google-auth-library: 11.3.1(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@3sixty/entity-storage-connector-memory@0.20.0-next.0': + '@3sixty/entity-storage-connector-memory@0.20.0-next.1': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/entity-storage-connector-mongodb@0.20.0-next.0(socks@2.8.10)': + '@3sixty/entity-storage-connector-mongodb@0.20.0-next.1(socks@2.8.10)': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - mongodb: 7.6.0(socks@2.8.10) + mongodb: 7.7.0(socks@2.8.10) transitivePeerDependencies: - '@aws-sdk/credential-providers' - '@mongodb-js/zstd' @@ -6920,58 +6919,58 @@ snapshots: - snappy - socks - '@3sixty/entity-storage-connector-mysql@0.20.0-next.0(@types/node@26.6.5)': + '@3sixty/entity-storage-connector-mysql@0.20.0-next.1(@types/node@26.6.5)': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - mysql2: 3.24.4(@types/node@26.6.5) + mysql2: 3.24.6(@types/node@26.6.5) transitivePeerDependencies: - '@types/node' - '@3sixty/entity-storage-connector-postgresql@0.20.0-next.0': + '@3sixty/entity-storage-connector-postgresql@0.20.0-next.1': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 postgres: 3.4.9 - '@3sixty/entity-storage-connector-scylladb@0.20.0-next.0': + '@3sixty/entity-storage-connector-scylladb@0.20.0-next.1': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - cassandra-driver: 4.9.0 + cassandra-driver: 4.10.0 - '@3sixty/entity-storage-models@0.20.0-next.0': + '@3sixty/entity-storage-models@0.20.0-next.1': dependencies: '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/entity-storage-rest-client@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/entity-storage-rest-client@0.20.0-next.1(supports-color@10.2.2)': dependencies: - '@3sixty/api-core': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 transitivePeerDependencies: @@ -6979,14 +6978,14 @@ snapshots: - supports-color - utf-8-validate - '@3sixty/entity-storage-service@0.20.0-next.0': + '@3sixty/entity-storage-service@0.20.0-next.1': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 @@ -6997,33 +6996,33 @@ snapshots: reflect-metadata: 0.2.2 tslib: 2.8.1 - '@3sixty/event-bus-connector-local@0.20.0-next.0': + '@3sixty/event-bus-connector-local@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/event-bus-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/event-bus-models': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/event-bus-models@0.20.0-next.0': + '@3sixty/event-bus-models@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/event-bus-service@0.20.0-next.0': + '@3sixty/event-bus-service@0.20.0-next.1': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 - '@3sixty/event-bus-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/event-bus-models': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/event-bus-socket-client@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/event-bus-socket-client@0.20.0-next.1(supports-color@10.2.2)': dependencies: - '@3sixty/api-core': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 - '@3sixty/event-bus-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/event-bus-models': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 transitivePeerDependencies: - bufferutil @@ -7032,44 +7031,44 @@ snapshots: '@3sixty/federated-catalogue-filters@0.20.0-next.0': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 '@3sixty/federated-catalogue-models': 0.20.0-next.0 '@3sixty/federated-catalogue-service': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/standards-dataspace-protocol': 0.20.0-next.1 - '@3sixty/standards-w3c-dcat': 0.20.0-next.1 + '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 + '@3sixty/standards-w3c-dcat': 0.20.0-next.2 '@3sixty/trust-models': 0.20.0-next.0 '@3sixty/web': 0.20.0-next.2 '@3sixty/federated-catalogue-models@0.20.0-next.0': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-core': 0.20.0-next.3 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/standards-dataspace-protocol': 0.20.0-next.1 - '@3sixty/standards-w3c-dcat': 0.20.0-next.1 - '@3sixty/telemetry-models': 0.20.0-next.0 + '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 + '@3sixty/standards-w3c-dcat': 0.20.0-next.2 + '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/trust-models': 0.20.0-next.0 '@3sixty/web': 0.20.0-next.2 '@3sixty/federated-catalogue-rest-client@0.20.0-next.0(supports-color@10.2.2)': dependencies: - '@3sixty/api-core': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/federated-catalogue-models': 0.20.0-next.0 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/standards-dataspace-protocol': 0.20.0-next.1 - '@3sixty/standards-w3c-dcat': 0.20.0-next.1 + '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 + '@3sixty/standards-w3c-dcat': 0.20.0-next.2 '@3sixty/trust-models': 0.20.0-next.0 '@3sixty/web': 0.20.0-next.2 transitivePeerDependencies: @@ -7079,51 +7078,51 @@ snapshots: '@3sixty/federated-catalogue-service@0.20.0-next.0': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 '@3sixty/federated-catalogue-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 - '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/standards-dataspace-protocol': 0.20.0-next.1 - '@3sixty/standards-dublin-core': 0.20.0-next.1 - '@3sixty/standards-foaf': 0.20.0-next.1 - '@3sixty/standards-w3c-dcat': 0.20.0-next.1 - '@3sixty/standards-w3c-odrl': 0.20.0-next.1 - '@3sixty/telemetry-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 + '@3sixty/nameof': 0.20.0-next.2 + '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 + '@3sixty/standards-dublin-core': 0.20.0-next.2 + '@3sixty/standards-foaf': 0.20.0-next.2 + '@3sixty/standards-w3c-dcat': 0.20.0-next.2 + '@3sixty/standards-w3c-odrl': 0.20.0-next.2 + '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/trust-models': 0.20.0-next.0 - '@3sixty/vault-models': 0.20.0-next.0 + '@3sixty/vault-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 '@3sixty/identity-connector-entity-storage@0.20.0-next.0': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-core': 0.20.0-next.3 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 '@3sixty/identity-models': 0.20.0-next.0 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/standards-w3c-did': 0.20.0-next.1 - '@3sixty/vault-models': 0.20.0-next.0 + '@3sixty/standards-w3c-did': 0.20.0-next.2 + '@3sixty/vault-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 '@3sixty/identity-connector-iota@0.20.0-next.0(typescript@6.0.3)': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 - '@3sixty/dlt-account': 0.20.0-next.0 - '@3sixty/dlt-iota': 0.20.0-next.0(typescript@6.0.3) + '@3sixty/data-json-ld': 0.20.0-next.3 + '@3sixty/dlt-account': 0.20.0-next.1 + '@3sixty/dlt-iota': 0.20.0-next.1(typescript@6.0.3) '@3sixty/entity': 0.20.0-next.2 '@3sixty/identity-models': 0.20.0-next.0 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/standards-w3c-did': 0.20.0-next.1 - '@3sixty/vault-models': 0.20.0-next.0 + '@3sixty/standards-w3c-did': 0.20.0-next.2 + '@3sixty/vault-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 '@iota/identity-wasm': 1.9.6-beta.1(@iota/iota-sdk@1.15.0(typescript@6.0.3)) '@iota/iota-interaction-ts': 0.14.0(@iota/iota-sdk@1.15.0(typescript@6.0.3)) @@ -7136,36 +7135,36 @@ snapshots: '@3sixty/identity-connector-universal@0.20.0-next.0': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/identity-models': 0.20.0-next.0 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/standards-w3c-did': 0.20.0-next.1 + '@3sixty/standards-w3c-did': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 '@3sixty/identity-models@0.20.0-next.0': dependencies: '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-core': 0.20.0-next.3 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/standards-w3c-did': 0.20.0-next.1 - '@3sixty/telemetry-models': 0.20.0-next.0 + '@3sixty/standards-w3c-did': 0.20.0-next.2 + '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 '@3sixty/identity-rest-client@0.20.0-next.0(supports-color@10.2.2)': dependencies: - '@3sixty/api-core': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-core': 0.20.0-next.3 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 '@3sixty/identity-models': 0.20.0-next.0 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/standards-w3c-did': 0.20.0-next.1 + '@3sixty/standards-w3c-did': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 transitivePeerDependencies: - bufferutil @@ -7174,38 +7173,38 @@ snapshots: '@3sixty/identity-service@0.20.0-next.0': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 - '@3sixty/dlt-account': 0.20.0-next.0 + '@3sixty/data-core': 0.20.0-next.3 + '@3sixty/data-json-ld': 0.20.0-next.3 + '@3sixty/dlt-account': 0.20.0-next.1 '@3sixty/entity': 0.20.0-next.2 '@3sixty/identity-models': 0.20.0-next.0 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/standards-w3c-did': 0.20.0-next.1 - '@3sixty/telemetry-models': 0.20.0-next.0 - '@3sixty/vault-models': 0.20.0-next.0 - '@3sixty/wallet-models': 0.20.0-next.0 + '@3sixty/standards-w3c-did': 0.20.0-next.2 + '@3sixty/telemetry-models': 0.20.0-next.1 + '@3sixty/vault-models': 0.20.0-next.1 + '@3sixty/wallet-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 '@3sixty/immutable-proof-models@0.20.0-next.0': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-core': 0.20.0-next.3 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/standards-w3c-did': 0.20.0-next.1 - '@3sixty/telemetry-models': 0.20.0-next.0 + '@3sixty/standards-w3c-did': 0.20.0-next.2 + '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 '@3sixty/immutable-proof-rest-client@0.20.0-next.0(supports-color@10.2.2)': dependencies: - '@3sixty/api-core': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 '@3sixty/immutable-proof-models': 0.20.0-next.0 '@3sixty/nameof': 0.20.0-next.2 @@ -7217,96 +7216,96 @@ snapshots: '@3sixty/immutable-proof-service@0.20.0-next.0': dependencies: - '@3sixty/api-models': 0.20.0-next.0 - '@3sixty/background-task-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 + '@3sixty/background-task-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/event-bus-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/event-bus-models': 0.20.0-next.1 '@3sixty/identity-models': 0.20.0-next.0 '@3sixty/immutable-proof-models': 0.20.0-next.0 '@3sixty/immutable-proof-task': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/notarization-models': 0.20.0-next.0 - '@3sixty/standards-w3c-did': 0.20.0-next.1 - '@3sixty/telemetry-models': 0.20.0-next.0 + '@3sixty/standards-w3c-did': 0.20.0-next.2 + '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 '@3sixty/immutable-proof-task@0.20.0-next.0': dependencies: '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/identity-models': 0.20.0-next.0 '@3sixty/immutable-proof-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/modules': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/notarization-models': 0.20.0-next.0 - '@3sixty/standards-w3c-did': 0.20.0-next.1 + '@3sixty/standards-w3c-did': 0.20.0-next.2 - '@3sixty/logging-connector-console@0.20.0-next.0': + '@3sixty/logging-connector-console@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/logging-connector-elk@0.20.0-next.0': + '@3sixty/logging-connector-elk@0.20.0-next.1': dependencies: '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 - '@3sixty/logging-connector-entity-storage@0.20.0-next.0': + '@3sixty/logging-connector-entity-storage@0.20.0-next.1': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/logging-connector-file@0.20.0-next.0': + '@3sixty/logging-connector-file@0.20.0-next.1': dependencies: '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/logging-connector-opentelemetry@0.20.0-next.0(@opentelemetry/api@1.9.1)': + '@3sixty/logging-connector-opentelemetry@0.20.0-next.1(@opentelemetry/api@1.9.1)': dependencies: '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@opentelemetry/api-logs': 0.222.0 - '@opentelemetry/exporter-logs-otlp-http': 0.222.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.11.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-logs': 0.222.0(@opentelemetry/api@1.9.1) + '@opentelemetry/api-logs': 0.223.0 + '@opentelemetry/exporter-logs-otlp-http': 0.223.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.12.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-logs': 0.223.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.43.0 transitivePeerDependencies: - '@opentelemetry/api' - '@3sixty/logging-models@0.20.0-next.0': + '@3sixty/logging-models@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/logging-rest-client@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/logging-rest-client@0.20.0-next.1(supports-color@10.2.2)': dependencies: - '@3sixty/api-core': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 transitivePeerDependencies: @@ -7314,46 +7313,46 @@ snapshots: - supports-color - utf-8-validate - '@3sixty/logging-service@0.20.0-next.0': + '@3sixty/logging-service@0.20.0-next.1': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 - '@3sixty/mailbox-connector-gmail@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/mailbox-connector-gmail@0.20.0-next.1(supports-color@10.2.2)': dependencies: - '@3sixty/background-task-models': 0.20.0-next.0 + '@3sixty/background-task-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 - '@3sixty/mailbox-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 + '@3sixty/mailbox-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - googleapis: 181.0.0(supports-color@10.2.2) + googleapis: 186.0.0(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@3sixty/mailbox-connector-imap@0.20.0-next.0': + '@3sixty/mailbox-connector-imap@0.20.0-next.1': dependencies: - '@3sixty/background-task-models': 0.20.0-next.0 + '@3sixty/background-task-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 - '@3sixty/mailbox-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 + '@3sixty/mailbox-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - imapflow: 2.0.5 + imapflow: 2.5.8 - '@3sixty/mailbox-connector-outlook@0.20.0-next.0(buffer@6.0.3)': + '@3sixty/mailbox-connector-outlook@0.20.0-next.1(buffer@6.0.3)': dependencies: - '@3sixty/background-task-models': 0.20.0-next.0 + '@3sixty/background-task-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 - '@3sixty/mailbox-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 + '@3sixty/mailbox-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@azure/msal-node': 6.0.1 + '@azure/msal-node': 7.1.0 '@microsoft/microsoft-graph-client': 3.0.7(buffer@6.0.3) transitivePeerDependencies: - '@azure/identity' @@ -7361,31 +7360,31 @@ snapshots: - buffer - stream-browserify - '@3sixty/mailbox-connector-pop3@0.20.0-next.0': + '@3sixty/mailbox-connector-pop3@0.20.0-next.1': dependencies: - '@3sixty/background-task-models': 0.20.0-next.0 + '@3sixty/background-task-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 - '@3sixty/mailbox-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 + '@3sixty/mailbox-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 node-pop3: 0.15.3 - '@3sixty/mailbox-models@0.20.0-next.0': + '@3sixty/mailbox-models@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/telemetry-models': 0.20.0-next.0 + '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - postal-mime: 3.0.0 + postal-mime: 4.0.11 - '@3sixty/mailbox-rest-client@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/mailbox-rest-client@0.20.0-next.1(supports-color@10.2.2)': dependencies: - '@3sixty/api-core': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 - '@3sixty/mailbox-models': 0.20.0-next.0 + '@3sixty/mailbox-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 transitivePeerDependencies: @@ -7393,19 +7392,19 @@ snapshots: - supports-color - utf-8-validate - '@3sixty/mailbox-service@0.20.0-next.0': + '@3sixty/mailbox-service@0.20.0-next.1': dependencies: - '@3sixty/api-models': 0.20.0-next.0 - '@3sixty/background-task-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 + '@3sixty/background-task-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 - '@3sixty/mailbox-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 + '@3sixty/mailbox-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/telemetry-models': 0.20.0-next.0 - '@3sixty/vault-models': 0.20.0-next.0 + '@3sixty/telemetry-models': 0.20.0-next.1 + '@3sixty/vault-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 '@3sixty/merge-locales@0.20.0-next.2': @@ -7416,46 +7415,46 @@ snapshots: commander: 15.0.0 glob: 13.0.6 - '@3sixty/messaging-connector-aws@0.20.0-next.0': + '@3sixty/messaging-connector-aws@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 - '@3sixty/messaging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 + '@3sixty/messaging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 - '@aws-sdk/client-ses': 3.1137.0 - '@aws-sdk/client-sns': 3.1137.0 + '@aws-sdk/client-ses': 3.1153.0 + '@aws-sdk/client-sns': 3.1153.0 - '@3sixty/messaging-connector-entity-storage@0.20.0-next.0': + '@3sixty/messaging-connector-entity-storage@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 - '@3sixty/messaging-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 + '@3sixty/messaging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/messaging-connector-smtp@0.20.0-next.0': + '@3sixty/messaging-connector-smtp@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 - '@3sixty/messaging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 + '@3sixty/messaging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - nodemailer: 10.0.10 + nodemailer: 10.1.7 - '@3sixty/messaging-models@0.20.0-next.0': + '@3sixty/messaging-models@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/messaging-service@0.20.0-next.0': + '@3sixty/messaging-service@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 - '@3sixty/messaging-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 + '@3sixty/messaging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/modules@0.20.0-next.2': @@ -7496,19 +7495,19 @@ snapshots: '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/nft-models': 0.20.0-next.0 '@3sixty/nft-connector-iota@0.20.0-next.0(typescript@6.0.3)': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/dlt-account': 0.20.0-next.0 - '@3sixty/dlt-iota': 0.20.0-next.0(typescript@6.0.3) - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/dlt-account': 0.20.0-next.1 + '@3sixty/dlt-iota': 0.20.0-next.1(typescript@6.0.3) + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/nft-models': 0.20.0-next.0 - '@3sixty/vault-models': 0.20.0-next.0 + '@3sixty/vault-models': 0.20.0-next.1 transitivePeerDependencies: - '@gql.tada/svelte-support' - '@gql.tada/vue-support' @@ -7519,13 +7518,13 @@ snapshots: dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/telemetry-models': 0.20.0-next.0 + '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 '@3sixty/nft-rest-client@0.20.0-next.0(supports-color@10.2.2)': dependencies: - '@3sixty/api-core': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 @@ -7537,13 +7536,13 @@ snapshots: '@3sixty/nft-service@0.20.0-next.0': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/nft-models': 0.20.0-next.0 - '@3sixty/telemetry-models': 0.20.0-next.0 + '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 '@3sixty/notarization-connector-entity-storage@0.20.0-next.0': @@ -7551,20 +7550,20 @@ snapshots: '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/notarization-models': 0.20.0-next.0 '@3sixty/notarization-connector-iota@0.20.0-next.0(typescript@6.0.3)': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/dlt-account': 0.20.0-next.0 - '@3sixty/dlt-iota': 0.20.0-next.0(typescript@6.0.3) - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/dlt-account': 0.20.0-next.1 + '@3sixty/dlt-iota': 0.20.0-next.1(typescript@6.0.3) + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/notarization-models': 0.20.0-next.0 - '@3sixty/vault-models': 0.20.0-next.0 + '@3sixty/vault-models': 0.20.0-next.1 '@iota/iota-sdk': 1.15.0(typescript@6.0.3) '@iota/notarization': 0.1.14(@iota/iota-sdk@1.15.0(typescript@6.0.3)) transitivePeerDependencies: @@ -7577,13 +7576,13 @@ snapshots: dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/telemetry-models': 0.20.0-next.0 + '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 '@3sixty/notarization-rest-client@0.20.0-next.0(supports-color@10.2.2)': dependencies: - '@3sixty/api-core': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 @@ -7595,26 +7594,26 @@ snapshots: '@3sixty/notarization-service@0.20.0-next.0': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/notarization-models': 0.20.0-next.0 - '@3sixty/telemetry-models': 0.20.0-next.0 + '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 '@3sixty/rights-management-models@0.20.0-next.0': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/engine-models': 0.20.0-next.1 '@3sixty/entity': 0.20.0-next.2 '@3sixty/identity-models': 0.20.0-next.0 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/standards-dataspace-protocol': 0.20.0-next.1 - '@3sixty/standards-w3c-did': 0.20.0-next.1 - '@3sixty/standards-w3c-odrl': 0.20.0-next.1 + '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 + '@3sixty/standards-w3c-did': 0.20.0-next.2 + '@3sixty/standards-w3c-odrl': 0.20.0-next.2 '@3sixty/trust-models': 0.20.0-next.0 '@3sixty/web': 0.20.0-next.2 @@ -7622,103 +7621,103 @@ snapshots: dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/rights-management-models': 0.20.0-next.0 - '@3sixty/standards-dataspace-protocol': 0.20.0-next.1 - '@3sixty/standards-w3c-odrl': 0.20.0-next.1 + '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 + '@3sixty/standards-w3c-odrl': 0.20.0-next.2 '@3sixty/rights-management-pdp-service@0.20.0-next.0': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/data-json-ld': 0.20.0-next.3 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/rights-management-models': 0.20.0-next.0 - '@3sixty/standards-dataspace-protocol': 0.20.0-next.1 - '@3sixty/standards-w3c-odrl': 0.20.0-next.1 + '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 + '@3sixty/standards-w3c-odrl': 0.20.0-next.2 '@3sixty/rights-management-pep-service@0.20.0-next.0': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/data-json-ld': 0.20.0-next.3 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/rights-management-models': 0.20.0-next.0 - '@3sixty/standards-dataspace-protocol': 0.20.0-next.1 - '@3sixty/standards-w3c-odrl': 0.20.0-next.1 + '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 + '@3sixty/standards-w3c-odrl': 0.20.0-next.2 '@3sixty/rights-management-pip-service@0.20.0-next.0': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/identity-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/rights-management-models': 0.20.0-next.0 - '@3sixty/standards-w3c-odrl': 0.20.0-next.1 + '@3sixty/standards-w3c-odrl': 0.20.0-next.2 '@3sixty/rights-management-plugins@0.20.0-next.0': dependencies: - '@3sixty/automation-models': 0.20.0-next.0 + '@3sixty/automation-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 - '@3sixty/data-json-path': 0.20.0-next.2 + '@3sixty/data-json-ld': 0.20.0-next.3 + '@3sixty/data-json-path': 0.20.0-next.3 '@3sixty/identity-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/rights-management-models': 0.20.0-next.0 - '@3sixty/standards-dataspace-protocol': 0.20.0-next.1 - '@3sixty/standards-w3c-odrl': 0.20.0-next.1 + '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 + '@3sixty/standards-w3c-odrl': 0.20.0-next.2 '@3sixty/rights-management-pmp-service@0.20.0-next.0': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/rights-management-models': 0.20.0-next.0 '@3sixty/rights-management-pnp-service@0.20.0-next.0': dependencies: - '@3sixty/api-models': 0.20.0-next.0 - '@3sixty/background-task-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 + '@3sixty/background-task-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/rights-management-models': 0.20.0-next.0 - '@3sixty/standards-dataspace-protocol': 0.20.0-next.1 - '@3sixty/standards-w3c-did': 0.20.0-next.1 - '@3sixty/standards-w3c-odrl': 0.20.0-next.1 + '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 + '@3sixty/standards-w3c-did': 0.20.0-next.2 + '@3sixty/standards-w3c-odrl': 0.20.0-next.2 '@3sixty/trust-models': 0.20.0-next.0 '@3sixty/rights-management-pxp-service@0.20.0-next.0': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/rights-management-models': 0.20.0-next.0 - '@3sixty/standards-w3c-odrl': 0.20.0-next.1 + '@3sixty/standards-w3c-odrl': 0.20.0-next.2 '@3sixty/rights-management-rest-client@0.20.0-next.0(supports-color@10.2.2)': dependencies: - '@3sixty/api-core': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/rights-management-models': 0.20.0-next.0 - '@3sixty/standards-dataspace-protocol': 0.20.0-next.1 - '@3sixty/standards-w3c-did': 0.20.0-next.1 + '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 + '@3sixty/standards-w3c-did': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 transitivePeerDependencies: - bufferutil @@ -7727,161 +7726,161 @@ snapshots: '@3sixty/rights-management-service@0.20.0-next.0': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/rights-management-models': 0.20.0-next.0 - '@3sixty/standards-dataspace-protocol': 0.20.0-next.1 - '@3sixty/standards-w3c-did': 0.20.0-next.1 - '@3sixty/standards-w3c-odrl': 0.20.0-next.1 + '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 + '@3sixty/standards-w3c-did': 0.20.0-next.2 + '@3sixty/standards-w3c-odrl': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 - '@3sixty/standards-dataspace-protocol@0.20.0-next.1': + '@3sixty/standards-dataspace-protocol@0.20.0-next.2': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-core': 0.20.0-next.3 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/standards-dublin-core': 0.20.0-next.1 - '@3sixty/standards-foaf': 0.20.0-next.1 - '@3sixty/standards-w3c-dcat': 0.20.0-next.1 - '@3sixty/standards-w3c-odrl': 0.20.0-next.1 + '@3sixty/standards-dublin-core': 0.20.0-next.2 + '@3sixty/standards-foaf': 0.20.0-next.2 + '@3sixty/standards-w3c-dcat': 0.20.0-next.2 + '@3sixty/standards-w3c-odrl': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 - '@3sixty/standards-dublin-core@0.20.0-next.1': + '@3sixty/standards-dublin-core@0.20.0-next.2': dependencies: - '@3sixty/data-core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-core': 0.20.0-next.3 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/web': 0.20.0-next.2 - '@3sixty/standards-foaf@0.20.0-next.1': + '@3sixty/standards-foaf@0.20.0-next.2': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-core': 0.20.0-next.3 + '@3sixty/data-json-ld': 0.20.0-next.3 - '@3sixty/standards-schema-org@0.20.0-next.1': + '@3sixty/standards-schema-org@0.20.0-next.2': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-core': 0.20.0-next.3 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - schema-dts: 2.0.0 + schema-dts: 2.1.0 - '@3sixty/standards-unece@0.20.0-next.1': + '@3sixty/standards-unece@0.20.0-next.2': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-core': 0.20.0-next.3 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/standards-w3c-activity-streams@0.20.0-next.1': + '@3sixty/standards-w3c-activity-streams@0.20.0-next.2': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-core': 0.20.0-next.3 + '@3sixty/data-json-ld': 0.20.0-next.3 - '@3sixty/standards-w3c-dcat@0.20.0-next.1': + '@3sixty/standards-w3c-dcat@0.20.0-next.2': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 - '@3sixty/standards-dublin-core': 0.20.0-next.1 - '@3sixty/standards-foaf': 0.20.0-next.1 - '@3sixty/standards-w3c-odrl': 0.20.0-next.1 + '@3sixty/data-core': 0.20.0-next.3 + '@3sixty/data-json-ld': 0.20.0-next.3 + '@3sixty/standards-dublin-core': 0.20.0-next.2 + '@3sixty/standards-foaf': 0.20.0-next.2 + '@3sixty/standards-w3c-odrl': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 - '@3sixty/standards-w3c-did@0.20.0-next.1': + '@3sixty/standards-w3c-did@0.20.0-next.2': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 - '@3sixty/data-core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-core': 0.20.0-next.3 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 - '@3sixty/standards-w3c-odrl@0.20.0-next.1': + '@3sixty/standards-w3c-odrl@0.20.0-next.2': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-core': 0.20.0-next.3 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/web': 0.20.0-next.2 - '@3sixty/telemetry-connector-entity-storage@0.20.0-next.0': + '@3sixty/telemetry-connector-entity-storage@0.20.0-next.1': dependencies: - '@3sixty/background-task-models': 0.20.0-next.0 + '@3sixty/background-task-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/modules': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/telemetry-models': 0.20.0-next.0 + '@3sixty/telemetry-models': 0.20.0-next.1 - '@3sixty/telemetry-connector-opentelemetry@0.20.0-next.0': + '@3sixty/telemetry-connector-opentelemetry@0.20.0-next.1': dependencies: '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/telemetry-connector-entity-storage': 0.20.0-next.0 - '@3sixty/telemetry-models': 0.20.0-next.0 + '@3sixty/telemetry-connector-entity-storage': 0.20.0-next.1 + '@3sixty/telemetry-models': 0.20.0-next.1 '@opentelemetry/api': 1.9.1 - '@opentelemetry/exporter-metrics-otlp-http': 0.222.0(@opentelemetry/api@1.9.1) - '@opentelemetry/exporter-prometheus': 0.222.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.11.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-metrics': 2.11.0(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-metrics-otlp-http': 0.223.0(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-prometheus': 0.223.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.12.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-metrics': 2.12.0(@opentelemetry/api@1.9.1) - '@3sixty/telemetry-models@0.20.0-next.0': + '@3sixty/telemetry-models@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/telemetry-processors@0.20.0-next.0': + '@3sixty/telemetry-processors@0.20.0-next.1': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/telemetry-models': 0.20.0-next.0 + '@3sixty/telemetry-models': 0.20.0-next.1 - '@3sixty/telemetry-producers@0.20.0-next.0': + '@3sixty/telemetry-producers@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/telemetry-models': 0.20.0-next.0 + '@3sixty/telemetry-models': 0.20.0-next.1 - '@3sixty/telemetry-rest-client@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/telemetry-rest-client@0.20.0-next.1(supports-color@10.2.2)': dependencies: - '@3sixty/api-core': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/telemetry-models': 0.20.0-next.0 + '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate - '@3sixty/telemetry-service@0.20.0-next.0': + '@3sixty/telemetry-service@0.20.0-next.1': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/telemetry-models': 0.20.0-next.0 + '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 '@3sixty/tools-core@0.20.0-next.4': @@ -7898,92 +7897,92 @@ snapshots: '@3sixty/core': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/tracing-connector-console@0.20.0-next.0': + '@3sixty/tracing-connector-console@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/tracing-models': 0.20.0-next.0 + '@3sixty/tracing-models': 0.20.0-next.1 - '@3sixty/tracing-connector-entity-storage@0.20.0-next.0': + '@3sixty/tracing-connector-entity-storage@0.20.0-next.1': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-connector-memory': 0.20.0-next.0 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/entity-storage-connector-memory': 0.20.0-next.1 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/tracing-models': 0.20.0-next.0 + '@3sixty/tracing-models': 0.20.0-next.1 - '@3sixty/tracing-connector-opentelemetry@0.20.0-next.0': + '@3sixty/tracing-connector-opentelemetry@0.20.0-next.1': dependencies: '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/tracing-models': 0.20.0-next.0 + '@3sixty/tracing-models': 0.20.0-next.1 '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.11.0(@opentelemetry/api@1.9.1) - '@opentelemetry/exporter-trace-otlp-proto': 0.222.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.11.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace': 2.11.0(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.12.0(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-trace-otlp-proto': 0.223.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.12.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace': 2.12.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.43.0 - '@3sixty/tracing-facades@0.20.0-next.0': + '@3sixty/tracing-facades@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/tracing-models': 0.20.0-next.0 + '@3sixty/tracing-models': 0.20.0-next.1 - '@3sixty/tracing-models@0.20.0-next.0': + '@3sixty/tracing-models@0.20.0-next.1': dependencies: '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/tracing-processors@0.20.0-next.0': + '@3sixty/tracing-processors@0.20.0-next.1': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/tracing-models': 0.20.0-next.0 + '@3sixty/tracing-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/tracing-rest-client@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/tracing-rest-client@0.20.0-next.1(supports-color@10.2.2)': dependencies: - '@3sixty/api-core': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/tracing-models': 0.20.0-next.0 + '@3sixty/tracing-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate - '@3sixty/tracing-service@0.20.0-next.0': + '@3sixty/tracing-service@0.20.0-next.1': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/tracing-models': 0.20.0-next.0 + '@3sixty/tracing-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 '@3sixty/trust-generators@0.20.0-next.0': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/identity-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/trust-models': 0.20.0-next.0 '@3sixty/web': 0.20.0-next.2 @@ -7992,13 +7991,13 @@ snapshots: dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/trust-service@0.20.0-next.0': dependencies: '@3sixty/core': 0.20.0-next.2 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/trust-models': 0.20.0-next.0 @@ -8006,9 +8005,9 @@ snapshots: dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 - '@3sixty/data-json-ld': 0.20.0-next.2 + '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/identity-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/trust-models': 0.20.0-next.0 '@3sixty/web': 0.20.0-next.2 @@ -8034,63 +8033,63 @@ snapshots: glob: 13.0.6 typescript: 6.0.3 - '@3sixty/vault-connector-entity-storage@0.20.0-next.0': + '@3sixty/vault-connector-entity-storage@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/vault-models': 0.20.0-next.0 + '@3sixty/vault-models': 0.20.0-next.1 - '@3sixty/vault-connector-hashicorp@0.20.0-next.0': + '@3sixty/vault-connector-hashicorp@0.20.0-next.1': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 - '@3sixty/logging-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/vault-models': 0.20.0-next.0 + '@3sixty/vault-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/vault-models@0.20.0-next.0': + '@3sixty/vault-models@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 - '@3sixty/wallet-connector-entity-storage@0.20.0-next.0': + '@3sixty/wallet-connector-entity-storage@0.20.0-next.1': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 - '@3sixty/dlt-account': 0.20.0-next.0 + '@3sixty/dlt-account': 0.20.0-next.1 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/entity-storage-models': 0.20.0-next.0 + '@3sixty/entity-storage-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/vault-models': 0.20.0-next.0 - '@3sixty/wallet-models': 0.20.0-next.0 + '@3sixty/vault-models': 0.20.0-next.1 + '@3sixty/wallet-models': 0.20.0-next.1 - '@3sixty/wallet-connector-iota@0.20.0-next.0(typescript@6.0.3)': + '@3sixty/wallet-connector-iota@0.20.0-next.1(typescript@6.0.3)': dependencies: - '@3sixty/api-models': 0.20.0-next.0 + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 - '@3sixty/dlt-account': 0.20.0-next.0 - '@3sixty/dlt-iota': 0.20.0-next.0(typescript@6.0.3) + '@3sixty/dlt-account': 0.20.0-next.1 + '@3sixty/dlt-iota': 0.20.0-next.1(typescript@6.0.3) '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/vault-models': 0.20.0-next.0 - '@3sixty/wallet-models': 0.20.0-next.0 + '@3sixty/vault-models': 0.20.0-next.1 + '@3sixty/wallet-models': 0.20.0-next.1 transitivePeerDependencies: - '@gql.tada/svelte-support' - '@gql.tada/vue-support' - encoding - typescript - '@3sixty/wallet-models@0.20.0-next.0': + '@3sixty/wallet-models@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 @@ -8111,7 +8110,7 @@ snapshots: '@smithy/types': 4.19.0 tslib: 2.8.1 - '@aws-sdk/client-dynamodb@3.1137.0': + '@aws-sdk/client-dynamodb@3.1153.0': dependencies: '@aws-sdk/core': 3.978.4 '@aws-sdk/credential-provider-node': 3.972.87 @@ -8124,7 +8123,7 @@ snapshots: '@smithy/types': 4.19.0 tslib: 2.8.1 - '@aws-sdk/client-s3@3.1137.0': + '@aws-sdk/client-s3@3.1153.0': dependencies: '@aws-sdk/checksums': 3.1001.4 '@aws-sdk/core': 3.978.4 @@ -8138,7 +8137,7 @@ snapshots: '@smithy/types': 4.19.0 tslib: 2.8.1 - '@aws-sdk/client-ses@3.1137.0': + '@aws-sdk/client-ses@3.1153.0': dependencies: '@aws-sdk/core': 3.978.4 '@aws-sdk/credential-provider-node': 3.972.87 @@ -8149,7 +8148,7 @@ snapshots: '@smithy/types': 4.19.0 tslib: 2.8.1 - '@aws-sdk/client-sns@3.1137.0': + '@aws-sdk/client-sns@3.1153.0': dependencies: '@aws-sdk/core': 3.978.4 '@aws-sdk/credential-provider-node': 3.972.87 @@ -8267,11 +8266,11 @@ snapshots: mnemonist: 0.38.3 tslib: 2.8.1 - '@aws-sdk/lib-dynamodb@3.1137.0(@aws-sdk/client-dynamodb@3.1137.0)': + '@aws-sdk/lib-dynamodb@3.1153.0(@aws-sdk/client-dynamodb@3.1153.0)': dependencies: - '@aws-sdk/client-dynamodb': 3.1137.0 + '@aws-sdk/client-dynamodb': 3.1153.0 '@aws-sdk/core': 3.978.4 - '@aws-sdk/util-dynamodb': 3.996.9(@aws-sdk/client-dynamodb@3.1137.0) + '@aws-sdk/util-dynamodb': 3.996.9(@aws-sdk/client-dynamodb@3.1153.0) '@smithy/core': 3.36.0 '@smithy/types': 4.19.0 tslib: 2.8.1 @@ -8325,9 +8324,9 @@ snapshots: '@smithy/types': 4.19.0 tslib: 2.8.1 - '@aws-sdk/util-dynamodb@3.996.9(@aws-sdk/client-dynamodb@3.1137.0)': + '@aws-sdk/util-dynamodb@3.996.9(@aws-sdk/client-dynamodb@3.1153.0)': dependencies: - '@aws-sdk/client-dynamodb': 3.1137.0 + '@aws-sdk/client-dynamodb': 3.1153.0 tslib: 2.8.1 '@aws-sdk/xml-builder@3.972.41': @@ -8472,14 +8471,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@azure/msal-common@16.14.1': {} + '@azure/msal-common@16.14.2': {} - '@azure/msal-node@6.0.1': + '@azure/msal-node@7.1.0': dependencies: - '@azure/msal-common': 16.14.1 + '@azure/msal-common': 16.14.2 jsonwebtoken: 9.0.3 - '@azure/storage-blob@12.33.0(supports-color@10.2.2)': + '@azure/storage-blob@12.34.0(supports-color@10.2.2)': dependencies: '@azure/abort-controller': 2.2.0 '@azure/core-auth': 1.11.0(supports-color@10.2.2) @@ -8493,6 +8492,7 @@ snapshots: '@azure/core-xml': 1.6.0 '@azure/logger': 1.4.0(supports-color@10.2.2) '@azure/storage-common': 12.5.0(@azure/core-client@1.11.1(supports-color@10.2.2))(supports-color@10.2.2) + apache-arrow: 21.2.0 events: 3.3.0 tslib: 2.8.1 transitivePeerDependencies: @@ -8986,15 +8986,13 @@ snapshots: ajv-formats: 3.0.1(ajv@8.20.0) fast-uri: 4.2.3 - '@fastify/compress@9.2.0': + '@fastify/compress@9.2.2': dependencies: '@fastify/accept-negotiator': 2.1.1 fastify-plugin: 6.0.0 mime-db: 1.54.0 - minipass: 7.1.3 - readable-stream: 4.8.0 - '@fastify/cors@11.3.0': + '@fastify/cors@11.3.1': dependencies: fastify-plugin: 6.0.0 toad-cache: 3.7.4 @@ -9045,7 +9043,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@google-cloud/firestore@9.2.0(supports-color@10.2.2)': + '@google-cloud/firestore@9.3.1(supports-color@10.2.2)': dependencies: '@google-cloud/firestore-api': 0.2.0(supports-color@10.2.2) '@opentelemetry/api': 1.9.1 @@ -9064,7 +9062,7 @@ snapshots: '@google-cloud/promisify@6.2.0': {} - '@google-cloud/storage@8.2.0(supports-color@10.2.2)': + '@google-cloud/storage@8.4.0(supports-color@10.2.2)': dependencies: '@google-cloud/paginator': 7.2.0 '@google-cloud/projectify': 6.2.0 @@ -9073,15 +9071,14 @@ snapshots: async-retry: 1.3.3 duplexify: 4.1.3 fast-xml-parser: 5.11.2 - gaxios: 6.7.1(supports-color@10.2.2) - google-auth-library: 9.15.1(supports-color@10.2.2) + gaxios: 7.3.1(supports-color@10.2.2) + google-auth-library: 11.3.1(supports-color@10.2.2) html-entities: 2.6.0 mime: 3.0.0 p-limit: 3.1.0 retry-request: 9.1.0 teeny-request: 11.1.1(supports-color@10.2.2) transitivePeerDependencies: - - encoding - supports-color '@gql.tada/cli-utils@1.9.4(@0no-co/graphqlsp@1.17.5(graphql@16.14.2)(typescript@6.0.3))(graphql@16.14.2)(typescript@6.0.3)': @@ -9350,89 +9347,89 @@ snapshots: dependencies: '@octokit/openapi-types': 24.2.0 - '@opentelemetry/api-logs@0.222.0': + '@opentelemetry/api-logs@0.223.0': dependencies: '@opentelemetry/api': 1.9.1 '@opentelemetry/api@1.9.1': {} - '@opentelemetry/core@2.11.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/core@2.12.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 '@opentelemetry/semantic-conventions': 1.43.0 - '@opentelemetry/exporter-logs-otlp-http@0.222.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/exporter-logs-otlp-http@0.223.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/otlp-exporter-base': 0.222.0(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-transformer': 0.222.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-logs': 0.222.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-exporter-base': 0.223.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.223.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-logs': 0.223.0(@opentelemetry/api@1.9.1) - '@opentelemetry/exporter-metrics-otlp-http@0.222.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/exporter-metrics-otlp-http@0.223.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.11.0(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-exporter-base': 0.222.0(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-transformer': 0.222.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.11.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-metrics': 2.11.0(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.12.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-exporter-base': 0.223.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.223.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.12.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-metrics': 2.12.0(@opentelemetry/api@1.9.1) - '@opentelemetry/exporter-prometheus@0.222.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/exporter-prometheus@0.223.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.11.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.11.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-metrics': 2.11.0(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.12.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.12.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-metrics': 2.12.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.43.0 - '@opentelemetry/exporter-trace-otlp-proto@0.222.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/exporter-trace-otlp-proto@0.223.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/otlp-exporter-base': 0.222.0(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-transformer': 0.222.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace': 2.11.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-exporter-base': 0.223.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.223.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace': 2.12.0(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-exporter-base@0.222.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/otlp-exporter-base@0.223.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.11.0(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-transformer': 0.222.0(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.12.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.223.0(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-transformer@0.222.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/otlp-transformer@0.223.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/api-logs': 0.222.0 - '@opentelemetry/core': 2.11.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.11.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-logs': 0.222.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-metrics': 2.11.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace': 2.11.0(@opentelemetry/api@1.9.1) + '@opentelemetry/api-logs': 0.223.0 + '@opentelemetry/core': 2.12.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.12.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-logs': 0.223.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-metrics': 2.12.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace': 2.12.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources@2.11.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/resources@2.12.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.11.0(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.12.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.43.0 - '@opentelemetry/sdk-logs@0.222.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/sdk-logs@0.223.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/api-logs': 0.222.0 - '@opentelemetry/core': 2.11.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.11.0(@opentelemetry/api@1.9.1) + '@opentelemetry/api-logs': 0.223.0 + '@opentelemetry/core': 2.12.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.12.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.43.0 - '@opentelemetry/sdk-metrics@2.11.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/sdk-metrics@2.12.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.11.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.11.0(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.12.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.12.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace@2.11.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/sdk-trace@2.12.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.11.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.11.0(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.12.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.12.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.43.0 '@opentelemetry/semantic-conventions@1.43.0': {} @@ -9664,9 +9661,9 @@ snapshots: '@types/node': 26.6.5 form-data: 4.0.6 - '@types/node@20.19.43': + '@types/node@25.9.9': dependencies: - undici-types: 6.21.0 + undici-types: 7.24.6 '@types/node@26.6.5': dependencies: @@ -9953,11 +9950,11 @@ snapshots: '@xmldom/xmldom@0.8.15': {} - '@zone-eu/mailsplit@5.4.17': + '@zone-eu/mailsplit@5.4.27': dependencies: - libbase64: 1.3.0 - libmime: 5.4.4 - libqp: 2.1.1 + libbase64: 1.4.1 + libmime: 5.5.2 + libqp: 3.0.1 abort-controller@3.0.0: dependencies: @@ -9976,7 +9973,7 @@ snapshots: acorn@8.19.0: {} - adm-zip@0.5.18: {} + adm-zip@0.6.1: {} agent-base@7.1.4: {} @@ -10015,6 +10012,13 @@ snapshots: anynum@1.0.1: {} + apache-arrow@21.2.0: + dependencies: + '@types/node': 25.9.9 + flatbuffers: 25.9.23 + json-with-bigint: 3.5.12 + tslib: 2.8.1 + are-docs-informative@0.1.1: {} argparse@2.0.1: {} @@ -10060,8 +10064,6 @@ snapshots: base64-js@1.5.1: {} - base64id@2.0.0: {} - baseline-browser-mapping@2.11.30: {} before-after-hook@2.2.3: {} @@ -10107,6 +10109,7 @@ snapshots: dependencies: base64-js: 1.5.1 ieee754: 1.2.1 + optional: true builtin-modules@5.4.0: {} @@ -10142,10 +10145,9 @@ snapshots: canonicalize@2.1.0: {} - cassandra-driver@4.9.0: + cassandra-driver@4.10.0: dependencies: - '@types/node': 20.19.43 - adm-zip: 0.5.18 + adm-zip: 0.6.1 long: 5.2.5 chai@6.3.0: {} @@ -10832,7 +10834,9 @@ snapshots: fastify-plugin@6.0.0: {} - fastify@5.12.5: + fastify-plugin@6.0.1: {} + + fastify@5.12.7: dependencies: '@fastify/ajv-compiler': 4.0.7 '@fastify/error': 4.2.1 @@ -10899,6 +10903,8 @@ snapshots: flatted: 3.4.4 hookified: 1.15.1 + flatbuffers@25.9.23: {} + flatted@3.4.4: {} foreground-child@3.3.1: @@ -10927,17 +10933,6 @@ snapshots: functional-red-black-tree@1.0.1: {} - gaxios@6.7.1(supports-color@10.2.2): - dependencies: - extend: 3.0.2 - https-proxy-agent: 7.0.6(supports-color@10.2.2) - is-stream: 2.0.1 - node-fetch: 2.7.0 - uuid: 9.0.1 - transitivePeerDependencies: - - encoding - - supports-color - gaxios@7.1.3(supports-color@10.2.2): dependencies: extend: 3.0.2 @@ -10963,15 +10958,6 @@ snapshots: transitivePeerDependencies: - supports-color - gcp-metadata@6.1.1(supports-color@10.2.2): - dependencies: - gaxios: 6.7.1(supports-color@10.2.2) - google-logging-utils: 0.0.2 - json-bigint: 1.0.0 - transitivePeerDependencies: - - encoding - - supports-color - gcp-metadata@8.1.4(supports-color@10.2.2): dependencies: gaxios: 7.1.3(supports-color@10.2.2) @@ -11082,17 +11068,6 @@ snapshots: transitivePeerDependencies: - supports-color - google-auth-library@11.1.0(supports-color@10.2.2): - dependencies: - base64-js: 1.5.1 - ecdsa-sig-formatter: 1.0.11 - gaxios: 7.3.1(supports-color@10.2.2) - gcp-metadata: 9.2.1(supports-color@10.2.2) - google-logging-utils: 2.1.0 - jws: 4.0.1 - transitivePeerDependencies: - - supports-color - google-auth-library@11.3.1(supports-color@10.2.2): dependencies: base64-js: 1.5.1 @@ -11104,18 +11079,6 @@ snapshots: transitivePeerDependencies: - supports-color - google-auth-library@9.15.1(supports-color@10.2.2): - dependencies: - base64-js: 1.5.1 - ecdsa-sig-formatter: 1.0.11 - gaxios: 6.7.1(supports-color@10.2.2) - gcp-metadata: 6.1.1(supports-color@10.2.2) - gtoken: 7.1.0(supports-color@10.2.2) - jws: 4.0.1 - transitivePeerDependencies: - - encoding - - supports-color - google-gax@5.0.8(supports-color@10.2.2): dependencies: '@grpc/grpc-js': 1.14.6 @@ -11148,8 +11111,6 @@ snapshots: transitivePeerDependencies: - supports-color - google-logging-utils@0.0.2: {} - google-logging-utils@1.1.3: {} google-logging-utils@2.1.0: {} @@ -11165,7 +11126,7 @@ snapshots: transitivePeerDependencies: - supports-color - googleapis@181.0.0(supports-color@10.2.2): + googleapis@186.0.0(supports-color@10.2.2): dependencies: google-auth-library: 11.3.1(supports-color@10.2.2) googleapis-common: 9.3.1(supports-color@10.2.2) @@ -11188,14 +11149,6 @@ snapshots: graphql@16.14.2: {} - gtoken@7.1.0(supports-color@10.2.2): - dependencies: - gaxios: 6.7.1(supports-color@10.2.2) - jws: 4.0.1 - transitivePeerDependencies: - - encoding - - supports-color - gtoken@8.0.0(supports-color@10.2.2): dependencies: gaxios: 7.3.1(supports-color@10.2.2) @@ -11268,7 +11221,8 @@ snapshots: dependencies: reserved-identifiers: 1.2.0 - ieee754@1.2.1: {} + ieee754@1.2.1: + optional: true ignore-by-default@1.0.1: {} @@ -11276,14 +11230,14 @@ snapshots: ignore@7.0.13: {} - imapflow@2.0.5: + imapflow@2.5.8: dependencies: - '@zone-eu/mailsplit': 5.4.17 + '@zone-eu/mailsplit': 5.4.27 encoding-japanese: 2.4.0 iconv-lite: 0.7.3 - libbase64: 1.3.0 - libmime: 5.4.4 - libqp: 2.1.1 + libbase64: 1.4.1 + libmime: 5.5.2 + libqp: 3.0.1 pino: 10.3.1 socks: 2.8.10 @@ -11367,8 +11321,6 @@ snapshots: is-safe-filename@0.1.1: {} - is-stream@2.0.1: {} - is-unsafe@2.0.2: {} isarray@0.0.1: {} @@ -11429,6 +11381,8 @@ snapshots: json-stringify-safe@5.0.1: {} + json-with-bigint@3.5.12: {} + jsonc-parser@3.3.1: {} jsonld@9.0.0: @@ -11487,16 +11441,16 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - libbase64@1.3.0: {} + libbase64@1.4.1: {} - libmime@5.4.4: + libmime@5.5.2: dependencies: encoding-japanese: 2.4.0 iconv-lite: 0.7.3 - libbase64: 1.3.0 - libqp: 2.1.1 + libbase64: 1.4.1 + libqp: 3.0.1 - libqp@2.1.1: {} + libqp@3.0.1: {} light-my-request@6.8.0: dependencies: @@ -11957,7 +11911,7 @@ snapshots: '@types/whatwg-url': 13.0.0 whatwg-url: 14.2.0 - mongodb@7.6.0(socks@2.8.10): + mongodb@7.7.0(socks@2.8.10): dependencies: '@mongodb-js/saslprep': 1.6.1 bson: 7.3.3 @@ -11969,7 +11923,7 @@ snapshots: ms@2.1.3: {} - mysql2@3.24.4(@types/node@26.6.5): + mysql2@3.24.6(@types/node@26.6.5): dependencies: '@types/node': 26.6.5 aws-ssl-profiles: 1.1.2 @@ -12015,7 +11969,7 @@ snapshots: node-releases@2.0.59: {} - nodemailer@10.0.10: {} + nodemailer@10.1.7: {} nodemon@3.1.14: dependencies: @@ -12199,7 +12153,7 @@ snapshots: pluralize@8.0.0: {} - postal-mime@3.0.0: {} + postal-mime@4.0.11: {} postcss@8.5.31: dependencies: @@ -12223,8 +12177,6 @@ snapshots: process-warning@5.1.1: {} - process@0.11.10: {} - proto3-json-serializer@3.0.4: dependencies: protobufjs: 7.6.6 @@ -12317,14 +12269,6 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 - readable-stream@4.8.0: - dependencies: - abort-controller: 3.0.0 - buffer: 6.0.3 - events: 3.3.0 - process: 0.11.10 - string_decoder: 1.3.0 - readdirp@3.6.0: dependencies: picomatch: 2.3.2 @@ -12478,10 +12422,6 @@ snapshots: schema-dts-lib@1.1.0: {} - schema-dts@2.0.0: - dependencies: - schema-dts-lib: 1.1.0 - schema-dts@2.1.0: dependencies: schema-dts-lib: 1.1.0 @@ -12557,7 +12497,7 @@ snapshots: - supports-color - utf-8-validate - socket.io-client@4.8.3(supports-color@10.2.2): + socket.io-client@4.8.4(supports-color@10.2.2): dependencies: '@socket.io/component-emitter': 3.1.2 debug: 4.4.3(supports-color@10.2.2) @@ -12575,10 +12515,9 @@ snapshots: transitivePeerDependencies: - supports-color - socket.io@4.8.3(supports-color@10.2.2): + socket.io@4.8.4(supports-color@10.2.2): dependencies: accepts: 1.3.8 - base64id: 2.0.0 cors: 2.8.6 debug: 4.4.3(supports-color@10.2.2) engine.io: 6.6.11(supports-color@10.2.2) @@ -12851,7 +12790,7 @@ snapshots: undefsafe@2.0.5: {} - undici-types@6.21.0: {} + undici-types@7.24.6: {} undici-types@8.9.0: {} @@ -12917,8 +12856,6 @@ snapshots: util-deprecate@1.0.2: {} - uuid@9.0.1: {} - valibot@1.5.0(typescript@6.0.3): optionalDependencies: typescript: 6.0.3 From 2310a6711797d62abe890b9ee7f969a99158ff27 Mon Sep 17 00:00:00 2001 From: Martyn Janes Date: Fri, 23 Oct 2026 16:01:40 +0800 Subject: [PATCH 17/17] feat: update authorization --- apps/node/.env.example-aws-ec2 | 5 +- apps/node/.env.example-federated-catalogue | 5 +- apps/node/.env.example-iota-testnet | 5 +- apps/node/.env.example-local-entity-storage | 5 +- apps/node/package.json | 4 - docs/architecture/node-env-variables.mdx | 3 +- packages/node-core/package.json | 3 - .../src/builders/engineEnvBuilder.ts | 6 - .../src/models/IEngineEnvironmentVariables.ts | 8 +- .../models/engineEnvironmentVariableKeys.ts | 1 - .../tests/authorizationSeeder.spec.ts | 12 +- .../tests/builders/engineEnvBuilder.spec.ts | 28 +- .../groups/global-admin-unauthorized.json | 2 +- .../groups/identity-profile-self-update.json | 18 +- packages/node-core/tests/facades.spec.ts | 18 +- pnpm-lock.yaml | 1082 ++++++++--------- 16 files changed, 585 insertions(+), 620 deletions(-) diff --git a/apps/node/.env.example-aws-ec2 b/apps/node/.env.example-aws-ec2 index 64907494..63084b7a 100644 --- a/apps/node/.env.example-aws-ec2 +++ b/apps/node/.env.example-aws-ec2 @@ -458,12 +458,9 @@ TWIN_IDENTITY_CONNECTOR="iota" TWIN_IDENTITY_PROFILE_CONNECTOR="entity-storage" ## Comma separated list of public and private profile properties which can only be added, changed or removed -## by callers with one of the admin scopes. Defaults to none. +## by callers with escalated privilege. Defaults to none. # TWIN_IDENTITY_PROFILE_SELF_UPDATE_DENIED_PROPERTIES="" -## Comma separated list of scopes which allow the self update denied properties to be modified, any one is sufficient. -# TWIN_IDENTITY_PROFILE_ADMIN_SCOPES="user-admin,global-admin" - # Immutable Proof ## The assertion method from the identity to use in immutable proof operations diff --git a/apps/node/.env.example-federated-catalogue b/apps/node/.env.example-federated-catalogue index 505694af..e9b7ac16 100644 --- a/apps/node/.env.example-federated-catalogue +++ b/apps/node/.env.example-federated-catalogue @@ -497,12 +497,9 @@ TWIN_IDENTITY_CONNECTOR="entity-storage" TWIN_IDENTITY_PROFILE_CONNECTOR="entity-storage" ## Comma separated list of public and private profile properties which can only be added, changed or removed -## by callers with one of the admin scopes. Defaults to none. +## by callers with escalated privilege. Defaults to none. # TWIN_IDENTITY_PROFILE_SELF_UPDATE_DENIED_PROPERTIES="" -## Comma separated list of scopes which allow the self update denied properties to be modified, any one is sufficient. -# TWIN_IDENTITY_PROFILE_ADMIN_SCOPES="user-admin,global-admin" - # Immutable Proof # Not applicable for a standalone catalogue node. diff --git a/apps/node/.env.example-iota-testnet b/apps/node/.env.example-iota-testnet index 39e6a47e..7c5703a5 100644 --- a/apps/node/.env.example-iota-testnet +++ b/apps/node/.env.example-iota-testnet @@ -458,12 +458,9 @@ TWIN_IDENTITY_CONNECTOR="iota" TWIN_IDENTITY_PROFILE_CONNECTOR="entity-storage" ## Comma separated list of public and private profile properties which can only be added, changed or removed -## by callers with one of the admin scopes. Defaults to none. +## by callers with escalated privilege. Defaults to none. # TWIN_IDENTITY_PROFILE_SELF_UPDATE_DENIED_PROPERTIES="" -## Comma separated list of scopes which allow the self update denied properties to be modified, any one is sufficient. -# TWIN_IDENTITY_PROFILE_ADMIN_SCOPES="user-admin,global-admin" - # Immutable Proof ## The assertion method from the identity to use in immutable proof operations diff --git a/apps/node/.env.example-local-entity-storage b/apps/node/.env.example-local-entity-storage index c06282d9..ce5981fc 100644 --- a/apps/node/.env.example-local-entity-storage +++ b/apps/node/.env.example-local-entity-storage @@ -458,12 +458,9 @@ TWIN_IDENTITY_CONNECTOR="entity-storage" TWIN_IDENTITY_PROFILE_CONNECTOR="entity-storage" ## Comma separated list of public and private profile properties which can only be added, changed or removed -## by callers with one of the admin scopes. Defaults to none. +## by callers with escalated privilege. Defaults to none. # TWIN_IDENTITY_PROFILE_SELF_UPDATE_DENIED_PROPERTIES="" -## Comma separated list of scopes which allow the self update denied properties to be modified, any one is sufficient. -# TWIN_IDENTITY_PROFILE_ADMIN_SCOPES="user-admin,global-admin" - # Immutable Proof ## The assertion method from the identity to use in immutable proof operations diff --git a/apps/node/package.json b/apps/node/package.json index 88c0a8b3..6c9b4d49 100644 --- a/apps/node/package.json +++ b/apps/node/package.json @@ -35,7 +35,6 @@ "@3sixty/node-core": "0.20.0-next.1" }, "devDependencies": { - "@3sixty/entity-storage-connector-memory": "next", "@3sixty/merge-locales": "next", "@3sixty/nameof-transformer": "next", "@3sixty/nameof-vitest-plugin": "next", @@ -44,11 +43,8 @@ "@types/node": "26.6.5", "@vitest/coverage-v8": "5.0.5", "concurrently": "10.0.6", - "copyfiles": "2.4.1", "nodemon": "3.1.14", "rimraf": "6.1.3", - "typedoc": "0.28.20", - "typedoc-plugin-markdown": "4.14.1", "typescript": "6.0.3", "vitest": "5.0.5" }, diff --git a/docs/architecture/node-env-variables.mdx b/docs/architecture/node-env-variables.mdx index 9b38168f..c904204e 100644 --- a/docs/architecture/node-env-variables.mdx +++ b/docs/architecture/node-env-variables.mdx @@ -187,8 +187,7 @@ These variables are only read when running the `bootstrap-dev` CLI command. They | `TWIN_IDENTITY_DID_RESOLUTION_CACHE_MUTEX_TIMEOUT` | Integer ms | Connector default | Mutex timeout for the DID resolution cache. Only used when `TWIN_IDENTITY_CONNECTOR=iota` and caching is enabled. | | `TWIN_IDENTITY_DID_RESOLUTION_RETRIES` | Integer | `10` | Number of times to retry resolving a DID after a write operation (create, update, or delete) to confirm propagation. Only used when `TWIN_IDENTITY_CONNECTOR=iota`. | | `TWIN_IDENTITY_DID_RESOLUTION_RETRY_DELAY` | Integer ms | `500` | Delay between DID resolution retries after a write operation. Only used when `TWIN_IDENTITY_CONNECTOR=iota`. | -| `TWIN_IDENTITY_PROFILE_SELF_UPDATE_DENIED_PROPERTIES` | Comma separated list | None | Public and private profile properties which can only be added, changed or removed by callers with one of the `TWIN_IDENTITY_PROFILE_ADMIN_SCOPES`. | -| `TWIN_IDENTITY_PROFILE_ADMIN_SCOPES` | Comma separated list | `user-admin,global-admin` | Scopes which allow the `TWIN_IDENTITY_PROFILE_SELF_UPDATE_DENIED_PROPERTIES` to be modified, any one is sufficient. | +| `TWIN_IDENTITY_PROFILE_SELF_UPDATE_DENIED_PROPERTIES` | Comma separated list | None | Public and private profile properties which can only be added, changed or removed by callers with escalated privilege. | | `TWIN_IMMUTABLE_PROOF_VERIFICATION_METHOD_ID` | Method id string | `immutable-proof-assertion` | Default injected by node defaults. | | `TWIN_IMMUTABLE_PROOF_TASK_RETRY_COUNT` | Integer | `5` | Number of times to retry a proof task before abandoning it. Set to `0` to disable retries. | | `TWIN_IMMUTABLE_PROOF_TASK_RETRY_INTERVAL` | Integer seconds | `5` | Interval in seconds between proof task retries. | diff --git a/packages/node-core/package.json b/packages/node-core/package.json index 709a34d5..2c24499c 100644 --- a/packages/node-core/package.json +++ b/packages/node-core/package.json @@ -59,7 +59,6 @@ "@3sixty/nameof": "next", "@3sixty/rights-management-pap-service": "next", "@3sixty/standards-w3c-did": "next", - "@3sixty/standards-w3c-odrl": "next", "@3sixty/telemetry-connector-opentelemetry": "next", "@3sixty/tracing-connector-opentelemetry": "next", "@3sixty/tracing-facades": "next", @@ -82,12 +81,10 @@ "@3sixty/rights-management-models": "next", "@3sixty/telemetry-models": "next", "@3sixty/trust-models": "next", - "@3sixty/ts-to-openapi": "next", "@3sixty/validate-locales": "next", "@types/node": "26.6.5", "@vitest/coverage-v8": "5.0.5", "concurrently": "10.0.6", - "copyfiles": "2.4.1", "nodemon": "3.1.14", "rimraf": "6.1.3", "typedoc": "0.28.20", diff --git a/packages/node-core/src/builders/engineEnvBuilder.ts b/packages/node-core/src/builders/engineEnvBuilder.ts index 042d67ed..b7348a84 100644 --- a/packages/node-core/src/builders/engineEnvBuilder.ts +++ b/packages/node-core/src/builders/engineEnvBuilder.ts @@ -1849,12 +1849,6 @@ async function configureIdentityProfile( "identityProfileSelfUpdateDeniedProperties", undefined, undefined - ), - adminScopes: EnvHelper.envListToArray( - envVars, - "identityProfileAdminScopes", - undefined, - undefined ) } } diff --git a/packages/node-core/src/models/IEngineEnvironmentVariables.ts b/packages/node-core/src/models/IEngineEnvironmentVariables.ts index 39cb8add..4d935e9f 100644 --- a/packages/node-core/src/models/IEngineEnvironmentVariables.ts +++ b/packages/node-core/src/models/IEngineEnvironmentVariables.ts @@ -987,16 +987,10 @@ export interface IEngineEnvironmentVariables { /** * Comma separated list of public and private profile properties which can only be added, changed - * or removed by callers with an admin scope. Defaults to none. + * or removed by callers with escalated privilege. Defaults to none. */ identityProfileSelfUpdateDeniedProperties?: string; - /** - * Comma separated list of scopes which allow the self update denied profile properties to be - * modified, any one is sufficient. Defaults to user-admin, global-admin. - */ - identityProfileAdminScopes?: string; - /** * The identity verification method id to use with immutable proofs. */ diff --git a/packages/node-core/src/models/engineEnvironmentVariableKeys.ts b/packages/node-core/src/models/engineEnvironmentVariableKeys.ts index bb2bc3fa..a87bd2e6 100644 --- a/packages/node-core/src/models/engineEnvironmentVariableKeys.ts +++ b/packages/node-core/src/models/engineEnvironmentVariableKeys.ts @@ -213,7 +213,6 @@ const engineEnvironmentVariableKeysInternal: { identityResolverConnector: true, identityProfileConnector: true, identityProfileSelfUpdateDeniedProperties: true, - identityProfileAdminScopes: true, universalResolverEndpoint: true, // IOTA iotaFaucetEndpoint: true, diff --git a/packages/node-core/tests/authorizationSeeder.spec.ts b/packages/node-core/tests/authorizationSeeder.spec.ts index fea4c5cb..5b1ac21b 100644 --- a/packages/node-core/tests/authorizationSeeder.spec.ts +++ b/packages/node-core/tests/authorizationSeeder.spec.ts @@ -25,7 +25,11 @@ import { } from "../src/defaults.js"; import type { INodeEngineState } from "../src/models/INodeEngineState.js"; import type { INodeOptions } from "../src/models/INodeOptions.js"; -import { buildConfiguration } from "../src/node.js"; +import { + buildConfiguration, + loadEnvironmentVariables, + processEnvironmentVariables +} from "../src/node.js"; import { start } from "../src/start.js"; import { initialiseLocales } from "../src/utils.js"; @@ -60,7 +64,11 @@ describe("seedAuthorizationDefaults", () => { nodeOrganizationId: TEST_NODE_ORG_ID }) }; - const { nodeEngineConfig, nodeEnvVars } = await buildConfiguration(envVars, nodeOptions, { + const nodeEnvVars = await processEnvironmentVariables( + loadEnvironmentVariables(envVars, nodeOptions), + nodeOptions + ); + const { nodeEngineConfig } = await buildConfiguration(nodeEnvVars, nodeOptions, { name: "test", version: "0.0.0" }); diff --git a/packages/node-core/tests/builders/engineEnvBuilder.spec.ts b/packages/node-core/tests/builders/engineEnvBuilder.spec.ts index 4bd9977e..24e61a5c 100644 --- a/packages/node-core/tests/builders/engineEnvBuilder.spec.ts +++ b/packages/node-core/tests/builders/engineEnvBuilder.spec.ts @@ -35,10 +35,23 @@ import { TrustVerifierComponentType } from "@3sixty/engine-types"; import { LogLevel } from "@3sixty/logging-models"; -import { buildEngineConfiguration } from "../../src/builders/engineEnvBuilder.js"; +import { buildEngineConfiguration as buildEngineConfigurationBase } from "../../src/builders/engineEnvBuilder.js"; import { DEFAULT_HEALTH_EXCLUDE_CLONE_COMPONENTS } from "../../src/defaults.js"; import type { IEngineEnvironmentVariables } from "../../src/models/IEngineEnvironmentVariables.js"; +const AUTH = { authorizationConnector: AuthorizationConnectorType.EntityStorage } as const; + +/** + * Builds the engine configuration with the required authorization connector set. + * @param envVars The environment variables. + * @returns The engine configuration. + */ +async function buildEngineConfiguration( + envVars: IEngineEnvironmentVariables +): ReturnType { + return buildEngineConfigurationBase({ ...AUTH, ...envVars }); +} + describe("buildEngineConfiguration - silent", () => { test("log level is left unset when silent is not enabled", async () => { const config = await buildEngineConfiguration({}); @@ -175,8 +188,6 @@ describe("buildEngineConfiguration - disableColor", () => { }); }); -const AUTH = { authorizationConnector: AuthorizationConnectorType.EntityStorage } as const; - describe("buildEngineConfiguration - schemaMigrationEnabled", () => { test("schema migration service is registered when schemaMigrationEnabled is unset (default true)", async () => { const config = await buildEngineConfiguration({ ...AUTH }); @@ -1408,24 +1419,21 @@ describe("buildEngineConfiguration - identity profile", () => { expect(identityProfileConfig(config)).toEqual({ authorizationModelId: "system", escalatedPrivilegeRole: "global-admin", - selfUpdateDeniedProperties: undefined, - adminScopes: undefined + selfUpdateDeniedProperties: undefined }); }); - test("uses the authorization model, self update denied properties and admin scopes from the env vars", async () => { + test("uses the authorization model and self update denied properties from the env vars", async () => { const config = await buildEngineConfiguration({ identityProfileConnector: IdentityProfileConnectorType.EntityStorage, authorizationModelId: "custom", - identityProfileSelfUpdateDeniedProperties: "email, jobTitle", - identityProfileAdminScopes: "profile-admin" + identityProfileSelfUpdateDeniedProperties: "email, jobTitle" }); expect(identityProfileConfig(config)).toEqual({ authorizationModelId: "custom", escalatedPrivilegeRole: "global-admin", - selfUpdateDeniedProperties: ["email", "jobTitle"], - adminScopes: ["profile-admin"] + selfUpdateDeniedProperties: ["email", "jobTitle"] }); }); diff --git a/packages/node-core/tests/endpoints/groups/global-admin-unauthorized.json b/packages/node-core/tests/endpoints/groups/global-admin-unauthorized.json index 334c996f..ce057d4e 100644 --- a/packages/node-core/tests/endpoints/groups/global-admin-unauthorized.json +++ b/packages/node-core/tests/endpoints/groups/global-admin-unauthorized.json @@ -41,7 +41,7 @@ "description": "GET /authentication/admin/users/:email - rejected for user-only role", "method": "GET", "path": "/authentication/admin/users/{{adminEmail}}", - "expectedStatus": 401 + "expectedStatus": 403 }, { "description": "POST /aig?override-tenant - rejected without global-admin role", diff --git a/packages/node-core/tests/endpoints/groups/identity-profile-self-update.json b/packages/node-core/tests/endpoints/groups/identity-profile-self-update.json index 6da31a63..1e1d78e2 100644 --- a/packages/node-core/tests/endpoints/groups/identity-profile-self-update.json +++ b/packages/node-core/tests/endpoints/groups/identity-profile-self-update.json @@ -10,18 +10,24 @@ "capture": { "profileUserDid": "body.id" } }, { - "description": "POST /authentication/admin/users - create profile test user without admin scope", + "description": "POST /authentication/admin/users - create profile test user without escalated privilege", "method": "POST", "path": "/authentication/admin/users", "body": { "email": "profile-user@node", "password": "Profile@Node12345!", "userIdentity": "{{profileUserDid}}", - "organizationIdentity": "{{adminOrgIdentity}}", - "scope": ["read-only"] + "organizationIdentity": "{{adminOrgIdentity}}" }, "expectedStatus": 201 }, + { + "description": "POST /authorization/system/subject/:subject/role - assign user role", + "method": "POST", + "path": "/authorization/system/subject/{{profileUserDid}}/role", + "body": { "role": "user" }, + "expectedStatus": 204 + }, { "description": "POST /authentication/login - login as profile test user", "method": "POST", @@ -32,7 +38,7 @@ "capture": { "authToken": "cookie:access_token" } }, { - "description": "POST /identity/profile - 401 setting denied property without admin scope", + "description": "POST /identity/profile - 401 setting denied property without escalated privilege", "method": "POST", "path": "/identity/profile", "body": { @@ -59,7 +65,7 @@ "expectedStatus": 204 }, { - "description": "PUT /identity/profile - 401 adding denied property without admin scope", + "description": "PUT /identity/profile - 401 adding denied property without escalated privilege", "method": "PUT", "path": "/identity/profile", "body": { @@ -105,7 +111,7 @@ "capture": { "authToken": "cookie:access_token" } }, { - "description": "PUT /identity/profile - 401 changing denied property without admin scope", + "description": "PUT /identity/profile - 401 changing denied property without escalated privilege", "method": "PUT", "path": "/identity/profile", "body": { diff --git a/packages/node-core/tests/facades.spec.ts b/packages/node-core/tests/facades.spec.ts index 678a3d5c..59209cb5 100644 --- a/packages/node-core/tests/facades.spec.ts +++ b/packages/node-core/tests/facades.spec.ts @@ -5,6 +5,7 @@ import { ComponentFactory, Factory } from "@3sixty/core"; import { MemoryStateStorage } from "@3sixty/engine-core"; import { EngineCloneMode } from "@3sixty/engine-models"; import { + AuthorizationConnectorType, EntityStorageConnectorType, FacadeType, TracingComponentType, @@ -13,12 +14,13 @@ import { import { TracingFacade, TracingFacadeAttributes } from "@3sixty/tracing-facades"; import { type ISpan, SpanStatus, TracingConnectorFactory } from "@3sixty/tracing-models"; import { CI_ENV_VARS, getFreePort } from "./setupTestEnv.js"; -import { buildEngineConfiguration } from "../src/builders/engineEnvBuilder.js"; +import { buildEngineConfiguration as buildEngineConfigurationBase } from "../src/builders/engineEnvBuilder.js"; import { DEFAULT_TRACING_FACADE_COMPONENT_EXCLUDE_TYPES, DEFAULT_TRACING_FACADE_FACTORIES, TRACING_FACADE_NAME } from "../src/defaults.js"; +import type { IEngineEnvironmentVariables } from "../src/models/IEngineEnvironmentVariables.js"; import { run } from "../src/node.js"; const TEST_NODE_ID = "did:iota:testnet:0x1234"; @@ -27,6 +29,20 @@ const TEST_ORG_ID = const CHILD_SERVICE = "child-service"; const PARENT_SERVICE = "parent-service"; +/** + * Builds the engine configuration with the required authorization connector set. + * @param envVars The environment variables. + * @returns The engine configuration. + */ +async function buildEngineConfiguration( + envVars: IEngineEnvironmentVariables +): ReturnType { + return buildEngineConfigurationBase({ + authorizationConnector: AuthorizationConnectorType.EntityStorage, + ...envVars + }); +} + describe("buildEngineConfiguration - tracing facades", () => { test("activates the facade on the default factories when the tracing facade is requested", async () => { const config = await buildEngineConfiguration({ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f810b50e..9e678f84 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -245,9 +245,6 @@ importers: specifier: 0.20.0-next.1 version: link:../../packages/node-core devDependencies: - '@3sixty/entity-storage-connector-memory': - specifier: next - version: 0.20.0-next.1 '@3sixty/merge-locales': specifier: next version: 0.20.0-next.2 @@ -272,21 +269,12 @@ importers: concurrently: specifier: 10.0.6 version: 10.0.6 - copyfiles: - specifier: 2.4.1 - version: 2.4.1 nodemon: specifier: 3.1.14 version: 3.1.14 rimraf: specifier: 6.1.3 version: 6.1.3 - typedoc: - specifier: 0.28.20 - version: 0.28.20(typescript@6.0.3) - typedoc-plugin-markdown: - specifier: 4.14.1 - version: 4.14.1(typedoc@0.28.20(typescript@6.0.3)) typescript: specifier: 6.0.3 version: 6.0.3 @@ -310,7 +298,7 @@ importers: version: 0.20.0-next.1 '@3sixty/auditable-item-graph-service': specifier: next - version: 0.20.0-next.0 + version: 0.20.0-next.1 '@3sixty/authorization-models': specifier: next version: 0.20.0-next.1 @@ -340,22 +328,22 @@ importers: version: 0.20.0-next.1(typescript@6.0.3) '@3sixty/engine': specifier: next - version: 0.20.0-next.1(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(buffer@6.0.3)(socks@2.8.10)(supports-color@10.2.2)(typescript@6.0.3) + version: 0.20.0-next.2(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(buffer@6.0.3)(socks@2.8.10)(supports-color@10.2.2)(typescript@6.0.3) '@3sixty/engine-core': specifier: next - version: 0.20.0-next.1 + version: 0.20.0-next.2 '@3sixty/engine-models': specifier: next - version: 0.20.0-next.1 + version: 0.20.0-next.2 '@3sixty/engine-server': specifier: next - version: 0.20.0-next.1(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(buffer@6.0.3)(socks@2.8.10)(supports-color@10.2.2)(typescript@6.0.3) + version: 0.20.0-next.2(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(buffer@6.0.3)(socks@2.8.10)(supports-color@10.2.2)(typescript@6.0.3) '@3sixty/engine-server-types': specifier: next - version: 0.20.0-next.1(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(buffer@6.0.3)(socks@2.8.10)(supports-color@10.2.2)(typescript@6.0.3) + version: 0.20.0-next.2(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(buffer@6.0.3)(socks@2.8.10)(supports-color@10.2.2)(typescript@6.0.3) '@3sixty/engine-types': specifier: next - version: 0.20.0-next.1(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(buffer@6.0.3)(socks@2.8.10)(supports-color@10.2.2)(typescript@6.0.3) + version: 0.20.0-next.2(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(buffer@6.0.3)(socks@2.8.10)(supports-color@10.2.2)(typescript@6.0.3) '@3sixty/entity': specifier: next version: 0.20.0-next.2 @@ -364,10 +352,10 @@ importers: version: 0.20.0-next.1 '@3sixty/identity-connector-entity-storage': specifier: next - version: 0.20.0-next.0 + version: 0.20.0-next.1 '@3sixty/identity-models': specifier: next - version: 0.20.0-next.0 + version: 0.20.0-next.1 '@3sixty/logging-connector-opentelemetry': specifier: next version: 0.20.0-next.1(@opentelemetry/api@1.9.1) @@ -382,13 +370,10 @@ importers: version: 0.20.0-next.2 '@3sixty/rights-management-pap-service': specifier: next - version: 0.20.0-next.0 + version: 0.20.0-next.1 '@3sixty/standards-w3c-did': specifier: next version: 0.20.0-next.2 - '@3sixty/standards-w3c-odrl': - specifier: next - version: 0.20.0-next.2 '@3sixty/telemetry-connector-opentelemetry': specifier: next version: 0.20.0-next.1 @@ -425,13 +410,13 @@ importers: version: 0.20.0-next.1 '@3sixty/dataspace-models': specifier: next - version: 0.20.0-next.0 + version: 0.20.0-next.1 '@3sixty/entity-storage-connector-memory': specifier: next version: 0.20.0-next.1 '@3sixty/federated-catalogue-models': specifier: next - version: 0.20.0-next.0 + version: 0.20.0-next.1 '@3sixty/merge-locales': specifier: next version: 0.20.0-next.2 @@ -443,16 +428,13 @@ importers: version: 0.20.0-next.2(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(@vitest/coverage-v8@5.0.5)(vite@8.3.4(@types/node@26.6.5)(jiti@2.7.0)) '@3sixty/rights-management-models': specifier: next - version: 0.20.0-next.0 + version: 0.20.0-next.1 '@3sixty/telemetry-models': specifier: next version: 0.20.0-next.1 '@3sixty/trust-models': specifier: next - version: 0.20.0-next.0 - '@3sixty/ts-to-openapi': - specifier: next - version: 0.20.0-next.4 + version: 0.20.0-next.1 '@3sixty/validate-locales': specifier: next version: 0.20.0-next.2 @@ -465,9 +447,6 @@ importers: concurrently: specifier: 10.0.6 version: 10.0.6 - copyfiles: - specifier: 2.4.1 - version: 2.4.1 nodemon: specifier: 3.1.14 version: 3.1.14 @@ -519,6 +498,10 @@ packages: resolution: {integrity: sha512-KbzkoxveWHguZufLUPD6DnosHxqVQQvR4nPCzKZ8bey4oWPeJmviDvso3KXjYRk0pb2BtP8N1eTl9XgTuibB2Q==} engines: {node: '>=24.0.0'} + '@3sixty/api-auth-service@0.20.0-next.1': + resolution: {integrity: sha512-N24mw0iX47OnP9oE+YWefP6u/6qQy+/MNYdBkColqI1mvGACjpI0xT2/bpso5ZC//+9mXlpKHwEzj72MUvyRCg==} + engines: {node: '>=24.0.0'} + '@3sixty/api-core-server@0.20.0-next.1': resolution: {integrity: sha512-WfiTBDTLcuKo81MRzRxHDpo3v9euRvltJVA7lXT80mDpIbu1BBl55whSRsma/dcQ9JjqU3Jr5Q4b9uaRwCoWNQ==} engines: {node: '>=24.0.0'} @@ -543,6 +526,14 @@ packages: resolution: {integrity: sha512-y1D5Mr8odZHvikxRjst0upGuXMb+dow5dB6FfUgwJ2hiBzEGOedIkz4lsc+mr1p/bWGyIH8WHWMNlT8l28v7hA==} engines: {node: '>=24.0.0'} + '@3sixty/api-server-hono@0.20.0-next.1': + resolution: {integrity: sha512-IrpAdHZjx3pDNxUVu7k/SoxGc06DKICwF4Ko+Ouy4NTz14Wgyl8gmm0zMuTg1Kk5wQ7O2giDz3lxfjz4asq08w==} + engines: {node: '>=24.0.0'} + + '@3sixty/api-server-native@0.20.0-next.1': + resolution: {integrity: sha512-qo5g+eyXMSULCdkvPDC/tamE+Sb7LtoOCLFF/y3b1JsxgywJ/VTd0OHRJghU0K3WP/IEAAWQ/PpXJUPcQhD11w==} + engines: {node: '>=24.0.0'} + '@3sixty/api-service@0.20.0-next.1': resolution: {integrity: sha512-trp2PbbfaPRkiE8/nLtS+tWGiu7lxzsCc19YSz3PARAzpwGLMy1gDFtGVz5O4qJbpY0kNv1+ujPUD+dkuXWuiQ==} engines: {node: '>=24.0.0'} @@ -551,50 +542,66 @@ packages: resolution: {integrity: sha512-KKFguJ2wC6o1BOkuIoKbBwMck2D2T/Xil61gi++CFtMdcSS2tMbkvYpGYkngrpSwwnaGwtihAJ+UDO7DbjYSyA==} engines: {node: '>=24.0.0'} - '@3sixty/attestation-connector-nft@0.20.0-next.0': - resolution: {integrity: sha512-fR2uOECGAOpHStw4Z5+5VNQ5NUSdk4zNDtDP5u7aUlcInmWk4sM+IZ1P9soQC1UGCg2PF7+O75OM3Cyw3fvVwQ==} + '@3sixty/attestation-connector-nft@0.20.0-next.1': + resolution: {integrity: sha512-aPhByDgQ8yJXiNWk2Yr32NzNxIAtseSMpSHTsaA0ufUFcN9FNe/PWODxFpv2IOPNd2hRfDeecltYC2hwAZ/7gw==} + engines: {node: '>=24.0.0'} + + '@3sixty/attestation-models@0.20.0-next.1': + resolution: {integrity: sha512-FHH6RBuzuw9/bf2WXo14/NaXK+4SixNCubGdc261E6CNJEv8twoPvG7LIdO91rUyHUkQxk75qJ+dz8ubyvRysA==} engines: {node: '>=24.0.0'} - '@3sixty/attestation-models@0.20.0-next.0': - resolution: {integrity: sha512-30A7QHitq9VVvhHwnHYwwG3ozoGVleOFvua/i2GGssP6fJZK8Dmb1CvH9mrCyiONyVZ1RudzCLG+31cz9UseFg==} + '@3sixty/attestation-rest-client@0.20.0-next.1': + resolution: {integrity: sha512-Nw1d+LYNvAObZRkZx9JDMPdQXRoeSoBuc71xaohw5cevBqXooEtAY0xiBXSZL7X2IJyhZFGuL7YGShFIBGwxeg==} engines: {node: '>=24.0.0'} - '@3sixty/attestation-rest-client@0.20.0-next.0': - resolution: {integrity: sha512-u2moDen0aXM/tvgEC1Kcow0dZ9rsi4gDHvKFVtpi4xa4zNSJoxYv2msPKaElVrvCM5F80uei6gfTI6mFa3Q7iA==} + '@3sixty/attestation-service@0.20.0-next.1': + resolution: {integrity: sha512-HtFQYjjUOpGAwNwO2yCxegQQCDRoWEt+UD4/w5deT2dab/JfkjLfkn0ACVfRU/j5c5eznZcUlQG1G8rxG/oFww==} engines: {node: '>=24.0.0'} - '@3sixty/attestation-service@0.20.0-next.0': - resolution: {integrity: sha512-1UVHLp7D16CxJYGyPy/OCmnLoEPbiPOqM32updugs5TYt2ax5C2/3ZZ52RUoYLXuzsNUwNyISiNGvN3Tf2eO+g==} + '@3sixty/auditable-item-graph-models@0.20.0-next.1': + resolution: {integrity: sha512-U2ab/QU+XBAg84NiONIBgMXC+COXYsn/VqHtTS3yFf6uU1hX49jiqWw2lH3gRlr/KGseaQ0l5Bo3/K9/s1xcaQ==} engines: {node: '>=24.0.0'} - '@3sixty/auditable-item-graph-models@0.20.0-next.0': - resolution: {integrity: sha512-+48s2UgzTUgweaUcb5CWj29lZ23gPPb+CLSu8oq8s/HAecFdEXoSOSavYbwuNn62pt7p2Lrh6nQSzZ8K8TdBlA==} + '@3sixty/auditable-item-graph-rest-client@0.20.0-next.1': + resolution: {integrity: sha512-0q89KbrTZfpzHe0sURwbRH109mTV59HdcNZpplQkK8OAoDb0DMEhxeqFiuAUu2Y7/96uaHbrMwgOMa1YDNcHDw==} engines: {node: '>=24.0.0'} - '@3sixty/auditable-item-graph-rest-client@0.20.0-next.0': - resolution: {integrity: sha512-z1IFlQjBESpChF0MvuOVFE3NtDVqicUM3wCDtIvhVRxdWGTkngamLjYLka2JQ+TMaX6vBZLv9MMvImC/VMZA1Q==} + '@3sixty/auditable-item-graph-service@0.20.0-next.1': + resolution: {integrity: sha512-bJM2vyKEfT/l0zWx7walKAlwoTdGE//vwUwKB7Uj0pSUtRNbz7+1hIn0pmCIboXcFI7fYmK5tpmGS5Ve7W7GUw==} engines: {node: '>=24.0.0'} - '@3sixty/auditable-item-graph-service@0.20.0-next.0': - resolution: {integrity: sha512-AcXVhg2dYIZzKy8WQj4kojyFrqwO0mZGryuwDSpZgncalBG/nHWqRDjSleRqde06ONfVDulmqnWkQXsPKAaX8g==} + '@3sixty/auditable-item-stream-models@0.20.0-next.1': + resolution: {integrity: sha512-b5/RJUJDnLNzjQvoBmitar3Z8cJtHAbFcUVZke+BT8TKRYtVU+gdTFyUnba7fxzO/o/40vCPm69PTW/7YPXc2Q==} engines: {node: '>=24.0.0'} - '@3sixty/auditable-item-stream-models@0.20.0-next.0': - resolution: {integrity: sha512-eBUeq0+e3J4zm8635ok8pGHyXzXleaHVoyv+oGYlFGrbJJa2RtLxi4aLAi1RG2x9Vva07Xk2Y9Aj4tq7SHj7kw==} + '@3sixty/auditable-item-stream-rest-client@0.20.0-next.1': + resolution: {integrity: sha512-DoVaDjERYUtkHhP1DDWU8z5wLVByYn2WEsN+bomAhAS//FikWfw5kZ+oQ4DSknDk53zODzicx5qtcSf5YdS76A==} engines: {node: '>=24.0.0'} - '@3sixty/auditable-item-stream-rest-client@0.20.0-next.0': - resolution: {integrity: sha512-XlTUkHUuoM+yqY7kFUxtB74eVPy/K5RDrKupUV9nWlXYQWXpdM8DE1SQXcKMQT2aedZfcsGVMrw773JW3UFzaA==} + '@3sixty/auditable-item-stream-service@0.20.0-next.1': + resolution: {integrity: sha512-HAoS4htMLiYAoExz9rAwt+0KcxLKMHyWvJNLN3lR1uDAPKPMbjc3pv0UqnH0cOMgoV3SFaA07HNMYio1uPdvhg==} engines: {node: '>=24.0.0'} - '@3sixty/auditable-item-stream-service@0.20.0-next.0': - resolution: {integrity: sha512-pfAb97XXrn7TVFuf5DKo7cPrbucfNxIGpk5TKml8oCOU3p0FkpCSWOZ3tqZP6rTSebuATRkYW6Ul6hZeGJfiWg==} + '@3sixty/authorization-connector-casbin@0.20.0-next.1': + resolution: {integrity: sha512-urV9NcO6XJ3GgJM1qzAJg955yppVqj7/hgQWVEDmgOQP1aaI0FgKnXgXTOLUp0f8dORuAKsZxW+6wq/cGxUWYg==} + engines: {node: '>=24.0.0'} + + '@3sixty/authorization-connector-entity-storage@0.20.0-next.1': + resolution: {integrity: sha512-/rg8zGbzkZJu12c5Klg+Uq33LTCcixFQ+nhsa8Z1IZ1ntvXjIjGbWQEoyiyq0/RRCB5TLOUcXId7cUBi1tJhGQ==} engines: {node: '>=24.0.0'} '@3sixty/authorization-models@0.20.0-next.1': resolution: {integrity: sha512-t8MsVzRm6AmlNUtENJLym7bW0zR8dwqZ920gErKRFGknbNH4eoh5fmxLH+4zA1EOmgohn//xSKP8UR9uxdRHNA==} engines: {node: '>=24.0.0'} + '@3sixty/authorization-rest-client@0.20.0-next.1': + resolution: {integrity: sha512-vZcGORo0PGVlpeDvc7dKN5LuCj1F41FsL62hZiWCuTL4dQZC9vpbm3kedu72tgsoefAJVDI9uwAce+vn1tdyIQ==} + engines: {node: '>=24.0.0'} + + '@3sixty/authorization-service@0.20.0-next.1': + resolution: {integrity: sha512-zjyQS4l16ZG+X2B/pxpvTtKNAdjp4c58rcV970t6plVIaYKxa6H0gKd3B0oMSOZQ8GY1tnp6XbxUlrcsaPBbmw==} + engines: {node: '>=24.0.0'} + '@3sixty/automation-actions@0.20.0-next.1': resolution: {integrity: sha512-1kRe8G+3LgHZiHFMdc4BpIADkF3pYAgdgD0StggcYtBUQ1wGY9ElNBNEVTkM0rx4dGFAw8BwtOBMVlaHmR07Jg==} engines: {node: '>=24.0.0'} @@ -707,32 +714,32 @@ packages: resolution: {integrity: sha512-VTWTTimL5q7Sd/VLuaaQss0lLkV4PwBaWDFR2reOQG+SNjFmVZnqGb7fSnFff13cEPuQlHV0QeAshsLi2Qrhtw==} engines: {node: '>=24.0.0'} - '@3sixty/dataspace-app-runner@0.20.0-next.0': - resolution: {integrity: sha512-WVN8AVCokMEDTsWzTfcR3ZFuBZQkUYm9Zx/XafUsR+Yt/NF/vSQAFUtyxfLDo7fQBedjgNT5n63UooEiQB5v+w==} + '@3sixty/dataspace-app-runner@0.20.0-next.1': + resolution: {integrity: sha512-8392Zb1XVtKqEbERiv1oewKVoJCTSjwpb4g2hHMMU/Tc5rdJsk367lBDv+vUdkbigMhVHJHACJVntIcppkYxog==} engines: {node: '>=24.0.0'} - '@3sixty/dataspace-control-plane-rest-client@0.20.0-next.0': - resolution: {integrity: sha512-VLk5gYeXWq55FIambM9yFhp5sWX8vITvT9wrS/biSbgcYI5Y/yi1O8WAoNJpXqQmQQL7IpH40Y8CrI3FsBEDDg==} + '@3sixty/dataspace-control-plane-rest-client@0.20.0-next.1': + resolution: {integrity: sha512-/xdS0f/1j4sGyJ2jaw9zHIZyenY8fnMjbbYQ6fDIovregqQfDKcxgDXJTbe35INg6mxa8rc6aF9ROigKkMA2Gg==} engines: {node: '>=24.0.0'} - '@3sixty/dataspace-control-plane-service@0.20.0-next.0': - resolution: {integrity: sha512-PlyhGeAj511DNmn4+W3h1+vXO+axA2ZnMXfPmyUbtZUUZel5+KnCSZSHR5/3v5hXlLK86PMqCdpKkf53nu0D9Q==} + '@3sixty/dataspace-control-plane-service@0.20.0-next.1': + resolution: {integrity: sha512-xD6L/xV/5sjBDmVuVC4Ijx07HaiZ4SfknkIp9oPbaDwffAMrG9ummpzakMF6Q3YZ7Tgb2s2Uej2e0aF6KohMfA==} engines: {node: '>=24.0.0'} - '@3sixty/dataspace-data-plane-rest-client@0.20.0-next.0': - resolution: {integrity: sha512-rxDh5kaCWNarg3PEsOemeFErQ+n2aMQkLkfub6ETPj2DFZK8Nf9mmXnlUa9NMuj6extO6WoLUWY05bQJl6y7Bw==} + '@3sixty/dataspace-data-plane-rest-client@0.20.0-next.1': + resolution: {integrity: sha512-UVxBERMXoDm38XRKdsX2OU2uZVNCSh4Mebo6naAwDogiRZIzZUaIq0jdTrampxweyHk2ZJC8+8o92viBvEJFtA==} engines: {node: '>=24.0.0'} - '@3sixty/dataspace-data-plane-service@0.20.0-next.0': - resolution: {integrity: sha512-gXenP3DycMEekMO76YGYvsG5LM96zkjeIdnWRsAII6pkA6unqH+FGQy9cXZHlenEfD6WFA5FgNyXhlRA/p+p2g==} + '@3sixty/dataspace-data-plane-service@0.20.0-next.1': + resolution: {integrity: sha512-HKsqd3d5Gil3tLBpMvUVa1lbd9sHQ24+F3C7D5jLX3bZhd9RCV+TxraUOaog86rh0NusKAuxFBG/cqKzeJ+S/g==} engines: {node: '>=24.0.0'} - '@3sixty/dataspace-data-plane-socket-client@0.20.0-next.0': - resolution: {integrity: sha512-lf+a6fR/PFB5F0x5TALEJjM1t49ZXub/JLNJGNdw6zW/45pnl5ve/eTl3YYkVKAEaQwiGA/QkmlrQMpH5MGr2A==} + '@3sixty/dataspace-data-plane-socket-client@0.20.0-next.1': + resolution: {integrity: sha512-SjoQ5ztadQtYBKWMui+BbDf1+vadp5T9R8h1FnEKxqGX0C3KB7QhfKnZIGeCVAvWQP81xsX3OR2HJ26EcqxOLw==} engines: {node: '>=24.0.0'} - '@3sixty/dataspace-models@0.20.0-next.0': - resolution: {integrity: sha512-okG6GnJvwvFLh4zLu9B1wbYmIoYaE3AaK+wlWfIGiuvBPFACxUkdlAHyhTkwiK1+St5rNzgZDpXocFx/OnjA/Q==} + '@3sixty/dataspace-models@0.20.0-next.1': + resolution: {integrity: sha512-fDQpha2OHzhIXxswC8gcdQ/W/po3qqtUNi5aB2VvbOD/bB9nESvdrm04Pn9fqa6FgqY2M1soAvU4IPHcXJQMgQ==} engines: {node: '>=24.0.0'} '@3sixty/dlt-account@0.20.0-next.1': @@ -743,40 +750,40 @@ packages: resolution: {integrity: sha512-X3GEK1xTuQIYvMoZ7/s9Y1pShb9NLbzy/gwDVgNkdc28rGOKg5iFJnNHXuK4qVBSi1vgsNy+VNwYJI2oiZjSkA==} engines: {node: '>=24.0.0'} - '@3sixty/document-management-models@0.20.0-next.0': - resolution: {integrity: sha512-+VXjBv/NlmEyX3hVKqpdfUQYOLc+eF7dw5sw4vUdTx6MHWjUUmsMVmhRQRZ2BGykEjVFKpOsd+6cM7kWb/SUeA==} + '@3sixty/document-management-models@0.20.0-next.1': + resolution: {integrity: sha512-vABF80laJL41+wnJSrVaukqw+98R0g7gaf/KuKU0W2hrC0PBiXn8nDmiYUsnpvPvsVwWFW0cn8kHad5B9kpVaA==} engines: {node: '>=24.0.0'} - '@3sixty/document-management-rest-client@0.20.0-next.0': - resolution: {integrity: sha512-srfTUlMDrwlT5PyNe6e9itd82iiUVwp4PSI2EmhwY1Wn8AdPcN/wNJHNIAc+N4kAXhq8KFrrTfPV64oCPNlYHg==} + '@3sixty/document-management-rest-client@0.20.0-next.1': + resolution: {integrity: sha512-9YwMJ7zRHlIbi6K74tMAGAhjxtfMcofT2swGdg4TWo5BXhwSuhTSk9sGHhaJFRbEtUchYk3sl4OwnLBqXtqqng==} engines: {node: '>=24.0.0'} - '@3sixty/document-management-service@0.20.0-next.0': - resolution: {integrity: sha512-UkawuqheyDTo1P++/Ey6kF+MdM7hZ3KptyclfPTO2ODPFJRdgfMKblLIiebDfUHI2fIeKu4qZ3NqSz4LmKHtkA==} + '@3sixty/document-management-service@0.20.0-next.1': + resolution: {integrity: sha512-nJzOhYvCYfYlMU3313Q+CfKgYwl2GkRdIIiA3jcDQT5m/wK5Si0ifzG69P+Z/cclCyzPbJ/Q8p2FQUJ/60YKAQ==} engines: {node: '>=24.0.0'} - '@3sixty/engine-core@0.20.0-next.1': - resolution: {integrity: sha512-UHLIbRFDzy36qflG+B5j21tmiPEbT5uXYAtdiB6DZyRzV1oL0DY3alzWblywjFg0l8DevWpLxm8v7sNtWGXwqA==} + '@3sixty/engine-core@0.20.0-next.2': + resolution: {integrity: sha512-2vwei3BdDhBZcBhlsLA6aTUIf5zxSeJyLyy21gfEHSm7+fTju4KDeJ+fk1Jd+lTlgQSDHG9RWssLCryXwluQ5Q==} engines: {node: '>=24.0.0'} - '@3sixty/engine-models@0.20.0-next.1': - resolution: {integrity: sha512-ilR2HwIJ3Jwu+ikNJc/uiVN9PQrm8Ln9ku8bYztt2Ja9OiOzc+vFQRz/9iXPV7UUfH/nMWjxu1O5BrzhOxERiQ==} + '@3sixty/engine-models@0.20.0-next.2': + resolution: {integrity: sha512-Ja1JPEma0/BBA4JX7Eg7IGuO2r7YXnOxRZB6NvthkJ/qpfLhEFbf85qBASUAUnsaHWfOpFPDWH84952W+xq6jA==} engines: {node: '>=24.0.0'} - '@3sixty/engine-server-types@0.20.0-next.1': - resolution: {integrity: sha512-g08dDbuRFcsArtuNHOdLXiV2fJABDVYm8nyg1pMbeaswXT1ARYI2y0wEfaVvfkfVmaGb29UkelzUAEJo67PbUw==} + '@3sixty/engine-server-types@0.20.0-next.2': + resolution: {integrity: sha512-kZkqXIXwApmiJDioVxyEtFHwlOJk6u34SY5hZMQ3JuyKc10BVOPojJmdrdvKUPB2xu9Id9rD+nRqbRPzfQTOKQ==} engines: {node: '>=24.0.0'} - '@3sixty/engine-server@0.20.0-next.1': - resolution: {integrity: sha512-Auzkv28Kq++g0TTfN8uXN8n8Qi8Dd2nviBcR41Y7m6UNpifv/W8MO9c8otraWjn/9SdsAr1ZD97+t7BmyXnM0A==} + '@3sixty/engine-server@0.20.0-next.2': + resolution: {integrity: sha512-BX6Z3FWqwd/ga+fsn0/SCAtisZIQ5X7LiYp9AR2sBEApEsEyFUJyijSFs7rUDk2lDdx2felZrw9dHL09CbVuJw==} engines: {node: '>=24.0.0'} - '@3sixty/engine-types@0.20.0-next.1': - resolution: {integrity: sha512-xNgERFH+zRB4Vtt8/LgOzac9tKFSX88ZP3n+ZJdb/tAMzWlDk0khl6Ow8NUbaOg72udCjmTAXeKvhIxvaUjLQQ==} + '@3sixty/engine-types@0.20.0-next.2': + resolution: {integrity: sha512-RyGaH7oiibUdf1OX/zT7T8UTi+0HhmWRVxjJh5Mr7Nsozc/djgin8hjU5ZKZfjq37seI1ZgrddbOfkEwceroxQ==} engines: {node: '>=24.0.0'} - '@3sixty/engine@0.20.0-next.1': - resolution: {integrity: sha512-g9e9HlOja1qdGdB+evf5lNV93s7GgYfqhAcwJ5eEE+D+BvBEpImVfFbxOzvZibhdddVfs4LC/WU57iA5RROitQ==} + '@3sixty/engine@0.20.0-next.2': + resolution: {integrity: sha512-+QBHiev1E0iJjeyu85J1IqkdK4nhfjsrYsN55FNbZyGYNLYhqrxghAfvzEYs2A6+bQHqHT8r8fckb4ckGfaz8w==} engines: {node: '>=24.0.0'} '@3sixty/entity-storage-connector-cosmosdb@0.20.0-next.1': @@ -847,60 +854,60 @@ packages: resolution: {integrity: sha512-9QTnsDPfoGxg5Q3CzyGO9jvwvyvRfURFhy2GJAfxx01K9fBkchTE08Hh/Cc4ZbcnLxsxJ2771eqZ52m+uu5a2A==} engines: {node: '>=24.0.0'} - '@3sixty/federated-catalogue-filters@0.20.0-next.0': - resolution: {integrity: sha512-AOGie820JbFwI41F3/ljdH03DMTDwcNHPJYeGeeAW+mIlgkmPS/LievzqqxR/waznlAp4C3gEeIPldrf+cwFNA==} + '@3sixty/federated-catalogue-filters@0.20.0-next.1': + resolution: {integrity: sha512-bRxM4uWw/NeN8MzHjhLACTmyeRyWMtEmMrUryzSQKQEBrUdOsYvZhqZF5ViSKfN1GGWrCQkDtb1URIi+sQ57dg==} engines: {node: '>=24.0.0'} - '@3sixty/federated-catalogue-models@0.20.0-next.0': - resolution: {integrity: sha512-bCEUCgswDKc2ZkGt2Unb/qWCe5V4NjbVQurDeBLUr8kfjkqDuprIJlyLaqxRxMEyp2KulZhjCIS18Ybtch+ryg==} + '@3sixty/federated-catalogue-models@0.20.0-next.1': + resolution: {integrity: sha512-7Rt++BZVyw28G/7NLAGXo5gRqyiiYr7KTRDvzvcZxPfQkDY6/UzI+p+0OuZjgth27vCkKQFFb8At/1K2DJcD0A==} engines: {node: '>=24.0.0'} - '@3sixty/federated-catalogue-rest-client@0.20.0-next.0': - resolution: {integrity: sha512-FO1bSNqil2keQnmD0/+c/CwrDwG6yOA8PszdVpeVjS3cHe6GGK6j1OQt9yMMsw31J3LwI5MZ5C0zwLJOqqbrNg==} + '@3sixty/federated-catalogue-rest-client@0.20.0-next.1': + resolution: {integrity: sha512-Ueou3LrjGo/PAQ9ZZT49Da7cHQHoLw5lvQEnBhMBfQTyuXI3VXjYFvSMYgRJz7zvtZGY+oDSk/+d3960/fON5g==} engines: {node: '>=24.0.0'} - '@3sixty/federated-catalogue-service@0.20.0-next.0': - resolution: {integrity: sha512-hr62dFp02cGHZbqbf8ta5YD4OksQOY4S5FQt24EKbqrj4ysnXnswVAufNW158c44RnW1kVxidcD9lJ2bdR7teg==} + '@3sixty/federated-catalogue-service@0.20.0-next.1': + resolution: {integrity: sha512-lYsHcrzMjjI303rjvXCHJWe2xrcbhiS2ibb4M5+li2vDBbOyRwg272jsM4onRXyQ6HCgTqpBj00Nr5uYi5xgxg==} engines: {node: '>=24.0.0'} - '@3sixty/identity-connector-entity-storage@0.20.0-next.0': - resolution: {integrity: sha512-8Fu54gfd6rYpqlBTh51ZpmVz9FicsiUc+OTBz1NdchiI2UjuMQ+rvk1JvSXMmUm1xqyc+tzDx7EkFixDiHD87Q==} + '@3sixty/identity-connector-entity-storage@0.20.0-next.1': + resolution: {integrity: sha512-Sgk1F/uRnh+aPAecxutvN0VtfXjWsELcDbXeNEZGRVzVAm89qtLCwA/592jPcFUjn7OCpy1QgBlSt/KtPoJfdQ==} engines: {node: '>=24.0.0'} - '@3sixty/identity-connector-iota@0.20.0-next.0': - resolution: {integrity: sha512-0i/WzpnKcS8xq2BGXXAhcnke8sPNellHelI7Qk9cMDpkZQbhnuRMyfLLQCOOnmIVL7V/aMvic3uM/6Fc+fPmvQ==} + '@3sixty/identity-connector-iota@0.20.0-next.1': + resolution: {integrity: sha512-iUbtzvuRnPE6qu0T88+ApasCnPSOy35UD72TkuAG0fOiPPywvuTKy8boS5tPMM4teGYL9DFrG6bRU/fkBPXhgA==} engines: {node: '>=24.0.0'} - '@3sixty/identity-connector-universal@0.20.0-next.0': - resolution: {integrity: sha512-pFvPOlipvR1ZgSIjtmzrWHMHiK+VTmC48hbqml3ddglkUOTrYWSE0A7wcGMW5kBJuSgiQaPBsMUbiw6BbPw4QA==} + '@3sixty/identity-connector-universal@0.20.0-next.1': + resolution: {integrity: sha512-GAavUqzJ1Pqh/i1J3V6tFPVJzqQtIP46hyiyQ+am3vei2iPUJ762cI9XqB/4slVPo/GwL1JckzaXEIBQRmzy4Q==} engines: {node: '>=24.0.0'} - '@3sixty/identity-models@0.20.0-next.0': - resolution: {integrity: sha512-+06Wxw1syPT84ywv/9tdzWQ3NF92qP6XUfocVvKsznxGvMGl2coyYFCzzE4flSQYC9HhppBTfGED6vBKiokozQ==} + '@3sixty/identity-models@0.20.0-next.1': + resolution: {integrity: sha512-4aayTHgERVAYvEdCeYSloOEhhoFfGMFoAPQNm/+VPUTxpr6x8My7p+IgKiOLWmdt3TETiyx7MJERXKbhoiYrOg==} engines: {node: '>=24.0.0'} - '@3sixty/identity-rest-client@0.20.0-next.0': - resolution: {integrity: sha512-Fsk9U8H3FkBKrpmQKidyiwSf15T5VOQ7J9fVevw+EMn565KbtjkkD/kqsjFwoa4JzKhkeEcCoeVzO7ORu4CfoA==} + '@3sixty/identity-rest-client@0.20.0-next.1': + resolution: {integrity: sha512-aCgn1SaMEq2PCa7YfudHInNlifMJazmPF8Qohyen3gSpRFtvmbVgRnGhZO/JM3f4DZ/8qYhUjPUs6EbX8FfRaw==} engines: {node: '>=24.0.0'} - '@3sixty/identity-service@0.20.0-next.0': - resolution: {integrity: sha512-Fw/9GaENWYJ5mS4MzP2o5LE1/Iufa633cQVn/kf/ajHqRajs6zrhuUViSkDbTOuGDfmvtGWoiK7NDZXZA3I8EQ==} + '@3sixty/identity-service@0.20.0-next.1': + resolution: {integrity: sha512-0BInEh/OYCdmwnIB2bclj7lUth4H44xZDGFsra9xTjZuW/epZbB+H1V0VS81jrP6lFFiJ0l/WOF5cO/XMmGA/A==} engines: {node: '>=24.0.0'} - '@3sixty/immutable-proof-models@0.20.0-next.0': - resolution: {integrity: sha512-+KxdhhYFO6Rzp7ppDyo6LlwtNJvCRfjy6lkXB6ajJyQeHf/4ZSoQ1/U01x8wc2lkkMpc+bpXojFjN1Ig6/gqLQ==} + '@3sixty/immutable-proof-models@0.20.0-next.1': + resolution: {integrity: sha512-WFwoEasRXY9unFrTu9CzHXWpSgZA6tCgUgAlOVwH8LqF0HlzFi9Nv3Igcvqdf51FXoKLjth6KatdGPGABr8cnA==} engines: {node: '>=24.0.0'} - '@3sixty/immutable-proof-rest-client@0.20.0-next.0': - resolution: {integrity: sha512-kPOm/hK0FjNIYnR8uWXAsDwcgMweQQLk4opGbrjIRQVLNTR15p3VtpOU9k7/zD/tpZVR+T199C5oWx8K9t5l+w==} + '@3sixty/immutable-proof-rest-client@0.20.0-next.1': + resolution: {integrity: sha512-s7lnot7H7TGtK2EXIxKfcC1bKkhDhR2WN0RxbXXSxhJG4tNlf8sP8NrOMX21FV/BAGwq8R2qANk7ljnuk//vdg==} engines: {node: '>=24.0.0'} - '@3sixty/immutable-proof-service@0.20.0-next.0': - resolution: {integrity: sha512-McghwdtYqpA8JpgSgidqx21d9qcLd2Z4ZHkOxZAkJTK8xh0y/JZ9eItnEyAAmgVOJ9O6PACrTVoXpw5f7f+5GA==} + '@3sixty/immutable-proof-service@0.20.0-next.1': + resolution: {integrity: sha512-26SYXFz6vE/Y+bw7xs6d+dDf7h78yzIVfwWZELLgGH+gNeCYU3+JgGrjQm6+GvdWAmZaVfqXdloL4lTLsJspBg==} engines: {node: '>=24.0.0'} - '@3sixty/immutable-proof-task@0.20.0-next.0': - resolution: {integrity: sha512-ktfTt/wBGN2VRRXXs3nyiNcQg6EzBKe0OU6/Uiz9LkKmIeMBhL4Ph72SyxETJrdEXfhv3YKAs6kBWc0PIZz3jA==} + '@3sixty/immutable-proof-task@0.20.0-next.1': + resolution: {integrity: sha512-NZLQYgTISZ1byxtXDpMJXeTSA6X+/ZHboIEHw6Vc/2+LB3+WGmESZHXvDIP3yoK+Hxe8rbo/5k2AdnCvEzExlA==} engines: {node: '>=24.0.0'} '@3sixty/logging-connector-console@0.20.0-next.1': @@ -1005,88 +1012,88 @@ packages: resolution: {integrity: sha512-isPi+GgUWa/B3+gtLbPm3HJ5yaMJrp2uMlzLIkC2aBGQGC2jFmDk5HSmbpJg7mhQf38YomwI6AzC2JaZcL1XWQ==} engines: {node: '>=24.0.0'} - '@3sixty/nft-connector-entity-storage@0.20.0-next.0': - resolution: {integrity: sha512-7lVs7CbpPBYrryK64Co+lD6OHAlYQwQLYsQgWY/ts7QyJZVlmx/BTN/gqLF3ViesYsSx0KjO++MyP9pYiie2xw==} + '@3sixty/nft-connector-entity-storage@0.20.0-next.1': + resolution: {integrity: sha512-wmEuSIIiZIkP7gup1mvDeWK2+i/1bPGXWKKGE3p7acjKW4LOiGcrtcxV6talb8dN3kUxmy/By/85L8E0algQAg==} engines: {node: '>=24.0.0'} - '@3sixty/nft-connector-iota@0.20.0-next.0': - resolution: {integrity: sha512-Ad9/wFeVS4yM8iWfp2FQLD53aD/1ipo0zwRsqXyax91rYJhlxEFCqOucdkj5FMbsgkyzMd++fNJVHyP7y/8xxw==} + '@3sixty/nft-connector-iota@0.20.0-next.1': + resolution: {integrity: sha512-vXoTfykvNwc+BYEs9jFYrKzAwR2Pw6GDX93uI3l6jibgNsfgOKCtNS0fOKLg+m5pqrEEHf5hD72YwhqDACIkDA==} engines: {node: '>=24.0.0'} - '@3sixty/nft-models@0.20.0-next.0': - resolution: {integrity: sha512-NfsJFu+1Ru3za9sDZS30LbwTolecUbu9idvZLsQXU8G+dfuuts90TcoBNP55au5h961TlV/LARVwejXwO8S4sA==} + '@3sixty/nft-models@0.20.0-next.1': + resolution: {integrity: sha512-elDwqXcsnXHZafC7PV3lfVGJzcvfqqAPduBhuGwFwh5KolvYyb7ufKB/3tEZyuPQYFyx59dYujnUrGT4qjShpQ==} engines: {node: '>=24.0.0'} - '@3sixty/nft-rest-client@0.20.0-next.0': - resolution: {integrity: sha512-x2J6JZLm/BvlxewjzrveBfLNdoaNL+BNLPAl6YG723tBWjW617tRtJ9x65Kkh4SkPg5O97RBQ/z1OaoBYz1TiA==} + '@3sixty/nft-rest-client@0.20.0-next.1': + resolution: {integrity: sha512-cLUK95JoyJqGdHfE9jLJp1WYzeB/C3kszwOIzsGb1nm06x5vosK95bJvw2vcod+0K1bpWJ6TrPnQ3bYECsVFVQ==} engines: {node: '>=24.0.0'} - '@3sixty/nft-service@0.20.0-next.0': - resolution: {integrity: sha512-82MMePZoRJ6OmmVfBf+pXOua8a59j0M1/qRWkckQvTJwcYjxTlGumd7kcSQOIbUiEE2WJe86Ghv2xb3NJBG/yA==} + '@3sixty/nft-service@0.20.0-next.1': + resolution: {integrity: sha512-OmsMhdP/wyJSK829Na3pX9yUGSDc3waDjZyIttExpGz0AvUFlcb4hk2yCYJYM0Y6tlT1AM2sEMgLaQ3X+1BhvQ==} engines: {node: '>=24.0.0'} - '@3sixty/notarization-connector-entity-storage@0.20.0-next.0': - resolution: {integrity: sha512-o6gfXI4Q7F5mDJQ7/sGqjrtZW9P4Mfr9oZnAujPLjsd4l03WGCw7ZjH3NXysOko8G8cOuyfs3yt2rp75+c+fFg==} + '@3sixty/notarization-connector-entity-storage@0.20.0-next.1': + resolution: {integrity: sha512-nThE95H8y/hSSrawNElaSLG0DjiSfmQg4JSU5pI5+LqZNI8rV7m/s/shipU1JRLNpZNOar+V7Foud29nNWnOVg==} engines: {node: '>=24.0.0'} - '@3sixty/notarization-connector-iota@0.20.0-next.0': - resolution: {integrity: sha512-TDWR6Q+iDre2h3OZJ+9TYWa0g14zEGfHQFzFiipn//LiGbIDCVKpRN/cV81oLHqWfL5ySwuVeb2YeWMbCtARJw==} + '@3sixty/notarization-connector-iota@0.20.0-next.1': + resolution: {integrity: sha512-HFL5DmU2qNtGjCqKKXr7G88eZviYid1Ie0as2mcmIf4VQuG1xK2KLnQgewgDxXSD8lCH4DlkXD4CUaggG/PRtQ==} engines: {node: '>=24.0.0'} - '@3sixty/notarization-models@0.20.0-next.0': - resolution: {integrity: sha512-KBoJ9CAJgZ7KjyUDF49aVl5KapO1vk4K/YPANLwqpyhSs3ZsIkIe2RjpMRdMSIjEpWrTesHGVDLhzrmIOKjaFQ==} + '@3sixty/notarization-models@0.20.0-next.1': + resolution: {integrity: sha512-hJlsBwmsDrDG0CjF+LgfJG/2wX+mr59pb82ymVM+HNGZzU+g4dU2E+aiqtW3syDVxZAQlJTHVGfnwfG/rXTDtg==} engines: {node: '>=24.0.0'} - '@3sixty/notarization-rest-client@0.20.0-next.0': - resolution: {integrity: sha512-7bUR0XNJvKIO4m9QGzDnq4oxp0Ga1pZuTDveARvtt0xP5nClWBxGKSHZMS0ibe4YigFmvqNijChIcuGceFvaxw==} + '@3sixty/notarization-rest-client@0.20.0-next.1': + resolution: {integrity: sha512-D8llK4wr+rtTiSHV0lkCf4YaxRON8DmkPZdl7lOh11eUzci+AHSqwyp7Narj0ZXFSzqgNjjjnILQf/+tYoiRtg==} engines: {node: '>=24.0.0'} - '@3sixty/notarization-service@0.20.0-next.0': - resolution: {integrity: sha512-1wum0yUBNfJxCkXFUt02yeCiAL8ds+6HmG75ts3l8waj3QLx6HuZb2hMym6R/pC48RZ8Eq93Z8uHWK6usQeymg==} + '@3sixty/notarization-service@0.20.0-next.1': + resolution: {integrity: sha512-RaR9NBZE0b6OgNEOwnLZqILB1EcNeT9SPQx1G2AYcYuLk2bDmPRF01C9V5i9nGYRisdJUToLDO6Ric1ObQLQCQ==} engines: {node: '>=24.0.0'} - '@3sixty/rights-management-models@0.20.0-next.0': - resolution: {integrity: sha512-GaZTsXBLychbb+4U4pEnGTYQihkZ56wT75Wkrccw5bE/vI/xCWgyp9+VK2BRD4E2SVpAuBYYYbFbhVJbmzDPnQ==} + '@3sixty/rights-management-models@0.20.0-next.1': + resolution: {integrity: sha512-Z9N841VQZUHluA3kG0z1eT5d3G9CDUfzNaM0THghQ4jyuFwJ2c20IuVeIJkEhSZi4QdufpOKYFtxnaHCkUE1vg==} engines: {node: '>=24.0.0'} - '@3sixty/rights-management-pap-service@0.20.0-next.0': - resolution: {integrity: sha512-vSfMRVTvwA64RyVowRibAd5vSh8ydWak19Ibqtsuk7+WAZ5moccSKcnTdNyOj7ZUl3B52c9RzWhhGBNa+wpOfg==} + '@3sixty/rights-management-pap-service@0.20.0-next.1': + resolution: {integrity: sha512-rNlt3STjTsSi9GA0JkmP2sTv/8y6RN7cNQM2ZeG0redrnNK3yH2R8xET8L4klauYMpUtu4ujCYBdiBtluAmdBA==} engines: {node: '>=24.0.0'} - '@3sixty/rights-management-pdp-service@0.20.0-next.0': - resolution: {integrity: sha512-rGnq3aHeiKjKx0Rx6vJa+RGJyH9e6Ptu+087DriZ1GqQwYFcPZjDtVgTrFlT+ws0zn+Z+v5PPRdINbS5i0pN/Q==} + '@3sixty/rights-management-pdp-service@0.20.0-next.1': + resolution: {integrity: sha512-TsXZF/eLtuXJA9MGhO7TrClSNoHl18nKxCDkceGKwv48EBUyL3M3oDlG3pC9A4RRazTenRoQsQuKTXGbf7mG3Q==} engines: {node: '>=24.0.0'} - '@3sixty/rights-management-pep-service@0.20.0-next.0': - resolution: {integrity: sha512-FccaAIuC88umHHi8S571eAtVwEvB8Sq19jPGgfnRCnfOYbrXLRCw0YrGytDRmUzVXzHX5oPibl3LUa8Ca9BOdA==} + '@3sixty/rights-management-pep-service@0.20.0-next.1': + resolution: {integrity: sha512-F5yDd6TVbr56JefiCb1Hi7YDNnYSRiA0PMkK4alwPsGvPhBnsLbXpoegtwskmnIUJhvooZwav/zkoRE39qp+ew==} engines: {node: '>=24.0.0'} - '@3sixty/rights-management-pip-service@0.20.0-next.0': - resolution: {integrity: sha512-mtANVsqF8N/PfGBzH44phtJUDKfRdtJ1wBViCxtMS5RCbW3uPjIa4Z1c6lmDP8ILaAYSCHkTJ9tofldANPbTeQ==} + '@3sixty/rights-management-pip-service@0.20.0-next.1': + resolution: {integrity: sha512-HDfk3d1e70dLS/Zq8h2tuPeXQUU1MzHeLNyZ7o6lTrhY4ACCeCRyKnSauKxZiRmp+P+YYCrkZRxmidiKOtLGsQ==} engines: {node: '>=24.0.0'} - '@3sixty/rights-management-plugins@0.20.0-next.0': - resolution: {integrity: sha512-LEGxV27SjrpkBV8zvE+dK7OomCEwso8rAXfaXGWittJh5agWeJSxsqVQTrZub3xkNLAwBlKq/qkBHeeONAgl6Q==} + '@3sixty/rights-management-plugins@0.20.0-next.1': + resolution: {integrity: sha512-BiZ24rmEaGAfStMi7/pM4+DHfVJvK6WLxExyEqBgqL9SwwEKsiZvpsSE9r/QEOdUcFvJT2j9pkx6z+f7XH1/DQ==} engines: {node: '>=24.0.0'} - '@3sixty/rights-management-pmp-service@0.20.0-next.0': - resolution: {integrity: sha512-fVijHdlpsop4jGsFUWtyXYRlPP4KpjiJG4NwLQgZYetPncRDJ/rYyRseYqLBYgUHSETqgVRzPC1kPDgFPMuByw==} + '@3sixty/rights-management-pmp-service@0.20.0-next.1': + resolution: {integrity: sha512-Mql3AdRXfnEyM+QQ6U3o5BucE+sSdpCRttZk3bsfWvAphwOkFsXgoZvK9480u/PvwrjWZr4iaXP2DN+3Hywpqw==} engines: {node: '>=24.0.0'} - '@3sixty/rights-management-pnp-service@0.20.0-next.0': - resolution: {integrity: sha512-pRUWwNlIUVCupklwgmOuHbzpJrQuw/r12TKdomjb0ATad2UVL+ka6/S93Ul28hP/6bDRsVOrGZ3GVvv+4l347Q==} + '@3sixty/rights-management-pnp-service@0.20.0-next.1': + resolution: {integrity: sha512-mDv85Ztd3/XyzWQhslIszd+rRCaCR2mwJGvTdGgE8WrVsL2ImAauGLeNuJekge0wqv3oJW+dP71RwVUCvevGpA==} engines: {node: '>=24.0.0'} - '@3sixty/rights-management-pxp-service@0.20.0-next.0': - resolution: {integrity: sha512-IH3/HYG9TQAz2I5jS/3y0RnNqNJohxeo8F5aJSWwJYgrhNtx4lC5td8mHfxfiM8KQ/ABYKyZUXU/9yLlSMljzA==} + '@3sixty/rights-management-pxp-service@0.20.0-next.1': + resolution: {integrity: sha512-6aX1VDsgYCx2q7XL6fs5o0CPFZCGc5NxFrZMavlQiHFysd7RNI0IFfFnVLfGHVgKbt231G1F/j0KFf0aLV7Sng==} engines: {node: '>=24.0.0'} - '@3sixty/rights-management-rest-client@0.20.0-next.0': - resolution: {integrity: sha512-tomgAfAzlvc/PKemc8TUU0snUSFfvEGxIa1iwfdY6prLHMxhB/9CNkY04eUuR8gxiT4c/z8bxtv1LAvOpkk1zw==} + '@3sixty/rights-management-rest-client@0.20.0-next.1': + resolution: {integrity: sha512-gHNXBwv6syNpkYNxBIZnhq7K2QUYVSayOUQOPUEn0eM95cbmhuKOb+s4qwMBbzGYeAJgVBXJoJNaO1oH3rGU2g==} engines: {node: '>=24.0.0'} - '@3sixty/rights-management-service@0.20.0-next.0': - resolution: {integrity: sha512-TmvamUtd6yI3XiKO2SKRsI5RSwAbonuJiHG36qOoqoZTBHAPjhIF5iLc739OOitKTqYxZ+ano1gD7QyV2aq/DQ==} + '@3sixty/rights-management-service@0.20.0-next.1': + resolution: {integrity: sha512-TAoyt9PooqyXyQMubSYpgJRISHMLPflhv/b3Fxjx+KEM2kPMimp1iGvW2l4PXEhVP+ERzMigsdXS/nwaWS9znw==} engines: {node: '>=24.0.0'} '@3sixty/standards-dataspace-protocol@0.20.0-next.2': @@ -1193,20 +1200,20 @@ packages: resolution: {integrity: sha512-13/bqqort+zFS5MlCIcyNqhp8P2GoWo25vpA2Dm1OyMqMBWFjniBspEgqO+w671A6Ymr77l98UMPYxByqRosfw==} engines: {node: '>=24.0.0'} - '@3sixty/trust-generators@0.20.0-next.0': - resolution: {integrity: sha512-HbkiuSTgrjc3FQL8YL94svHEBIDZNiZZIN2GI2gjw3szHluoY6x5P+OoUC1vUOpJDphPGdrycKQs5EtDklvfsA==} + '@3sixty/trust-generators@0.20.0-next.1': + resolution: {integrity: sha512-kPSa83z+dR34S/WbWPlBhweEbZP2A+rhe44ij5N2BSo2wnlzNOtS+piZKGQACP/n/97w+0/24d32w7+ZV3h54A==} engines: {node: '>=24.0.0'} - '@3sixty/trust-models@0.20.0-next.0': - resolution: {integrity: sha512-PUG9+uIK+EyNMr67cX8XRgj0DVSkQoPwfVeCvdhAyYI8kalwB10vIGqthdJocCW3b0cNI+EYoX0edzA+O4tu9w==} + '@3sixty/trust-models@0.20.0-next.1': + resolution: {integrity: sha512-J6uaGvHXHw/ZNBk3P8k2XWKX7cocbEG6uZlqt+0o96BrY8GadOagPwR0vp8jBc2hbKdNrZ/nICSr7iZf4G0aOg==} engines: {node: '>=24.0.0'} - '@3sixty/trust-service@0.20.0-next.0': - resolution: {integrity: sha512-HBow9sWdUuy9wwQoQhCw9kzgWwNxWOIBX8bOvs4r+Gn7FRR9t9QfO1AwLLsRXazXJ+5BNpBu7tKNT6PAvq7rGA==} + '@3sixty/trust-service@0.20.0-next.1': + resolution: {integrity: sha512-tK4IaDZC9/hGJstMM4dugMdMlnmHptT/5Fzlibjd4xybLT8h7+3OeauztTP8yKNng6LuNnwfIRdv6TiTSlrW8A==} engines: {node: '>=24.0.0'} - '@3sixty/trust-verifiers@0.20.0-next.0': - resolution: {integrity: sha512-lZ1rPnqXwBUja/4LrnhEFhE30R1wmrOlt73mNiXMB/PEhODJ7cNDboKRnOjhTtbn1dHocNw0ArgqXB6XeB3qZg==} + '@3sixty/trust-verifiers@0.20.0-next.1': + resolution: {integrity: sha512-T8ZtX5CxsJDPy0GMPVFpAJ7BnQjjze09ll3J3px6QkhMvmucSEvNxB+vkWzp1p8Wv0xo3uI60ZyjtDOWASUg1w==} engines: {node: '>=24.0.0'} '@3sixty/ts-to-openapi@0.20.0-next.4': @@ -1966,6 +1973,12 @@ packages: engines: {node: '>=6'} hasBin: true + '@hono/node-server@2.1.3': + resolution: {integrity: sha512-TA//nWMqPhbfdfneACk6t5a9eqbS9lABEPyKn0/xZTah3H3U2XaVg85rJFl0/Fyit0I552YDHgXGVSf3GwqbUw==} + engines: {node: '>=20'} + peerDependencies: + hono: ^4 + '@humanfs/core@0.19.2': resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} engines: {node: '>=18.18.0'} @@ -3047,6 +3060,10 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + base64id@2.0.0: + resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==} + engines: {node: ^4.5.0 || >= 5.9} + baseline-browser-mapping@2.11.30: resolution: {integrity: sha512-YJs6Pz17RMNv8HoyKREtCY38E3BV1nPkWVmIb+XN1uHC1Vqt3KZCH/uJH9ZKRoiKb/icZ6tvehyee6RZNbFfRA==} engines: {node: '>=6.0.0'} @@ -3175,9 +3192,6 @@ packages: resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} engines: {node: '>=8'} - cliui@7.0.4: - resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} - cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -3258,17 +3272,10 @@ packages: resolution: {integrity: sha512-yuToqVvRrj6pfDXREyQAAv8SkAEk/8GS3jQRTiUMm66TVtBYmqQeoEjL2Lmq8Rpo6271vH76InTChTitEAm65w==} engines: {node: '>=22'} - copyfiles@2.4.1: - resolution: {integrity: sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==} - hasBin: true - core-js-compat@3.51.0: resolution: {integrity: sha512-52r6fkXgxv4GLMjmFcMWRx7X9bw071xTTdrDcdyPGRqU2oE+9pCG0bAOMifSBdLw0JRBZKEF0q3B55qPlLuE8g==} engines: {node: '>=6.4.0'} - core-util-is@1.0.3: - resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - cors@2.8.6: resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} engines: {node: '>= 0.10'} @@ -3713,9 +3720,6 @@ packages: resolution: {integrity: sha512-R9iDuNrQYeQut46cn2r2wHKn4HYzVDvDm5J1wW+koZewykv0yuO2HChTYeZtrULyHIDM9cj9TUXloCsueCQUog==} hasBin: true - fastify-plugin@6.0.0: - resolution: {integrity: sha512-fZOty7z3O7vOliF6d8bHE3wiEh1KcNnKEQensSgTk9C1DvN6nRLS++XVd86v33Hw/8u9Un8A1zDrQ8ujcQDHEg==} - fastify-plugin@6.0.1: resolution: {integrity: sha512-4wW4RxSmvPXLrh5mgQEiu43qU3bw44N2ss4FTkTkQIbprUhE+/s43QX0j/ttcztdWK7PEkHqVthdc5GdEGDvjA==} @@ -3786,9 +3790,6 @@ packages: resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} engines: {node: '>=12.20.0'} - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -3863,10 +3864,6 @@ packages: resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} engines: {node: 18 || 20 || >=22} - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - global-directory@5.0.0: resolution: {integrity: sha512-1pgFdhK3J2LeM+dVf2Pd424yHx2ou338lC0ErNP2hPx4j8eW1Sp0XqSjNxtk6Tc4Kr5wlWtSvz8cn2yb7/SG/w==} engines: {node: '>=20'} @@ -3970,6 +3967,10 @@ packages: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true + hono@4.13.13: + resolution: {integrity: sha512-CQ46U0ZkAGmbT/4UxdzzGJpacP2IeKgY4a5/tOI9AABbpOMfK739wfDXmv1usCk+3RkKj1hQy4/fjhiwa2xlrA==} + engines: {node: '>=16.9.0'} + hookified@1.15.1: resolution: {integrity: sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==} @@ -4043,10 +4044,6 @@ packages: resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} engines: {node: '>=12'} - inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. - inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -4134,12 +4131,6 @@ packages: is-unsafe@2.0.2: resolution: {integrity: sha512-HgbIHPBH0KHHCcjLfGsCvhtPTVxjaAZlXjwdz7/GQC40SjSe4sfQsar8J5VFo8JOSbarkpV0OLG95bbaNd9aAQ==} - isarray@0.0.1: - resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==} - - isarray@1.0.0: - resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -4605,11 +4596,6 @@ packages: resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} engines: {node: '>=16 || 14 >=14.17'} - mkdirp@1.0.4: - resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} - engines: {node: '>=10'} - hasBin: true - mnemonist@0.38.3: resolution: {integrity: sha512-2K9QYubXx/NAjv4VLq1d1Ly8pWNC5L3BrixtdkyTegXWJIqY+zLNDhhX/A+ZwWt70tB1S8H4BE8FLYEFyNoOBw==} @@ -4724,9 +4710,6 @@ packages: engines: {node: '>=10'} hasBin: true - noms@0.0.0: - resolution: {integrity: sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==} - normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} @@ -4831,10 +4814,6 @@ packages: resolution: {integrity: sha512-enSlaiat05iasnzmgNxRj8reFdj3puY2QpNgP1aPIaVfT6nn9ICuPoFlKHk8EN22HcwewshO+mN2DGbkCEOtqQ==} engines: {node: '>=14.0.0'} - path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -4907,9 +4886,6 @@ packages: priorityqueuejs@2.0.0: resolution: {integrity: sha512-19BMarhgpq3x4ccvVi8k2QpJZcymo/iFUcrhPd4V96kYGovOdTsWwy7fxChYi4QY+m2EnGBWSX9Buakz+tWNQQ==} - process-nextick-args@2.0.1: - resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - process-warning@5.1.1: resolution: {integrity: sha512-oCkNVj4OKnKEcocVBcDfiIugN1/cE6rgfT3nCtzeqZPA8+rIxMaQ0xXzIkGP8Gj2qUaP1UR7uhJ1VD8lUCpzCg==} @@ -4975,12 +4951,6 @@ packages: resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} engines: {node: '>=8'} - readable-stream@1.0.34: - resolution: {integrity: sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==} - - readable-stream@2.3.8: - resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} - readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} @@ -5090,9 +5060,6 @@ packages: resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} engines: {node: '>=6'} - safe-buffer@5.1.2: - resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} @@ -5203,6 +5170,10 @@ packages: resolution: {integrity: sha512-IH/iSeO9T6gz1KkFleGDWkG9N3dl4jXVYUtMhIqH10Md0ttMer8nUNWiP1DKuNrybD2xBrixLJdCC9J6ECoYkg==} engines: {node: '>=10.0.0'} + socket.io@4.8.3: + resolution: {integrity: sha512-2Dd78bqzzjE6KPkD5fHZmDAKRNe3J15q+YHDrIsy9WEkqttc7GY+kT9OBLSMaPbQaEd0x1BjcmtMtXkfpc+T5A==} + engines: {node: '>=10.2.0'} + socket.io@4.8.4: resolution: {integrity: sha512-9ZV9zg8vN8hO3Y25DhR7nUkJ1VDnBhq5O/JrXhFT9s6+F0gqytSASTHVfCFc2mJXaTfARroErplXlzFWwETZqQ==} engines: {node: '>=10.2.0'} @@ -5284,12 +5255,6 @@ packages: resolution: {integrity: sha512-ZbmZM0JCihQN91dWnxoipT2KOEyHqEyfRXUyjuRhW8b/xnqPDoq4gWEVApTVa9db2wN8mmoikgFBbjh71+cGeQ==} engines: {node: '>=20'} - string_decoder@0.10.31: - resolution: {integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==} - - string_decoder@1.1.1: - resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} - string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} @@ -5351,9 +5316,6 @@ packages: resolution: {integrity: sha512-e2zZ96wSChazBsbENf/Pcm/4swHt2cEKQ92rhUjkL9GCKiTDJIaTBenjE/m9DXi0QBmTMDkFDdOomUy20A1tDQ==} engines: {node: '>=20'} - through2@2.0.5: - resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} - through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} @@ -5504,10 +5466,6 @@ packages: unrs-resolver@1.12.2: resolution: {integrity: sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==} - untildify@4.0.0: - resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} - engines: {node: '>=8'} - update-browserslist-db@1.3.4: resolution: {integrity: sha512-t8wonIOdQyOjtPd2VktlBu6QjTVTks6v8bSi7kd0r2Vll8TK1JYDZtRRdbmCHOAMphkZgrzK+L+vXK4pyZ8t4A==} hasBin: true @@ -5718,10 +5676,6 @@ packages: resolution: {integrity: sha512-FxF6+rkr1rNSQrhUNYrAFJpRXNzlDoMxeXN5qI84939ylEv3qqPFKa85Oxr6tDaJKqwW6KKyo2v26TSv3k6LeA==} engines: {node: '>=0.6.0'} - xtend@4.0.2: - resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} - engines: {node: '>=0.4'} - y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -5746,10 +5700,6 @@ packages: resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} engines: {node: ^20.19.0 || ^22.12.0 || >=23} - yargs@16.2.2: - resolution: {integrity: sha512-Nt9ZJjXTv5R8MHbqby/wXQ6Gi0Bb3TcYZkR1bzuL4yB2OxWPkXknz513gEF0GoA6tn00UpbPvERW8rzCuWCA6w==} - engines: {node: '>=10'} - yargs@17.7.3: resolution: {integrity: sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==} engines: {node: '>=12'} @@ -5817,6 +5767,20 @@ snapshots: '@3sixty/core': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 + '@3sixty/api-auth-service@0.20.0-next.1': + dependencies: + '@3sixty/api-auth-models': 0.20.0-next.1 + '@3sixty/api-models': 0.20.0-next.1 + '@3sixty/authorization-models': 0.20.0-next.1 + '@3sixty/background-task-models': 0.20.0-next.1 + '@3sixty/context': 0.20.0-next.2 + '@3sixty/core': 0.20.0-next.2 + '@3sixty/crypto': 0.20.0-next.2 + '@3sixty/entity': 0.20.0-next.2 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/nameof': 0.20.0-next.2 + '@3sixty/web': 0.20.0-next.2 + '@3sixty/api-core-server@0.20.0-next.1': dependencies: '@3sixty/api-models': 0.20.0-next.1 @@ -5886,6 +5850,37 @@ snapshots: - supports-color - utf-8-validate + '@3sixty/api-server-hono@0.20.0-next.1(supports-color@10.2.2)': + dependencies: + '@3sixty/api-core-server': 0.20.0-next.1 + '@3sixty/api-models': 0.20.0-next.1 + '@3sixty/context': 0.20.0-next.2 + '@3sixty/core': 0.20.0-next.2 + '@3sixty/nameof': 0.20.0-next.2 + '@3sixty/web': 0.20.0-next.2 + '@hono/node-server': 2.1.3(hono@4.13.13) + hono: 4.13.13 + socket.io: 4.8.3(supports-color@10.2.2) + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@3sixty/api-server-native@0.20.0-next.1(supports-color@10.2.2)': + dependencies: + '@3sixty/api-core-server': 0.20.0-next.1 + '@3sixty/api-models': 0.20.0-next.1 + '@3sixty/context': 0.20.0-next.2 + '@3sixty/core': 0.20.0-next.2 + '@3sixty/nameof': 0.20.0-next.2 + '@3sixty/web': 0.20.0-next.2 + find-my-way: 9.10.0 + socket.io: 4.8.3(supports-color@10.2.2) + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + '@3sixty/api-service@0.20.0-next.1': dependencies: '@3sixty/api-models': 0.20.0-next.1 @@ -5911,19 +5906,19 @@ snapshots: '@3sixty/vault-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/attestation-connector-nft@0.20.0-next.0': + '@3sixty/attestation-connector-nft@0.20.0-next.1': dependencies: - '@3sixty/attestation-models': 0.20.0-next.0 + '@3sixty/attestation-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/identity-models': 0.20.0-next.0 + '@3sixty/identity-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/nft-models': 0.20.0-next.0 + '@3sixty/nft-models': 0.20.0-next.1 '@3sixty/standards-schema-org': 0.20.0-next.2 '@3sixty/standards-w3c-did': 0.20.0-next.2 - '@3sixty/attestation-models@0.20.0-next.0': + '@3sixty/attestation-models@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/data-core': 0.20.0-next.3 @@ -5935,11 +5930,11 @@ snapshots: '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/attestation-rest-client@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/attestation-rest-client@0.20.0-next.1(supports-color@10.2.2)': dependencies: '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) '@3sixty/api-models': 0.20.0-next.1 - '@3sixty/attestation-models': 0.20.0-next.0 + '@3sixty/attestation-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 @@ -5951,10 +5946,10 @@ snapshots: - supports-color - utf-8-validate - '@3sixty/attestation-service@0.20.0-next.0': + '@3sixty/attestation-service@0.20.0-next.1': dependencies: '@3sixty/api-models': 0.20.0-next.1 - '@3sixty/attestation-models': 0.20.0-next.0 + '@3sixty/attestation-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/data-json-ld': 0.20.0-next.3 @@ -5965,27 +5960,27 @@ snapshots: '@3sixty/wallet-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/auditable-item-graph-models@0.20.0-next.0': + '@3sixty/auditable-item-graph-models@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/data-core': 0.20.0-next.3 '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/immutable-proof-models': 0.20.0-next.0 + '@3sixty/immutable-proof-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/standards-schema-org': 0.20.0-next.2 '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/auditable-item-graph-rest-client@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/auditable-item-graph-rest-client@0.20.0-next.1(supports-color@10.2.2)': dependencies: '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) '@3sixty/api-models': 0.20.0-next.1 - '@3sixty/auditable-item-graph-models': 0.20.0-next.0 + '@3sixty/auditable-item-graph-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/immutable-proof-models': 0.20.0-next.0 + '@3sixty/immutable-proof-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 transitivePeerDependencies: @@ -5993,10 +5988,10 @@ snapshots: - supports-color - utf-8-validate - '@3sixty/auditable-item-graph-service@0.20.0-next.0': + '@3sixty/auditable-item-graph-service@0.20.0-next.1': dependencies: '@3sixty/api-models': 0.20.0-next.1 - '@3sixty/auditable-item-graph-models': 0.20.0-next.0 + '@3sixty/auditable-item-graph-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 @@ -6005,30 +6000,30 @@ snapshots: '@3sixty/entity': 0.20.0-next.2 '@3sixty/entity-storage-models': 0.20.0-next.1 '@3sixty/event-bus-models': 0.20.0-next.1 - '@3sixty/immutable-proof-models': 0.20.0-next.0 + '@3sixty/immutable-proof-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/standards-schema-org': 0.20.0-next.2 '@3sixty/standards-w3c-did': 0.20.0-next.2 '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/auditable-item-stream-models@0.20.0-next.0': + '@3sixty/auditable-item-stream-models@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/data-core': 0.20.0-next.3 '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/immutable-proof-models': 0.20.0-next.0 + '@3sixty/immutable-proof-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/standards-schema-org': 0.20.0-next.2 '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/auditable-item-stream-rest-client@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/auditable-item-stream-rest-client@0.20.0-next.1(supports-color@10.2.2)': dependencies: '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) '@3sixty/api-models': 0.20.0-next.1 - '@3sixty/auditable-item-stream-models': 0.20.0-next.0 + '@3sixty/auditable-item-stream-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 @@ -6039,10 +6034,10 @@ snapshots: - supports-color - utf-8-validate - '@3sixty/auditable-item-stream-service@0.20.0-next.0': + '@3sixty/auditable-item-stream-service@0.20.0-next.1': dependencies: '@3sixty/api-models': 0.20.0-next.1 - '@3sixty/auditable-item-stream-models': 0.20.0-next.0 + '@3sixty/auditable-item-stream-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/data-core': 0.20.0-next.3 @@ -6050,19 +6045,61 @@ snapshots: '@3sixty/entity': 0.20.0-next.2 '@3sixty/entity-storage-models': 0.20.0-next.1 '@3sixty/event-bus-models': 0.20.0-next.1 - '@3sixty/immutable-proof-models': 0.20.0-next.0 + '@3sixty/immutable-proof-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/standards-schema-org': 0.20.0-next.2 '@3sixty/standards-w3c-did': 0.20.0-next.2 '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 + '@3sixty/authorization-connector-casbin@0.20.0-next.1': + dependencies: + '@3sixty/authorization-models': 0.20.0-next.1 + '@3sixty/context': 0.20.0-next.2 + '@3sixty/core': 0.20.0-next.2 + '@3sixty/crypto': 0.20.0-next.2 + '@3sixty/logging-models': 0.20.0-next.1 + '@3sixty/nameof': 0.20.0-next.2 + '@3sixty/web': 0.20.0-next.2 + + '@3sixty/authorization-connector-entity-storage@0.20.0-next.1': + dependencies: + '@3sixty/authorization-models': 0.20.0-next.1 + '@3sixty/core': 0.20.0-next.2 + '@3sixty/entity': 0.20.0-next.2 + '@3sixty/entity-storage-models': 0.20.0-next.1 + '@3sixty/nameof': 0.20.0-next.2 + '@3sixty/authorization-models@0.20.0-next.1': dependencies: '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/telemetry-models': 0.20.0-next.1 + '@3sixty/authorization-rest-client@0.20.0-next.1(supports-color@10.2.2)': + dependencies: + '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-models': 0.20.0-next.1 + '@3sixty/authorization-models': 0.20.0-next.1 + '@3sixty/core': 0.20.0-next.2 + '@3sixty/nameof': 0.20.0-next.2 + '@3sixty/web': 0.20.0-next.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@3sixty/authorization-service@0.20.0-next.1': + dependencies: + '@3sixty/api-models': 0.20.0-next.1 + '@3sixty/authorization-models': 0.20.0-next.1 + '@3sixty/context': 0.20.0-next.2 + '@3sixty/core': 0.20.0-next.2 + '@3sixty/logging-models': 0.20.0-next.1 + '@3sixty/nameof': 0.20.0-next.2 + '@3sixty/telemetry-models': 0.20.0-next.1 + '@3sixty/web': 0.20.0-next.2 + '@3sixty/automation-actions@0.20.0-next.1': dependencies: '@3sixty/api-models': 0.20.0-next.1 @@ -6344,26 +6381,26 @@ snapshots: '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 - '@3sixty/dataspace-app-runner@0.20.0-next.0': + '@3sixty/dataspace-app-runner@0.20.0-next.1': dependencies: '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 - '@3sixty/dataspace-models': 0.20.0-next.0 + '@3sixty/dataspace-models': 0.20.0-next.1 '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/modules': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/rights-management-models': 0.20.0-next.0 + '@3sixty/rights-management-models': 0.20.0-next.1 '@3sixty/standards-w3c-activity-streams': 0.20.0-next.2 - '@3sixty/trust-models': 0.20.0-next.0 + '@3sixty/trust-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/dataspace-control-plane-rest-client@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/dataspace-control-plane-rest-client@0.20.0-next.1(supports-color@10.2.2)': dependencies: '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/data-json-ld': 0.20.0-next.3 - '@3sixty/dataspace-models': 0.20.0-next.0 + '@3sixty/dataspace-models': 0.20.0-next.1 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 @@ -6373,7 +6410,7 @@ snapshots: - supports-color - utf-8-validate - '@3sixty/dataspace-control-plane-service@0.20.0-next.0': + '@3sixty/dataspace-control-plane-service@0.20.0-next.1': dependencies: '@3sixty/api-models': 0.20.0-next.1 '@3sixty/api-tenant-processor': 0.20.0-next.1 @@ -6381,22 +6418,22 @@ snapshots: '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/data-json-ld': 0.20.0-next.3 - '@3sixty/dataspace-models': 0.20.0-next.0 + '@3sixty/dataspace-models': 0.20.0-next.1 '@3sixty/entity': 0.20.0-next.2 '@3sixty/entity-storage-models': 0.20.0-next.1 - '@3sixty/federated-catalogue-models': 0.20.0-next.0 + '@3sixty/federated-catalogue-models': 0.20.0-next.1 '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/rights-management-models': 0.20.0-next.0 + '@3sixty/rights-management-models': 0.20.0-next.1 '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 '@3sixty/standards-w3c-dcat': 0.20.0-next.2 '@3sixty/standards-w3c-odrl': 0.20.0-next.2 '@3sixty/telemetry-models': 0.20.0-next.1 - '@3sixty/trust-models': 0.20.0-next.0 + '@3sixty/trust-models': 0.20.0-next.1 '@3sixty/vault-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/dataspace-data-plane-rest-client@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/dataspace-data-plane-rest-client@0.20.0-next.1(supports-color@10.2.2)': dependencies: '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) '@3sixty/api-models': 0.20.0-next.1 @@ -6411,7 +6448,7 @@ snapshots: - supports-color - utf-8-validate - '@3sixty/dataspace-data-plane-service@0.20.0-next.0': + '@3sixty/dataspace-data-plane-service@0.20.0-next.1': dependencies: '@3sixty/api-models': 0.20.0-next.1 '@3sixty/background-task-models': 0.20.0-next.1 @@ -6420,30 +6457,30 @@ snapshots: '@3sixty/crypto': 0.20.0-next.2 '@3sixty/data-core': 0.20.0-next.3 '@3sixty/data-json-ld': 0.20.0-next.3 - '@3sixty/dataspace-app-runner': 0.20.0-next.0 - '@3sixty/dataspace-models': 0.20.0-next.0 + '@3sixty/dataspace-app-runner': 0.20.0-next.1 + '@3sixty/dataspace-models': 0.20.0-next.1 '@3sixty/entity': 0.20.0-next.2 '@3sixty/entity-storage-models': 0.20.0-next.1 '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/modules': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/rights-management-models': 0.20.0-next.0 + '@3sixty/rights-management-models': 0.20.0-next.1 '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 '@3sixty/standards-schema-org': 0.20.0-next.2 '@3sixty/standards-w3c-activity-streams': 0.20.0-next.2 '@3sixty/standards-w3c-dcat': 0.20.0-next.2 '@3sixty/standards-w3c-odrl': 0.20.0-next.2 '@3sixty/telemetry-models': 0.20.0-next.1 - '@3sixty/trust-models': 0.20.0-next.0 + '@3sixty/trust-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/dataspace-data-plane-socket-client@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/dataspace-data-plane-socket-client@0.20.0-next.1(supports-color@10.2.2)': dependencies: '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/data-json-ld': 0.20.0-next.3 - '@3sixty/dataspace-models': 0.20.0-next.0 + '@3sixty/dataspace-models': 0.20.0-next.1 '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/standards-w3c-activity-streams': 0.20.0-next.2 @@ -6452,7 +6489,7 @@ snapshots: - supports-color - utf-8-validate - '@3sixty/dataspace-models@0.20.0-next.0': + '@3sixty/dataspace-models@0.20.0-next.1': dependencies: '@3sixty/background-task-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 @@ -6460,7 +6497,7 @@ snapshots: '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/rights-management-models': 0.20.0-next.0 + '@3sixty/rights-management-models': 0.20.0-next.1 '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 '@3sixty/standards-schema-org': 0.20.0-next.2 '@3sixty/standards-w3c-activity-streams': 0.20.0-next.2 @@ -6495,10 +6532,10 @@ snapshots: - encoding - typescript - '@3sixty/document-management-models@0.20.0-next.0': + '@3sixty/document-management-models@0.20.0-next.1': dependencies: - '@3sixty/attestation-models': 0.20.0-next.0 - '@3sixty/auditable-item-graph-models': 0.20.0-next.0 + '@3sixty/attestation-models': 0.20.0-next.1 + '@3sixty/auditable-item-graph-models': 0.20.0-next.1 '@3sixty/blob-storage-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/data-core': 0.20.0-next.3 @@ -6509,11 +6546,11 @@ snapshots: '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/document-management-rest-client@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/document-management-rest-client@0.20.0-next.1(supports-color@10.2.2)': dependencies: '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) '@3sixty/api-models': 0.20.0-next.1 - '@3sixty/auditable-item-graph-models': 0.20.0-next.0 + '@3sixty/auditable-item-graph-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 @@ -6524,18 +6561,18 @@ snapshots: - supports-color - utf-8-validate - '@3sixty/document-management-service@0.20.0-next.0': + '@3sixty/document-management-service@0.20.0-next.1': dependencies: '@3sixty/api-models': 0.20.0-next.1 - '@3sixty/attestation-models': 0.20.0-next.0 - '@3sixty/auditable-item-graph-models': 0.20.0-next.0 + '@3sixty/attestation-models': 0.20.0-next.1 + '@3sixty/auditable-item-graph-models': 0.20.0-next.1 '@3sixty/blob-storage-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/data-processing-models': 0.20.0-next.1 - '@3sixty/document-management-models': 0.20.0-next.0 + '@3sixty/document-management-models': 0.20.0-next.1 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/standards-schema-org': 0.20.0-next.2 @@ -6543,13 +6580,12 @@ snapshots: '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/engine-core@0.20.0-next.1': + '@3sixty/engine-core@0.20.0-next.2': dependencies: '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 - '@3sixty/crypto': 0.20.0-next.2 '@3sixty/data-core': 0.20.0-next.3 - '@3sixty/engine-models': 0.20.0-next.1 + '@3sixty/engine-models': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 '@3sixty/logging-connector-console': 0.20.0-next.1 '@3sixty/logging-models': 0.20.0-next.1 @@ -6557,29 +6593,29 @@ snapshots: '@3sixty/modules': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/engine-models@0.20.0-next.1': + '@3sixty/engine-models@0.20.0-next.2': dependencies: + '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/engine-server-types@0.20.0-next.1(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(buffer@6.0.3)(socks@2.8.10)(supports-color@10.2.2)(typescript@6.0.3)': + '@3sixty/engine-server-types@0.20.0-next.2(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(buffer@6.0.3)(socks@2.8.10)(supports-color@10.2.2)(typescript@6.0.3)': dependencies: '@3sixty/api-auth-entity-storage-rest-client': 0.20.0-next.1(supports-color@10.2.2) '@3sixty/api-auth-entity-storage-service': 0.20.0-next.1 - '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-auth-service': 0.20.0-next.1 '@3sixty/api-models': 0.20.0-next.1 '@3sixty/api-processors': 0.20.0-next.1 '@3sixty/api-rest-client': 0.20.0-next.1(supports-color@10.2.2) - '@3sixty/api-server-fastify': 0.20.0-next.1(supports-color@10.2.2) '@3sixty/api-service': 0.20.0-next.1 '@3sixty/api-tenant-processor': 0.20.0-next.1 + '@3sixty/authorization-service': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 - '@3sixty/engine-models': 0.20.0-next.1 - '@3sixty/engine-types': 0.20.0-next.1(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(buffer@6.0.3)(socks@2.8.10)(supports-color@10.2.2)(typescript@6.0.3) - '@3sixty/entity': 0.20.0-next.2 + '@3sixty/engine-models': 0.20.0-next.2 + '@3sixty/engine-types': 0.20.0-next.2(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(buffer@6.0.3)(socks@2.8.10)(supports-color@10.2.2)(typescript@6.0.3) '@3sixty/nameof': 0.20.0-next.2 '@3sixty/telemetry-processors': 0.20.0-next.1 '@3sixty/tracing-processors': 0.20.0-next.1 @@ -6605,14 +6641,16 @@ snapshots: - typescript - utf-8-validate - '@3sixty/engine-server@0.20.0-next.1(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(buffer@6.0.3)(socks@2.8.10)(supports-color@10.2.2)(typescript@6.0.3)': + '@3sixty/engine-server@0.20.0-next.2(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(buffer@6.0.3)(socks@2.8.10)(supports-color@10.2.2)(typescript@6.0.3)': dependencies: '@3sixty/api-models': 0.20.0-next.1 '@3sixty/api-server-fastify': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-server-hono': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/api-server-native': 0.20.0-next.1(supports-color@10.2.2) '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 - '@3sixty/engine-models': 0.20.0-next.1 - '@3sixty/engine-server-types': 0.20.0-next.1(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(buffer@6.0.3)(socks@2.8.10)(supports-color@10.2.2)(typescript@6.0.3) + '@3sixty/engine-models': 0.20.0-next.2 + '@3sixty/engine-server-types': 0.20.0-next.2(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(buffer@6.0.3)(socks@2.8.10)(supports-color@10.2.2)(typescript@6.0.3) '@3sixty/modules': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 transitivePeerDependencies: @@ -6637,27 +6675,29 @@ snapshots: - typescript - utf-8-validate - '@3sixty/engine-types@0.20.0-next.1(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(buffer@6.0.3)(socks@2.8.10)(supports-color@10.2.2)(typescript@6.0.3)': + '@3sixty/engine-types@0.20.0-next.2(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(buffer@6.0.3)(socks@2.8.10)(supports-color@10.2.2)(typescript@6.0.3)': dependencies: '@3sixty/api-models': 0.20.0-next.1 '@3sixty/api-rest-client': 0.20.0-next.1(supports-color@10.2.2) '@3sixty/api-service': 0.20.0-next.1 '@3sixty/api-tenant-processor': 0.20.0-next.1 - '@3sixty/attestation-connector-nft': 0.20.0-next.0 - '@3sixty/attestation-models': 0.20.0-next.0 - '@3sixty/attestation-rest-client': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/attestation-service': 0.20.0-next.0 - '@3sixty/auditable-item-graph-models': 0.20.0-next.0 - '@3sixty/auditable-item-graph-rest-client': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/auditable-item-graph-service': 0.20.0-next.0 - '@3sixty/auditable-item-stream-models': 0.20.0-next.0 - '@3sixty/auditable-item-stream-rest-client': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/auditable-item-stream-service': 0.20.0-next.0 + '@3sixty/attestation-connector-nft': 0.20.0-next.1 + '@3sixty/attestation-models': 0.20.0-next.1 + '@3sixty/attestation-rest-client': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/attestation-service': 0.20.0-next.1 + '@3sixty/auditable-item-graph-rest-client': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/auditable-item-graph-service': 0.20.0-next.1 + '@3sixty/auditable-item-stream-rest-client': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/auditable-item-stream-service': 0.20.0-next.1 + '@3sixty/authorization-connector-casbin': 0.20.0-next.1 + '@3sixty/authorization-connector-entity-storage': 0.20.0-next.1 + '@3sixty/authorization-models': 0.20.0-next.1 + '@3sixty/authorization-rest-client': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/authorization-service': 0.20.0-next.1 '@3sixty/automation-actions': 0.20.0-next.1 '@3sixty/automation-models': 0.20.0-next.1 '@3sixty/automation-rest-client': 0.20.0-next.1(supports-color@10.2.2) '@3sixty/automation-service': 0.20.0-next.1 - '@3sixty/background-task-models': 0.20.0-next.1 '@3sixty/background-task-scheduler': 0.20.0-next.1 '@3sixty/background-task-service': 0.20.0-next.1 '@3sixty/blob-storage-connector-aws-s3': 0.20.0-next.1 @@ -6671,26 +6711,21 @@ snapshots: '@3sixty/blob-storage-service': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 - '@3sixty/crypto': 0.20.0-next.2 - '@3sixty/data-core': 0.20.0-next.3 '@3sixty/data-processing-converters': 0.20.0-next.1 '@3sixty/data-processing-extractors': 0.20.0-next.1 '@3sixty/data-processing-models': 0.20.0-next.1 '@3sixty/data-processing-rest-client': 0.20.0-next.1(supports-color@10.2.2) '@3sixty/data-processing-service': 0.20.0-next.1 - '@3sixty/dataspace-control-plane-rest-client': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/dataspace-control-plane-service': 0.20.0-next.0 - '@3sixty/dataspace-data-plane-rest-client': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/dataspace-data-plane-service': 0.20.0-next.0 - '@3sixty/dataspace-data-plane-socket-client': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/dataspace-models': 0.20.0-next.0 + '@3sixty/dataspace-control-plane-rest-client': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/dataspace-control-plane-service': 0.20.0-next.1 + '@3sixty/dataspace-data-plane-rest-client': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/dataspace-data-plane-service': 0.20.0-next.1 + '@3sixty/dataspace-data-plane-socket-client': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/dataspace-models': 0.20.0-next.1 '@3sixty/dlt-iota': 0.20.0-next.1(typescript@6.0.3) - '@3sixty/document-management-models': 0.20.0-next.0 - '@3sixty/document-management-rest-client': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/document-management-service': 0.20.0-next.0 - '@3sixty/engine-core': 0.20.0-next.1 - '@3sixty/engine-models': 0.20.0-next.1 - '@3sixty/entity': 0.20.0-next.2 + '@3sixty/document-management-rest-client': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/document-management-service': 0.20.0-next.1 + '@3sixty/engine-models': 0.20.0-next.2 '@3sixty/entity-storage-connector-cosmosdb': 0.20.0-next.1(supports-color@10.2.2) '@3sixty/entity-storage-connector-dynamodb': 0.20.0-next.1 '@3sixty/entity-storage-connector-file': 0.20.0-next.1 @@ -6707,19 +6742,18 @@ snapshots: '@3sixty/event-bus-models': 0.20.0-next.1 '@3sixty/event-bus-service': 0.20.0-next.1 '@3sixty/event-bus-socket-client': 0.20.0-next.1(supports-color@10.2.2) - '@3sixty/federated-catalogue-filters': 0.20.0-next.0 - '@3sixty/federated-catalogue-models': 0.20.0-next.0 - '@3sixty/federated-catalogue-rest-client': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/federated-catalogue-service': 0.20.0-next.0 - '@3sixty/identity-connector-entity-storage': 0.20.0-next.0 - '@3sixty/identity-connector-iota': 0.20.0-next.0(typescript@6.0.3) - '@3sixty/identity-connector-universal': 0.20.0-next.0 - '@3sixty/identity-models': 0.20.0-next.0 - '@3sixty/identity-rest-client': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/identity-service': 0.20.0-next.0 - '@3sixty/immutable-proof-models': 0.20.0-next.0 - '@3sixty/immutable-proof-rest-client': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/immutable-proof-service': 0.20.0-next.0 + '@3sixty/federated-catalogue-filters': 0.20.0-next.1 + '@3sixty/federated-catalogue-models': 0.20.0-next.1 + '@3sixty/federated-catalogue-rest-client': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/federated-catalogue-service': 0.20.0-next.1 + '@3sixty/identity-connector-entity-storage': 0.20.0-next.1 + '@3sixty/identity-connector-iota': 0.20.0-next.1(typescript@6.0.3) + '@3sixty/identity-connector-universal': 0.20.0-next.1 + '@3sixty/identity-models': 0.20.0-next.1 + '@3sixty/identity-rest-client': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/identity-service': 0.20.0-next.1 + '@3sixty/immutable-proof-rest-client': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/immutable-proof-service': 0.20.0-next.1 '@3sixty/logging-connector-console': 0.20.0-next.1 '@3sixty/logging-connector-elk': 0.20.0-next.1 '@3sixty/logging-connector-entity-storage': 0.20.0-next.1 @@ -6740,29 +6774,28 @@ snapshots: '@3sixty/messaging-connector-smtp': 0.20.0-next.1 '@3sixty/messaging-models': 0.20.0-next.1 '@3sixty/messaging-service': 0.20.0-next.1 - '@3sixty/modules': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/nft-connector-entity-storage': 0.20.0-next.0 - '@3sixty/nft-connector-iota': 0.20.0-next.0(typescript@6.0.3) - '@3sixty/nft-models': 0.20.0-next.0 - '@3sixty/nft-rest-client': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/nft-service': 0.20.0-next.0 - '@3sixty/notarization-connector-entity-storage': 0.20.0-next.0 - '@3sixty/notarization-connector-iota': 0.20.0-next.0(typescript@6.0.3) - '@3sixty/notarization-models': 0.20.0-next.0 - '@3sixty/notarization-rest-client': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/notarization-service': 0.20.0-next.0 - '@3sixty/rights-management-models': 0.20.0-next.0 - '@3sixty/rights-management-pap-service': 0.20.0-next.0 - '@3sixty/rights-management-pdp-service': 0.20.0-next.0 - '@3sixty/rights-management-pep-service': 0.20.0-next.0 - '@3sixty/rights-management-pip-service': 0.20.0-next.0 - '@3sixty/rights-management-plugins': 0.20.0-next.0 - '@3sixty/rights-management-pmp-service': 0.20.0-next.0 - '@3sixty/rights-management-pnp-service': 0.20.0-next.0 - '@3sixty/rights-management-pxp-service': 0.20.0-next.0 - '@3sixty/rights-management-rest-client': 0.20.0-next.0(supports-color@10.2.2) - '@3sixty/rights-management-service': 0.20.0-next.0 + '@3sixty/nft-connector-entity-storage': 0.20.0-next.1 + '@3sixty/nft-connector-iota': 0.20.0-next.1(typescript@6.0.3) + '@3sixty/nft-models': 0.20.0-next.1 + '@3sixty/nft-rest-client': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/nft-service': 0.20.0-next.1 + '@3sixty/notarization-connector-entity-storage': 0.20.0-next.1 + '@3sixty/notarization-connector-iota': 0.20.0-next.1(typescript@6.0.3) + '@3sixty/notarization-models': 0.20.0-next.1 + '@3sixty/notarization-rest-client': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/notarization-service': 0.20.0-next.1 + '@3sixty/rights-management-models': 0.20.0-next.1 + '@3sixty/rights-management-pap-service': 0.20.0-next.1 + '@3sixty/rights-management-pdp-service': 0.20.0-next.1 + '@3sixty/rights-management-pep-service': 0.20.0-next.1 + '@3sixty/rights-management-pip-service': 0.20.0-next.1 + '@3sixty/rights-management-plugins': 0.20.0-next.1 + '@3sixty/rights-management-pmp-service': 0.20.0-next.1 + '@3sixty/rights-management-pnp-service': 0.20.0-next.1 + '@3sixty/rights-management-pxp-service': 0.20.0-next.1 + '@3sixty/rights-management-rest-client': 0.20.0-next.1(supports-color@10.2.2) + '@3sixty/rights-management-service': 0.20.0-next.1 '@3sixty/telemetry-connector-entity-storage': 0.20.0-next.1 '@3sixty/telemetry-connector-opentelemetry': 0.20.0-next.1 '@3sixty/telemetry-models': 0.20.0-next.1 @@ -6777,10 +6810,10 @@ snapshots: '@3sixty/tracing-processors': 0.20.0-next.1 '@3sixty/tracing-rest-client': 0.20.0-next.1(supports-color@10.2.2) '@3sixty/tracing-service': 0.20.0-next.1 - '@3sixty/trust-generators': 0.20.0-next.0 - '@3sixty/trust-models': 0.20.0-next.0 - '@3sixty/trust-service': 0.20.0-next.0 - '@3sixty/trust-verifiers': 0.20.0-next.0 + '@3sixty/trust-generators': 0.20.0-next.1 + '@3sixty/trust-models': 0.20.0-next.1 + '@3sixty/trust-service': 0.20.0-next.1 + '@3sixty/trust-verifiers': 0.20.0-next.1 '@3sixty/vault-connector-entity-storage': 0.20.0-next.1 '@3sixty/vault-connector-hashicorp': 0.20.0-next.1 '@3sixty/vault-models': 0.20.0-next.1 @@ -6809,13 +6842,12 @@ snapshots: - typescript - utf-8-validate - '@3sixty/engine@0.20.0-next.1(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(buffer@6.0.3)(socks@2.8.10)(supports-color@10.2.2)(typescript@6.0.3)': + '@3sixty/engine@0.20.0-next.2(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(buffer@6.0.3)(socks@2.8.10)(supports-color@10.2.2)(typescript@6.0.3)': dependencies: - '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 - '@3sixty/engine-core': 0.20.0-next.1 - '@3sixty/engine-models': 0.20.0-next.1 - '@3sixty/engine-types': 0.20.0-next.1(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(buffer@6.0.3)(socks@2.8.10)(supports-color@10.2.2)(typescript@6.0.3) + '@3sixty/engine-core': 0.20.0-next.2 + '@3sixty/engine-models': 0.20.0-next.2 + '@3sixty/engine-types': 0.20.0-next.2(@opentelemetry/api@1.9.1)(@types/node@26.6.5)(buffer@6.0.3)(socks@2.8.10)(supports-color@10.2.2)(typescript@6.0.3) '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 transitivePeerDependencies: @@ -7029,23 +7061,23 @@ snapshots: - supports-color - utf-8-validate - '@3sixty/federated-catalogue-filters@0.20.0-next.0': + '@3sixty/federated-catalogue-filters@0.20.0-next.1': dependencies: '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 '@3sixty/entity-storage-models': 0.20.0-next.1 - '@3sixty/federated-catalogue-models': 0.20.0-next.0 - '@3sixty/federated-catalogue-service': 0.20.0-next.0 + '@3sixty/federated-catalogue-models': 0.20.0-next.1 + '@3sixty/federated-catalogue-service': 0.20.0-next.1 '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 '@3sixty/standards-w3c-dcat': 0.20.0-next.2 - '@3sixty/trust-models': 0.20.0-next.0 + '@3sixty/trust-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/federated-catalogue-models@0.20.0-next.0': + '@3sixty/federated-catalogue-models@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/data-core': 0.20.0-next.3 @@ -7055,28 +7087,28 @@ snapshots: '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 '@3sixty/standards-w3c-dcat': 0.20.0-next.2 '@3sixty/telemetry-models': 0.20.0-next.1 - '@3sixty/trust-models': 0.20.0-next.0 + '@3sixty/trust-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/federated-catalogue-rest-client@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/federated-catalogue-rest-client@0.20.0-next.1(supports-color@10.2.2)': dependencies: '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/data-json-ld': 0.20.0-next.3 - '@3sixty/federated-catalogue-models': 0.20.0-next.0 + '@3sixty/federated-catalogue-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 '@3sixty/standards-w3c-dcat': 0.20.0-next.2 - '@3sixty/trust-models': 0.20.0-next.0 + '@3sixty/trust-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate - '@3sixty/federated-catalogue-service@0.20.0-next.0': + '@3sixty/federated-catalogue-service@0.20.0-next.1': dependencies: '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 @@ -7085,7 +7117,7 @@ snapshots: '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 '@3sixty/entity-storage-models': 0.20.0-next.1 - '@3sixty/federated-catalogue-models': 0.20.0-next.0 + '@3sixty/federated-catalogue-models': 0.20.0-next.1 '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 @@ -7094,24 +7126,24 @@ snapshots: '@3sixty/standards-w3c-dcat': 0.20.0-next.2 '@3sixty/standards-w3c-odrl': 0.20.0-next.2 '@3sixty/telemetry-models': 0.20.0-next.1 - '@3sixty/trust-models': 0.20.0-next.0 + '@3sixty/trust-models': 0.20.0-next.1 '@3sixty/vault-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/identity-connector-entity-storage@0.20.0-next.0': + '@3sixty/identity-connector-entity-storage@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/data-core': 0.20.0-next.3 '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 '@3sixty/entity-storage-models': 0.20.0-next.1 - '@3sixty/identity-models': 0.20.0-next.0 + '@3sixty/identity-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/standards-w3c-did': 0.20.0-next.2 '@3sixty/vault-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/identity-connector-iota@0.20.0-next.0(typescript@6.0.3)': + '@3sixty/identity-connector-iota@0.20.0-next.1(typescript@6.0.3)': dependencies: '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 @@ -7119,7 +7151,7 @@ snapshots: '@3sixty/dlt-account': 0.20.0-next.1 '@3sixty/dlt-iota': 0.20.0-next.1(typescript@6.0.3) '@3sixty/entity': 0.20.0-next.2 - '@3sixty/identity-models': 0.20.0-next.0 + '@3sixty/identity-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/standards-w3c-did': 0.20.0-next.2 '@3sixty/vault-models': 0.20.0-next.1 @@ -7133,16 +7165,16 @@ snapshots: - encoding - typescript - '@3sixty/identity-connector-universal@0.20.0-next.0': + '@3sixty/identity-connector-universal@0.20.0-next.1': dependencies: '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 - '@3sixty/identity-models': 0.20.0-next.0 + '@3sixty/identity-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/standards-w3c-did': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 - '@3sixty/identity-models@0.20.0-next.0': + '@3sixty/identity-models@0.20.0-next.1': dependencies: '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 @@ -7154,7 +7186,7 @@ snapshots: '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/identity-rest-client@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/identity-rest-client@0.20.0-next.1(supports-color@10.2.2)': dependencies: '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) '@3sixty/api-models': 0.20.0-next.1 @@ -7162,7 +7194,7 @@ snapshots: '@3sixty/data-core': 0.20.0-next.3 '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/identity-models': 0.20.0-next.0 + '@3sixty/identity-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/standards-w3c-did': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 @@ -7171,16 +7203,17 @@ snapshots: - supports-color - utf-8-validate - '@3sixty/identity-service@0.20.0-next.0': + '@3sixty/identity-service@0.20.0-next.1': dependencies: '@3sixty/api-models': 0.20.0-next.1 + '@3sixty/authorization-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/data-core': 0.20.0-next.3 '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/dlt-account': 0.20.0-next.1 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/identity-models': 0.20.0-next.0 + '@3sixty/identity-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/standards-w3c-did': 0.20.0-next.2 '@3sixty/telemetry-models': 0.20.0-next.1 @@ -7188,7 +7221,7 @@ snapshots: '@3sixty/wallet-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/immutable-proof-models@0.20.0-next.0': + '@3sixty/immutable-proof-models@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/data-core': 0.20.0-next.3 @@ -7199,14 +7232,14 @@ snapshots: '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/immutable-proof-rest-client@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/immutable-proof-rest-client@0.20.0-next.1(supports-color@10.2.2)': dependencies: '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) '@3sixty/api-models': 0.20.0-next.1 '@3sixty/core': 0.20.0-next.2 '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/immutable-proof-models': 0.20.0-next.0 + '@3sixty/immutable-proof-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 transitivePeerDependencies: @@ -7214,7 +7247,7 @@ snapshots: - supports-color - utf-8-validate - '@3sixty/immutable-proof-service@0.20.0-next.0': + '@3sixty/immutable-proof-service@0.20.0-next.1': dependencies: '@3sixty/api-models': 0.20.0-next.1 '@3sixty/background-task-models': 0.20.0-next.1 @@ -7225,27 +7258,27 @@ snapshots: '@3sixty/entity': 0.20.0-next.2 '@3sixty/entity-storage-models': 0.20.0-next.1 '@3sixty/event-bus-models': 0.20.0-next.1 - '@3sixty/identity-models': 0.20.0-next.0 - '@3sixty/immutable-proof-models': 0.20.0-next.0 - '@3sixty/immutable-proof-task': 0.20.0-next.0 + '@3sixty/identity-models': 0.20.0-next.1 + '@3sixty/immutable-proof-models': 0.20.0-next.1 + '@3sixty/immutable-proof-task': 0.20.0-next.1 '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/notarization-models': 0.20.0-next.0 + '@3sixty/notarization-models': 0.20.0-next.1 '@3sixty/standards-w3c-did': 0.20.0-next.2 '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/immutable-proof-task@0.20.0-next.0': + '@3sixty/immutable-proof-task@0.20.0-next.1': dependencies: '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/data-json-ld': 0.20.0-next.3 - '@3sixty/identity-models': 0.20.0-next.0 - '@3sixty/immutable-proof-models': 0.20.0-next.0 + '@3sixty/identity-models': 0.20.0-next.1 + '@3sixty/immutable-proof-models': 0.20.0-next.1 '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/modules': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/notarization-models': 0.20.0-next.0 + '@3sixty/notarization-models': 0.20.0-next.1 '@3sixty/standards-w3c-did': 0.20.0-next.2 '@3sixty/logging-connector-console@0.20.0-next.1': @@ -7490,23 +7523,23 @@ snapshots: '@3sixty/nameof@0.20.0-next.2': {} - '@3sixty/nft-connector-entity-storage@0.20.0-next.0': + '@3sixty/nft-connector-entity-storage@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 '@3sixty/entity-storage-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/nft-models': 0.20.0-next.0 + '@3sixty/nft-models': 0.20.0-next.1 - '@3sixty/nft-connector-iota@0.20.0-next.0(typescript@6.0.3)': + '@3sixty/nft-connector-iota@0.20.0-next.1(typescript@6.0.3)': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/dlt-account': 0.20.0-next.1 '@3sixty/dlt-iota': 0.20.0-next.1(typescript@6.0.3) '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/nft-models': 0.20.0-next.0 + '@3sixty/nft-models': 0.20.0-next.1 '@3sixty/vault-models': 0.20.0-next.1 transitivePeerDependencies: - '@gql.tada/svelte-support' @@ -7514,14 +7547,14 @@ snapshots: - encoding - typescript - '@3sixty/nft-models@0.20.0-next.0': + '@3sixty/nft-models@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/nft-rest-client@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/nft-rest-client@0.20.0-next.1(supports-color@10.2.2)': dependencies: '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) '@3sixty/api-models': 0.20.0-next.1 @@ -7534,18 +7567,18 @@ snapshots: - supports-color - utf-8-validate - '@3sixty/nft-service@0.20.0-next.0': + '@3sixty/nft-service@0.20.0-next.1': dependencies: '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/nft-models': 0.20.0-next.0 + '@3sixty/nft-models': 0.20.0-next.1 '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/notarization-connector-entity-storage@0.20.0-next.0': + '@3sixty/notarization-connector-entity-storage@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 @@ -7553,16 +7586,16 @@ snapshots: '@3sixty/entity-storage-models': 0.20.0-next.1 '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/notarization-models': 0.20.0-next.0 + '@3sixty/notarization-models': 0.20.0-next.1 - '@3sixty/notarization-connector-iota@0.20.0-next.0(typescript@6.0.3)': + '@3sixty/notarization-connector-iota@0.20.0-next.1(typescript@6.0.3)': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/dlt-account': 0.20.0-next.1 '@3sixty/dlt-iota': 0.20.0-next.1(typescript@6.0.3) '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/notarization-models': 0.20.0-next.0 + '@3sixty/notarization-models': 0.20.0-next.1 '@3sixty/vault-models': 0.20.0-next.1 '@iota/iota-sdk': 1.15.0(typescript@6.0.3) '@iota/notarization': 0.1.14(@iota/iota-sdk@1.15.0(typescript@6.0.3)) @@ -7572,14 +7605,14 @@ snapshots: - encoding - typescript - '@3sixty/notarization-models@0.20.0-next.0': + '@3sixty/notarization-models@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/notarization-rest-client@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/notarization-rest-client@0.20.0-next.1(supports-color@10.2.2)': dependencies: '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) '@3sixty/api-models': 0.20.0-next.1 @@ -7592,32 +7625,32 @@ snapshots: - supports-color - utf-8-validate - '@3sixty/notarization-service@0.20.0-next.0': + '@3sixty/notarization-service@0.20.0-next.1': dependencies: '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/notarization-models': 0.20.0-next.0 + '@3sixty/notarization-models': 0.20.0-next.1 '@3sixty/telemetry-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/rights-management-models@0.20.0-next.0': + '@3sixty/rights-management-models@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/data-json-ld': 0.20.0-next.3 - '@3sixty/engine-models': 0.20.0-next.1 + '@3sixty/engine-models': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 - '@3sixty/identity-models': 0.20.0-next.0 + '@3sixty/identity-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 '@3sixty/standards-w3c-did': 0.20.0-next.2 '@3sixty/standards-w3c-odrl': 0.20.0-next.2 - '@3sixty/trust-models': 0.20.0-next.0 + '@3sixty/trust-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/rights-management-pap-service@0.20.0-next.0': + '@3sixty/rights-management-pap-service@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 @@ -7626,63 +7659,63 @@ snapshots: '@3sixty/entity-storage-models': 0.20.0-next.1 '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/rights-management-models': 0.20.0-next.0 + '@3sixty/rights-management-models': 0.20.0-next.1 '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 '@3sixty/standards-w3c-odrl': 0.20.0-next.2 - '@3sixty/rights-management-pdp-service@0.20.0-next.0': + '@3sixty/rights-management-pdp-service@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/rights-management-models': 0.20.0-next.0 + '@3sixty/rights-management-models': 0.20.0-next.1 '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 '@3sixty/standards-w3c-odrl': 0.20.0-next.2 - '@3sixty/rights-management-pep-service@0.20.0-next.0': + '@3sixty/rights-management-pep-service@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/rights-management-models': 0.20.0-next.0 + '@3sixty/rights-management-models': 0.20.0-next.1 '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 '@3sixty/standards-w3c-odrl': 0.20.0-next.2 - '@3sixty/rights-management-pip-service@0.20.0-next.0': + '@3sixty/rights-management-pip-service@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/data-json-ld': 0.20.0-next.3 - '@3sixty/identity-models': 0.20.0-next.0 + '@3sixty/identity-models': 0.20.0-next.1 '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/rights-management-models': 0.20.0-next.0 + '@3sixty/rights-management-models': 0.20.0-next.1 '@3sixty/standards-w3c-odrl': 0.20.0-next.2 - '@3sixty/rights-management-plugins@0.20.0-next.0': + '@3sixty/rights-management-plugins@0.20.0-next.1': dependencies: '@3sixty/automation-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/data-json-path': 0.20.0-next.3 - '@3sixty/identity-models': 0.20.0-next.0 + '@3sixty/identity-models': 0.20.0-next.1 '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/rights-management-models': 0.20.0-next.0 + '@3sixty/rights-management-models': 0.20.0-next.1 '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 '@3sixty/standards-w3c-odrl': 0.20.0-next.2 - '@3sixty/rights-management-pmp-service@0.20.0-next.0': + '@3sixty/rights-management-pmp-service@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/rights-management-models': 0.20.0-next.0 + '@3sixty/rights-management-models': 0.20.0-next.1 - '@3sixty/rights-management-pnp-service@0.20.0-next.0': + '@3sixty/rights-management-pnp-service@0.20.0-next.1': dependencies: '@3sixty/api-models': 0.20.0-next.1 '@3sixty/background-task-models': 0.20.0-next.1 @@ -7692,21 +7725,21 @@ snapshots: '@3sixty/entity-storage-models': 0.20.0-next.1 '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/rights-management-models': 0.20.0-next.0 + '@3sixty/rights-management-models': 0.20.0-next.1 '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 '@3sixty/standards-w3c-did': 0.20.0-next.2 '@3sixty/standards-w3c-odrl': 0.20.0-next.2 - '@3sixty/trust-models': 0.20.0-next.0 + '@3sixty/trust-models': 0.20.0-next.1 - '@3sixty/rights-management-pxp-service@0.20.0-next.0': + '@3sixty/rights-management-pxp-service@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/rights-management-models': 0.20.0-next.0 + '@3sixty/rights-management-models': 0.20.0-next.1 '@3sixty/standards-w3c-odrl': 0.20.0-next.2 - '@3sixty/rights-management-rest-client@0.20.0-next.0(supports-color@10.2.2)': + '@3sixty/rights-management-rest-client@0.20.0-next.1(supports-color@10.2.2)': dependencies: '@3sixty/api-core': 0.20.0-next.1(supports-color@10.2.2) '@3sixty/api-models': 0.20.0-next.1 @@ -7715,7 +7748,7 @@ snapshots: '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/rights-management-models': 0.20.0-next.0 + '@3sixty/rights-management-models': 0.20.0-next.1 '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 '@3sixty/standards-w3c-did': 0.20.0-next.2 '@3sixty/web': 0.20.0-next.2 @@ -7724,14 +7757,14 @@ snapshots: - supports-color - utf-8-validate - '@3sixty/rights-management-service@0.20.0-next.0': + '@3sixty/rights-management-service@0.20.0-next.1': dependencies: '@3sixty/api-models': 0.20.0-next.1 '@3sixty/context': 0.20.0-next.2 '@3sixty/core': 0.20.0-next.2 '@3sixty/entity': 0.20.0-next.2 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/rights-management-models': 0.20.0-next.0 + '@3sixty/rights-management-models': 0.20.0-next.1 '@3sixty/standards-dataspace-protocol': 0.20.0-next.2 '@3sixty/standards-w3c-did': 0.20.0-next.2 '@3sixty/standards-w3c-odrl': 0.20.0-next.2 @@ -7977,39 +8010,39 @@ snapshots: '@3sixty/tracing-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/trust-generators@0.20.0-next.0': + '@3sixty/trust-generators@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/data-json-ld': 0.20.0-next.3 - '@3sixty/identity-models': 0.20.0-next.0 + '@3sixty/identity-models': 0.20.0-next.1 '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/trust-models': 0.20.0-next.0 + '@3sixty/trust-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 - '@3sixty/trust-models@0.20.0-next.0': + '@3sixty/trust-models@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 '@3sixty/data-json-ld': 0.20.0-next.3 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/trust-service@0.20.0-next.0': + '@3sixty/trust-service@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/trust-models': 0.20.0-next.0 + '@3sixty/trust-models': 0.20.0-next.1 - '@3sixty/trust-verifiers@0.20.0-next.0': + '@3sixty/trust-verifiers@0.20.0-next.1': dependencies: '@3sixty/core': 0.20.0-next.2 '@3sixty/crypto': 0.20.0-next.2 '@3sixty/data-json-ld': 0.20.0-next.3 - '@3sixty/identity-models': 0.20.0-next.0 + '@3sixty/identity-models': 0.20.0-next.1 '@3sixty/logging-models': 0.20.0-next.1 '@3sixty/nameof': 0.20.0-next.2 - '@3sixty/trust-models': 0.20.0-next.0 + '@3sixty/trust-models': 0.20.0-next.1 '@3sixty/web': 0.20.0-next.2 '@3sixty/ts-to-openapi@0.20.0-next.4': @@ -8989,12 +9022,12 @@ snapshots: '@fastify/compress@9.2.2': dependencies: '@fastify/accept-negotiator': 2.1.1 - fastify-plugin: 6.0.0 + fastify-plugin: 6.0.1 mime-db: 1.54.0 '@fastify/cors@11.3.1': dependencies: - fastify-plugin: 6.0.0 + fastify-plugin: 6.0.1 toad-cache: 3.7.4 '@fastify/deepmerge@3.2.2': {} @@ -9110,6 +9143,10 @@ snapshots: protobufjs: 7.6.6 yargs: 17.7.3 + '@hono/node-server@2.1.3(hono@4.13.13)': + dependencies: + hono: 4.13.13 + '@humanfs/core@0.19.2': dependencies: '@humanfs/types': 0.15.0 @@ -10064,6 +10101,8 @@ snapshots: base64-js@1.5.1: {} + base64id@2.0.0: {} + baseline-browser-mapping@2.11.30: {} before-after-hook@2.2.3: {} @@ -10187,12 +10226,6 @@ snapshots: ci-info@4.4.0: {} - cliui@7.0.4: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - cliui@8.0.1: dependencies: string-width: 4.2.3 @@ -10278,22 +10311,10 @@ snapshots: cookie@2.0.1: {} - copyfiles@2.4.1: - dependencies: - glob: 7.2.3 - minimatch: 3.1.5 - mkdirp: 1.0.4 - noms: 0.0.0 - through2: 2.0.5 - untildify: 4.0.0 - yargs: 16.2.2 - core-js-compat@3.51.0: dependencies: browserslist: 4.29.4 - core-util-is@1.0.3: {} - cors@2.8.6: dependencies: object-assign: 4.1.1 @@ -10832,8 +10853,6 @@ snapshots: strnum: 2.5.1 xml-naming: 0.3.0 - fastify-plugin@6.0.0: {} - fastify-plugin@6.0.1: {} fastify@5.12.7: @@ -10924,8 +10943,6 @@ snapshots: dependencies: fetch-blob: 3.2.0 - fs.realpath@1.0.0: {} - fsevents@2.3.3: optional: true @@ -11029,15 +11046,6 @@ snapshots: minipass: 7.1.3 path-scurry: 2.0.2 - glob@7.2.3: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.5 - once: 1.4.0 - path-is-absolute: 1.0.1 - global-directory@5.0.0: dependencies: ini: 6.0.0 @@ -11187,6 +11195,8 @@ snapshots: he@1.2.0: {} + hono@4.13.13: {} + hookified@1.15.1: {} hookified@2.2.0: {} @@ -11256,11 +11266,6 @@ snapshots: indent-string@5.0.0: {} - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - inherits@2.0.4: {} ini@6.0.0: {} @@ -11323,10 +11328,6 @@ snapshots: is-unsafe@2.0.2: {} - isarray@0.0.1: {} - - isarray@1.0.0: {} - isexe@2.0.0: {} jackspeak@3.4.3: @@ -11898,8 +11899,6 @@ snapshots: minipass@7.1.3: {} - mkdirp@1.0.4: {} - mnemonist@0.38.3: dependencies: obliterator: 1.6.1 @@ -11984,11 +11983,6 @@ snapshots: touch: 3.1.1 undefsafe: 2.0.5 - noms@0.0.0: - dependencies: - inherits: 2.0.4 - readable-stream: 1.0.34 - normalize-package-data@2.5.0: dependencies: hosted-git-info: 2.8.9 @@ -12095,8 +12089,6 @@ snapshots: path-expression-matcher@1.6.2: {} - path-is-absolute@1.0.1: {} - path-key@3.1.1: {} path-parse@1.0.7: {} @@ -12173,8 +12165,6 @@ snapshots: priorityqueuejs@2.0.0: {} - process-nextick-args@2.0.1: {} - process-warning@5.1.1: {} proto3-json-serializer@3.0.4: @@ -12246,23 +12236,6 @@ snapshots: parse-json: 5.2.0 type-fest: 0.6.0 - readable-stream@1.0.34: - dependencies: - core-util-is: 1.0.3 - inherits: 2.0.4 - isarray: 0.0.1 - string_decoder: 0.10.31 - - readable-stream@2.3.8: - dependencies: - core-util-is: 1.0.3 - inherits: 2.0.4 - isarray: 1.0.0 - process-nextick-args: 2.0.1 - safe-buffer: 5.1.2 - string_decoder: 1.1.1 - util-deprecate: 1.0.2 - readable-stream@3.6.2: dependencies: inherits: 2.0.4 @@ -12406,8 +12379,6 @@ snapshots: dependencies: mri: 1.2.0 - safe-buffer@5.1.2: {} - safe-buffer@5.2.1: {} safe-regex2@5.1.2: @@ -12515,6 +12486,20 @@ snapshots: transitivePeerDependencies: - supports-color + socket.io@4.8.3(supports-color@10.2.2): + dependencies: + accepts: 1.3.8 + base64id: 2.0.0 + cors: 2.8.6 + debug: 4.4.3(supports-color@10.2.2) + engine.io: 6.6.11(supports-color@10.2.2) + socket.io-adapter: 2.5.8(supports-color@10.2.2) + socket.io-parser: 4.2.7(supports-color@10.2.2) + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + socket.io@4.8.4(supports-color@10.2.2): dependencies: accepts: 1.3.8 @@ -12610,12 +12595,6 @@ snapshots: get-east-asian-width: 1.7.0 strip-ansi: 7.2.0 - string_decoder@0.10.31: {} - - string_decoder@1.1.1: - dependencies: - safe-buffer: 5.1.2 - string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 @@ -12681,11 +12660,6 @@ snapshots: dependencies: real-require: 1.0.0 - through2@2.0.5: - dependencies: - readable-stream: 2.3.8 - xtend: 4.0.2 - through@2.3.8: {} tinybench@6.2.2: {} @@ -12840,8 +12814,6 @@ snapshots: '@unrs/resolver-binding-win32-ia32-msvc': 1.12.2 '@unrs/resolver-binding-win32-x64-msvc': 1.12.2 - untildify@4.0.0: {} - update-browserslist-db@1.3.4(browserslist@4.29.4): dependencies: browserslist: 4.29.4 @@ -12972,8 +12944,6 @@ snapshots: xpath@0.0.34: {} - xtend@4.0.2: {} - y18n@5.0.8: {} yallist@4.0.0: {} @@ -12986,16 +12956,6 @@ snapshots: yargs-parser@22.0.0: {} - yargs@16.2.2: - dependencies: - cliui: 7.0.4 - escalade: 3.2.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 20.2.9 - yargs@17.7.3: dependencies: cliui: 8.0.1