owosk 0.2.3 → 0.3.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.
Files changed (3) hide show
  1. package/README.md +7 -7
  2. package/dist/index.js +217 -140
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -13,7 +13,7 @@ npm install -g owosk
13
13
  Or use it directly with npx:
14
14
 
15
15
  ```bash
16
- npx owo --help
16
+ npx owosk --help
17
17
  ```
18
18
 
19
19
  ## Commands
@@ -23,7 +23,7 @@ npx owo --help
23
23
  Initialize a new Owostack project with a default configuration file (`owo.config.ts` or `owo.config.js`). JavaScript configs use ESM `import`/`export` syntax.
24
24
 
25
25
  ```bash
26
- npx owo init
26
+ npx owosk init
27
27
  ```
28
28
 
29
29
  ### `sync`
@@ -31,7 +31,7 @@ npx owo init
31
31
  Push your local catalog configuration to the Owostack cloud.
32
32
 
33
33
  ```bash
34
- npx owo sync
34
+ npx owosk sync
35
35
  ```
36
36
 
37
37
  ### `pull`
@@ -39,7 +39,7 @@ npx owo sync
39
39
  Pull existing plans and features from the cloud into your local configuration.
40
40
 
41
41
  ```bash
42
- npx owo pull
42
+ npx owosk pull
43
43
  ```
44
44
 
45
45
  ### `diff`
@@ -47,7 +47,7 @@ npx owo pull
47
47
  Preview changes by comparing your local configuration with the cloud.
48
48
 
49
49
  ```bash
50
- npx owo diff
50
+ npx owosk diff
51
51
  ```
52
52
 
53
53
  ### `validate`
@@ -55,7 +55,7 @@ npx owo diff
55
55
  Check your local configuration for errors without applying changes.
56
56
 
57
57
  ```bash
58
- npx owo validate
58
+ npx owosk validate
59
59
  ```
60
60
 
61
61
  ### `connect`
@@ -63,7 +63,7 @@ npx owo validate
63
63
  Authenticate and connect your local environment to an organization.
64
64
 
65
65
  ```bash
66
- npx owo connect
66
+ npx owosk connect
67
67
  ```
68
68
 
69
69
  ## Features
package/dist/index.js CHANGED
@@ -231,19 +231,51 @@ async function fetchCreditPacks(apiKey, apiUrl) {
231
231
  // src/lib/diff.ts
232
232
  import pc2 from "picocolors";
233
233
  import * as p from "@clack/prompts";
234
- function normalizeFeature(pf) {
234
+ function normalizeReset(reset) {
235
+ switch (reset) {
236
+ case "hour":
237
+ return "hourly";
238
+ case "day":
239
+ return "daily";
240
+ case "week":
241
+ return "weekly";
242
+ case "month":
243
+ return "monthly";
244
+ case "quarter":
245
+ return "quarterly";
246
+ case "year":
247
+ case "annually":
248
+ return "yearly";
249
+ default:
250
+ return reset || "monthly";
251
+ }
252
+ }
253
+ function normalizeOverage(usageModel, overage) {
254
+ if (usageModel === "usage_based") return "charge";
255
+ return overage === "charge" ? "charge" : "block";
256
+ }
257
+ function normalizeFeature(pf, creditSystemSlugs) {
258
+ const usageModel = pf.usageModel || "included";
259
+ const isCreditSystemFeature = creditSystemSlugs.has(pf.slug);
235
260
  return {
236
261
  slug: pf.slug,
237
262
  enabled: pf.enabled,
238
263
  limit: pf.limit ?? null,
239
264
  // Handle both SDK 'reset' and API 'resetInterval'
240
- reset: pf.reset || pf.resetInterval || "monthly",
265
+ reset: normalizeReset(pf.reset || pf.resetInterval),
266
+ usageModel: isCreditSystemFeature ? "included" : usageModel,
267
+ pricePerUnit: isCreditSystemFeature ? null : pf.pricePerUnit ?? null,
268
+ billingUnits: isCreditSystemFeature ? 1 : pf.billingUnits ?? 1,
269
+ ratingModel: isCreditSystemFeature ? "package" : pf.ratingModel || "package",
270
+ tiers: isCreditSystemFeature ? null : pf.tiers ?? null,
241
271
  // Handle both SDK 'overage' and API 'overage' (same name)
242
- overage: pf.overage || "block",
243
- overagePrice: pf.overagePrice ?? null
272
+ overage: normalizeOverage(usageModel, pf.overage),
273
+ overagePrice: isCreditSystemFeature ? null : pf.overagePrice ?? null,
274
+ maxOverageUnits: isCreditSystemFeature ? null : pf.maxOverageUnits ?? null,
275
+ creditCost: isCreditSystemFeature ? 0 : pf.creditCost ?? 0
244
276
  };
245
277
  }
246
- function normalizePlan(plan) {
278
+ function normalizePlan(plan, creditSystemSlugs) {
247
279
  return {
248
280
  slug: plan.slug,
249
281
  name: plan.name ?? null,
@@ -255,7 +287,18 @@ function normalizePlan(plan) {
255
287
  trialDays: plan.trialDays ?? 0,
256
288
  isAddon: plan.isAddon ?? false,
257
289
  autoEnable: plan.autoEnable ?? false,
258
- features: (plan.features || []).map(normalizeFeature).sort((a, b) => a.slug.localeCompare(b.slug))
290
+ features: (plan.features || []).map((feature) => normalizeFeature(feature, creditSystemSlugs)).sort((a, b) => a.slug.localeCompare(b.slug))
291
+ };
292
+ }
293
+ function normalizeCreditSystem(cs) {
294
+ return {
295
+ slug: cs.slug,
296
+ name: cs.name ?? null,
297
+ description: cs.description ?? null,
298
+ features: (cs.features || []).map((feature) => ({
299
+ feature: feature.feature,
300
+ creditCost: feature.creditCost ?? 0
301
+ })).sort((a, b) => a.feature.localeCompare(b.feature))
259
302
  };
260
303
  }
261
304
  function normalizeCreditPack(pack) {
@@ -271,10 +314,18 @@ function normalizeCreditPack(pack) {
271
314
  };
272
315
  }
273
316
  function diffPlans(localPlans, remotePlans, localCreditSystems = [], remoteCreditSystems = [], localCreditPacks = [], remoteCreditPacks = []) {
317
+ const creditSystemSlugs = /* @__PURE__ */ new Set([
318
+ ...localCreditSystems.map((cs) => cs.slug),
319
+ ...remoteCreditSystems.map((cs) => cs.slug)
320
+ ]);
274
321
  const localMap = /* @__PURE__ */ new Map();
275
322
  const remoteMap = /* @__PURE__ */ new Map();
276
- for (const p9 of localPlans) localMap.set(p9.slug, normalizePlan(p9));
277
- for (const p9 of remotePlans) remoteMap.set(p9.slug, normalizePlan(p9));
323
+ for (const p9 of localPlans) {
324
+ localMap.set(p9.slug, normalizePlan(p9, creditSystemSlugs));
325
+ }
326
+ for (const p9 of remotePlans) {
327
+ remoteMap.set(p9.slug, normalizePlan(p9, creditSystemSlugs));
328
+ }
278
329
  const onlyLocal = [];
279
330
  const onlyRemote = [];
280
331
  const changed = [];
@@ -328,8 +379,15 @@ function diffPlans(localPlans, remotePlans, localCreditSystems = [], remoteCredi
328
379
  "enabled",
329
380
  "limit",
330
381
  "reset",
382
+ "usageModel",
383
+ "pricePerUnit",
384
+ "billingUnits",
385
+ "ratingModel",
386
+ "tiers",
331
387
  "overage",
332
- "overagePrice"
388
+ "overagePrice",
389
+ "maxOverageUnits",
390
+ "creditCost"
333
391
  ];
334
392
  for (const ff of featureFields) {
335
393
  if (JSON.stringify(lf[ff]) !== JSON.stringify(rf[ff])) {
@@ -353,8 +411,12 @@ function diffPlans(localPlans, remotePlans, localCreditSystems = [], remoteCredi
353
411
  }
354
412
  const localCsMap = /* @__PURE__ */ new Map();
355
413
  const remoteCsMap = /* @__PURE__ */ new Map();
356
- for (const cs of localCreditSystems) localCsMap.set(cs.slug, cs);
357
- for (const cs of remoteCreditSystems) remoteCsMap.set(cs.slug, cs);
414
+ for (const cs of localCreditSystems) {
415
+ localCsMap.set(cs.slug, normalizeCreditSystem(cs));
416
+ }
417
+ for (const cs of remoteCreditSystems) {
418
+ remoteCsMap.set(cs.slug, normalizeCreditSystem(cs));
419
+ }
358
420
  const csOnlyLocal = [];
359
421
  const csOnlyRemote = [];
360
422
  const csChanged = [];
@@ -779,7 +841,10 @@ import * as p3 from "@clack/prompts";
779
841
  import pc4 from "picocolors";
780
842
  import { existsSync as existsSync3 } from "fs";
781
843
  import { writeFile as writeFile2 } from "fs/promises";
782
- import { resolve as resolve2, extname as extname2, isAbsolute as isAbsolute2 } from "path";
844
+ import { resolve as resolve2, isAbsolute as isAbsolute2 } from "path";
845
+
846
+ // src/lib/catalog-import.ts
847
+ import { extname as extname2 } from "path";
783
848
 
784
849
  // src/lib/generate.ts
785
850
  function slugToIdentifier(slug, used) {
@@ -834,6 +899,28 @@ function slugToIdentifier(slug, used) {
834
899
  used.add(candidate);
835
900
  return candidate;
836
901
  }
902
+ function normalizeResetForCodegen(reset) {
903
+ switch (reset) {
904
+ case void 0:
905
+ case null:
906
+ return void 0;
907
+ case "hour":
908
+ return "hourly";
909
+ case "day":
910
+ return "daily";
911
+ case "week":
912
+ return "weekly";
913
+ case "month":
914
+ return "monthly";
915
+ case "quarter":
916
+ return "quarterly";
917
+ case "year":
918
+ case "annually":
919
+ return "yearly";
920
+ default:
921
+ return reset;
922
+ }
923
+ }
837
924
  function generateConfig(plans, creditSystems = [], creditPacks = [], defaultProvider, format = "ts") {
838
925
  const isTs = format === "ts";
839
926
  const creditSystemSlugs = new Set(creditSystems.map((cs) => cs.slug));
@@ -925,8 +1012,12 @@ function generateConfig(plans, creditSystems = [], creditPacks = [], defaultProv
925
1012
  const csVar = creditSystemVars.get(pf.slug);
926
1013
  if (csVar && pf.enabled) {
927
1014
  const opts = [];
928
- if (pf.resetInterval || pf.reset)
929
- opts.push(`reset: "${pf.resetInterval || pf.reset || "monthly"}"`);
1015
+ const creditReset = normalizeResetForCodegen(
1016
+ pf.resetInterval || pf.reset
1017
+ );
1018
+ if (creditReset !== void 0) {
1019
+ opts.push(`reset: "${creditReset}"`);
1020
+ }
930
1021
  if (pf.overage) opts.push(`overage: "${pf.overage}"`);
931
1022
  if (opts.length > 0) {
932
1023
  featureEntries.push(
@@ -950,11 +1041,23 @@ function generateConfig(plans, creditSystems = [], creditPacks = [], defaultProv
950
1041
  if (pf.enabled === false) {
951
1042
  const config2 = { enabled: false };
952
1043
  if (pf.limit !== void 0) config2.limit = pf.limit;
953
- if (pf.resetInterval || pf.reset)
954
- config2.reset = pf.resetInterval || pf.reset;
1044
+ const disabledReset = normalizeResetForCodegen(
1045
+ pf.resetInterval || pf.reset
1046
+ );
1047
+ if (disabledReset !== void 0) config2.reset = disabledReset;
1048
+ if (pf.usageModel) config2.usageModel = pf.usageModel;
1049
+ if (pf.pricePerUnit !== void 0)
1050
+ config2.pricePerUnit = pf.pricePerUnit;
1051
+ if (pf.ratingModel) config2.ratingModel = pf.ratingModel;
1052
+ if (pf.tiers !== void 0) config2.tiers = pf.tiers;
1053
+ if (pf.billingUnits !== void 0)
1054
+ config2.billingUnits = pf.billingUnits;
955
1055
  if (pf.overage) config2.overage = pf.overage;
956
1056
  if (pf.overagePrice !== void 0)
957
1057
  config2.overagePrice = pf.overagePrice;
1058
+ if (pf.maxOverageUnits !== void 0)
1059
+ config2.maxOverageUnits = pf.maxOverageUnits;
1060
+ if (pf.creditCost !== void 0) config2.creditCost = pf.creditCost;
958
1061
  featureEntries.push(`${varName}.config(${JSON.stringify(config2)})`);
959
1062
  continue;
960
1063
  }
@@ -962,11 +1065,21 @@ function generateConfig(plans, creditSystems = [], creditPacks = [], defaultProv
962
1065
  const config = {};
963
1066
  if (pf.limit !== void 0) config.limit = pf.limit;
964
1067
  if (!isEntityFeature) {
965
- const reset = pf.resetInterval || pf.reset || "monthly";
966
- if (reset !== "none") config.reset = reset;
1068
+ const reset = normalizeResetForCodegen(
1069
+ pf.resetInterval || pf.reset || "monthly"
1070
+ );
1071
+ if (reset !== void 0) config.reset = reset;
967
1072
  }
1073
+ if (pf.usageModel) config.usageModel = pf.usageModel;
1074
+ if (pf.pricePerUnit !== void 0) config.pricePerUnit = pf.pricePerUnit;
1075
+ if (pf.ratingModel) config.ratingModel = pf.ratingModel;
1076
+ if (pf.tiers !== void 0) config.tiers = pf.tiers;
1077
+ if (pf.billingUnits !== void 0) config.billingUnits = pf.billingUnits;
968
1078
  if (pf.overage) config.overage = pf.overage;
969
1079
  if (pf.overagePrice !== void 0) config.overagePrice = pf.overagePrice;
1080
+ if (pf.maxOverageUnits !== void 0)
1081
+ config.maxOverageUnits = pf.maxOverageUnits;
1082
+ if (pf.creditCost !== void 0) config.creditCost = pf.creditCost;
970
1083
  const configKeys = Object.keys(config);
971
1084
  const hasExtras = configKeys.some((k) => k !== "limit");
972
1085
  if (config.limit === null && !hasExtras) {
@@ -1045,8 +1158,8 @@ function generateConfig(plans, creditSystems = [], creditPacks = [], defaultProv
1045
1158
  ].filter(Boolean).join("\n");
1046
1159
  }
1047
1160
 
1048
- // src/commands/pull.ts
1049
- function determineFormat(fullPath) {
1161
+ // src/lib/catalog-import.ts
1162
+ function determineConfigFormat(fullPath) {
1050
1163
  const ext = extname2(fullPath);
1051
1164
  if (ext === ".ts" || ext === ".mts" || ext === ".cts") return "ts";
1052
1165
  if (ext === ".mjs") return "esm";
@@ -1058,6 +1171,32 @@ function determineFormat(fullPath) {
1058
1171
  if (ext === ".js") return "esm";
1059
1172
  return "ts";
1060
1173
  }
1174
+ async function buildRemoteCatalogSnapshot(params) {
1175
+ const plans = await fetchPlans({
1176
+ apiKey: params.apiKey,
1177
+ apiUrl: params.apiUrl,
1178
+ ...params.filters || {}
1179
+ });
1180
+ const creditSystems = await fetchCreditSystems(params.apiKey, params.apiUrl);
1181
+ const creditPacks = await fetchCreditPacks(params.apiKey, params.apiUrl);
1182
+ const providers = new Set(plans.map((plan) => plan.provider).filter(Boolean));
1183
+ const defaultProvider = providers.size === 1 ? Array.from(providers)[0] : void 0;
1184
+ return {
1185
+ plans,
1186
+ creditSystems,
1187
+ creditPacks,
1188
+ defaultProvider,
1189
+ configContent: generateConfig(
1190
+ plans,
1191
+ creditSystems,
1192
+ creditPacks,
1193
+ defaultProvider,
1194
+ params.format
1195
+ )
1196
+ };
1197
+ }
1198
+
1199
+ // src/commands/pull.ts
1061
1200
  async function runPull(options) {
1062
1201
  p3.intro(pc4.bgYellow(pc4.black(" pull ")));
1063
1202
  let fullPath;
@@ -1080,105 +1219,53 @@ async function runPull(options) {
1080
1219
  const filters = configSettings.filters || {};
1081
1220
  let format;
1082
1221
  try {
1083
- format = determineFormat(fullPath);
1222
+ format = determineConfigFormat(fullPath);
1084
1223
  } catch (e) {
1085
1224
  p3.log.error(pc4.red(e.message));
1086
1225
  process.exit(1);
1087
1226
  }
1088
1227
  const s = p3.spinner();
1089
- if (options.prod) {
1090
- p3.log.step(pc4.magenta("Production Mode: Pulling from PROD environment"));
1091
- const apiUrl = `${liveUrl}/api/v1`;
1092
- s.start(`Fetching plans from ${pc4.dim("prod")}...`);
1093
- const plans = await fetchPlans({
1094
- apiKey,
1095
- apiUrl,
1096
- ...filters
1097
- });
1098
- s.stop(`Fetched ${plans.length} plans from prod`);
1099
- s.start(`Fetching credit systems...`);
1100
- const creditSystems = await fetchCreditSystems(apiKey, apiUrl);
1101
- s.stop(`Fetched ${creditSystems.length} credit systems`);
1102
- s.start(`Fetching credit packs...`);
1103
- const creditPacks = await fetchCreditPacks(apiKey, apiUrl);
1104
- s.stop(`Fetched ${creditPacks.length} credit packs`);
1105
- const providers = new Set(
1106
- plans.map((p9) => p9.provider).filter(Boolean)
1107
- );
1108
- const defaultProvider = providers.size === 1 ? Array.from(providers)[0] : void 0;
1109
- const configContent = generateConfig(
1110
- plans,
1111
- creditSystems,
1112
- creditPacks,
1113
- defaultProvider,
1114
- format
1228
+ const modeLabel = options.prod ? "prod" : "sandbox";
1229
+ const modeMessage = options.prod ? pc4.magenta("Production Mode: Pulling from PROD environment") : pc4.cyan("Sandbox Mode: Pulling from SANDBOX environment");
1230
+ const apiUrl = `${options.prod ? liveUrl : testUrl}/api/v1`;
1231
+ p3.log.step(modeMessage);
1232
+ s.start(`Fetching remote catalog from ${pc4.dim(modeLabel)}...`);
1233
+ const snapshot = await buildRemoteCatalogSnapshot({
1234
+ apiKey,
1235
+ apiUrl,
1236
+ format,
1237
+ filters
1238
+ });
1239
+ s.stop(
1240
+ `Fetched ${snapshot.plans.length} plans, ${snapshot.creditSystems.length} credit systems, and ${snapshot.creditPacks.length} credit packs from ${modeLabel}`
1241
+ );
1242
+ if (options.dryRun) {
1243
+ p3.note(snapshot.configContent, "Generated Config (Dry Run)");
1244
+ printPullSummary(
1245
+ snapshot.plans,
1246
+ snapshot.creditSystems,
1247
+ snapshot.creditPacks
1115
1248
  );
1116
- if (options.dryRun) {
1117
- p3.note(configContent, "Generated Config (Dry Run)");
1118
- printPullSummary(plans, creditSystems, creditPacks);
1119
- p3.outro(pc4.yellow("Dry run complete. No changes made."));
1120
- return;
1121
- }
1122
- if (existsSync3(fullPath) && !options.force) {
1123
- const confirm4 = await p3.confirm({
1124
- message: `Config file already exists at ${fullPath}. Overwrite?`,
1125
- initialValue: false
1126
- });
1127
- if (p3.isCancel(confirm4) || !confirm4) {
1128
- p3.outro(pc4.yellow("Operation cancelled"));
1129
- process.exit(0);
1130
- }
1131
- }
1132
- await writeFile2(fullPath, configContent, "utf8");
1133
- p3.log.success(pc4.green(`Wrote configuration to ${fullPath}`));
1134
- printPullSummary(plans, creditSystems, creditPacks);
1135
- } else {
1136
- p3.log.step(pc4.cyan("Sandbox Mode: Pulling from SANDBOX environment"));
1137
- const apiUrl = `${testUrl}/api/v1`;
1138
- s.start(`Fetching plans from ${pc4.dim("sandbox")}...`);
1139
- const plans = await fetchPlans({
1140
- apiKey,
1141
- apiUrl,
1142
- ...filters
1249
+ p3.outro(pc4.yellow("Dry run complete. No changes made."));
1250
+ return;
1251
+ }
1252
+ if (existsSync3(fullPath) && !options.force) {
1253
+ const confirm4 = await p3.confirm({
1254
+ message: `Config file already exists${options.prod ? ` at ${fullPath}` : ""}. Overwrite?`,
1255
+ initialValue: false
1143
1256
  });
1144
- s.stop(`Fetched ${plans.length} plans from sandbox`);
1145
- s.start(`Fetching credit systems...`);
1146
- const creditSystems = await fetchCreditSystems(apiKey, apiUrl);
1147
- s.stop(`Fetched ${creditSystems.length} credit systems`);
1148
- s.start(`Fetching credit packs...`);
1149
- const creditPacks = await fetchCreditPacks(apiKey, apiUrl);
1150
- s.stop(`Fetched ${creditPacks.length} credit packs`);
1151
- const providers = new Set(
1152
- plans.map((p9) => p9.provider).filter(Boolean)
1153
- );
1154
- const defaultProvider = providers.size === 1 ? Array.from(providers)[0] : void 0;
1155
- const configContent = generateConfig(
1156
- plans,
1157
- creditSystems,
1158
- creditPacks,
1159
- defaultProvider,
1160
- format
1161
- );
1162
- if (options.dryRun) {
1163
- p3.note(configContent, "Generated Config (Dry Run)");
1164
- printPullSummary(plans, creditSystems, creditPacks);
1165
- p3.outro(pc4.yellow("Dry run complete. No changes made."));
1166
- return;
1167
- }
1168
- if (existsSync3(fullPath) && !options.force) {
1169
- const confirm4 = await p3.confirm({
1170
- message: `Config file already exists. Overwrite?`,
1171
- initialValue: false
1172
- });
1173
- if (p3.isCancel(confirm4) || !confirm4) {
1174
- p3.outro(pc4.yellow("Operation cancelled"));
1175
- process.exit(0);
1176
- }
1257
+ if (p3.isCancel(confirm4) || !confirm4) {
1258
+ p3.outro(pc4.yellow("Operation cancelled"));
1259
+ process.exit(0);
1177
1260
  }
1178
- await writeFile2(fullPath, configContent, "utf8");
1179
- p3.log.success(pc4.green(`Wrote configuration to ${fullPath}`));
1180
- printPullSummary(plans, creditSystems, creditPacks);
1181
1261
  }
1262
+ await writeFile2(fullPath, snapshot.configContent, "utf8");
1263
+ p3.log.success(pc4.green(`Wrote configuration to ${fullPath}`));
1264
+ printPullSummary(
1265
+ snapshot.plans,
1266
+ snapshot.creditSystems,
1267
+ snapshot.creditPacks
1268
+ );
1182
1269
  p3.outro(pc4.green("Pull complete! \u2728"));
1183
1270
  }
1184
1271
  function printPullSummary(plans, creditSystems, creditPacks = []) {
@@ -1332,7 +1419,7 @@ import * as p6 from "@clack/prompts";
1332
1419
  import pc7 from "picocolors";
1333
1420
  import { existsSync as existsSync4 } from "fs";
1334
1421
  import { writeFile as writeFile3 } from "fs/promises";
1335
- import { join as join2, resolve as resolve3, isAbsolute as isAbsolute3, extname as extname3 } from "path";
1422
+ import { join as join2, resolve as resolve3, isAbsolute as isAbsolute3 } from "path";
1336
1423
 
1337
1424
  // src/lib/connect.ts
1338
1425
  import * as p5 from "@clack/prompts";
@@ -1450,16 +1537,21 @@ async function runInit(options) {
1450
1537
  }
1451
1538
  }
1452
1539
  const fullPath = isAbsolute3(targetPath) ? targetPath : resolve3(process.cwd(), targetPath);
1540
+ const configSettings = await loadConfigSettings(options.config);
1541
+ const testUrl = getTestApiUrl(
1542
+ configSettings.environments?.test || configSettings.apiUrl
1543
+ );
1544
+ const filters = configSettings.filters || {};
1453
1545
  let apiKey = getApiKey(options.key);
1454
1546
  if (!apiKey) {
1455
1547
  p6.log.warn(
1456
1548
  pc7.yellow("No API key found. Let's connect your account first.")
1457
1549
  );
1458
1550
  apiKey = await executeConnectFlow({
1459
- apiUrl: getApiUrl(),
1460
- dashboardUrl: getDashboardUrl(),
1551
+ apiUrl: testUrl,
1552
+ dashboardUrl: getDashboardUrl(configSettings.connect?.dashboardUrl),
1461
1553
  noBrowser: false,
1462
- timeout: 300
1554
+ timeout: configSettings.connect?.timeout || 300
1463
1555
  }) || "";
1464
1556
  if (!apiKey) {
1465
1557
  p6.log.error(pc7.red("Could not obtain API key. Initialization aborted."));
@@ -1479,36 +1571,21 @@ async function runInit(options) {
1479
1571
  const s = p6.spinner();
1480
1572
  s.start("Generating project configuration...");
1481
1573
  try {
1482
- const apiUrl = `${getApiUrl()}/api/v1`;
1483
- const plans = await fetchPlans({ apiKey, apiUrl });
1484
- const creditSystems = await fetchCreditSystems(apiKey, apiUrl);
1485
- const ext = extname3(fullPath);
1486
- let format = "ts";
1487
- if (ext === ".ts" || ext === ".mts" || ext === ".cts") {
1488
- format = "ts";
1489
- } else if (ext === ".mjs") {
1490
- format = "esm";
1491
- } else if (ext === ".cjs") {
1492
- throw new Error(
1493
- "CommonJS config files are not supported. Use owo.config.js or owo.config.ts."
1494
- );
1495
- } else if (ext === ".js") {
1496
- format = "esm";
1497
- }
1498
- const configContent = generateConfig(
1499
- plans,
1500
- creditSystems,
1501
- [],
1502
- void 0,
1503
- format
1504
- );
1505
- await writeFile3(fullPath, configContent, "utf8");
1574
+ const format = determineConfigFormat(fullPath);
1575
+ const snapshot = await buildRemoteCatalogSnapshot({
1576
+ apiKey,
1577
+ apiUrl: `${testUrl}/api/v1`,
1578
+ format,
1579
+ filters
1580
+ });
1581
+ await writeFile3(fullPath, snapshot.configContent, "utf8");
1506
1582
  s.stop(pc7.green("Configuration created"));
1507
1583
  p6.note(
1508
1584
  `${pc7.dim("File:")} ${fullPath}
1509
1585
  ${pc7.dim("Format:")} ${format.toUpperCase()}
1510
- ${pc7.dim("Plans:")} ${plans.length} imported
1511
- ${pc7.dim("Credit Systems:")} ${creditSystems.length}`,
1586
+ ${pc7.dim("Plans:")} ${snapshot.plans.length} imported
1587
+ ${pc7.dim("Credit Systems:")} ${snapshot.creditSystems.length}
1588
+ ${pc7.dim("Credit Packs:")} ${snapshot.creditPacks.length}`,
1512
1589
  "\u2728 Project Initialized"
1513
1590
  );
1514
1591
  p6.outro(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "owosk",
3
- "version": "0.2.3",
3
+ "version": "0.3.1",
4
4
  "description": "CLI for Owostack - sync catalog, manage billing infrastructure",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -24,8 +24,8 @@
24
24
  "commander": "^14.0.3",
25
25
  "jiti": "^2.6.1",
26
26
  "picocolors": "^1.1.1",
27
- "@owostack/types": "0.2.0",
28
- "owostack": "0.2.0"
27
+ "@owostack/types": "0.3.1",
28
+ "owostack": "0.3.1"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@types/node": "^22.19.10",