@by-association-only/theme-backup 1.0.0 → 1.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.
@@ -0,0 +1,20 @@
1
+ name: Publish package to npm
2
+ on:
3
+ release:
4
+ types: [published]
5
+ jobs:
6
+ build:
7
+ runs-on: ubuntu-latest
8
+ permissions:
9
+ contents: read
10
+ id-token: write
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ - uses: actions/setup-node@v4
14
+ with:
15
+ node-version: '20.x'
16
+ registry-url: 'https://registry.npmjs.org'
17
+ - run: npm ci
18
+ - run: npm publish --access public
19
+ env:
20
+ NODE_AUTH_TOKEN: ${{ secrets.npm_token }}
package/README.md CHANGED
@@ -16,19 +16,7 @@ This tool helps you create backups of Shopify themes across multiple stores in y
16
16
 
17
17
  ## Setup
18
18
 
19
- 1) Install the package:
20
-
21
- ```bash
22
- npm i @by-association-only/theme-backup --save-dev
23
- ```
24
-
25
- or
26
-
27
- ```bash
28
- yarn add @by-association-only/theme-backup --save-dev
29
- ```
30
-
31
- 2) Add a config file in the root: `.bao-stores` (or use existing `.bao-translation-checker`)
19
+ 1) Add a config file in the root: `.bao-stores` (or use existing `.bao-translation-checker`)
32
20
 
33
21
  List each store name on a separate line (the part before .myshopify.com).
34
22
 
@@ -43,10 +31,10 @@ acmestore
43
31
  acmestore-us
44
32
  ```
45
33
 
46
- 3) Run the backup tool:
34
+ 2) Run the backup tool:
47
35
 
48
36
  ```bash
49
- bao-theme-backup
37
+ npx @by-association-only/theme-backup
50
38
  ```
51
39
 
52
40
  ## Usage
package/index.js CHANGED
@@ -410,7 +410,16 @@ async function deleteThemes(store, themes) {
410
410
  async function backupTheme(store, theme) {
411
411
  const date = new Date()
412
412
  const today = `${String(date.getDate()).padStart(2, '0')}/${String(date.getMonth() + 1).padStart(2, '0')}/${date.getFullYear()}` // DD/MM/YYYY
413
- const backupName = `${theme.name} (Backup ${today})`
413
+ let backupName = `${theme.name} (Backup ${today})`
414
+
415
+ // Check if name exceeds Shopify's 50 character limit
416
+ if (backupName.length > 50) {
417
+ console.log(chalk.yellow(`\n⚠ Generated backup name is too long (${backupName.length} characters)`))
418
+ console.log(chalk.gray(` Original: "${backupName}"`))
419
+ console.log(chalk.yellow('\nPlease enter a custom name for this backup:'))
420
+ backupName = await promptTextInput('Enter custom backup name', 50)
421
+ }
422
+
414
423
  const tempPath = path.join(process.cwd(), '.temp-backup')
415
424
 
416
425
  try {
@@ -446,6 +455,70 @@ async function backupTheme(store, theme) {
446
455
  }
447
456
  }
448
457
 
458
+ // Function to prompt user for text input
459
+ async function promptTextInput(message, maxLength = 50) {
460
+ // Remove all existing listeners to prevent conflicts
461
+ process.stdin.removeAllListeners('data')
462
+ process.stdin.setRawMode(true)
463
+ process.stdin.resume()
464
+
465
+ let input = ''
466
+
467
+ const updateDisplay = () => {
468
+ process.stdout.write('\x1B[2J\x1B[H') // Clear screen
469
+ console.log(chalk.yellow(`\n${message}`))
470
+ console.log(chalk.gray(`(Max ${maxLength} characters)`))
471
+ console.log(chalk.cyan(`\n> ${input}`))
472
+ if (input.length > maxLength) {
473
+ console.log(chalk.red(`\n⚠ Name is too long (${input.length}/${maxLength} characters)`))
474
+ }
475
+ console.log(chalk.gray('\nPress Enter to confirm, Ctrl+C to cancel'))
476
+ }
477
+
478
+ updateDisplay()
479
+
480
+ return new Promise((resolve) => {
481
+ const handleKey = (data) => {
482
+ const key = data.toString()
483
+
484
+ if (key === '\x03') { // Ctrl+C
485
+ process.stdin.removeAllListeners('data')
486
+ process.stdin.setRawMode(false)
487
+ process.stdin.pause()
488
+ console.log(chalk.yellow('\nCancelled...'))
489
+ process.exit(0)
490
+ return
491
+ }
492
+
493
+ if (key === '\r') { // Enter
494
+ if (input.length === 0) {
495
+ updateDisplay()
496
+ return
497
+ }
498
+ if (input.length > maxLength) {
499
+ updateDisplay()
500
+ return
501
+ }
502
+ process.stdin.removeAllListeners('data')
503
+ process.stdin.setRawMode(false)
504
+ process.stdin.pause()
505
+ resolve(input.trim())
506
+ return
507
+ }
508
+
509
+ if (key === '\x7F') { // Backspace
510
+ input = input.slice(0, -1)
511
+ } else if (key.length === 1 && key >= ' ' && key <= '~') { // Printable characters
512
+ input += key
513
+ }
514
+
515
+ updateDisplay()
516
+ }
517
+
518
+ process.stdin.on('data', handleKey)
519
+ })
520
+ }
521
+
449
522
  // Function to prompt user for yes/no
450
523
  async function promptYesNo(message) {
451
524
  process.stdin.setRawMode(true)
@@ -517,7 +590,16 @@ async function runBackup() {
517
590
  console.log(chalk.green('✓ Authentication verified\n'))
518
591
  }
519
592
 
520
- for (const store of stores) {
593
+ for (let i = 0; i < stores.length; i++) {
594
+ const store = stores[i]
595
+
596
+ // Clear screen before processing each store (except the first)
597
+ if (i > 0) {
598
+ // Use multiple methods for maximum compatibility
599
+ process.stdout.write('\x1B[2J\x1B[H') // ANSI clear
600
+ console.log('\n'.repeat(50)) // Fallback: push content off screen
601
+ }
602
+
521
603
  console.log(chalk.bold(`\nProcessing ${store}:`))
522
604
 
523
605
  // Get all themes
@@ -563,6 +645,9 @@ async function runBackup() {
563
645
  }
564
646
  }
565
647
 
648
+ // Clear screen before theme selection to remove any previous store's theme list
649
+ process.stdout.write('\x1B[2J\x1B[H')
650
+
566
651
  // Select theme to backup
567
652
  const selectedTheme = await selectTheme(store, 'Please select theme to backup')
568
653
  if (!selectedTheme) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@by-association-only/theme-backup",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Backup Shopify themes across multiple stores.",
5
5
  "type": "module",
6
6
  "main": "index.js",