@swell/cli 2.3.2 → 2.3.4
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.js +3 -1
- package/dist/commands/inspect/models.d.ts +1 -1
- package/dist/commands/inspect/models.js +50 -11
- package/dist/commands/logs.d.ts +0 -1
- package/dist/commands/logs.js +38 -17
- package/dist/lib/api.js +1 -0
- 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.js +11 -5
- package/oclif.manifest.json +5 -4
- package/package.json +1 -1
package/dist/commands/app/dev.js
CHANGED
|
@@ -297,6 +297,8 @@ ENVIRONMENT = "development"
|
|
|
297
297
|
// Get all functions in this app
|
|
298
298
|
const functions = await this.getAppFunctions();
|
|
299
299
|
if (functions.length === 0) {
|
|
300
|
+
// Create routing server to proxy requests to frontend even without functions
|
|
301
|
+
await this.createFunctionRouter(serverPort);
|
|
300
302
|
spinner.stop();
|
|
301
303
|
return;
|
|
302
304
|
}
|
|
@@ -308,7 +310,7 @@ ENVIRONMENT = "development"
|
|
|
308
310
|
this.watchForChanges({
|
|
309
311
|
onChange: this.onChangeFunctionWatcher.bind(this),
|
|
310
312
|
});
|
|
311
|
-
// Create
|
|
313
|
+
// Create routing server after function servers are ready
|
|
312
314
|
await this.createFunctionRouter(serverPort);
|
|
313
315
|
spinner.succeed(`App function server running on port ${serverPort}\n`);
|
|
314
316
|
this.log(`${style.appConfigName(`Functions:`)}`);
|
|
@@ -16,7 +16,7 @@ export default class Models extends SwellCommand {
|
|
|
16
16
|
private showStandardModels;
|
|
17
17
|
private showAppModels;
|
|
18
18
|
private showModels;
|
|
19
|
-
private
|
|
19
|
+
private getModelPath;
|
|
20
20
|
private getCurrentAppSlugId;
|
|
21
21
|
private getAppSlugId;
|
|
22
22
|
private showModelDetail;
|
|
@@ -31,6 +31,7 @@ With a collection path, it retrieves the model for that specific collection in J
|
|
|
31
31
|
static examples = [
|
|
32
32
|
'swell inspect models',
|
|
33
33
|
'swell inspect models /products',
|
|
34
|
+
'swell inspect models /content/blogs',
|
|
34
35
|
'swell inspect models /apps/myapp/orders',
|
|
35
36
|
'swell inspect models /orders --live',
|
|
36
37
|
];
|
|
@@ -69,7 +70,6 @@ With a collection path, it retrieves the model for that specific collection in J
|
|
|
69
70
|
adminPath: '/data/:models',
|
|
70
71
|
}, {
|
|
71
72
|
query: {
|
|
72
|
-
content_id: { $exists: false },
|
|
73
73
|
deprecated: { $ne: true },
|
|
74
74
|
development: { $ne: true },
|
|
75
75
|
abstract: { $ne: true },
|
|
@@ -102,6 +102,7 @@ With a collection path, it retrieves the model for that specific collection in J
|
|
|
102
102
|
this.log();
|
|
103
103
|
this.log('Examples:');
|
|
104
104
|
this.log(' swell inspect models /products');
|
|
105
|
+
this.log(' swell inspect models /content/blogs');
|
|
105
106
|
this.log(' swell inspect models /apps/myapp/orders');
|
|
106
107
|
}
|
|
107
108
|
showStandardModels(models) {
|
|
@@ -123,20 +124,34 @@ With a collection path, it retrieves the model for that specific collection in J
|
|
|
123
124
|
showModels(models, label, options) {
|
|
124
125
|
this.log(label);
|
|
125
126
|
this.log();
|
|
126
|
-
const sortedModels = [...models].sort((a, b) =>
|
|
127
|
+
const sortedModels = [...models].sort((a, b) => {
|
|
128
|
+
const pathA = this.getModelPath(a, options?.pathPrefix);
|
|
129
|
+
const pathB = this.getModelPath(b, options?.pathPrefix);
|
|
130
|
+
return pathA.localeCompare(pathB);
|
|
131
|
+
});
|
|
127
132
|
for (const model of sortedModels) {
|
|
128
|
-
this.
|
|
133
|
+
const modelPath = this.getModelPath(model, options?.pathPrefix);
|
|
134
|
+
this.log(` ${modelPath}`);
|
|
129
135
|
const sortedSubModels = Object.values(model.fields)
|
|
130
136
|
.filter((field) => field.type === 'collection')
|
|
131
137
|
.map((field) => field.name)
|
|
132
138
|
.sort((a, b) => a.localeCompare(b));
|
|
133
139
|
for (const sub of sortedSubModels) {
|
|
134
|
-
|
|
140
|
+
const subPath = options?.pathPrefix
|
|
141
|
+
? `${options.pathPrefix}/${sub}`
|
|
142
|
+
: `/${sub}`;
|
|
143
|
+
this.log(` ${subPath}`);
|
|
135
144
|
}
|
|
136
145
|
}
|
|
137
146
|
}
|
|
138
|
-
|
|
139
|
-
|
|
147
|
+
getModelPath(model, pathPrefix) {
|
|
148
|
+
if (pathPrefix) {
|
|
149
|
+
return `${pathPrefix}/${model.name}`;
|
|
150
|
+
}
|
|
151
|
+
if (model.namespace) {
|
|
152
|
+
return `/${model.namespace}/${model.name}`;
|
|
153
|
+
}
|
|
154
|
+
return `/${model.name}`;
|
|
140
155
|
}
|
|
141
156
|
async getCurrentAppSlugId() {
|
|
142
157
|
const hasAppContext = fs.existsSync('swell.json');
|
|
@@ -155,15 +170,32 @@ With a collection path, it retrieves the model for that specific collection in J
|
|
|
155
170
|
return app.public_id || app.private_id.replace(/^_/, '');
|
|
156
171
|
}
|
|
157
172
|
async showModelDetail(path) {
|
|
158
|
-
const [modelPath, subModelKey] = await this.resolveModelPath(path);
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
173
|
+
const [modelPath, subModelKey, namespace] = await this.resolveModelPath(path);
|
|
174
|
+
let model = null;
|
|
175
|
+
if (namespace) {
|
|
176
|
+
// For namespaced models, fetch by name and namespace filter
|
|
177
|
+
// since the API may return a different model with the same name
|
|
178
|
+
const modelName = modelPath.slice(1); // Remove leading /
|
|
179
|
+
const { results } = await this.api.get({ adminPath: '/data/:models' }, {
|
|
180
|
+
query: {
|
|
181
|
+
name: modelName,
|
|
182
|
+
namespace,
|
|
183
|
+
$app: true,
|
|
184
|
+
},
|
|
185
|
+
});
|
|
186
|
+
model = results?.[0] ?? null;
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
model = await this.api.get({
|
|
190
|
+
adminPath: `/data/:models${modelPath}`,
|
|
191
|
+
}, { query: { $app: true } });
|
|
192
|
+
}
|
|
162
193
|
if (!model) {
|
|
163
194
|
this.throwModelNotFound(path);
|
|
164
195
|
}
|
|
165
196
|
if (!subModelKey) {
|
|
166
|
-
|
|
197
|
+
this.showModel(model);
|
|
198
|
+
return;
|
|
167
199
|
}
|
|
168
200
|
const subModel = model.fields[subModelKey];
|
|
169
201
|
if (!subModel) {
|
|
@@ -176,6 +208,13 @@ With a collection path, it retrieves the model for that specific collection in J
|
|
|
176
208
|
return this.resolveAppModelPath(path);
|
|
177
209
|
}
|
|
178
210
|
const [modelPath, subModelKey] = path.split(':');
|
|
211
|
+
// Check if this is a namespaced path (e.g., /content/blogs)
|
|
212
|
+
const pathParts = modelPath.slice(1).split('/');
|
|
213
|
+
if (pathParts.length === 2) {
|
|
214
|
+
const [namespace, modelName] = pathParts;
|
|
215
|
+
// Return model name and namespace for filtering
|
|
216
|
+
return [`/${modelName}`, subModelKey, namespace];
|
|
217
|
+
}
|
|
179
218
|
return [modelPath, subModelKey];
|
|
180
219
|
}
|
|
181
220
|
async resolveAppModelPath(path) {
|
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
|
}
|
package/dist/lib/api.js
CHANGED
|
@@ -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);
|
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",
|
|
@@ -2326,6 +2326,7 @@
|
|
|
2326
2326
|
"examples": [
|
|
2327
2327
|
"swell inspect models",
|
|
2328
2328
|
"swell inspect models /products",
|
|
2329
|
+
"swell inspect models /content/blogs",
|
|
2329
2330
|
"swell inspect models /apps/myapp/orders",
|
|
2330
2331
|
"swell inspect models /orders --live"
|
|
2331
2332
|
],
|
|
@@ -2875,5 +2876,5 @@
|
|
|
2875
2876
|
]
|
|
2876
2877
|
}
|
|
2877
2878
|
},
|
|
2878
|
-
"version": "2.3.
|
|
2879
|
+
"version": "2.3.4"
|
|
2879
2880
|
}
|