diff --git a/.github/workflows/backend_publish_release_candidate.yml b/.github/workflows/backend_publish_release_candidate.yml index 3aad151fd5..993a52c01c 100644 --- a/.github/workflows/backend_publish_release_candidate.yml +++ b/.github/workflows/backend_publish_release_candidate.yml @@ -28,6 +28,11 @@ jobs: PROJECT_VERSION: ${{ inputs.project_version || github.event.inputs.project_version }} SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} + # Required: backend/gradle/publishing-module.gradle only applies the 'signing' + # plugin when both of these are set. Without them nothing produces .asc files + # and Sonatype rejects every component with "Missing signature for file". + SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD }} + SIGNING_KEY_BASE64: ${{ secrets.SIGNING_KEY_BASE64 }} JRELEASER_MAVENCENTRAL_sonatype_STAGE: UPLOAD steps: diff --git a/.github/workflows/frontend_build_push_docker_image.yml b/.github/workflows/frontend_build_push_docker_image.yml index 9cc439e65e..d5a3893107 100644 --- a/.github/workflows/frontend_build_push_docker_image.yml +++ b/.github/workflows/frontend_build_push_docker_image.yml @@ -177,10 +177,13 @@ jobs: npm install - # The app bundles @valtimo/shared's versions.ts from source (via - # tsconfig.paths), so stamp the version into that source file here — the - # libs build's version bump happens on a different runner and never reaches - # this checkout. No-op when project_version is empty (keeps committed value). + # The libs build's version bump happens on a different runner and never + # reaches this checkout, so stamp the version here. Release builds resolve + # @valtimo/* through node_modules -> dist (see apps/*/src/tsconfig.app.prod.json), + # so the compiled constant in dist is what ends up in the app bundle; the + # source versions.ts is stamped too so branches that still bundle the + # libraries from source keep working. + # No-op when project_version is empty (keeps committed value). - name: Stamp frontend version if: ${{ inputs.project_version != '' }} shell: bash @@ -188,15 +191,20 @@ jobs: PROJECT_VERSION: ${{ inputs.project_version }} run: | set -euo pipefail + stamped=0 # versions.ts location differs per branch (shared/ on v13, config/ on # v12); locate the one holding frontendLibraries so this works on both. - f=$(grep -rl 'frontendLibraries' projects/valtimo --include='versions.ts' 2>/dev/null | head -1 || true) - if [ -z "$f" ]; then - echo "::warning::no versions.ts with frontendLibraries found; skipping frontend version stamp" - exit 0 + # The compiled copy is found the same way, by grepping dist. + for f in \ + $(grep -rl 'frontendLibraries' projects/valtimo --include='versions.ts' 2>/dev/null || true) \ + $(grep -rl "frontendLibraries: *'" dist/valtimo --include='*.mjs' 2>/dev/null || true); do + sed -i "s/\(frontendLibraries: *'\)[^']*'/\1${PROJECT_VERSION}'/" "$f" + echo "Stamped $f:"; grep -o "frontendLibraries: *'[^']*'" "$f" || true + stamped=1 + done + if [ "$stamped" -eq 0 ]; then + echo "::warning::no frontendLibraries constant found; skipping frontend version stamp" fi - sed -i "s/\(frontendLibraries: *'\)[^']*'/\1${PROJECT_VERSION}'/" "$f" - echo "Stamped $f:"; grep frontendLibraries "$f" || true - name: Build app run: npm run build:${{ inputs.variant }} diff --git a/backend/apps/evenementenvergunning/src/main/resources/config/global/permission/all.permission.json b/backend/apps/evenementenvergunning/src/main/resources/config/global/permission/all.permission.json new file mode 100644 index 0000000000..40a24b0fe4 --- /dev/null +++ b/backend/apps/evenementenvergunning/src/main/resources/config/global/permission/all.permission.json @@ -0,0 +1,167 @@ +[ + { + "resourceType": "com.ritense.case.domain.CaseTab", + "actions": [ + "view" + ], + "roleKey": "ROLE_ADMIN" + }, + { + "resourceType": "com.ritense.case_.domain.definition.CaseDefinition", + "actions": [ + "view", + "view_list" + ], + "roleKey": "ROLE_ADMIN" + }, + { + "resourceType": "com.ritense.case_.domain.tab.CaseWidgetTabWidget", + "actions": [ + "view" + ], + "roleKey": "ROLE_ADMIN" + }, + { + "resourceType": "com.ritense.dashboard.domain.Dashboard", + "actions": [ + "view", + "view_list" + ], + "roleKey": "ROLE_ADMIN" + }, + { + "resourceType": "com.ritense.document.domain.impl.JsonSchemaDocument", + "actions": [ + "view", + "view_list", + "create", + "modify", + "delete", + "claim", + "assign", + "assignable", + "export", + "inspect", + "inspect_modify" + ], + "roleKey": "ROLE_ADMIN" + }, + { + "resourceType": "com.ritense.document.domain.impl.JsonSchemaDocumentDefinition", + "actions": [ + "view", + "view_list", + "create", + "modify", + "delete" + ], + "roleKey": "ROLE_ADMIN" + }, + { + "resourceType": "com.ritense.document.domain.impl.searchfield.SearchField", + "actions": [ + "view_list" + ], + "roleKey": "ROLE_ADMIN" + }, + { + "resourceType": "com.ritense.document.domain.impl.snapshot.JsonSchemaDocumentSnapshot", + "actions": [ + "view", + "view_list" + ], + "roleKey": "ROLE_ADMIN" + }, + { + "resourceType": "com.ritense.documentenapi.authorization.ZgwDocument", + "actions": [ + "view", + "view_list", + "create", + "modify", + "delete" + ], + "roleKey": "ROLE_ADMIN" + }, + { + "resourceType": "com.ritense.iko.domain.IkoView", + "actions": [ + "view", + "view_list" + ], + "roleKey": "ROLE_ADMIN" + }, + { + "resourceType": "com.ritense.note.domain.Note", + "actions": [ + "view_list", + "create", + "modify", + "delete" + ], + "roleKey": "ROLE_ADMIN" + }, + { + "resourceType": "com.ritense.objectenapi.security.Object", + "actions": [ + "view", + "view_list", + "create", + "modify", + "delete" + ], + "roleKey": "ROLE_ADMIN" + }, + { + "resourceType": "com.ritense.objectmanagement.domain.ObjectManagement", + "actions": [ + "view_list" + ], + "roleKey": "ROLE_ADMIN" + }, + { + "resourceType": "com.ritense.resource.authorization.ResourcePermission", + "actions": [ + "view", + "view_list", + "create", + "modify", + "delete" + ], + "roleKey": "ROLE_ADMIN" + }, + { + "resourceType": "com.ritense.valtimo.operaton.domain.OperatonExecution", + "actions": [ + "create" + ], + "roleKey": "ROLE_ADMIN" + }, + { + "resourceType": "com.ritense.valtimo.operaton.domain.OperatonTask", + "actions": [ + "view", + "view_list", + "modify", + "assign", + "assignable", + "claim", + "complete" + ], + "roleKey": "ROLE_ADMIN" + }, + { + "resourceType": "com.ritense.valtimo.operaton.domain.OperatonTimer", + "actions": [ + "complete" + ], + "roleKey": "ROLE_ADMIN" + }, + { + "resourceType": "com.ritense.zakenapi.security.Zaak", + "actions": [ + "view" + ], + "roleKey": "ROLE_ADMIN" + } +] diff --git a/backend/apps/evenementenvergunning/src/main/resources/config/global/role/all.role.json b/backend/apps/evenementenvergunning/src/main/resources/config/global/role/all.role.json new file mode 100644 index 0000000000..37aed18471 --- /dev/null +++ b/backend/apps/evenementenvergunning/src/main/resources/config/global/role/all.role.json @@ -0,0 +1,4 @@ +[ + "ROLE_USER", + "ROLE_ADMIN" +] diff --git a/backend/apps/evenementenvergunning/src/main/resources/config/pbac/all.permission.json b/backend/apps/evenementenvergunning/src/main/resources/config/pbac/all.permission.json deleted file mode 100644 index 791b72c0c6..0000000000 --- a/backend/apps/evenementenvergunning/src/main/resources/config/pbac/all.permission.json +++ /dev/null @@ -1,242 +0,0 @@ -{ - "changesetId": "permissions-v3", - "permissions": [ - { - "resourceType": "com.ritense.case_.domain.definition.CaseDefinition", - "action": "view", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.case_.domain.definition.CaseDefinition", - "action": "view_list", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.valtimo.operaton.domain.OperatonExecution", - "action": "create", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.case.domain.CaseTab", - "action": "view", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.case_.domain.tab.CaseWidgetTabWidget", - "action": "view", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.document.domain.impl.JsonSchemaDocument", - "action": "view", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.document.domain.impl.JsonSchemaDocument", - "action": "view_list", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.document.domain.impl.JsonSchemaDocument", - "action": "create", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.document.domain.impl.JsonSchemaDocument", - "action": "modify", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.document.domain.impl.JsonSchemaDocument", - "action": "delete", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.document.domain.impl.JsonSchemaDocument", - "action": "claim", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.document.domain.impl.JsonSchemaDocument", - "action": "assignable", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.document.domain.impl.JsonSchemaDocument", - "action": "assign", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.document.domain.impl.JsonSchemaDocumentDefinition", - "action": "delete", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.document.domain.impl.JsonSchemaDocumentDefinition", - "action": "view_list", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.document.domain.impl.JsonSchemaDocumentDefinition", - "action": "create", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.document.domain.impl.JsonSchemaDocumentDefinition", - "action": "modify", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.document.domain.impl.JsonSchemaDocumentDefinition", - "action": "view", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.document.domain.impl.searchfield.SearchField", - "action": "view_list", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.document.domain.impl.snapshot.JsonSchemaDocumentSnapshot", - "action": "view", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.document.domain.impl.snapshot.JsonSchemaDocumentSnapshot", - "action": "view_list", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.note.domain.Note", - "action": "modify", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.note.domain.Note", - "action": "view_list", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.note.domain.Note", - "action": "create", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.note.domain.Note", - "action": "delete", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.valtimo.operaton.domain.OperatonTask", - "action": "assign", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.valtimo.operaton.domain.OperatonTask", - "action": "assignable", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.valtimo.operaton.domain.OperatonTask", - "action": "claim", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.valtimo.operaton.domain.OperatonTask", - "action": "complete", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.valtimo.operaton.domain.OperatonTask", - "action": "view_list", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.valtimo.operaton.domain.OperatonTask", - "action": "view", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.resource.authorization.ResourcePermission", - "action": "create", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.resource.authorization.ResourcePermission", - "action": "view_list", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.resource.authorization.ResourcePermission", - "action": "view", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.resource.authorization.ResourcePermission", - "action": "modify", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.resource.authorization.ResourcePermission", - "action": "delete", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.objectenapi.security.Object", - "action": "view", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.objectenapi.security.Object", - "action": "view_list", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.objectenapi.security.Object", - "action": "modify", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.objectenapi.security.Object", - "action": "delete", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.objectenapi.security.Object", - "action": "create", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.dashboard.domain.Dashboard", - "action": "view", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.dashboard.domain.Dashboard", - "action": "view_list", - "roleKey": "ROLE_ADMIN" - }, - { - "resourceType": "com.ritense.team.domain.Team", - "actions": [ - "modify", - "view_list", - "assign", - "create", - "delete", - "view" - ], - "conditions": [], - "roleKey": "ROLE_USER" - }, - { - "resourceType": "com.ritense.valtimo.contract.authentication.User", - "actions": [ - "view_list", - "view" - ], - "conditions": [], - "roleKey": "ROLE_USER" - } - ] -} diff --git a/backend/apps/evenementenvergunning/src/main/resources/config/pbac/all.role.json b/backend/apps/evenementenvergunning/src/main/resources/config/pbac/all.role.json deleted file mode 100644 index b755bfa52f..0000000000 --- a/backend/apps/evenementenvergunning/src/main/resources/config/pbac/all.role.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "changesetId": "roles-v1", - "roles": [ - "ROLE_USER", - "ROLE_ADMIN" - ] -} \ No newline at end of file diff --git a/backend/apps/valtimo/src/main/resources/config/application.yml b/backend/apps/valtimo/src/main/resources/config/application.yml index ae35894788..0f2791e3eb 100644 --- a/backend/apps/valtimo/src/main/resources/config/application.yml +++ b/backend/apps/valtimo/src/main/resources/config/application.yml @@ -177,9 +177,6 @@ valtimo: plugin: encryption-secret: ${VALTIMO_PLUGIN_ENCRYPTIONSECRET} database: postgres - changelog: - pbac: - clear-tables: true security: whitelist: hosts: diff --git a/backend/building-block/src/main/kotlin/com/ritense/buildingblock/web/rest/BuildingBlockValueResolverResource.kt b/backend/building-block/src/main/kotlin/com/ritense/buildingblock/web/rest/BuildingBlockValueResolverResource.kt index 996cdc1e3a..75fc6c7e15 100644 --- a/backend/building-block/src/main/kotlin/com/ritense/buildingblock/web/rest/BuildingBlockValueResolverResource.kt +++ b/backend/building-block/src/main/kotlin/com/ritense/buildingblock/web/rest/BuildingBlockValueResolverResource.kt @@ -16,6 +16,7 @@ package com.ritense.buildingblock.web.rest +import com.ritense.authorization.annotation.RunWithoutAuthorization import com.ritense.valtimo.contract.annotation.SkipComponentScan import com.ritense.valtimo.contract.buildingblock.BuildingBlockDefinitionId import com.ritense.valtimo.contract.domain.ValtimoMediaType.APPLICATION_JSON_UTF8_VALUE @@ -37,6 +38,7 @@ class BuildingBlockValueResolverResource( private val valueResolverService: ValueResolverService ) { + @RunWithoutAuthorization @PostMapping("/management/v1/value-resolver/building-block/{buildingBlockDefinitionKey}/version/{buildingBlockDefinitionVersionTag}/keys") fun getResolvableKeys( @PathVariable buildingBlockDefinitionKey: String, diff --git a/backend/core/src/main/kotlin/com/ritense/valtimo/operaton/authorization/OperatonTaskActionProvider.kt b/backend/core/src/main/kotlin/com/ritense/valtimo/operaton/authorization/OperatonTaskActionProvider.kt index 18d6e9680a..31edf8b13b 100644 --- a/backend/core/src/main/kotlin/com/ritense/valtimo/operaton/authorization/OperatonTaskActionProvider.kt +++ b/backend/core/src/main/kotlin/com/ritense/valtimo/operaton/authorization/OperatonTaskActionProvider.kt @@ -22,7 +22,7 @@ import com.ritense.valtimo.operaton.domain.OperatonTask class OperatonTaskActionProvider : ResourceActionProvider { override fun getAvailableActions(): List> { - return listOf(ASSIGN, ASSIGNABLE, CLAIM, COMPLETE, VIEW_LIST, VIEW) + return listOf(ASSIGN, ASSIGNABLE, CLAIM, COMPLETE, VIEW_LIST, VIEW, MODIFY) } companion object { diff --git a/backend/value-resolver/build.gradle b/backend/value-resolver/build.gradle index 7f74da06d0..2f72c18686 100644 --- a/backend/value-resolver/build.gradle +++ b/backend/value-resolver/build.gradle @@ -36,6 +36,11 @@ dockerCompose { } dependencies { + // Only needed to compile the @RunWithoutAuthorization annotation on the management endpoints. + // Kept off the runtime classpath so this low-level module does not drag + // AuthorizationAutoConfiguration into every consumer's context; the applications that host + // these endpoints always have :backend:authorization, so the aspect is there to intercept. + compileOnly(project(":backend:authorization")) implementation(project(":backend:contract")) implementation(project(":backend:logging")) diff --git a/backend/value-resolver/src/main/kotlin/com/ritense/valueresolver/web/rest/ValueResolverResource.kt b/backend/value-resolver/src/main/kotlin/com/ritense/valueresolver/web/rest/ValueResolverResource.kt index 080f1273a2..21ba1f947f 100644 --- a/backend/value-resolver/src/main/kotlin/com/ritense/valueresolver/web/rest/ValueResolverResource.kt +++ b/backend/value-resolver/src/main/kotlin/com/ritense/valueresolver/web/rest/ValueResolverResource.kt @@ -16,6 +16,7 @@ package com.ritense.valueresolver.web.rest +import com.ritense.authorization.annotation.RunWithoutAuthorization import com.ritense.valtimo.contract.annotation.SkipComponentScan import com.ritense.valtimo.contract.case_.CaseDefinitionId import com.ritense.valtimo.contract.domain.ValtimoMediaType.APPLICATION_JSON_UTF8_VALUE @@ -38,11 +39,13 @@ import org.springframework.web.bind.annotation.RestController class ValueResolverResource( private val valueResolverService: ValueResolverService ) { + @RunWithoutAuthorization @GetMapping("/management/v1/value-resolver") fun getValueResolvers(): ResponseEntity> { return ResponseEntity.ok(valueResolverService.getValueResolvers()) } + @RunWithoutAuthorization @PostMapping("/management/v1/value-resolver/case-definition/{caseDefinitionKey}/keys") fun getResolvableKeys( @PathVariable caseDefinitionKey: String, @@ -51,6 +54,7 @@ class ValueResolverResource( return ResponseEntity.ok(valueResolverService.getResolvableKeys(request, caseDefinitionKey)) } + @RunWithoutAuthorization @PostMapping("/management/v1/value-resolver/case-definition/{caseDefinitionKey}/version/{caseDefinitionVersionTag}/keys") fun getResolvableKeys( @PathVariable caseDefinitionKey: String, diff --git a/frontend/angular.json b/frontend/angular.json index d9d9f72875..fef91d1bda 100644 --- a/frontend/angular.json +++ b/frontend/angular.json @@ -105,6 +105,7 @@ }, "configurations": { "production": { + "tsConfig": "apps/dev/src/tsconfig.app.prod.json", "fileReplacements": [ { "replace": "apps/dev/src/environments/environment.ts", @@ -299,6 +300,7 @@ }, "configurations": { "production": { + "tsConfig": "apps/gzac/src/tsconfig.app.prod.json", "fileReplacements": [ { "replace": "apps/gzac/src/environments/environment.ts", @@ -489,6 +491,7 @@ }, "configurations": { "production": { + "tsConfig": "apps/valtimo/src/tsconfig.app.prod.json", "fileReplacements": [ { "replace": "apps/valtimo/src/environments/environment.ts", @@ -675,6 +678,7 @@ }, "configurations": { "production": { + "tsConfig": "apps/evenementenvergunning/src/tsconfig.app.prod.json", "fileReplacements": [ { "replace": "apps/evenementenvergunning/src/environments/environment.ts", diff --git a/frontend/apps/dev/src/tsconfig.app.prod.json b/frontend/apps/dev/src/tsconfig.app.prod.json new file mode 100644 index 0000000000..cc1590570e --- /dev/null +++ b/frontend/apps/dev/src/tsconfig.app.prod.json @@ -0,0 +1,25 @@ +{ + "extends": "./tsconfig.app.json", + "compilerOptions": { + // Release builds deliberately drop the @valtimo/* path mappings from + // tsconfig.json. The @valtimo-plugins/* packages installed from npm import + // '@valtimo/plugin' (and other libs) as bare specifiers, which the bundler + // resolves through node_modules -> the file: links into dist/valtimo/*. If + // the app itself kept resolving those libraries to projects/valtimo/* + // source, the bundle would end up with two compiled copies of every + // library: two InjectionToken instances, two PluginService classes. The + // plugin config token the app module provides is then not the one the + // plugin packages inject, which fails at runtime with + // NullInjectorError: No provider for InjectionToken + // Provide plugin config; an array of plugin specifications. + // + // Without the mappings the app resolves @valtimo/* the same way the plugin + // packages do, so there is exactly one instance of each library. Local dev + // (npm start) is unaffected and keeps using the source mappings. + "paths": { + "@src": ["apps/dev/src"], + "@src/*": ["apps/dev/src/*"], + "@e2e/constants": ["../e2e/constants"] + } + } +} diff --git a/frontend/apps/evenementenvergunning/src/tsconfig.app.prod.json b/frontend/apps/evenementenvergunning/src/tsconfig.app.prod.json new file mode 100644 index 0000000000..cc1590570e --- /dev/null +++ b/frontend/apps/evenementenvergunning/src/tsconfig.app.prod.json @@ -0,0 +1,25 @@ +{ + "extends": "./tsconfig.app.json", + "compilerOptions": { + // Release builds deliberately drop the @valtimo/* path mappings from + // tsconfig.json. The @valtimo-plugins/* packages installed from npm import + // '@valtimo/plugin' (and other libs) as bare specifiers, which the bundler + // resolves through node_modules -> the file: links into dist/valtimo/*. If + // the app itself kept resolving those libraries to projects/valtimo/* + // source, the bundle would end up with two compiled copies of every + // library: two InjectionToken instances, two PluginService classes. The + // plugin config token the app module provides is then not the one the + // plugin packages inject, which fails at runtime with + // NullInjectorError: No provider for InjectionToken + // Provide plugin config; an array of plugin specifications. + // + // Without the mappings the app resolves @valtimo/* the same way the plugin + // packages do, so there is exactly one instance of each library. Local dev + // (npm start) is unaffected and keeps using the source mappings. + "paths": { + "@src": ["apps/dev/src"], + "@src/*": ["apps/dev/src/*"], + "@e2e/constants": ["../e2e/constants"] + } + } +} diff --git a/frontend/apps/gzac/src/tsconfig.app.prod.json b/frontend/apps/gzac/src/tsconfig.app.prod.json new file mode 100644 index 0000000000..cc1590570e --- /dev/null +++ b/frontend/apps/gzac/src/tsconfig.app.prod.json @@ -0,0 +1,25 @@ +{ + "extends": "./tsconfig.app.json", + "compilerOptions": { + // Release builds deliberately drop the @valtimo/* path mappings from + // tsconfig.json. The @valtimo-plugins/* packages installed from npm import + // '@valtimo/plugin' (and other libs) as bare specifiers, which the bundler + // resolves through node_modules -> the file: links into dist/valtimo/*. If + // the app itself kept resolving those libraries to projects/valtimo/* + // source, the bundle would end up with two compiled copies of every + // library: two InjectionToken instances, two PluginService classes. The + // plugin config token the app module provides is then not the one the + // plugin packages inject, which fails at runtime with + // NullInjectorError: No provider for InjectionToken + // Provide plugin config; an array of plugin specifications. + // + // Without the mappings the app resolves @valtimo/* the same way the plugin + // packages do, so there is exactly one instance of each library. Local dev + // (npm start) is unaffected and keeps using the source mappings. + "paths": { + "@src": ["apps/dev/src"], + "@src/*": ["apps/dev/src/*"], + "@e2e/constants": ["../e2e/constants"] + } + } +} diff --git a/frontend/apps/valtimo/src/tsconfig.app.prod.json b/frontend/apps/valtimo/src/tsconfig.app.prod.json new file mode 100644 index 0000000000..cc1590570e --- /dev/null +++ b/frontend/apps/valtimo/src/tsconfig.app.prod.json @@ -0,0 +1,25 @@ +{ + "extends": "./tsconfig.app.json", + "compilerOptions": { + // Release builds deliberately drop the @valtimo/* path mappings from + // tsconfig.json. The @valtimo-plugins/* packages installed from npm import + // '@valtimo/plugin' (and other libs) as bare specifiers, which the bundler + // resolves through node_modules -> the file: links into dist/valtimo/*. If + // the app itself kept resolving those libraries to projects/valtimo/* + // source, the bundle would end up with two compiled copies of every + // library: two InjectionToken instances, two PluginService classes. The + // plugin config token the app module provides is then not the one the + // plugin packages inject, which fails at runtime with + // NullInjectorError: No provider for InjectionToken + // Provide plugin config; an array of plugin specifications. + // + // Without the mappings the app resolves @valtimo/* the same way the plugin + // packages do, so there is exactly one instance of each library. Local dev + // (npm start) is unaffected and keeps using the source mappings. + "paths": { + "@src": ["apps/dev/src"], + "@src/*": ["apps/dev/src/*"], + "@e2e/constants": ["../e2e/constants"] + } + } +} diff --git a/frontend/release-plugins.json b/frontend/release-plugins.json index e176d97027..113af7e9d1 100644 --- a/frontend/release-plugins.json +++ b/frontend/release-plugins.json @@ -1,4 +1,4 @@ { - "@valtimo-plugins/freemarker": "8.5.2", + "@valtimo-plugins/freemarker": "8.5.4", "@valtimo-plugins/smtpmail": "2.0.6" } diff --git a/gradle.properties b/gradle.properties index 4ebd76a34c..fcabd1a797 100644 --- a/gradle.properties +++ b/gradle.properties @@ -100,5 +100,5 @@ semver4jVersion=5.6.0 projectVersion=13.1.3 -freemarkerPluginVersion=8.5.2 +freemarkerPluginVersion=8.5.4 smtpmailPluginVersion=2.0.6