@ollie-shop/cli 1.0.2 → 1.1.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/.env.example +3 -0
- package/.turbo/turbo-build.log +3 -3
- package/CHANGELOG.md +23 -0
- package/CONTEXT.md +84 -0
- package/README.md +199 -0
- package/dist/index.js +886 -48
- package/package.json +4 -2
- package/src/commands/component-cmd.ts +107 -0
- package/src/commands/help.tsx +90 -17
- package/src/commands/init-cmd.ts +53 -0
- package/src/commands/schema-cmd.ts +34 -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/component.ts +76 -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 +34 -4
- package/src/utils/output.ts +125 -0
- package/src/utils/parse-args.ts +90 -0
- package/src/utils/supabase.ts +59 -0
- package/src/utils/validate.ts +58 -0
package/dist/index.js
CHANGED
|
@@ -21,49 +21,98 @@ function HelpCommand() {
|
|
|
21
21
|
"<command>",
|
|
22
22
|
" [options]"
|
|
23
23
|
] }) }),
|
|
24
|
-
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, children: "Commands:" }) }),
|
|
24
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, children: "Interactive Commands:" }) }),
|
|
25
25
|
/* @__PURE__ */ jsxs(Box, { marginLeft: 2, flexDirection: "column", gap: 0, children: [
|
|
26
26
|
/* @__PURE__ */ jsxs(Box, { children: [
|
|
27
|
-
/* @__PURE__ */ jsx(Box, { width:
|
|
27
|
+
/* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsx(Text, { color: "green", children: "login" }) }),
|
|
28
28
|
/* @__PURE__ */ jsx(Text, { children: "Authenticate with your Ollie Shop account" })
|
|
29
29
|
] }),
|
|
30
30
|
/* @__PURE__ */ jsxs(Box, { children: [
|
|
31
|
-
/* @__PURE__ */ jsx(Box, { width:
|
|
31
|
+
/* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsx(Text, { color: "green", children: "start" }) }),
|
|
32
32
|
/* @__PURE__ */ jsx(Text, { children: "Start the development server with hot reload" })
|
|
33
|
+
] })
|
|
34
|
+
] }),
|
|
35
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, children: "Agent Commands:" }) }),
|
|
36
|
+
/* @__PURE__ */ jsxs(Box, { marginLeft: 2, flexDirection: "column", gap: 0, children: [
|
|
37
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
38
|
+
/* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsx(Text, { color: "green", children: "whoami" }) }),
|
|
39
|
+
/* @__PURE__ */ jsx(Text, { children: "Show current user and organization" })
|
|
40
|
+
] }),
|
|
41
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
42
|
+
/* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsx(Text, { color: "green", children: "store create|list" }) }),
|
|
43
|
+
/* @__PURE__ */ jsx(Text, { children: "Create or list stores" })
|
|
44
|
+
] }),
|
|
45
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
46
|
+
/* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsx(Text, { color: "green", children: "version create|list" }) }),
|
|
47
|
+
/* @__PURE__ */ jsx(Text, { children: "Create or list versions" })
|
|
33
48
|
] }),
|
|
34
49
|
/* @__PURE__ */ jsxs(Box, { children: [
|
|
35
|
-
/* @__PURE__ */ jsx(Box, { width:
|
|
50
|
+
/* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsx(Text, { color: "green", children: "component create|list" }) }),
|
|
51
|
+
/* @__PURE__ */ jsx(Text, { children: "Create or list components" })
|
|
52
|
+
] }),
|
|
53
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
54
|
+
/* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsx(Text, { color: "green", children: "schema" }) }),
|
|
55
|
+
/* @__PURE__ */ jsx(Text, { children: "Introspect resource schemas (JSON Schema)" })
|
|
56
|
+
] }),
|
|
57
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
58
|
+
/* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsx(Text, { color: "green", children: "init" }) }),
|
|
59
|
+
/* @__PURE__ */ jsx(Text, { children: "Write store/version IDs to ollie.json" })
|
|
60
|
+
] }),
|
|
61
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
62
|
+
/* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsx(Text, { color: "green", children: "help" }) }),
|
|
36
63
|
/* @__PURE__ */ jsx(Text, { children: "Show this help message" })
|
|
37
64
|
] }),
|
|
38
65
|
/* @__PURE__ */ jsxs(Box, { children: [
|
|
39
|
-
/* @__PURE__ */ jsx(Box, { width:
|
|
66
|
+
/* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsx(Text, { color: "green", children: "version" }) }),
|
|
40
67
|
/* @__PURE__ */ jsx(Text, { children: "Show CLI version" })
|
|
41
68
|
] })
|
|
42
69
|
] }),
|
|
43
|
-
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, children: "
|
|
44
|
-
/* @__PURE__ */
|
|
45
|
-
/* @__PURE__ */
|
|
46
|
-
|
|
47
|
-
"
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
70
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, children: "Global Flags:" }) }),
|
|
71
|
+
/* @__PURE__ */ jsxs(Box, { marginLeft: 2, flexDirection: "column", gap: 0, children: [
|
|
72
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
73
|
+
/* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsx(Text, { color: "yellow", children: "--output json, -o json" }) }),
|
|
74
|
+
/* @__PURE__ */ jsx(Text, { children: "Force JSON output (auto when piped)" })
|
|
75
|
+
] }),
|
|
76
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
77
|
+
/* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsx(Text, { color: "yellow", children: "--dry-run" }) }),
|
|
78
|
+
/* @__PURE__ */ jsx(Text, { children: "Validate without executing mutations" })
|
|
79
|
+
] }),
|
|
80
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
81
|
+
/* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsx(Text, { color: "yellow", children: "--fields a,b,c" }) }),
|
|
82
|
+
/* @__PURE__ */ jsx(Text, { children: "Limit output fields" })
|
|
83
|
+
] }),
|
|
84
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
85
|
+
/* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
86
|
+
"--data ",
|
|
87
|
+
`'{...}'`
|
|
88
|
+
] }) }),
|
|
89
|
+
/* @__PURE__ */ jsx(Text, { children: "Raw JSON payload for mutations" })
|
|
90
|
+
] }),
|
|
91
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
92
|
+
/* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsx(Text, { color: "yellow", children: "--stage, -s" }) }),
|
|
93
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
94
|
+
"Config stage (loads ollie.",
|
|
95
|
+
"{stage}",
|
|
96
|
+
".json)"
|
|
97
|
+
] })
|
|
60
98
|
] })
|
|
61
99
|
] }),
|
|
62
100
|
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, children: "Examples:" }) }),
|
|
63
101
|
/* @__PURE__ */ jsxs(Box, { marginLeft: 2, flexDirection: "column", children: [
|
|
64
102
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "$ ollieshop login" }),
|
|
65
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "$ ollieshop start" }),
|
|
66
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "$ ollieshop
|
|
103
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "$ ollieshop start --stage dev" }),
|
|
104
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "$ ollieshop whoami -o json" }),
|
|
105
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "$ ollieshop schema store.create" }),
|
|
106
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: '$ ollieshop store create --name "My Store" --platform vtex --platform-store-id mystore' }),
|
|
107
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
108
|
+
"$ ollieshop store create --data",
|
|
109
|
+
" ",
|
|
110
|
+
`'{"name":"My Store","platform":"vtex","platformStoreId":"mystore"}'`,
|
|
111
|
+
" ",
|
|
112
|
+
"-o json"
|
|
113
|
+
] }),
|
|
114
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "$ ollieshop version create --store-id UUID --name v1 --active" }),
|
|
115
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "$ ollieshop init --store-id UUID --version-id UUID" })
|
|
67
116
|
] })
|
|
68
117
|
] });
|
|
69
118
|
}
|
|
@@ -227,14 +276,32 @@ async function saveCredentials(token) {
|
|
|
227
276
|
};
|
|
228
277
|
await fs.writeFile(CREDENTIALS_PATH, JSON.stringify(credentials, null, 2));
|
|
229
278
|
}
|
|
279
|
+
async function getCredentials() {
|
|
280
|
+
try {
|
|
281
|
+
const content = await fs.readFile(CREDENTIALS_PATH, "utf-8");
|
|
282
|
+
return JSON.parse(content);
|
|
283
|
+
} catch {
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
async function getCurrentUser() {
|
|
288
|
+
const credentials = await getCredentials();
|
|
289
|
+
if (!credentials) return null;
|
|
290
|
+
try {
|
|
291
|
+
const decoded = jwtDecode(credentials.accessToken);
|
|
292
|
+
return decoded.email ? { email: decoded.email } : null;
|
|
293
|
+
} catch {
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
230
297
|
|
|
231
298
|
// src/commands/login.tsx
|
|
232
299
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
233
|
-
function LoginCommand({ args
|
|
300
|
+
function LoginCommand({ args }) {
|
|
234
301
|
const { exit } = useApp();
|
|
235
302
|
const [state, setState] = useState({ status: "idle" });
|
|
236
|
-
const portIndex =
|
|
237
|
-
const port = portIndex !== -1 ? Number.parseInt(
|
|
303
|
+
const portIndex = args.findIndex((a) => a === "--port" || a === "-p");
|
|
304
|
+
const port = portIndex !== -1 ? Number.parseInt(args[portIndex + 1], 10) : 7777;
|
|
238
305
|
useEffect(() => {
|
|
239
306
|
if (state.status !== "idle") return;
|
|
240
307
|
setState({ status: "waiting" });
|
|
@@ -341,6 +408,17 @@ async function loadConfig(options = {}) {
|
|
|
341
408
|
};
|
|
342
409
|
return OllieConfigSchema.parse(merged);
|
|
343
410
|
}
|
|
411
|
+
async function saveConfig(config, options = {}) {
|
|
412
|
+
const { cwd = process.cwd(), stage } = options;
|
|
413
|
+
const fileName = getConfigFileName(stage);
|
|
414
|
+
const configPath = path2.join(cwd, fileName);
|
|
415
|
+
const existing = await loadConfigFile(configPath);
|
|
416
|
+
const merged = {
|
|
417
|
+
...existing,
|
|
418
|
+
...config
|
|
419
|
+
};
|
|
420
|
+
await fs2.writeFile(configPath, JSON.stringify(merged, null, 2));
|
|
421
|
+
}
|
|
344
422
|
function resolveStage(cliStage) {
|
|
345
423
|
return cliStage || process.env.OLLIE_STAGE || void 0;
|
|
346
424
|
}
|
|
@@ -764,11 +842,11 @@ import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
|
764
842
|
var STUDIO_BASE_URL = "https://admin.ollie.shop/studio";
|
|
765
843
|
var MAX_LOGS = 10;
|
|
766
844
|
var PORT = 4e3;
|
|
767
|
-
function parseArg(
|
|
768
|
-
const index =
|
|
769
|
-
return index !== -1 ?
|
|
845
|
+
function parseArg(args, ...flags) {
|
|
846
|
+
const index = args.findIndex((a) => flags.includes(a));
|
|
847
|
+
return index !== -1 ? args[index + 1] : void 0;
|
|
770
848
|
}
|
|
771
|
-
function StartCommand({ args
|
|
849
|
+
function StartCommand({ args }) {
|
|
772
850
|
const { exit } = useApp2();
|
|
773
851
|
const [state, setState] = useState2({ status: "initializing" });
|
|
774
852
|
const [components, setComponents] = useState2([]);
|
|
@@ -778,7 +856,7 @@ function StartCommand({ args: args2 }) {
|
|
|
778
856
|
const logIdRef = useRef(0);
|
|
779
857
|
const ctxRef = useRef(null);
|
|
780
858
|
const stopRef = useRef(null);
|
|
781
|
-
const stage = resolveStage(parseArg(
|
|
859
|
+
const stage = resolveStage(parseArg(args, "--stage", "-s"));
|
|
782
860
|
const addLog = useCallback((log) => {
|
|
783
861
|
setLogs((prev) => {
|
|
784
862
|
const newLog = {
|
|
@@ -790,12 +868,12 @@ function StartCommand({ args: args2 }) {
|
|
|
790
868
|
});
|
|
791
869
|
}, []);
|
|
792
870
|
const handleRequest = useCallback(
|
|
793
|
-
(
|
|
871
|
+
(args2) => {
|
|
794
872
|
addLog({
|
|
795
|
-
method:
|
|
796
|
-
path:
|
|
797
|
-
status:
|
|
798
|
-
time:
|
|
873
|
+
method: args2.method,
|
|
874
|
+
path: args2.path,
|
|
875
|
+
status: args2.status,
|
|
876
|
+
time: args2.timeInMS
|
|
799
877
|
});
|
|
800
878
|
},
|
|
801
879
|
[addLog]
|
|
@@ -1065,12 +1143,12 @@ function Footer() {
|
|
|
1065
1143
|
|
|
1066
1144
|
// src/cli.tsx
|
|
1067
1145
|
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1068
|
-
function App({ command
|
|
1069
|
-
switch (
|
|
1146
|
+
function App({ command, args }) {
|
|
1147
|
+
switch (command) {
|
|
1070
1148
|
case "login":
|
|
1071
|
-
return /* @__PURE__ */ jsx4(LoginCommand, { args
|
|
1149
|
+
return /* @__PURE__ */ jsx4(LoginCommand, { args });
|
|
1072
1150
|
case "start":
|
|
1073
|
-
return /* @__PURE__ */ jsx4(StartCommand, { args
|
|
1151
|
+
return /* @__PURE__ */ jsx4(StartCommand, { args });
|
|
1074
1152
|
case "help":
|
|
1075
1153
|
case "--help":
|
|
1076
1154
|
case "-h":
|
|
@@ -1080,25 +1158,785 @@ function App({ command: command2, args: args2 }) {
|
|
|
1080
1158
|
case "-v":
|
|
1081
1159
|
return /* @__PURE__ */ jsx4(VersionCommand, {});
|
|
1082
1160
|
default:
|
|
1083
|
-
return /* @__PURE__ */ jsx4(UnknownCommand, { command
|
|
1161
|
+
return /* @__PURE__ */ jsx4(UnknownCommand, { command });
|
|
1084
1162
|
}
|
|
1085
1163
|
}
|
|
1086
1164
|
function VersionCommand() {
|
|
1087
1165
|
return /* @__PURE__ */ jsx4(Box4, { children: /* @__PURE__ */ jsx4(Text4, { children: "ollie v0.1.0" }) });
|
|
1088
1166
|
}
|
|
1089
|
-
function UnknownCommand({ command
|
|
1167
|
+
function UnknownCommand({ command }) {
|
|
1090
1168
|
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", gap: 1, children: [
|
|
1091
1169
|
/* @__PURE__ */ jsxs4(Text4, { color: "red", children: [
|
|
1092
1170
|
"Unknown command: ",
|
|
1093
|
-
|
|
1171
|
+
command
|
|
1094
1172
|
] }),
|
|
1095
1173
|
/* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "Run `ollie help` for available commands." })
|
|
1096
1174
|
] });
|
|
1097
1175
|
}
|
|
1098
1176
|
|
|
1177
|
+
// src/core/schema.ts
|
|
1178
|
+
import { z as z2 } from "zod";
|
|
1179
|
+
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
1180
|
+
var PLATFORM_VENDORS = ["vtex", "shopify", "vnda", "custom"];
|
|
1181
|
+
var storeCreateSchema = z2.object({
|
|
1182
|
+
name: z2.string().min(1).describe("Store display name"),
|
|
1183
|
+
platform: z2.enum(PLATFORM_VENDORS).describe("E-commerce platform vendor"),
|
|
1184
|
+
platformStoreId: z2.string().min(1).describe("Platform-specific store identifier (e.g. account name)"),
|
|
1185
|
+
logo: z2.string().url().optional().describe("Store logo URL"),
|
|
1186
|
+
settings: z2.string().optional().describe("JSON settings string")
|
|
1187
|
+
});
|
|
1188
|
+
var storeListSchema = z2.object({}).describe("No parameters required");
|
|
1189
|
+
var versionCreateSchema = z2.object({
|
|
1190
|
+
storeId: z2.string().uuid().describe("Parent store UUID"),
|
|
1191
|
+
name: z2.string().min(1).describe("Version name (e.g. v1, main)"),
|
|
1192
|
+
active: z2.boolean().default(false).describe("Whether version is active"),
|
|
1193
|
+
default: z2.boolean().default(false).describe("Whether this is the default version"),
|
|
1194
|
+
template: z2.string().nullable().default(null).describe("Template name or null")
|
|
1195
|
+
});
|
|
1196
|
+
var versionListSchema = z2.object({
|
|
1197
|
+
storeId: z2.string().uuid().describe("Store UUID to list versions for")
|
|
1198
|
+
});
|
|
1199
|
+
var componentCreateSchema = z2.object({
|
|
1200
|
+
versionId: z2.string().uuid().describe("Parent version UUID"),
|
|
1201
|
+
name: z2.string().min(1).describe("Component name (e.g. FreeShippingBar)"),
|
|
1202
|
+
slot: z2.string().min(1).describe(
|
|
1203
|
+
"Target slot (e.g. cart_header_full_page, shipping_address_details_form)"
|
|
1204
|
+
),
|
|
1205
|
+
active: z2.boolean().default(true).describe("Whether component is active"),
|
|
1206
|
+
props: z2.record(z2.unknown()).nullable().default(null).describe("Default component props as JSON object")
|
|
1207
|
+
});
|
|
1208
|
+
var componentListSchema = z2.object({
|
|
1209
|
+
storeId: z2.string().uuid().describe("Store UUID"),
|
|
1210
|
+
versionId: z2.string().uuid().optional().describe("Optional version UUID to filter by")
|
|
1211
|
+
});
|
|
1212
|
+
var functionCreateSchema = z2.object({
|
|
1213
|
+
versionId: z2.string().uuid().describe("Parent version UUID"),
|
|
1214
|
+
name: z2.string().min(1).describe("Function name"),
|
|
1215
|
+
trigger: z2.string().min(1).describe("Function trigger (e.g. beforePayment, afterShipping)"),
|
|
1216
|
+
active: z2.boolean().default(true).describe("Whether function is active")
|
|
1217
|
+
});
|
|
1218
|
+
var functionListSchema = z2.object({
|
|
1219
|
+
versionId: z2.string().uuid().describe("Version UUID to list functions for")
|
|
1220
|
+
});
|
|
1221
|
+
var schemas = {
|
|
1222
|
+
store: {
|
|
1223
|
+
create: storeCreateSchema,
|
|
1224
|
+
list: storeListSchema
|
|
1225
|
+
},
|
|
1226
|
+
version: {
|
|
1227
|
+
create: versionCreateSchema,
|
|
1228
|
+
list: versionListSchema
|
|
1229
|
+
},
|
|
1230
|
+
component: {
|
|
1231
|
+
create: componentCreateSchema,
|
|
1232
|
+
list: componentListSchema
|
|
1233
|
+
},
|
|
1234
|
+
function: {
|
|
1235
|
+
create: functionCreateSchema,
|
|
1236
|
+
list: functionListSchema
|
|
1237
|
+
}
|
|
1238
|
+
};
|
|
1239
|
+
function getSchemaNames() {
|
|
1240
|
+
const names = [];
|
|
1241
|
+
for (const [resource, actions] of Object.entries(schemas)) {
|
|
1242
|
+
names.push(resource);
|
|
1243
|
+
for (const action of Object.keys(actions)) {
|
|
1244
|
+
names.push(`${resource}.${action}`);
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
return names;
|
|
1248
|
+
}
|
|
1249
|
+
function getJsonSchema(name) {
|
|
1250
|
+
const parts = name.split(".");
|
|
1251
|
+
const resource = parts[0];
|
|
1252
|
+
const action = parts[1];
|
|
1253
|
+
if (!resource || !schemas[resource]) return null;
|
|
1254
|
+
if (action) {
|
|
1255
|
+
const schema = schemas[resource][action];
|
|
1256
|
+
if (!schema) return null;
|
|
1257
|
+
return zodToJsonSchema(schema, { name: `${resource}.${action}` });
|
|
1258
|
+
}
|
|
1259
|
+
const result = {};
|
|
1260
|
+
for (const [actionName, schema] of Object.entries(schemas[resource])) {
|
|
1261
|
+
result[actionName] = zodToJsonSchema(schema, {
|
|
1262
|
+
name: `${resource}.${actionName}`
|
|
1263
|
+
});
|
|
1264
|
+
}
|
|
1265
|
+
return result;
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
// src/core/component.ts
|
|
1269
|
+
async function createComponent(client, input) {
|
|
1270
|
+
const parsed2 = componentCreateSchema.safeParse(input);
|
|
1271
|
+
if (!parsed2.success) {
|
|
1272
|
+
return {
|
|
1273
|
+
error: { message: parsed2.error.issues.map((i) => i.message).join("; ") }
|
|
1274
|
+
};
|
|
1275
|
+
}
|
|
1276
|
+
const { data, error } = await client.from("components").insert({
|
|
1277
|
+
name: parsed2.data.name,
|
|
1278
|
+
slot: parsed2.data.slot,
|
|
1279
|
+
active: parsed2.data.active,
|
|
1280
|
+
version_id: parsed2.data.versionId,
|
|
1281
|
+
props: parsed2.data.props
|
|
1282
|
+
}).select("id").single();
|
|
1283
|
+
if (error) {
|
|
1284
|
+
return { error: { message: error.message } };
|
|
1285
|
+
}
|
|
1286
|
+
return { data: { id: data.id } };
|
|
1287
|
+
}
|
|
1288
|
+
async function listComponents(client, storeId, versionId) {
|
|
1289
|
+
let query = client.from("components").select(
|
|
1290
|
+
"id, name, slot, active, version_id, props, created_at, versions!inner(id, name)"
|
|
1291
|
+
).eq("versions.store_id", storeId);
|
|
1292
|
+
if (versionId) {
|
|
1293
|
+
query = query.eq("versions.id", versionId);
|
|
1294
|
+
}
|
|
1295
|
+
const { data, error } = await query;
|
|
1296
|
+
if (error) {
|
|
1297
|
+
return { error: { message: error.message } };
|
|
1298
|
+
}
|
|
1299
|
+
return { data: data ?? [] };
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
// src/utils/output.ts
|
|
1303
|
+
function detectOutputFormat(cliOutput) {
|
|
1304
|
+
if (cliOutput === "json" || cliOutput === "j") return "json";
|
|
1305
|
+
if (cliOutput === "pretty") return "pretty";
|
|
1306
|
+
return process.stdout.isTTY ? "pretty" : "json";
|
|
1307
|
+
}
|
|
1308
|
+
function filterFields(data, fields) {
|
|
1309
|
+
if (!fields || fields.length === 0) return data;
|
|
1310
|
+
const result = {};
|
|
1311
|
+
for (const field of fields) {
|
|
1312
|
+
if (field in data) {
|
|
1313
|
+
result[field] = data[field];
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
return result;
|
|
1317
|
+
}
|
|
1318
|
+
function outputResult(result, format, fields) {
|
|
1319
|
+
if (format === "json") {
|
|
1320
|
+
let output = result;
|
|
1321
|
+
if (fields && result.data && typeof result.data === "object") {
|
|
1322
|
+
if (Array.isArray(result.data)) {
|
|
1323
|
+
output = {
|
|
1324
|
+
...result,
|
|
1325
|
+
data: result.data.map(
|
|
1326
|
+
(item) => filterFields(item, fields)
|
|
1327
|
+
)
|
|
1328
|
+
};
|
|
1329
|
+
} else {
|
|
1330
|
+
output = {
|
|
1331
|
+
...result,
|
|
1332
|
+
data: filterFields(result.data, fields)
|
|
1333
|
+
};
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
process.stdout.write(`${JSON.stringify(output)}
|
|
1337
|
+
`);
|
|
1338
|
+
return;
|
|
1339
|
+
}
|
|
1340
|
+
if (result.error) {
|
|
1341
|
+
const errMsg = typeof result.error === "object" && result.error !== null ? result.error.message || JSON.stringify(result.error) : String(result.error);
|
|
1342
|
+
console.error(`\x1B[31mError:\x1B[0m ${errMsg}`);
|
|
1343
|
+
return;
|
|
1344
|
+
}
|
|
1345
|
+
if (Array.isArray(result.data)) {
|
|
1346
|
+
printTable(result.data, fields);
|
|
1347
|
+
} else if (typeof result.data === "object" && result.data !== null) {
|
|
1348
|
+
const filtered = fields ? filterFields(result.data, fields) : result.data;
|
|
1349
|
+
for (const [key, value] of Object.entries(
|
|
1350
|
+
filtered
|
|
1351
|
+
)) {
|
|
1352
|
+
console.log(`\x1B[1m${key}:\x1B[0m ${value}`);
|
|
1353
|
+
}
|
|
1354
|
+
} else {
|
|
1355
|
+
console.log(result.data);
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
function printTable(rows, fields) {
|
|
1359
|
+
if (rows.length === 0) {
|
|
1360
|
+
console.log("(no results)");
|
|
1361
|
+
return;
|
|
1362
|
+
}
|
|
1363
|
+
const keys = fields || Object.keys(rows[0]);
|
|
1364
|
+
const widths = {};
|
|
1365
|
+
for (const key of keys) {
|
|
1366
|
+
widths[key] = key.length;
|
|
1367
|
+
for (const row of rows) {
|
|
1368
|
+
const val = String(row[key] ?? "");
|
|
1369
|
+
widths[key] = Math.max(widths[key], val.length);
|
|
1370
|
+
}
|
|
1371
|
+
widths[key] = Math.min(widths[key], 40);
|
|
1372
|
+
}
|
|
1373
|
+
const header = keys.map((k) => k.padEnd(widths[k])).join(" ");
|
|
1374
|
+
console.log(`\x1B[1m${header}\x1B[0m`);
|
|
1375
|
+
console.log(keys.map((k) => "\u2500".repeat(widths[k])).join("\u2500\u2500"));
|
|
1376
|
+
for (const row of rows) {
|
|
1377
|
+
const line = keys.map(
|
|
1378
|
+
(k) => String(row[k] ?? "").padEnd(widths[k]).slice(0, widths[k])
|
|
1379
|
+
).join(" ");
|
|
1380
|
+
console.log(line);
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
function outputDryRun(action, data, format) {
|
|
1384
|
+
if (format === "json") {
|
|
1385
|
+
process.stdout.write(`${JSON.stringify({ dryRun: true, action, data })}
|
|
1386
|
+
`);
|
|
1387
|
+
} else {
|
|
1388
|
+
console.log(`\x1B[33m[dry-run]\x1B[0m Would execute: ${action}`);
|
|
1389
|
+
for (const [key, value] of Object.entries(data)) {
|
|
1390
|
+
console.log(` ${key}: ${JSON.stringify(value)}`);
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
// src/utils/parse-args.ts
|
|
1396
|
+
function parseArgs(argv) {
|
|
1397
|
+
const args = argv.slice(2);
|
|
1398
|
+
const command = args[0] || "help";
|
|
1399
|
+
const flags = {};
|
|
1400
|
+
const positional = [];
|
|
1401
|
+
let subcommand;
|
|
1402
|
+
if (args[1] && !args[1].startsWith("-")) {
|
|
1403
|
+
subcommand = args[1];
|
|
1404
|
+
}
|
|
1405
|
+
const startIdx = subcommand ? 2 : 1;
|
|
1406
|
+
for (let i = startIdx; i < args.length; i++) {
|
|
1407
|
+
const arg = args[i];
|
|
1408
|
+
if (arg.startsWith("--")) {
|
|
1409
|
+
const key = arg.slice(2);
|
|
1410
|
+
const next = args[i + 1];
|
|
1411
|
+
if (next && !next.startsWith("-")) {
|
|
1412
|
+
flags[key] = next;
|
|
1413
|
+
i++;
|
|
1414
|
+
} else {
|
|
1415
|
+
flags[key] = true;
|
|
1416
|
+
}
|
|
1417
|
+
} else if (arg.startsWith("-") && arg.length === 2) {
|
|
1418
|
+
const key = arg.slice(1);
|
|
1419
|
+
const next = args[i + 1];
|
|
1420
|
+
if (next && !next.startsWith("-")) {
|
|
1421
|
+
flags[key] = next;
|
|
1422
|
+
i++;
|
|
1423
|
+
} else {
|
|
1424
|
+
flags[key] = true;
|
|
1425
|
+
}
|
|
1426
|
+
} else {
|
|
1427
|
+
positional.push(arg);
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
const global = {
|
|
1431
|
+
output: flags.output || flags.o || void 0,
|
|
1432
|
+
dryRun: flags["dry-run"] === true,
|
|
1433
|
+
fields: flags.fields ? String(flags.fields).split(",").map((f) => f.trim()) : void 0,
|
|
1434
|
+
data: flags.data || flags.d || void 0
|
|
1435
|
+
};
|
|
1436
|
+
return { command, subcommand, flags, global, positional };
|
|
1437
|
+
}
|
|
1438
|
+
function getFlag(flags, ...names) {
|
|
1439
|
+
for (const name of names) {
|
|
1440
|
+
const val = flags[name];
|
|
1441
|
+
if (typeof val === "string") return val;
|
|
1442
|
+
}
|
|
1443
|
+
return void 0;
|
|
1444
|
+
}
|
|
1445
|
+
function getBoolFlag(flags, ...names) {
|
|
1446
|
+
for (const name of names) {
|
|
1447
|
+
if (flags[name] === true) return true;
|
|
1448
|
+
}
|
|
1449
|
+
return false;
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
// src/utils/supabase.ts
|
|
1453
|
+
import { createClient } from "@supabase/supabase-js";
|
|
1454
|
+
function requireEnv(name) {
|
|
1455
|
+
const value = process.env[name];
|
|
1456
|
+
if (!value) {
|
|
1457
|
+
throw new Error(
|
|
1458
|
+
`Missing required environment variable: ${name}. Set it in your .env file or shell.`
|
|
1459
|
+
);
|
|
1460
|
+
}
|
|
1461
|
+
return value;
|
|
1462
|
+
}
|
|
1463
|
+
async function getAuthenticatedClient() {
|
|
1464
|
+
const credentials = await getCredentials();
|
|
1465
|
+
if (!credentials) {
|
|
1466
|
+
throw new Error("Not authenticated. Run `ollieshop login` first.");
|
|
1467
|
+
}
|
|
1468
|
+
const supabaseUrl = requireEnv("OLLIE_SUPABASE_URL");
|
|
1469
|
+
const supabaseAnonKey = requireEnv("OLLIE_SUPABASE_ANON_KEY");
|
|
1470
|
+
const client = createClient(supabaseUrl, supabaseAnonKey, {
|
|
1471
|
+
auth: {
|
|
1472
|
+
autoRefreshToken: false,
|
|
1473
|
+
persistSession: false
|
|
1474
|
+
}
|
|
1475
|
+
});
|
|
1476
|
+
await client.auth.setSession({
|
|
1477
|
+
access_token: credentials.accessToken,
|
|
1478
|
+
refresh_token: credentials.refreshToken
|
|
1479
|
+
});
|
|
1480
|
+
return client;
|
|
1481
|
+
}
|
|
1482
|
+
async function getOrganizationId(client) {
|
|
1483
|
+
const { data: org, error } = await client.from("organizations").select("id").order("created_at", { ascending: true }).limit(1).maybeSingle();
|
|
1484
|
+
if (error) {
|
|
1485
|
+
throw new Error(`Failed to get organization: ${error.message}`);
|
|
1486
|
+
}
|
|
1487
|
+
if (!org) {
|
|
1488
|
+
throw new Error(
|
|
1489
|
+
"No organization found for your account. Create one at https://admin.ollie.shop"
|
|
1490
|
+
);
|
|
1491
|
+
}
|
|
1492
|
+
return org.id;
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
// src/utils/validate.ts
|
|
1496
|
+
var UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1497
|
+
var CONTROL_CHAR_REGEX = /[\x00-\x1f\x7f]/;
|
|
1498
|
+
function validateUuid(value, name) {
|
|
1499
|
+
if (!UUID_REGEX.test(value)) {
|
|
1500
|
+
throw new Error(
|
|
1501
|
+
`Invalid ${name}: "${value}". Must be a valid UUID (e.g. 7217542a-d7c6-40d3-a20e-db13b310a781).`
|
|
1502
|
+
);
|
|
1503
|
+
}
|
|
1504
|
+
return value;
|
|
1505
|
+
}
|
|
1506
|
+
function rejectControlChars(value, name) {
|
|
1507
|
+
if (CONTROL_CHAR_REGEX.test(value)) {
|
|
1508
|
+
throw new Error(
|
|
1509
|
+
`Invalid ${name}: contains control characters. Input must be printable text.`
|
|
1510
|
+
);
|
|
1511
|
+
}
|
|
1512
|
+
return value;
|
|
1513
|
+
}
|
|
1514
|
+
function validateEnum(value, allowed, name) {
|
|
1515
|
+
if (!allowed.includes(value)) {
|
|
1516
|
+
throw new Error(
|
|
1517
|
+
`Invalid ${name}: "${value}". Must be one of: ${allowed.join(", ")}`
|
|
1518
|
+
);
|
|
1519
|
+
}
|
|
1520
|
+
return value;
|
|
1521
|
+
}
|
|
1522
|
+
function validateRequired(value, name) {
|
|
1523
|
+
if (!value || value.trim() === "") {
|
|
1524
|
+
throw new Error(`Missing required parameter: --${name}`);
|
|
1525
|
+
}
|
|
1526
|
+
return rejectControlChars(value.trim(), name);
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
// src/commands/component-cmd.ts
|
|
1530
|
+
async function componentCommand(parsed2) {
|
|
1531
|
+
const sub = parsed2.subcommand;
|
|
1532
|
+
if (sub === "create") return componentCreateCommand(parsed2);
|
|
1533
|
+
if (sub === "list" || sub === "ls") return componentListCommand(parsed2);
|
|
1534
|
+
console.error(
|
|
1535
|
+
`Unknown component subcommand: ${sub}. Use: component create | component list`
|
|
1536
|
+
);
|
|
1537
|
+
process.exit(1);
|
|
1538
|
+
}
|
|
1539
|
+
async function componentCreateCommand(parsed2) {
|
|
1540
|
+
const format = detectOutputFormat(parsed2.global.output);
|
|
1541
|
+
try {
|
|
1542
|
+
let input;
|
|
1543
|
+
if (parsed2.global.data) {
|
|
1544
|
+
const raw = JSON.parse(parsed2.global.data);
|
|
1545
|
+
input = {
|
|
1546
|
+
versionId: validateUuid(raw.versionId, "versionId"),
|
|
1547
|
+
name: validateRequired(raw.name, "name"),
|
|
1548
|
+
slot: validateRequired(raw.slot, "slot"),
|
|
1549
|
+
active: raw.active ?? true,
|
|
1550
|
+
props: raw.props ?? null
|
|
1551
|
+
};
|
|
1552
|
+
} else {
|
|
1553
|
+
input = {
|
|
1554
|
+
versionId: validateUuid(
|
|
1555
|
+
validateRequired(getFlag(parsed2.flags, "version-id"), "version-id"),
|
|
1556
|
+
"version-id"
|
|
1557
|
+
),
|
|
1558
|
+
name: validateRequired(getFlag(parsed2.flags, "name", "n"), "name"),
|
|
1559
|
+
slot: validateRequired(getFlag(parsed2.flags, "slot", "s"), "slot"),
|
|
1560
|
+
active: getBoolFlag(parsed2.flags, "active") || !("active" in parsed2.flags),
|
|
1561
|
+
props: null
|
|
1562
|
+
};
|
|
1563
|
+
}
|
|
1564
|
+
if (parsed2.global.dryRun) {
|
|
1565
|
+
outputDryRun(
|
|
1566
|
+
"component.create",
|
|
1567
|
+
input,
|
|
1568
|
+
format
|
|
1569
|
+
);
|
|
1570
|
+
return;
|
|
1571
|
+
}
|
|
1572
|
+
const client = await getAuthenticatedClient();
|
|
1573
|
+
const result = await createComponent(client, input);
|
|
1574
|
+
outputResult(result, format, parsed2.global.fields);
|
|
1575
|
+
if (result.error) process.exit(1);
|
|
1576
|
+
} catch (err) {
|
|
1577
|
+
outputResult(
|
|
1578
|
+
{
|
|
1579
|
+
error: { message: err instanceof Error ? err.message : String(err) }
|
|
1580
|
+
},
|
|
1581
|
+
format
|
|
1582
|
+
);
|
|
1583
|
+
process.exit(1);
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
async function componentListCommand(parsed2) {
|
|
1587
|
+
const format = detectOutputFormat(parsed2.global.output);
|
|
1588
|
+
try {
|
|
1589
|
+
const storeId = validateUuid(
|
|
1590
|
+
validateRequired(getFlag(parsed2.flags, "store-id"), "store-id"),
|
|
1591
|
+
"store-id"
|
|
1592
|
+
);
|
|
1593
|
+
const versionId = getFlag(parsed2.flags, "version-id");
|
|
1594
|
+
if (versionId) validateUuid(versionId, "version-id");
|
|
1595
|
+
const client = await getAuthenticatedClient();
|
|
1596
|
+
const result = await listComponents(client, storeId, versionId);
|
|
1597
|
+
outputResult(result, format, parsed2.global.fields);
|
|
1598
|
+
if (result.error) process.exit(1);
|
|
1599
|
+
} catch (err) {
|
|
1600
|
+
outputResult(
|
|
1601
|
+
{
|
|
1602
|
+
error: { message: err instanceof Error ? err.message : String(err) }
|
|
1603
|
+
},
|
|
1604
|
+
format
|
|
1605
|
+
);
|
|
1606
|
+
process.exit(1);
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
// src/commands/init-cmd.ts
|
|
1611
|
+
async function initCommand(parsed2) {
|
|
1612
|
+
const format = detectOutputFormat(parsed2.global.output);
|
|
1613
|
+
try {
|
|
1614
|
+
const storeId = validateUuid(
|
|
1615
|
+
validateRequired(getFlag(parsed2.flags, "store-id"), "store-id"),
|
|
1616
|
+
"store-id"
|
|
1617
|
+
);
|
|
1618
|
+
const versionIdRaw = getFlag(parsed2.flags, "version-id");
|
|
1619
|
+
const versionId = versionIdRaw ? validateUuid(versionIdRaw, "version-id") : void 0;
|
|
1620
|
+
const stage = getFlag(parsed2.flags, "stage", "s");
|
|
1621
|
+
await saveConfig(
|
|
1622
|
+
{
|
|
1623
|
+
storeId,
|
|
1624
|
+
...versionId ? { versionId } : {}
|
|
1625
|
+
},
|
|
1626
|
+
{ stage }
|
|
1627
|
+
);
|
|
1628
|
+
const fileName = stage && stage !== "prod" ? `ollie.${stage}.json` : "ollie.json";
|
|
1629
|
+
outputResult(
|
|
1630
|
+
{
|
|
1631
|
+
data: {
|
|
1632
|
+
file: fileName,
|
|
1633
|
+
storeId,
|
|
1634
|
+
...versionId ? { versionId } : {}
|
|
1635
|
+
}
|
|
1636
|
+
},
|
|
1637
|
+
format,
|
|
1638
|
+
parsed2.global.fields
|
|
1639
|
+
);
|
|
1640
|
+
} catch (err) {
|
|
1641
|
+
outputResult(
|
|
1642
|
+
{
|
|
1643
|
+
error: { message: err instanceof Error ? err.message : String(err) }
|
|
1644
|
+
},
|
|
1645
|
+
format
|
|
1646
|
+
);
|
|
1647
|
+
process.exit(1);
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1651
|
+
// src/commands/schema-cmd.ts
|
|
1652
|
+
async function schemaCommand(parsed2) {
|
|
1653
|
+
const format = detectOutputFormat(parsed2.global.output);
|
|
1654
|
+
const resourceName = parsed2.subcommand || parsed2.positional[0];
|
|
1655
|
+
if (!resourceName) {
|
|
1656
|
+
const names = getSchemaNames();
|
|
1657
|
+
if (format === "json") {
|
|
1658
|
+
process.stdout.write(`${JSON.stringify({ schemas: names })}
|
|
1659
|
+
`);
|
|
1660
|
+
} else {
|
|
1661
|
+
console.log("\x1B[1mAvailable schemas:\x1B[0m");
|
|
1662
|
+
for (const name of names) {
|
|
1663
|
+
const indent = name.includes(".") ? " " : " ";
|
|
1664
|
+
console.log(`${indent}\x1B[32m${name}\x1B[0m`);
|
|
1665
|
+
}
|
|
1666
|
+
console.log("\nUsage: ollieshop schema <resource[.action]>");
|
|
1667
|
+
}
|
|
1668
|
+
return;
|
|
1669
|
+
}
|
|
1670
|
+
const schema = getJsonSchema(resourceName);
|
|
1671
|
+
if (!schema) {
|
|
1672
|
+
console.error(
|
|
1673
|
+
`Unknown schema: ${resourceName}. Run \`ollieshop schema\` to see available schemas.`
|
|
1674
|
+
);
|
|
1675
|
+
process.exit(1);
|
|
1676
|
+
}
|
|
1677
|
+
process.stdout.write(`${JSON.stringify(schema, null, 2)}
|
|
1678
|
+
`);
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
// src/core/store.ts
|
|
1682
|
+
async function createStore(client, input) {
|
|
1683
|
+
const parsed2 = storeCreateSchema.safeParse(input);
|
|
1684
|
+
if (!parsed2.success) {
|
|
1685
|
+
return {
|
|
1686
|
+
error: { message: parsed2.error.issues.map((i) => i.message).join("; ") }
|
|
1687
|
+
};
|
|
1688
|
+
}
|
|
1689
|
+
const organizationId = await getOrganizationId(client);
|
|
1690
|
+
const { data, error } = await client.from("stores").insert({
|
|
1691
|
+
name: parsed2.data.name,
|
|
1692
|
+
platform: parsed2.data.platform,
|
|
1693
|
+
platform_store_id: parsed2.data.platformStoreId,
|
|
1694
|
+
organization_id: organizationId,
|
|
1695
|
+
logo: parsed2.data.logo ?? null,
|
|
1696
|
+
settings: parsed2.data.settings ?? null
|
|
1697
|
+
}).select("id").single();
|
|
1698
|
+
if (error) {
|
|
1699
|
+
return { error: { message: error.message } };
|
|
1700
|
+
}
|
|
1701
|
+
return { data: { id: data.id } };
|
|
1702
|
+
}
|
|
1703
|
+
async function listStores(client) {
|
|
1704
|
+
const organizationId = await getOrganizationId(client);
|
|
1705
|
+
const { data, error } = await client.from("stores").select(
|
|
1706
|
+
"id, name, platform, platform_store_id, organization_id, logo, settings, created_at"
|
|
1707
|
+
).eq("organization_id", organizationId).order("created_at", { ascending: false });
|
|
1708
|
+
if (error) {
|
|
1709
|
+
return { error: { message: error.message } };
|
|
1710
|
+
}
|
|
1711
|
+
return { data };
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1714
|
+
// src/commands/store-cmd.ts
|
|
1715
|
+
async function storeCommand(parsed2) {
|
|
1716
|
+
const sub = parsed2.subcommand;
|
|
1717
|
+
if (sub === "create") return storeCreateCommand(parsed2);
|
|
1718
|
+
if (sub === "list" || sub === "ls") return storeListCommand(parsed2);
|
|
1719
|
+
console.error(
|
|
1720
|
+
`Unknown store subcommand: ${sub}. Use: store create | store list`
|
|
1721
|
+
);
|
|
1722
|
+
process.exit(1);
|
|
1723
|
+
}
|
|
1724
|
+
async function storeCreateCommand(parsed2) {
|
|
1725
|
+
const format = detectOutputFormat(parsed2.global.output);
|
|
1726
|
+
try {
|
|
1727
|
+
let input;
|
|
1728
|
+
if (parsed2.global.data) {
|
|
1729
|
+
const raw = JSON.parse(parsed2.global.data);
|
|
1730
|
+
input = {
|
|
1731
|
+
name: validateRequired(raw.name, "name"),
|
|
1732
|
+
platform: validateEnum(raw.platform, PLATFORM_VENDORS, "platform"),
|
|
1733
|
+
platformStoreId: validateRequired(
|
|
1734
|
+
raw.platformStoreId,
|
|
1735
|
+
"platformStoreId"
|
|
1736
|
+
),
|
|
1737
|
+
logo: raw.logo,
|
|
1738
|
+
settings: raw.settings
|
|
1739
|
+
};
|
|
1740
|
+
} else {
|
|
1741
|
+
input = {
|
|
1742
|
+
name: validateRequired(getFlag(parsed2.flags, "name", "n"), "name"),
|
|
1743
|
+
platform: validateEnum(
|
|
1744
|
+
validateRequired(getFlag(parsed2.flags, "platform", "p"), "platform"),
|
|
1745
|
+
PLATFORM_VENDORS,
|
|
1746
|
+
"platform"
|
|
1747
|
+
),
|
|
1748
|
+
platformStoreId: validateRequired(
|
|
1749
|
+
getFlag(parsed2.flags, "platform-store-id"),
|
|
1750
|
+
"platform-store-id"
|
|
1751
|
+
),
|
|
1752
|
+
logo: getFlag(parsed2.flags, "logo"),
|
|
1753
|
+
settings: getFlag(parsed2.flags, "settings")
|
|
1754
|
+
};
|
|
1755
|
+
}
|
|
1756
|
+
if (parsed2.global.dryRun) {
|
|
1757
|
+
outputDryRun("store.create", input, format);
|
|
1758
|
+
return;
|
|
1759
|
+
}
|
|
1760
|
+
const client = await getAuthenticatedClient();
|
|
1761
|
+
const result = await createStore(client, input);
|
|
1762
|
+
outputResult(result, format, parsed2.global.fields);
|
|
1763
|
+
if (result.error) process.exit(1);
|
|
1764
|
+
} catch (err) {
|
|
1765
|
+
outputResult(
|
|
1766
|
+
{
|
|
1767
|
+
error: { message: err instanceof Error ? err.message : String(err) }
|
|
1768
|
+
},
|
|
1769
|
+
format
|
|
1770
|
+
);
|
|
1771
|
+
process.exit(1);
|
|
1772
|
+
}
|
|
1773
|
+
}
|
|
1774
|
+
async function storeListCommand(parsed2) {
|
|
1775
|
+
const format = detectOutputFormat(parsed2.global.output);
|
|
1776
|
+
try {
|
|
1777
|
+
const client = await getAuthenticatedClient();
|
|
1778
|
+
const result = await listStores(client);
|
|
1779
|
+
outputResult(result, format, parsed2.global.fields);
|
|
1780
|
+
if (result.error) process.exit(1);
|
|
1781
|
+
} catch (err) {
|
|
1782
|
+
outputResult(
|
|
1783
|
+
{
|
|
1784
|
+
error: { message: err instanceof Error ? err.message : String(err) }
|
|
1785
|
+
},
|
|
1786
|
+
format
|
|
1787
|
+
);
|
|
1788
|
+
process.exit(1);
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1792
|
+
// src/core/version.ts
|
|
1793
|
+
async function createVersion(client, input) {
|
|
1794
|
+
const parsed2 = versionCreateSchema.safeParse(input);
|
|
1795
|
+
if (!parsed2.success) {
|
|
1796
|
+
return {
|
|
1797
|
+
error: { message: parsed2.error.issues.map((i) => i.message).join("; ") }
|
|
1798
|
+
};
|
|
1799
|
+
}
|
|
1800
|
+
const { data, error } = await client.from("versions").insert({
|
|
1801
|
+
name: parsed2.data.name,
|
|
1802
|
+
active: parsed2.data.active,
|
|
1803
|
+
default: parsed2.data.default,
|
|
1804
|
+
store_id: parsed2.data.storeId,
|
|
1805
|
+
template: parsed2.data.template
|
|
1806
|
+
}).select("id").single();
|
|
1807
|
+
if (error) {
|
|
1808
|
+
return { error: { message: error.message } };
|
|
1809
|
+
}
|
|
1810
|
+
return { data: { id: data.id } };
|
|
1811
|
+
}
|
|
1812
|
+
async function listVersions(client, storeId) {
|
|
1813
|
+
const { data, error } = await client.from("versions").select("id, name, active, default, store_id, template, created_at").eq("store_id", storeId).order("created_at", { ascending: false });
|
|
1814
|
+
if (error) {
|
|
1815
|
+
return { error: { message: error.message } };
|
|
1816
|
+
}
|
|
1817
|
+
return { data };
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
// src/commands/version-cmd.ts
|
|
1821
|
+
async function versionCommand(parsed2) {
|
|
1822
|
+
const sub = parsed2.subcommand;
|
|
1823
|
+
if (sub === "create") return versionCreateCommand(parsed2);
|
|
1824
|
+
if (sub === "list" || sub === "ls") return versionListCommand(parsed2);
|
|
1825
|
+
console.error(
|
|
1826
|
+
`Unknown version subcommand: ${sub}. Use: version create | version list`
|
|
1827
|
+
);
|
|
1828
|
+
process.exit(1);
|
|
1829
|
+
}
|
|
1830
|
+
async function versionCreateCommand(parsed2) {
|
|
1831
|
+
const format = detectOutputFormat(parsed2.global.output);
|
|
1832
|
+
try {
|
|
1833
|
+
let input;
|
|
1834
|
+
if (parsed2.global.data) {
|
|
1835
|
+
const raw = JSON.parse(parsed2.global.data);
|
|
1836
|
+
input = {
|
|
1837
|
+
storeId: validateUuid(raw.storeId, "storeId"),
|
|
1838
|
+
name: validateRequired(raw.name, "name"),
|
|
1839
|
+
active: raw.active ?? false,
|
|
1840
|
+
default: raw.default ?? false,
|
|
1841
|
+
template: raw.template ?? null
|
|
1842
|
+
};
|
|
1843
|
+
} else {
|
|
1844
|
+
input = {
|
|
1845
|
+
storeId: validateUuid(
|
|
1846
|
+
validateRequired(getFlag(parsed2.flags, "store-id"), "store-id"),
|
|
1847
|
+
"store-id"
|
|
1848
|
+
),
|
|
1849
|
+
name: validateRequired(getFlag(parsed2.flags, "name", "n"), "name"),
|
|
1850
|
+
active: getBoolFlag(parsed2.flags, "active"),
|
|
1851
|
+
default: getBoolFlag(parsed2.flags, "default"),
|
|
1852
|
+
template: getFlag(parsed2.flags, "template") ?? null
|
|
1853
|
+
};
|
|
1854
|
+
}
|
|
1855
|
+
if (parsed2.global.dryRun) {
|
|
1856
|
+
outputDryRun("version.create", input, format);
|
|
1857
|
+
return;
|
|
1858
|
+
}
|
|
1859
|
+
const client = await getAuthenticatedClient();
|
|
1860
|
+
const result = await createVersion(client, input);
|
|
1861
|
+
outputResult(result, format, parsed2.global.fields);
|
|
1862
|
+
if (result.error) process.exit(1);
|
|
1863
|
+
} catch (err) {
|
|
1864
|
+
outputResult(
|
|
1865
|
+
{
|
|
1866
|
+
error: { message: err instanceof Error ? err.message : String(err) }
|
|
1867
|
+
},
|
|
1868
|
+
format
|
|
1869
|
+
);
|
|
1870
|
+
process.exit(1);
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
async function versionListCommand(parsed2) {
|
|
1874
|
+
const format = detectOutputFormat(parsed2.global.output);
|
|
1875
|
+
try {
|
|
1876
|
+
const storeId = validateUuid(
|
|
1877
|
+
validateRequired(getFlag(parsed2.flags, "store-id"), "store-id"),
|
|
1878
|
+
"store-id"
|
|
1879
|
+
);
|
|
1880
|
+
const client = await getAuthenticatedClient();
|
|
1881
|
+
const result = await listVersions(client, storeId);
|
|
1882
|
+
outputResult(result, format, parsed2.global.fields);
|
|
1883
|
+
if (result.error) process.exit(1);
|
|
1884
|
+
} catch (err) {
|
|
1885
|
+
outputResult(
|
|
1886
|
+
{
|
|
1887
|
+
error: { message: err instanceof Error ? err.message : String(err) }
|
|
1888
|
+
},
|
|
1889
|
+
format
|
|
1890
|
+
);
|
|
1891
|
+
process.exit(1);
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
// src/commands/whoami.ts
|
|
1896
|
+
async function whoamiCommand(parsed2) {
|
|
1897
|
+
const format = detectOutputFormat(parsed2.global.output);
|
|
1898
|
+
const user = await getCurrentUser();
|
|
1899
|
+
if (!user) {
|
|
1900
|
+
outputResult(
|
|
1901
|
+
{
|
|
1902
|
+
error: { message: "Not logged in. Run `ollieshop login`." }
|
|
1903
|
+
},
|
|
1904
|
+
format
|
|
1905
|
+
);
|
|
1906
|
+
process.exit(1);
|
|
1907
|
+
}
|
|
1908
|
+
outputResult(
|
|
1909
|
+
{
|
|
1910
|
+
data: {
|
|
1911
|
+
email: user.email
|
|
1912
|
+
}
|
|
1913
|
+
},
|
|
1914
|
+
format,
|
|
1915
|
+
parsed2.global.fields
|
|
1916
|
+
);
|
|
1917
|
+
}
|
|
1918
|
+
|
|
1099
1919
|
// src/index.tsx
|
|
1100
1920
|
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
1101
|
-
var
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1921
|
+
var AGENT_COMMANDS = {
|
|
1922
|
+
whoami: whoamiCommand,
|
|
1923
|
+
store: storeCommand,
|
|
1924
|
+
version: versionCommand,
|
|
1925
|
+
component: componentCommand,
|
|
1926
|
+
schema: schemaCommand,
|
|
1927
|
+
init: initCommand
|
|
1928
|
+
};
|
|
1929
|
+
var parsed = parseArgs(process.argv);
|
|
1930
|
+
if (parsed.command in AGENT_COMMANDS) {
|
|
1931
|
+
AGENT_COMMANDS[parsed.command](parsed).catch((err) => {
|
|
1932
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1933
|
+
process.stderr.write(`${JSON.stringify({ error: { message: msg } })}
|
|
1934
|
+
`);
|
|
1935
|
+
process.exit(1);
|
|
1936
|
+
});
|
|
1937
|
+
} else {
|
|
1938
|
+
const args = process.argv.slice(2);
|
|
1939
|
+
const command = args[0] || "help";
|
|
1940
|
+
const commandArgs = args.slice(1);
|
|
1941
|
+
render(/* @__PURE__ */ jsx5(App, { command, args: commandArgs }));
|
|
1942
|
+
}
|