@swell/cli 2.0.8 → 2.0.10
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/dist/commands/theme/dev.d.ts +1 -0
- package/dist/commands/theme/dev.js +12 -3
- package/dist/lib/apps/app-config.js +1 -1
- package/dist/lib/apps/index.d.ts +11 -5
- package/dist/lib/apps/index.js +18 -16
- package/dist/push-app-command.js +1 -1
- package/dist/remote-app-command.d.ts +1 -0
- package/dist/remote-app-command.js +15 -9
- package/oclif.manifest.json +7 -1
- package/package.json +1 -1
|
@@ -3,6 +3,7 @@ export default class AppThemeDev extends PushAppCommand {
|
|
|
3
3
|
static examples: string[];
|
|
4
4
|
static flags: {
|
|
5
5
|
bundle: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
6
|
+
force: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
6
7
|
local: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
7
8
|
'no-push': import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
8
9
|
'storefront-id': import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
@@ -21,6 +21,10 @@ export default class AppThemeDev extends PushAppCommand {
|
|
|
21
21
|
bundle: Flags.boolean({
|
|
22
22
|
description: 'bundle assets',
|
|
23
23
|
}),
|
|
24
|
+
force: Flags.boolean({
|
|
25
|
+
default: false,
|
|
26
|
+
description: 'force push all configurations',
|
|
27
|
+
}),
|
|
24
28
|
local: Flags.boolean({
|
|
25
29
|
description: 'connect to a running local storefront app dev server',
|
|
26
30
|
}),
|
|
@@ -45,13 +49,18 @@ export default class AppThemeDev extends PushAppCommand {
|
|
|
45
49
|
}
|
|
46
50
|
async run() {
|
|
47
51
|
const { flags } = await this.parse(AppThemeDev);
|
|
48
|
-
const { local } = flags;
|
|
52
|
+
const { force, local } = flags;
|
|
49
53
|
const noPush = flags['no-push'];
|
|
50
54
|
if (!(await this.ensureAppExists(undefined, false))) {
|
|
51
55
|
return;
|
|
52
56
|
}
|
|
57
|
+
if (local) {
|
|
58
|
+
const currentStore = localConfig.getDefaultStore();
|
|
59
|
+
const sessionId = localConfig.getSessionId(currentStore);
|
|
60
|
+
this.storefrontLocalUrl = this.localFrontendUrl(currentStore, sessionId);
|
|
61
|
+
}
|
|
53
62
|
if (!noPush) {
|
|
54
|
-
await this.pushAppConfigs();
|
|
63
|
+
await this.pushAppConfigs(force);
|
|
55
64
|
}
|
|
56
65
|
await this.getStorefrontToPush(flags);
|
|
57
66
|
this.logStorefrontConnected();
|
|
@@ -136,7 +145,7 @@ export default class AppThemeDev extends PushAppCommand {
|
|
|
136
145
|
const freePort = (await getPort({ port: portNumbers(3000, 3100) })) || FALLBACK_PORT;
|
|
137
146
|
spinner.start(`Starting theme dev server on port ${freePort}...`);
|
|
138
147
|
const storefrontUrl = local
|
|
139
|
-
? this.
|
|
148
|
+
? this.storefrontLocalUrl
|
|
140
149
|
: this.storefrontFrontendUrl(currentStore, this.storefront, undefined, true);
|
|
141
150
|
const bs = BrowserSync.create();
|
|
142
151
|
bs.init({
|
|
@@ -80,7 +80,7 @@ class AppConfig {
|
|
|
80
80
|
this.appPath = path.join(appPath, filePath);
|
|
81
81
|
}
|
|
82
82
|
if (filePathExists(this.appPath)) {
|
|
83
|
-
this.fileHash = hashFile(this.appPath);
|
|
83
|
+
this.fileHash = hashFile(this.appPath, undefined, filePath);
|
|
84
84
|
this.hash = this.hash || this.fileHash;
|
|
85
85
|
this.fileData = fs.readFileSync(this.appPath);
|
|
86
86
|
this.fileContent = this.fileData.toString('utf8');
|
package/dist/lib/apps/index.d.ts
CHANGED
|
@@ -131,18 +131,24 @@ declare function filePathExists(filePath: string): boolean;
|
|
|
131
131
|
declare function writeFile(file: string, data: string): Promise<void>;
|
|
132
132
|
declare function deleteFile(file: string): Promise<void>;
|
|
133
133
|
declare function writeJsonFile(file: string, data?: any): Promise<void>;
|
|
134
|
-
declare function hashFile(filePath: string, fileContents?: Buffer): string;
|
|
135
|
-
declare function hashString(contents: string): string;
|
|
134
|
+
declare function hashFile(filePath: string, fileContents?: Buffer, relativePath?: string): string;
|
|
135
|
+
declare function hashString(...contents: (Buffer | string)[]): string;
|
|
136
136
|
declare function appAssetImage(appPath: string, fileName: string): string | undefined;
|
|
137
137
|
declare function appConfigFromFile(filePath: string, configType: ConfigType, appPath: string): AppConfig;
|
|
138
138
|
declare function findAppConfig(app: App, filePath: string, configType: ConfigType): AppConfig | undefined;
|
|
139
|
+
interface BatchAppFiles {
|
|
140
|
+
configs: AppConfig[];
|
|
141
|
+
type: ConfigType;
|
|
142
|
+
label: string;
|
|
143
|
+
concurrency: number;
|
|
144
|
+
}
|
|
139
145
|
/**
|
|
140
146
|
* Get files to push in batches prioritized by dependencies
|
|
141
147
|
*
|
|
142
|
-
* @param configs - List of app configs
|
|
143
|
-
* @returns {
|
|
148
|
+
* @param {AppConfig[]} configs - List of app configs
|
|
149
|
+
* @returns {BatchAppFiles[]} Batches of files to push
|
|
144
150
|
*/
|
|
145
|
-
declare function batchAppFilesByType(configs: AppConfig[]):
|
|
151
|
+
declare function batchAppFilesByType(configs: AppConfig[]): BatchAppFiles[];
|
|
146
152
|
export { PUSH_CONCURRENCY, App, AppVersion, ConfigInputFields, ConfigPaths, ConfigPathsType, ConfigType, FrontendProjectType, FrontendProjectTypes, StorefrontConfigPaths, StorefrontConfigTypes, SwellJsonFields, ThemeConfigPaths, ThemeConfigTypes, appAssetImage, appConfigFromFile, batchAppFilesByType, deleteFile, filePathExists, findAppConfig, getAppSlugId, getConfigTypeFromPath, getConfigTypeKeyFromValue, getFrontendProjectType, hashFile, hashString, writeFile, writeJsonFile, };
|
|
147
153
|
export { AppConfig, FunctionProcessingError, IgnoringFileError, } from './app-config.js';
|
|
148
154
|
export { allBaseFilesInDir, allConfigDirsPaths, allConfigFilesInDir, allConfigFilesPaths, allConfigFilesPathsByType, getAllConfigPaths, globAllFilesByPath, isPathDirectory, } from './paths.js';
|
package/dist/lib/apps/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createHash as createBlake3Hash } from 'blake3-wasm';
|
|
2
2
|
import { pluralize, titleize } from 'inflection';
|
|
3
3
|
import * as fs from 'node:fs';
|
|
4
4
|
import * as path from 'node:path';
|
|
@@ -184,14 +184,18 @@ async function writeJsonFile(file, data = {}) {
|
|
|
184
184
|
return writeFile(file, `${JSON.stringify(data, null, 2)}\n`);
|
|
185
185
|
}
|
|
186
186
|
// Hash method adapted from wrangler-sdk
|
|
187
|
-
function hashFile(filePath, fileContents) {
|
|
187
|
+
function hashFile(filePath, fileContents, relativePath) {
|
|
188
188
|
const contents = fileContents ?? fs.readFileSync(filePath);
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
return hashString(
|
|
189
|
+
// Include relative file path because we typically cache by hash including file metadata
|
|
190
|
+
// This allows de-duplication of cache entries for the same file contents
|
|
191
|
+
return hashString(contents, relativePath || '');
|
|
192
192
|
}
|
|
193
|
-
function hashString(contents) {
|
|
194
|
-
|
|
193
|
+
function hashString(...contents) {
|
|
194
|
+
const hash = createBlake3Hash();
|
|
195
|
+
for (const content of contents) {
|
|
196
|
+
hash.update(content);
|
|
197
|
+
}
|
|
198
|
+
return hash.digest('hex', { length: 16 });
|
|
195
199
|
}
|
|
196
200
|
function appAssetImage(appPath, fileName) {
|
|
197
201
|
const assetsDirPath = path.join(appPath, ConfigPaths['ASSET']);
|
|
@@ -227,28 +231,26 @@ function findAppConfig(app, filePath, configType) {
|
|
|
227
231
|
/**
|
|
228
232
|
* Get files to push in batches prioritized by dependencies
|
|
229
233
|
*
|
|
230
|
-
* @param configs - List of app configs
|
|
231
|
-
* @returns {
|
|
234
|
+
* @param {AppConfig[]} configs - List of app configs
|
|
235
|
+
* @returns {BatchAppFiles[]} Batches of files to push
|
|
232
236
|
*/
|
|
233
237
|
function batchAppFilesByType(configs) {
|
|
234
238
|
const modelsWithExtends = configs.filter((config) => config.type === 'model' && config.values.extends);
|
|
235
239
|
const modelsWithoutExtends = configs.filter((config) => config.type === 'model' && !config.values.extends);
|
|
236
240
|
const contentTypesWithCollection = configs.filter((config) => config.type === 'content' && config.values.collection);
|
|
237
241
|
const contentTypesWithoutCollection = configs.filter((config) => config.type === 'content' && !config.values.collection);
|
|
238
|
-
const prioritized = [
|
|
242
|
+
const prioritized = new Set([
|
|
239
243
|
...modelsWithExtends,
|
|
240
244
|
...modelsWithoutExtends,
|
|
241
245
|
...contentTypesWithCollection,
|
|
242
246
|
...contentTypesWithoutCollection,
|
|
243
|
-
];
|
|
247
|
+
]);
|
|
244
248
|
const sorted = [
|
|
245
|
-
...prioritized,
|
|
246
|
-
...configs.filter((config) => !prioritized.
|
|
249
|
+
...prioritized.values(),
|
|
250
|
+
...configs.filter((config) => !prioritized.has(config)),
|
|
247
251
|
];
|
|
248
252
|
const batches = [];
|
|
249
|
-
|
|
250
|
-
for (const type in ConfigTypeBatchOrder) {
|
|
251
|
-
const configType = ConfigTypeBatchOrder[type];
|
|
253
|
+
for (const configType of ConfigTypeBatchOrder) {
|
|
252
254
|
const configsByType = sorted.filter((config) => config.type === configType);
|
|
253
255
|
const label = configType === ConfigType.FILE ? 'App files' : titleize(configType);
|
|
254
256
|
const concurrency = configType === ConfigType.NOTIFICATION || configType === ConfigType.ASSET
|
package/dist/push-app-command.js
CHANGED
|
@@ -375,7 +375,7 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
375
375
|
const packageHash = localConfigs.find((config) => config.filePath === 'package.json')?.hash;
|
|
376
376
|
frontendHashes += `|${packageHash}`;
|
|
377
377
|
}
|
|
378
|
-
return frontendHashes
|
|
378
|
+
return frontendHashes.length > 0 ? hashString(frontendHashes) : undefined;
|
|
379
379
|
}
|
|
380
380
|
getFrontendProjectType(required = true) {
|
|
381
381
|
this.frontendPath = path.join(this.appPath, 'frontend');
|
|
@@ -11,6 +11,7 @@ export declare abstract class RemoteAppCommand extends AppCommand {
|
|
|
11
11
|
appCreated: boolean;
|
|
12
12
|
appType: string;
|
|
13
13
|
storefront?: any;
|
|
14
|
+
storefrontLocalUrl?: string;
|
|
14
15
|
themeSyncApp?: boolean;
|
|
15
16
|
appFrontendUrl(storeId: string, installedAppId: string): string;
|
|
16
17
|
cleanRemoteConfigs(remoteConfigs: AppConfig[], deleteDeprecated?: boolean): Promise<AppConfig[]>;
|
|
@@ -26,6 +26,8 @@ export class RemoteAppCommand extends AppCommand {
|
|
|
26
26
|
appType = 'any';
|
|
27
27
|
// API instance of the target storefront, if applicable
|
|
28
28
|
storefront = null;
|
|
29
|
+
// Indicates we are syncing with a local app frontend via proxy
|
|
30
|
+
storefrontLocalUrl = '';
|
|
29
31
|
// Indicates app configs are being synced along with theme configs
|
|
30
32
|
themeSyncApp = false;
|
|
31
33
|
appFrontendUrl(storeId, installedAppId) {
|
|
@@ -334,6 +336,9 @@ export class RemoteAppCommand extends AppCommand {
|
|
|
334
336
|
...configJson,
|
|
335
337
|
...(themeId ? { theme_id: themeId } : undefined),
|
|
336
338
|
...(this.themeSyncApp ? { $sync_app: true } : undefined),
|
|
339
|
+
...(this.storefrontLocalUrl
|
|
340
|
+
? { $storefront_local_url: this.storefrontLocalUrl }
|
|
341
|
+
: undefined),
|
|
337
342
|
},
|
|
338
343
|
});
|
|
339
344
|
}
|
|
@@ -352,7 +357,7 @@ export class RemoteAppCommand extends AppCommand {
|
|
|
352
357
|
try {
|
|
353
358
|
const localConfig = localBatchConfigs.find((config) => config.filePath === batchConfig.filePath);
|
|
354
359
|
if (localConfig) {
|
|
355
|
-
const hash = hashFile(batchConfig.appPath);
|
|
360
|
+
const hash = hashFile(batchConfig.appPath, undefined, batchConfig.filePath);
|
|
356
361
|
if (hash === batchConfig.hash) {
|
|
357
362
|
return false;
|
|
358
363
|
}
|
|
@@ -374,9 +379,8 @@ export class RemoteAppCommand extends AppCommand {
|
|
|
374
379
|
}
|
|
375
380
|
if (pullFiles.length > 0) {
|
|
376
381
|
while (pullFiles.length > 0) {
|
|
377
|
-
await
|
|
378
|
-
|
|
379
|
-
.map(async (config) => {
|
|
382
|
+
// eslint-disable-next-line no-await-in-loop
|
|
383
|
+
await Promise.all(pullFiles.splice(0, PUSH_CONCURRENCY).map(async (config) => {
|
|
380
384
|
await this.pullRemoteFile(config);
|
|
381
385
|
pulled.push(config.id);
|
|
382
386
|
}));
|
|
@@ -388,6 +392,7 @@ export class RemoteAppCommand extends AppCommand {
|
|
|
388
392
|
const removeList = filesToRemove
|
|
389
393
|
.map((config) => config.filePath)
|
|
390
394
|
.join('\n');
|
|
395
|
+
// eslint-disable-next-line no-await-in-loop
|
|
391
396
|
const confirmed = await confirm({
|
|
392
397
|
default: false,
|
|
393
398
|
message: `The following files are not in the remote app:\n\n${removeList}\n\nDo you want to delete these files locally?`,
|
|
@@ -397,6 +402,7 @@ export class RemoteAppCommand extends AppCommand {
|
|
|
397
402
|
}
|
|
398
403
|
}
|
|
399
404
|
while (filesToRemove.length > 0) {
|
|
405
|
+
// eslint-disable-next-line no-await-in-loop
|
|
400
406
|
await Promise.all(filesToRemove.splice(0, PUSH_CONCURRENCY).map(async (config) => {
|
|
401
407
|
await this.removeLocalFile(config);
|
|
402
408
|
removed.push(config.id);
|
|
@@ -474,10 +480,9 @@ export class RemoteAppCommand extends AppCommand {
|
|
|
474
480
|
this.log(`${style.appConfigName(`${batch.label} ${updatedLog}`)}`);
|
|
475
481
|
}
|
|
476
482
|
if (pushFiles.length > 0) {
|
|
477
|
-
while (pushFiles.length) {
|
|
478
|
-
await
|
|
479
|
-
|
|
480
|
-
.map(async (config) => {
|
|
483
|
+
while (pushFiles.length > 0) {
|
|
484
|
+
// eslint-disable-next-line no-await-in-loop
|
|
485
|
+
await Promise.all(pushFiles.splice(0, batch.concurrency).map(async (config) => {
|
|
481
486
|
const pushedConfig = await this.pushRemoteFile(config);
|
|
482
487
|
if (pushedConfig) {
|
|
483
488
|
pushed.push(pushedConfig.id);
|
|
@@ -490,7 +495,8 @@ export class RemoteAppCommand extends AppCommand {
|
|
|
490
495
|
}
|
|
491
496
|
// Remove any deleted files
|
|
492
497
|
if (filesToRemove.length > 0) {
|
|
493
|
-
while (filesToRemove.length) {
|
|
498
|
+
while (filesToRemove.length > 0) {
|
|
499
|
+
// eslint-disable-next-line no-await-in-loop
|
|
494
500
|
await Promise.all(filesToRemove.splice(0, batch.concurrency).map(async (config) => {
|
|
495
501
|
await this.removeRemoteFile(config);
|
|
496
502
|
removed.push(config.id);
|
package/oclif.manifest.json
CHANGED
|
@@ -1473,6 +1473,12 @@
|
|
|
1473
1473
|
"allowNo": false,
|
|
1474
1474
|
"type": "boolean"
|
|
1475
1475
|
},
|
|
1476
|
+
"force": {
|
|
1477
|
+
"description": "force push all configurations",
|
|
1478
|
+
"name": "force",
|
|
1479
|
+
"allowNo": false,
|
|
1480
|
+
"type": "boolean"
|
|
1481
|
+
},
|
|
1476
1482
|
"local": {
|
|
1477
1483
|
"description": "connect to a running local storefront app dev server",
|
|
1478
1484
|
"name": "local",
|
|
@@ -1835,5 +1841,5 @@
|
|
|
1835
1841
|
]
|
|
1836
1842
|
}
|
|
1837
1843
|
},
|
|
1838
|
-
"version": "2.0.
|
|
1844
|
+
"version": "2.0.10"
|
|
1839
1845
|
}
|