tiendu 0.6.1 → 0.8.0

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 CHANGED
@@ -24,16 +24,18 @@ npm install -g tiendu
24
24
 
25
25
  ## Quick start
26
26
 
27
- ### Buildless theme (simple)
27
+ ### Simple theme
28
28
 
29
29
  ```bash
30
30
  mkdir my-theme && cd my-theme
31
31
  tiendu init
32
+ tiendu stores list
33
+ tiendu stores set <store-id>
32
34
  tiendu pull
33
35
  tiendu dev
34
36
  ```
35
37
 
36
- ### Built theme (TypeScript, npm packages, bundling)
38
+ ### Pipeline-enabled theme
37
39
 
38
40
  Clone the default theme template, connect to your store, and start developing:
39
41
 
@@ -41,10 +43,22 @@ Clone the default theme template, connect to your store, and start developing:
41
43
  git clone <default-theme-repo> my-theme && cd my-theme
42
44
  npm install
43
45
  tiendu init
46
+ tiendu stores list
47
+ tiendu stores set <store-id>
44
48
  tiendu dev
45
49
  ```
46
50
 
47
- `tiendu dev` creates a remote preview, builds your source files, runs an initial push from the prepared output, and then watches for changes. It prints a local live-preview URL first, plus a sharable preview URL like:
51
+ ### Agent-friendly setup
52
+
53
+ ```bash
54
+ tiendu init <api-key> [base-url] --non-interactive
55
+ tiendu stores list --non-interactive
56
+ tiendu stores set <store-id> --non-interactive
57
+ ```
58
+
59
+ When `--non-interactive` is passed, the CLI avoids prompts and prints plain text output.
60
+
61
+ `tiendu dev` creates a remote preview, builds or stages your theme into `dist/`, runs an initial push from that prepared output, and then watches for changes. It prints a local live-preview URL first, plus a sharable preview URL like:
48
62
 
49
63
  ```
50
64
  http://preview-xxxxxxxxxxxx.tiendu.uy/
@@ -59,24 +73,54 @@ It also starts a local live-preview URL that proxies the preview and auto-reload
59
73
 
60
74
  ## Commands
61
75
 
62
- ### `tiendu init`
76
+ ### `tiendu init [apiKey] [baseUrl]`
77
+
78
+ Initializes a theme project in the current directory.
63
79
 
64
- Initializes a theme project in the current directory. Prompts for your API key, API base URL (defaults to `https://tiendu.uy`), and store ID. Saves configuration to `.cli/`.
80
+ - With no arguments, it runs the interactive setup wizard.
81
+ - With `apiKey` and optional `baseUrl`, it reinitializes the saved config without prompts.
82
+ - If only one store is available, it is selected automatically.
83
+ - If multiple stores are available, leave the store unset and use `tiendu stores list` plus `tiendu stores set <id>`.
65
84
 
66
85
  ```bash
67
86
  tiendu init
87
+ tiendu init <api-key>
88
+ tiendu init <api-key> https://tiendu.uy --non-interactive
68
89
  ```
69
90
 
70
91
  > Add `.cli/` to your `.gitignore` if you version-control your theme — it contains your API key.
71
92
 
72
93
  ---
73
94
 
95
+ ### `tiendu stores list`
96
+
97
+ Lists all stores available for the configured API key and highlights the active one when present.
98
+
99
+ ```bash
100
+ tiendu stores list
101
+ tiendu stores list --non-interactive
102
+ ```
103
+
104
+ ---
105
+
106
+ ### `tiendu stores set <storeId>`
107
+
108
+ Validates the store against the configured API key and saves it as the active store.
109
+
110
+ ```bash
111
+ tiendu stores set 123
112
+ tiendu stores set 123 --non-interactive
113
+ ```
114
+
115
+ ---
116
+
74
117
  ### `tiendu pull`
75
118
 
76
- Downloads the current live theme from your store as local files.
119
+ Downloads the current live theme from your store into `dist/`.
77
120
 
78
- - **Buildless themes:** extracts to the current directory.
79
- - **Built themes** (with `tiendu.config.json`): extracts to `dist/`.
121
+ - `pull` clears `dist/` first.
122
+ - The downloaded archive is then extracted into `dist/`.
123
+ - Your source files, including `src/`, are left untouched.
80
124
 
81
125
  ```bash
82
126
  tiendu pull
@@ -86,19 +130,26 @@ tiendu pull
86
130
 
87
131
  ### `tiendu build`
88
132
 
89
- Builds a theme into its deployable output directory (`dist/`). Only available for built themes (requires `tiendu.config.json`).
133
+ Builds or stages the current theme into its deployable output directory (`dist/`).
134
+
135
+ - Theme files and assets are always prepared into `dist/`.
136
+ - Optional pipeline steps are enabled through `tiendu.config.json`.
137
+ - With no config file, or with no enabled pipeline steps, `build` just stages the theme files into `dist/`.
90
138
 
91
139
  ```bash
92
140
  tiendu build
141
+ tiendu build --skip-instances
93
142
  ```
94
143
 
144
+ - Use `--skip-instances` to omit template JSON, section group JSON, and `config/settings_data.json` from `dist/`. This is useful when you want to preserve the existing page/section instances on the preview.
145
+
95
146
  The build:
96
147
 
97
- 1. Copies theme files from `src/layout/`, `src/templates/`, and `src/snippets/` to `dist/`
148
+ 1. Copies theme files from `src/layout/`, `src/templates/`, `src/sections/`, `src/blocks/`, `src/snippets/`, and `src/config/` to `dist/`
98
149
  2. Flattens static files from `src/assets/` into `dist/assets/`
99
- 3. Discovers entry points in `src/layout/` and `src/templates/`
100
- 4. Bundles JS/TS and CSS into `dist/assets/`
101
- 5. Runs project PostCSS plugins for CSS entries when available (for example Tailwind v4)
150
+ 3. Optionally discovers script and style entry points in `src/layout/` and `src/templates/`
151
+ 4. Optionally compiles JS/TS and CSS into `dist/assets/`
152
+ 5. Optionally runs project PostCSS plugins for compiled CSS entries
102
153
 
103
154
  For TypeScript source, extensionless relative imports such as `import { initHeaderCart } from '../lib/scripts/cart'` are supported and recommended.
104
155
 
@@ -114,13 +165,15 @@ Entry naming convention:
114
165
 
115
166
  The main development command.
116
167
 
117
- - **Buildless themes:** watches the current directory and syncs file changes to the preview.
118
- - **Built themes:** runs `tiendu build` in watch mode first, then watches `dist/` and syncs changes to the preview.
168
+ - Runs `tiendu build` in watch mode first.
169
+ - Watches `dist/` and syncs changes to the preview.
119
170
 
120
171
  ```bash
121
172
  tiendu dev
173
+ tiendu dev --skip-instances
122
174
  ```
123
175
 
176
+ - Use `--skip-instances` to sync everything except template JSON, section group JSON, and `config/settings_data.json`. Existing instances on the preview are preserved.
124
177
  - Prints the preview URL on start
125
178
  - Re-syncs the full local theme to the preview on startup
126
179
  - Syncs file creates, edits and deletes
@@ -133,17 +186,19 @@ tiendu dev
133
186
 
134
187
  ### `tiendu push`
135
188
 
136
- Zips and uploads files to the active preview, replacing its content entirely.
189
+ Zips and uploads `dist/` to the active preview, replacing its content entirely.
137
190
 
138
- - **Buildless themes:** uploads from the current directory.
139
- - **Built themes:** runs `tiendu build` first, then uploads from `dist/`.
191
+ - By default it runs `tiendu build` first.
192
+ - Use `--skip-build` to upload the existing `dist/` artifact without rebuilding.
140
193
 
141
194
  ```bash
142
195
  tiendu push
143
196
  tiendu push --skip-build
197
+ tiendu push --skip-build --non-interactive
198
+ tiendu push --skip-instances
144
199
  ```
145
200
 
146
- Use `--skip-build` to upload the existing `dist/` output without rebuilding.
201
+ - Use `--skip-instances` to upload everything except template JSON, section group JSON, and `config/settings_data.json`. Existing instances on the preview are preserved.
147
202
 
148
203
  ---
149
204
 
@@ -151,15 +206,19 @@ Use `--skip-build` to upload the existing `dist/` output without rebuilding.
151
206
 
152
207
  Publishes the active preview to the live storefront. Visitors will see the new theme immediately. All previews for the store are removed after publishing.
153
208
 
154
- - **Buildless themes:** publishes the active preview as-is.
155
- - **Built themes:** builds the theme, uploads the latest `dist/` output to the preview, then publishes it.
209
+ - By default it runs `tiendu build`, uploads `dist/` to the preview, and then publishes it.
210
+ - Use `--skip-build` to publish after syncing the existing `dist/` output.
156
211
 
157
212
  ```bash
158
213
  tiendu publish
159
214
  tiendu publish --skip-build
215
+ tiendu publish --skip-build --non-interactive
216
+ tiendu publish --skip-instances
160
217
  ```
161
218
 
162
- Use `--skip-build` to publish after uploading the existing `dist/` output without rebuilding.
219
+ - Use `--skip-instances` to publish everything except template JSON, section group JSON, and `config/settings_data.json`. Existing instances on the preview are preserved.
220
+
221
+ In non-interactive mode, the publish confirmation is skipped.
163
222
 
164
223
  ---
165
224
 
@@ -211,6 +270,7 @@ Deletes the active preview (both remotely and from your local config).
211
270
 
212
271
  ```bash
213
272
  tiendu preview delete
273
+ tiendu preview delete --non-interactive
214
274
  ```
215
275
 
216
276
  ---
@@ -227,23 +287,27 @@ tiendu preview open
227
287
 
228
288
  ## Typical workflow
229
289
 
230
- ### Buildless
290
+ ### Standard
231
291
 
232
292
  ```
233
- tiendu init # one time: connect to your store
234
- tiendu pull # one time: download the live theme
293
+ tiendu init # one time: connect to your Tiendu account
294
+ tiendu stores list # one time: see available stores
295
+ tiendu stores set # one time: select the store to work on
296
+ tiendu pull # one time: refresh dist/ from the live theme
235
297
 
236
- tiendu dev # develop: edit locally, see changes live at the preview URL
298
+ tiendu dev # develop: build/stage into dist/, sync preview updates live
237
299
 
238
300
  tiendu publish # when ready: push to the live storefront
239
301
  ```
240
302
 
241
- ### Built theme
303
+ ### Pipeline-enabled
242
304
 
243
305
  ```
244
306
  git clone <template-repo> my-theme
245
307
  cd my-theme && npm install
246
- tiendu init # one time: connect to your store
308
+ tiendu init # one time: connect to your Tiendu account
309
+ tiendu stores list # one time: see available stores
310
+ tiendu stores set # one time: select the store to work on
247
311
 
248
312
  tiendu dev # develop: builds src/, watches dist/, syncs to preview
249
313
 
@@ -264,9 +328,13 @@ A **theme preview** is a remote copy of your theme hosted by Tiendu. It renders
264
328
 
265
329
  ---
266
330
 
267
- ## Built themes
331
+ ## Pipeline-enabled themes
332
+
333
+ All themes are staged into `dist/` before upload.
268
334
 
269
- A **built theme** is a theme that uses `tiendu.config.json` to enable the build pipeline. It allows:
335
+ `tiendu.config.json` can optionally enable extra pipeline steps such as script compilation, style compilation, and PostCSS processing.
336
+
337
+ When pipeline steps are enabled, a theme can use:
270
338
 
271
339
  - npm packages via a local `package.json`
272
340
  - TypeScript (`.ts`) for browser code
@@ -277,7 +345,7 @@ A **built theme** is a theme that uses `tiendu.config.json` to enable the build
277
345
 
278
346
  ```
279
347
  my-theme/
280
- ├── tiendu.config.json # marks this as a built theme
348
+ ├── tiendu.config.json # optional pipeline flags
281
349
  ├── package.json # npm dependencies
282
350
  ├── .gitignore
283
351
  ├── src/
@@ -293,21 +361,21 @@ my-theme/
293
361
  │ ├── assets/ # source assets → flattened into dist/assets/
294
362
  │ ├── lib/ # shared modules (bundled into entries, not served)
295
363
  │ └── css/ # shared CSS (imported by entry CSS)
296
- └── dist/ # build output (gitignored, uploaded to Tiendu)
364
+ └── dist/ # staged upload artifact (gitignored, uploaded to Tiendu)
297
365
  ```
298
366
 
299
367
  ### How it works
300
368
 
301
- 1. Source assets in `src/assets/` are flattened into `dist/assets/` (`payment-methods/visa.svg` becomes `payment-methods___visa.svg`)
302
- 2. Source JS/TS/CSS in `src/` is bundled by esbuild into `dist/assets/`
303
- 3. CSS entries also run through your local PostCSS pipeline when configured
304
- 4. Liquid files are copied from `src/` to `dist/`
369
+ 1. Theme files and static assets are staged into `dist/`
370
+ 2. Script entries are compiled only when `pipeline.compileScripts` is enabled
371
+ 3. Style entries are compiled only when `pipeline.compileStyles` is enabled
372
+ 4. PostCSS runs only when `pipeline.postcss` is enabled
305
373
  5. `dist/` is what gets uploaded — it looks like a normal Tiendu theme
306
- 6. Liquid templates reference bundles and assets via `asset_url` (e.g. `{{ 'layout-theme.bundle.js' | asset_url | script_tag }}` or `{{ 'payment-methods/visa.svg' | asset_url }}`)
374
+ 6. Liquid templates reference bundles and assets via `asset_url` when compiled entries are used
307
375
 
308
376
  ### Tailwind v4
309
377
 
310
- Built themes can use Tailwind v4 in CSS entry files.
378
+ Pipeline-enabled themes can use Tailwind v4 in CSS entry files when `pipeline.compileStyles` and `pipeline.postcss` are enabled.
311
379
 
312
380
  Install it in your theme project:
313
381
 
@@ -338,15 +406,22 @@ export default {
338
406
 
339
407
  ### tiendu.config.json
340
408
 
341
- Minimal config the build conventions are hardcoded:
409
+ Config is optional. When present, you can enable pipeline steps explicitly:
342
410
 
343
411
  ```json
344
412
  {
345
- "name": "my-theme",
346
- "version": "1.0.0"
413
+ "pipeline": {
414
+ "compileScripts": true,
415
+ "compileStyles": true,
416
+ "postcss": true
417
+ }
347
418
  }
348
419
  ```
349
420
 
421
+ Without enabled pipeline steps, the CLI still stages the theme into `dist/`, but it skips compilation and PostCSS.
422
+
423
+ With no `tiendu.config.json`, the behavior is the same as having all pipeline steps disabled.
424
+
350
425
  ---
351
426
 
352
427
  ## License
package/bin/tiendu.js CHANGED
@@ -15,80 +15,140 @@ import {
15
15
  previewAttach,
16
16
  previewDetach,
17
17
  } from "../lib/preview.mjs";
18
+ import { storesList, storesSet } from "../lib/stores.mjs";
18
19
  import {
19
20
  checkForUpdates,
20
21
  checkForUpdatesNow,
21
22
  getCurrentVersion,
22
23
  } from "../lib/update-check.mjs";
24
+ import { configureUi } from "../lib/ui.mjs";
23
25
 
24
26
  const HELP = `
25
27
  tiendu — Tiendu theme development CLI
26
28
 
27
29
  Usage:
28
- tiendu init [dir] Set up a theme project (optionally in a new directory)
29
- tiendu pull [previewKey] Download the live theme, or a specific preview's files
30
- tiendu build Build a theme (requires tiendu.config.json)
30
+ tiendu init [apiKey] [baseUrl] [--dir <path>]
31
+ Initialize interactively, or reset config with direct credentials
32
+ tiendu stores list List stores available for the configured API key
33
+ tiendu stores set <storeId> Select the active store
34
+ tiendu pull [previewKey] Download the live theme or a preview into dist/
35
+ tiendu build Build or stage the current theme into dist/
31
36
  tiendu push [previewKey] [--skip-build]
32
- Upload files to the attached or specified preview
33
- tiendu dev Start dev mode: auto-sync changes to a live preview URL
37
+ Upload dist/ to the attached or specified preview
38
+ tiendu dev Start dev mode: auto-sync changes to a live preview URL
34
39
  tiendu publish [previewKey] [--skip-build]
35
- Publish the attached or specified preview to the live storefront
40
+ Build/sync dist/ and publish the preview live
36
41
 
37
- tiendu preview Show the attached preview details
42
+ tiendu preview Show the attached preview details
38
43
  tiendu preview create [name]
39
- Create a new preview (and attach to it)
40
- tiendu preview list List all previews for your store
41
- tiendu preview attach [key]
42
- Attach to an existing preview by its key
43
- tiendu preview detach Detach from the current preview (without deleting it)
44
- tiendu preview delete [key]
45
- Delete a preview (defaults to the attached one)
46
- tiendu preview open Open the attached preview URL in your browser
44
+ Create a new preview (and attach to it)
45
+ tiendu preview list List all previews for your store
46
+ tiendu preview attach [key] Attach to an existing preview by its key
47
+ tiendu preview detach Detach from the current preview (without deleting it)
48
+ tiendu preview delete [key] Delete a preview (defaults to the attached one)
49
+ tiendu preview open Open the attached preview URL in your browser
47
50
 
48
- tiendu check-updates Check npm for a newer CLI version
49
- tiendu version Show the current CLI version
51
+ tiendu check-updates Check npm for a newer CLI version
52
+ tiendu version Show the current CLI version
50
53
 
51
- tiendu --help, -h Show this help message
52
- tiendu --version, -v Show the current CLI version
54
+ Global options:
55
+ --non-interactive Disable prompts, print plain text output, and skip confirmations
56
+ --dir <path> Create the project inside a new directory during init
57
+ --skip-build Reuse the existing dist/ output for push or publish
58
+ --skip-instances Skip template/section group JSON and settings_data.json (preserves existing instances on the preview)
59
+ --help, -h Show this help message
60
+ --version, -v Show the current CLI version
61
+
62
+ Init behavior:
63
+ tiendu init Interactive setup wizard
64
+ tiendu init <apiKey> Reset saved config and connect using the default base URL
65
+ tiendu init <apiKey> <url> Reset saved config and connect using a custom base URL
66
+ The default base URL points to the Tiendu platform and rarely needs to change.
67
+ If exactly one store is available, it is selected automatically.
68
+ If multiple stores are available, run tiendu stores list and tiendu stores set <id>.
69
+
70
+ Agent-friendly setup:
71
+ tiendu init <apiKey> [baseUrl] --non-interactive
72
+ tiendu stores list --non-interactive
73
+ tiendu stores set <id> --non-interactive
74
+ tiendu pull --non-interactive
75
+ tiendu push --non-interactive
76
+ tiendu publish --non-interactive
77
+
78
+ Push and pull behavior:
79
+ build always prepares dist/ as the local deploy artifact.
80
+ push sends a zip of dist/ to the target preview.
81
+ pull resets dist/ and extracts the downloaded theme there.
82
+ pull does not delete src/ files.
83
+
84
+ Pipeline behavior:
85
+ tiendu.config.json can enable optional pipeline steps.
86
+ pipeline.compileScripts enables JS/TS entry compilation.
87
+ pipeline.compileStyles enables CSS entry compilation.
88
+ pipeline.postcss enables PostCSS for compiled style entries.
89
+ With no config file, or with no enabled pipeline steps, build just stages theme files into dist/.
53
90
 
54
91
  Typical workflow:
55
- tiendu init my-store Set up a new project in ./my-store
56
- cd my-store
57
- tiendu pull Download the current live theme
58
- tiendu build Build the theme (for themes with tiendu.config.json)
59
- tiendu dev Edit locally — preview updates in real time
60
- tiendu publish Ship to the live storefront when ready
92
+ tiendu init Connect to Tiendu and save your credentials
93
+ tiendu stores list See available stores
94
+ tiendu stores set <id> Select the store you want to work on
95
+ tiendu pull Refresh dist/ from the current live theme
96
+ tiendu dev Edit locally — preview updates in real time
97
+ tiendu publish Ship to the live storefront when ready
61
98
  `;
62
99
 
63
- /**
64
- * Extract the first positional argument that is not a flag (--skip-build, etc.).
65
- * @param {string[]} args - CLI args after the command name
66
- * @returns {string | undefined}
67
- */
68
- const extractPositionalArg = (args) =>
69
- args.find((arg) => !arg.startsWith("--"));
100
+ const parseArgv = (argv) => {
101
+ const flags = new Set();
102
+ const values = new Map();
103
+ const positionals = [];
104
+
105
+ for (let index = 0; index < argv.length; index += 1) {
106
+ const arg = argv[index];
107
+
108
+ if (!arg.startsWith("--")) {
109
+ positionals.push(arg);
110
+ continue;
111
+ }
112
+
113
+ if (arg === "--dir") {
114
+ const value = argv[index + 1];
115
+ if (!value || value.startsWith("--")) {
116
+ console.error("Missing value for --dir.");
117
+ process.exit(1);
118
+ }
119
+ values.set("dir", value);
120
+ index += 1;
121
+ continue;
122
+ }
123
+
124
+ flags.add(arg);
125
+ }
126
+
127
+ return { flags, values, positionals };
128
+ };
70
129
 
71
130
  const main = async () => {
72
- const args = process.argv.slice(2);
73
- const command = args[0];
74
- const subcommand = args[1];
75
- const restArgs = args.slice(1);
76
- const skipBuild = args.includes("--skip-build");
131
+ const argv = process.argv.slice(2);
132
+ const { flags, values, positionals } = parseArgv(argv);
133
+ const command = positionals[0];
134
+ const subcommand = positionals[1];
135
+ const skipBuild = flags.has("--skip-build");
136
+ const skipInstances = flags.has("--skip-instances");
137
+ const nonInteractive =
138
+ flags.has("--non-interactive") || !process.stdin.isTTY || !process.stdout.isTTY;
139
+
140
+ configureUi({ nonInteractive });
77
141
 
78
142
  if (
79
143
  command === "version" ||
80
- command === "--version" ||
81
- command === "-v"
144
+ argv.includes("--version") ||
145
+ argv.includes("-v")
82
146
  ) {
83
147
  console.log(getCurrentVersion());
84
148
  process.exit(0);
85
149
  }
86
150
 
87
- if (
88
- !command ||
89
- command === "--help" ||
90
- command === "-h"
91
- ) {
151
+ if (!command || argv.includes("--help") || argv.includes("-h")) {
92
152
  console.log(HELP.trim());
93
153
  process.exit(0);
94
154
  }
@@ -98,40 +158,57 @@ const main = async () => {
98
158
  return;
99
159
  }
100
160
 
101
- // Check for updates at most once per day (non-blocking)
102
161
  await checkForUpdates();
103
162
 
104
163
  if (command === "init") {
105
- await init(args[1]); // optional directory name
164
+ const initArgs = positionals.slice(1);
165
+ await init({
166
+ dirArg: values.get("dir"),
167
+ apiKeyArg: initArgs[0],
168
+ baseUrlArg: initArgs[1],
169
+ });
106
170
  return;
107
171
  }
108
172
 
173
+ if (command === "stores") {
174
+ if (subcommand === "list") {
175
+ await storesList();
176
+ return;
177
+ }
178
+
179
+ if (subcommand === "set") {
180
+ await storesSet(positionals[2]);
181
+ return;
182
+ }
183
+
184
+ console.error(`Unknown subcommand: stores ${subcommand ?? "(none)"}`);
185
+ console.log(HELP.trim());
186
+ process.exit(1);
187
+ }
188
+
109
189
  if (command === "pull") {
110
- const previewKey = extractPositionalArg(restArgs);
111
- await pull({ previewKey });
190
+ await pull({ previewKey: positionals[1] });
112
191
  return;
113
192
  }
114
193
 
115
194
  if (command === "build") {
116
- const result = await build();
195
+ const result = await build({ skipInstances });
117
196
  if (!result.ok) process.exit(1);
118
197
  return;
119
198
  }
120
199
 
121
200
  if (command === "push") {
122
- const previewKey = extractPositionalArg(restArgs);
123
- await push({ skipBuild, previewKey });
201
+ await push({ skipBuild, previewKey: positionals[1], skipInstances });
124
202
  return;
125
203
  }
126
204
 
127
205
  if (command === "dev") {
128
- await dev();
206
+ await dev({ skipInstances });
129
207
  return;
130
208
  }
131
209
 
132
210
  if (command === "publish") {
133
- const previewKey = extractPositionalArg(restArgs);
134
- await publish({ skipBuild, previewKey });
211
+ await publish({ skipBuild, previewKey: positionals[1], skipInstances });
135
212
  return;
136
213
  }
137
214
 
@@ -141,7 +218,7 @@ const main = async () => {
141
218
  return;
142
219
  }
143
220
  if (subcommand === "create") {
144
- await previewCreate(args[2]);
221
+ await previewCreate(positionals[2]);
145
222
  return;
146
223
  }
147
224
  if (subcommand === "list") {
@@ -149,7 +226,7 @@ const main = async () => {
149
226
  return;
150
227
  }
151
228
  if (subcommand === "attach") {
152
- await previewAttach(args[2]);
229
+ await previewAttach(positionals[2]);
153
230
  return;
154
231
  }
155
232
  if (subcommand === "detach") {
@@ -157,7 +234,7 @@ const main = async () => {
157
234
  return;
158
235
  }
159
236
  if (subcommand === "delete") {
160
- await previewDelete(args[2]);
237
+ await previewDelete(positionals[2]);
161
238
  return;
162
239
  }
163
240
  if (subcommand === "open") {
package/lib/api.mjs CHANGED
@@ -219,23 +219,25 @@ export const downloadPreviewArchive = async (
219
219
  * @returns {Promise<{ ok: true } | { ok: false, error: string, retriable?: boolean }>}
220
220
  */
221
221
  export const uploadPreviewZip = async (
222
- apiBaseUrl,
223
- apiKey,
224
- storeId,
225
- previewKey,
226
- zipBuffer,
222
+ apiBaseUrl,
223
+ apiKey,
224
+ storeId,
225
+ previewKey,
226
+ zipBuffer,
227
+ preserveInstances = false,
227
228
  ) => {
228
- try {
229
- const response = await apiFetch(
230
- apiBaseUrl,
231
- apiKey,
232
- `/api/admin/stores/${storeId}/theme-previews/${previewKey}/upload`,
233
- {
234
- method: "POST",
235
- body: zipBuffer,
236
- contentType: "application/zip",
237
- },
238
- );
229
+ try {
230
+ const query = preserveInstances ? "?preserveInstances=true" : "";
231
+ const response = await apiFetch(
232
+ apiBaseUrl,
233
+ apiKey,
234
+ `/api/admin/stores/${storeId}/theme-previews/${previewKey}/upload${query}`,
235
+ {
236
+ method: "POST",
237
+ body: zipBuffer,
238
+ contentType: "application/zip",
239
+ },
240
+ );
239
241
 
240
242
  if (!response.ok) {
241
243
  const body = await response.text().catch(() => "");
package/lib/archive.mjs CHANGED
@@ -13,7 +13,7 @@ export const listAllFiles = async (rootDir) => listFilesRecursive(rootDir);
13
13
  * @param {string} rootDir
14
14
  * @returns {Promise<Buffer>}
15
15
  */
16
- export const createZipFromDirectory = async (rootDir) => {
16
+ export const createZipFromDirectory = async (rootDir, shouldInclude) => {
17
17
  const absoluteFiles = await listAllFiles(rootDir);
18
18
  /** @type {Record<string, Uint8Array>} */
19
19
  const entries = {};
@@ -23,6 +23,7 @@ export const createZipFromDirectory = async (rootDir) => {
23
23
  .relative(rootDir, absolutePath)
24
24
  .split(path.sep)
25
25
  .join("/");
26
+ if (shouldInclude && !shouldInclude(relativePath)) continue;
26
27
  entries[relativePath] = new Uint8Array(await readFile(absolutePath));
27
28
  }
28
29