@adobedjangir/commerce-admin-management 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +637 -0
- package/actions/commerce-creds.js +262 -0
- package/actions/configurations/commerce/index.js +41 -0
- package/actions/configurations/commerce-connection-save/index.js +53 -0
- package/actions/configurations/commerce-connection-status/index.js +27 -0
- package/actions/configurations/commerce-connection-test/index.js +47 -0
- package/actions/configurations/export-config/index.js +256 -0
- package/actions/configurations/ext.config.yaml +192 -0
- package/actions/configurations/import-config/index.js +541 -0
- package/actions/configurations/registration/index.js +37 -0
- package/actions/configurations/sync-store-mappings-from-commerce/index.js +190 -0
- package/actions/configurations/system-config-list/index.js +127 -0
- package/actions/configurations/system-config-save/index.js +160 -0
- package/actions/configurations/system-config-schema/index.js +327 -0
- package/actions/utils.js +73 -0
- package/package.json +80 -0
- package/scripts/build-web.js +58 -0
- package/scripts/setup.js +445 -0
- package/src/abdb-config.js +8 -0
- package/src/abdb-helper.js +8 -0
- package/src/index.js +22 -0
- package/src/oauth1a.js +8 -0
- package/src/system-config-crypto.js +8 -0
- package/src/system-config-shared.js +8 -0
- package/web/dist/index.css +305 -0
- package/web/dist/index.js +2986 -0
- package/web/index.js +7 -0
- package/web/src/components/App.js +54 -0
- package/web/src/components/AppSectionNav.js +49 -0
- package/web/src/components/CommerceSetupWizard.js +160 -0
- package/web/src/components/ExtensionRegistration.js +33 -0
- package/web/src/components/MainPage.js +147 -0
- package/web/src/components/SystemConfig.js +1464 -0
- package/web/src/components/SystemConfigSchemaEditor.js +459 -0
- package/web/src/hooks/useConfirm.js +355 -0
- package/web/src/hooks/useSystemConfig.js +238 -0
- package/web/src/hooks/useSystemConfigSchema.js +102 -0
- package/web/src/index.js +46 -0
- package/web/src/nav-icons.js +30 -0
- package/web/src/nav.json +10 -0
- package/web/src/pages/index.js +17 -0
- package/web/src/schema/systemConfigSchema.js +82 -0
- package/web/src/settings.js +101 -0
- package/web/src/styles/index.css +337 -0
- package/web/src/theme.js +104 -0
- package/web/src/utils/storeMappingsFromCommerceRest.js +73 -0
- package/web/src/utils.js +52 -0
- package/web/styles.css +337 -0
package/README.md
ADDED
|
@@ -0,0 +1,637 @@
|
|
|
1
|
+
# @adobedjangir/commerce-admin-management — Developer Guide
|
|
2
|
+
|
|
3
|
+
A turnkey Adobe App Builder package for **schema-driven system configuration**
|
|
4
|
+
in Adobe Commerce extensions. Provides encrypted scoped storage, a React-Spectrum
|
|
5
|
+
admin UI mounted inside the Commerce Admin, OAuth1a helpers, import/export,
|
|
6
|
+
and an extension point for host apps to add their own pages and actions.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Table of contents
|
|
11
|
+
|
|
12
|
+
1. [What you get](#what-you-get)
|
|
13
|
+
2. [Quick start](#quick-start)
|
|
14
|
+
3. [What `npm install` scaffolds for you](#what-npm-install-scaffolds-for-you)
|
|
15
|
+
4. [Required `.env` values](#required-env-values)
|
|
16
|
+
5. [Architecture](#architecture)
|
|
17
|
+
6. [Built-in actions](#built-in-actions)
|
|
18
|
+
7. [Storage model](#storage-model)
|
|
19
|
+
8. [Encryption](#encryption)
|
|
20
|
+
9. [Commerce connection flow](#commerce-connection-flow)
|
|
21
|
+
10. [Adding a host page (UI tab)](#adding-a-host-page-ui-tab)
|
|
22
|
+
11. [Adding a host action (backend)](#adding-a-host-action-backend)
|
|
23
|
+
12. [Reusable helpers exported by the package](#reusable-helpers-exported-by-the-package)
|
|
24
|
+
13. [Configuration override matrix](#configuration-override-matrix)
|
|
25
|
+
14. [Common operations](#common-operations)
|
|
26
|
+
15. [Troubleshooting](#troubleshooting)
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## What you get
|
|
31
|
+
|
|
32
|
+
| Capability | Where it lives |
|
|
33
|
+
|---|---|
|
|
34
|
+
| Schema-driven config form (sections / groups / fields) | UI: `SystemConfig` page (built-in tab) |
|
|
35
|
+
| Per-scope values (`default → websites → stores`) with Magento-style inheritance | Action: `system-config-list` / `system-config-save` |
|
|
36
|
+
| AES-256-GCM encryption of sensitive fields at rest | `system-config-crypto` module |
|
|
37
|
+
| Adobe Commerce REST/OAuth1a client helper | `commerce-creds` module |
|
|
38
|
+
| First-run setup wizard for Commerce credentials (saved encrypted in ABDB) | UI: `CommerceSetupWizard` |
|
|
39
|
+
| Bulk JSON export/import with cross-environment website/store id remapping | Actions: `export-config`, `import-config` |
|
|
40
|
+
| App Builder Database (ABDB) auto-provisioning on deploy | `ext.config.yaml` |
|
|
41
|
+
| Host-extensible nav and pages | `configureWeb({ extraNav, extraPages })` |
|
|
42
|
+
| Auto-scaffolded host scaffold on `npm install` | `scripts/setup.js` (postinstall hook) |
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Quick start
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# 1. Create a new App Builder project (skip if you already have one)
|
|
50
|
+
aio app init my-commerce-admin
|
|
51
|
+
cd my-commerce-admin
|
|
52
|
+
|
|
53
|
+
# 2. Install the package — postinstall scaffolds everything
|
|
54
|
+
npm install @adobedjangir/commerce-admin-management
|
|
55
|
+
|
|
56
|
+
# 3. Fill in .env (see required values below)
|
|
57
|
+
cp env.dist .env
|
|
58
|
+
$EDITOR .env
|
|
59
|
+
|
|
60
|
+
# 4. Deploy. ABDB is auto-provisioned; 11 actions + web assets ship to CDN.
|
|
61
|
+
aio app deploy
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Open the URL the deploy prints. First run shows the Commerce setup wizard;
|
|
65
|
+
enter your store URL + OAuth1a creds, click **Test connection**, then
|
|
66
|
+
**Save & continue**. The rest of the UI is then unlocked.
|
|
67
|
+
|
|
68
|
+
For local dev:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
aio app run
|
|
72
|
+
# → https://localhost:9080
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## What `npm install` scaffolds for you
|
|
78
|
+
|
|
79
|
+
The package's `postinstall` runs `scripts/setup.js`, which idempotently
|
|
80
|
+
materializes a host scaffold:
|
|
81
|
+
|
|
82
|
+
| Path | First install | Subsequent installs |
|
|
83
|
+
|---|---|---|
|
|
84
|
+
| `app.config.yaml` | Adds `extensions: commerce/backend-ui/1: $include …` if absent | No-op |
|
|
85
|
+
| `web-src/src/index.js` | Writes the package-wired bootstrap | Re-syncs if the marker is present; left alone if the host imported `@adobedjangir/commerce-admin-management/web` and removed the marker |
|
|
86
|
+
| `web-src/src/nav.json` | Writes a starter entry → `#/welcome` | Never overwritten |
|
|
87
|
+
| `web-src/src/pages/index.js` | Writes a registry that imports `Welcome` | Never overwritten |
|
|
88
|
+
| `web-src/src/pages/Welcome.js` | Writes a React-Spectrum starter page | Never overwritten |
|
|
89
|
+
|
|
90
|
+
> The "never overwritten" rule means you can edit those files freely;
|
|
91
|
+
> upgrading the package will not lose your changes.
|
|
92
|
+
|
|
93
|
+
The package also runs `scripts/build-web.js`, producing
|
|
94
|
+
`node_modules/@adobedjangir/commerce-admin-management/web/dist/index.{js,css}` so the host
|
|
95
|
+
bundle has a ready-to-consume artifact.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Required `.env` values
|
|
100
|
+
|
|
101
|
+
| Variable | Purpose |
|
|
102
|
+
|---|---|
|
|
103
|
+
| `OAUTH_CLIENT_ID` | Adobe IMS Server-to-Server credentials — for ABDB token |
|
|
104
|
+
| `OAUTH_CLIENT_SECRET` | same |
|
|
105
|
+
| `OAUTH_ORG_ID` | same |
|
|
106
|
+
| `OAUTH_SCOPES` | should include `AdobeID, openid, read_organizations, additional_info.projectedProductContext, additional_info.roles, adobeio_api, read_client_secret, manage_client_secrets, event_receiver_api, commerce.accs` |
|
|
107
|
+
| `AIO_DB_REGION` | One of `amer \| emea \| apac \| aus`. Must match the region where the App Builder Database service is entitled. |
|
|
108
|
+
| `SYSTEM_CONFIG_CRYPT_KEY` | At least 8 chars. **Generate once with `openssl rand -base64 32` and never rotate** — rotating breaks every encrypted value already in ABDB. |
|
|
109
|
+
|
|
110
|
+
Commerce REST creds (`COMMERCE_BASE_URL`, `COMMERCE_CONSUMER_KEY`, …) are
|
|
111
|
+
**no longer set via `.env`**. They are entered in the in-app wizard and
|
|
112
|
+
encrypted into ABDB under `default/_system/commerce/connection`.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Architecture
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
120
|
+
│ Adobe Commerce Admin ← iframe ← Experience Cloud Shell │
|
|
121
|
+
└─────────────────────────────────────────────────────────────┘
|
|
122
|
+
│
|
|
123
|
+
▼
|
|
124
|
+
https://<workspace>.adobeio-static.net
|
|
125
|
+
│
|
|
126
|
+
▼
|
|
127
|
+
React app (@adobedjangir/commerce-admin-management/web/dist/index.js)
|
|
128
|
+
│
|
|
129
|
+
┌───────────────┼───────────────┐
|
|
130
|
+
▼ ▼ ▼
|
|
131
|
+
HashRouter AppSectionNav MainPage (gated on connection status)
|
|
132
|
+
│
|
|
133
|
+
▼
|
|
134
|
+
getNavItems() + getPageComponent(id)
|
|
135
|
+
│
|
|
136
|
+
▼
|
|
137
|
+
<Page runtime ims> ─→ callAction(props, key, op, body)
|
|
138
|
+
│
|
|
139
|
+
▼
|
|
140
|
+
POST /api/v1/web/<package>/<action>
|
|
141
|
+
│
|
|
142
|
+
▼
|
|
143
|
+
OpenWhisk action handlers
|
|
144
|
+
│
|
|
145
|
+
┌───────────────┼───────────────┐
|
|
146
|
+
▼ ▼ ▼
|
|
147
|
+
ABDB Commerce REST/OAuth1a IMS
|
|
148
|
+
(system_config_data, system_config_schema, _system/*)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Built-in actions
|
|
154
|
+
|
|
155
|
+
All under runtime package **`CommerceAdminManagement`**.
|
|
156
|
+
|
|
157
|
+
| Action | Verb | Description |
|
|
158
|
+
|---|---|---|
|
|
159
|
+
| `commerce-rest-get` | POST | Proxy any Commerce REST GET via OAuth1a using stored creds |
|
|
160
|
+
| `commerce-connection-status` | POST | `{ configured: bool, creds: masked }` |
|
|
161
|
+
| `commerce-connection-test` | POST | Verifies form values OR saved creds against `store/storeConfigs` |
|
|
162
|
+
| `commerce-connection-save` | POST | Tests then encrypts + upserts creds in ABDB |
|
|
163
|
+
| `system-config-list` | POST | Reads paths with Magento-style scope inheritance, decrypts sensitive fields |
|
|
164
|
+
| `system-config-save` | POST | Upserts values, encrypts sensitive paths |
|
|
165
|
+
| `system-config-schema` | POST | CRUD on the schema document |
|
|
166
|
+
| `export-config` | POST | Dumps schema + values (sensitive decrypted) as portable JSON |
|
|
167
|
+
| `import-config` | POST | Re-imports a dump, re-encrypts with the target's key, remaps website/store ids via Commerce REST |
|
|
168
|
+
| `sync-store-mappings-from-commerce` | POST | Refreshes the `general/settings/store_mappings` blob from Commerce |
|
|
169
|
+
|
|
170
|
+
All actions are `require-adobe-auth: false` and `include-ims-credentials: true`,
|
|
171
|
+
so they receive the host's OAuth credentials via env-injection — they don't
|
|
172
|
+
require a user IMS token.
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Storage model
|
|
177
|
+
|
|
178
|
+
ABDB collection `system_config_data` — one document per (scope, scope_id, path):
|
|
179
|
+
|
|
180
|
+
```json
|
|
181
|
+
{
|
|
182
|
+
"_id": "sysconfig__default__0__campaign_general__url__url",
|
|
183
|
+
"scope": "default",
|
|
184
|
+
"scope_id": "0",
|
|
185
|
+
"path": "campaign_general/url/url",
|
|
186
|
+
"value": "https://example.com",
|
|
187
|
+
"createdAt": "2026-01-04T...",
|
|
188
|
+
"updatedAt": "2026-06-19T..."
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
- `_id` is `sysconfig__<scope>__<scopeId>__<path-with-/-as-__>`
|
|
193
|
+
- Inheritance chain: `stores:<storeId> → websites:<websiteId> → default:0`
|
|
194
|
+
- Sensitive `value`s carry the prefix `enc:v1:<salt>:<iv>:<tag>:<ct>` (all
|
|
195
|
+
base64url) — see [Encryption](#encryption).
|
|
196
|
+
|
|
197
|
+
Schema is stored separately in `system_config_schema` (single doc `_id: 'v1'`).
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Encryption
|
|
202
|
+
|
|
203
|
+
`SYSTEM_CONFIG_CRYPT_KEY` is the master secret for AES-256-GCM.
|
|
204
|
+
|
|
205
|
+
```js
|
|
206
|
+
const { encrypt, decrypt, isEncrypted } = require('@adobedjangir/commerce-admin-management/crypto')
|
|
207
|
+
|
|
208
|
+
encrypt('hello', params) // → 'enc:v1:...:...:...:...'
|
|
209
|
+
decrypt('enc:v1:...', params) // → 'hello'
|
|
210
|
+
isEncrypted('enc:v1:...') // → true
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
- Per-record `salt` ⇒ same plaintext under same key produces a different
|
|
214
|
+
ciphertext each save (no oracle attacks).
|
|
215
|
+
- Wire format is versioned (`v1`) so the algorithm can be rotated without
|
|
216
|
+
breaking existing values.
|
|
217
|
+
- A fallback to `OAUTH_CLIENT_SECRET` exists for first-touch convenience but
|
|
218
|
+
is **strongly discouraged in production** — your IMS client secret rotates;
|
|
219
|
+
your at-rest data must not.
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Commerce connection flow
|
|
224
|
+
|
|
225
|
+
```
|
|
226
|
+
First load ──→ GET /commerce-connection-status {configured: false}
|
|
227
|
+
│
|
|
228
|
+
▼
|
|
229
|
+
CommerceSetupWizard
|
|
230
|
+
│
|
|
231
|
+
User fills form ──→ POST /commerce-connection-test {ok: true|false}
|
|
232
|
+
User clicks Save ──→ POST /commerce-connection-save
|
|
233
|
+
│
|
|
234
|
+
▼ encrypt(JSON.stringify(creds), SYSTEM_CONFIG_CRYPT_KEY)
|
|
235
|
+
│ upsert ABDB at default/_system/commerce/connection
|
|
236
|
+
▼
|
|
237
|
+
App unlocks → System Config tab visible
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Any action that needs Commerce REST calls
|
|
241
|
+
`getCommerceCreds(params, logger)` or
|
|
242
|
+
`getStoredCommerceOauthClient(params, logger)`, which read+decrypt the blob.
|
|
243
|
+
A 5-minute in-process cache avoids repeating the lookup per request.
|
|
244
|
+
|
|
245
|
+
A **Reconfigure Commerce** button in the top-right of the nav lets operators
|
|
246
|
+
edit/replace the creds later.
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## Adding a host page (UI tab)
|
|
251
|
+
|
|
252
|
+
Three edits, no rebuild of the package:
|
|
253
|
+
|
|
254
|
+
### 1. Create the page
|
|
255
|
+
|
|
256
|
+
```jsx
|
|
257
|
+
// web-src/src/pages/Orders.js
|
|
258
|
+
import React from 'react'
|
|
259
|
+
import { View, Heading } from '@adobe/react-spectrum'
|
|
260
|
+
|
|
261
|
+
export default function Orders ({ runtime, ims }) {
|
|
262
|
+
return (
|
|
263
|
+
<View padding="size-400">
|
|
264
|
+
<Heading level={2}>Orders</Heading>
|
|
265
|
+
</View>
|
|
266
|
+
)
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### 2. Register it
|
|
271
|
+
|
|
272
|
+
```js
|
|
273
|
+
// web-src/src/pages/index.js
|
|
274
|
+
import Welcome from './Welcome'
|
|
275
|
+
import Orders from './Orders'
|
|
276
|
+
|
|
277
|
+
const pages = {
|
|
278
|
+
welcome: Welcome,
|
|
279
|
+
orders: Orders
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
export default pages
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### 3. Add a nav entry
|
|
286
|
+
|
|
287
|
+
```json
|
|
288
|
+
// web-src/src/nav.json
|
|
289
|
+
{
|
|
290
|
+
"items": [
|
|
291
|
+
{ "id": "welcome", "path": "/welcome", "label": "Welcome", "icon": "Folder" },
|
|
292
|
+
{ "id": "orders", "path": "/orders", "label": "Orders", "icon": "ShoppingCart" }
|
|
293
|
+
]
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
`aio app run` → the tab appears. The page receives `{ runtime, ims }` as
|
|
298
|
+
props for use with `callAction`.
|
|
299
|
+
|
|
300
|
+
**Icon names** come from a Spectrum-icon registry in
|
|
301
|
+
[`web/src/nav-icons.js`](web/src/nav-icons.js). Built-in: `Settings`,
|
|
302
|
+
`Properties`, `Data`, `User`, `ShoppingCart`, `Box`, `Folder`. To add more,
|
|
303
|
+
extend that file and rebuild the package (`node scripts/build-web.js`).
|
|
304
|
+
|
|
305
|
+
### Override a built-in page
|
|
306
|
+
|
|
307
|
+
If you want to replace the built-in **System Configurations** with your own
|
|
308
|
+
version, just put an entry with the same id in your host registry:
|
|
309
|
+
|
|
310
|
+
```js
|
|
311
|
+
const pages = { 'system-config': MyOwnSystemConfig, ... }
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
The host always wins on id collision.
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## Adding a host action (backend)
|
|
319
|
+
|
|
320
|
+
Adobe App Builder merges `application.runtimeManifest` from `app.config.yaml`
|
|
321
|
+
with the extension's manifest, so host-defined actions live next to the
|
|
322
|
+
package's without any wiring step.
|
|
323
|
+
|
|
324
|
+
### 1. Write the action
|
|
325
|
+
|
|
326
|
+
```js
|
|
327
|
+
// actions/reports-list/index.js
|
|
328
|
+
const { Core } = require('@adobe/aio-sdk')
|
|
329
|
+
const { errorResponse } = require('@adobedjangir/commerce-admin-management/actions/utils')
|
|
330
|
+
const {
|
|
331
|
+
getStoredCommerceOauthClient
|
|
332
|
+
} = require('@adobedjangir/commerce-admin-management/actions/commerce-creds')
|
|
333
|
+
|
|
334
|
+
async function main (params) {
|
|
335
|
+
const logger = Core.Logger('reports-list', { level: params.LOG_LEVEL || 'info' })
|
|
336
|
+
try {
|
|
337
|
+
const oauth = await getStoredCommerceOauthClient(params, logger)
|
|
338
|
+
const orders = await oauth.get('orders?searchCriteria[pageSize]=10')
|
|
339
|
+
return { statusCode: 200, body: { ok: true, items: orders.items || [] } }
|
|
340
|
+
} catch (e) {
|
|
341
|
+
if (e.code === 'COMMERCE_NOT_CONFIGURED') {
|
|
342
|
+
return errorResponse(412, e.message, logger)
|
|
343
|
+
}
|
|
344
|
+
return errorResponse(500, e.message, logger)
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
exports.main = main
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
### 2. Declare it in `app.config.yaml`
|
|
352
|
+
|
|
353
|
+
```yaml
|
|
354
|
+
application:
|
|
355
|
+
runtimeManifest:
|
|
356
|
+
packages:
|
|
357
|
+
HostActions:
|
|
358
|
+
license: Apache-2.0
|
|
359
|
+
actions:
|
|
360
|
+
reports-list:
|
|
361
|
+
function: actions/reports-list/index.js
|
|
362
|
+
web: 'yes'
|
|
363
|
+
runtime: 'nodejs:20'
|
|
364
|
+
inputs:
|
|
365
|
+
LOG_LEVEL: debug
|
|
366
|
+
SYSTEM_CONFIG_CRYPT_KEY: $SYSTEM_CONFIG_CRYPT_KEY
|
|
367
|
+
OAUTH_CLIENT_ID: $OAUTH_CLIENT_ID
|
|
368
|
+
OAUTH_CLIENT_SECRET: $OAUTH_CLIENT_SECRET
|
|
369
|
+
OAUTH_ORG_ID: $OAUTH_ORG_ID
|
|
370
|
+
OAUTH_SCOPES: $OAUTH_SCOPES
|
|
371
|
+
AIO_DB_REGION: $AIO_DB_REGION
|
|
372
|
+
annotations:
|
|
373
|
+
require-adobe-auth: false
|
|
374
|
+
include-ims-credentials: true
|
|
375
|
+
final: true
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
`aio app deploy` ships 11 package actions **+** your `HostActions/reports-list`
|
|
379
|
+
together. The action URL appears in `web-src/src/config.json` automatically.
|
|
380
|
+
|
|
381
|
+
### 3. Call it from a host page
|
|
382
|
+
|
|
383
|
+
```jsx
|
|
384
|
+
import { callAction } from '@adobedjangir/commerce-admin-management/web'
|
|
385
|
+
|
|
386
|
+
// inside the component:
|
|
387
|
+
const r = await callAction({ runtime, ims }, 'HostActions/reports-list', '', { /* body */ })
|
|
388
|
+
console.log(r.body)
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
`callAction(props, key, operation, body)` POSTs to the URL stored under
|
|
392
|
+
`key` in `web-src/src/config.json`, adds `Bearer` + `x-gw-ims-org-id`
|
|
393
|
+
headers, parses the JSON response, and surfaces non-2xx as thrown errors
|
|
394
|
+
with `err.status` and `err.response`.
|
|
395
|
+
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
## Reusable helpers exported by the package
|
|
399
|
+
|
|
400
|
+
### Backend (Node)
|
|
401
|
+
|
|
402
|
+
```js
|
|
403
|
+
// ABDB client + helpers
|
|
404
|
+
const {
|
|
405
|
+
getClient, // → { client, close } using IMS S2S creds
|
|
406
|
+
withDbClient, // run a function with an auto-closed client
|
|
407
|
+
ensureImportCollectionsExist
|
|
408
|
+
} = require('@adobedjangir/commerce-admin-management/abdb')
|
|
409
|
+
|
|
410
|
+
// Magento-style scope helpers
|
|
411
|
+
const {
|
|
412
|
+
toStateKey, // (scope, scopeId, path) → ABDB _id
|
|
413
|
+
isValidPath,
|
|
414
|
+
normalizeScope,
|
|
415
|
+
normalizeScopeId,
|
|
416
|
+
buildInheritanceChain,
|
|
417
|
+
SENSITIVE_PLACEHOLDER
|
|
418
|
+
} = require('@adobedjangir/commerce-admin-management/shared')
|
|
419
|
+
|
|
420
|
+
// Per-record AES-256-GCM
|
|
421
|
+
const {
|
|
422
|
+
encrypt,
|
|
423
|
+
decrypt,
|
|
424
|
+
isEncrypted
|
|
425
|
+
} = require('@adobedjangir/commerce-admin-management/crypto')
|
|
426
|
+
|
|
427
|
+
// Commerce REST/OAuth1a
|
|
428
|
+
const {
|
|
429
|
+
getOauthClient,
|
|
430
|
+
getCommerceOauthClient
|
|
431
|
+
} = require('@adobedjangir/commerce-admin-management/oauth1a')
|
|
432
|
+
|
|
433
|
+
// Commerce credential storage (stored encrypted in ABDB)
|
|
434
|
+
const {
|
|
435
|
+
readCommerceCreds,
|
|
436
|
+
writeCommerceCreds,
|
|
437
|
+
testCommerceConnection,
|
|
438
|
+
getCommerceCreds,
|
|
439
|
+
getStoredCommerceOauthClient
|
|
440
|
+
} = require('@adobedjangir/commerce-admin-management/actions/commerce-creds')
|
|
441
|
+
|
|
442
|
+
// Schema-driven config lookup at runtime (used by external sync actions)
|
|
443
|
+
const { getConfig } = require('@adobedjangir/commerce-admin-management/config')
|
|
444
|
+
const value = await getConfig('campaign_general/url/url', params, { scope: 'stores', scopeCode: 'en_ch' })
|
|
445
|
+
|
|
446
|
+
// Top-level barrel:
|
|
447
|
+
const { getConfig, getClient, encrypt } = require('@adobedjangir/commerce-admin-management')
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
### Front-end (ESM)
|
|
451
|
+
|
|
452
|
+
```js
|
|
453
|
+
import {
|
|
454
|
+
// App shell
|
|
455
|
+
CommerceAdminManagementApp, // full router + Spectrum provider
|
|
456
|
+
configureWeb, // pass actionUrls + extraNav + extraPages
|
|
457
|
+
|
|
458
|
+
// Components
|
|
459
|
+
MainPage,
|
|
460
|
+
SystemConfig,
|
|
461
|
+
SystemConfigSchemaEditor,
|
|
462
|
+
AppSectionNav,
|
|
463
|
+
|
|
464
|
+
// Registries
|
|
465
|
+
getNavItems,
|
|
466
|
+
getPageComponent,
|
|
467
|
+
NAV_ICONS,
|
|
468
|
+
getNavIcon,
|
|
469
|
+
BUILT_IN_PAGES,
|
|
470
|
+
|
|
471
|
+
// Hooks
|
|
472
|
+
useSystemConfig,
|
|
473
|
+
useSystemConfigSchema,
|
|
474
|
+
useConfirm,
|
|
475
|
+
|
|
476
|
+
// Utilities
|
|
477
|
+
callAction,
|
|
478
|
+
|
|
479
|
+
// Theme tokens (for styling host pages consistently)
|
|
480
|
+
THEME, PALETTE, RADIUS, SHADOW, SPACE, FONT
|
|
481
|
+
} from '@adobedjangir/commerce-admin-management/web'
|
|
482
|
+
import '@adobedjangir/commerce-admin-management/web/styles.css'
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
---
|
|
486
|
+
|
|
487
|
+
## Configuration override matrix
|
|
488
|
+
|
|
489
|
+
| Setting | Default lives in | Override location | Override mechanism |
|
|
490
|
+
|---|---|---|---|
|
|
491
|
+
| ABDB auto-provision | package `ext.config.yaml` (`runtimeManifest.database.auto-provision: true`) | host `app.config.yaml` | `application: runtimeManifest: database: auto-provision: false` |
|
|
492
|
+
| ABDB region | package `ext.config.yaml` (literal `emea`) | host `app.config.yaml` | `application: runtimeManifest: database: region: amer` (and update `AIO_DB_REGION` in `.env` to match) |
|
|
493
|
+
| Runtime IMS token | computed by `aio-lib-core-auth` | n/a | The action runtime injects via `include-ims-credentials: true` |
|
|
494
|
+
| Action keys (URL paths) | `web/src/settings.js` (`DEFAULT_ACTION_KEYS`) | host bootstrap | `configureWeb({ actionKeys: { ... } })` |
|
|
495
|
+
| Built-in nav entries | package `web/src/nav.json` | host `web-src/src/nav.json` | extras merge after built-ins; host wins on id collision |
|
|
496
|
+
| Built-in pages | package `web/src/pages/index.js` | host `web-src/src/pages/index.js` | extras merge; host wins on id collision |
|
|
497
|
+
| Bootstrap (`web-src/src/index.js`) | package generator | own the file | Either remove the marker comment **and** import from `@adobedjangir/commerce-admin-management/web`, **or** edit freely while keeping the marker (loses on next install) |
|
|
498
|
+
|
|
499
|
+
---
|
|
500
|
+
|
|
501
|
+
## Common operations
|
|
502
|
+
|
|
503
|
+
### Rotate `SYSTEM_CONFIG_CRYPT_KEY`
|
|
504
|
+
|
|
505
|
+
**Do not** unless you've planned for re-encryption — every existing encrypted
|
|
506
|
+
value becomes undecryptable. If you must:
|
|
507
|
+
|
|
508
|
+
1. Export with the old key: `POST /export-config { schemaOnly: false }` — the
|
|
509
|
+
dump contains plaintext values for sensitive fields (v2+ dump format).
|
|
510
|
+
2. Update `SYSTEM_CONFIG_CRYPT_KEY` in `.env` and redeploy.
|
|
511
|
+
3. Re-import the dump: `POST /import-config { dump, overwrite: true }` — the
|
|
512
|
+
importer re-encrypts sensitive paths with the new key.
|
|
513
|
+
|
|
514
|
+
For cross-environment migration (different key on each side), pass
|
|
515
|
+
`sourceCryptKey: '<old-key>'` to `import-config` so it can decrypt the
|
|
516
|
+
ciphertext with the old key before re-encrypting with the new one.
|
|
517
|
+
|
|
518
|
+
### Change region
|
|
519
|
+
|
|
520
|
+
1. Update `AIO_DB_REGION` in `.env`.
|
|
521
|
+
2. Update `region:` literal under `runtimeManifest.database` in
|
|
522
|
+
`app.config.yaml` (host overrides the package default).
|
|
523
|
+
3. Ensure the workspace has App Builder Database entitled in that region in
|
|
524
|
+
the Adobe Developer Console.
|
|
525
|
+
4. `aio app deploy`.
|
|
526
|
+
|
|
527
|
+
### Promote a deploy
|
|
528
|
+
|
|
529
|
+
```bash
|
|
530
|
+
aio app deploy --workspace Production
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
Targets the named workspace's database/region/region-bound creds.
|
|
534
|
+
`SYSTEM_CONFIG_CRYPT_KEY` should differ per environment; use
|
|
535
|
+
`import-config` with `sourceCryptKey` to migrate values.
|
|
536
|
+
|
|
537
|
+
### Add an icon for use in `nav.json`
|
|
538
|
+
|
|
539
|
+
1. Import the icon into `packages/commerce-admin-management/web/src/nav-icons.js`
|
|
540
|
+
2. Add it to the `NAV_ICONS` map
|
|
541
|
+
3. `node packages/commerce-admin-management/scripts/build-web.js`
|
|
542
|
+
4. Reference it in `nav.json` as `"icon": "<NewIconName>"`
|
|
543
|
+
|
|
544
|
+
### Re-link a local package during development
|
|
545
|
+
|
|
546
|
+
If you're hacking on the package and need the host to pick up changes:
|
|
547
|
+
|
|
548
|
+
```bash
|
|
549
|
+
cd packages/commerce-admin-management
|
|
550
|
+
node scripts/build-web.js
|
|
551
|
+
cd ../..
|
|
552
|
+
npm install ./packages/commerce-admin-management # refreshes node_modules link
|
|
553
|
+
rm -rf .parcel-cache dist web-src/dist
|
|
554
|
+
aio app run
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
---
|
|
558
|
+
|
|
559
|
+
## Troubleshooting
|
|
560
|
+
|
|
561
|
+
| Symptom | Likely cause | Fix |
|
|
562
|
+
|---|---|---|
|
|
563
|
+
| `Database not provisioned` | App Builder Database not entitled on the workspace, **or** never ran `aio app deploy` since adding the package | Add the service in the Developer Console (region must match `AIO_DB_REGION`), then `aio app deploy` |
|
|
564
|
+
| `Invalid region '$AIO_DB_REGION'` | Tried to use `$VAR` substitution in `runtimeManifest.database.region` | aio substitutes `$VAR` only inside action `inputs:`. Use a literal region in YAML |
|
|
565
|
+
| Blank page at `#/<anything>` | Route table doesn't include a catch-all | Already fixed — `App.js` uses `path="*"`. If you forked it, add `<Route path="*" element={…}>` |
|
|
566
|
+
| Stuck on "Checking Commerce connection…" forever | Running outside Experience Cloud iframe; `@adobe/uix-guest`'s `attach()` was blocking | Already fixed — MainPage's `attach()` now races a 2-second timeout |
|
|
567
|
+
| Reports tab blank but System Configurations works | `pages/index.js` used CommonJS `require('./X').default` interop | Use ES `import X from './X'` instead |
|
|
568
|
+
| Nav button overflows below tabs | CSS not picked up | Make sure the package's `dist/index.css` is loaded (the bootstrap imports it automatically) |
|
|
569
|
+
| Encryption errors after env change | `SYSTEM_CONFIG_CRYPT_KEY` was rotated and there are old `enc:v1:` values | Either restore the old key, or perform the export/import re-encryption flow above |
|
|
570
|
+
| `npm install` overwrote my bootstrap | Marker comment still present | Remove the marker comment line, **and** ensure your file imports from `@adobedjangir/commerce-admin-management/web` so setup recognizes host-managed mode |
|
|
571
|
+
|
|
572
|
+
---
|
|
573
|
+
|
|
574
|
+
## File reference
|
|
575
|
+
|
|
576
|
+
```
|
|
577
|
+
packages/commerce-admin-management/
|
|
578
|
+
├── DEVELOPER.md ← you are here
|
|
579
|
+
├── README.md ← short overview
|
|
580
|
+
├── package.json
|
|
581
|
+
├── src/ ← thin re-exports from @adobedjangir/commerce-admin-get-config
|
|
582
|
+
│ ├── abdb-helper.js
|
|
583
|
+
│ ├── abdb-config.js
|
|
584
|
+
│ ├── system-config-crypto.js
|
|
585
|
+
│ ├── system-config-shared.js
|
|
586
|
+
│ └── oauth1a.js
|
|
587
|
+
├── actions/
|
|
588
|
+
│ ├── utils.js
|
|
589
|
+
│ ├── commerce-creds.js ← read/write/test encrypted creds in ABDB
|
|
590
|
+
│ └── configurations/
|
|
591
|
+
│ ├── ext.config.yaml ← runtime manifest (database + 11 actions)
|
|
592
|
+
│ ├── index.html
|
|
593
|
+
│ ├── registration/index.js
|
|
594
|
+
│ ├── commerce/index.js
|
|
595
|
+
│ ├── commerce-connection-status/index.js
|
|
596
|
+
│ ├── commerce-connection-test/index.js
|
|
597
|
+
│ ├── commerce-connection-save/index.js
|
|
598
|
+
│ ├── system-config-list/index.js
|
|
599
|
+
│ ├── system-config-save/index.js
|
|
600
|
+
│ ├── system-config-schema/index.js
|
|
601
|
+
│ ├── export-config/index.js
|
|
602
|
+
│ ├── import-config/index.js
|
|
603
|
+
│ └── sync-store-mappings-from-commerce/index.js
|
|
604
|
+
├── web/
|
|
605
|
+
│ ├── index.js ← re-exports dist/
|
|
606
|
+
│ ├── styles.css ← flat fallback
|
|
607
|
+
│ ├── dist/ ← built by scripts/build-web.js
|
|
608
|
+
│ └── src/
|
|
609
|
+
│ ├── index.js ← package entry
|
|
610
|
+
│ ├── nav.json ← built-in nav entries
|
|
611
|
+
│ ├── nav-icons.js ← string-name → Spectrum icon map
|
|
612
|
+
│ ├── settings.js ← actionKeys, extensionId, configureWeb, registries
|
|
613
|
+
│ ├── theme.js
|
|
614
|
+
│ ├── utils.js ← callAction
|
|
615
|
+
│ ├── styles/index.css
|
|
616
|
+
│ ├── pages/index.js ← built-in page registry
|
|
617
|
+
│ ├── components/
|
|
618
|
+
│ │ ├── App.js ← router + Provider + ErrorBoundary
|
|
619
|
+
│ │ ├── MainPage.js ← gates app on Commerce connection
|
|
620
|
+
│ │ ├── ExtensionRegistration.js ← UIX guest registration
|
|
621
|
+
│ │ ├── AppSectionNav.js ← top nav from registry
|
|
622
|
+
│ │ ├── CommerceSetupWizard.js ← first-run wizard
|
|
623
|
+
│ │ ├── SystemConfig.js ← main config form
|
|
624
|
+
│ │ └── SystemConfigSchemaEditor.js ← schema editor
|
|
625
|
+
│ ├── hooks/
|
|
626
|
+
│ ├── schema/systemConfigSchema.js
|
|
627
|
+
│ └── utils/storeMappingsFromCommerceRest.js
|
|
628
|
+
└── scripts/
|
|
629
|
+
├── build-web.js ← esbuild bundle
|
|
630
|
+
└── setup.js ← postinstall scaffolding
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
---
|
|
634
|
+
|
|
635
|
+
## License
|
|
636
|
+
|
|
637
|
+
Apache-2.0 © Adobe Inc.
|