@swell/cli 2.6.0 → 2.7.0
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/frontend/dev.js +18 -0
- package/dist/commands/inspect/content.d.ts +25 -14
- package/dist/commands/inspect/content.js +34 -144
- package/dist/commands/inspect/functions.d.ts +48 -0
- package/dist/commands/inspect/functions.js +83 -0
- package/dist/commands/inspect/index.js +8 -7
- package/dist/commands/inspect/models.d.ts +17 -2
- package/dist/commands/inspect/models.js +114 -47
- package/dist/commands/inspect/notifications.d.ts +31 -0
- package/dist/commands/inspect/notifications.js +125 -0
- package/dist/commands/inspect/settings.d.ts +28 -0
- package/dist/commands/inspect/settings.js +82 -0
- package/dist/commands/inspect/webhooks.d.ts +34 -0
- package/dist/commands/inspect/webhooks.js +61 -0
- package/dist/create-app-command.d.ts +7 -0
- package/dist/create-app-command.js +66 -3
- package/dist/inspect-resource-command.d.ts +91 -0
- package/dist/inspect-resource-command.js +232 -0
- package/dist/lib/apps/index.d.ts +2 -1
- package/dist/lib/apps/index.js +43 -6
- package/dist/lib/apps/inspect-scope.d.ts +58 -0
- package/dist/lib/apps/inspect-scope.js +60 -0
- package/dist/lib/apps/object-id.d.ts +7 -0
- package/dist/lib/apps/object-id.js +9 -0
- package/dist/lib/apps/paths.js +8 -1
- package/dist/lib/apps/resolve.d.ts +16 -0
- package/dist/lib/apps/resolve.js +39 -0
- package/dist/lib/apps/slug.d.ts +29 -0
- package/dist/lib/apps/slug.js +12 -0
- package/dist/lib/inspect/content.d.ts +39 -0
- package/dist/lib/inspect/content.js +76 -0
- package/dist/lib/inspect/notifications.d.ts +115 -0
- package/dist/lib/inspect/notifications.js +173 -0
- package/dist/lib/inspect/settings.d.ts +61 -0
- package/dist/lib/inspect/settings.js +56 -0
- package/dist/lib/inspect/table.d.ts +29 -0
- package/dist/lib/inspect/table.js +61 -0
- package/dist/push-app-command.js +3 -2
- package/dist/swell-api-command.d.ts +0 -4
- package/dist/swell-api-command.js +2 -18
- package/oclif.manifest.json +328 -35
- package/package.json +1 -1
|
@@ -182,6 +182,24 @@ export default class AppFrontendDev extends PushAppCommand {
|
|
|
182
182
|
}
|
|
183
183
|
break;
|
|
184
184
|
}
|
|
185
|
+
case 'react':
|
|
186
|
+
case 'react-storefront': {
|
|
187
|
+
// Vite emits the Local URL as its ready signal — no separate
|
|
188
|
+
// detector needed.
|
|
189
|
+
if (/➜\s+local:\s+http:\/\//i.test(string) ||
|
|
190
|
+
/➜\s+network:/i.test(string)) {
|
|
191
|
+
if (!serverReadyDetected) {
|
|
192
|
+
serverReadyDetected = true;
|
|
193
|
+
this.log(`Started ${projectType.name} dev server on port ${serverPort}.\n`);
|
|
194
|
+
setTimeout(() => this.logLocalPreviewUrl(), 100);
|
|
195
|
+
if (!isAppDev) {
|
|
196
|
+
this.watchForChanges();
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
185
203
|
case 'nuxt': {
|
|
186
204
|
// 2. URL FILTER: Hide localhost/network URLs (confusing - users should use Swell tunnel)
|
|
187
205
|
if (/➜ local:\s+http:\/\//i.test(string) ||
|
|
@@ -1,25 +1,36 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { InspectResourceCommand, InspectResourceCommandParsed } from '../../inspect-resource-command.js';
|
|
2
|
+
import { InspectScope } from '../../lib/apps/inspect-scope.js';
|
|
3
|
+
import { GroupInfo } from '../../lib/inspect/table.js';
|
|
4
|
+
interface ContentView {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
app_id?: string;
|
|
8
|
+
collection?: string;
|
|
9
|
+
fields?: any[];
|
|
10
|
+
source_id?: string;
|
|
11
|
+
source_type?: string;
|
|
12
|
+
views?: any[];
|
|
13
|
+
}
|
|
14
|
+
export default class Content extends InspectResourceCommand {
|
|
3
15
|
static summary: string;
|
|
4
16
|
static description: string;
|
|
5
17
|
static args: {
|
|
6
|
-
|
|
18
|
+
identifier: import("@oclif/core/lib/interfaces/parser.js").Arg<string | undefined, Record<string, unknown>>;
|
|
7
19
|
};
|
|
8
20
|
static flags: {
|
|
21
|
+
app: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
9
22
|
live: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
23
|
+
json: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
10
24
|
yes: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
11
25
|
};
|
|
12
26
|
static examples: string[];
|
|
27
|
+
protected resourceLabel: string;
|
|
28
|
+
protected resourceLabelSingular: string;
|
|
29
|
+
protected adminPath: string;
|
|
30
|
+
protected commandName: string;
|
|
13
31
|
run(): Promise<void>;
|
|
14
|
-
protected
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
private showContentView;
|
|
18
|
-
private resolveContentId;
|
|
19
|
-
private showContentDetail;
|
|
20
|
-
private reverseResolveContentId;
|
|
21
|
-
private getAppBySlug;
|
|
22
|
-
private getAppSlugId;
|
|
23
|
-
private throwContentNotFound;
|
|
24
|
-
private showContent;
|
|
32
|
+
protected keyFor(record: ContentView, appSlugById: Record<string, string>): string;
|
|
33
|
+
protected groupForRecord(record: ContentView, appSlugById: Record<string, string>): GroupInfo;
|
|
34
|
+
protected showDetail(identifier: string, scope: InspectScope, flags: InspectResourceCommandParsed['flags']): Promise<void>;
|
|
25
35
|
}
|
|
36
|
+
export {};
|
|
@@ -1,159 +1,49 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
static
|
|
7
|
-
static description = `
|
|
8
|
-
View content view extensions available in your Swell store.
|
|
1
|
+
import { InspectResourceCommand, inspectResourceBaseArgs, inspectResourceBaseFlags, } from '../../inspect-resource-command.js';
|
|
2
|
+
import { resolveAppId } from '../../lib/apps/resolve.js';
|
|
3
|
+
import { groupContentRecord, resolveContentKey, reverseResolveContentId, } from '../../lib/inspect/content.js';
|
|
4
|
+
export default class Content extends InspectResourceCommand {
|
|
5
|
+
static summary = 'App and platform content views.';
|
|
6
|
+
static description = `Lists content view extensions across all apps plus platform 'custom' sources, grouped by owner. Pass --app=<slug> or --app=. (current swell.json) to scope.
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
Pass an identifier to view a single record as JSON.
|
|
9
|
+
|
|
10
|
+
Identifier forms:
|
|
11
|
+
app.<app>.<name> — app-owned view (list column 1)
|
|
12
|
+
custom.<source>.<name> — platform custom view (e.g. custom.admin.products)
|
|
13
|
+
<name> — requires --app= scope
|
|
12
14
|
`;
|
|
13
|
-
static args = {
|
|
14
|
-
|
|
15
|
-
description: 'Optional content view ID. Example: custom.admin.products, app.myapp.products',
|
|
16
|
-
required: false,
|
|
17
|
-
}),
|
|
18
|
-
};
|
|
19
|
-
static flags = {
|
|
20
|
-
live: Flags.boolean({
|
|
21
|
-
description: 'Use the live environment instead of test (default: test).',
|
|
22
|
-
default: false,
|
|
23
|
-
}),
|
|
24
|
-
yes: Flags.boolean({
|
|
25
|
-
char: 'y',
|
|
26
|
-
description: 'Accept all prompts automatically (for agent compatibility; no functional effect).',
|
|
27
|
-
default: false,
|
|
28
|
-
}),
|
|
29
|
-
};
|
|
15
|
+
static args = { ...inspectResourceBaseArgs };
|
|
16
|
+
static flags = { ...inspectResourceBaseFlags };
|
|
30
17
|
static examples = [
|
|
31
18
|
'swell inspect content',
|
|
32
|
-
'swell inspect content
|
|
19
|
+
'swell inspect content --app=my-app',
|
|
33
20
|
'swell inspect content app.honest_reviews.reviews',
|
|
34
|
-
'swell inspect content
|
|
21
|
+
'swell inspect content custom.admin.products',
|
|
22
|
+
'swell inspect content reviews --app=honest_reviews',
|
|
23
|
+
'swell inspect content --live',
|
|
35
24
|
];
|
|
25
|
+
resourceLabel = 'Content views';
|
|
26
|
+
resourceLabelSingular = 'content view';
|
|
27
|
+
adminPath = '/data/:content';
|
|
28
|
+
commandName = 'content';
|
|
36
29
|
async run() {
|
|
37
30
|
const { args, flags } = await this.parse(Content);
|
|
38
|
-
|
|
39
|
-
const { live } = flags;
|
|
40
|
-
if (!live) {
|
|
41
|
-
await this.api.setEnv('test');
|
|
42
|
-
}
|
|
43
|
-
// Detail mode: show configuration for a specific content view
|
|
44
|
-
if (contentId) {
|
|
45
|
-
await this.showContentDetail(contentId);
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
const store = localConfig.getDefaultStore();
|
|
49
|
-
// List mode: show all content views
|
|
50
|
-
await this.listContent(store, live);
|
|
51
|
-
}
|
|
52
|
-
async catch(error) {
|
|
53
|
-
if (error instanceof FetchError) {
|
|
54
|
-
const message = `Could not connect to Swell API. Please try again later: ${error.message}`;
|
|
55
|
-
return this.error(message, { exit: 2, code: error.code });
|
|
56
|
-
}
|
|
57
|
-
return this.error(error.message, { exit: 1 });
|
|
58
|
-
}
|
|
59
|
-
async listContent(store, live) {
|
|
60
|
-
const { results: apps } = await this.api.get({
|
|
61
|
-
adminPath: '/apps',
|
|
62
|
-
});
|
|
63
|
-
const appsById = Object.fromEntries(apps.map((app) => [app.id, app]));
|
|
64
|
-
const { results: contentViews } = await this.api.getAll({
|
|
65
|
-
adminPath: '/data/:content',
|
|
66
|
-
});
|
|
67
|
-
// Sort by resolved ID in reverse order (custom.* first)
|
|
68
|
-
const sortedContentViews = [...contentViews].sort((a, b) => {
|
|
69
|
-
const resolvedA = this.resolveContentId(a, appsById);
|
|
70
|
-
const resolvedB = this.resolveContentId(b, appsById);
|
|
71
|
-
return resolvedB.localeCompare(resolvedA);
|
|
72
|
-
});
|
|
73
|
-
this.log(`Content views extensions available in '${store}' ${live ? '[live]' : '[test]'}:`);
|
|
74
|
-
this.log();
|
|
75
|
-
this.showContentViews(sortedContentViews, appsById);
|
|
76
|
-
// Show next step hints
|
|
77
|
-
this.log();
|
|
78
|
-
this.log('Examples:');
|
|
79
|
-
this.log(' swell inspect content custom.admin.products');
|
|
80
|
-
this.log(' swell inspect content app.honest_reviews.accounts');
|
|
81
|
-
}
|
|
82
|
-
showContentViews(contentViews, appsById) {
|
|
83
|
-
const maxNameWidth = Math.max(...contentViews.map((cv) => cv.name.length), 15);
|
|
84
|
-
for (const cv of contentViews) {
|
|
85
|
-
this.showContentView(cv, maxNameWidth, appsById);
|
|
86
|
-
}
|
|
31
|
+
await this.runInspect({ args, flags });
|
|
87
32
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
const paddedName = contentView.name.padEnd(nameWidth + 2);
|
|
91
|
-
this.log(`${paddedName}${resolvedId}`);
|
|
33
|
+
keyFor(record, appSlugById) {
|
|
34
|
+
return resolveContentKey(record.id, appSlugById);
|
|
92
35
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
// Parse ID: app.{appId}.{name} or custom.{source}.{name}
|
|
96
|
-
const match = id.match(/^(app|custom)\.([^.]+)\.(.+)$/);
|
|
97
|
-
if (!match)
|
|
98
|
-
return id; // fallback to original
|
|
99
|
-
const [, type, identifier] = match;
|
|
100
|
-
if (type === 'custom') {
|
|
101
|
-
return id; // custom IDs are already resolved
|
|
102
|
-
}
|
|
103
|
-
// type === 'app': resolve app ID to slug
|
|
104
|
-
const appId = identifier;
|
|
105
|
-
const app = appsById[appId];
|
|
106
|
-
if (!app) {
|
|
107
|
-
return id; // fallback if app not found
|
|
108
|
-
}
|
|
109
|
-
const appSlug = this.getAppSlugId(app);
|
|
110
|
-
return `app.${appSlug}.${name}`;
|
|
36
|
+
groupForRecord(record, appSlugById) {
|
|
37
|
+
return groupContentRecord(record, appSlugById);
|
|
111
38
|
}
|
|
112
|
-
async
|
|
113
|
-
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
const content = await this.api.get({
|
|
117
|
-
adminPath: `/data/:content/${unresolvedId}`,
|
|
39
|
+
async showDetail(identifier, scope, flags) {
|
|
40
|
+
const unresolved = await reverseResolveContentId(identifier, scope, (slug) => resolveAppId(this.api, slug));
|
|
41
|
+
const record = await this.api.get({
|
|
42
|
+
adminPath: `${this.adminPath}/${unresolved}`,
|
|
118
43
|
});
|
|
119
|
-
if (!
|
|
120
|
-
this.
|
|
121
|
-
}
|
|
122
|
-
this.showContent(content);
|
|
123
|
-
}
|
|
124
|
-
async reverseResolveContentId(resolvedId) {
|
|
125
|
-
// Parse ID: app.{slug}.{name} or custom.{source}.{name}
|
|
126
|
-
const match = resolvedId.match(/^(app|custom)\.([^.]+)\.(.+)$/);
|
|
127
|
-
if (!match) {
|
|
128
|
-
throw new Error(`Invalid content ID format: ${resolvedId}`);
|
|
129
|
-
}
|
|
130
|
-
const [, type, identifier, name] = match;
|
|
131
|
-
if (type === 'custom') {
|
|
132
|
-
return resolvedId; // custom IDs don't need reverse resolution
|
|
44
|
+
if (!record) {
|
|
45
|
+
this.throwNotFound(identifier);
|
|
133
46
|
}
|
|
134
|
-
|
|
135
|
-
if (/^[\da-f]{24}$/.test(identifier)) {
|
|
136
|
-
return resolvedId; // already unresolved format
|
|
137
|
-
}
|
|
138
|
-
// type === 'app': resolve slug to app ID
|
|
139
|
-
const appSlug = identifier;
|
|
140
|
-
const app = await this.getAppBySlug(appSlug);
|
|
141
|
-
return `app.${app.id}.${name}`;
|
|
142
|
-
}
|
|
143
|
-
async getAppBySlug(slug) {
|
|
144
|
-
const app = await this.api.get({ adminPath: `/apps/${slug}` });
|
|
145
|
-
if (!app) {
|
|
146
|
-
throw new Error(`App '${slug}' not found.\nList available content: swell inspect content`);
|
|
147
|
-
}
|
|
148
|
-
return app;
|
|
149
|
-
}
|
|
150
|
-
getAppSlugId(app) {
|
|
151
|
-
return app.public_id || app.private_id.replace(/^_/, '');
|
|
152
|
-
}
|
|
153
|
-
throwContentNotFound(id) {
|
|
154
|
-
throw new Error(`No content view found for '${id}'.\nList available content: swell inspect content`);
|
|
155
|
-
}
|
|
156
|
-
showContent(content) {
|
|
157
|
-
this.log(JSON.stringify(content, null, 2));
|
|
47
|
+
this.emitDetail(record, flags);
|
|
158
48
|
}
|
|
159
49
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { InspectResourceCommand } from '../../inspect-resource-command.js';
|
|
2
|
+
interface FunctionRecord {
|
|
3
|
+
id?: string;
|
|
4
|
+
name?: string;
|
|
5
|
+
enabled?: boolean;
|
|
6
|
+
cron?: {
|
|
7
|
+
schedule?: string;
|
|
8
|
+
};
|
|
9
|
+
route?: {
|
|
10
|
+
headers?: string[];
|
|
11
|
+
methods?: string[];
|
|
12
|
+
public?: boolean;
|
|
13
|
+
};
|
|
14
|
+
model?: {
|
|
15
|
+
events?: string[];
|
|
16
|
+
};
|
|
17
|
+
date_cron_scheduled?: string;
|
|
18
|
+
date_final_attempt?: string;
|
|
19
|
+
app_id?: string;
|
|
20
|
+
}
|
|
21
|
+
export default class Functions extends InspectResourceCommand {
|
|
22
|
+
static summary: string;
|
|
23
|
+
static description: string;
|
|
24
|
+
static args: {
|
|
25
|
+
identifier: import("@oclif/core/lib/interfaces/parser.js").Arg<string | undefined, Record<string, unknown>>;
|
|
26
|
+
};
|
|
27
|
+
static flags: {
|
|
28
|
+
app: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
29
|
+
live: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
30
|
+
json: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
31
|
+
yes: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
32
|
+
};
|
|
33
|
+
static examples: string[];
|
|
34
|
+
protected resourceLabel: string;
|
|
35
|
+
protected resourceLabelSingular: string;
|
|
36
|
+
protected adminPath: string;
|
|
37
|
+
protected commandName: string;
|
|
38
|
+
run(): Promise<void>;
|
|
39
|
+
protected metaFor(r: FunctionRecord): string | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Model-triggered functions emit `/events:webhooks` rows on each invocation.
|
|
42
|
+
* Route and cron functions do not — pointing the agent at an empty query
|
|
43
|
+
* would teach them their function isn't running. The logs hint always
|
|
44
|
+
* applies as long as we have a function name.
|
|
45
|
+
*/
|
|
46
|
+
protected hints(record: FunctionRecord): string[];
|
|
47
|
+
}
|
|
48
|
+
export {};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { InspectResourceCommand, inspectResourceBaseArgs, inspectResourceBaseFlags, } from '../../inspect-resource-command.js';
|
|
2
|
+
function deriveTrigger(r) {
|
|
3
|
+
if (r.cron?.schedule) {
|
|
4
|
+
return `cron (${r.cron.schedule})`;
|
|
5
|
+
}
|
|
6
|
+
if (r.model?.events?.length) {
|
|
7
|
+
const n = r.model.events.length;
|
|
8
|
+
return `model (${n} event${n === 1 ? '' : 's'})`;
|
|
9
|
+
}
|
|
10
|
+
if (r.route) {
|
|
11
|
+
const { methods } = r.route;
|
|
12
|
+
if (!methods?.length)
|
|
13
|
+
return 'route';
|
|
14
|
+
return methods.length <= 2
|
|
15
|
+
? `route (${methods.join(',')})`
|
|
16
|
+
: `route (${methods.length} methods)`;
|
|
17
|
+
}
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
export default class Functions extends InspectResourceCommand {
|
|
21
|
+
static summary = 'Functions with scheduling and trigger state.';
|
|
22
|
+
static description = `Lists functions across all apps, grouped by app. Pass --app=<slug> or --app=. (current swell.json) to scope.
|
|
23
|
+
|
|
24
|
+
List output: paste-back key + status (disabled, trigger, next cron run, last failure).
|
|
25
|
+
|
|
26
|
+
Pass an identifier to view a single record as JSON.
|
|
27
|
+
|
|
28
|
+
Identifier forms:
|
|
29
|
+
app.<app>.<name> — full paste-back key (list column 1)
|
|
30
|
+
<name> — requires --app= scope
|
|
31
|
+
<24-char id> — any scope
|
|
32
|
+
`;
|
|
33
|
+
static args = { ...inspectResourceBaseArgs };
|
|
34
|
+
static flags = { ...inspectResourceBaseFlags };
|
|
35
|
+
static examples = [
|
|
36
|
+
'swell inspect functions',
|
|
37
|
+
'swell inspect functions --app=my-app',
|
|
38
|
+
'swell inspect functions app.my-app.payment-sync',
|
|
39
|
+
'swell inspect functions payment-sync --app=my-app',
|
|
40
|
+
'swell inspect functions --live',
|
|
41
|
+
];
|
|
42
|
+
resourceLabel = 'Functions';
|
|
43
|
+
resourceLabelSingular = 'function';
|
|
44
|
+
adminPath = '/data/:functions';
|
|
45
|
+
commandName = 'functions';
|
|
46
|
+
async run() {
|
|
47
|
+
const { args, flags } = await this.parse(Functions);
|
|
48
|
+
await this.runInspect({ args, flags });
|
|
49
|
+
}
|
|
50
|
+
metaFor(r) {
|
|
51
|
+
const parts = [];
|
|
52
|
+
if (!r.enabled) {
|
|
53
|
+
parts.push('disabled');
|
|
54
|
+
}
|
|
55
|
+
const trigger = deriveTrigger(r);
|
|
56
|
+
if (trigger) {
|
|
57
|
+
parts.push(trigger);
|
|
58
|
+
}
|
|
59
|
+
if (r.date_cron_scheduled) {
|
|
60
|
+
parts.push(`next ${r.date_cron_scheduled}`);
|
|
61
|
+
}
|
|
62
|
+
if (r.date_final_attempt) {
|
|
63
|
+
parts.push(`last fail ${r.date_final_attempt}`);
|
|
64
|
+
}
|
|
65
|
+
return parts.length > 0 ? parts.join(' · ') : undefined;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Model-triggered functions emit `/events:webhooks` rows on each invocation.
|
|
69
|
+
* Route and cron functions do not — pointing the agent at an empty query
|
|
70
|
+
* would teach them their function isn't running. The logs hint always
|
|
71
|
+
* applies as long as we have a function name.
|
|
72
|
+
*/
|
|
73
|
+
hints(record) {
|
|
74
|
+
const lines = [];
|
|
75
|
+
if (record.model?.events?.length && record.id) {
|
|
76
|
+
lines.push(`swell api get '/events:webhooks?where[function_id]=${record.id}&limit=10'`);
|
|
77
|
+
}
|
|
78
|
+
if (record.name) {
|
|
79
|
+
lines.push(`swell logs --type function -s '${record.name}'`);
|
|
80
|
+
}
|
|
81
|
+
return lines;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { Command } from '@oclif/core';
|
|
2
2
|
export default class Inspect extends Command {
|
|
3
3
|
static summary = 'Inspect deployed artifacts in your store.';
|
|
4
|
-
static description = `
|
|
5
|
-
|
|
6
|
-
Inspect models, content views, and other deployed artifacts in your Swell store.`;
|
|
4
|
+
static description = `Subcommands list globally and group by app. Pass --app=<slug> or --app=. (current swell.json) to scope. Pass an identifier to print the full record as JSON, followed by a "Next steps" footer of related commands. Use --json to omit the footer for piping.
|
|
5
|
+
`;
|
|
7
6
|
static examples = [
|
|
8
|
-
'swell inspect models',
|
|
9
7
|
'swell inspect models /products',
|
|
10
|
-
'swell inspect
|
|
8
|
+
'swell inspect content app.honest_reviews.reviews',
|
|
9
|
+
'swell inspect webhooks --app=my-app',
|
|
10
|
+
'swell inspect functions app.my-app.payment-sync',
|
|
11
|
+
'swell inspect notifications com.orders.receipt.v2',
|
|
12
|
+
'swell inspect settings app.my-app',
|
|
11
13
|
];
|
|
12
14
|
async run() {
|
|
13
|
-
this.log('
|
|
14
|
-
this.log('Run "swell inspect --help" for more information.');
|
|
15
|
+
this.log('Run "swell inspect --help" to see available subcommands.');
|
|
15
16
|
}
|
|
16
17
|
}
|
|
@@ -6,7 +6,9 @@ export default class Models extends SwellCommand {
|
|
|
6
6
|
'collection-path': import("@oclif/core/lib/interfaces/parser.js").Arg<string | undefined, Record<string, unknown>>;
|
|
7
7
|
};
|
|
8
8
|
static flags: {
|
|
9
|
+
app: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
9
10
|
live: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
11
|
+
json: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
10
12
|
yes: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
11
13
|
};
|
|
12
14
|
static examples: string[];
|
|
@@ -17,10 +19,23 @@ export default class Models extends SwellCommand {
|
|
|
17
19
|
private showAppModels;
|
|
18
20
|
private showModels;
|
|
19
21
|
private getModelPath;
|
|
20
|
-
private getAppSlugId;
|
|
21
22
|
private showModelDetail;
|
|
22
23
|
private resolveModelPath;
|
|
23
24
|
private resolveAppModelPath;
|
|
24
25
|
private throwModelNotFound;
|
|
25
|
-
private
|
|
26
|
+
private emitModel;
|
|
27
|
+
/**
|
|
28
|
+
* Detail-mode hints for a model record. Mirrors `InspectResourceCommand.hints`
|
|
29
|
+
* but lives here because `models` doesn't extend that base.
|
|
30
|
+
*
|
|
31
|
+
* Two hints: the records collection at the model's runtime address, and the
|
|
32
|
+
* mutation event stream filtered by canonical model string. Both interpolate
|
|
33
|
+
* from the record's own fields — `app_id`, `namespace`, `name` — so we stay
|
|
34
|
+
* consistent with column 1 if the platform renames anything.
|
|
35
|
+
*
|
|
36
|
+
* Canonical model string: `accounts` (system), `content/blogs` (namespaced
|
|
37
|
+
* system), `apps/<hex>/<col>` (app). The records path mirrors that with a
|
|
38
|
+
* leading slash.
|
|
39
|
+
*/
|
|
40
|
+
private modelHints;
|
|
26
41
|
}
|