@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.
Files changed (48) hide show
  1. package/README.md +637 -0
  2. package/actions/commerce-creds.js +262 -0
  3. package/actions/configurations/commerce/index.js +41 -0
  4. package/actions/configurations/commerce-connection-save/index.js +53 -0
  5. package/actions/configurations/commerce-connection-status/index.js +27 -0
  6. package/actions/configurations/commerce-connection-test/index.js +47 -0
  7. package/actions/configurations/export-config/index.js +256 -0
  8. package/actions/configurations/ext.config.yaml +192 -0
  9. package/actions/configurations/import-config/index.js +541 -0
  10. package/actions/configurations/registration/index.js +37 -0
  11. package/actions/configurations/sync-store-mappings-from-commerce/index.js +190 -0
  12. package/actions/configurations/system-config-list/index.js +127 -0
  13. package/actions/configurations/system-config-save/index.js +160 -0
  14. package/actions/configurations/system-config-schema/index.js +327 -0
  15. package/actions/utils.js +73 -0
  16. package/package.json +80 -0
  17. package/scripts/build-web.js +58 -0
  18. package/scripts/setup.js +445 -0
  19. package/src/abdb-config.js +8 -0
  20. package/src/abdb-helper.js +8 -0
  21. package/src/index.js +22 -0
  22. package/src/oauth1a.js +8 -0
  23. package/src/system-config-crypto.js +8 -0
  24. package/src/system-config-shared.js +8 -0
  25. package/web/dist/index.css +305 -0
  26. package/web/dist/index.js +2986 -0
  27. package/web/index.js +7 -0
  28. package/web/src/components/App.js +54 -0
  29. package/web/src/components/AppSectionNav.js +49 -0
  30. package/web/src/components/CommerceSetupWizard.js +160 -0
  31. package/web/src/components/ExtensionRegistration.js +33 -0
  32. package/web/src/components/MainPage.js +147 -0
  33. package/web/src/components/SystemConfig.js +1464 -0
  34. package/web/src/components/SystemConfigSchemaEditor.js +459 -0
  35. package/web/src/hooks/useConfirm.js +355 -0
  36. package/web/src/hooks/useSystemConfig.js +238 -0
  37. package/web/src/hooks/useSystemConfigSchema.js +102 -0
  38. package/web/src/index.js +46 -0
  39. package/web/src/nav-icons.js +30 -0
  40. package/web/src/nav.json +10 -0
  41. package/web/src/pages/index.js +17 -0
  42. package/web/src/schema/systemConfigSchema.js +82 -0
  43. package/web/src/settings.js +101 -0
  44. package/web/src/styles/index.css +337 -0
  45. package/web/src/theme.js +104 -0
  46. package/web/src/utils/storeMappingsFromCommerceRest.js +73 -0
  47. package/web/src/utils.js +52 -0
  48. package/web/styles.css +337 -0
@@ -0,0 +1,445 @@
1
+ #!/usr/bin/env node
2
+ /*
3
+ Copyright 2025 Adobe. All rights reserved.
4
+ Licensed under the Apache License, Version 2.0
5
+ */
6
+
7
+ const fs = require('fs')
8
+ const path = require('path')
9
+
10
+ const EXTENSION_POINT = 'commerce/backend-ui/1'
11
+ const INCLUDE_REL = 'node_modules/@adobedjangir/commerce-admin-management/actions/configurations/ext.config.yaml'
12
+ const MARKER = '# @adobedjangir/commerce-admin-management (auto-linked on npm install)'
13
+
14
+ function escapeRe (str) {
15
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
16
+ }
17
+
18
+ function findProjectRoot (startDir) {
19
+ let dir = startDir
20
+ while (dir && dir !== path.dirname(dir)) {
21
+ if (fs.existsSync(path.join(dir, 'app.config.yaml'))) {
22
+ return dir
23
+ }
24
+ dir = path.dirname(dir)
25
+ }
26
+ return null
27
+ }
28
+
29
+ function resolveProjectRoot () {
30
+ const initCwd = process.env.INIT_CWD
31
+ if (initCwd) {
32
+ const fromInit = findProjectRoot(initCwd)
33
+ if (fromInit) return fromInit
34
+ }
35
+ return findProjectRoot(process.cwd())
36
+ }
37
+
38
+ function alreadyLinked (content) {
39
+ return content.includes('@adobedjangir/commerce-admin-management/actions/configurations/ext.config.yaml')
40
+ }
41
+
42
+ function hasExtensionPoint (content) {
43
+ return /^[ \t]*commerce\/backend-ui\/1:/m.test(content)
44
+ }
45
+
46
+ function buildExtensionBlock () {
47
+ return [
48
+ MARKER,
49
+ 'extensions:',
50
+ ` ${EXTENSION_POINT}:`,
51
+ ` $include: ${INCLUDE_REL}`
52
+ ].join('\n')
53
+ }
54
+
55
+ function updateExistingExtensionBlock (content) {
56
+ const match = content.match(/^([ \t]*)commerce\/backend-ui\/1:/m)
57
+ if (!match) return null
58
+
59
+ const indent = match[1]
60
+ const includeIndent = `${indent} `
61
+ const blockRe = new RegExp(
62
+ `^${escapeRe(indent)}commerce/backend-ui/1:[ \\t]*\\n` +
63
+ `(?:${escapeRe(includeIndent)}\\$include:[^\\n]*\\n)?`,
64
+ 'm'
65
+ )
66
+ const replacement =
67
+ `${indent}${EXTENSION_POINT}:\n${includeIndent}$include: ${INCLUDE_REL}\n`
68
+ const next = content.replace(blockRe, replacement)
69
+ return next !== content ? next : null
70
+ }
71
+
72
+ function patchAppConfig (content) {
73
+ if (alreadyLinked(content)) {
74
+ return { content, changed: false, reason: 'already-linked' }
75
+ }
76
+
77
+ if (hasExtensionPoint(content)) {
78
+ const updated = updateExistingExtensionBlock(content)
79
+ if (updated) {
80
+ return { content: updated, changed: true, reason: 'updated-existing-extension' }
81
+ }
82
+ return { content, changed: false, reason: 'extension-exists-unmodified' }
83
+ }
84
+
85
+ if (/^extensions:[ \t]*\n/m.test(content)) {
86
+ const injection = ` ${EXTENSION_POINT}:\n $include: ${INCLUDE_REL}\n`
87
+ const next = content.replace(/^extensions:[ \t]*\n/m, `extensions:\n${injection}`)
88
+ if (next !== content) {
89
+ return { content: next, changed: true, reason: 'added-under-extensions' }
90
+ }
91
+ }
92
+
93
+ if (!/^extensions:/m.test(content)) {
94
+ const trimmed = content.replace(/\s+$/, '')
95
+ const separator = trimmed.length > 0 ? '\n\n' : ''
96
+ return {
97
+ content: `${trimmed}${separator}${buildExtensionBlock()}\n`,
98
+ changed: true,
99
+ reason: 'appended'
100
+ }
101
+ }
102
+
103
+ return { content, changed: false, reason: 'no-change' }
104
+ }
105
+
106
+ // ────────────────────────────────────────────────────────────────────────────
107
+ // app.config.yaml: ABDB auto-provisioning default
108
+ //
109
+ // The package needs App Builder Database to be auto-provisioned on deploy.
110
+ // `database` is a top-level key under `application:` in app.config.yaml (it
111
+ // cannot live inside ext.config.yaml — Adobe's extension schema rejects it).
112
+ // We inject it once on install. Hosts that want to override either edit
113
+ // app.config.yaml (set auto-provision: false, change region, etc.) or override
114
+ // the region via AIO_DB_REGION in .env — that variable is read at runtime by
115
+ // aio-lib-db.init and takes precedence over any defaults.
116
+ // ────────────────────────────────────────────────────────────────────────────
117
+
118
+ const DB_MARKER = '# @adobedjangir/commerce-admin-management (auto-linked on npm install)'
119
+
120
+ function hasApplicationDatabase (content) {
121
+ // Quick string sniff to avoid re-patching once the block is present.
122
+ return /^application:[ \t]*\n(?:[ \t][^\n]*\n)*[ \t]+database:/m.test(content)
123
+ }
124
+
125
+ function buildDatabaseBlock () {
126
+ return [
127
+ DB_MARKER,
128
+ 'application:',
129
+ ' database:',
130
+ ' auto-provision: true',
131
+ ' region: emea'
132
+ ].join('\n')
133
+ }
134
+
135
+ function patchAppConfigDatabase (content) {
136
+ if (hasApplicationDatabase(content)) {
137
+ return { content, changed: false, reason: 'already-present' }
138
+ }
139
+
140
+ // Case 1: `application:` exists but has no nested `database:` — inject under it.
141
+ if (/^application:[ \t]*\n/m.test(content)) {
142
+ const next = content.replace(
143
+ /^application:[ \t]*\n/m,
144
+ `application:\n ${DB_MARKER}\n database:\n auto-provision: true\n region: emea\n`
145
+ )
146
+ if (next !== content) {
147
+ return { content: next, changed: true, reason: 'added-under-application' }
148
+ }
149
+ }
150
+
151
+ // Case 2: No `application:` block — append one at the bottom.
152
+ const trimmed = content.replace(/\s+$/, '')
153
+ const separator = trimmed.length > 0 ? '\n\n' : ''
154
+ return {
155
+ content: `${trimmed}${separator}${buildDatabaseBlock()}\n`,
156
+ changed: true,
157
+ reason: 'appended-application-database'
158
+ }
159
+ }
160
+
161
+ // ────────────────────────────────────────────────────────────────────────────
162
+ // Host web-src/ scaffolding
163
+ //
164
+ // Goal: after `npm install @adobedjangir/commerce-admin-management` the host app should pick
165
+ // up nav.json + pages/index.js automatically, with no manual edit of the
166
+ // bootstrap file required. We:
167
+ // 1. (re)write web-src/src/index.js — it carries a marker, so subsequent
168
+ // installs keep it in sync with whatever wiring the package needs.
169
+ // 2. create web-src/src/nav.json only if missing (host's data — never
170
+ // overwrite).
171
+ // 3. create web-src/src/pages/index.js only if missing (same reason).
172
+ // ────────────────────────────────────────────────────────────────────────────
173
+
174
+ const BOOTSTRAP_MARKER = '// @adobedjangir/commerce-admin-management: auto-generated bootstrap'
175
+
176
+ function bootstrapContents () {
177
+ return `/*
178
+ Copyright 2025 Adobe. All rights reserved.
179
+ Licensed under the Apache License, Version 2.0 (the "License");
180
+ */
181
+ ${BOOTSTRAP_MARKER} (updated on npm install)
182
+ // Edit nav.json or pages/index.js next to this file to add tabs.
183
+ // This file is overwritten on every \`npm install @adobedjangir/commerce-admin-management\`
184
+ // — delete the marker line above to opt out of auto-regeneration.
185
+
186
+ import 'core-js/stable'
187
+ import 'regenerator-runtime/runtime'
188
+
189
+ import React from 'react'
190
+ import { createRoot } from 'react-dom/client'
191
+
192
+ import Runtime, { init } from '@adobe/exc-app'
193
+ import { CommerceAdminManagementApp as App, configureWeb } from '@adobedjangir/commerce-admin-management/web'
194
+ import actions from './config.json'
195
+ import navConfig from './nav.json'
196
+ import extraPages from './pages'
197
+
198
+ configureWeb({
199
+ actionUrls: actions,
200
+ extraNav: Array.isArray(navConfig && navConfig.items) ? navConfig.items : [],
201
+ extraPages
202
+ })
203
+
204
+ window.React = React
205
+
206
+ try {
207
+ require('./exc-runtime')
208
+ init(bootstrapInExcShell)
209
+ } catch (e) {
210
+ console.log('application not running in Adobe Experience Cloud Shell')
211
+ bootstrapRaw()
212
+ }
213
+
214
+ function renderApp (runtime, ims) {
215
+ createRoot(document.getElementById('root')).render(
216
+ React.createElement(App, { runtime, ims })
217
+ )
218
+ }
219
+
220
+ function bootstrapRaw () {
221
+ renderApp({ on: () => {} }, {})
222
+ }
223
+
224
+ function bootstrapInExcShell () {
225
+ const runtime = Runtime()
226
+ runtime.favicon = './favicon.svg'
227
+
228
+ runtime.on('ready', ({ imsOrg, imsToken, imsProfile }) => {
229
+ runtime.done()
230
+ renderApp(runtime, {
231
+ profile: imsProfile,
232
+ org: imsOrg,
233
+ token: imsToken
234
+ })
235
+ })
236
+
237
+ runtime.solution = {
238
+ icon: 'AdobeExperienceCloud',
239
+ title: 'Commerce Admin Management',
240
+ shortTitle: 'Commerce Admin Management'
241
+ }
242
+ runtime.title = 'Commerce Admin Management'
243
+ }
244
+ `
245
+ }
246
+
247
+ function navJsonContents () {
248
+ // Ship a working starter entry so fresh installs render a host-side tab
249
+ // immediately. Devs replace/extend by editing this file.
250
+ return JSON.stringify({
251
+ items: [
252
+ {
253
+ id: 'welcome',
254
+ path: '/welcome',
255
+ label: 'Welcome',
256
+ icon: 'Folder'
257
+ }
258
+ ]
259
+ }, null, 2) + '\n'
260
+ }
261
+
262
+ function pagesIndexContents () {
263
+ return `/*
264
+ Copyright 2025 Adobe. All rights reserved.
265
+ Licensed under the Apache License, Version 2.0
266
+ */
267
+
268
+ // Host-app page registry. To add a new tab to the running app:
269
+ // 1. Create a file in this folder, e.g. ./MyReports.js, exporting a React
270
+ // component as default. It receives { runtime, ims } as props.
271
+ // 2. Import it here and add it to the map below, keyed by a stable id.
272
+ // 3. Add a matching entry to ../nav.json:
273
+ // { "id": "my-reports", "path": "/reports", "label": "My Reports",
274
+ // "icon": "Data" }
275
+ // On rebuild (or \`aio app run\`) the tab appears next to the package's
276
+ // built-in tabs — no other code changes needed.
277
+
278
+ import Welcome from './Welcome'
279
+
280
+ const pages = {
281
+ welcome: Welcome
282
+ }
283
+
284
+ export default pages
285
+ `
286
+ }
287
+
288
+ function welcomePageContents () {
289
+ return `/*
290
+ Copyright 2025 Adobe. All rights reserved.
291
+ Licensed under the Apache License, Version 2.0
292
+ */
293
+
294
+ // Starter page scaffolded by @adobedjangir/commerce-admin-management's installer.
295
+ // Safe to rename, edit, or delete — just remember to update
296
+ // ./index.js (page registry) and ../nav.json (tab entry) accordingly.
297
+
298
+ import React from 'react'
299
+ import { View, Heading } from '@adobe/react-spectrum'
300
+
301
+ export default function Welcome ({ runtime, ims }) {
302
+ return (
303
+ <View padding="size-400">
304
+ <Heading level={2}>Welcome</Heading>
305
+ <p>
306
+ This is a host-defined page registered via
307
+ <code> web-src/src/pages/index.js</code>. Duplicate this file to add
308
+ more tabs.
309
+ </p>
310
+ </View>
311
+ )
312
+ }
313
+ `
314
+ }
315
+
316
+ function ensureDir (dir) {
317
+ fs.mkdirSync(dir, { recursive: true })
318
+ }
319
+
320
+ function writeIfMissing (filePath, contents) {
321
+ if (fs.existsSync(filePath)) return { changed: false, reason: 'exists' }
322
+ ensureDir(path.dirname(filePath))
323
+ fs.writeFileSync(filePath, contents, 'utf8')
324
+ return { changed: true, reason: 'created' }
325
+ }
326
+
327
+ function writeBootstrap (filePath, contents) {
328
+ ensureDir(path.dirname(filePath))
329
+ if (fs.existsSync(filePath)) {
330
+ const existing = fs.readFileSync(filePath, 'utf8')
331
+ const hasMarker = existing.includes(BOOTSTRAP_MARKER)
332
+ // A bootstrap is considered "host-owned" only when it actively wires up
333
+ // the package (imports from `@adobedjangir/commerce-admin-management/web`). Without
334
+ // either the marker OR a real package import, we assume this is the
335
+ // stock aio template (e.g. just-scaffolded `aio app init`) — safe to
336
+ // overwrite so the install can connect the package's UI shell.
337
+ const wiresPackage = new RegExp("from\\s+['\"]@adobedjangir/commerce-admin-management/web['\"]").test(existing) ||
338
+ new RegExp("require\\(['\"]@adobedjangir/commerce-admin-management/web['\"]\\)").test(existing)
339
+ if (!hasMarker && wiresPackage) {
340
+ return { changed: false, reason: 'host-managed' }
341
+ }
342
+ if (hasMarker && existing === contents) {
343
+ return { changed: false, reason: 'up-to-date' }
344
+ }
345
+ }
346
+ fs.writeFileSync(filePath, contents, 'utf8')
347
+ return { changed: true, reason: 'written' }
348
+ }
349
+
350
+ function setupWebSrc (projectRoot) {
351
+ const webSrcDir = path.join(projectRoot, 'web-src', 'src')
352
+ const hasShell = fs.existsSync(path.join(projectRoot, 'web-src'))
353
+ if (!hasShell) {
354
+ return { changed: false, reason: 'no-web-src' }
355
+ }
356
+
357
+ const results = {
358
+ bootstrap: writeBootstrap(path.join(webSrcDir, 'index.js'), bootstrapContents()),
359
+ nav: writeIfMissing(path.join(webSrcDir, 'nav.json'), navJsonContents()),
360
+ pages: writeIfMissing(path.join(webSrcDir, 'pages', 'index.js'), pagesIndexContents()),
361
+ // Default starter page — only created on first install, never overwritten,
362
+ // and never auto-removed even if the dev deletes the registry entry.
363
+ welcome: writeIfMissing(path.join(webSrcDir, 'pages', 'Welcome.js'), welcomePageContents())
364
+ }
365
+ const changed = Object.values(results).some((r) => r.changed)
366
+ return { changed, results }
367
+ }
368
+
369
+ function setupAppConfig (projectRoot) {
370
+ const appConfigPath = path.join(projectRoot, 'app.config.yaml')
371
+ if (!fs.existsSync(appConfigPath)) {
372
+ return { changed: false, reason: 'no-app-config' }
373
+ }
374
+
375
+ // We only auto-patch the $include line here. ABDB provisioning defaults
376
+ // ship inside the package's ext.config.yaml — host devs override by adding
377
+ // their own `application: database: ...` block to app.config.yaml or by
378
+ // changing AIO_DB_REGION in .env. patchAppConfigDatabase is still exported
379
+ // so callers can opt into materializing the default into app.config.yaml,
380
+ // but it's not run by default to keep the host's app.config.yaml clean.
381
+ const original = fs.readFileSync(appConfigPath, 'utf8')
382
+ const { content, changed, reason } = patchAppConfig(original)
383
+ if (!changed) {
384
+ return { changed: false, reason }
385
+ }
386
+
387
+ fs.writeFileSync(appConfigPath, content, 'utf8')
388
+ return { changed: true, reason, detail: INCLUDE_REL }
389
+ }
390
+
391
+ function main () {
392
+ if (process.env.CONFIGURATION_MANAGEMENT_SKIP_SETUP === '1') {
393
+ return
394
+ }
395
+
396
+ const projectRoot = resolveProjectRoot()
397
+ if (!projectRoot) {
398
+ console.log(
399
+ '[@adobedjangir/commerce-admin-management] No App Builder project found — skip setup. ' +
400
+ 'Run `npx @adobedjangir/commerce-admin-management-setup` from your project root after `aio app init`.'
401
+ )
402
+ return
403
+ }
404
+
405
+ const app = setupAppConfig(projectRoot)
406
+ if (app.changed) {
407
+ console.log(
408
+ `[@adobedjangir/commerce-admin-management] Updated app.config.yaml (${app.reason}):\n` +
409
+ ` $include: ${app.detail}`
410
+ )
411
+ } else {
412
+ console.log('[@adobedjangir/commerce-admin-management] app.config.yaml already configured.')
413
+ }
414
+
415
+ const web = setupWebSrc(projectRoot)
416
+ if (web.reason === 'no-web-src') {
417
+ return
418
+ }
419
+ for (const [name, r] of Object.entries(web.results)) {
420
+ if (r.changed) {
421
+ console.log(`[@adobedjangir/commerce-admin-management] web-src/${name}: ${r.reason}`)
422
+ }
423
+ }
424
+ if (!web.changed) {
425
+ console.log('[@adobedjangir/commerce-admin-management] web-src bootstrap, nav.json, pages/ already in place.')
426
+ }
427
+ }
428
+
429
+ if (require.main === module) {
430
+ try {
431
+ main()
432
+ } catch (err) {
433
+ console.error('[@adobedjangir/commerce-admin-management] setup failed:', err.message)
434
+ process.exitCode = 1
435
+ }
436
+ }
437
+
438
+ module.exports = {
439
+ patchAppConfig,
440
+ patchAppConfigDatabase,
441
+ setupAppConfig,
442
+ setupWebSrc,
443
+ INCLUDE_REL,
444
+ EXTENSION_POINT
445
+ }
@@ -0,0 +1,8 @@
1
+ /*
2
+ Copyright 2025 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ */
7
+
8
+ module.exports = require('@adobedjangir/commerce-admin-get-config/config')
@@ -0,0 +1,8 @@
1
+ /*
2
+ Copyright 2025 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ */
7
+
8
+ module.exports = require('@adobedjangir/commerce-admin-get-config/abdb')
package/src/index.js ADDED
@@ -0,0 +1,22 @@
1
+ /*
2
+ Copyright 2025 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ */
7
+
8
+ const {
9
+ getConfig,
10
+ clearAbdbConfigCache,
11
+ COLLECTION: CONFIG_COLLECTION
12
+ } = require('@adobedjangir/commerce-admin-get-config/config')
13
+
14
+ module.exports = {
15
+ getConfig,
16
+ clearAbdbConfigCache,
17
+ COLLECTION: CONFIG_COLLECTION,
18
+ ...require('@adobedjangir/commerce-admin-get-config/abdb'),
19
+ ...require('@adobedjangir/commerce-admin-get-config/shared'),
20
+ ...require('@adobedjangir/commerce-admin-get-config/crypto'),
21
+ ...require('@adobedjangir/commerce-admin-get-config/oauth1a')
22
+ }
package/src/oauth1a.js ADDED
@@ -0,0 +1,8 @@
1
+ /*
2
+ Copyright 2025 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ */
7
+
8
+ module.exports = require('@adobedjangir/commerce-admin-get-config/oauth1a')
@@ -0,0 +1,8 @@
1
+ /*
2
+ Copyright 2025 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ */
7
+
8
+ module.exports = require('@adobedjangir/commerce-admin-get-config/crypto')
@@ -0,0 +1,8 @@
1
+ /*
2
+ Copyright 2025 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ */
7
+
8
+ module.exports = require('@adobedjangir/commerce-admin-get-config/shared')