@ollie-shop/cli 1.0.2 → 1.2.1
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/.env.example +6 -0
- package/.turbo/turbo-build.log +3 -3
- package/CHANGELOG.md +39 -0
- package/CONTEXT.md +102 -0
- package/README.md +231 -0
- package/dist/index.js +1341 -48
- package/package.json +4 -2
- package/src/commands/business-rule-cmd.ts +161 -0
- package/src/commands/component-cmd.ts +107 -0
- package/src/commands/deploy-cmd.ts +146 -0
- package/src/commands/help.tsx +108 -17
- package/src/commands/init-cmd.ts +53 -0
- package/src/commands/schema-cmd.ts +34 -0
- package/src/commands/status-cmd.ts +68 -0
- package/src/commands/store-cmd.ts +105 -0
- package/src/commands/version-cmd.ts +100 -0
- package/src/commands/whoami.ts +28 -0
- package/src/core/business-rule.ts +128 -0
- package/src/core/component.ts +76 -0
- package/src/core/deploy.ts +171 -0
- package/src/core/schema.ts +136 -0
- package/src/core/store.ts +76 -0
- package/src/core/version.ts +67 -0
- package/src/index.tsx +40 -4
- package/src/utils/output.ts +125 -0
- package/src/utils/parse-args.ts +90 -0
- package/src/utils/supabase.ts +67 -0
- package/src/utils/validate.ts +58 -0
- package/tsup.config.ts +9 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ollie-shop/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "Ollie Shop CLI - Development tools for custom checkouts",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"ollieshop": "dist/index.js"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
+
"@supabase/supabase-js": "^2.49.4",
|
|
12
13
|
"archiver": "^7.0.1",
|
|
13
14
|
"esbuild": "^0.24.0",
|
|
14
15
|
"glob": "^11.0.0",
|
|
@@ -16,7 +17,8 @@
|
|
|
16
17
|
"jwt-decode": "^4.0.0",
|
|
17
18
|
"open": "^10.1.0",
|
|
18
19
|
"react": "^18.3.1",
|
|
19
|
-
"zod": "^3.24.2"
|
|
20
|
+
"zod": "^3.24.2",
|
|
21
|
+
"zod-to-json-schema": "^3.24.5"
|
|
20
22
|
},
|
|
21
23
|
"devDependencies": {
|
|
22
24
|
"@types/archiver": "^6.0.3",
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getBusinessRule,
|
|
3
|
+
listBusinessRules,
|
|
4
|
+
updateBusinessRule,
|
|
5
|
+
} from "../core/business-rule.js";
|
|
6
|
+
import {
|
|
7
|
+
detectOutputFormat,
|
|
8
|
+
outputDryRun,
|
|
9
|
+
outputResult,
|
|
10
|
+
} from "../utils/output.js";
|
|
11
|
+
import { type ParsedArgs, getFlag } from "../utils/parse-args.js";
|
|
12
|
+
import { getAuthenticatedClient } from "../utils/supabase.js";
|
|
13
|
+
import { validateRequired, validateUuid } from "../utils/validate.js";
|
|
14
|
+
|
|
15
|
+
export async function businessRuleCommand(parsed: ParsedArgs): Promise<void> {
|
|
16
|
+
const sub = parsed.subcommand;
|
|
17
|
+
if (sub === "list" || sub === "ls") return businessRuleListCommand(parsed);
|
|
18
|
+
if (sub === "get") return businessRuleGetCommand(parsed);
|
|
19
|
+
if (sub === "update") return businessRuleUpdateCommand(parsed);
|
|
20
|
+
|
|
21
|
+
console.error(
|
|
22
|
+
`Unknown business-rule subcommand: ${sub}. Use: business-rule list | business-rule get | business-rule update`,
|
|
23
|
+
);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function businessRuleListCommand(parsed: ParsedArgs): Promise<void> {
|
|
28
|
+
const format = detectOutputFormat(parsed.global.output);
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const storeId = getFlag(parsed.flags, "store-id");
|
|
32
|
+
const versionId = getFlag(parsed.flags, "version-id");
|
|
33
|
+
const codeUpdatedRaw = parsed.flags["code-updated"];
|
|
34
|
+
|
|
35
|
+
let codeUpdated: boolean | undefined;
|
|
36
|
+
if (codeUpdatedRaw === "true" || codeUpdatedRaw === true) {
|
|
37
|
+
codeUpdated = true;
|
|
38
|
+
} else if (codeUpdatedRaw === "false") {
|
|
39
|
+
codeUpdated = false;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (storeId !== undefined) validateUuid(storeId, "store-id");
|
|
43
|
+
if (versionId !== undefined) validateUuid(versionId, "version-id");
|
|
44
|
+
|
|
45
|
+
const client = await getAuthenticatedClient();
|
|
46
|
+
const result = await listBusinessRules(client, {
|
|
47
|
+
store_id: storeId,
|
|
48
|
+
version_id: versionId,
|
|
49
|
+
code_updated: codeUpdated,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
outputResult(result, format, parsed.global.fields);
|
|
53
|
+
if (result.error) process.exit(1);
|
|
54
|
+
} catch (err) {
|
|
55
|
+
outputResult(
|
|
56
|
+
{
|
|
57
|
+
error: { message: err instanceof Error ? err.message : String(err) },
|
|
58
|
+
},
|
|
59
|
+
format,
|
|
60
|
+
);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function businessRuleGetCommand(parsed: ParsedArgs): Promise<void> {
|
|
66
|
+
const format = detectOutputFormat(parsed.global.output);
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
const id = validateUuid(
|
|
70
|
+
validateRequired(getFlag(parsed.flags, "id"), "id"),
|
|
71
|
+
"id",
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
const client = await getAuthenticatedClient();
|
|
75
|
+
const result = await getBusinessRule(client, id);
|
|
76
|
+
|
|
77
|
+
outputResult(result, format, parsed.global.fields);
|
|
78
|
+
if (result.error) process.exit(1);
|
|
79
|
+
} catch (err) {
|
|
80
|
+
outputResult(
|
|
81
|
+
{
|
|
82
|
+
error: { message: err instanceof Error ? err.message : String(err) },
|
|
83
|
+
},
|
|
84
|
+
format,
|
|
85
|
+
);
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function businessRuleUpdateCommand(parsed: ParsedArgs): Promise<void> {
|
|
91
|
+
const format = detectOutputFormat(parsed.global.output);
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
let id: string;
|
|
95
|
+
let input: {
|
|
96
|
+
content: string;
|
|
97
|
+
versions_ids?: string[] | null;
|
|
98
|
+
components_ids?: string[] | null;
|
|
99
|
+
functions_ids?: string[] | null;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
if (parsed.global.data) {
|
|
103
|
+
const raw = JSON.parse(parsed.global.data);
|
|
104
|
+
id = validateUuid(validateRequired(raw.id, "id"), "id");
|
|
105
|
+
input = {
|
|
106
|
+
content: validateRequired(raw.content, "content"),
|
|
107
|
+
versions_ids: raw.versionsIds ?? undefined,
|
|
108
|
+
components_ids: raw.componentsIds ?? undefined,
|
|
109
|
+
functions_ids: raw.functionsIds ?? undefined,
|
|
110
|
+
};
|
|
111
|
+
} else {
|
|
112
|
+
id = validateUuid(
|
|
113
|
+
validateRequired(getFlag(parsed.flags, "id"), "id"),
|
|
114
|
+
"id",
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
const versionsIdsRaw = getFlag(parsed.flags, "versions-ids");
|
|
118
|
+
const componentsIdsRaw = getFlag(parsed.flags, "components-ids");
|
|
119
|
+
const functionsIdsRaw = getFlag(parsed.flags, "functions-ids");
|
|
120
|
+
|
|
121
|
+
input = {
|
|
122
|
+
content: validateRequired(
|
|
123
|
+
getFlag(parsed.flags, "content", "c"),
|
|
124
|
+
"content",
|
|
125
|
+
),
|
|
126
|
+
versions_ids: versionsIdsRaw
|
|
127
|
+
? (JSON.parse(versionsIdsRaw) as string[])
|
|
128
|
+
: undefined,
|
|
129
|
+
components_ids: componentsIdsRaw
|
|
130
|
+
? (JSON.parse(componentsIdsRaw) as string[])
|
|
131
|
+
: undefined,
|
|
132
|
+
functions_ids: functionsIdsRaw
|
|
133
|
+
? (JSON.parse(functionsIdsRaw) as string[])
|
|
134
|
+
: undefined,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (parsed.global.dryRun) {
|
|
139
|
+
outputDryRun(
|
|
140
|
+
"business-rule.update",
|
|
141
|
+
{ id, ...input } as Record<string, unknown>,
|
|
142
|
+
format,
|
|
143
|
+
);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const client = await getAuthenticatedClient();
|
|
148
|
+
const result = await updateBusinessRule(client, id, input);
|
|
149
|
+
|
|
150
|
+
outputResult(result, format, parsed.global.fields);
|
|
151
|
+
if (result.error) process.exit(1);
|
|
152
|
+
} catch (err) {
|
|
153
|
+
outputResult(
|
|
154
|
+
{
|
|
155
|
+
error: { message: err instanceof Error ? err.message : String(err) },
|
|
156
|
+
},
|
|
157
|
+
format,
|
|
158
|
+
);
|
|
159
|
+
process.exit(1);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { createComponent, listComponents } from "../core/component.js";
|
|
2
|
+
import {
|
|
3
|
+
detectOutputFormat,
|
|
4
|
+
outputDryRun,
|
|
5
|
+
outputResult,
|
|
6
|
+
} from "../utils/output.js";
|
|
7
|
+
import { type ParsedArgs, getBoolFlag, getFlag } from "../utils/parse-args.js";
|
|
8
|
+
import { getAuthenticatedClient } from "../utils/supabase.js";
|
|
9
|
+
import { validateRequired, validateUuid } from "../utils/validate.js";
|
|
10
|
+
|
|
11
|
+
export async function componentCommand(parsed: ParsedArgs): Promise<void> {
|
|
12
|
+
const sub = parsed.subcommand;
|
|
13
|
+
if (sub === "create") return componentCreateCommand(parsed);
|
|
14
|
+
if (sub === "list" || sub === "ls") return componentListCommand(parsed);
|
|
15
|
+
|
|
16
|
+
console.error(
|
|
17
|
+
`Unknown component subcommand: ${sub}. Use: component create | component list`,
|
|
18
|
+
);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function componentCreateCommand(parsed: ParsedArgs): Promise<void> {
|
|
23
|
+
const format = detectOutputFormat(parsed.global.output);
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
let input: {
|
|
27
|
+
versionId: string;
|
|
28
|
+
name: string;
|
|
29
|
+
slot: string;
|
|
30
|
+
active?: boolean;
|
|
31
|
+
props?: Record<string, unknown> | null;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
if (parsed.global.data) {
|
|
35
|
+
const raw = JSON.parse(parsed.global.data);
|
|
36
|
+
input = {
|
|
37
|
+
versionId: validateUuid(raw.versionId, "versionId"),
|
|
38
|
+
name: validateRequired(raw.name, "name"),
|
|
39
|
+
slot: validateRequired(raw.slot, "slot"),
|
|
40
|
+
active: raw.active ?? true,
|
|
41
|
+
props: raw.props ?? null,
|
|
42
|
+
};
|
|
43
|
+
} else {
|
|
44
|
+
input = {
|
|
45
|
+
versionId: validateUuid(
|
|
46
|
+
validateRequired(getFlag(parsed.flags, "version-id"), "version-id"),
|
|
47
|
+
"version-id",
|
|
48
|
+
),
|
|
49
|
+
name: validateRequired(getFlag(parsed.flags, "name", "n"), "name"),
|
|
50
|
+
slot: validateRequired(getFlag(parsed.flags, "slot", "s"), "slot"),
|
|
51
|
+
active:
|
|
52
|
+
getBoolFlag(parsed.flags, "active") || !("active" in parsed.flags),
|
|
53
|
+
props: null,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (parsed.global.dryRun) {
|
|
58
|
+
outputDryRun(
|
|
59
|
+
"component.create",
|
|
60
|
+
input as Record<string, unknown>,
|
|
61
|
+
format,
|
|
62
|
+
);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const client = await getAuthenticatedClient();
|
|
67
|
+
const result = await createComponent(client, input);
|
|
68
|
+
|
|
69
|
+
outputResult(result, format, parsed.global.fields);
|
|
70
|
+
if (result.error) process.exit(1);
|
|
71
|
+
} catch (err) {
|
|
72
|
+
outputResult(
|
|
73
|
+
{
|
|
74
|
+
error: { message: err instanceof Error ? err.message : String(err) },
|
|
75
|
+
},
|
|
76
|
+
format,
|
|
77
|
+
);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function componentListCommand(parsed: ParsedArgs): Promise<void> {
|
|
83
|
+
const format = detectOutputFormat(parsed.global.output);
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
const storeId = validateUuid(
|
|
87
|
+
validateRequired(getFlag(parsed.flags, "store-id"), "store-id"),
|
|
88
|
+
"store-id",
|
|
89
|
+
);
|
|
90
|
+
const versionId = getFlag(parsed.flags, "version-id");
|
|
91
|
+
if (versionId) validateUuid(versionId, "version-id");
|
|
92
|
+
|
|
93
|
+
const client = await getAuthenticatedClient();
|
|
94
|
+
const result = await listComponents(client, storeId, versionId);
|
|
95
|
+
|
|
96
|
+
outputResult(result, format, parsed.global.fields);
|
|
97
|
+
if (result.error) process.exit(1);
|
|
98
|
+
} catch (err) {
|
|
99
|
+
outputResult(
|
|
100
|
+
{
|
|
101
|
+
error: { message: err instanceof Error ? err.message : String(err) },
|
|
102
|
+
},
|
|
103
|
+
format,
|
|
104
|
+
);
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ResourceType,
|
|
3
|
+
isTerminalStatus,
|
|
4
|
+
pollBuildStatus,
|
|
5
|
+
uploadBuild,
|
|
6
|
+
} from "../core/deploy.js";
|
|
7
|
+
import { createComponentBundle } from "../utils/bundle.js";
|
|
8
|
+
import {
|
|
9
|
+
detectOutputFormat,
|
|
10
|
+
outputDryRun,
|
|
11
|
+
outputResult,
|
|
12
|
+
} from "../utils/output.js";
|
|
13
|
+
import { type ParsedArgs, getBoolFlag, getFlag } from "../utils/parse-args.js";
|
|
14
|
+
import { validateRequired, validateUuid } from "../utils/validate.js";
|
|
15
|
+
|
|
16
|
+
export async function deployCommand(parsed: ParsedArgs): Promise<void> {
|
|
17
|
+
const format = detectOutputFormat(parsed.global.output);
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
let resourceId: string;
|
|
21
|
+
let componentName: string;
|
|
22
|
+
let resourceType: ResourceType;
|
|
23
|
+
let wait: boolean;
|
|
24
|
+
let timeout: number;
|
|
25
|
+
|
|
26
|
+
if (parsed.global.data) {
|
|
27
|
+
const raw = JSON.parse(parsed.global.data);
|
|
28
|
+
resourceId = validateUuid(
|
|
29
|
+
raw.componentId || raw.functionId || raw.resourceId,
|
|
30
|
+
"componentId or functionId",
|
|
31
|
+
);
|
|
32
|
+
componentName = validateRequired(raw.name, "name");
|
|
33
|
+
resourceType = raw.type === "function" ? "function" : "component";
|
|
34
|
+
wait = raw.wait ?? false;
|
|
35
|
+
timeout = raw.timeout ?? 300;
|
|
36
|
+
} else {
|
|
37
|
+
const compId = getFlag(parsed.flags, "component-id");
|
|
38
|
+
const funcId = getFlag(parsed.flags, "function-id");
|
|
39
|
+
|
|
40
|
+
if (compId && funcId) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
"Provide either --component-id or --function-id, not both.",
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (compId) {
|
|
47
|
+
resourceId = validateUuid(compId, "component-id");
|
|
48
|
+
resourceType = "component";
|
|
49
|
+
} else if (funcId) {
|
|
50
|
+
resourceId = validateUuid(funcId, "function-id");
|
|
51
|
+
resourceType = "function";
|
|
52
|
+
} else {
|
|
53
|
+
throw new Error("Either --component-id or --function-id is required.");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
componentName = validateRequired(
|
|
57
|
+
getFlag(parsed.flags, "name", "n"),
|
|
58
|
+
"name",
|
|
59
|
+
);
|
|
60
|
+
wait = getBoolFlag(parsed.flags, "wait");
|
|
61
|
+
timeout = Number(getFlag(parsed.flags, "timeout") ?? "300");
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Bundle the component
|
|
65
|
+
const stream = await createComponentBundle({
|
|
66
|
+
componentName,
|
|
67
|
+
cwd: process.cwd(),
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Collect the zip buffer
|
|
71
|
+
const chunks: Buffer[] = [];
|
|
72
|
+
for await (const chunk of stream) {
|
|
73
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
74
|
+
}
|
|
75
|
+
const zipBuffer = Buffer.concat(chunks);
|
|
76
|
+
|
|
77
|
+
if (parsed.global.dryRun) {
|
|
78
|
+
outputDryRun(
|
|
79
|
+
"deploy",
|
|
80
|
+
{
|
|
81
|
+
resourceId,
|
|
82
|
+
resourceType,
|
|
83
|
+
componentName,
|
|
84
|
+
bundleSizeBytes: zipBuffer.length,
|
|
85
|
+
bundleSizeKB: Math.round(zipBuffer.length / 1024),
|
|
86
|
+
wait,
|
|
87
|
+
timeout,
|
|
88
|
+
},
|
|
89
|
+
format,
|
|
90
|
+
);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Upload to builder
|
|
95
|
+
const uploadResult = await uploadBuild({
|
|
96
|
+
resourceId,
|
|
97
|
+
type: resourceType,
|
|
98
|
+
zipBuffer,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
if (!uploadResult.success) {
|
|
102
|
+
outputResult(uploadResult, format);
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// If --wait, poll until terminal
|
|
107
|
+
if (wait) {
|
|
108
|
+
const isJson = format === "json";
|
|
109
|
+
if (!isJson) {
|
|
110
|
+
process.stderr.write(
|
|
111
|
+
`Build ${uploadResult.data.id} started. Polling...\n`,
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const pollResult = await pollBuildStatus(uploadResult.data.id, {
|
|
116
|
+
timeoutMs: timeout * 1000,
|
|
117
|
+
onPoll: (build) => {
|
|
118
|
+
if (!isJson) {
|
|
119
|
+
process.stderr.write(` status: ${build.status}\n`);
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
outputResult(pollResult, format, parsed.global.fields);
|
|
125
|
+
if (!pollResult.success) process.exit(1);
|
|
126
|
+
if (
|
|
127
|
+
pollResult.success &&
|
|
128
|
+
isTerminalStatus(pollResult.data.status) &&
|
|
129
|
+
pollResult.data.status !== "SUCCEEDED"
|
|
130
|
+
) {
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
133
|
+
} else {
|
|
134
|
+
outputResult(uploadResult, format, parsed.global.fields);
|
|
135
|
+
}
|
|
136
|
+
} catch (err) {
|
|
137
|
+
outputResult(
|
|
138
|
+
{
|
|
139
|
+
success: false,
|
|
140
|
+
error: { message: err instanceof Error ? err.message : String(err) },
|
|
141
|
+
},
|
|
142
|
+
format,
|
|
143
|
+
);
|
|
144
|
+
process.exit(1);
|
|
145
|
+
}
|
|
146
|
+
}
|
package/src/commands/help.tsx
CHANGED
|
@@ -16,29 +16,83 @@ export function HelpCommand() {
|
|
|
16
16
|
</Box>
|
|
17
17
|
|
|
18
18
|
<Box marginTop={1}>
|
|
19
|
-
<Text bold>Commands:</Text>
|
|
19
|
+
<Text bold>Interactive Commands:</Text>
|
|
20
20
|
</Box>
|
|
21
21
|
<Box marginLeft={2} flexDirection="column" gap={0}>
|
|
22
22
|
<Box>
|
|
23
|
-
<Box width={
|
|
23
|
+
<Box width={24}>
|
|
24
24
|
<Text color="green">login</Text>
|
|
25
25
|
</Box>
|
|
26
26
|
<Text>Authenticate with your Ollie Shop account</Text>
|
|
27
27
|
</Box>
|
|
28
28
|
<Box>
|
|
29
|
-
<Box width={
|
|
29
|
+
<Box width={24}>
|
|
30
30
|
<Text color="green">start</Text>
|
|
31
31
|
</Box>
|
|
32
32
|
<Text>Start the development server with hot reload</Text>
|
|
33
33
|
</Box>
|
|
34
|
+
</Box>
|
|
35
|
+
|
|
36
|
+
<Box marginTop={1}>
|
|
37
|
+
<Text bold>Agent Commands:</Text>
|
|
38
|
+
</Box>
|
|
39
|
+
<Box marginLeft={2} flexDirection="column" gap={0}>
|
|
40
|
+
<Box>
|
|
41
|
+
<Box width={24}>
|
|
42
|
+
<Text color="green">whoami</Text>
|
|
43
|
+
</Box>
|
|
44
|
+
<Text>Show current user and organization</Text>
|
|
45
|
+
</Box>
|
|
46
|
+
<Box>
|
|
47
|
+
<Box width={24}>
|
|
48
|
+
<Text color="green">store create|list</Text>
|
|
49
|
+
</Box>
|
|
50
|
+
<Text>Create or list stores</Text>
|
|
51
|
+
</Box>
|
|
52
|
+
<Box>
|
|
53
|
+
<Box width={24}>
|
|
54
|
+
<Text color="green">version create|list</Text>
|
|
55
|
+
</Box>
|
|
56
|
+
<Text>Create or list versions</Text>
|
|
57
|
+
</Box>
|
|
58
|
+
<Box>
|
|
59
|
+
<Box width={24}>
|
|
60
|
+
<Text color="green">component create|list</Text>
|
|
61
|
+
</Box>
|
|
62
|
+
<Text>Create or list components</Text>
|
|
63
|
+
</Box>
|
|
64
|
+
<Box>
|
|
65
|
+
<Box width={24}>
|
|
66
|
+
<Text color="green">deploy</Text>
|
|
67
|
+
</Box>
|
|
68
|
+
<Text>Bundle and upload a component/function build</Text>
|
|
69
|
+
</Box>
|
|
70
|
+
<Box>
|
|
71
|
+
<Box width={24}>
|
|
72
|
+
<Text color="green">status</Text>
|
|
73
|
+
</Box>
|
|
74
|
+
<Text>Check or poll a build status</Text>
|
|
75
|
+
</Box>
|
|
76
|
+
<Box>
|
|
77
|
+
<Box width={24}>
|
|
78
|
+
<Text color="green">schema</Text>
|
|
79
|
+
</Box>
|
|
80
|
+
<Text>Introspect resource schemas (JSON Schema)</Text>
|
|
81
|
+
</Box>
|
|
34
82
|
<Box>
|
|
35
|
-
<Box width={
|
|
83
|
+
<Box width={24}>
|
|
84
|
+
<Text color="green">init</Text>
|
|
85
|
+
</Box>
|
|
86
|
+
<Text>Write store/version IDs to ollie.json</Text>
|
|
87
|
+
</Box>
|
|
88
|
+
<Box>
|
|
89
|
+
<Box width={24}>
|
|
36
90
|
<Text color="green">help</Text>
|
|
37
91
|
</Box>
|
|
38
92
|
<Text>Show this help message</Text>
|
|
39
93
|
</Box>
|
|
40
94
|
<Box>
|
|
41
|
-
<Box width={
|
|
95
|
+
<Box width={24}>
|
|
42
96
|
<Text color="green">version</Text>
|
|
43
97
|
</Box>
|
|
44
98
|
<Text>Show CLI version</Text>
|
|
@@ -46,33 +100,70 @@ export function HelpCommand() {
|
|
|
46
100
|
</Box>
|
|
47
101
|
|
|
48
102
|
<Box marginTop={1}>
|
|
49
|
-
<Text bold>
|
|
103
|
+
<Text bold>Global Flags:</Text>
|
|
50
104
|
</Box>
|
|
51
105
|
<Box marginLeft={2} flexDirection="column" gap={0}>
|
|
52
106
|
<Box>
|
|
53
|
-
<Box width={
|
|
107
|
+
<Box width={24}>
|
|
108
|
+
<Text color="yellow">--output json, -o json</Text>
|
|
109
|
+
</Box>
|
|
110
|
+
<Text>Force JSON output (auto when piped)</Text>
|
|
111
|
+
</Box>
|
|
112
|
+
<Box>
|
|
113
|
+
<Box width={24}>
|
|
114
|
+
<Text color="yellow">--dry-run</Text>
|
|
115
|
+
</Box>
|
|
116
|
+
<Text>Validate without executing mutations</Text>
|
|
117
|
+
</Box>
|
|
118
|
+
<Box>
|
|
119
|
+
<Box width={24}>
|
|
120
|
+
<Text color="yellow">--fields a,b,c</Text>
|
|
121
|
+
</Box>
|
|
122
|
+
<Text>Limit output fields</Text>
|
|
123
|
+
</Box>
|
|
124
|
+
<Box>
|
|
125
|
+
<Box width={24}>
|
|
126
|
+
<Text color="yellow">--data {`'{...}'`}</Text>
|
|
127
|
+
</Box>
|
|
128
|
+
<Text>Raw JSON payload for mutations</Text>
|
|
129
|
+
</Box>
|
|
130
|
+
<Box>
|
|
131
|
+
<Box width={24}>
|
|
54
132
|
<Text color="yellow">--stage, -s</Text>
|
|
55
133
|
</Box>
|
|
56
134
|
<Text>Config stage (loads ollie.{"{stage}"}.json)</Text>
|
|
57
135
|
</Box>
|
|
58
136
|
</Box>
|
|
59
137
|
|
|
60
|
-
<Box marginTop={1}>
|
|
61
|
-
<Text bold>Configuration:</Text>
|
|
62
|
-
</Box>
|
|
63
|
-
<Box marginLeft={2} flexDirection="column">
|
|
64
|
-
<Text dimColor>ollie.json - Default config (prod)</Text>
|
|
65
|
-
<Text dimColor>ollie.dev.json - Dev stage config</Text>
|
|
66
|
-
<Text dimColor>ollie.{"{stage}"}.json - Custom stage config</Text>
|
|
67
|
-
</Box>
|
|
68
|
-
|
|
69
138
|
<Box marginTop={1}>
|
|
70
139
|
<Text bold>Examples:</Text>
|
|
71
140
|
</Box>
|
|
72
141
|
<Box marginLeft={2} flexDirection="column">
|
|
73
142
|
<Text dimColor>$ ollieshop login</Text>
|
|
74
|
-
<Text dimColor>$ ollieshop start</Text>
|
|
75
143
|
<Text dimColor>$ ollieshop start --stage dev</Text>
|
|
144
|
+
<Text dimColor>$ ollieshop whoami -o json</Text>
|
|
145
|
+
<Text dimColor>$ ollieshop schema store.create</Text>
|
|
146
|
+
<Text dimColor>
|
|
147
|
+
$ ollieshop store create --name "My Store" --platform vtex
|
|
148
|
+
--platform-store-id mystore
|
|
149
|
+
</Text>
|
|
150
|
+
<Text dimColor>
|
|
151
|
+
$ ollieshop store create --data{" "}
|
|
152
|
+
{
|
|
153
|
+
'\'{"name":"My Store","platform":"vtex","platformStoreId":"mystore"}\''
|
|
154
|
+
}{" "}
|
|
155
|
+
-o json
|
|
156
|
+
</Text>
|
|
157
|
+
<Text dimColor>
|
|
158
|
+
$ ollieshop version create --store-id UUID --name v1 --active
|
|
159
|
+
</Text>
|
|
160
|
+
<Text dimColor>$ ollieshop init --store-id UUID --version-id UUID</Text>
|
|
161
|
+
<Text dimColor>
|
|
162
|
+
$ ollieshop deploy --component-id UUID --name FreeShippingBar --wait
|
|
163
|
+
</Text>
|
|
164
|
+
<Text dimColor>
|
|
165
|
+
$ ollieshop status --build-id BUILD_ID --wait -o json
|
|
166
|
+
</Text>
|
|
76
167
|
</Box>
|
|
77
168
|
</Box>
|
|
78
169
|
);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { saveConfig } from "../utils/config.js";
|
|
2
|
+
import { detectOutputFormat, outputResult } from "../utils/output.js";
|
|
3
|
+
import { type ParsedArgs, getFlag } from "../utils/parse-args.js";
|
|
4
|
+
import { validateRequired, validateUuid } from "../utils/validate.js";
|
|
5
|
+
|
|
6
|
+
export async function initCommand(parsed: ParsedArgs): Promise<void> {
|
|
7
|
+
const format = detectOutputFormat(parsed.global.output);
|
|
8
|
+
|
|
9
|
+
try {
|
|
10
|
+
const storeId = validateUuid(
|
|
11
|
+
validateRequired(getFlag(parsed.flags, "store-id"), "store-id"),
|
|
12
|
+
"store-id",
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
const versionIdRaw = getFlag(parsed.flags, "version-id");
|
|
16
|
+
const versionId = versionIdRaw
|
|
17
|
+
? validateUuid(versionIdRaw, "version-id")
|
|
18
|
+
: undefined;
|
|
19
|
+
|
|
20
|
+
const stage = getFlag(parsed.flags, "stage", "s");
|
|
21
|
+
|
|
22
|
+
await saveConfig(
|
|
23
|
+
{
|
|
24
|
+
storeId,
|
|
25
|
+
...(versionId ? { versionId } : {}),
|
|
26
|
+
},
|
|
27
|
+
{ stage },
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const fileName =
|
|
31
|
+
stage && stage !== "prod" ? `ollie.${stage}.json` : "ollie.json";
|
|
32
|
+
|
|
33
|
+
outputResult(
|
|
34
|
+
{
|
|
35
|
+
data: {
|
|
36
|
+
file: fileName,
|
|
37
|
+
storeId,
|
|
38
|
+
...(versionId ? { versionId } : {}),
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
format,
|
|
42
|
+
parsed.global.fields,
|
|
43
|
+
);
|
|
44
|
+
} catch (err) {
|
|
45
|
+
outputResult(
|
|
46
|
+
{
|
|
47
|
+
error: { message: err instanceof Error ? err.message : String(err) },
|
|
48
|
+
},
|
|
49
|
+
format,
|
|
50
|
+
);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { getJsonSchema, getSchemaNames } from "../core/schema.js";
|
|
2
|
+
import { detectOutputFormat } from "../utils/output.js";
|
|
3
|
+
import type { ParsedArgs } from "../utils/parse-args.js";
|
|
4
|
+
|
|
5
|
+
export async function schemaCommand(parsed: ParsedArgs): Promise<void> {
|
|
6
|
+
const format = detectOutputFormat(parsed.global.output);
|
|
7
|
+
const resourceName = parsed.subcommand || parsed.positional[0];
|
|
8
|
+
|
|
9
|
+
if (!resourceName) {
|
|
10
|
+
// List all available schemas
|
|
11
|
+
const names = getSchemaNames();
|
|
12
|
+
if (format === "json") {
|
|
13
|
+
process.stdout.write(`${JSON.stringify({ schemas: names })}\n`);
|
|
14
|
+
} else {
|
|
15
|
+
console.log("\x1b[1mAvailable schemas:\x1b[0m");
|
|
16
|
+
for (const name of names) {
|
|
17
|
+
const indent = name.includes(".") ? " " : " ";
|
|
18
|
+
console.log(`${indent}\x1b[32m${name}\x1b[0m`);
|
|
19
|
+
}
|
|
20
|
+
console.log("\nUsage: ollieshop schema <resource[.action]>");
|
|
21
|
+
}
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const schema = getJsonSchema(resourceName);
|
|
26
|
+
if (!schema) {
|
|
27
|
+
console.error(
|
|
28
|
+
`Unknown schema: ${resourceName}. Run \`ollieshop schema\` to see available schemas.`,
|
|
29
|
+
);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
process.stdout.write(`${JSON.stringify(schema, null, 2)}\n`);
|
|
34
|
+
}
|