@adobedjangir/commerce-admin-management 0.0.14 → 0.0.16
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 +4 -2
- package/package.json +8 -14
- package/scripts/setup.js +137 -7
package/README.md
CHANGED
|
@@ -40,6 +40,7 @@ and an extension point for host apps to add their own pages and actions.
|
|
|
40
40
|
| App Builder Database (ABDB) auto-provisioning on deploy | `ext.config.yaml` |
|
|
41
41
|
| Host-extensible nav and pages | `configureWeb({ extraNav, extraPages })` |
|
|
42
42
|
| Auto-scaffolded host scaffold on `npm install` | `scripts/setup.js` (postinstall hook) |
|
|
43
|
+
| Auto-bump host React/Spectrum/Adobe deps to React-18 floor | `scripts/setup.js` mutates host `package.json` |
|
|
43
44
|
|
|
44
45
|
---
|
|
45
46
|
|
|
@@ -50,14 +51,15 @@ and an extension point for host apps to add their own pages and actions.
|
|
|
50
51
|
aio app init my-commerce-admin
|
|
51
52
|
cd my-commerce-admin
|
|
52
53
|
|
|
53
|
-
# 2. Install the package
|
|
54
|
+
# 2. Install. The postinstall bumps the host's package.json to the
|
|
55
|
+
# React 18 / Spectrum 4 floor and re-runs `npm install` automatically.
|
|
54
56
|
npm install @adobedjangir/commerce-admin-management
|
|
55
57
|
|
|
56
58
|
# 3. Fill in .env (see required values below)
|
|
57
59
|
cp env.dist .env
|
|
58
60
|
$EDITOR .env
|
|
59
61
|
|
|
60
|
-
# 4. Deploy. ABDB is auto-provisioned;
|
|
62
|
+
# 4. Deploy. ABDB is auto-provisioned; actions + web assets ship to CDN.
|
|
61
63
|
aio app deploy
|
|
62
64
|
```
|
|
63
65
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobedjangir/commerce-admin-management",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.16",
|
|
4
4
|
"description": "Schema-driven system configuration for Adobe Commerce App Builder sync apps. Magento-style scoped config in Adobe App Builder Database (ABDB) with encryption, Commerce REST helpers, and React Admin UI.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Adobe Inc.",
|
|
@@ -53,26 +53,20 @@
|
|
|
53
53
|
"@adobe/aio-lib-core-auth": ">=1.1.0",
|
|
54
54
|
"@adobe/aio-lib-db": ">=1.0.0",
|
|
55
55
|
"@adobe/aio-lib-ims": ">=7.0.0",
|
|
56
|
-
"
|
|
57
|
-
"@adobe/exc-app": ">=1.0.0",
|
|
58
|
-
"@adobe/react-spectrum": ">=3.30.0",
|
|
59
|
-
"@adobe/uix-guest": ">=0.8.0",
|
|
60
|
-
"@spectrum-icons/workflow": ">=3.0.0 <5.0.0",
|
|
61
|
-
"dotenv": ">=16.0.0",
|
|
62
|
-
"react": ">=18.0.0",
|
|
63
|
-
"react-dom": ">=18.0.0",
|
|
64
|
-
"react-error-boundary": ">=3.1.0",
|
|
65
|
-
"react-router-dom": ">=6.0.0"
|
|
56
|
+
"dotenv": ">=16.0.0"
|
|
66
57
|
},
|
|
67
58
|
"peerDependenciesMeta": {
|
|
68
59
|
"@adobe/aio-lib-core-auth": {
|
|
69
|
-
"optional":
|
|
60
|
+
"optional": true
|
|
70
61
|
},
|
|
71
62
|
"@adobe/aio-lib-db": {
|
|
72
|
-
"optional":
|
|
63
|
+
"optional": true
|
|
73
64
|
},
|
|
74
65
|
"@adobe/aio-lib-ims": {
|
|
75
|
-
"optional":
|
|
66
|
+
"optional": true
|
|
67
|
+
},
|
|
68
|
+
"dotenv": {
|
|
69
|
+
"optional": true
|
|
76
70
|
}
|
|
77
71
|
},
|
|
78
72
|
"dependencies": {
|
package/scripts/setup.js
CHANGED
|
@@ -553,6 +553,35 @@ function satisfiesFloor (currentSpec, floorSpec) {
|
|
|
553
553
|
return compareVersions(cur, min) >= 0
|
|
554
554
|
}
|
|
555
555
|
|
|
556
|
+
/**
|
|
557
|
+
* Re-run `npm install` after bumping host package.json so the upgraded
|
|
558
|
+
* versions actually land in node_modules. Without this, the consumer
|
|
559
|
+
* would have to run `npm install` manually after our postinstall.
|
|
560
|
+
*
|
|
561
|
+
* Recursion is prevented by setting COMMERCE_ADMIN_MANAGEMENT_SKIP_SETUP=1
|
|
562
|
+
* in the child npm's env — main() bails immediately when it sees that
|
|
563
|
+
* flag, so the inner install doesn't loop back through this code.
|
|
564
|
+
*
|
|
565
|
+
* Failures here don't throw — we print a fallback hint and let the
|
|
566
|
+
* outer install report success. The consumer can re-run `npm install`
|
|
567
|
+
* manually if our auto-invocation can't reach the network.
|
|
568
|
+
*/
|
|
569
|
+
function autoRunNpmInstall (projectRoot) {
|
|
570
|
+
const { execSync } = require('child_process')
|
|
571
|
+
console.log('[@adobedjangir/commerce-admin-management] running `npm install` to apply the bumped versions…')
|
|
572
|
+
try {
|
|
573
|
+
execSync('npm install --no-audit --no-fund --silent --legacy-peer-deps', {
|
|
574
|
+
cwd: projectRoot,
|
|
575
|
+
stdio: 'inherit',
|
|
576
|
+
env: { ...process.env, COMMERCE_ADMIN_MANAGEMENT_SKIP_SETUP: '1' }
|
|
577
|
+
})
|
|
578
|
+
console.log('[@adobedjangir/commerce-admin-management] dependency upgrade complete ✓')
|
|
579
|
+
} catch (e) {
|
|
580
|
+
console.warn('[@adobedjangir/commerce-admin-management] auto-install failed. Run `npm install` manually.')
|
|
581
|
+
console.warn(` reason: ${e.message}`)
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
556
585
|
function ensureHostDeps (projectRoot) {
|
|
557
586
|
const pkgPath = path.join(projectRoot, 'package.json')
|
|
558
587
|
if (!fs.existsSync(pkgPath)) {
|
|
@@ -583,6 +612,90 @@ function ensureHostDeps (projectRoot) {
|
|
|
583
612
|
return { changed: true, bumped }
|
|
584
613
|
}
|
|
585
614
|
|
|
615
|
+
/**
|
|
616
|
+
* Seed the host's .env with the two values our actions can't run without:
|
|
617
|
+
* - AIO_DB_REGION defaults to "emea" (override after install if needed)
|
|
618
|
+
* - SYSTEM_CONFIG_CRYPT_KEY freshly generated AES-256 key, base64-encoded
|
|
619
|
+
*
|
|
620
|
+
* Never overwrites an existing value. The crypt key in particular must
|
|
621
|
+
* remain stable for the life of the workspace — rotating it makes every
|
|
622
|
+
* encrypted value already in ABDB undecryptable. So we only write it
|
|
623
|
+
* when the key is missing or empty.
|
|
624
|
+
*
|
|
625
|
+
* Returns { changed, set: [{key, source}], file }.
|
|
626
|
+
*/
|
|
627
|
+
function ensureEnvDefaults (projectRoot) {
|
|
628
|
+
const envPath = path.join(projectRoot, '.env')
|
|
629
|
+
let lines = []
|
|
630
|
+
let existed = false
|
|
631
|
+
if (fs.existsSync(envPath)) {
|
|
632
|
+
existed = true
|
|
633
|
+
try {
|
|
634
|
+
lines = fs.readFileSync(envPath, 'utf8').split(/\r?\n/)
|
|
635
|
+
} catch (_) {
|
|
636
|
+
return { changed: false, set: [], file: envPath, reason: 'unreadable' }
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// Read current values (ignore comments + blanks). Treat KEY= (empty)
|
|
641
|
+
// as missing so a half-stubbed .env still gets populated.
|
|
642
|
+
const current = new Map()
|
|
643
|
+
for (const raw of lines) {
|
|
644
|
+
const line = raw.trim()
|
|
645
|
+
if (!line || line.startsWith('#')) continue
|
|
646
|
+
const eq = line.indexOf('=')
|
|
647
|
+
if (eq === -1) continue
|
|
648
|
+
const k = line.slice(0, eq).trim()
|
|
649
|
+
const v = line.slice(eq + 1).trim()
|
|
650
|
+
if (k) current.set(k, v)
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
const set = []
|
|
654
|
+
const defaults = [
|
|
655
|
+
{ key: 'AIO_DB_REGION', value: 'emea',
|
|
656
|
+
comment: '# App Builder Database region — one of: amer | emea | apac | aus' },
|
|
657
|
+
{ key: 'SYSTEM_CONFIG_CRYPT_KEY', value: () => require('crypto').randomBytes(32).toString('base64'),
|
|
658
|
+
comment: '# AES-256 master key for at-rest encryption.\n# DO NOT rotate — values already in ABDB become undecryptable if you do.\n# Auto-generated on install; back this up like a database password.' }
|
|
659
|
+
]
|
|
660
|
+
|
|
661
|
+
// Build additions for keys that are missing OR empty.
|
|
662
|
+
const additions = []
|
|
663
|
+
for (const def of defaults) {
|
|
664
|
+
const cur = current.get(def.key)
|
|
665
|
+
if (cur && cur !== '' && cur !== '""' && cur !== "''") continue
|
|
666
|
+
const v = typeof def.value === 'function' ? def.value() : def.value
|
|
667
|
+
additions.push({ key: def.key, value: v, comment: def.comment })
|
|
668
|
+
set.push({ key: def.key, source: cur === undefined ? 'added' : 'filled-empty' })
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
if (additions.length === 0) return { changed: false, set: [], file: envPath }
|
|
672
|
+
|
|
673
|
+
// If the file existed, we either replace empty assignments in place
|
|
674
|
+
// (preserves user comments / ordering) or append at the bottom.
|
|
675
|
+
let next = existed ? lines.slice() : []
|
|
676
|
+
for (const add of additions) {
|
|
677
|
+
const cur = current.get(add.key)
|
|
678
|
+
if (cur === '' || cur === '""' || cur === "''") {
|
|
679
|
+
// Replace the empty line in place.
|
|
680
|
+
for (let i = 0; i < next.length; i++) {
|
|
681
|
+
const trimmed = next[i].trim()
|
|
682
|
+
if (trimmed.startsWith(add.key + '=') || trimmed.startsWith(add.key + ' =')) {
|
|
683
|
+
next[i] = `${add.key}=${add.value}`
|
|
684
|
+
break
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
} else {
|
|
688
|
+
// Append.
|
|
689
|
+
if (next.length && next[next.length - 1].trim() !== '') next.push('')
|
|
690
|
+
next.push(add.comment)
|
|
691
|
+
next.push(`${add.key}=${add.value}`)
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
fs.writeFileSync(envPath, next.join('\n') + (next[next.length - 1] === '' ? '' : '\n'), 'utf8')
|
|
696
|
+
return { changed: true, set, file: envPath, existed }
|
|
697
|
+
}
|
|
698
|
+
|
|
586
699
|
function setupAppConfig (projectRoot) {
|
|
587
700
|
const appConfigPath = path.join(projectRoot, 'app.config.yaml')
|
|
588
701
|
if (!fs.existsSync(appConfigPath)) {
|
|
@@ -606,9 +719,12 @@ function setupAppConfig (projectRoot) {
|
|
|
606
719
|
}
|
|
607
720
|
|
|
608
721
|
function main () {
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
722
|
+
// Two opt-outs:
|
|
723
|
+
// - CONFIGURATION_MANAGEMENT_SKIP_SETUP: legacy name kept for compat.
|
|
724
|
+
// - COMMERCE_ADMIN_MANAGEMENT_SKIP_SETUP: set by autoRunNpmInstall to
|
|
725
|
+
// prevent the recursive postinstall from re-running this code.
|
|
726
|
+
if (process.env.CONFIGURATION_MANAGEMENT_SKIP_SETUP === '1') return
|
|
727
|
+
if (process.env.COMMERCE_ADMIN_MANAGEMENT_SKIP_SETUP === '1') return
|
|
612
728
|
|
|
613
729
|
const projectRoot = resolveProjectRoot()
|
|
614
730
|
if (!projectRoot) {
|
|
@@ -626,18 +742,32 @@ function main () {
|
|
|
626
742
|
console.log('[@adobedjangir/commerce-admin-management] removed src/dx-excshell-1/ (replaced by commerce/backend-ui/1)')
|
|
627
743
|
}
|
|
628
744
|
|
|
745
|
+
// Seed .env with AIO_DB_REGION + SYSTEM_CONFIG_CRYPT_KEY so the consumer
|
|
746
|
+
// doesn't have to. Never overwrites an existing crypt key — see
|
|
747
|
+
// ensureEnvDefaults for why.
|
|
748
|
+
const env = ensureEnvDefaults(projectRoot)
|
|
749
|
+
if (env.changed) {
|
|
750
|
+
for (const s of env.set) {
|
|
751
|
+
console.log(`[@adobedjangir/commerce-admin-management] .env ${s.source}: ${s.key}`)
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
|
|
629
755
|
// Bump host package.json so React-18 + Spectrum-4 peers are satisfied
|
|
630
756
|
// without the consumer running a long `npm install --save react@^18 ...`
|
|
631
|
-
// chant.
|
|
632
|
-
//
|
|
633
|
-
//
|
|
757
|
+
// chant. If anything was bumped, automatically re-run npm install so the
|
|
758
|
+
// new versions actually land in node_modules. A guard env var prevents
|
|
759
|
+
// the recursive postinstall from re-running this step.
|
|
634
760
|
const deps = ensureHostDeps(projectRoot)
|
|
635
761
|
if (deps.changed) {
|
|
636
762
|
console.log('[@adobedjangir/commerce-admin-management] bumped host package.json:')
|
|
637
763
|
for (const b of deps.bumped) {
|
|
638
764
|
console.log(` • ${b.name}: ${b.was} → ${b.now}`)
|
|
639
765
|
}
|
|
640
|
-
|
|
766
|
+
if (process.env.COMMERCE_ADMIN_MANAGEMENT_NO_AUTO_INSTALL === '1') {
|
|
767
|
+
console.log('[@adobedjangir/commerce-admin-management] auto-install disabled; run `npm install` to apply.')
|
|
768
|
+
} else {
|
|
769
|
+
autoRunNpmInstall(projectRoot)
|
|
770
|
+
}
|
|
641
771
|
}
|
|
642
772
|
|
|
643
773
|
const app = setupAppConfig(projectRoot)
|