@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/dist/index.js CHANGED
@@ -21,49 +21,108 @@ 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: 16, children: /* @__PURE__ */ jsx(Text, { color: "green", children: "login" }) }),
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: 16, children: /* @__PURE__ */ jsx(Text, { color: "green", children: "start" }) }),
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" })
48
+ ] }),
49
+ /* @__PURE__ */ jsxs(Box, { children: [
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: "deploy" }) }),
55
+ /* @__PURE__ */ jsx(Text, { children: "Bundle and upload a component/function build" })
33
56
  ] }),
34
57
  /* @__PURE__ */ jsxs(Box, { children: [
35
- /* @__PURE__ */ jsx(Box, { width: 16, children: /* @__PURE__ */ jsx(Text, { color: "green", children: "help" }) }),
58
+ /* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsx(Text, { color: "green", children: "status" }) }),
59
+ /* @__PURE__ */ jsx(Text, { children: "Check or poll a build status" })
60
+ ] }),
61
+ /* @__PURE__ */ jsxs(Box, { children: [
62
+ /* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsx(Text, { color: "green", children: "schema" }) }),
63
+ /* @__PURE__ */ jsx(Text, { children: "Introspect resource schemas (JSON Schema)" })
64
+ ] }),
65
+ /* @__PURE__ */ jsxs(Box, { children: [
66
+ /* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsx(Text, { color: "green", children: "init" }) }),
67
+ /* @__PURE__ */ jsx(Text, { children: "Write store/version IDs to ollie.json" })
68
+ ] }),
69
+ /* @__PURE__ */ jsxs(Box, { children: [
70
+ /* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsx(Text, { color: "green", children: "help" }) }),
36
71
  /* @__PURE__ */ jsx(Text, { children: "Show this help message" })
37
72
  ] }),
38
73
  /* @__PURE__ */ jsxs(Box, { children: [
39
- /* @__PURE__ */ jsx(Box, { width: 16, children: /* @__PURE__ */ jsx(Text, { color: "green", children: "version" }) }),
74
+ /* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsx(Text, { color: "green", children: "version" }) }),
40
75
  /* @__PURE__ */ jsx(Text, { children: "Show CLI version" })
41
76
  ] })
42
77
  ] }),
43
- /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, children: "Start Options:" }) }),
44
- /* @__PURE__ */ jsx(Box, { marginLeft: 2, flexDirection: "column", gap: 0, children: /* @__PURE__ */ jsxs(Box, { children: [
45
- /* @__PURE__ */ jsx(Box, { width: 20, children: /* @__PURE__ */ jsx(Text, { color: "yellow", children: "--stage, -s" }) }),
46
- /* @__PURE__ */ jsxs(Text, { children: [
47
- "Config stage (loads ollie.",
48
- "{stage}",
49
- ".json)"
50
- ] })
51
- ] }) }),
52
- /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, children: "Configuration:" }) }),
53
- /* @__PURE__ */ jsxs(Box, { marginLeft: 2, flexDirection: "column", children: [
54
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "ollie.json - Default config (prod)" }),
55
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "ollie.dev.json - Dev stage config" }),
56
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
57
- "ollie.",
58
- "{stage}",
59
- ".json - Custom stage config"
78
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, children: "Global Flags:" }) }),
79
+ /* @__PURE__ */ jsxs(Box, { marginLeft: 2, flexDirection: "column", gap: 0, children: [
80
+ /* @__PURE__ */ jsxs(Box, { children: [
81
+ /* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsx(Text, { color: "yellow", children: "--output json, -o json" }) }),
82
+ /* @__PURE__ */ jsx(Text, { children: "Force JSON output (auto when piped)" })
83
+ ] }),
84
+ /* @__PURE__ */ jsxs(Box, { children: [
85
+ /* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsx(Text, { color: "yellow", children: "--dry-run" }) }),
86
+ /* @__PURE__ */ jsx(Text, { children: "Validate without executing mutations" })
87
+ ] }),
88
+ /* @__PURE__ */ jsxs(Box, { children: [
89
+ /* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsx(Text, { color: "yellow", children: "--fields a,b,c" }) }),
90
+ /* @__PURE__ */ jsx(Text, { children: "Limit output fields" })
91
+ ] }),
92
+ /* @__PURE__ */ jsxs(Box, { children: [
93
+ /* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
94
+ "--data ",
95
+ `'{...}'`
96
+ ] }) }),
97
+ /* @__PURE__ */ jsx(Text, { children: "Raw JSON payload for mutations" })
98
+ ] }),
99
+ /* @__PURE__ */ jsxs(Box, { children: [
100
+ /* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsx(Text, { color: "yellow", children: "--stage, -s" }) }),
101
+ /* @__PURE__ */ jsxs(Text, { children: [
102
+ "Config stage (loads ollie.",
103
+ "{stage}",
104
+ ".json)"
105
+ ] })
60
106
  ] })
61
107
  ] }),
62
108
  /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, children: "Examples:" }) }),
63
109
  /* @__PURE__ */ jsxs(Box, { marginLeft: 2, flexDirection: "column", children: [
64
110
  /* @__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 start --stage dev" })
111
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "$ ollieshop start --stage dev" }),
112
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "$ ollieshop whoami -o json" }),
113
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "$ ollieshop schema store.create" }),
114
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: '$ ollieshop store create --name "My Store" --platform vtex --platform-store-id mystore' }),
115
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
116
+ "$ ollieshop store create --data",
117
+ " ",
118
+ `'{"name":"My Store","platform":"vtex","platformStoreId":"mystore"}'`,
119
+ " ",
120
+ "-o json"
121
+ ] }),
122
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "$ ollieshop version create --store-id UUID --name v1 --active" }),
123
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "$ ollieshop init --store-id UUID --version-id UUID" }),
124
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "$ ollieshop deploy --component-id UUID --name FreeShippingBar --wait" }),
125
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "$ ollieshop status --build-id BUILD_ID --wait -o json" })
67
126
  ] })
68
127
  ] });
69
128
  }
@@ -227,14 +286,32 @@ async function saveCredentials(token) {
227
286
  };
228
287
  await fs.writeFile(CREDENTIALS_PATH, JSON.stringify(credentials, null, 2));
229
288
  }
289
+ async function getCredentials() {
290
+ try {
291
+ const content = await fs.readFile(CREDENTIALS_PATH, "utf-8");
292
+ return JSON.parse(content);
293
+ } catch {
294
+ return null;
295
+ }
296
+ }
297
+ async function getCurrentUser() {
298
+ const credentials = await getCredentials();
299
+ if (!credentials) return null;
300
+ try {
301
+ const decoded = jwtDecode(credentials.accessToken);
302
+ return decoded.email ? { email: decoded.email } : null;
303
+ } catch {
304
+ return null;
305
+ }
306
+ }
230
307
 
231
308
  // src/commands/login.tsx
232
309
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
233
- function LoginCommand({ args: args2 }) {
310
+ function LoginCommand({ args }) {
234
311
  const { exit } = useApp();
235
312
  const [state, setState] = useState({ status: "idle" });
236
- const portIndex = args2.findIndex((a) => a === "--port" || a === "-p");
237
- const port = portIndex !== -1 ? Number.parseInt(args2[portIndex + 1], 10) : 7777;
313
+ const portIndex = args.findIndex((a) => a === "--port" || a === "-p");
314
+ const port = portIndex !== -1 ? Number.parseInt(args[portIndex + 1], 10) : 7777;
238
315
  useEffect(() => {
239
316
  if (state.status !== "idle") return;
240
317
  setState({ status: "waiting" });
@@ -341,6 +418,17 @@ async function loadConfig(options = {}) {
341
418
  };
342
419
  return OllieConfigSchema.parse(merged);
343
420
  }
421
+ async function saveConfig(config, options = {}) {
422
+ const { cwd = process.cwd(), stage } = options;
423
+ const fileName = getConfigFileName(stage);
424
+ const configPath = path2.join(cwd, fileName);
425
+ const existing = await loadConfigFile(configPath);
426
+ const merged = {
427
+ ...existing,
428
+ ...config
429
+ };
430
+ await fs2.writeFile(configPath, JSON.stringify(merged, null, 2));
431
+ }
344
432
  function resolveStage(cliStage) {
345
433
  return cliStage || process.env.OLLIE_STAGE || void 0;
346
434
  }
@@ -764,11 +852,11 @@ import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
764
852
  var STUDIO_BASE_URL = "https://admin.ollie.shop/studio";
765
853
  var MAX_LOGS = 10;
766
854
  var PORT = 4e3;
767
- function parseArg(args2, ...flags) {
768
- const index = args2.findIndex((a) => flags.includes(a));
769
- return index !== -1 ? args2[index + 1] : void 0;
855
+ function parseArg(args, ...flags) {
856
+ const index = args.findIndex((a) => flags.includes(a));
857
+ return index !== -1 ? args[index + 1] : void 0;
770
858
  }
771
- function StartCommand({ args: args2 }) {
859
+ function StartCommand({ args }) {
772
860
  const { exit } = useApp2();
773
861
  const [state, setState] = useState2({ status: "initializing" });
774
862
  const [components, setComponents] = useState2([]);
@@ -778,7 +866,7 @@ function StartCommand({ args: args2 }) {
778
866
  const logIdRef = useRef(0);
779
867
  const ctxRef = useRef(null);
780
868
  const stopRef = useRef(null);
781
- const stage = resolveStage(parseArg(args2, "--stage", "-s"));
869
+ const stage = resolveStage(parseArg(args, "--stage", "-s"));
782
870
  const addLog = useCallback((log) => {
783
871
  setLogs((prev) => {
784
872
  const newLog = {
@@ -790,12 +878,12 @@ function StartCommand({ args: args2 }) {
790
878
  });
791
879
  }, []);
792
880
  const handleRequest = useCallback(
793
- (args3) => {
881
+ (args2) => {
794
882
  addLog({
795
- method: args3.method,
796
- path: args3.path,
797
- status: args3.status,
798
- time: args3.timeInMS
883
+ method: args2.method,
884
+ path: args2.path,
885
+ status: args2.status,
886
+ time: args2.timeInMS
799
887
  });
800
888
  },
801
889
  [addLog]
@@ -1065,12 +1153,12 @@ function Footer() {
1065
1153
 
1066
1154
  // src/cli.tsx
1067
1155
  import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1068
- function App({ command: command2, args: args2 }) {
1069
- switch (command2) {
1156
+ function App({ command, args }) {
1157
+ switch (command) {
1070
1158
  case "login":
1071
- return /* @__PURE__ */ jsx4(LoginCommand, { args: args2 });
1159
+ return /* @__PURE__ */ jsx4(LoginCommand, { args });
1072
1160
  case "start":
1073
- return /* @__PURE__ */ jsx4(StartCommand, { args: args2 });
1161
+ return /* @__PURE__ */ jsx4(StartCommand, { args });
1074
1162
  case "help":
1075
1163
  case "--help":
1076
1164
  case "-h":
@@ -1080,25 +1168,1230 @@ function App({ command: command2, args: args2 }) {
1080
1168
  case "-v":
1081
1169
  return /* @__PURE__ */ jsx4(VersionCommand, {});
1082
1170
  default:
1083
- return /* @__PURE__ */ jsx4(UnknownCommand, { command: command2 });
1171
+ return /* @__PURE__ */ jsx4(UnknownCommand, { command });
1084
1172
  }
1085
1173
  }
1086
1174
  function VersionCommand() {
1087
1175
  return /* @__PURE__ */ jsx4(Box4, { children: /* @__PURE__ */ jsx4(Text4, { children: "ollie v0.1.0" }) });
1088
1176
  }
1089
- function UnknownCommand({ command: command2 }) {
1177
+ function UnknownCommand({ command }) {
1090
1178
  return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", gap: 1, children: [
1091
1179
  /* @__PURE__ */ jsxs4(Text4, { color: "red", children: [
1092
1180
  "Unknown command: ",
1093
- command2
1181
+ command
1094
1182
  ] }),
1095
1183
  /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "Run `ollie help` for available commands." })
1096
1184
  ] });
1097
1185
  }
1098
1186
 
1187
+ // src/core/business-rule.ts
1188
+ var SELECT_FIELDS = "id, store_id, title, content, previous_content, versions_ids, components_ids, functions_ids, status, code_updated, created_at, updated_at";
1189
+ async function listBusinessRules(client, filters = {}) {
1190
+ let query = client.from("business_rules").select(SELECT_FIELDS).order("created_at", { ascending: false });
1191
+ if (filters.store_id !== void 0) {
1192
+ query = query.eq("store_id", filters.store_id);
1193
+ }
1194
+ if (filters.version_id !== void 0) {
1195
+ query = query.filter(
1196
+ "versions_ids",
1197
+ "cs",
1198
+ JSON.stringify([filters.version_id])
1199
+ );
1200
+ }
1201
+ if (filters.code_updated !== void 0) {
1202
+ query = query.eq("code_updated", filters.code_updated);
1203
+ }
1204
+ const { data, error } = await query;
1205
+ if (error) {
1206
+ return { error: { message: error.message } };
1207
+ }
1208
+ return { data };
1209
+ }
1210
+ async function getBusinessRule(client, id) {
1211
+ const { data, error } = await client.from("business_rules").select(SELECT_FIELDS).eq("id", id).single();
1212
+ if (error) {
1213
+ return { error: { message: error.message } };
1214
+ }
1215
+ return { data };
1216
+ }
1217
+ async function updateBusinessRule(client, id, input) {
1218
+ const { data: current, error: fetchError } = await client.from("business_rules").select("content").eq("id", id).single();
1219
+ if (fetchError) {
1220
+ return { error: { message: fetchError.message } };
1221
+ }
1222
+ const updatePayload = {
1223
+ previous_content: current.content,
1224
+ content: input.content,
1225
+ code_updated: false
1226
+ };
1227
+ if (input.versions_ids !== void 0) {
1228
+ updatePayload.versions_ids = input.versions_ids;
1229
+ }
1230
+ if (input.components_ids !== void 0) {
1231
+ updatePayload.components_ids = input.components_ids;
1232
+ }
1233
+ if (input.functions_ids !== void 0) {
1234
+ updatePayload.functions_ids = input.functions_ids;
1235
+ }
1236
+ const { data, error } = await client.from("business_rules").update(updatePayload).eq("id", id).select("id").single();
1237
+ if (error) {
1238
+ return { error: { message: error.message } };
1239
+ }
1240
+ return { data: { id: data.id } };
1241
+ }
1242
+
1243
+ // src/utils/output.ts
1244
+ function detectOutputFormat(cliOutput) {
1245
+ if (cliOutput === "json" || cliOutput === "j") return "json";
1246
+ if (cliOutput === "pretty") return "pretty";
1247
+ return process.stdout.isTTY ? "pretty" : "json";
1248
+ }
1249
+ function filterFields(data, fields) {
1250
+ if (!fields || fields.length === 0) return data;
1251
+ const result = {};
1252
+ for (const field of fields) {
1253
+ if (field in data) {
1254
+ result[field] = data[field];
1255
+ }
1256
+ }
1257
+ return result;
1258
+ }
1259
+ function outputResult(result, format, fields) {
1260
+ if (format === "json") {
1261
+ let output = result;
1262
+ if (fields && result.data && typeof result.data === "object") {
1263
+ if (Array.isArray(result.data)) {
1264
+ output = {
1265
+ ...result,
1266
+ data: result.data.map(
1267
+ (item) => filterFields(item, fields)
1268
+ )
1269
+ };
1270
+ } else {
1271
+ output = {
1272
+ ...result,
1273
+ data: filterFields(result.data, fields)
1274
+ };
1275
+ }
1276
+ }
1277
+ process.stdout.write(`${JSON.stringify(output)}
1278
+ `);
1279
+ return;
1280
+ }
1281
+ if (result.error) {
1282
+ const errMsg = typeof result.error === "object" && result.error !== null ? result.error.message || JSON.stringify(result.error) : String(result.error);
1283
+ console.error(`\x1B[31mError:\x1B[0m ${errMsg}`);
1284
+ return;
1285
+ }
1286
+ if (Array.isArray(result.data)) {
1287
+ printTable(result.data, fields);
1288
+ } else if (typeof result.data === "object" && result.data !== null) {
1289
+ const filtered = fields ? filterFields(result.data, fields) : result.data;
1290
+ for (const [key, value] of Object.entries(
1291
+ filtered
1292
+ )) {
1293
+ console.log(`\x1B[1m${key}:\x1B[0m ${value}`);
1294
+ }
1295
+ } else {
1296
+ console.log(result.data);
1297
+ }
1298
+ }
1299
+ function printTable(rows, fields) {
1300
+ if (rows.length === 0) {
1301
+ console.log("(no results)");
1302
+ return;
1303
+ }
1304
+ const keys = fields || Object.keys(rows[0]);
1305
+ const widths = {};
1306
+ for (const key of keys) {
1307
+ widths[key] = key.length;
1308
+ for (const row of rows) {
1309
+ const val = String(row[key] ?? "");
1310
+ widths[key] = Math.max(widths[key], val.length);
1311
+ }
1312
+ widths[key] = Math.min(widths[key], 40);
1313
+ }
1314
+ const header = keys.map((k) => k.padEnd(widths[k])).join(" ");
1315
+ console.log(`\x1B[1m${header}\x1B[0m`);
1316
+ console.log(keys.map((k) => "\u2500".repeat(widths[k])).join("\u2500\u2500"));
1317
+ for (const row of rows) {
1318
+ const line = keys.map(
1319
+ (k) => String(row[k] ?? "").padEnd(widths[k]).slice(0, widths[k])
1320
+ ).join(" ");
1321
+ console.log(line);
1322
+ }
1323
+ }
1324
+ function outputDryRun(action, data, format) {
1325
+ if (format === "json") {
1326
+ process.stdout.write(`${JSON.stringify({ dryRun: true, action, data })}
1327
+ `);
1328
+ } else {
1329
+ console.log(`\x1B[33m[dry-run]\x1B[0m Would execute: ${action}`);
1330
+ for (const [key, value] of Object.entries(data)) {
1331
+ console.log(` ${key}: ${JSON.stringify(value)}`);
1332
+ }
1333
+ }
1334
+ }
1335
+
1336
+ // src/utils/parse-args.ts
1337
+ function parseArgs(argv) {
1338
+ const args = argv.slice(2);
1339
+ const command = args[0] || "help";
1340
+ const flags = {};
1341
+ const positional = [];
1342
+ let subcommand;
1343
+ if (args[1] && !args[1].startsWith("-")) {
1344
+ subcommand = args[1];
1345
+ }
1346
+ const startIdx = subcommand ? 2 : 1;
1347
+ for (let i = startIdx; i < args.length; i++) {
1348
+ const arg = args[i];
1349
+ if (arg.startsWith("--")) {
1350
+ const key = arg.slice(2);
1351
+ const next = args[i + 1];
1352
+ if (next && !next.startsWith("-")) {
1353
+ flags[key] = next;
1354
+ i++;
1355
+ } else {
1356
+ flags[key] = true;
1357
+ }
1358
+ } else if (arg.startsWith("-") && arg.length === 2) {
1359
+ const key = arg.slice(1);
1360
+ const next = args[i + 1];
1361
+ if (next && !next.startsWith("-")) {
1362
+ flags[key] = next;
1363
+ i++;
1364
+ } else {
1365
+ flags[key] = true;
1366
+ }
1367
+ } else {
1368
+ positional.push(arg);
1369
+ }
1370
+ }
1371
+ const global = {
1372
+ output: flags.output || flags.o || void 0,
1373
+ dryRun: flags["dry-run"] === true,
1374
+ fields: flags.fields ? String(flags.fields).split(",").map((f) => f.trim()) : void 0,
1375
+ data: flags.data || flags.d || void 0
1376
+ };
1377
+ return { command, subcommand, flags, global, positional };
1378
+ }
1379
+ function getFlag(flags, ...names) {
1380
+ for (const name of names) {
1381
+ const val = flags[name];
1382
+ if (typeof val === "string") return val;
1383
+ }
1384
+ return void 0;
1385
+ }
1386
+ function getBoolFlag(flags, ...names) {
1387
+ for (const name of names) {
1388
+ if (flags[name] === true) return true;
1389
+ }
1390
+ return false;
1391
+ }
1392
+
1393
+ // src/utils/supabase.ts
1394
+ import { createClient } from "@supabase/supabase-js";
1395
+ async function getAuthenticatedClient() {
1396
+ const credentials = await getCredentials();
1397
+ if (!credentials) {
1398
+ throw new Error("Not authenticated. Run `ollieshop login` first.");
1399
+ }
1400
+ const supabaseUrl = process.env.OLLIE_SUPABASE_URL || "https://aazahtmqrhjqsyqoqdkm.supabase.co";
1401
+ const supabaseAnonKey = process.env.OLLIE_SUPABASE_ANON_KEY || "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImFhemFodG1xcmhqcXN5cW9xZGttIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDg2MzEwOTcsImV4cCI6MjA2NDIwNzA5N30.VuAbAyjDe0HcL09SZtQ-UmP1o7Z6qwGuOtvfFhnyAcM";
1402
+ const client = createClient(supabaseUrl, supabaseAnonKey, {
1403
+ auth: {
1404
+ autoRefreshToken: false,
1405
+ persistSession: false
1406
+ }
1407
+ });
1408
+ await client.auth.setSession({
1409
+ access_token: credentials.accessToken,
1410
+ refresh_token: credentials.refreshToken
1411
+ });
1412
+ return client;
1413
+ }
1414
+ function getBuilderUrl() {
1415
+ return process.env.OLLIE_BUILDER_URL || "";
1416
+ }
1417
+ async function getAuthToken() {
1418
+ const credentials = await getCredentials();
1419
+ if (!credentials) {
1420
+ throw new Error("Not authenticated. Run `ollieshop login` first.");
1421
+ }
1422
+ return credentials.accessToken;
1423
+ }
1424
+ async function getOrganizationId(client) {
1425
+ const { data: org, error } = await client.from("organizations").select("id").order("created_at", { ascending: true }).limit(1).maybeSingle();
1426
+ if (error) {
1427
+ throw new Error(`Failed to get organization: ${error.message}`);
1428
+ }
1429
+ if (!org) {
1430
+ throw new Error(
1431
+ "No organization found for your account. Create one at https://admin.ollie.shop"
1432
+ );
1433
+ }
1434
+ return org.id;
1435
+ }
1436
+
1437
+ // src/utils/validate.ts
1438
+ var UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1439
+ var CONTROL_CHAR_REGEX = /[\x00-\x1f\x7f]/;
1440
+ function validateUuid(value, name) {
1441
+ if (!UUID_REGEX.test(value)) {
1442
+ throw new Error(
1443
+ `Invalid ${name}: "${value}". Must be a valid UUID (e.g. 7217542a-d7c6-40d3-a20e-db13b310a781).`
1444
+ );
1445
+ }
1446
+ return value;
1447
+ }
1448
+ function rejectControlChars(value, name) {
1449
+ if (CONTROL_CHAR_REGEX.test(value)) {
1450
+ throw new Error(
1451
+ `Invalid ${name}: contains control characters. Input must be printable text.`
1452
+ );
1453
+ }
1454
+ return value;
1455
+ }
1456
+ function validateEnum(value, allowed, name) {
1457
+ if (!allowed.includes(value)) {
1458
+ throw new Error(
1459
+ `Invalid ${name}: "${value}". Must be one of: ${allowed.join(", ")}`
1460
+ );
1461
+ }
1462
+ return value;
1463
+ }
1464
+ function validateRequired(value, name) {
1465
+ if (!value || value.trim() === "") {
1466
+ throw new Error(`Missing required parameter: --${name}`);
1467
+ }
1468
+ return rejectControlChars(value.trim(), name);
1469
+ }
1470
+
1471
+ // src/commands/business-rule-cmd.ts
1472
+ async function businessRuleCommand(parsed2) {
1473
+ const sub = parsed2.subcommand;
1474
+ if (sub === "list" || sub === "ls") return businessRuleListCommand(parsed2);
1475
+ if (sub === "get") return businessRuleGetCommand(parsed2);
1476
+ if (sub === "update") return businessRuleUpdateCommand(parsed2);
1477
+ console.error(
1478
+ `Unknown business-rule subcommand: ${sub}. Use: business-rule list | business-rule get | business-rule update`
1479
+ );
1480
+ process.exit(1);
1481
+ }
1482
+ async function businessRuleListCommand(parsed2) {
1483
+ const format = detectOutputFormat(parsed2.global.output);
1484
+ try {
1485
+ const storeId = getFlag(parsed2.flags, "store-id");
1486
+ const versionId = getFlag(parsed2.flags, "version-id");
1487
+ const codeUpdatedRaw = parsed2.flags["code-updated"];
1488
+ let codeUpdated;
1489
+ if (codeUpdatedRaw === "true" || codeUpdatedRaw === true) {
1490
+ codeUpdated = true;
1491
+ } else if (codeUpdatedRaw === "false") {
1492
+ codeUpdated = false;
1493
+ }
1494
+ if (storeId !== void 0) validateUuid(storeId, "store-id");
1495
+ if (versionId !== void 0) validateUuid(versionId, "version-id");
1496
+ const client = await getAuthenticatedClient();
1497
+ const result = await listBusinessRules(client, {
1498
+ store_id: storeId,
1499
+ version_id: versionId,
1500
+ code_updated: codeUpdated
1501
+ });
1502
+ outputResult(result, format, parsed2.global.fields);
1503
+ if (result.error) process.exit(1);
1504
+ } catch (err) {
1505
+ outputResult(
1506
+ {
1507
+ error: { message: err instanceof Error ? err.message : String(err) }
1508
+ },
1509
+ format
1510
+ );
1511
+ process.exit(1);
1512
+ }
1513
+ }
1514
+ async function businessRuleGetCommand(parsed2) {
1515
+ const format = detectOutputFormat(parsed2.global.output);
1516
+ try {
1517
+ const id = validateUuid(
1518
+ validateRequired(getFlag(parsed2.flags, "id"), "id"),
1519
+ "id"
1520
+ );
1521
+ const client = await getAuthenticatedClient();
1522
+ const result = await getBusinessRule(client, id);
1523
+ outputResult(result, format, parsed2.global.fields);
1524
+ if (result.error) process.exit(1);
1525
+ } catch (err) {
1526
+ outputResult(
1527
+ {
1528
+ error: { message: err instanceof Error ? err.message : String(err) }
1529
+ },
1530
+ format
1531
+ );
1532
+ process.exit(1);
1533
+ }
1534
+ }
1535
+ async function businessRuleUpdateCommand(parsed2) {
1536
+ const format = detectOutputFormat(parsed2.global.output);
1537
+ try {
1538
+ let id;
1539
+ let input;
1540
+ if (parsed2.global.data) {
1541
+ const raw = JSON.parse(parsed2.global.data);
1542
+ id = validateUuid(validateRequired(raw.id, "id"), "id");
1543
+ input = {
1544
+ content: validateRequired(raw.content, "content"),
1545
+ versions_ids: raw.versionsIds ?? void 0,
1546
+ components_ids: raw.componentsIds ?? void 0,
1547
+ functions_ids: raw.functionsIds ?? void 0
1548
+ };
1549
+ } else {
1550
+ id = validateUuid(
1551
+ validateRequired(getFlag(parsed2.flags, "id"), "id"),
1552
+ "id"
1553
+ );
1554
+ const versionsIdsRaw = getFlag(parsed2.flags, "versions-ids");
1555
+ const componentsIdsRaw = getFlag(parsed2.flags, "components-ids");
1556
+ const functionsIdsRaw = getFlag(parsed2.flags, "functions-ids");
1557
+ input = {
1558
+ content: validateRequired(
1559
+ getFlag(parsed2.flags, "content", "c"),
1560
+ "content"
1561
+ ),
1562
+ versions_ids: versionsIdsRaw ? JSON.parse(versionsIdsRaw) : void 0,
1563
+ components_ids: componentsIdsRaw ? JSON.parse(componentsIdsRaw) : void 0,
1564
+ functions_ids: functionsIdsRaw ? JSON.parse(functionsIdsRaw) : void 0
1565
+ };
1566
+ }
1567
+ if (parsed2.global.dryRun) {
1568
+ outputDryRun(
1569
+ "business-rule.update",
1570
+ { id, ...input },
1571
+ format
1572
+ );
1573
+ return;
1574
+ }
1575
+ const client = await getAuthenticatedClient();
1576
+ const result = await updateBusinessRule(client, id, input);
1577
+ outputResult(result, format, parsed2.global.fields);
1578
+ if (result.error) process.exit(1);
1579
+ } catch (err) {
1580
+ outputResult(
1581
+ {
1582
+ error: { message: err instanceof Error ? err.message : String(err) }
1583
+ },
1584
+ format
1585
+ );
1586
+ process.exit(1);
1587
+ }
1588
+ }
1589
+
1590
+ // src/core/schema.ts
1591
+ import { z as z2 } from "zod";
1592
+ import { zodToJsonSchema } from "zod-to-json-schema";
1593
+ var PLATFORM_VENDORS = ["vtex", "shopify", "vnda", "custom"];
1594
+ var storeCreateSchema = z2.object({
1595
+ name: z2.string().min(1).describe("Store display name"),
1596
+ platform: z2.enum(PLATFORM_VENDORS).describe("E-commerce platform vendor"),
1597
+ platformStoreId: z2.string().min(1).describe("Platform-specific store identifier (e.g. account name)"),
1598
+ logo: z2.string().url().optional().describe("Store logo URL"),
1599
+ settings: z2.string().optional().describe("JSON settings string")
1600
+ });
1601
+ var storeListSchema = z2.object({}).describe("No parameters required");
1602
+ var versionCreateSchema = z2.object({
1603
+ storeId: z2.string().uuid().describe("Parent store UUID"),
1604
+ name: z2.string().min(1).describe("Version name (e.g. v1, main)"),
1605
+ active: z2.boolean().default(false).describe("Whether version is active"),
1606
+ default: z2.boolean().default(false).describe("Whether this is the default version"),
1607
+ template: z2.string().nullable().default(null).describe("Template name or null")
1608
+ });
1609
+ var versionListSchema = z2.object({
1610
+ storeId: z2.string().uuid().describe("Store UUID to list versions for")
1611
+ });
1612
+ var componentCreateSchema = z2.object({
1613
+ versionId: z2.string().uuid().describe("Parent version UUID"),
1614
+ name: z2.string().min(1).describe("Component name (e.g. FreeShippingBar)"),
1615
+ slot: z2.string().min(1).describe(
1616
+ "Target slot (e.g. cart_header_full_page, shipping_address_details_form)"
1617
+ ),
1618
+ active: z2.boolean().default(true).describe("Whether component is active"),
1619
+ props: z2.record(z2.unknown()).nullable().default(null).describe("Default component props as JSON object")
1620
+ });
1621
+ var componentListSchema = z2.object({
1622
+ storeId: z2.string().uuid().describe("Store UUID"),
1623
+ versionId: z2.string().uuid().optional().describe("Optional version UUID to filter by")
1624
+ });
1625
+ var functionCreateSchema = z2.object({
1626
+ versionId: z2.string().uuid().describe("Parent version UUID"),
1627
+ name: z2.string().min(1).describe("Function name"),
1628
+ trigger: z2.string().min(1).describe("Function trigger (e.g. beforePayment, afterShipping)"),
1629
+ active: z2.boolean().default(true).describe("Whether function is active")
1630
+ });
1631
+ var functionListSchema = z2.object({
1632
+ versionId: z2.string().uuid().describe("Version UUID to list functions for")
1633
+ });
1634
+ var schemas = {
1635
+ store: {
1636
+ create: storeCreateSchema,
1637
+ list: storeListSchema
1638
+ },
1639
+ version: {
1640
+ create: versionCreateSchema,
1641
+ list: versionListSchema
1642
+ },
1643
+ component: {
1644
+ create: componentCreateSchema,
1645
+ list: componentListSchema
1646
+ },
1647
+ function: {
1648
+ create: functionCreateSchema,
1649
+ list: functionListSchema
1650
+ }
1651
+ };
1652
+ function getSchemaNames() {
1653
+ const names = [];
1654
+ for (const [resource, actions] of Object.entries(schemas)) {
1655
+ names.push(resource);
1656
+ for (const action of Object.keys(actions)) {
1657
+ names.push(`${resource}.${action}`);
1658
+ }
1659
+ }
1660
+ return names;
1661
+ }
1662
+ function getJsonSchema(name) {
1663
+ const parts = name.split(".");
1664
+ const resource = parts[0];
1665
+ const action = parts[1];
1666
+ if (!resource || !schemas[resource]) return null;
1667
+ if (action) {
1668
+ const schema = schemas[resource][action];
1669
+ if (!schema) return null;
1670
+ return zodToJsonSchema(schema, { name: `${resource}.${action}` });
1671
+ }
1672
+ const result = {};
1673
+ for (const [actionName, schema] of Object.entries(schemas[resource])) {
1674
+ result[actionName] = zodToJsonSchema(schema, {
1675
+ name: `${resource}.${actionName}`
1676
+ });
1677
+ }
1678
+ return result;
1679
+ }
1680
+
1681
+ // src/core/component.ts
1682
+ async function createComponent(client, input) {
1683
+ const parsed2 = componentCreateSchema.safeParse(input);
1684
+ if (!parsed2.success) {
1685
+ return {
1686
+ error: { message: parsed2.error.issues.map((i) => i.message).join("; ") }
1687
+ };
1688
+ }
1689
+ const { data, error } = await client.from("components").insert({
1690
+ name: parsed2.data.name,
1691
+ slot: parsed2.data.slot,
1692
+ active: parsed2.data.active,
1693
+ version_id: parsed2.data.versionId,
1694
+ props: parsed2.data.props
1695
+ }).select("id").single();
1696
+ if (error) {
1697
+ return { error: { message: error.message } };
1698
+ }
1699
+ return { data: { id: data.id } };
1700
+ }
1701
+ async function listComponents(client, storeId, versionId) {
1702
+ let query = client.from("components").select(
1703
+ "id, name, slot, active, version_id, props, created_at, versions!inner(id, name)"
1704
+ ).eq("versions.store_id", storeId);
1705
+ if (versionId) {
1706
+ query = query.eq("versions.id", versionId);
1707
+ }
1708
+ const { data, error } = await query;
1709
+ if (error) {
1710
+ return { error: { message: error.message } };
1711
+ }
1712
+ return { data: data ?? [] };
1713
+ }
1714
+
1715
+ // src/commands/component-cmd.ts
1716
+ async function componentCommand(parsed2) {
1717
+ const sub = parsed2.subcommand;
1718
+ if (sub === "create") return componentCreateCommand(parsed2);
1719
+ if (sub === "list" || sub === "ls") return componentListCommand(parsed2);
1720
+ console.error(
1721
+ `Unknown component subcommand: ${sub}. Use: component create | component list`
1722
+ );
1723
+ process.exit(1);
1724
+ }
1725
+ async function componentCreateCommand(parsed2) {
1726
+ const format = detectOutputFormat(parsed2.global.output);
1727
+ try {
1728
+ let input;
1729
+ if (parsed2.global.data) {
1730
+ const raw = JSON.parse(parsed2.global.data);
1731
+ input = {
1732
+ versionId: validateUuid(raw.versionId, "versionId"),
1733
+ name: validateRequired(raw.name, "name"),
1734
+ slot: validateRequired(raw.slot, "slot"),
1735
+ active: raw.active ?? true,
1736
+ props: raw.props ?? null
1737
+ };
1738
+ } else {
1739
+ input = {
1740
+ versionId: validateUuid(
1741
+ validateRequired(getFlag(parsed2.flags, "version-id"), "version-id"),
1742
+ "version-id"
1743
+ ),
1744
+ name: validateRequired(getFlag(parsed2.flags, "name", "n"), "name"),
1745
+ slot: validateRequired(getFlag(parsed2.flags, "slot", "s"), "slot"),
1746
+ active: getBoolFlag(parsed2.flags, "active") || !("active" in parsed2.flags),
1747
+ props: null
1748
+ };
1749
+ }
1750
+ if (parsed2.global.dryRun) {
1751
+ outputDryRun(
1752
+ "component.create",
1753
+ input,
1754
+ format
1755
+ );
1756
+ return;
1757
+ }
1758
+ const client = await getAuthenticatedClient();
1759
+ const result = await createComponent(client, input);
1760
+ outputResult(result, format, parsed2.global.fields);
1761
+ if (result.error) process.exit(1);
1762
+ } catch (err) {
1763
+ outputResult(
1764
+ {
1765
+ error: { message: err instanceof Error ? err.message : String(err) }
1766
+ },
1767
+ format
1768
+ );
1769
+ process.exit(1);
1770
+ }
1771
+ }
1772
+ async function componentListCommand(parsed2) {
1773
+ const format = detectOutputFormat(parsed2.global.output);
1774
+ try {
1775
+ const storeId = validateUuid(
1776
+ validateRequired(getFlag(parsed2.flags, "store-id"), "store-id"),
1777
+ "store-id"
1778
+ );
1779
+ const versionId = getFlag(parsed2.flags, "version-id");
1780
+ if (versionId) validateUuid(versionId, "version-id");
1781
+ const client = await getAuthenticatedClient();
1782
+ const result = await listComponents(client, storeId, versionId);
1783
+ outputResult(result, format, parsed2.global.fields);
1784
+ if (result.error) process.exit(1);
1785
+ } catch (err) {
1786
+ outputResult(
1787
+ {
1788
+ error: { message: err instanceof Error ? err.message : String(err) }
1789
+ },
1790
+ format
1791
+ );
1792
+ process.exit(1);
1793
+ }
1794
+ }
1795
+
1796
+ // src/core/deploy.ts
1797
+ async function uploadBuild(input) {
1798
+ const builderUrl = getBuilderUrl();
1799
+ const token = await getAuthToken();
1800
+ const formData = new FormData();
1801
+ formData.append(
1802
+ "code",
1803
+ new Blob([input.zipBuffer], { type: "application/zip" }),
1804
+ "code.zip"
1805
+ );
1806
+ formData.append("type", input.type);
1807
+ formData.append("resource_id", input.resourceId);
1808
+ let response;
1809
+ try {
1810
+ response = await fetch(`${builderUrl}/`, {
1811
+ method: "POST",
1812
+ headers: {
1813
+ Authorization: `Bearer ${token}`
1814
+ },
1815
+ body: formData
1816
+ });
1817
+ } catch (err) {
1818
+ return {
1819
+ success: false,
1820
+ error: {
1821
+ message: `Cannot reach builder at ${builderUrl}: ${err instanceof Error ? err.message : String(err)}`
1822
+ }
1823
+ };
1824
+ }
1825
+ const body = await response.json();
1826
+ if (!response.ok || !body.success) {
1827
+ const msg = body.error?.message || body.error?.type || `Builder returned ${response.status}`;
1828
+ return { success: false, error: { message: msg } };
1829
+ }
1830
+ return { success: true, data: body.data };
1831
+ }
1832
+ async function fetchBuildStatus(buildId) {
1833
+ const builderUrl = getBuilderUrl();
1834
+ const token = await getAuthToken();
1835
+ let response;
1836
+ try {
1837
+ response = await fetch(`${builderUrl}/${encodeURIComponent(buildId)}`, {
1838
+ method: "GET",
1839
+ headers: {
1840
+ Authorization: `Bearer ${token}`
1841
+ }
1842
+ });
1843
+ } catch (err) {
1844
+ return {
1845
+ success: false,
1846
+ error: {
1847
+ message: `Cannot reach builder at ${builderUrl}: ${err instanceof Error ? err.message : String(err)}`
1848
+ }
1849
+ };
1850
+ }
1851
+ const body = await response.json();
1852
+ if (!response.ok || !body.success) {
1853
+ const msg = body.error?.message || body.error?.type || `Builder returned ${response.status}`;
1854
+ return { success: false, error: { message: msg } };
1855
+ }
1856
+ return { success: true, data: body.data };
1857
+ }
1858
+ var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
1859
+ "SUCCEEDED",
1860
+ "FAILED",
1861
+ "STOPPED",
1862
+ "TIMED_OUT",
1863
+ "FAULT"
1864
+ ]);
1865
+ function isTerminalStatus(status) {
1866
+ return TERMINAL_STATUSES.has(status);
1867
+ }
1868
+ async function pollBuildStatus(buildId, options = {}) {
1869
+ const { intervalMs = 5e3, timeoutMs = 3e5, onPoll } = options;
1870
+ const deadline = Date.now() + timeoutMs;
1871
+ while (Date.now() < deadline) {
1872
+ const result = await fetchBuildStatus(buildId);
1873
+ if (!result.success) {
1874
+ return result;
1875
+ }
1876
+ if (onPoll) {
1877
+ onPoll(result.data);
1878
+ }
1879
+ if (isTerminalStatus(result.data.status)) {
1880
+ return result;
1881
+ }
1882
+ const remaining = deadline - Date.now();
1883
+ if (remaining <= 0) break;
1884
+ await new Promise(
1885
+ (resolve) => setTimeout(resolve, Math.min(intervalMs, remaining))
1886
+ );
1887
+ }
1888
+ return {
1889
+ success: false,
1890
+ error: { message: `Build ${buildId} timed out after ${timeoutMs / 1e3}s` }
1891
+ };
1892
+ }
1893
+
1894
+ // src/commands/deploy-cmd.ts
1895
+ async function deployCommand(parsed2) {
1896
+ const format = detectOutputFormat(parsed2.global.output);
1897
+ try {
1898
+ let resourceId;
1899
+ let componentName;
1900
+ let resourceType;
1901
+ let wait;
1902
+ let timeout;
1903
+ if (parsed2.global.data) {
1904
+ const raw = JSON.parse(parsed2.global.data);
1905
+ resourceId = validateUuid(
1906
+ raw.componentId || raw.functionId || raw.resourceId,
1907
+ "componentId or functionId"
1908
+ );
1909
+ componentName = validateRequired(raw.name, "name");
1910
+ resourceType = raw.type === "function" ? "function" : "component";
1911
+ wait = raw.wait ?? false;
1912
+ timeout = raw.timeout ?? 300;
1913
+ } else {
1914
+ const compId = getFlag(parsed2.flags, "component-id");
1915
+ const funcId = getFlag(parsed2.flags, "function-id");
1916
+ if (compId && funcId) {
1917
+ throw new Error(
1918
+ "Provide either --component-id or --function-id, not both."
1919
+ );
1920
+ }
1921
+ if (compId) {
1922
+ resourceId = validateUuid(compId, "component-id");
1923
+ resourceType = "component";
1924
+ } else if (funcId) {
1925
+ resourceId = validateUuid(funcId, "function-id");
1926
+ resourceType = "function";
1927
+ } else {
1928
+ throw new Error("Either --component-id or --function-id is required.");
1929
+ }
1930
+ componentName = validateRequired(
1931
+ getFlag(parsed2.flags, "name", "n"),
1932
+ "name"
1933
+ );
1934
+ wait = getBoolFlag(parsed2.flags, "wait");
1935
+ timeout = Number(getFlag(parsed2.flags, "timeout") ?? "300");
1936
+ }
1937
+ const stream = await createComponentBundle({
1938
+ componentName,
1939
+ cwd: process.cwd()
1940
+ });
1941
+ const chunks = [];
1942
+ for await (const chunk of stream) {
1943
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
1944
+ }
1945
+ const zipBuffer = Buffer.concat(chunks);
1946
+ if (parsed2.global.dryRun) {
1947
+ outputDryRun(
1948
+ "deploy",
1949
+ {
1950
+ resourceId,
1951
+ resourceType,
1952
+ componentName,
1953
+ bundleSizeBytes: zipBuffer.length,
1954
+ bundleSizeKB: Math.round(zipBuffer.length / 1024),
1955
+ wait,
1956
+ timeout
1957
+ },
1958
+ format
1959
+ );
1960
+ return;
1961
+ }
1962
+ const uploadResult = await uploadBuild({
1963
+ resourceId,
1964
+ type: resourceType,
1965
+ zipBuffer
1966
+ });
1967
+ if (!uploadResult.success) {
1968
+ outputResult(uploadResult, format);
1969
+ process.exit(1);
1970
+ }
1971
+ if (wait) {
1972
+ const isJson = format === "json";
1973
+ if (!isJson) {
1974
+ process.stderr.write(
1975
+ `Build ${uploadResult.data.id} started. Polling...
1976
+ `
1977
+ );
1978
+ }
1979
+ const pollResult = await pollBuildStatus(uploadResult.data.id, {
1980
+ timeoutMs: timeout * 1e3,
1981
+ onPoll: (build) => {
1982
+ if (!isJson) {
1983
+ process.stderr.write(` status: ${build.status}
1984
+ `);
1985
+ }
1986
+ }
1987
+ });
1988
+ outputResult(pollResult, format, parsed2.global.fields);
1989
+ if (!pollResult.success) process.exit(1);
1990
+ if (pollResult.success && isTerminalStatus(pollResult.data.status) && pollResult.data.status !== "SUCCEEDED") {
1991
+ process.exit(1);
1992
+ }
1993
+ } else {
1994
+ outputResult(uploadResult, format, parsed2.global.fields);
1995
+ }
1996
+ } catch (err) {
1997
+ outputResult(
1998
+ {
1999
+ success: false,
2000
+ error: { message: err instanceof Error ? err.message : String(err) }
2001
+ },
2002
+ format
2003
+ );
2004
+ process.exit(1);
2005
+ }
2006
+ }
2007
+
2008
+ // src/commands/init-cmd.ts
2009
+ async function initCommand(parsed2) {
2010
+ const format = detectOutputFormat(parsed2.global.output);
2011
+ try {
2012
+ const storeId = validateUuid(
2013
+ validateRequired(getFlag(parsed2.flags, "store-id"), "store-id"),
2014
+ "store-id"
2015
+ );
2016
+ const versionIdRaw = getFlag(parsed2.flags, "version-id");
2017
+ const versionId = versionIdRaw ? validateUuid(versionIdRaw, "version-id") : void 0;
2018
+ const stage = getFlag(parsed2.flags, "stage", "s");
2019
+ await saveConfig(
2020
+ {
2021
+ storeId,
2022
+ ...versionId ? { versionId } : {}
2023
+ },
2024
+ { stage }
2025
+ );
2026
+ const fileName = stage && stage !== "prod" ? `ollie.${stage}.json` : "ollie.json";
2027
+ outputResult(
2028
+ {
2029
+ data: {
2030
+ file: fileName,
2031
+ storeId,
2032
+ ...versionId ? { versionId } : {}
2033
+ }
2034
+ },
2035
+ format,
2036
+ parsed2.global.fields
2037
+ );
2038
+ } catch (err) {
2039
+ outputResult(
2040
+ {
2041
+ error: { message: err instanceof Error ? err.message : String(err) }
2042
+ },
2043
+ format
2044
+ );
2045
+ process.exit(1);
2046
+ }
2047
+ }
2048
+
2049
+ // src/commands/schema-cmd.ts
2050
+ async function schemaCommand(parsed2) {
2051
+ const format = detectOutputFormat(parsed2.global.output);
2052
+ const resourceName = parsed2.subcommand || parsed2.positional[0];
2053
+ if (!resourceName) {
2054
+ const names = getSchemaNames();
2055
+ if (format === "json") {
2056
+ process.stdout.write(`${JSON.stringify({ schemas: names })}
2057
+ `);
2058
+ } else {
2059
+ console.log("\x1B[1mAvailable schemas:\x1B[0m");
2060
+ for (const name of names) {
2061
+ const indent = name.includes(".") ? " " : " ";
2062
+ console.log(`${indent}\x1B[32m${name}\x1B[0m`);
2063
+ }
2064
+ console.log("\nUsage: ollieshop schema <resource[.action]>");
2065
+ }
2066
+ return;
2067
+ }
2068
+ const schema = getJsonSchema(resourceName);
2069
+ if (!schema) {
2070
+ console.error(
2071
+ `Unknown schema: ${resourceName}. Run \`ollieshop schema\` to see available schemas.`
2072
+ );
2073
+ process.exit(1);
2074
+ }
2075
+ process.stdout.write(`${JSON.stringify(schema, null, 2)}
2076
+ `);
2077
+ }
2078
+
2079
+ // src/commands/status-cmd.ts
2080
+ async function statusCommand(parsed2) {
2081
+ const format = detectOutputFormat(parsed2.global.output);
2082
+ try {
2083
+ let buildId;
2084
+ let wait;
2085
+ let timeout;
2086
+ if (parsed2.global.data) {
2087
+ const raw = JSON.parse(parsed2.global.data);
2088
+ buildId = validateRequired(raw.buildId, "buildId");
2089
+ wait = raw.wait ?? false;
2090
+ timeout = raw.timeout ?? 300;
2091
+ } else {
2092
+ buildId = validateRequired(getFlag(parsed2.flags, "build-id"), "build-id");
2093
+ wait = getBoolFlag(parsed2.flags, "wait");
2094
+ timeout = Number(getFlag(parsed2.flags, "timeout") ?? "300");
2095
+ }
2096
+ if (wait) {
2097
+ const isJson = format === "json";
2098
+ if (!isJson) {
2099
+ process.stderr.write(`Polling build ${buildId}...
2100
+ `);
2101
+ }
2102
+ const result = await pollBuildStatus(buildId, {
2103
+ timeoutMs: timeout * 1e3,
2104
+ onPoll: (build) => {
2105
+ if (!isJson) {
2106
+ process.stderr.write(` status: ${build.status}
2107
+ `);
2108
+ }
2109
+ }
2110
+ });
2111
+ outputResult(result, format, parsed2.global.fields);
2112
+ if (!result.success) process.exit(1);
2113
+ if (result.success && isTerminalStatus(result.data.status) && result.data.status !== "SUCCEEDED") {
2114
+ process.exit(1);
2115
+ }
2116
+ } else {
2117
+ const result = await fetchBuildStatus(buildId);
2118
+ outputResult(result, format, parsed2.global.fields);
2119
+ if (!result.success) process.exit(1);
2120
+ }
2121
+ } catch (err) {
2122
+ outputResult(
2123
+ {
2124
+ success: false,
2125
+ error: { message: err instanceof Error ? err.message : String(err) }
2126
+ },
2127
+ format
2128
+ );
2129
+ process.exit(1);
2130
+ }
2131
+ }
2132
+
2133
+ // src/core/store.ts
2134
+ async function createStore(client, input) {
2135
+ const parsed2 = storeCreateSchema.safeParse(input);
2136
+ if (!parsed2.success) {
2137
+ return {
2138
+ error: { message: parsed2.error.issues.map((i) => i.message).join("; ") }
2139
+ };
2140
+ }
2141
+ const organizationId = await getOrganizationId(client);
2142
+ const { data, error } = await client.from("stores").insert({
2143
+ name: parsed2.data.name,
2144
+ platform: parsed2.data.platform,
2145
+ platform_store_id: parsed2.data.platformStoreId,
2146
+ organization_id: organizationId,
2147
+ logo: parsed2.data.logo ?? null,
2148
+ settings: parsed2.data.settings ?? null
2149
+ }).select("id").single();
2150
+ if (error) {
2151
+ return { error: { message: error.message } };
2152
+ }
2153
+ return { data: { id: data.id } };
2154
+ }
2155
+ async function listStores(client) {
2156
+ const organizationId = await getOrganizationId(client);
2157
+ const { data, error } = await client.from("stores").select(
2158
+ "id, name, platform, platform_store_id, organization_id, logo, settings, created_at"
2159
+ ).eq("organization_id", organizationId).order("created_at", { ascending: false });
2160
+ if (error) {
2161
+ return { error: { message: error.message } };
2162
+ }
2163
+ return { data };
2164
+ }
2165
+
2166
+ // src/commands/store-cmd.ts
2167
+ async function storeCommand(parsed2) {
2168
+ const sub = parsed2.subcommand;
2169
+ if (sub === "create") return storeCreateCommand(parsed2);
2170
+ if (sub === "list" || sub === "ls") return storeListCommand(parsed2);
2171
+ console.error(
2172
+ `Unknown store subcommand: ${sub}. Use: store create | store list`
2173
+ );
2174
+ process.exit(1);
2175
+ }
2176
+ async function storeCreateCommand(parsed2) {
2177
+ const format = detectOutputFormat(parsed2.global.output);
2178
+ try {
2179
+ let input;
2180
+ if (parsed2.global.data) {
2181
+ const raw = JSON.parse(parsed2.global.data);
2182
+ input = {
2183
+ name: validateRequired(raw.name, "name"),
2184
+ platform: validateEnum(raw.platform, PLATFORM_VENDORS, "platform"),
2185
+ platformStoreId: validateRequired(
2186
+ raw.platformStoreId,
2187
+ "platformStoreId"
2188
+ ),
2189
+ logo: raw.logo,
2190
+ settings: raw.settings
2191
+ };
2192
+ } else {
2193
+ input = {
2194
+ name: validateRequired(getFlag(parsed2.flags, "name", "n"), "name"),
2195
+ platform: validateEnum(
2196
+ validateRequired(getFlag(parsed2.flags, "platform", "p"), "platform"),
2197
+ PLATFORM_VENDORS,
2198
+ "platform"
2199
+ ),
2200
+ platformStoreId: validateRequired(
2201
+ getFlag(parsed2.flags, "platform-store-id"),
2202
+ "platform-store-id"
2203
+ ),
2204
+ logo: getFlag(parsed2.flags, "logo"),
2205
+ settings: getFlag(parsed2.flags, "settings")
2206
+ };
2207
+ }
2208
+ if (parsed2.global.dryRun) {
2209
+ outputDryRun("store.create", input, format);
2210
+ return;
2211
+ }
2212
+ const client = await getAuthenticatedClient();
2213
+ const result = await createStore(client, input);
2214
+ outputResult(result, format, parsed2.global.fields);
2215
+ if (result.error) process.exit(1);
2216
+ } catch (err) {
2217
+ outputResult(
2218
+ {
2219
+ error: { message: err instanceof Error ? err.message : String(err) }
2220
+ },
2221
+ format
2222
+ );
2223
+ process.exit(1);
2224
+ }
2225
+ }
2226
+ async function storeListCommand(parsed2) {
2227
+ const format = detectOutputFormat(parsed2.global.output);
2228
+ try {
2229
+ const client = await getAuthenticatedClient();
2230
+ const result = await listStores(client);
2231
+ outputResult(result, format, parsed2.global.fields);
2232
+ if (result.error) process.exit(1);
2233
+ } catch (err) {
2234
+ outputResult(
2235
+ {
2236
+ error: { message: err instanceof Error ? err.message : String(err) }
2237
+ },
2238
+ format
2239
+ );
2240
+ process.exit(1);
2241
+ }
2242
+ }
2243
+
2244
+ // src/core/version.ts
2245
+ async function createVersion(client, input) {
2246
+ const parsed2 = versionCreateSchema.safeParse(input);
2247
+ if (!parsed2.success) {
2248
+ return {
2249
+ error: { message: parsed2.error.issues.map((i) => i.message).join("; ") }
2250
+ };
2251
+ }
2252
+ const { data, error } = await client.from("versions").insert({
2253
+ name: parsed2.data.name,
2254
+ active: parsed2.data.active,
2255
+ default: parsed2.data.default,
2256
+ store_id: parsed2.data.storeId,
2257
+ template: parsed2.data.template
2258
+ }).select("id").single();
2259
+ if (error) {
2260
+ return { error: { message: error.message } };
2261
+ }
2262
+ return { data: { id: data.id } };
2263
+ }
2264
+ async function listVersions(client, storeId) {
2265
+ 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 });
2266
+ if (error) {
2267
+ return { error: { message: error.message } };
2268
+ }
2269
+ return { data };
2270
+ }
2271
+
2272
+ // src/commands/version-cmd.ts
2273
+ async function versionCommand(parsed2) {
2274
+ const sub = parsed2.subcommand;
2275
+ if (sub === "create") return versionCreateCommand(parsed2);
2276
+ if (sub === "list" || sub === "ls") return versionListCommand(parsed2);
2277
+ console.error(
2278
+ `Unknown version subcommand: ${sub}. Use: version create | version list`
2279
+ );
2280
+ process.exit(1);
2281
+ }
2282
+ async function versionCreateCommand(parsed2) {
2283
+ const format = detectOutputFormat(parsed2.global.output);
2284
+ try {
2285
+ let input;
2286
+ if (parsed2.global.data) {
2287
+ const raw = JSON.parse(parsed2.global.data);
2288
+ input = {
2289
+ storeId: validateUuid(raw.storeId, "storeId"),
2290
+ name: validateRequired(raw.name, "name"),
2291
+ active: raw.active ?? false,
2292
+ default: raw.default ?? false,
2293
+ template: raw.template ?? null
2294
+ };
2295
+ } else {
2296
+ input = {
2297
+ storeId: validateUuid(
2298
+ validateRequired(getFlag(parsed2.flags, "store-id"), "store-id"),
2299
+ "store-id"
2300
+ ),
2301
+ name: validateRequired(getFlag(parsed2.flags, "name", "n"), "name"),
2302
+ active: getBoolFlag(parsed2.flags, "active"),
2303
+ default: getBoolFlag(parsed2.flags, "default"),
2304
+ template: getFlag(parsed2.flags, "template") ?? null
2305
+ };
2306
+ }
2307
+ if (parsed2.global.dryRun) {
2308
+ outputDryRun("version.create", input, format);
2309
+ return;
2310
+ }
2311
+ const client = await getAuthenticatedClient();
2312
+ const result = await createVersion(client, input);
2313
+ outputResult(result, format, parsed2.global.fields);
2314
+ if (result.error) process.exit(1);
2315
+ } catch (err) {
2316
+ outputResult(
2317
+ {
2318
+ error: { message: err instanceof Error ? err.message : String(err) }
2319
+ },
2320
+ format
2321
+ );
2322
+ process.exit(1);
2323
+ }
2324
+ }
2325
+ async function versionListCommand(parsed2) {
2326
+ const format = detectOutputFormat(parsed2.global.output);
2327
+ try {
2328
+ const storeId = validateUuid(
2329
+ validateRequired(getFlag(parsed2.flags, "store-id"), "store-id"),
2330
+ "store-id"
2331
+ );
2332
+ const client = await getAuthenticatedClient();
2333
+ const result = await listVersions(client, storeId);
2334
+ outputResult(result, format, parsed2.global.fields);
2335
+ if (result.error) process.exit(1);
2336
+ } catch (err) {
2337
+ outputResult(
2338
+ {
2339
+ error: { message: err instanceof Error ? err.message : String(err) }
2340
+ },
2341
+ format
2342
+ );
2343
+ process.exit(1);
2344
+ }
2345
+ }
2346
+
2347
+ // src/commands/whoami.ts
2348
+ async function whoamiCommand(parsed2) {
2349
+ const format = detectOutputFormat(parsed2.global.output);
2350
+ const user = await getCurrentUser();
2351
+ if (!user) {
2352
+ outputResult(
2353
+ {
2354
+ error: { message: "Not logged in. Run `ollieshop login`." }
2355
+ },
2356
+ format
2357
+ );
2358
+ process.exit(1);
2359
+ }
2360
+ outputResult(
2361
+ {
2362
+ data: {
2363
+ email: user.email
2364
+ }
2365
+ },
2366
+ format,
2367
+ parsed2.global.fields
2368
+ );
2369
+ }
2370
+
1099
2371
  // src/index.tsx
1100
2372
  import { jsx as jsx5 } from "react/jsx-runtime";
1101
- var args = process.argv.slice(2);
1102
- var command = args[0] || "help";
1103
- var commandArgs = args.slice(1);
1104
- render(/* @__PURE__ */ jsx5(App, { command, args: commandArgs }));
2373
+ var AGENT_COMMANDS = {
2374
+ whoami: whoamiCommand,
2375
+ store: storeCommand,
2376
+ version: versionCommand,
2377
+ component: componentCommand,
2378
+ "business-rule": businessRuleCommand,
2379
+ schema: schemaCommand,
2380
+ init: initCommand,
2381
+ deploy: deployCommand,
2382
+ status: statusCommand
2383
+ };
2384
+ var parsed = parseArgs(process.argv);
2385
+ if (parsed.command in AGENT_COMMANDS) {
2386
+ AGENT_COMMANDS[parsed.command](parsed).catch((err) => {
2387
+ const msg = err instanceof Error ? err.message : String(err);
2388
+ process.stderr.write(`${JSON.stringify({ error: { message: msg } })}
2389
+ `);
2390
+ process.exit(1);
2391
+ });
2392
+ } else {
2393
+ const args = process.argv.slice(2);
2394
+ const command = args[0] || "help";
2395
+ const commandArgs = args.slice(1);
2396
+ render(/* @__PURE__ */ jsx5(App, { command, args: commandArgs }));
2397
+ }