@swell/cli 2.3.1 → 2.3.3
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 +42 -1
- package/dist/commands/app/frontend/dev.js +6 -2
- package/dist/commands/logs.d.ts +0 -1
- package/dist/commands/logs.js +38 -17
- package/dist/lib/apps/app-config.d.ts +6 -0
- package/dist/lib/apps/app-config.js +41 -1
- package/dist/lib/apps/index.d.ts +1 -0
- package/dist/lib/apps/index.js +3 -0
- package/dist/lib/bundle.d.ts +1 -0
- package/dist/lib/bundle.js +39 -0
- package/dist/lib/logs/table-output.js +1 -1
- package/dist/push-app-command.d.ts +1 -1
- package/dist/push-app-command.js +11 -5
- package/oclif.manifest.json +4 -4
- package/package.json +1 -1
|
@@ -16,7 +16,10 @@ export default class AppDev extends PushAppCommand {
|
|
|
16
16
|
functionErrors: Map<string, string>;
|
|
17
17
|
functionPorts: Map<string, number>;
|
|
18
18
|
tmpDir: string;
|
|
19
|
+
frontendPort: number | null;
|
|
20
|
+
isCleaningUp: boolean;
|
|
19
21
|
run(): Promise<void>;
|
|
22
|
+
private cleanupOnExit;
|
|
20
23
|
runAppFrontendDevIfApplicable(frontendPort?: number): Promise<number | void>;
|
|
21
24
|
private createFunctionRouter;
|
|
22
25
|
private createTmpDirectory;
|
package/dist/commands/app/dev.js
CHANGED
|
@@ -46,6 +46,10 @@ export default class AppDev extends PushAppCommand {
|
|
|
46
46
|
functionPorts = new Map();
|
|
47
47
|
// Directory for compiled function files and wrangler context
|
|
48
48
|
tmpDir = '';
|
|
49
|
+
// Port for frontend dev server (used for routing non-function requests)
|
|
50
|
+
frontendPort = null;
|
|
51
|
+
// Guard against multiple cleanup calls
|
|
52
|
+
isCleaningUp = false;
|
|
49
53
|
async run() {
|
|
50
54
|
const { flags } = await this.parse(AppDev);
|
|
51
55
|
const { port, 'frontend-port': frontendPort } = flags;
|
|
@@ -62,6 +66,21 @@ export default class AppDev extends PushAppCommand {
|
|
|
62
66
|
const serverPort = await this.startProxyServer(port);
|
|
63
67
|
await this.startAppFunctionServer(spinner, serverPort);
|
|
64
68
|
await this.runAppFrontendDevIfApplicable(frontendPort);
|
|
69
|
+
// Register cleanup handlers to clear local proxy on exit
|
|
70
|
+
process.on('SIGINT', this.cleanupOnExit.bind(this));
|
|
71
|
+
process.on('SIGTERM', this.cleanupOnExit.bind(this));
|
|
72
|
+
}
|
|
73
|
+
async cleanupOnExit() {
|
|
74
|
+
if (this.isCleaningUp)
|
|
75
|
+
return;
|
|
76
|
+
this.isCleaningUp = true;
|
|
77
|
+
try {
|
|
78
|
+
await this.updateLocalProxy(null, this.storefront?.id);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// Ignore errors during cleanup
|
|
82
|
+
}
|
|
83
|
+
// Note: proxy.ts signal handlers will call process.exit()
|
|
65
84
|
}
|
|
66
85
|
async runAppFrontendDevIfApplicable(frontendPort) {
|
|
67
86
|
const projectType = this.getFrontendProjectType(false);
|
|
@@ -70,6 +89,8 @@ export default class AppDev extends PushAppCommand {
|
|
|
70
89
|
this.argv.push('--app-dev');
|
|
71
90
|
// add proxy-port flag (use provided port or auto-detect)
|
|
72
91
|
const proxyPort = frontendPort || (await getPort({ port: portNumbers(4000, 4100) }));
|
|
92
|
+
// Store frontend port for function router to use for fallback routing
|
|
93
|
+
this.frontendPort = proxyPort;
|
|
73
94
|
this.argv.push('--proxy-port', String(proxyPort));
|
|
74
95
|
this.config.runCommand('app:frontend:dev', this.argv);
|
|
75
96
|
return proxyPort;
|
|
@@ -111,6 +132,24 @@ export default class AppDev extends PushAppCommand {
|
|
|
111
132
|
});
|
|
112
133
|
req.pipe(proxyReq);
|
|
113
134
|
}
|
|
135
|
+
else if (this.frontendPort) {
|
|
136
|
+
// Proxy non-function requests to frontend dev server
|
|
137
|
+
const proxyReq = http.request({
|
|
138
|
+
hostname: 'localhost',
|
|
139
|
+
port: this.frontendPort,
|
|
140
|
+
path: req.url,
|
|
141
|
+
method: req.method,
|
|
142
|
+
headers: req.headers,
|
|
143
|
+
}, (proxyRes) => {
|
|
144
|
+
res.writeHead(proxyRes.statusCode, proxyRes.headers);
|
|
145
|
+
proxyRes.pipe(res);
|
|
146
|
+
});
|
|
147
|
+
proxyReq.on('error', (error) => {
|
|
148
|
+
res.writeHead(502);
|
|
149
|
+
res.end(`Frontend dev server error: ${error.message}`);
|
|
150
|
+
});
|
|
151
|
+
req.pipe(proxyReq);
|
|
152
|
+
}
|
|
114
153
|
else {
|
|
115
154
|
res.writeHead(404);
|
|
116
155
|
const functionError = this.functionErrors.get(functionName);
|
|
@@ -258,6 +297,8 @@ ENVIRONMENT = "development"
|
|
|
258
297
|
// Get all functions in this app
|
|
259
298
|
const functions = await this.getAppFunctions();
|
|
260
299
|
if (functions.length === 0) {
|
|
300
|
+
// Create routing server to proxy requests to frontend even without functions
|
|
301
|
+
await this.createFunctionRouter(serverPort);
|
|
261
302
|
spinner.stop();
|
|
262
303
|
return;
|
|
263
304
|
}
|
|
@@ -269,7 +310,7 @@ ENVIRONMENT = "development"
|
|
|
269
310
|
this.watchForChanges({
|
|
270
311
|
onChange: this.onChangeFunctionWatcher.bind(this),
|
|
271
312
|
});
|
|
272
|
-
// Create
|
|
313
|
+
// Create routing server after function servers are ready
|
|
273
314
|
await this.createFunctionRouter(serverPort);
|
|
274
315
|
spinner.succeed(`App function server running on port ${serverPort}\n`);
|
|
275
316
|
this.log(`${style.appConfigName(`Functions:`)}`);
|
|
@@ -26,7 +26,7 @@ export default class AppFrontendDev extends PushAppCommand {
|
|
|
26
26
|
}),
|
|
27
27
|
'app-dev': Flags.boolean({
|
|
28
28
|
description: 'indicates frontend app is running in app dev mode',
|
|
29
|
-
default:
|
|
29
|
+
default: false,
|
|
30
30
|
}),
|
|
31
31
|
};
|
|
32
32
|
static orientation = {
|
|
@@ -57,7 +57,11 @@ export default class AppFrontendDev extends PushAppCommand {
|
|
|
57
57
|
if (!isAppDev) {
|
|
58
58
|
this.log(`Starting app dev server...\n`);
|
|
59
59
|
}
|
|
60
|
-
|
|
60
|
+
// When running as child of `swell app dev`, don't create a new tunnel.
|
|
61
|
+
// The parent command already created the tunnel and handles routing.
|
|
62
|
+
const serverPort = isAppDev && proxyPort
|
|
63
|
+
? proxyPort
|
|
64
|
+
: await this.startProxyServer(proxyPort || port);
|
|
61
65
|
await this.execFrontendProject(serverPort, isAppDev);
|
|
62
66
|
}
|
|
63
67
|
async execFrontendProject(serverPort, isAppDev) {
|
package/dist/commands/logs.d.ts
CHANGED
package/dist/commands/logs.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Flags } from '@oclif/core';
|
|
2
|
-
import ora from 'ora';
|
|
3
2
|
import { LineOutput, LoggedItem, TableOutput } from '../lib/logs/index.js';
|
|
4
3
|
import { SwellCommand } from '../swell-command.js';
|
|
5
4
|
// the columns available to display in the table
|
|
@@ -19,6 +18,23 @@ const OUTPUT_COLUMNS = [
|
|
|
19
18
|
const OUTPUT_COLUMNS_DEFAULTS = ['date', 'request', 'data', 'status', 'time'];
|
|
20
19
|
// the interval to poll the API when following logs
|
|
21
20
|
const FOLLOW_POLLING_INTERVAL = 1000 * 2; // 2 seconds
|
|
21
|
+
/**
|
|
22
|
+
* Converts $in value to array
|
|
23
|
+
* @param value value to convert
|
|
24
|
+
* @param op operator
|
|
25
|
+
* @param convertToNumber true if string value should be converted to number
|
|
26
|
+
* @returns converted value
|
|
27
|
+
*/
|
|
28
|
+
function convertOperatorValue(value, op, convertToNumber = false) {
|
|
29
|
+
if (Array.isArray(value)) {
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
const converted = convertToNumber ? Number.parseInt(value, 10) : value;
|
|
33
|
+
if (op !== '$in') {
|
|
34
|
+
return converted;
|
|
35
|
+
}
|
|
36
|
+
return [converted];
|
|
37
|
+
}
|
|
22
38
|
/**
|
|
23
39
|
* Builds the request options to send to the API based on the flags passed
|
|
24
40
|
* to the command.
|
|
@@ -36,7 +52,7 @@ function buildLogRequestBody(flags) {
|
|
|
36
52
|
// some filters are simple and can be mapped directly to the API
|
|
37
53
|
const logFilters = [
|
|
38
54
|
{ filter: 'app_id', flag: 'app', operator: '$in' },
|
|
39
|
-
{ filter: 'message.status', flag: 'status', operator: '$in' },
|
|
55
|
+
{ filter: 'message.status', flag: 'status', operator: '$in', number: true },
|
|
40
56
|
{ filter: 'message.type', flag: 'type', operator: '$in' },
|
|
41
57
|
];
|
|
42
58
|
// map the flags to the API query
|
|
@@ -44,7 +60,9 @@ function buildLogRequestBody(flags) {
|
|
|
44
60
|
if (flags[filter.flag]) {
|
|
45
61
|
andConditions.push({
|
|
46
62
|
[filter.filter]: filter.operator
|
|
47
|
-
? {
|
|
63
|
+
? {
|
|
64
|
+
[filter.operator]: convertOperatorValue(flags[filter.flag], filter.operator, filter.number),
|
|
65
|
+
}
|
|
48
66
|
: flags[filter.flag],
|
|
49
67
|
});
|
|
50
68
|
}
|
|
@@ -145,7 +163,7 @@ export default class Logs extends SwellCommand {
|
|
|
145
163
|
char: 'p',
|
|
146
164
|
default: false,
|
|
147
165
|
description: 'note that this flag will take more space in the terminal and require more time to load',
|
|
148
|
-
summary: 'pretty print json data',
|
|
166
|
+
summary: 'pretty print json data in table output',
|
|
149
167
|
}),
|
|
150
168
|
search: Flags.string({
|
|
151
169
|
char: 's',
|
|
@@ -163,10 +181,6 @@ export default class Logs extends SwellCommand {
|
|
|
163
181
|
static summary = 'Output or stream store logs to the terminal.';
|
|
164
182
|
output;
|
|
165
183
|
async run() {
|
|
166
|
-
const spinner = ora();
|
|
167
|
-
spinner.fail('This command is temporarily disabled. Check back soon.');
|
|
168
|
-
}
|
|
169
|
-
async __run() {
|
|
170
184
|
const { flags } = await this.parse(Logs);
|
|
171
185
|
// indentify the columns to display
|
|
172
186
|
const columns = flags.columns.split(',');
|
|
@@ -175,24 +189,30 @@ export default class Logs extends SwellCommand {
|
|
|
175
189
|
flags.output === 'table'
|
|
176
190
|
? new TableOutput(columns, flags.pretty)
|
|
177
191
|
: new LineOutput(columns, flags.pretty);
|
|
178
|
-
// first run for getting the logs
|
|
179
|
-
// we keep track of the last date we received so we can get logs after that
|
|
180
|
-
flags.startPolling = await this.getLogsAndWriteToStream(flags);
|
|
181
192
|
// if following, poll the API every FOLLOW_POLLING_INTERVAL seconds and
|
|
182
193
|
// write new logs to the stream
|
|
183
194
|
if (flags.follow) {
|
|
195
|
+
// first get the latest log to use its date
|
|
196
|
+
// we keep track of the last date we received so we can get logs after that
|
|
197
|
+
const previousNumber = flags.number;
|
|
198
|
+
flags.number = 1; // get the latest log
|
|
199
|
+
flags.startPolling = await this.getLogsAndWriteToStream(flags, false);
|
|
200
|
+
flags.number = previousNumber;
|
|
184
201
|
setInterval(async () => {
|
|
185
202
|
// when polling, we want to get logs after the last date we received
|
|
186
203
|
flags.startPolling = await this.getLogsAndWriteToStream(flags);
|
|
187
204
|
}, FOLLOW_POLLING_INTERVAL);
|
|
188
205
|
}
|
|
206
|
+
else {
|
|
207
|
+
await this.getLogsAndWriteToStream(flags);
|
|
208
|
+
}
|
|
189
209
|
}
|
|
190
210
|
async getLogs(flags) {
|
|
191
211
|
const body = buildLogRequestBody(flags);
|
|
192
212
|
const response = await this.api.post({ adminPath: `/data/$get/:logs` }, { body });
|
|
193
213
|
return response?.results?.reverse() || [];
|
|
194
214
|
}
|
|
195
|
-
async getLogsAndWriteToStream(flags) {
|
|
215
|
+
async getLogsAndWriteToStream(flags, show = true) {
|
|
196
216
|
const logs = await this.getLogs(flags);
|
|
197
217
|
let lastDate = '';
|
|
198
218
|
if (!this.output) {
|
|
@@ -200,12 +220,13 @@ export default class Logs extends SwellCommand {
|
|
|
200
220
|
}
|
|
201
221
|
if (logs.length > 0) {
|
|
202
222
|
lastDate = logs.at(-1).date;
|
|
203
|
-
|
|
204
|
-
|
|
223
|
+
if (show) {
|
|
224
|
+
for (const log of logs) {
|
|
225
|
+
this.output.write(this.output.prepareData(new LoggedItem(log)));
|
|
226
|
+
}
|
|
205
227
|
}
|
|
206
228
|
}
|
|
207
|
-
// if the user is following logs, we want to return the last date we
|
|
208
|
-
|
|
209
|
-
return lastDate || flags.startPolling;
|
|
229
|
+
// if the user is following logs, we want to return the last date we received
|
|
230
|
+
return lastDate || flags.startPolling || new Date().toISOString();
|
|
210
231
|
}
|
|
211
232
|
}
|
|
@@ -89,6 +89,12 @@ export declare class AppConfigFunction extends AppConfig {
|
|
|
89
89
|
isRootFunction(): boolean;
|
|
90
90
|
preparePostData(postData: any): Promise<any>;
|
|
91
91
|
}
|
|
92
|
+
export declare class AppConfigComponent extends AppConfig {
|
|
93
|
+
hasValues: boolean;
|
|
94
|
+
type: ConfigType;
|
|
95
|
+
isRootComponent(): boolean;
|
|
96
|
+
preparePostData(postData: any): Promise<any>;
|
|
97
|
+
}
|
|
92
98
|
export declare class AppConfigAsset extends AppConfigDefault {
|
|
93
99
|
hasValues: boolean;
|
|
94
100
|
type: ConfigType;
|
|
@@ -3,7 +3,7 @@ import isEmpty from 'lodash/isEmpty.js';
|
|
|
3
3
|
import { detectFilenameMime } from 'mime-detect';
|
|
4
4
|
import * as fs from 'node:fs';
|
|
5
5
|
import * as path from 'node:path';
|
|
6
|
-
import { bundleFunction } from '../bundle.js';
|
|
6
|
+
import { bundleFunction, bundleComponent } from '../bundle.js';
|
|
7
7
|
import { AllConfigPaths, ConfigType, filePathExists, hashFile, } from './index.js';
|
|
8
8
|
export class IgnoringFileError extends Error {
|
|
9
9
|
constructor(message) {
|
|
@@ -117,6 +117,9 @@ export class AppConfig {
|
|
|
117
117
|
case ConfigType.THEME: {
|
|
118
118
|
return new AppConfigTheme(attrs);
|
|
119
119
|
}
|
|
120
|
+
case ConfigType.COMPONENT: {
|
|
121
|
+
return new AppConfigComponent(attrs);
|
|
122
|
+
}
|
|
120
123
|
default: {
|
|
121
124
|
// the default type is file
|
|
122
125
|
const defaultConfig = new AppConfigDefault(attrs);
|
|
@@ -275,6 +278,43 @@ export class AppConfigFunction extends AppConfig {
|
|
|
275
278
|
return postData;
|
|
276
279
|
}
|
|
277
280
|
}
|
|
281
|
+
export class AppConfigComponent extends AppConfig {
|
|
282
|
+
hasValues = true;
|
|
283
|
+
type = ConfigType.COMPONENT;
|
|
284
|
+
isRootComponent() {
|
|
285
|
+
return (this.isRootConfig('components') &&
|
|
286
|
+
(this.filePath.endsWith('.jsx') || this.filePath.endsWith('.tsx')));
|
|
287
|
+
}
|
|
288
|
+
async preparePostData(postData) {
|
|
289
|
+
if (!this.isRootComponent()) {
|
|
290
|
+
return postData;
|
|
291
|
+
}
|
|
292
|
+
try {
|
|
293
|
+
// get file contents and if it's empty ignore
|
|
294
|
+
const fileData = this.prepareFileData();
|
|
295
|
+
if (!fileData) {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
const { code, config } = await bundleComponent(this.filePath);
|
|
299
|
+
if (!config) {
|
|
300
|
+
throw new IgnoringFileError('Component must export a `config` object.');
|
|
301
|
+
}
|
|
302
|
+
// Save the original file and the bundled version
|
|
303
|
+
postData.file = {
|
|
304
|
+
data: fileData,
|
|
305
|
+
};
|
|
306
|
+
postData.build_file = {
|
|
307
|
+
content_type: 'application/javascript',
|
|
308
|
+
data: code,
|
|
309
|
+
};
|
|
310
|
+
postData.values = config;
|
|
311
|
+
}
|
|
312
|
+
catch (error) {
|
|
313
|
+
throw new FunctionProcessingError(`Unable to compile component ${this.name}`, error);
|
|
314
|
+
}
|
|
315
|
+
return postData;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
278
318
|
// Assets do not get installed but saved as plain files
|
|
279
319
|
export class AppConfigAsset extends AppConfigDefault {
|
|
280
320
|
hasValues = false;
|
package/dist/lib/apps/index.d.ts
CHANGED
package/dist/lib/apps/index.js
CHANGED
|
@@ -26,6 +26,7 @@ export var ConfigType;
|
|
|
26
26
|
ConfigType["CONTENT"] = "content";
|
|
27
27
|
ConfigType["FILE"] = "file";
|
|
28
28
|
ConfigType["FRONTEND"] = "frontend";
|
|
29
|
+
ConfigType["COMPONENT"] = "component";
|
|
29
30
|
ConfigType["FUNCTION"] = "function";
|
|
30
31
|
ConfigType["MODEL"] = "model";
|
|
31
32
|
ConfigType["NOTIFICATION"] = "notification";
|
|
@@ -44,6 +45,7 @@ const ConfigTypeBatchOrder = [
|
|
|
44
45
|
ConfigType.WEBHOOK,
|
|
45
46
|
ConfigType.THEME,
|
|
46
47
|
ConfigType.FRONTEND,
|
|
48
|
+
ConfigType.COMPONENT,
|
|
47
49
|
ConfigType.FILE,
|
|
48
50
|
];
|
|
49
51
|
// All available configs
|
|
@@ -51,6 +53,7 @@ const AllConfigTypes = [
|
|
|
51
53
|
'ASSET',
|
|
52
54
|
'CONTENT',
|
|
53
55
|
'FRONTEND',
|
|
56
|
+
'COMPONENT',
|
|
54
57
|
'FUNCTION',
|
|
55
58
|
'MODEL',
|
|
56
59
|
'NOTIFICATION',
|
package/dist/lib/bundle.d.ts
CHANGED
package/dist/lib/bundle.js
CHANGED
|
@@ -36,6 +36,45 @@ export async function bundleFunction(filePath) {
|
|
|
36
36
|
throw new Error(`Unable to compile function ${filePath}: ${error.message}`);
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
+
export async function bundleComponent(filePath) {
|
|
40
|
+
try {
|
|
41
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
42
|
+
const stdinLoader = filePath.endsWith('.tsx') ? 'tsx' : 'jsx';
|
|
43
|
+
const buildResult = await esbuild.build({
|
|
44
|
+
stdin: {
|
|
45
|
+
contents: `
|
|
46
|
+
${content}
|
|
47
|
+
import { render, h } from "preact";
|
|
48
|
+
export const preact = { render, h };
|
|
49
|
+
`,
|
|
50
|
+
loader: stdinLoader,
|
|
51
|
+
resolveDir: path.dirname(filePath),
|
|
52
|
+
},
|
|
53
|
+
bundle: true,
|
|
54
|
+
minify: true,
|
|
55
|
+
platform: 'browser',
|
|
56
|
+
format: 'iife',
|
|
57
|
+
globalName: 'Component',
|
|
58
|
+
loader: {
|
|
59
|
+
'.ts': 'ts',
|
|
60
|
+
'.jsx': 'jsx',
|
|
61
|
+
'.tsx': 'tsx',
|
|
62
|
+
},
|
|
63
|
+
jsxFactory: 'h',
|
|
64
|
+
jsxFragment: 'Fragment',
|
|
65
|
+
write: false,
|
|
66
|
+
logLevel: 'silent',
|
|
67
|
+
});
|
|
68
|
+
const { outputFiles: [{ text: code }], } = buildResult;
|
|
69
|
+
// eslint-disable-next-line no-new-func
|
|
70
|
+
const evalFn = new Function(`${code}\nreturn { ...Component }`);
|
|
71
|
+
const { config } = evalFn();
|
|
72
|
+
return { code, config };
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
throw new Error(`Unable to compile component ${filePath}: ${error.message}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
39
78
|
function getSwellFunctionWrapper() {
|
|
40
79
|
const __filename = fileURLToPath(import.meta.url);
|
|
41
80
|
const __dirname = path.dirname(__filename);
|
|
@@ -80,7 +80,7 @@ export declare abstract class PushAppCommand extends RemoteAppCommand {
|
|
|
80
80
|
setWatchingFiles(): Promise<void>;
|
|
81
81
|
startProxyServer(port?: number): Promise<number>;
|
|
82
82
|
updateFrontendDeployment(currentStore: string, projectType: FrontendProjectType, deploymentUrl: string, deploymentHash: string): Promise<void>;
|
|
83
|
-
updateLocalProxy(proxyUrl: string, storefrontId?: string): Promise<void>;
|
|
83
|
+
updateLocalProxy(proxyUrl: string | null, storefrontId?: string): Promise<void>;
|
|
84
84
|
watchForChanges({ logChanges, onChange, syncAll, }?: {
|
|
85
85
|
logChanges?: boolean;
|
|
86
86
|
onChange?: (appConfig?: AppConfig, result?: any) => void;
|
package/dist/push-app-command.js
CHANGED
|
@@ -792,14 +792,14 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
792
792
|
let deploymentUrl;
|
|
793
793
|
let interactiveError = false;
|
|
794
794
|
let pagesProjectError = false;
|
|
795
|
+
let outputBuffer = '';
|
|
795
796
|
this.log(`\nDeploying to Cloudflare...\n`);
|
|
796
797
|
try {
|
|
797
798
|
await this.execFrontend(`npx wrangler deploy`, (string) => {
|
|
798
|
-
//
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
if (match
|
|
802
|
-
deploymentUrl = match[1];
|
|
799
|
+
// Accumulate output for URL parsing after command completes
|
|
800
|
+
outputBuffer += string;
|
|
801
|
+
// Suppress workers.dev URL from output (users should use swell domain)
|
|
802
|
+
if (string.match(/^\s*https:\/\/\S+\.workers\.dev\s*$/m)) {
|
|
803
803
|
return false;
|
|
804
804
|
}
|
|
805
805
|
// Check for Pages project error
|
|
@@ -834,6 +834,12 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
834
834
|
throw error;
|
|
835
835
|
}
|
|
836
836
|
}
|
|
837
|
+
// Parse deployment URL from accumulated output
|
|
838
|
+
// Match the workers.dev URL that appears on its own line after "Deployed ... triggers"
|
|
839
|
+
const urlMatch = outputBuffer.match(/^\s*(https:\/\/\S+\.workers\.dev)\s*$/m);
|
|
840
|
+
if (urlMatch && urlMatch[1]) {
|
|
841
|
+
deploymentUrl = urlMatch[1];
|
|
842
|
+
}
|
|
837
843
|
if (!deploymentUrl) {
|
|
838
844
|
this.error('Unable to retrieve deployment URL.');
|
|
839
845
|
}
|
package/oclif.manifest.json
CHANGED
|
@@ -190,7 +190,7 @@
|
|
|
190
190
|
"char": "p",
|
|
191
191
|
"description": "note that this flag will take more space in the terminal and require more time to load",
|
|
192
192
|
"name": "pretty",
|
|
193
|
-
"summary": "pretty print json data",
|
|
193
|
+
"summary": "pretty print json data in table output",
|
|
194
194
|
"allowNo": false,
|
|
195
195
|
"type": "boolean"
|
|
196
196
|
},
|
|
@@ -999,7 +999,7 @@
|
|
|
999
999
|
"name": "targetPath"
|
|
1000
1000
|
}
|
|
1001
1001
|
},
|
|
1002
|
-
"description": "Pull all app files, a specific file, or a specific configuration\ntype from an app in your store's test environment to your local machine.\n\nIf APPID is not specified, you will be prompted with a list of apps to choose from.\n\nApp file directories:\nassets/\ncontent/\nfrontend/\nfunctions/\nmodels/\nnotifications/\nsettings/\ntheme/\nwebhooks/\nfrontend/",
|
|
1002
|
+
"description": "Pull all app files, a specific file, or a specific configuration\ntype from an app in your store's test environment to your local machine.\n\nIf APPID is not specified, you will be prompted with a list of apps to choose from.\n\nApp file directories:\nassets/\ncontent/\nfrontend/\ncomponents/\nfunctions/\nmodels/\nnotifications/\nsettings/\ntheme/\nwebhooks/\nfrontend/",
|
|
1003
1003
|
"examples": [
|
|
1004
1004
|
"swell app pull",
|
|
1005
1005
|
"swell app pull example_app",
|
|
@@ -1048,7 +1048,7 @@
|
|
|
1048
1048
|
"name": "file"
|
|
1049
1049
|
}
|
|
1050
1050
|
},
|
|
1051
|
-
"description": "Push all app files, a specific file, or a specific configuration\ntype to an app in your store's test environment.\n\nIf the app does not exist, it will be created and its global ID saved to a .swellrc file.\n\n- If no file is specified, all configuration files will be pushed to the store.\n This includes the app icon (assets/icon.png) and swell.json.\n- If a file is specified, only that file will be pushed to the store.\n- If a directory is specified, only files in that directory will be pushed.\n\nApp file directories:\nassets/\ncontent/\nfrontend/\nfunctions/\nmodels/\nnotifications/\nsettings/\ntheme/\nwebhooks/",
|
|
1051
|
+
"description": "Push all app files, a specific file, or a specific configuration\ntype to an app in your store's test environment.\n\nIf the app does not exist, it will be created and its global ID saved to a .swellrc file.\n\n- If no file is specified, all configuration files will be pushed to the store.\n This includes the app icon (assets/icon.png) and swell.json.\n- If a file is specified, only that file will be pushed to the store.\n- If a directory is specified, only files in that directory will be pushed.\n\nApp file directories:\nassets/\ncontent/\nfrontend/\ncomponents/\nfunctions/\nmodels/\nnotifications/\nsettings/\ntheme/\nwebhooks/",
|
|
1052
1052
|
"examples": [
|
|
1053
1053
|
"swell app push",
|
|
1054
1054
|
"swell app push content",
|
|
@@ -2875,5 +2875,5 @@
|
|
|
2875
2875
|
]
|
|
2876
2876
|
}
|
|
2877
2877
|
},
|
|
2878
|
-
"version": "2.3.
|
|
2878
|
+
"version": "2.3.3"
|
|
2879
2879
|
}
|