@swell/cli 2.9.6 → 2.9.7
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/app/dev.d.ts +3 -0
- package/dist/commands/app/dev.js +25 -1
- package/dist/commands/app/frontend/dev.d.ts +1 -0
- package/dist/commands/create/app.d.ts +2 -0
- package/dist/commands/create/app.js +32 -6
- package/dist/commands/create/frontend.js +3 -1
- package/dist/create-app-command.d.ts +16 -2
- package/dist/create-app-command.js +59 -11
- package/dist/lib/apps/create-app-result.d.ts +31 -0
- package/dist/lib/apps/create-app-result.js +23 -0
- package/dist/lib/apps/index.d.ts +1 -0
- package/dist/lib/apps/index.js +1 -0
- package/dist/lib/apps/storefront-resources.d.ts +28 -0
- package/dist/lib/apps/storefront-resources.js +60 -0
- package/oclif.manifest.json +33 -1
- package/package.json +1 -1
|
@@ -11,6 +11,7 @@ export default class AppDev extends PushAppCommand {
|
|
|
11
11
|
function: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
12
12
|
'storefront-id': import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
13
13
|
'storefront-select': import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
14
|
+
'json-events': import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
14
15
|
yes: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
15
16
|
};
|
|
16
17
|
static orientation: {
|
|
@@ -24,10 +25,12 @@ export default class AppDev extends PushAppCommand {
|
|
|
24
25
|
tmpDir: string;
|
|
25
26
|
frontendPort: number | null;
|
|
26
27
|
isCleaningUp: boolean;
|
|
28
|
+
jsonEvents: boolean;
|
|
27
29
|
run(): Promise<void>;
|
|
28
30
|
private cleanupOnExit;
|
|
29
31
|
runAppFrontendDevIfApplicable(frontendPort?: number): Promise<number | undefined>;
|
|
30
32
|
private createFunctionRouter;
|
|
33
|
+
private emitLifecycleEvent;
|
|
31
34
|
private createTmpDirectory;
|
|
32
35
|
private generateWranglerConfig;
|
|
33
36
|
private getAppFunctions;
|
package/dist/commands/app/dev.js
CHANGED
|
@@ -42,6 +42,10 @@ export default class AppDev extends PushAppCommand {
|
|
|
42
42
|
default: false,
|
|
43
43
|
description: 'for storefront apps, prompt to select a storefront to preview',
|
|
44
44
|
}),
|
|
45
|
+
'json-events': Flags.boolean({
|
|
46
|
+
description: 'emit machine-readable dev server lifecycle events',
|
|
47
|
+
hidden: true,
|
|
48
|
+
}),
|
|
45
49
|
// Declared here so oclif accepts -y; passed through to app:frontend:dev via this.argv
|
|
46
50
|
yes: Flags.boolean({
|
|
47
51
|
char: 'y',
|
|
@@ -65,10 +69,12 @@ export default class AppDev extends PushAppCommand {
|
|
|
65
69
|
frontendPort = null;
|
|
66
70
|
// Guard against multiple cleanup calls
|
|
67
71
|
isCleaningUp = false;
|
|
72
|
+
jsonEvents = false;
|
|
68
73
|
async run() {
|
|
69
74
|
const { flags } = await this.parse(AppDev);
|
|
70
75
|
const { port, 'frontend-port': frontendPort } = flags;
|
|
71
76
|
const noPush = flags['no-push'];
|
|
77
|
+
this.jsonEvents = flags['json-events'];
|
|
72
78
|
this.functionFilter = flags.function ?? null;
|
|
73
79
|
if (!(await this.ensureAppExists(undefined, false))) {
|
|
74
80
|
return;
|
|
@@ -88,6 +94,10 @@ export default class AppDev extends PushAppCommand {
|
|
|
88
94
|
process.on('SIGTERM', this.cleanupOnExit.bind(this));
|
|
89
95
|
const serverPort = await this.startProxyServer(port);
|
|
90
96
|
await this.startAppFunctionServer(spinner, serverPort);
|
|
97
|
+
this.emitLifecycleEvent('preview:proxy-ready', {
|
|
98
|
+
proxyPort: serverPort,
|
|
99
|
+
storefrontId: this.storefront?.id ?? null,
|
|
100
|
+
});
|
|
91
101
|
await this.runAppFrontendDevIfApplicable(frontendPort);
|
|
92
102
|
}
|
|
93
103
|
async cleanupOnExit() {
|
|
@@ -103,6 +113,9 @@ export default class AppDev extends PushAppCommand {
|
|
|
103
113
|
catch {
|
|
104
114
|
// Ignore errors during cleanup
|
|
105
115
|
}
|
|
116
|
+
this.emitLifecycleEvent('preview:stopped', {
|
|
117
|
+
storefrontId: this.storefront?.id ?? null,
|
|
118
|
+
});
|
|
106
119
|
this.log();
|
|
107
120
|
// eslint-disable-next-line no-process-exit, unicorn/no-process-exit
|
|
108
121
|
process.exit();
|
|
@@ -199,7 +212,18 @@ export default class AppDev extends PushAppCommand {
|
|
|
199
212
|
: ''}`);
|
|
200
213
|
}
|
|
201
214
|
});
|
|
202
|
-
|
|
215
|
+
await new Promise((resolve, reject) => {
|
|
216
|
+
server.once('error', reject);
|
|
217
|
+
server.listen(serverPort, () => {
|
|
218
|
+
server.off('error', reject);
|
|
219
|
+
resolve();
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
emitLifecycleEvent(type, data) {
|
|
224
|
+
if (!this.jsonEvents)
|
|
225
|
+
return;
|
|
226
|
+
this.log(JSON.stringify({ type, ...data }));
|
|
203
227
|
}
|
|
204
228
|
async createTmpDirectory() {
|
|
205
229
|
const tmpBase = path.join(os.tmpdir(), 'swell-cli');
|
|
@@ -11,6 +11,7 @@ export default class AppFrontendDev extends PushAppCommand {
|
|
|
11
11
|
port: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
12
12
|
'frontend-port': import("@oclif/core/lib/interfaces/parser.js").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
13
13
|
function: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
14
|
+
'json-events': import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
14
15
|
};
|
|
15
16
|
static orientation: {
|
|
16
17
|
env: string;
|
|
@@ -14,6 +14,8 @@ export default class CreateApp extends CreateAppCommand {
|
|
|
14
14
|
static helpMeta: HelpMeta;
|
|
15
15
|
static flags: any;
|
|
16
16
|
appType: string;
|
|
17
|
+
private jsonOutput;
|
|
18
|
+
log(message?: string, ...args: any[]): void;
|
|
17
19
|
createSwellConfig({ allowOverwrite, inputId, inputStorefrontApp, inputType, inputName, inputVersion, inputDescription, inputFrontend, inputIntegrationType, inputIntegrationId, inputYes, nestedPath, }: {
|
|
18
20
|
allowOverwrite?: boolean;
|
|
19
21
|
inputDescription?: string;
|
|
@@ -4,6 +4,7 @@ import path from 'node:path';
|
|
|
4
4
|
import ora from 'ora';
|
|
5
5
|
import { CreateAppCommand } from '../../create-app-command.js';
|
|
6
6
|
import { newConfig, swellConfigFileExists } from '../../lib/app-config.js';
|
|
7
|
+
import { buildCreateAppResult } from '../../lib/apps/create-app-result.js';
|
|
7
8
|
import { toAppId, toAppName } from '../../lib/create/index.js';
|
|
8
9
|
import style from '../../lib/style.js';
|
|
9
10
|
/**
|
|
@@ -90,8 +91,16 @@ export default class CreateApp extends CreateAppCommand {
|
|
|
90
91
|
char: 'd',
|
|
91
92
|
description: 'Description',
|
|
92
93
|
}),
|
|
94
|
+
json: Flags.boolean({
|
|
95
|
+
description: 'Output the command result as JSON',
|
|
96
|
+
}),
|
|
93
97
|
};
|
|
94
98
|
appType = '';
|
|
99
|
+
jsonOutput = false;
|
|
100
|
+
log(message, ...args) {
|
|
101
|
+
if (!this.jsonOutput)
|
|
102
|
+
super.log(message, ...args);
|
|
103
|
+
}
|
|
95
104
|
async createSwellConfig({ allowOverwrite = true, inputId = '', inputStorefrontApp, inputType, inputName, inputVersion, inputDescription, inputFrontend, inputIntegrationType, inputIntegrationId, inputYes, nestedPath = true, }) {
|
|
96
105
|
const confirmYes = inputYes;
|
|
97
106
|
let appId = toAppId(inputId || '');
|
|
@@ -352,7 +361,8 @@ export default class CreateApp extends CreateAppCommand {
|
|
|
352
361
|
async run() {
|
|
353
362
|
const { args, flags } = await this.parse(CreateApp);
|
|
354
363
|
const { id } = args;
|
|
355
|
-
const { pkg, yes, name, type, version, description, frontend } = flags;
|
|
364
|
+
const { pkg, yes, name, type, version, description, frontend, json } = flags;
|
|
365
|
+
this.jsonOutput = Boolean(json);
|
|
356
366
|
const confirmYes = Boolean(yes);
|
|
357
367
|
const createParams = await this.createSwellConfig({
|
|
358
368
|
inputId: id,
|
|
@@ -369,7 +379,7 @@ export default class CreateApp extends CreateAppCommand {
|
|
|
369
379
|
if (!createParams) {
|
|
370
380
|
return;
|
|
371
381
|
}
|
|
372
|
-
const { appId, config, installedStorefrontApp } = createParams;
|
|
382
|
+
const { appId, config, installedStorefrontApp, swellConfigJson } = createParams;
|
|
373
383
|
!confirmYes && this.log();
|
|
374
384
|
const spinner = ora();
|
|
375
385
|
spinner.start('Creating app...');
|
|
@@ -378,21 +388,37 @@ export default class CreateApp extends CreateAppCommand {
|
|
|
378
388
|
}
|
|
379
389
|
await this.createAppConfigFolders(config);
|
|
380
390
|
spinner.succeed(`${style.appConfigValue(config.get('name'))} app created.\n`);
|
|
381
|
-
let
|
|
391
|
+
let frontendResult;
|
|
392
|
+
let resources;
|
|
382
393
|
let createdTheme;
|
|
383
394
|
if (installedStorefrontApp) {
|
|
384
395
|
createdTheme = await this.createThemeApp(config, flags, installedStorefrontApp);
|
|
385
396
|
}
|
|
386
397
|
else if (config.get('type') === 'storefront') {
|
|
387
|
-
|
|
398
|
+
const storefrontResult = await this.createStorefrontApp(config, flags, {
|
|
399
|
+
provisionResources: true,
|
|
400
|
+
});
|
|
401
|
+
frontendResult = storefrontResult;
|
|
402
|
+
resources = storefrontResult.resources;
|
|
388
403
|
}
|
|
389
404
|
else {
|
|
390
|
-
|
|
405
|
+
frontendResult = await this.createFrontendApp(config, flags);
|
|
406
|
+
}
|
|
407
|
+
if (json) {
|
|
408
|
+
super.log(JSON.stringify(buildCreateAppResult({
|
|
409
|
+
privateId: swellConfigJson.id,
|
|
410
|
+
resources,
|
|
411
|
+
name: swellConfigJson.name,
|
|
412
|
+
type: swellConfigJson.type,
|
|
413
|
+
frontend: frontendResult?.framework ?? null,
|
|
414
|
+
path: path.dirname(config.path),
|
|
415
|
+
})));
|
|
416
|
+
return;
|
|
391
417
|
}
|
|
392
418
|
this.log('\nNext steps:');
|
|
393
419
|
this.log(`Run ${style.command('swell app push')} to push configurations to your test store.`);
|
|
394
420
|
this.log(`Run ${style.command('swell app install')} to install the app in another store or environment.`);
|
|
395
|
-
if (
|
|
421
|
+
if (frontendResult?.created) {
|
|
396
422
|
this.log(`Run ${style.command('swell app frontend dev')} to start a local dev server for your frontend app.`);
|
|
397
423
|
}
|
|
398
424
|
else if (createdTheme) {
|
|
@@ -32,7 +32,9 @@ export default class CreateFrontend extends CreateAppCommand {
|
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
34
34
|
await (appType === 'storefront'
|
|
35
|
-
? this.createStorefrontApp(newSwellConfig, flags,
|
|
35
|
+
? this.createStorefrontApp(newSwellConfig, flags, {
|
|
36
|
+
directCreate: true,
|
|
37
|
+
})
|
|
36
38
|
: this.createFrontendApp(newSwellConfig, flags, true));
|
|
37
39
|
}
|
|
38
40
|
}
|
|
@@ -1,5 +1,18 @@
|
|
|
1
|
+
import { type StorefrontResourceResult } from './lib/apps/storefront-resources.js';
|
|
1
2
|
import { PackageManager } from './lib/package-manager.js';
|
|
2
3
|
import { SwellCommand } from './swell-command.js';
|
|
4
|
+
export interface FrontendCreationResult {
|
|
5
|
+
created: boolean;
|
|
6
|
+
framework: string | null;
|
|
7
|
+
provisionsStorefront: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface StorefrontCreationResult extends FrontendCreationResult {
|
|
10
|
+
resources?: StorefrontResourceResult;
|
|
11
|
+
}
|
|
12
|
+
export interface StorefrontCreationOptions {
|
|
13
|
+
directCreate?: boolean;
|
|
14
|
+
provisionResources?: boolean;
|
|
15
|
+
}
|
|
3
16
|
export declare abstract class CreateAppCommand extends SwellCommand {
|
|
4
17
|
protected commandExample: string;
|
|
5
18
|
static baseFlags: {
|
|
@@ -25,8 +38,8 @@ export declare abstract class CreateAppCommand extends SwellCommand {
|
|
|
25
38
|
*/
|
|
26
39
|
private addViteAllowedHosts;
|
|
27
40
|
createAppConfigFolders(swellConfig: any): Promise<void>;
|
|
28
|
-
createFrontendApp(swellConfig: any, flags: any, directCreate?: boolean, kind?: string): Promise<
|
|
29
|
-
createStorefrontApp(swellConfig: any, flags: any,
|
|
41
|
+
createFrontendApp(swellConfig: any, flags: any, directCreate?: boolean, kind?: string): Promise<FrontendCreationResult>;
|
|
42
|
+
createStorefrontApp(swellConfig: any, flags: any, options?: StorefrontCreationOptions): Promise<StorefrontCreationResult>;
|
|
30
43
|
createThemeApp(config: any, flags: any, installedStorefrontApp: any): Promise<boolean>;
|
|
31
44
|
doesPackageManagerExist(packageManager: string): Promise<boolean>;
|
|
32
45
|
execWithStdio(cwd: string, command: string, onOutput?: (string: string) => any | false): Promise<void>;
|
|
@@ -40,6 +53,7 @@ export declare abstract class CreateAppCommand extends SwellCommand {
|
|
|
40
53
|
displayOrder?: number | undefined;
|
|
41
54
|
mainPackage: string;
|
|
42
55
|
name: string;
|
|
56
|
+
provisionsStorefront?: boolean | undefined;
|
|
43
57
|
slug: string;
|
|
44
58
|
};
|
|
45
59
|
setupPackage(name: string, config: any, pkg: PackageManager): Promise<void>;
|
|
@@ -9,6 +9,7 @@ import { promisify } from 'node:util';
|
|
|
9
9
|
import ora from 'ora';
|
|
10
10
|
import Api from './lib/api.js';
|
|
11
11
|
import { FrontendProjectTypes, getFrontendProjectValidValues, getAllConfigPaths, getFrontendProjectSlugs, writeFile, writeJsonFile, } from './lib/apps/index.js';
|
|
12
|
+
import { ensureStorefrontResources, } from './lib/apps/storefront-resources.js';
|
|
12
13
|
import { getPackageManagerCommands, transformCreateCommand, } from './lib/package-manager.js';
|
|
13
14
|
import style from './lib/style.js';
|
|
14
15
|
import { SwellCommand } from './swell-command.js';
|
|
@@ -287,7 +288,11 @@ export class CreateAppCommand extends SwellCommand {
|
|
|
287
288
|
const files = await fs.readdir(frontendPath);
|
|
288
289
|
if (files.length > 0) {
|
|
289
290
|
spinner.fail('frontend/ folder is not empty. Please remove existing files before scaffolding.');
|
|
290
|
-
return
|
|
291
|
+
return {
|
|
292
|
+
created: false,
|
|
293
|
+
framework: projectType.slug,
|
|
294
|
+
provisionsStorefront: Boolean(projectType.provisionsStorefront),
|
|
295
|
+
};
|
|
291
296
|
}
|
|
292
297
|
}
|
|
293
298
|
catch {
|
|
@@ -298,11 +303,28 @@ export class CreateAppCommand extends SwellCommand {
|
|
|
298
303
|
await execAsync(`mkdir -p frontend`, {
|
|
299
304
|
cwd: configPath,
|
|
300
305
|
});
|
|
301
|
-
//
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
+
// SWELL_LOCAL_TEMPLATE_PATH overrides the scaffold for local dev — copies
|
|
307
|
+
// the directory at the path into frontend/ instead of running the install
|
|
308
|
+
// command. Used to iterate on the canonical template repo without pushing.
|
|
309
|
+
const localTemplatePath = process.env.SWELL_LOCAL_TEMPLATE_PATH;
|
|
310
|
+
if (localTemplatePath) {
|
|
311
|
+
const source = path.resolve(localTemplatePath);
|
|
312
|
+
const dest = path.join(configPath, 'frontend');
|
|
313
|
+
await fs.cp(source, dest, {
|
|
314
|
+
recursive: true,
|
|
315
|
+
filter: (src) => !src.includes('/node_modules') &&
|
|
316
|
+
!src.endsWith('/.git') &&
|
|
317
|
+
!src.includes('/dist') &&
|
|
318
|
+
!src.includes('/.wrangler'),
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
// Transform install command for the selected package manager
|
|
323
|
+
const installCommand = transformCreateCommand(projectType.installCommand, pkg);
|
|
324
|
+
await execAsync(installCommand, {
|
|
325
|
+
cwd: configPath,
|
|
326
|
+
});
|
|
327
|
+
}
|
|
306
328
|
// Use this command to debug output, i.e.e when command becomes non-responsive
|
|
307
329
|
/* await this.execWithStdio(
|
|
308
330
|
configPath,
|
|
@@ -317,7 +339,11 @@ export class CreateAppCommand extends SwellCommand {
|
|
|
317
339
|
.join('\n') || (error.message ?? '').trim();
|
|
318
340
|
if (detail)
|
|
319
341
|
this.log(detail);
|
|
320
|
-
return
|
|
342
|
+
return {
|
|
343
|
+
created: false,
|
|
344
|
+
framework: projectType.slug,
|
|
345
|
+
provisionsStorefront: Boolean(projectType.provisionsStorefront),
|
|
346
|
+
};
|
|
321
347
|
}
|
|
322
348
|
// Ensure frontend package.json has correct name for workspace
|
|
323
349
|
try {
|
|
@@ -346,12 +372,34 @@ export class CreateAppCommand extends SwellCommand {
|
|
|
346
372
|
if (directCreate) {
|
|
347
373
|
this.log();
|
|
348
374
|
}
|
|
349
|
-
return
|
|
375
|
+
return {
|
|
376
|
+
created: true,
|
|
377
|
+
framework: projectType.slug,
|
|
378
|
+
provisionsStorefront: Boolean(projectType.provisionsStorefront),
|
|
379
|
+
};
|
|
350
380
|
}
|
|
351
|
-
return
|
|
381
|
+
return {
|
|
382
|
+
created: false,
|
|
383
|
+
framework: null,
|
|
384
|
+
provisionsStorefront: false,
|
|
385
|
+
};
|
|
352
386
|
}
|
|
353
|
-
async createStorefrontApp(swellConfig, flags,
|
|
354
|
-
|
|
387
|
+
async createStorefrontApp(swellConfig, flags, options = {}) {
|
|
388
|
+
const frontend = await this.createFrontendApp(swellConfig, flags, options.directCreate, 'storefront');
|
|
389
|
+
if (!options.provisionResources ||
|
|
390
|
+
!frontend.created ||
|
|
391
|
+
!frontend.provisionsStorefront) {
|
|
392
|
+
return frontend;
|
|
393
|
+
}
|
|
394
|
+
const resources = await ensureStorefrontResources(this.api, {
|
|
395
|
+
description: swellConfig.get('description'),
|
|
396
|
+
name: swellConfig.get('name'),
|
|
397
|
+
privateId: swellConfig.get('id'),
|
|
398
|
+
type: 'storefront',
|
|
399
|
+
version: swellConfig.get('version'),
|
|
400
|
+
});
|
|
401
|
+
this.log(`Storefront ${style.appConfigValue(resources.storefront.id)} created for app ${style.appConfigValue(resources.app.id)}.`);
|
|
402
|
+
return { ...frontend, resources };
|
|
355
403
|
}
|
|
356
404
|
async createThemeApp(config, flags, installedStorefrontApp) {
|
|
357
405
|
const spinner = ora();
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { StorefrontResourceResult } from './storefront-resources.js';
|
|
2
|
+
export interface CreateAppResultInput {
|
|
3
|
+
frontend: string | null;
|
|
4
|
+
name: string;
|
|
5
|
+
path: string;
|
|
6
|
+
privateId: string;
|
|
7
|
+
resources?: StorefrontResourceResult;
|
|
8
|
+
type: string;
|
|
9
|
+
}
|
|
10
|
+
export interface CreateAppResult {
|
|
11
|
+
app: {
|
|
12
|
+
name: string;
|
|
13
|
+
privateId: string;
|
|
14
|
+
resourceId: string | null;
|
|
15
|
+
type: string;
|
|
16
|
+
};
|
|
17
|
+
frontend: string | null;
|
|
18
|
+
path: string;
|
|
19
|
+
storefront: {
|
|
20
|
+
resourceId: string;
|
|
21
|
+
} | null;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Build the stable JSON contract for every `swell create app` variant.
|
|
25
|
+
* Remote resource IDs are nullable because only provisioning frontends create
|
|
26
|
+
* them; the shape itself never changes by app type or frontend.
|
|
27
|
+
*
|
|
28
|
+
* @param input completed local and optional remote creation result
|
|
29
|
+
* @returns serializable command result
|
|
30
|
+
*/
|
|
31
|
+
export declare function buildCreateAppResult(input: CreateAppResultInput): CreateAppResult;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build the stable JSON contract for every `swell create app` variant.
|
|
3
|
+
* Remote resource IDs are nullable because only provisioning frontends create
|
|
4
|
+
* them; the shape itself never changes by app type or frontend.
|
|
5
|
+
*
|
|
6
|
+
* @param input completed local and optional remote creation result
|
|
7
|
+
* @returns serializable command result
|
|
8
|
+
*/
|
|
9
|
+
export function buildCreateAppResult(input) {
|
|
10
|
+
return {
|
|
11
|
+
app: {
|
|
12
|
+
privateId: input.privateId,
|
|
13
|
+
resourceId: input.resources?.app.id ?? null,
|
|
14
|
+
name: input.name,
|
|
15
|
+
type: input.type,
|
|
16
|
+
},
|
|
17
|
+
storefront: input.resources
|
|
18
|
+
? { resourceId: input.resources.storefront.id }
|
|
19
|
+
: null,
|
|
20
|
+
frontend: input.frontend,
|
|
21
|
+
path: input.path,
|
|
22
|
+
};
|
|
23
|
+
}
|
package/dist/lib/apps/index.d.ts
CHANGED
package/dist/lib/apps/index.js
CHANGED
|
@@ -130,6 +130,7 @@ export const FrontendProjectTypes = [
|
|
|
130
130
|
installCommand: 'npm create cloudflare@latest -- frontend --template=swellstores/storefront-react-ai-template#main --deploy=false --git=false --no-agents',
|
|
131
131
|
mainPackage: '@swell/storefront-app-sdk-react',
|
|
132
132
|
name: 'Swell React Storefront',
|
|
133
|
+
provisionsStorefront: true,
|
|
133
134
|
slug: 'react-storefront',
|
|
134
135
|
},
|
|
135
136
|
{
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import Api from '../api.js';
|
|
2
|
+
export interface StorefrontResourceInput {
|
|
3
|
+
description?: string;
|
|
4
|
+
name: string;
|
|
5
|
+
privateId: string;
|
|
6
|
+
type: 'storefront';
|
|
7
|
+
version: string;
|
|
8
|
+
}
|
|
9
|
+
export interface StorefrontResourceResult {
|
|
10
|
+
app: {
|
|
11
|
+
id: string;
|
|
12
|
+
privateId: string;
|
|
13
|
+
};
|
|
14
|
+
storefront: {
|
|
15
|
+
id: string;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Ensure the remote development app and its storefront exist.
|
|
20
|
+
*
|
|
21
|
+
* `swell create app --frontend react-storefront` calls this after the local
|
|
22
|
+
* scaffold succeeds. Retrying is safe: existing resources are reused.
|
|
23
|
+
*
|
|
24
|
+
* @param api authenticated Swell API client
|
|
25
|
+
* @param input storefront app identity from the generated swell.json
|
|
26
|
+
* @returns the stable remote app and storefront IDs
|
|
27
|
+
*/
|
|
28
|
+
export declare function ensureStorefrontResources(api: Api, input: StorefrontResourceInput): Promise<StorefrontResourceResult>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import config from '../config.js';
|
|
2
|
+
/**
|
|
3
|
+
* Ensure the remote development app and its storefront exist.
|
|
4
|
+
*
|
|
5
|
+
* `swell create app --frontend react-storefront` calls this after the local
|
|
6
|
+
* scaffold succeeds. Retrying is safe: existing resources are reused.
|
|
7
|
+
*
|
|
8
|
+
* @param api authenticated Swell API client
|
|
9
|
+
* @param input storefront app identity from the generated swell.json
|
|
10
|
+
* @returns the stable remote app and storefront IDs
|
|
11
|
+
*/
|
|
12
|
+
export async function ensureStorefrontResources(api, input) {
|
|
13
|
+
const storeId = config.getDefaultStore();
|
|
14
|
+
await api.setStoreEnv(storeId, 'test');
|
|
15
|
+
let app;
|
|
16
|
+
try {
|
|
17
|
+
const existing = await api.get({
|
|
18
|
+
adminPath: `/apps/${input.privateId}`,
|
|
19
|
+
});
|
|
20
|
+
if (existing?.client_id === storeId) {
|
|
21
|
+
app = existing;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
// App not found — create it below.
|
|
26
|
+
}
|
|
27
|
+
if (!app) {
|
|
28
|
+
app = await api.post({ adminPath: '/apps' }, {
|
|
29
|
+
body: {
|
|
30
|
+
description: input.description,
|
|
31
|
+
name: input.name,
|
|
32
|
+
private_id: input.privateId,
|
|
33
|
+
type: input.type,
|
|
34
|
+
version: input.version,
|
|
35
|
+
permissions: [],
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
const storefronts = await api.get({
|
|
40
|
+
adminPath: `/apps/${app.id}/storefronts`,
|
|
41
|
+
});
|
|
42
|
+
let storefront = storefronts?.results?.[0];
|
|
43
|
+
if (!storefront) {
|
|
44
|
+
storefront = await api.post({ adminPath: '/storefronts' }, {
|
|
45
|
+
body: {
|
|
46
|
+
app_id: app.id,
|
|
47
|
+
name: input.name,
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
app: {
|
|
53
|
+
id: app.id,
|
|
54
|
+
privateId: input.privateId,
|
|
55
|
+
},
|
|
56
|
+
storefront: {
|
|
57
|
+
id: storefront.id,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
package/oclif.manifest.json
CHANGED
|
@@ -779,6 +779,13 @@
|
|
|
779
779
|
"allowNo": false,
|
|
780
780
|
"type": "boolean"
|
|
781
781
|
},
|
|
782
|
+
"json-events": {
|
|
783
|
+
"description": "emit machine-readable dev server lifecycle events",
|
|
784
|
+
"hidden": true,
|
|
785
|
+
"name": "json-events",
|
|
786
|
+
"allowNo": false,
|
|
787
|
+
"type": "boolean"
|
|
788
|
+
},
|
|
782
789
|
"yes": {
|
|
783
790
|
"char": "y",
|
|
784
791
|
"description": "skip prompts (non-interactive mode)",
|
|
@@ -976,6 +983,12 @@
|
|
|
976
983
|
"hasDynamicHelp": false,
|
|
977
984
|
"multiple": false,
|
|
978
985
|
"type": "option"
|
|
986
|
+
},
|
|
987
|
+
"json": {
|
|
988
|
+
"description": "Output the command result as JSON",
|
|
989
|
+
"name": "json",
|
|
990
|
+
"allowNo": false,
|
|
991
|
+
"type": "boolean"
|
|
979
992
|
}
|
|
980
993
|
},
|
|
981
994
|
"hasDynamicHelp": false,
|
|
@@ -1536,6 +1549,12 @@
|
|
|
1536
1549
|
"hasDynamicHelp": false,
|
|
1537
1550
|
"multiple": false,
|
|
1538
1551
|
"type": "option"
|
|
1552
|
+
},
|
|
1553
|
+
"json": {
|
|
1554
|
+
"description": "Output the command result as JSON",
|
|
1555
|
+
"name": "json",
|
|
1556
|
+
"allowNo": false,
|
|
1557
|
+
"type": "boolean"
|
|
1539
1558
|
}
|
|
1540
1559
|
},
|
|
1541
1560
|
"hasDynamicHelp": false,
|
|
@@ -3215,6 +3234,12 @@
|
|
|
3215
3234
|
"hasDynamicHelp": false,
|
|
3216
3235
|
"multiple": false,
|
|
3217
3236
|
"type": "option"
|
|
3237
|
+
},
|
|
3238
|
+
"json": {
|
|
3239
|
+
"description": "Output the command result as JSON",
|
|
3240
|
+
"name": "json",
|
|
3241
|
+
"allowNo": false,
|
|
3242
|
+
"type": "boolean"
|
|
3218
3243
|
}
|
|
3219
3244
|
},
|
|
3220
3245
|
"hasDynamicHelp": false,
|
|
@@ -3514,6 +3539,13 @@
|
|
|
3514
3539
|
"allowNo": false,
|
|
3515
3540
|
"type": "boolean"
|
|
3516
3541
|
},
|
|
3542
|
+
"json-events": {
|
|
3543
|
+
"description": "emit machine-readable dev server lifecycle events",
|
|
3544
|
+
"hidden": true,
|
|
3545
|
+
"name": "json-events",
|
|
3546
|
+
"allowNo": false,
|
|
3547
|
+
"type": "boolean"
|
|
3548
|
+
},
|
|
3517
3549
|
"yes": {
|
|
3518
3550
|
"char": "y",
|
|
3519
3551
|
"description": "skip prompts (non-interactive mode)",
|
|
@@ -3556,5 +3588,5 @@
|
|
|
3556
3588
|
]
|
|
3557
3589
|
}
|
|
3558
3590
|
},
|
|
3559
|
-
"version": "2.9.
|
|
3591
|
+
"version": "2.9.7"
|
|
3560
3592
|
}
|