@adobedjangir/commerce-admin-management 0.0.15 → 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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/scripts/setup.js +94 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobedjangir/commerce-admin-management",
3
- "version": "0.0.15",
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.",
package/scripts/setup.js CHANGED
@@ -612,6 +612,90 @@ function ensureHostDeps (projectRoot) {
612
612
  return { changed: true, bumped }
613
613
  }
614
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
+
615
699
  function setupAppConfig (projectRoot) {
616
700
  const appConfigPath = path.join(projectRoot, 'app.config.yaml')
617
701
  if (!fs.existsSync(appConfigPath)) {
@@ -658,6 +742,16 @@ function main () {
658
742
  console.log('[@adobedjangir/commerce-admin-management] removed src/dx-excshell-1/ (replaced by commerce/backend-ui/1)')
659
743
  }
660
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
+
661
755
  // Bump host package.json so React-18 + Spectrum-4 peers are satisfied
662
756
  // without the consumer running a long `npm install --save react@^18 ...`
663
757
  // chant. If anything was bumped, automatically re-run npm install so the