From 18c7e787315935015d9a06cc63baa0aca8c83f4b Mon Sep 17 00:00:00 2001 From: Kistl Date: Tue, 24 Mar 2026 20:00:33 +0100 Subject: [PATCH 1/2] Support upcoming Shell event handler update by enhancing model, schemas and docs --- CHANGELOG.md | 9 +++ docs/events.md | 74 ++++++++++++++++--- package-lock.json | 4 +- package.json | 2 +- src/index.ts | 2 + .../cloud-storage/get-item-request.model.ts | 2 + src/models/index.ts | 1 + .../get-item-request.v2.schema.ts | 12 ++- .../get-feature-flag-request.v1.schema.ts | 2 +- src/validation/schemas/schemas.spec.ts | 6 +- .../get-settings-request.v1.schema.ts | 4 +- 11 files changed, 97 insertions(+), 21 deletions(-) create mode 100644 src/models/cloud-storage/get-item-request.model.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index dd3d9ff..980e310 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.25.0] - 2026-03-25 + +### Added + +- Define and "publish" new model `GetItemRequest` +- Enhance `getItemRequest_v2_schema` to support multiple keys +- Improve schemas `getFeatureFlagRequest_v1_schema` and `getSettingsRequest_v1_schema` by replacing anyOf with oneOf +- Improve documentation for the events `GET_STORAGE_ITEM` and `SET_STORAGE_ITEM` + ## [1.24.0] - 2026-03-23 ### Added diff --git a/docs/events.md b/docs/events.md index a4a8ac5..a76c71f 100644 --- a/docs/events.md +++ b/docs/events.md @@ -28,7 +28,17 @@ Must be sent on application startup to get initial application context from the } ``` - The property `targetOutletName` is added automatically by the FSM-Shell in case the request is sent by an extension inside an outlet. It should not be added by the extension itself. + The property `targetOutletName` is automatically added by the FSM Shell when the request originates from an extension within an outlet. It should not be set manually by the extension. The property `cloudStorageKeys` allows you to register user setting keys that would otherwise not be accessible (see `GET_STORAGE_ITEM` and `SET_STORAGE_ITEM` for more information). + + A `CloudStorageKey` is defined as follows: + + ```typescript + { + name: string; + dataVersion: number; + companyDependent: boolean; + } + ``` * Response payload @@ -305,7 +315,7 @@ Request permissions for specified object from the Shell - ### GET_STORAGE_ITEM -With this event you can get user specific settings. You can find the available settings in the FSM admin page in "Users -> select a user -> User Settings". [Here](https://help.sap.com/viewer/fsm_admin/Cloud/en-US/users.html) you can find more information about users. +Retrieve user-specific settings from cloud storage. Available settings can be found in the FSM Admin page under "Users -> select a user -> User Settings". More details: [User Documentation](https://help.sap.com/viewer/fsm_admin/Cloud/en-US/users.html) @@ -315,17 +325,21 @@ With this event you can get user specific settings. You can find the available s SHELL_EVENTS.Version2.GET_STORAGE_ITEM ``` -Request value stored under specified key in cloud storage +Requests values stored under one or more keys in cloud storage. - Request payload - type: string - Key to read value from + type: GetItemRequest + Key(s) to read value from: + + ```typescript + string | string[] + ``` - Response payload type: GetItemResponse\ - object containing key name and value which was read from requested key + Returns key-value pairs for each requested key: ```typescript { @@ -348,7 +362,7 @@ Request value stored under specified key in cloud storage SHELL_EVENTS.Version1.GET_STORAGE_ITEM ``` -Request value stored under specified key in cloud storage +Requests a value stored under a single key in cloud storage. - Request payload @@ -364,12 +378,36 @@ Request value stored under specified key in cloud storage -> Note: Below in the table you can see some common keys. +Currently, the following keys are supported out of the box: -| Key | value type | Description | -| --------------------------- | ---------- | ------------------------------------ | -| Cockpit_SelectedCompanyName | string | Name of the current selected company | -| Cockpit_SelectedLocale | string | Current selected locale | +| Key | value type | company-dependent | Description | +| ------------------------------- | ---------- | ----------------- | ------------------------------------ | +| Cockpit_SelectedCompanyName | string | no | Name of the current selected company | +| Cockpit_SelectedLanguage | string | no | Current selected language code | +| Cockpit_SelectedLocale | string | no | Current selected locale | +| Shell_IsSideNavigationCollapsed | boolean | no | Side navigation state | +| Shell_SelectedThemeId | string | no | Current selected appearance | + +The keys listed above are preloaded by the Shell, as they are also used internally. Therefore, they are immediately available. + +Keys can be either **company-dependent** or **company-independent**: +- **Company-dependent keys** store a separate value for each company. The value returned depends on the currently selected company. +- **Company-independent keys** share the same value across all companies. + +It is also possible to fetch values for additional keys defined for a user in the Admin app. To do so, the keys must first be **registered** via the `REQUIRE_CONTEXT` event: +- The request payload of `REQUIRE_CONTEXT` includes the optional property `cloudStorageKeys`, which allows you to register non-preloaded keys. +- Once a key has been registered, its value can be retrieved using `Version2.GET_STORAGE_ITEM`. + +The event `REQUIRE_CONTEXT` also allows you to register non-existing keys, which is useful for key-value pairs created at runtime: +- After registering a non-existing key, it can be accessed via `Version2.GET_STORAGE_ITEM`. +- As long as the key-value pair has not been created, the returned value will be `null`. +- Once the key-value pair is created and becomes visible in the Admin app, the actual value will be returned. + +**Upcoming Change** + +> **Note:** This change is currently only active when Preview Mode is enabled. + +Registering keys via the `REQUIRE_CONTEXT` event will only be required for non-existing keys. All existing keys — including those not preloaded by the Shell — can be accessed directly using `Version2.GET_STORAGE_ITEM`. - ### SET_STORAGE_ITEM @@ -396,6 +434,18 @@ Request value stored under specified key in cloud storage type: boolean flag indicating if value was saved successfully + Only key-value pairs that are **preloaded by the Shell** can be updated directly. Other user settings must first be registered via the `REQUIRE_CONTEXT` event before they can be updated using `SET_STORAGE_ITEM` (see `GET_STORAGE_ITEM` for more details). + + It is also possible to create new user settings: + - Like non-preloaded settings, new keys must first be registered via `REQUIRE_CONTEXT`. + - Once registered, they can be created and assigned a value using `SET_STORAGE_ITEM`. + + **Upcoming Change** + + > **Note:** This change is currently only active when Preview Mode is enabled. + + Registering via the `REQUIRE_CONTEXT` event will only be required for new keys. All existing keys — including those not preloaded by the Shell — can be updated directly using the `SET_STORAGE_ITEM` event. + - ### GET_FEATURE_FLAG Feature flags are internally used flags in FSM to control some new features when the preview mode is off. diff --git a/package-lock.json b/package-lock.json index 966e9b0..37f134b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "fsm-shell", - "version": "1.24.0", + "version": "1.25.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "fsm-shell", - "version": "1.24.0", + "version": "1.25.0", "license": "Apache-2.0", "devDependencies": { "@types/jasmine": "^3.5.12", diff --git a/package.json b/package.json index 8b6bc93..5372163 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fsm-shell", - "version": "1.24.0", + "version": "1.25.0", "description": "client library for FSM shell", "main": "release/fsm-shell-client.js", "module": "release/fsm-shell-client.es.js", diff --git a/src/index.ts b/src/index.ts index a6c91b5..4bbe849 100644 --- a/src/index.ts +++ b/src/index.ts @@ -26,6 +26,7 @@ import { GetFeatureFlagRequest, GetFeatureFlagsRequest, GetFeatureFlagResponse, + GetItemRequest, GetItemResponse, ModalCloseRequest, ModalOpenRequest, @@ -62,6 +63,7 @@ export { GetFeatureFlagRequest, GetFeatureFlagsRequest, GetFeatureFlagResponse, + GetItemRequest, GetItemResponse, ModalCloseRequest, ModalOpenRequest, diff --git a/src/models/cloud-storage/get-item-request.model.ts b/src/models/cloud-storage/get-item-request.model.ts new file mode 100644 index 0000000..bf7e05a --- /dev/null +++ b/src/models/cloud-storage/get-item-request.model.ts @@ -0,0 +1,2 @@ + +export type GetItemRequest = string | string[]; diff --git a/src/models/index.ts b/src/models/index.ts index b6c4fbb..3595754 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -5,6 +5,7 @@ export { PermissionResponseV3 } from './permissions/permission-response.v3.model export { Permission } from './permissions/permission.model'; export { UiPermissions } from './permissions/ui-permissions.model'; +export { GetItemRequest } from './cloud-storage/get-item-request.model'; export { GetItemResponse } from './cloud-storage/get-item-response.model'; export { SetItemRequest } from './cloud-storage/set-item-request.model'; diff --git a/src/validation/schemas/cloud-storage/get-item-request.v2.schema.ts b/src/validation/schemas/cloud-storage/get-item-request.v2.schema.ts index ef3232c..2260b3d 100644 --- a/src/validation/schemas/cloud-storage/get-item-request.v2.schema.ts +++ b/src/validation/schemas/cloud-storage/get-item-request.v2.schema.ts @@ -1,3 +1,13 @@ export const getItemRequest_v2_schema = { - type: 'string', + oneOf: [ + { + type: 'string', + }, + { + type: 'array', + items: { + type: 'string', + }, + }, + ], }; diff --git a/src/validation/schemas/feature-flag/get-feature-flag-request.v1.schema.ts b/src/validation/schemas/feature-flag/get-feature-flag-request.v1.schema.ts index 77787cd..8b01412 100644 --- a/src/validation/schemas/feature-flag/get-feature-flag-request.v1.schema.ts +++ b/src/validation/schemas/feature-flag/get-feature-flag-request.v1.schema.ts @@ -13,7 +13,7 @@ export const getFeatureFlagRequest_v1_schema = { required: ['key', 'defaultValue'] } }, - anyOf: [ + oneOf: [ { $ref: '#/$defs/payload' }, diff --git a/src/validation/schemas/schemas.spec.ts b/src/validation/schemas/schemas.spec.ts index 4af02b9..2bb0112 100644 --- a/src/validation/schemas/schemas.spec.ts +++ b/src/validation/schemas/schemas.spec.ts @@ -46,7 +46,8 @@ import { outletsRequestDynamicContextResponse_v1_schema } from './outlets/outlet export const validAuthRequest_v1 = { response_type: 'token' }; export const validAuthResponse_v1 = { access_token: 'string', expires_in: 123, token_type: 'string' }; export const validGetItemRequest_v1 = 'string'; -export const validGetItemRequest_v2 = 'string'; +export const validGetItemRequest_v2_subschema_1 = 'string'; +export const validGetItemRequest_v2_subschema_2 = ['string', 'string']; export const validGetItemResponse_v2 = { key: 'string', value: {} }; export const validSetItemRequest_v1 = { key: 'string', value: {} }; export const validGetFeatureFlagRequest_v1_subschema_1 = { key: 'string', defaultValue: true }; @@ -312,7 +313,8 @@ describe('Schemas', () => { validateValidDataAgainstSchemaHelper(ajv, 'authRequest_v1_schema', authRequest_v1_schema, validAuthRequest_v1); validateValidDataAgainstSchemaHelper(ajv, 'authResponse_v1_schema', authResponse_v1_schema, validAuthResponse_v1); validateValidDataAgainstSchemaHelper(ajv, 'getItemRequest_v1_schema', getItemRequest_v1_schema, validGetItemRequest_v1); - validateValidDataAgainstSchemaHelper(ajv, 'getItemRequest_v2_schema', getItemRequest_v2_schema, validGetItemRequest_v2); + validateValidDataAgainstSchemaHelper(ajv, 'getItemRequest_v2_schema', getItemRequest_v2_schema, validGetItemRequest_v2_subschema_1); + validateValidDataAgainstSchemaHelper(ajv, 'getItemRequest_v2_schema', getItemRequest_v2_schema, validGetItemRequest_v2_subschema_2); validateValidDataAgainstSchemaHelper(ajv, 'getItemResponse_v2_schema', getItemResponse_v2_schema, validGetItemResponse_v2); validateValidDataAgainstSchemaHelper(ajv, 'setItemRequest_v1_schema', setItemRequest_v1_schema, validSetItemRequest_v1); validateValidDataAgainstSchemaHelper(ajv, 'getFeatureFlagRequest_v1_schema', getFeatureFlagRequest_v1_schema, validGetFeatureFlagRequest_v1_subschema_1); diff --git a/src/validation/schemas/settings/get-settings-request.v1.schema.ts b/src/validation/schemas/settings/get-settings-request.v1.schema.ts index 6503a77..52aab20 100644 --- a/src/validation/schemas/settings/get-settings-request.v1.schema.ts +++ b/src/validation/schemas/settings/get-settings-request.v1.schema.ts @@ -1,5 +1,5 @@ export const getSettingsRequest_v1_schema = { - anyOf: [ + oneOf: [ { type: 'string' }, @@ -7,7 +7,7 @@ export const getSettingsRequest_v1_schema = { type: 'array', items: { type: ['string', 'array'], - anyOf: [ + oneOf: [ { type: 'string' }, From b3497d19dd3d0697a6198627e59d43c2dfc6f46d Mon Sep 17 00:00:00 2001 From: Kistl Date: Wed, 25 Mar 2026 11:26:06 +0100 Subject: [PATCH 2/2] Fix model RequireContextRequest and the respected schema as the optional property cloudStorageKeys should conatin an array of objects and not an array of strings --- CHANGELOG.md | 3 ++- src/index.ts | 2 ++ .../cloud-storage/cloud-storage-key.model.ts | 5 +++++ src/models/index.ts | 2 ++ .../require-context-request.model.ts | 3 ++- .../require-context-request.v1.schema.ts | 14 +++++++++++++- src/validation/schemas/schemas.spec.ts | 2 +- 7 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 src/models/cloud-storage/cloud-storage-key.model.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 980e310..7903e1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,9 +10,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Define and "publish" new model `GetItemRequest` -- Enhance `getItemRequest_v2_schema` to support multiple keys +- Enhance schema `getItemRequest_v2_schema` to support multiple keys - Improve schemas `getFeatureFlagRequest_v1_schema` and `getSettingsRequest_v1_schema` by replacing anyOf with oneOf - Improve documentation for the events `GET_STORAGE_ITEM` and `SET_STORAGE_ITEM` +- Fix model `RequireContextRequest` and the respected schema as the optional property cloudStorageKeys should conatin an array of objects and not an array of strings ## [1.24.0] - 2026-03-23 diff --git a/src/index.ts b/src/index.ts index 4bbe849..2389f44 100644 --- a/src/index.ts +++ b/src/index.ts @@ -22,6 +22,7 @@ import { AuthRequest, AuthResponse, AuthResponseType, + CloudStorageKey, DialogSettings, GetFeatureFlagRequest, GetFeatureFlagsRequest, @@ -59,6 +60,7 @@ export { AuthRequest, AuthResponse, AuthResponseType, + CloudStorageKey, DialogSettings, GetFeatureFlagRequest, GetFeatureFlagsRequest, diff --git a/src/models/cloud-storage/cloud-storage-key.model.ts b/src/models/cloud-storage/cloud-storage-key.model.ts new file mode 100644 index 0000000..8592f63 --- /dev/null +++ b/src/models/cloud-storage/cloud-storage-key.model.ts @@ -0,0 +1,5 @@ +export interface CloudStorageKey { + name: string; + dataVersion: number; + companyDependent: boolean; +} diff --git a/src/models/index.ts b/src/models/index.ts index 3595754..852d00c 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -51,3 +51,5 @@ export { RequireContextRequest } from './require-context/require-context-request export { Outlet } from './outlets/outlet.model'; export { TraceEntry } from './trace/trace-entry.model'; + +export { CloudStorageKey } from './cloud-storage/cloud-storage-key.model'; diff --git a/src/models/require-context/require-context-request.model.ts b/src/models/require-context/require-context-request.model.ts index e6eabcf..81eb077 100644 --- a/src/models/require-context/require-context-request.model.ts +++ b/src/models/require-context/require-context-request.model.ts @@ -1,9 +1,10 @@ import { AuthRequest } from '../authentication/auth-request.model'; +import { CloudStorageKey } from '../cloud-storage/cloud-storage-key.model'; export interface RequireContextRequest { clientIdentifier: string; clientSecret: string; - cloudStorageKeys?: string[]; + cloudStorageKeys?: CloudStorageKey[]; auth?: AuthRequest; targetOutletName?: string; targetExtensionAssignmentId?: string; diff --git a/src/validation/schemas/require-context/require-context-request.v1.schema.ts b/src/validation/schemas/require-context/require-context-request.v1.schema.ts index a406c3b..d20c253 100644 --- a/src/validation/schemas/require-context/require-context-request.v1.schema.ts +++ b/src/validation/schemas/require-context/require-context-request.v1.schema.ts @@ -12,7 +12,19 @@ export const requireContextRequest_v1_schema = { cloudStorageKeys: { type: 'array', items: { - type: 'string', + type: 'object', + properties: { + name: { + type: 'string' + }, + dataVersion: { + type: 'number' + }, + companyDependent: { + type: 'boolean' + }, + }, + required: ['name', 'dataVersion', 'companyDependent'], }, }, auth: authRequest_v1_schema, diff --git a/src/validation/schemas/schemas.spec.ts b/src/validation/schemas/schemas.spec.ts index 2bb0112..942f5f4 100644 --- a/src/validation/schemas/schemas.spec.ts +++ b/src/validation/schemas/schemas.spec.ts @@ -90,7 +90,7 @@ export const validGetPermissionsResponse_v3 = { objectName: 'string', permission export const validRequireContextRequest_v1 = { clientIdentifier: 'string', clientSecret: 'string', - cloudStorageKeys: ['string'], + cloudStorageKeys: [{ name: 'string', dataVersion: 1, companyDependent: true }], auth: validAuthRequest_v1, targetOutletName: 'string', targetExtensionAssignmentId: 'string'