tiendu 0.2.0 → 0.2.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.
- package/bin/tiendu.js +7 -1
- package/lib/dev.mjs +28 -5
- package/lib/preview.mjs +111 -13
- package/lib/pull.mjs +0 -4
- package/package.json +1 -1
package/bin/tiendu.js
CHANGED
|
@@ -7,6 +7,7 @@ import { dev } from "../lib/dev.mjs";
|
|
|
7
7
|
import { publish } from "../lib/publish.mjs";
|
|
8
8
|
import {
|
|
9
9
|
previewCreate,
|
|
10
|
+
previewShow,
|
|
10
11
|
previewList,
|
|
11
12
|
previewDelete,
|
|
12
13
|
previewOpen,
|
|
@@ -23,10 +24,11 @@ Usage:
|
|
|
23
24
|
tiendu dev Start dev mode: auto-sync changes to a live preview URL
|
|
24
25
|
tiendu publish Publish the active preview to the live storefront
|
|
25
26
|
|
|
27
|
+
tiendu preview Show the active preview details
|
|
26
28
|
tiendu preview create Create a new remote preview
|
|
27
29
|
tiendu preview list List previews for your store
|
|
28
30
|
tiendu preview delete Delete the active preview
|
|
29
|
-
tiendu preview open Open the preview URL in your browser
|
|
31
|
+
tiendu preview open Open the active preview URL in your browser
|
|
30
32
|
|
|
31
33
|
tiendu help Show this help message
|
|
32
34
|
|
|
@@ -82,6 +84,10 @@ const main = async () => {
|
|
|
82
84
|
}
|
|
83
85
|
|
|
84
86
|
if (command === "preview") {
|
|
87
|
+
if (!subcommand) {
|
|
88
|
+
await previewShow();
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
85
91
|
if (subcommand === "create") {
|
|
86
92
|
await previewCreate(args[2]);
|
|
87
93
|
return;
|
package/lib/dev.mjs
CHANGED
|
@@ -4,7 +4,11 @@ import path from "node:path";
|
|
|
4
4
|
import * as p from "@clack/prompts";
|
|
5
5
|
import { zipSync } from "fflate";
|
|
6
6
|
import { loadConfigOrFail, writeConfig } from "./config.mjs";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
createPreview,
|
|
9
|
+
listPreviews,
|
|
10
|
+
resolveActivePreview,
|
|
11
|
+
} from "./preview.mjs";
|
|
8
12
|
import {
|
|
9
13
|
deletePreviewFile,
|
|
10
14
|
uploadPreviewFileMultipart,
|
|
@@ -54,7 +58,19 @@ export const dev = async () => {
|
|
|
54
58
|
const { apiKey } = credentials;
|
|
55
59
|
const rootDir = process.cwd();
|
|
56
60
|
|
|
57
|
-
|
|
61
|
+
const existingPreviewsResult = await listPreviews(
|
|
62
|
+
apiBaseUrl,
|
|
63
|
+
apiKey,
|
|
64
|
+
storeId,
|
|
65
|
+
);
|
|
66
|
+
if (!existingPreviewsResult.ok) {
|
|
67
|
+
p.log.error(existingPreviewsResult.error);
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
let previewKey =
|
|
72
|
+
resolveActivePreview(existingPreviewsResult.data, config.previewKey)
|
|
73
|
+
?.previewKey ?? config.previewKey;
|
|
58
74
|
let previewUrl;
|
|
59
75
|
|
|
60
76
|
if (!previewKey) {
|
|
@@ -102,15 +118,22 @@ export const dev = async () => {
|
|
|
102
118
|
process.exit(1);
|
|
103
119
|
}
|
|
104
120
|
|
|
105
|
-
const existing = listResult.data
|
|
121
|
+
const existing = resolveActivePreview(listResult.data, previewKey);
|
|
106
122
|
if (!existing) {
|
|
107
|
-
spinner.stop("
|
|
123
|
+
spinner.stop("Could not determine the active preview.", 1);
|
|
108
124
|
p.log.error(
|
|
109
|
-
|
|
125
|
+
listResult.data.length === 0
|
|
126
|
+
? "No previews found for this store. A new preview will be created if you clear the local config and run tiendu dev again."
|
|
127
|
+
: "Run tiendu preview list and then set or recreate the preview.",
|
|
110
128
|
);
|
|
111
129
|
process.exit(1);
|
|
112
130
|
}
|
|
113
131
|
|
|
132
|
+
previewKey = existing.previewKey;
|
|
133
|
+
if (config.previewKey !== previewKey) {
|
|
134
|
+
await writeConfig({ ...config, previewKey });
|
|
135
|
+
}
|
|
136
|
+
|
|
114
137
|
previewUrl = buildPreviewUrl(apiBaseUrl, existing.previewHostname);
|
|
115
138
|
spinner.stop(`Preview: ${previewUrl}`);
|
|
116
139
|
}
|
package/lib/preview.mjs
CHANGED
|
@@ -8,6 +8,25 @@ const buildPreviewUrl = (apiBaseUrl, previewHostname) => {
|
|
|
8
8
|
return `${base.protocol}//${previewHostname}${!hasExplicitPort && base.port ? `:${base.port}` : ""}/`;
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* @param {Array<any>} previews
|
|
13
|
+
* @param {string | undefined} previewKey
|
|
14
|
+
* @returns {any | null}
|
|
15
|
+
*/
|
|
16
|
+
export const resolveActivePreview = (previews, previewKey) => {
|
|
17
|
+
if (previewKey) {
|
|
18
|
+
return (
|
|
19
|
+
previews.find((preview) => preview.previewKey === previewKey) ?? null
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (previews.length === 1) {
|
|
24
|
+
return previews[0];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return null;
|
|
28
|
+
};
|
|
29
|
+
|
|
11
30
|
/**
|
|
12
31
|
* @param {string} apiBaseUrl
|
|
13
32
|
* @param {string} apiKey
|
|
@@ -196,23 +215,103 @@ export const previewList = async () => {
|
|
|
196
215
|
`${result.data.length} preview${result.data.length === 1 ? "" : "s"}:`,
|
|
197
216
|
);
|
|
198
217
|
|
|
218
|
+
const activePreview = resolveActivePreview(result.data, config.previewKey);
|
|
219
|
+
|
|
199
220
|
for (const preview of result.data) {
|
|
200
|
-
const active =
|
|
221
|
+
const active =
|
|
222
|
+
activePreview?.previewKey === preview.previewKey ? " ← active" : "";
|
|
201
223
|
const url = buildPreviewUrl(config.apiBaseUrl, preview.previewHostname);
|
|
202
224
|
p.log.message(` ${preview.name} ${url}${active}`);
|
|
203
225
|
}
|
|
204
226
|
};
|
|
205
227
|
|
|
228
|
+
const formatRelativeDate = (value) => {
|
|
229
|
+
if (!value) return "Unknown";
|
|
230
|
+
const date = new Date(value);
|
|
231
|
+
if (Number.isNaN(date.getTime())) return "Unknown";
|
|
232
|
+
|
|
233
|
+
const diffMs = Date.now() - date.getTime();
|
|
234
|
+
const diffMinutes = Math.floor(diffMs / (60 * 1000));
|
|
235
|
+
if (diffMinutes < 1) return "just now";
|
|
236
|
+
if (diffMinutes < 60)
|
|
237
|
+
return `${diffMinutes} minute${diffMinutes === 1 ? "" : "s"} ago`;
|
|
238
|
+
const diffHours = Math.floor(diffMinutes / 60);
|
|
239
|
+
if (diffHours < 24)
|
|
240
|
+
return `${diffHours} hour${diffHours === 1 ? "" : "s"} ago`;
|
|
241
|
+
const diffDays = Math.floor(diffHours / 24);
|
|
242
|
+
return `${diffDays} day${diffDays === 1 ? "" : "s"} ago`;
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
export const previewShow = async () => {
|
|
246
|
+
const { config, credentials } = await loadConfigOrFail();
|
|
247
|
+
|
|
248
|
+
const spinner = p.spinner();
|
|
249
|
+
spinner.start("Fetching preview details...");
|
|
250
|
+
|
|
251
|
+
const result = await listPreviews(
|
|
252
|
+
config.apiBaseUrl,
|
|
253
|
+
credentials.apiKey,
|
|
254
|
+
config.storeId,
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
if (!result.ok) {
|
|
258
|
+
spinner.stop("Failed to fetch previews.", 1);
|
|
259
|
+
p.log.error(result.error);
|
|
260
|
+
process.exit(1);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const preview = resolveActivePreview(result.data, config.previewKey);
|
|
264
|
+
if (!preview) {
|
|
265
|
+
spinner.stop("Could not determine the active preview.", 1);
|
|
266
|
+
p.log.error(
|
|
267
|
+
result.data.length === 0
|
|
268
|
+
? "No previews found for this store."
|
|
269
|
+
: "Run tiendu preview list to inspect available previews.",
|
|
270
|
+
);
|
|
271
|
+
process.exit(1);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const url = buildPreviewUrl(config.apiBaseUrl, preview.previewHostname);
|
|
275
|
+
spinner.stop("Preview details loaded.");
|
|
276
|
+
|
|
277
|
+
p.note(
|
|
278
|
+
[
|
|
279
|
+
`Name: ${preview.name || "Unnamed preview"}`,
|
|
280
|
+
`URL: ${url}`,
|
|
281
|
+
`Created: ${formatRelativeDate(preview.createdAt)}`,
|
|
282
|
+
].join("\n"),
|
|
283
|
+
"Active preview",
|
|
284
|
+
);
|
|
285
|
+
};
|
|
286
|
+
|
|
206
287
|
export const previewDelete = async () => {
|
|
207
288
|
const { config, credentials } = await loadConfigOrFail();
|
|
208
289
|
|
|
209
|
-
|
|
210
|
-
|
|
290
|
+
const listResult = await listPreviews(
|
|
291
|
+
config.apiBaseUrl,
|
|
292
|
+
credentials.apiKey,
|
|
293
|
+
config.storeId,
|
|
294
|
+
);
|
|
295
|
+
if (!listResult.ok) {
|
|
296
|
+
p.log.error(listResult.error);
|
|
297
|
+
process.exit(1);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const activePreview = resolveActivePreview(
|
|
301
|
+
listResult.data,
|
|
302
|
+
config.previewKey,
|
|
303
|
+
);
|
|
304
|
+
if (!activePreview) {
|
|
305
|
+
p.log.error(
|
|
306
|
+
listResult.data.length === 0
|
|
307
|
+
? "No previews found for this store."
|
|
308
|
+
: "Could not determine the active preview. Run tiendu preview list first.",
|
|
309
|
+
);
|
|
211
310
|
process.exit(1);
|
|
212
311
|
}
|
|
213
312
|
|
|
214
313
|
const confirmed = await p.confirm({
|
|
215
|
-
message: `Delete preview ${
|
|
314
|
+
message: `Delete preview ${activePreview.previewKey}?`,
|
|
216
315
|
});
|
|
217
316
|
|
|
218
317
|
if (p.isCancel(confirmed) || !confirmed) {
|
|
@@ -227,7 +326,7 @@ export const previewDelete = async () => {
|
|
|
227
326
|
config.apiBaseUrl,
|
|
228
327
|
credentials.apiKey,
|
|
229
328
|
config.storeId,
|
|
230
|
-
|
|
329
|
+
activePreview.previewKey,
|
|
231
330
|
);
|
|
232
331
|
|
|
233
332
|
if (!result.ok) {
|
|
@@ -245,11 +344,6 @@ export const previewDelete = async () => {
|
|
|
245
344
|
export const previewOpen = async () => {
|
|
246
345
|
const { config, credentials } = await loadConfigOrFail();
|
|
247
346
|
|
|
248
|
-
if (!config.previewKey) {
|
|
249
|
-
p.log.error("No active preview. Create one with: tiendu preview create");
|
|
250
|
-
process.exit(1);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
347
|
const spinner = p.spinner();
|
|
254
348
|
spinner.start("Fetching preview URL...");
|
|
255
349
|
|
|
@@ -265,10 +359,14 @@ export const previewOpen = async () => {
|
|
|
265
359
|
process.exit(1);
|
|
266
360
|
}
|
|
267
361
|
|
|
268
|
-
const preview = result.data
|
|
362
|
+
const preview = resolveActivePreview(result.data, config.previewKey);
|
|
269
363
|
if (!preview) {
|
|
270
|
-
spinner.stop("
|
|
271
|
-
p.log.error(
|
|
364
|
+
spinner.stop("Could not determine the active preview.", 1);
|
|
365
|
+
p.log.error(
|
|
366
|
+
result.data.length === 0
|
|
367
|
+
? "No previews found for this store."
|
|
368
|
+
: "Run tiendu preview list and then set or recreate the preview.",
|
|
369
|
+
);
|
|
272
370
|
process.exit(1);
|
|
273
371
|
}
|
|
274
372
|
|
package/lib/pull.mjs
CHANGED