@swell/cli 2.9.3 → 2.9.5
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/app-command.d.ts +2 -3
- package/dist/app-command.js +3 -6
- package/dist/commands/app/dev.d.ts +2 -2
- package/dist/commands/app/dev.js +49 -33
- package/dist/commands/app/frontend/dev.js +12 -6
- package/dist/commands/app/push.d.ts +1 -0
- package/dist/commands/app/push.js +3 -3
- package/dist/commands/app/release.js +2 -2
- package/dist/commands/create/app.d.ts +1 -1
- package/dist/commands/create/app.js +1 -1
- package/dist/commands/create/frontend.js +3 -3
- package/dist/commands/create/tests.js +10 -8
- package/dist/commands/inspect/extensions.js +4 -4
- package/dist/commands/schema.js +21 -18
- package/dist/commands/theme/dev.js +5 -5
- package/dist/commands/theme/push.d.ts +1 -0
- package/dist/commands/theme/push.js +3 -3
- package/dist/create-app-command.js +2 -2
- package/dist/create-config-command.d.ts +1 -1
- package/dist/create-config-command.js +3 -3
- package/dist/help/custom-help.d.ts +1 -1
- package/dist/help/types.d.ts +1 -1
- package/dist/lib/api.d.ts +1 -0
- package/dist/lib/api.js +1 -1
- package/dist/lib/app-config.d.ts +13 -8
- package/dist/lib/app-config.js +25 -23
- package/dist/lib/apps/app-config.d.ts +5 -5
- package/dist/lib/apps/app-config.js +53 -37
- package/dist/lib/apps/index.d.ts +15 -14
- package/dist/lib/apps/index.js +40 -23
- package/dist/lib/apps/paths.d.ts +1 -1
- package/dist/lib/apps/paths.js +3 -3
- package/dist/lib/bundle.js +26 -17
- package/dist/lib/config.d.ts +8 -8
- package/dist/lib/config.js +8 -10
- package/dist/lib/constants.d.ts +9 -9
- package/dist/lib/create/content.d.ts +6 -6
- package/dist/lib/create/content.js +7 -8
- package/dist/lib/create/function.d.ts +5 -6
- package/dist/lib/create/function.js +7 -8
- package/dist/lib/create/index.d.ts +8 -9
- package/dist/lib/create/index.js +7 -8
- package/dist/lib/create/model.d.ts +4 -4
- package/dist/lib/create/model.js +4 -5
- package/dist/lib/create/notification.d.ts +2 -3
- package/dist/lib/create/setting.d.ts +4 -4
- package/dist/lib/create/setting.js +3 -4
- package/dist/lib/create/tests/types.d.ts +3 -4
- package/dist/lib/create/tests.d.ts +1 -2
- package/dist/lib/create/tests.js +12 -13
- package/dist/lib/create/webhook.d.ts +6 -6
- package/dist/lib/create/webhook.js +15 -10
- package/dist/lib/function-source-analysis.js +3 -3
- package/dist/lib/info.d.ts +1 -1
- package/dist/lib/logs/index.d.ts +1 -0
- package/dist/lib/logs/line-output.d.ts +1 -0
- package/dist/lib/logs/line-output.js +12 -4
- package/dist/lib/logs/output.d.ts +1 -0
- package/dist/lib/logs/table-output.d.ts +1 -0
- package/dist/lib/logs/table-output.js +8 -5
- package/dist/lib/package-manager.d.ts +5 -5
- package/dist/lib/package-manager.js +9 -7
- package/dist/lib/proxy.js +4 -3
- package/dist/lib/sessions.d.ts +1 -2
- package/dist/lib/sessions.js +1 -2
- package/dist/lib/stores.d.ts +6 -6
- package/dist/lib/stores.js +5 -6
- package/dist/lib/swell-function-wrapper.d.ts +1 -193
- package/dist/lib/swell-function-wrapper.js +1 -1
- package/dist/lib/theme-sync.js +0 -5
- package/dist/push-app-command.d.ts +8 -6
- package/dist/push-app-command.js +45 -51
- package/dist/remote-app-command.d.ts +6 -4
- package/dist/remote-app-command.js +39 -25
- package/dist/swell-api-command.d.ts +1 -0
- package/dist/swell-api-command.js +3 -3
- package/dist/types/index.d.ts +94 -0
- package/dist/types/index.js +4 -0
- package/oclif.manifest.json +1 -1
- package/package.json +3 -3
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
1
|
+
/// <reference types="node" resolution-mode="require"/>
|
|
2
|
+
/// <reference types="node" resolution-mode="require"/>
|
|
2
3
|
import type { GlobbyFilterFunction } from 'globby';
|
|
3
4
|
import * as fs from 'node:fs';
|
|
4
5
|
import { App, AppConfig, ConfigType, FrontendProjectType } from './lib/apps/index.js';
|
|
@@ -26,7 +27,7 @@ export declare abstract class PushAppCommand extends RemoteAppCommand {
|
|
|
26
27
|
deployAppFrontend(force?: boolean, log?: boolean): Promise<void>;
|
|
27
28
|
deployFrontend(projectType: FrontendProjectType): Promise<string>;
|
|
28
29
|
ensureAppExists(file?: string, shouldCreate?: boolean): Promise<boolean>;
|
|
29
|
-
ensureLoggedIn(): Promise<
|
|
30
|
+
ensureLoggedIn(): Promise<void>;
|
|
30
31
|
exec(command: string, cwd?: string, onOutput?: (string: string) => any | false): Promise<void>;
|
|
31
32
|
execFrontend(command: string, onOutput?: (string: string) => any | false): Promise<void>;
|
|
32
33
|
getAllAppStorefronts(params?: {
|
|
@@ -46,8 +47,8 @@ export declare abstract class PushAppCommand extends RemoteAppCommand {
|
|
|
46
47
|
targetPath?: string;
|
|
47
48
|
}, shouldChoose?: boolean): Promise<App | undefined>;
|
|
48
49
|
getExistingApp(appId: string): Promise<App>;
|
|
49
|
-
getFrontendDeploymentHash(): string | undefined
|
|
50
|
-
getFrontendProjectType(required?: boolean): FrontendProjectType | null
|
|
50
|
+
getFrontendDeploymentHash(): Promise<string | undefined>;
|
|
51
|
+
getFrontendProjectType(required?: boolean): Promise<FrontendProjectType | null>;
|
|
51
52
|
getStorefrontToPull(args?: {
|
|
52
53
|
appId?: string;
|
|
53
54
|
targetPath?: string;
|
|
@@ -66,6 +67,7 @@ export declare abstract class PushAppCommand extends RemoteAppCommand {
|
|
|
66
67
|
env?: string;
|
|
67
68
|
'storefront-id'?: string;
|
|
68
69
|
'storefront-select'?: boolean;
|
|
70
|
+
yes?: boolean;
|
|
69
71
|
}, defaultStorefront?: any): Promise<void>;
|
|
70
72
|
handleWatchFileChange(configFile: string, configType: ConfigType, event: WatchFileEvent): Promise<void>;
|
|
71
73
|
logAppFrontendUrl(): void;
|
|
@@ -76,7 +78,7 @@ export declare abstract class PushAppCommand extends RemoteAppCommand {
|
|
|
76
78
|
logStorefrontFrontendUrl(storefront?: any, branchId?: string): void;
|
|
77
79
|
pushFile(relativePath: string): Promise<void>;
|
|
78
80
|
pushFilePath(relativePath: string, force?: boolean): Promise<void>;
|
|
79
|
-
resolveAppPath(appId?: string, targetPath?: string): string
|
|
81
|
+
resolveAppPath(appId?: string, targetPath?: string): Promise<string>;
|
|
80
82
|
runWatchChangeQueue(): Promise<void>;
|
|
81
83
|
saveCurrentStorefront(): void;
|
|
82
84
|
logLocalPreviewUrl(): void;
|
|
@@ -88,7 +90,7 @@ export declare abstract class PushAppCommand extends RemoteAppCommand {
|
|
|
88
90
|
logChanges?: boolean;
|
|
89
91
|
onChange?: (appConfig?: AppConfig, result?: any) => void;
|
|
90
92
|
syncAll?: boolean;
|
|
91
|
-
}): Promise<
|
|
93
|
+
}): Promise<fs.FSWatcher>;
|
|
92
94
|
wranglerDeployFrontend(_projectType: FrontendProjectType): Promise<string>;
|
|
93
95
|
private confirmRemoveInstalledApp;
|
|
94
96
|
}
|
package/dist/push-app-command.js
CHANGED
|
@@ -6,7 +6,7 @@ import * as path from 'node:path';
|
|
|
6
6
|
import Stream from 'node:stream';
|
|
7
7
|
import ora from 'ora';
|
|
8
8
|
import { default as swellConfig } from './lib/app-config.js';
|
|
9
|
-
import { ConfigType, getFrontendProjectValidValues, allConfigFilesInDir, CUSTOM_FRAMEWORK_SLUG, appConfigFromFile,
|
|
9
|
+
import { ConfigType, getFrontendProjectValidValues, allConfigFilesInDir, CUSTOM_FRAMEWORK_SLUG, appConfigFromFile, filePathExistsAsync, findAppConfig, getConfigTypeFromPath, getConfigTypeKeyFromValue, getFrontendProjectType, getProjectCommands, globAllFilesByPath, hashString, isPathDirectory, } from './lib/apps/index.js';
|
|
10
10
|
import { getGlobIgnorePathsChecker } from './lib/apps/paths.js';
|
|
11
11
|
import { slugFromApp } from './lib/apps/slug.js';
|
|
12
12
|
import { default as localConfig } from './lib/config.js';
|
|
@@ -121,7 +121,7 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
121
121
|
return;
|
|
122
122
|
}
|
|
123
123
|
// Get commands transformed for the detected package manager
|
|
124
|
-
const { buildCommand } = getProjectCommands(this.appPath, projectType);
|
|
124
|
+
const { buildCommand } = await getProjectCommands(this.appPath, projectType);
|
|
125
125
|
if (!buildCommand) {
|
|
126
126
|
// No build command needed for this framework
|
|
127
127
|
return;
|
|
@@ -251,11 +251,11 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
251
251
|
}
|
|
252
252
|
async deployAppFrontend(force, log) {
|
|
253
253
|
const currentStore = localConfig.getDefaultStore();
|
|
254
|
-
const projectType = this.getFrontendProjectType(false);
|
|
254
|
+
const projectType = await this.getFrontendProjectType(false);
|
|
255
255
|
if (!projectType) {
|
|
256
256
|
return;
|
|
257
257
|
}
|
|
258
|
-
const deploymentHash = this.getFrontendDeploymentHash();
|
|
258
|
+
const deploymentHash = await this.getFrontendDeploymentHash();
|
|
259
259
|
// Build and deploy only if there are files to push
|
|
260
260
|
if (deploymentHash &&
|
|
261
261
|
(force || deploymentHash !== this.app.frontend?.deployment_hash)) {
|
|
@@ -335,7 +335,6 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
335
335
|
this.log('Logging in...\n');
|
|
336
336
|
await this.config.runCommand('login');
|
|
337
337
|
this.log();
|
|
338
|
-
return true;
|
|
339
338
|
}
|
|
340
339
|
}
|
|
341
340
|
async exec(command, cwd, onOutput) {
|
|
@@ -386,25 +385,20 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
386
385
|
const query = Object.entries(params || {})
|
|
387
386
|
.map(([key, value]) => `${key}=${value}`)
|
|
388
387
|
.join('&');
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
}));
|
|
393
|
-
}
|
|
394
|
-
catch {
|
|
395
|
-
// noop
|
|
396
|
-
}
|
|
388
|
+
return this.handleRequestErrors(async () => this.api.get({
|
|
389
|
+
adminPath: `/apps/${this.app.id}/storefront?${query}`,
|
|
390
|
+
}));
|
|
397
391
|
}
|
|
398
392
|
async getAppToPull(args, shouldChoose = true) {
|
|
399
393
|
const { appId, targetPath } = args;
|
|
400
394
|
const klass = this.ctor;
|
|
401
395
|
const currentStore = localConfig.getDefaultStore();
|
|
402
396
|
await this.api.setStoreEnv(currentStore, klass.orientation?.env);
|
|
403
|
-
this.resolveAppPath(appId, targetPath);
|
|
404
|
-
if (isPathDirectory(this.appPath)) {
|
|
405
|
-
this.swellConfig = swellConfig(this.appPath);
|
|
406
|
-
const localAppId = this.swellConfig.get('id');
|
|
407
|
-
const localAppType = this.swellConfig.get('type');
|
|
397
|
+
await this.resolveAppPath(appId, targetPath);
|
|
398
|
+
if (await isPathDirectory(this.appPath)) {
|
|
399
|
+
this.swellConfig = await swellConfig(this.appPath);
|
|
400
|
+
const localAppId = String(this.swellConfig.get('id'));
|
|
401
|
+
const localAppType = String(this.swellConfig.get('type'));
|
|
408
402
|
if (localAppId) {
|
|
409
403
|
if (appId && appId !== localAppId) {
|
|
410
404
|
this.error(`${localAppType === 'theme' ? 'A theme' : 'An app'} already exists in this path with a different ID: ${style.appConfigValue(localAppId)}`);
|
|
@@ -418,7 +412,7 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
418
412
|
? await this.chooseAppToPull()
|
|
419
413
|
: undefined;
|
|
420
414
|
if (shouldChoose) {
|
|
421
|
-
this.swellConfig = swellConfig(this.appPath);
|
|
415
|
+
this.swellConfig = await swellConfig(this.appPath);
|
|
422
416
|
}
|
|
423
417
|
return app;
|
|
424
418
|
}
|
|
@@ -436,8 +430,8 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
436
430
|
}
|
|
437
431
|
}
|
|
438
432
|
}
|
|
439
|
-
getFrontendDeploymentHash() {
|
|
440
|
-
const localConfigs = this.getLocalAppConfigs();
|
|
433
|
+
async getFrontendDeploymentHash() {
|
|
434
|
+
const localConfigs = await this.getLocalAppConfigs();
|
|
441
435
|
let frontendHashes = localConfigs
|
|
442
436
|
.filter((config) => config.filePath?.startsWith(`frontend${path.sep}`))
|
|
443
437
|
.map((config) => config.hash)
|
|
@@ -449,13 +443,13 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
449
443
|
}
|
|
450
444
|
return frontendHashes.length > 0 ? hashString(frontendHashes) : undefined;
|
|
451
445
|
}
|
|
452
|
-
getFrontendProjectType(required = true) {
|
|
446
|
+
async getFrontendProjectType(required = true) {
|
|
453
447
|
this.frontendPath = path.join(this.appPath, 'frontend');
|
|
454
|
-
const frontendExists =
|
|
448
|
+
const frontendExists = await filePathExistsAsync(this.frontendPath);
|
|
455
449
|
if (!required && !frontendExists) {
|
|
456
450
|
return null;
|
|
457
451
|
}
|
|
458
|
-
const projectType = getFrontendProjectType(this.appPath);
|
|
452
|
+
const projectType = await getFrontendProjectType(this.appPath);
|
|
459
453
|
if (!projectType) {
|
|
460
454
|
// If frontend not required, just return null (don't error)
|
|
461
455
|
if (!required) {
|
|
@@ -475,10 +469,10 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
475
469
|
const { appId, targetPath } = args;
|
|
476
470
|
const targetStorefront = flags['storefront-id'];
|
|
477
471
|
const targetApp = await this.getAppToPull(args, false);
|
|
478
|
-
this.resolveAppPath(appId, targetPath);
|
|
472
|
+
await this.resolveAppPath(appId, targetPath);
|
|
479
473
|
// Only use default if path exists
|
|
480
474
|
let defaultStorefront;
|
|
481
|
-
if (isPathDirectory(this.appPath)) {
|
|
475
|
+
if (await isPathDirectory(this.appPath)) {
|
|
482
476
|
defaultStorefront = localConfig.getDefaultStorefront(this.appPath);
|
|
483
477
|
}
|
|
484
478
|
await this.setStorefrontEnv(flags, defaultStorefront);
|
|
@@ -501,7 +495,7 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
501
495
|
const appId = this.appType === 'theme'
|
|
502
496
|
? this.storefront.theme_app_id
|
|
503
497
|
: this.storefront.app_id;
|
|
504
|
-
this.resolveAppPath(this.storefront.name, targetPath);
|
|
498
|
+
await this.resolveAppPath(this.storefront.name, targetPath);
|
|
505
499
|
this.app = await this.getApp(appId);
|
|
506
500
|
}
|
|
507
501
|
else {
|
|
@@ -509,7 +503,7 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
509
503
|
// However it's a good fallback in case the storefront was deleted
|
|
510
504
|
// Choosing a theme app will proceed to pull app files
|
|
511
505
|
this.app = await this.chooseAppToPull();
|
|
512
|
-
this.resolveAppPath(this.app.name, targetPath);
|
|
506
|
+
await this.resolveAppPath(this.app.name, targetPath);
|
|
513
507
|
}
|
|
514
508
|
}
|
|
515
509
|
else {
|
|
@@ -528,7 +522,7 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
528
522
|
: this.storefront.app_id;
|
|
529
523
|
this.app = await this.getApp(appId);
|
|
530
524
|
}
|
|
531
|
-
this.swellConfig = swellConfig(this.appPath);
|
|
525
|
+
this.swellConfig = await swellConfig(this.appPath);
|
|
532
526
|
return this.storefront;
|
|
533
527
|
}
|
|
534
528
|
async getStorefrontToPush(flags = {}) {
|
|
@@ -600,6 +594,7 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
600
594
|
async setStorefrontEnv(flags, defaultStorefront) {
|
|
601
595
|
const currentStore = localConfig.getDefaultStore();
|
|
602
596
|
const targetStorefront = flags['storefront-id'];
|
|
597
|
+
const nonInteractive = flags.yes || false;
|
|
603
598
|
if (defaultStorefront &&
|
|
604
599
|
!targetStorefront &&
|
|
605
600
|
!flags['storefront-id'] &&
|
|
@@ -615,7 +610,7 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
615
610
|
else {
|
|
616
611
|
const hasTestEnv = await this.api.isTestEnvEnabled();
|
|
617
612
|
if (hasTestEnv) {
|
|
618
|
-
const env = await selectEnvironmentId();
|
|
613
|
+
const env = nonInteractive ? 'test' : await selectEnvironmentId();
|
|
619
614
|
await this.api.setStoreEnv(currentStore, env);
|
|
620
615
|
}
|
|
621
616
|
}
|
|
@@ -636,7 +631,7 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
636
631
|
break;
|
|
637
632
|
}
|
|
638
633
|
default: {
|
|
639
|
-
config = appConfigFromFile(configFile, configType, this.appPath);
|
|
634
|
+
config = await appConfigFromFile(configFile, configType, this.appPath);
|
|
640
635
|
this.watchingChangeQueue.set(configFile, {
|
|
641
636
|
action: 'push',
|
|
642
637
|
appConfig: config,
|
|
@@ -682,19 +677,21 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
682
677
|
async pushFile(relativePath) {
|
|
683
678
|
const basePath = relativePath.split(path.sep)[0];
|
|
684
679
|
const configType = getConfigTypeFromPath(basePath) || ConfigType.FILE;
|
|
685
|
-
const config = appConfigFromFile(relativePath, configType, this.appPath);
|
|
680
|
+
const config = await appConfigFromFile(relativePath, configType, this.appPath);
|
|
686
681
|
await this.pushRemoteFile(config);
|
|
687
682
|
}
|
|
688
683
|
async pushFilePath(relativePath, force) {
|
|
689
684
|
const topDir = relativePath.split(path.sep)[0];
|
|
690
|
-
const configType =
|
|
691
|
-
const configTypeKey = getConfigTypeKeyFromValue(configType) ||
|
|
685
|
+
const configType = getConfigTypeFromPath(topDir) || ConfigType.FILE;
|
|
686
|
+
const configTypeKey = getConfigTypeKeyFromValue(configType) || ConfigType.FILE;
|
|
692
687
|
const exAppConfigs = (this.app?.configs || []).filter((config) => config.filePath?.startsWith(`${relativePath}/`));
|
|
693
|
-
const
|
|
694
|
-
const pushFiles = [];
|
|
688
|
+
const promises = [];
|
|
695
689
|
for (const { configFile } of allConfigFilesInDir(this.appPath, relativePath, configTypeKey)) {
|
|
696
|
-
|
|
697
|
-
|
|
690
|
+
promises.push(appConfigFromFile(configFile, configType, this.appPath));
|
|
691
|
+
}
|
|
692
|
+
const allFiles = await Promise.all(promises);
|
|
693
|
+
const pushFiles = [];
|
|
694
|
+
for (const config of allFiles) {
|
|
698
695
|
const exConfig = exAppConfigs.find((exConfig) => config.filePath === exConfig.filePath);
|
|
699
696
|
if (!force && exConfig && exConfig.hash === config.hash) {
|
|
700
697
|
continue;
|
|
@@ -709,18 +706,16 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
709
706
|
// eslint-disable-next-line no-await-in-loop
|
|
710
707
|
await Promise.all(pushFiles
|
|
711
708
|
.splice(0, pushConcurrency)
|
|
712
|
-
.map(
|
|
713
|
-
await this.pushRemoteFile(appConfig);
|
|
714
|
-
}));
|
|
709
|
+
.map((appConfig) => this.pushRemoteFile(appConfig)));
|
|
715
710
|
}
|
|
716
711
|
}
|
|
717
712
|
// Remove any deleted files
|
|
718
713
|
if (filesToRemove.length > 0) {
|
|
719
714
|
while (filesToRemove.length > 0) {
|
|
720
715
|
// eslint-disable-next-line no-await-in-loop
|
|
721
|
-
await Promise.all(filesToRemove
|
|
722
|
-
|
|
723
|
-
|
|
716
|
+
await Promise.all(filesToRemove
|
|
717
|
+
.splice(0, PUSH_CONCURRENCY)
|
|
718
|
+
.map((appConfig) => this.removeRemoteFile(appConfig)));
|
|
724
719
|
}
|
|
725
720
|
}
|
|
726
721
|
if (!hasChanges && !force) {
|
|
@@ -731,12 +726,12 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
731
726
|
this.log(`${style.success('✔')} Pushed ${style.path(relativePath)} to ${style.appConfigValue(this.app.name)}.`);
|
|
732
727
|
}
|
|
733
728
|
}
|
|
734
|
-
resolveAppPath(appId, targetPath) {
|
|
729
|
+
async resolveAppPath(appId, targetPath) {
|
|
735
730
|
const resolvedAppId = appId || '';
|
|
736
731
|
let resolvedPath = targetPath || resolvedAppId;
|
|
737
732
|
// If app_id matches directory, use it as target path
|
|
738
733
|
if (!targetPath &&
|
|
739
|
-
isPathDirectory(path.resolve(process.cwd(), resolvedAppId))) {
|
|
734
|
+
(await isPathDirectory(path.resolve(process.cwd(), resolvedAppId)))) {
|
|
740
735
|
resolvedPath = resolvedAppId;
|
|
741
736
|
}
|
|
742
737
|
// Reset app path if appId is provided
|
|
@@ -765,7 +760,7 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
765
760
|
}));
|
|
766
761
|
}
|
|
767
762
|
catch {
|
|
768
|
-
//
|
|
763
|
+
// TODO: Ignore only some errors
|
|
769
764
|
}
|
|
770
765
|
}
|
|
771
766
|
/* eslint-enable no-await-in-loop */
|
|
@@ -848,13 +843,12 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
848
843
|
await this.setWatchingFiles();
|
|
849
844
|
if (syncAll) {
|
|
850
845
|
await this.pushAppConfigs();
|
|
851
|
-
fs.watch(this.appPath, { recursive: true }, async (_eventType, _filename) => {
|
|
846
|
+
return fs.watch(this.appPath, { recursive: true }, async (_eventType, _filename) => {
|
|
852
847
|
await this.pushAppConfigs();
|
|
853
848
|
await this.setWatchingFiles();
|
|
854
849
|
});
|
|
855
|
-
return;
|
|
856
850
|
}
|
|
857
|
-
fs.watch(this.appPath, { recursive: true }, this.watchListener);
|
|
851
|
+
return fs.watch(this.appPath, { recursive: true }, this.watchListener);
|
|
858
852
|
}
|
|
859
853
|
async wranglerDeployFrontend(_projectType) {
|
|
860
854
|
let deploymentUrl;
|
|
@@ -863,7 +857,7 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
863
857
|
let outputBuffer = '';
|
|
864
858
|
this.log(`\nDeploying to Cloudflare...\n`);
|
|
865
859
|
// Get the wrangler deploy command for the detected package manager
|
|
866
|
-
const pm = detectPackageManager(this.appPath);
|
|
860
|
+
const pm = await detectPackageManager(this.appPath);
|
|
867
861
|
const deployCommand = transformCommand('npx wrangler deploy', pm);
|
|
868
862
|
try {
|
|
869
863
|
await this.execFrontend(deployCommand, (string) => {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { type Ora } from 'ora';
|
|
2
|
+
import type { AppCommandOrientation } from './types/index.js';
|
|
1
3
|
import { AppCommand } from './app-command.js';
|
|
2
4
|
import { App, AppConfig, AppVersion } from './lib/apps/index.js';
|
|
3
5
|
/**
|
|
@@ -24,12 +26,12 @@ export declare abstract class RemoteAppCommand extends AppCommand {
|
|
|
24
26
|
getConfigData(configId: string): Promise<any>;
|
|
25
27
|
protected getCreateUpdateApp(updateApp?: App | null): Promise<App>;
|
|
26
28
|
protected getInstalledApp(): Promise<any>;
|
|
27
|
-
protected getLocalAppConfigs(): AppConfig[]
|
|
29
|
+
protected getLocalAppConfigs(): Promise<AppConfig[]>;
|
|
28
30
|
protected getVersion(version?: null | string | undefined): Promise<AppVersion>;
|
|
29
31
|
protected getVersions(version?: null | string | undefined): Promise<AppVersion[]>;
|
|
30
32
|
protected handleRequestErrors(request: () => any, spinnerError?: () => void): Promise<any>;
|
|
31
33
|
init(): Promise<void>;
|
|
32
|
-
protected installApp(version: string, spinner?:
|
|
34
|
+
protected installApp(version: string, spinner?: Ora): Promise<any>;
|
|
33
35
|
isConfigDeprecated(config: AppConfig): boolean;
|
|
34
36
|
localFrontendUrl(storeId: string, localId: string): string;
|
|
35
37
|
logOrientation(orientation?: AppCommandOrientation): Promise<void>;
|
|
@@ -51,8 +53,8 @@ export declare abstract class RemoteAppCommand extends AppCommand {
|
|
|
51
53
|
storefrontFrontendUrl(storeId: string, storefront?: any, branchId?: string, preview?: boolean): string;
|
|
52
54
|
protected swellRcPath(): string;
|
|
53
55
|
protected timestampStyled(): string;
|
|
54
|
-
protected updateInstalledApp(version: string, spinner?:
|
|
55
|
-
protected updateVersion(version: string, body: any, spinner?:
|
|
56
|
+
protected updateInstalledApp(version: string, spinner?: Ora): Promise<void>;
|
|
57
|
+
protected updateVersion(version: string, body: any, spinner?: Ora): Promise<void>;
|
|
56
58
|
/**
|
|
57
59
|
* Reads the .swellrc file and sets up the remote app configuration.
|
|
58
60
|
*
|
|
@@ -5,7 +5,7 @@ import * as path from 'node:path';
|
|
|
5
5
|
import { default as ora } from 'ora';
|
|
6
6
|
import { AppCommand } from './app-command.js';
|
|
7
7
|
import { readRcFile, writeRcFile } from './lib/app-config.js';
|
|
8
|
-
import { AppConfig, FunctionProcessingError, IgnoringFileError, SwellJsonFields, allBaseFilesInDir, allConfigFilesPaths, appConfigFromFile, batchAppFilesByType, deleteFile, hashFile, writeFile, writeJsonFile, PUSH_CONCURRENCY, } from './lib/apps/index.js';
|
|
8
|
+
import { AppConfig, ConfigType, FunctionProcessingError, IgnoringFileError, SwellJsonFields, allBaseFilesInDir, allConfigFilesPaths, appConfigFromFile, batchAppFilesByType, deleteFile, hashFile, writeFile, writeJsonFile, PUSH_CONCURRENCY, } from './lib/apps/index.js';
|
|
9
9
|
import { default as localConfig } from './lib/config.js';
|
|
10
10
|
import { getAppFrontendHost, getLocalFrontendHost, getLoginHost, getStorefrontFrontendHost, } from './lib/constants.js';
|
|
11
11
|
import { toAppId } from './lib/create/index.js';
|
|
@@ -78,20 +78,21 @@ export class RemoteAppCommand extends AppCommand {
|
|
|
78
78
|
},
|
|
79
79
|
});
|
|
80
80
|
// Instantiate AppConfig for each object
|
|
81
|
-
app.configs = (configs.results || []).map((config) => AppConfig.create({
|
|
81
|
+
app.configs = await Promise.all((configs.results || []).map((config) => AppConfig.create({
|
|
82
82
|
...config,
|
|
83
83
|
appPath: this.appPath,
|
|
84
|
-
}));
|
|
84
|
+
})));
|
|
85
85
|
// Pull app configs to compare with theme for push/pull
|
|
86
86
|
if (themeId && this.themeSyncApp) {
|
|
87
87
|
const appConfigs = await this.api.get({ adminPath: `/apps/${id}/configs` }, { query: { limit: 1000 } });
|
|
88
|
+
const promises = [];
|
|
88
89
|
for (const appConfig of appConfigs.results || []) {
|
|
89
90
|
const themeConfig = app.configs.find((config) => config.filePath === appConfig.file_path);
|
|
90
91
|
if (themeConfig && themeConfig.fileHash !== appConfig.hash) {
|
|
91
92
|
themeConfig.hash = appConfig.hash;
|
|
92
93
|
}
|
|
93
94
|
else if (!themeConfig && appConfig) {
|
|
94
|
-
|
|
95
|
+
promises.push(AppConfig.create({
|
|
95
96
|
...appConfig,
|
|
96
97
|
appConfigId: appConfig.id,
|
|
97
98
|
appPath: this.appPath,
|
|
@@ -99,6 +100,10 @@ export class RemoteAppCommand extends AppCommand {
|
|
|
99
100
|
}));
|
|
100
101
|
}
|
|
101
102
|
}
|
|
103
|
+
if (promises.length > 0) {
|
|
104
|
+
const list = await Promise.all(promises);
|
|
105
|
+
app.configs.push(...list);
|
|
106
|
+
}
|
|
102
107
|
for (const themeConfig of app.configs) {
|
|
103
108
|
const appConfig = appConfigs.results.find((config) => themeConfig.filePath === config.file_path);
|
|
104
109
|
if (!appConfig) {
|
|
@@ -178,7 +183,7 @@ export class RemoteAppCommand extends AppCommand {
|
|
|
178
183
|
throw error;
|
|
179
184
|
}
|
|
180
185
|
}
|
|
181
|
-
if (!this.swellConfig.store
|
|
186
|
+
if (!this.swellConfig.store?.id) {
|
|
182
187
|
throw new Error('App swell.json is missing or `id` is not defined.');
|
|
183
188
|
}
|
|
184
189
|
const body = {
|
|
@@ -244,17 +249,15 @@ export class RemoteAppCommand extends AppCommand {
|
|
|
244
249
|
// check if app is already installed on store
|
|
245
250
|
return this.api.get({ adminPath: `/client/apps/${this.app.id}` }, {});
|
|
246
251
|
}
|
|
247
|
-
getLocalAppConfigs() {
|
|
248
|
-
const
|
|
252
|
+
async getLocalAppConfigs() {
|
|
253
|
+
const promises = [];
|
|
249
254
|
for (const { configFile, configType } of allConfigFilesPaths(this.appPath)) {
|
|
250
|
-
|
|
251
|
-
localConfigs.push(config);
|
|
255
|
+
promises.push(appConfigFromFile(configFile, configType, this.appPath));
|
|
252
256
|
}
|
|
253
257
|
for (const filePath of allBaseFilesInDir(this.appPath)) {
|
|
254
|
-
|
|
255
|
-
localConfigs.push(config);
|
|
258
|
+
promises.push(appConfigFromFile(filePath, ConfigType.FILE, this.appPath));
|
|
256
259
|
}
|
|
257
|
-
return
|
|
260
|
+
return Promise.all(promises);
|
|
258
261
|
}
|
|
259
262
|
async getVersion(version) {
|
|
260
263
|
const versionsResponse = await this.api.get({ adminPath: `/apps/${this.app.id}/versions` }, {
|
|
@@ -289,8 +292,11 @@ export class RemoteAppCommand extends AppCommand {
|
|
|
289
292
|
try {
|
|
290
293
|
jsonError = JSON.parse(error.message);
|
|
291
294
|
}
|
|
292
|
-
catch {
|
|
293
|
-
//
|
|
295
|
+
catch (error) {
|
|
296
|
+
// Skip JSON parse error
|
|
297
|
+
if (!(error instanceof SyntaxError)) {
|
|
298
|
+
throw error;
|
|
299
|
+
}
|
|
294
300
|
}
|
|
295
301
|
if (!showedErrors) {
|
|
296
302
|
if (jsonError && jsonError.error) {
|
|
@@ -312,8 +318,8 @@ export class RemoteAppCommand extends AppCommand {
|
|
|
312
318
|
await this.logOrientation();
|
|
313
319
|
}
|
|
314
320
|
}
|
|
315
|
-
|
|
316
|
-
return this.api.post({ adminPath:
|
|
321
|
+
installApp(version, spinner) {
|
|
322
|
+
return this.api.post({ adminPath: '/client/apps' }, {
|
|
317
323
|
body: { app_id: this.app.id, version },
|
|
318
324
|
onAsyncGetPath: (response) => ({
|
|
319
325
|
adminPath: `/client/app-async-status/${response.app_id}`,
|
|
@@ -352,8 +358,10 @@ export class RemoteAppCommand extends AppCommand {
|
|
|
352
358
|
async pullAppConfigs(force, confirmRemove = true) {
|
|
353
359
|
const pulled = [];
|
|
354
360
|
const removed = [];
|
|
355
|
-
const localConfigs =
|
|
356
|
-
|
|
361
|
+
const [localConfigs, remoteConfigs] = await Promise.all([
|
|
362
|
+
this.getLocalAppConfigs(),
|
|
363
|
+
this.pullAppJsonAndRemoteConfigs().then((remoteConfigs) => this.cleanRemoteConfigs(remoteConfigs, false)),
|
|
364
|
+
]);
|
|
357
365
|
const batches = batchAppFilesByType(remoteConfigs);
|
|
358
366
|
for (const batch of batches) {
|
|
359
367
|
const remoteBatchConfigs = remoteConfigs.filter((config) => config.type === batch.type);
|
|
@@ -364,13 +372,15 @@ export class RemoteAppCommand extends AppCommand {
|
|
|
364
372
|
try {
|
|
365
373
|
const localConfig = localBatchConfigs.find((config) => config.filePath === batchConfig.filePath);
|
|
366
374
|
if (localConfig) {
|
|
367
|
-
const hash = hashFile(batchConfig.appPath,
|
|
375
|
+
const hash = hashFile(batchConfig.appPath, localConfig.fileData, batchConfig.filePath);
|
|
368
376
|
if (hash === batchConfig.hash) {
|
|
369
377
|
return false;
|
|
370
378
|
}
|
|
371
379
|
}
|
|
372
380
|
}
|
|
373
|
-
catch {
|
|
381
|
+
catch {
|
|
382
|
+
// TODO: Ignore only some errors
|
|
383
|
+
}
|
|
374
384
|
return true;
|
|
375
385
|
});
|
|
376
386
|
const filesToRemove = localBatchConfigs.filter((config) => !batch.configs.some((batchConfig) => batchConfig.filePath === config.filePath));
|
|
@@ -439,7 +449,7 @@ export class RemoteAppCommand extends AppCommand {
|
|
|
439
449
|
swellConfigJson.id = toAppId(this.app.private_id);
|
|
440
450
|
await writeJsonFile(path.join(this.appPath, 'swell.json'), swellConfigJson);
|
|
441
451
|
}
|
|
442
|
-
const swellConfig = appConfigFromFile('swell.json',
|
|
452
|
+
const swellConfig = await appConfigFromFile('swell.json', ConfigType.FILE, this.appPath);
|
|
443
453
|
swellConfig.id = swellJson?.id;
|
|
444
454
|
return [swellConfig, ...allOtherConfigs];
|
|
445
455
|
}
|
|
@@ -460,8 +470,10 @@ export class RemoteAppCommand extends AppCommand {
|
|
|
460
470
|
async pushAppConfigs(force) {
|
|
461
471
|
const pushed = [];
|
|
462
472
|
const removed = [];
|
|
463
|
-
const localConfigs =
|
|
464
|
-
|
|
473
|
+
const [localConfigs, remoteConfigs] = await Promise.all([
|
|
474
|
+
this.getLocalAppConfigs(),
|
|
475
|
+
this.cleanRemoteConfigs(this.app?.configs || []),
|
|
476
|
+
]);
|
|
465
477
|
// Do not allow more than 10K files
|
|
466
478
|
if (localConfigs.length > 10000) {
|
|
467
479
|
this.error(`Apps only support up to 10,000 files. Found ${localConfigs.length} files.`);
|
|
@@ -470,8 +482,10 @@ export class RemoteAppCommand extends AppCommand {
|
|
|
470
482
|
for (const batch of batches) {
|
|
471
483
|
const remoteBatchConfigs = remoteConfigs.filter((config) => config.type === batch.type);
|
|
472
484
|
const pushFiles = batch.configs.filter((batchConfig) => {
|
|
485
|
+
if (force)
|
|
486
|
+
return true;
|
|
473
487
|
const remoteConfig = remoteBatchConfigs.find((config) => batchConfig.filePath === config.filePath);
|
|
474
|
-
return Boolean(
|
|
488
|
+
return Boolean(!remoteConfig || remoteConfig.hash !== batchConfig.hash);
|
|
475
489
|
});
|
|
476
490
|
const filesToRemove = remoteBatchConfigs.filter((config) => !batch.configs.some((batchConfig) => batchConfig.filePath === config.filePath));
|
|
477
491
|
// Skip if there are no config changes
|
|
@@ -538,7 +552,7 @@ export class RemoteAppCommand extends AppCommand {
|
|
|
538
552
|
}
|
|
539
553
|
if (error instanceof FunctionProcessingError) {
|
|
540
554
|
log &&
|
|
541
|
-
spinner.fail(`${error.message} ${error.
|
|
555
|
+
spinner.fail(`${error.message} ${error.cause?.message?.toLowerCase()}`);
|
|
542
556
|
return;
|
|
543
557
|
}
|
|
544
558
|
log && spinner.fail(error.message);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type Api from './types/index.js';
|
|
1
2
|
import { HttpMethod } from './lib/api.js';
|
|
2
3
|
import { SwellCommand } from './swell-command.js';
|
|
3
4
|
export declare const headerFlag: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Flags } from '@oclif/core';
|
|
2
|
-
import * as fs from 'node:fs';
|
|
3
|
-
import path from 'node:path';
|
|
2
|
+
import * as fs from 'node:fs/promises';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
4
|
import { FetchError } from 'node-fetch';
|
|
5
5
|
import { HttpMethod } from './lib/api.js';
|
|
6
6
|
import { resolveAppId } from './lib/apps/resolve.js';
|
|
@@ -168,7 +168,7 @@ export class SwellApiCommand extends SwellCommand {
|
|
|
168
168
|
return;
|
|
169
169
|
}
|
|
170
170
|
const bodyData = this.isFilePath(body)
|
|
171
|
-
? await fs.
|
|
171
|
+
? await fs.readFile(path.resolve(body), 'utf8')
|
|
172
172
|
: body;
|
|
173
173
|
return JSON.parse(bodyData);
|
|
174
174
|
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Type definitions for the application.
|
|
3
|
+
*/
|
|
4
|
+
import type { default as Conf } from 'conf';
|
|
5
|
+
declare namespace Api {
|
|
6
|
+
export interface AuthenticationHeaders {
|
|
7
|
+
publicKey?: string;
|
|
8
|
+
secretKey?: string;
|
|
9
|
+
sessionId?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The paths to the API endpoints. Typically a Command will define the
|
|
13
|
+
* path to the API endpoint it needs.
|
|
14
|
+
*/
|
|
15
|
+
export interface Paths {
|
|
16
|
+
adminPath?: string;
|
|
17
|
+
backendPath?: string;
|
|
18
|
+
frontendPath?: string;
|
|
19
|
+
}
|
|
20
|
+
type RequestInit = import('node-fetch').RequestInit;
|
|
21
|
+
/**
|
|
22
|
+
* The options to pass to our generic API request function. This extends
|
|
23
|
+
* the built-in fetch RequestInit interface.
|
|
24
|
+
*/
|
|
25
|
+
export interface RequestOptions extends RequestInit {
|
|
26
|
+
body?: any;
|
|
27
|
+
headers?: Record<string, string>;
|
|
28
|
+
onAsyncGetPath?: (response: any) => Paths;
|
|
29
|
+
query?: any;
|
|
30
|
+
sessionId?: string;
|
|
31
|
+
spinner?: any;
|
|
32
|
+
rawResponse?: boolean;
|
|
33
|
+
}
|
|
34
|
+
export {};
|
|
35
|
+
}
|
|
36
|
+
export default Api;
|
|
37
|
+
/**
|
|
38
|
+
* The configuration of an app as defined by the developer.
|
|
39
|
+
*/
|
|
40
|
+
export interface LocalApp extends Conf<App> {
|
|
41
|
+
swDirPath: string;
|
|
42
|
+
}
|
|
43
|
+
export interface AppCommandOrientation {
|
|
44
|
+
env?: string;
|
|
45
|
+
storeId?: string;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* A log item as defined by the Swell API.
|
|
49
|
+
*/
|
|
50
|
+
export interface LogItem {
|
|
51
|
+
app: string;
|
|
52
|
+
data: string;
|
|
53
|
+
date: string;
|
|
54
|
+
env: string;
|
|
55
|
+
ip: string;
|
|
56
|
+
req: string;
|
|
57
|
+
request: string;
|
|
58
|
+
status: string;
|
|
59
|
+
time: string;
|
|
60
|
+
type: string;
|
|
61
|
+
}
|
|
62
|
+
export interface Store {
|
|
63
|
+
name: string;
|
|
64
|
+
email: string;
|
|
65
|
+
sessionId: string;
|
|
66
|
+
storeId: string;
|
|
67
|
+
}
|
|
68
|
+
export interface User {
|
|
69
|
+
email: string;
|
|
70
|
+
name: string;
|
|
71
|
+
}
|
|
72
|
+
export interface UserAuthorization {
|
|
73
|
+
client_id: string;
|
|
74
|
+
client_name: string;
|
|
75
|
+
}
|
|
76
|
+
export interface App {
|
|
77
|
+
id: string;
|
|
78
|
+
name: string;
|
|
79
|
+
type: string;
|
|
80
|
+
private_id: string;
|
|
81
|
+
public_id?: string;
|
|
82
|
+
}
|
|
83
|
+
export interface Model {
|
|
84
|
+
name: string;
|
|
85
|
+
namespace?: string;
|
|
86
|
+
app_id?: string;
|
|
87
|
+
deprecated?: boolean;
|
|
88
|
+
fields: {
|
|
89
|
+
[key: string]: {
|
|
90
|
+
name: string;
|
|
91
|
+
type: string;
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
}
|
package/oclif.manifest.json
CHANGED