owosk 0.2.2 → 0.3.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/README.md +7 -7
- package/dist/index.js +225 -145
- 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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
66
|
+
npx owosk connect
|
|
67
67
|
```
|
|
68
68
|
|
|
69
69
|
## Features
|
package/dist/index.js
CHANGED
|
@@ -17,6 +17,9 @@ var GLOBAL_CONFIG_PATH = join(GLOBAL_CONFIG_DIR, "config.json");
|
|
|
17
17
|
function getApiUrl(configUrl) {
|
|
18
18
|
return process.env.OWOSTACK_API_URL || configUrl || "https://sandbox.owostack.com";
|
|
19
19
|
}
|
|
20
|
+
function getLiveApiUrl(configUrl) {
|
|
21
|
+
return process.env.OWOSTACK_API_LIVE_URL || process.env.OWOSTACK_API_URL || configUrl || "https://api.owostack.com";
|
|
22
|
+
}
|
|
20
23
|
function getTestApiUrl(configUrl) {
|
|
21
24
|
return process.env.OWOSTACK_API_TEST_URL || configUrl || "https://sandbox.owostack.com";
|
|
22
25
|
}
|
|
@@ -228,19 +231,51 @@ async function fetchCreditPacks(apiKey, apiUrl) {
|
|
|
228
231
|
// src/lib/diff.ts
|
|
229
232
|
import pc2 from "picocolors";
|
|
230
233
|
import * as p from "@clack/prompts";
|
|
231
|
-
function
|
|
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);
|
|
232
260
|
return {
|
|
233
261
|
slug: pf.slug,
|
|
234
262
|
enabled: pf.enabled,
|
|
235
263
|
limit: pf.limit ?? null,
|
|
236
264
|
// Handle both SDK 'reset' and API 'resetInterval'
|
|
237
|
-
reset: pf.reset || pf.resetInterval
|
|
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,
|
|
238
271
|
// Handle both SDK 'overage' and API 'overage' (same name)
|
|
239
|
-
overage: pf.overage
|
|
240
|
-
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
|
|
241
276
|
};
|
|
242
277
|
}
|
|
243
|
-
function normalizePlan(plan) {
|
|
278
|
+
function normalizePlan(plan, creditSystemSlugs) {
|
|
244
279
|
return {
|
|
245
280
|
slug: plan.slug,
|
|
246
281
|
name: plan.name ?? null,
|
|
@@ -252,7 +287,18 @@ function normalizePlan(plan) {
|
|
|
252
287
|
trialDays: plan.trialDays ?? 0,
|
|
253
288
|
isAddon: plan.isAddon ?? false,
|
|
254
289
|
autoEnable: plan.autoEnable ?? false,
|
|
255
|
-
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))
|
|
256
302
|
};
|
|
257
303
|
}
|
|
258
304
|
function normalizeCreditPack(pack) {
|
|
@@ -268,10 +314,18 @@ function normalizeCreditPack(pack) {
|
|
|
268
314
|
};
|
|
269
315
|
}
|
|
270
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
|
+
]);
|
|
271
321
|
const localMap = /* @__PURE__ */ new Map();
|
|
272
322
|
const remoteMap = /* @__PURE__ */ new Map();
|
|
273
|
-
for (const p9 of localPlans)
|
|
274
|
-
|
|
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
|
+
}
|
|
275
329
|
const onlyLocal = [];
|
|
276
330
|
const onlyRemote = [];
|
|
277
331
|
const changed = [];
|
|
@@ -325,8 +379,15 @@ function diffPlans(localPlans, remotePlans, localCreditSystems = [], remoteCredi
|
|
|
325
379
|
"enabled",
|
|
326
380
|
"limit",
|
|
327
381
|
"reset",
|
|
382
|
+
"usageModel",
|
|
383
|
+
"pricePerUnit",
|
|
384
|
+
"billingUnits",
|
|
385
|
+
"ratingModel",
|
|
386
|
+
"tiers",
|
|
328
387
|
"overage",
|
|
329
|
-
"overagePrice"
|
|
388
|
+
"overagePrice",
|
|
389
|
+
"maxOverageUnits",
|
|
390
|
+
"creditCost"
|
|
330
391
|
];
|
|
331
392
|
for (const ff of featureFields) {
|
|
332
393
|
if (JSON.stringify(lf[ff]) !== JSON.stringify(rf[ff])) {
|
|
@@ -350,8 +411,12 @@ function diffPlans(localPlans, remotePlans, localCreditSystems = [], remoteCredi
|
|
|
350
411
|
}
|
|
351
412
|
const localCsMap = /* @__PURE__ */ new Map();
|
|
352
413
|
const remoteCsMap = /* @__PURE__ */ new Map();
|
|
353
|
-
for (const cs of localCreditSystems)
|
|
354
|
-
|
|
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
|
+
}
|
|
355
420
|
const csOnlyLocal = [];
|
|
356
421
|
const csOnlyRemote = [];
|
|
357
422
|
const csChanged = [];
|
|
@@ -746,7 +811,7 @@ async function runSync(options) {
|
|
|
746
811
|
p2.intro(pc3.bgYellow(pc3.black(" sync ")));
|
|
747
812
|
const configSettings = await loadConfigSettings(options.config);
|
|
748
813
|
const testUrl = getTestApiUrl(configSettings.environments?.test);
|
|
749
|
-
const liveUrl =
|
|
814
|
+
const liveUrl = getLiveApiUrl(configSettings.environments?.live);
|
|
750
815
|
if (options.prod) {
|
|
751
816
|
p2.log.step(pc3.magenta("Production Mode: Syncing to PROD environment"));
|
|
752
817
|
await runSyncSingle({
|
|
@@ -754,7 +819,7 @@ async function runSync(options) {
|
|
|
754
819
|
dryRun: !!options.dryRun,
|
|
755
820
|
autoApprove: !!options.yes,
|
|
756
821
|
apiKey: options.key || "",
|
|
757
|
-
apiUrl:
|
|
822
|
+
apiUrl: liveUrl,
|
|
758
823
|
environment: "prod"
|
|
759
824
|
});
|
|
760
825
|
} else {
|
|
@@ -776,7 +841,10 @@ import * as p3 from "@clack/prompts";
|
|
|
776
841
|
import pc4 from "picocolors";
|
|
777
842
|
import { existsSync as existsSync3 } from "fs";
|
|
778
843
|
import { writeFile as writeFile2 } from "fs/promises";
|
|
779
|
-
import { resolve as resolve2,
|
|
844
|
+
import { resolve as resolve2, isAbsolute as isAbsolute2 } from "path";
|
|
845
|
+
|
|
846
|
+
// src/lib/catalog-import.ts
|
|
847
|
+
import { extname as extname2 } from "path";
|
|
780
848
|
|
|
781
849
|
// src/lib/generate.ts
|
|
782
850
|
function slugToIdentifier(slug, used) {
|
|
@@ -831,6 +899,28 @@ function slugToIdentifier(slug, used) {
|
|
|
831
899
|
used.add(candidate);
|
|
832
900
|
return candidate;
|
|
833
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
|
+
}
|
|
834
924
|
function generateConfig(plans, creditSystems = [], creditPacks = [], defaultProvider, format = "ts") {
|
|
835
925
|
const isTs = format === "ts";
|
|
836
926
|
const creditSystemSlugs = new Set(creditSystems.map((cs) => cs.slug));
|
|
@@ -922,8 +1012,12 @@ function generateConfig(plans, creditSystems = [], creditPacks = [], defaultProv
|
|
|
922
1012
|
const csVar = creditSystemVars.get(pf.slug);
|
|
923
1013
|
if (csVar && pf.enabled) {
|
|
924
1014
|
const opts = [];
|
|
925
|
-
|
|
926
|
-
|
|
1015
|
+
const creditReset = normalizeResetForCodegen(
|
|
1016
|
+
pf.resetInterval || pf.reset
|
|
1017
|
+
);
|
|
1018
|
+
if (creditReset !== void 0) {
|
|
1019
|
+
opts.push(`reset: "${creditReset}"`);
|
|
1020
|
+
}
|
|
927
1021
|
if (pf.overage) opts.push(`overage: "${pf.overage}"`);
|
|
928
1022
|
if (opts.length > 0) {
|
|
929
1023
|
featureEntries.push(
|
|
@@ -947,11 +1041,23 @@ function generateConfig(plans, creditSystems = [], creditPacks = [], defaultProv
|
|
|
947
1041
|
if (pf.enabled === false) {
|
|
948
1042
|
const config2 = { enabled: false };
|
|
949
1043
|
if (pf.limit !== void 0) config2.limit = pf.limit;
|
|
950
|
-
|
|
951
|
-
|
|
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;
|
|
952
1055
|
if (pf.overage) config2.overage = pf.overage;
|
|
953
1056
|
if (pf.overagePrice !== void 0)
|
|
954
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;
|
|
955
1061
|
featureEntries.push(`${varName}.config(${JSON.stringify(config2)})`);
|
|
956
1062
|
continue;
|
|
957
1063
|
}
|
|
@@ -959,11 +1065,21 @@ function generateConfig(plans, creditSystems = [], creditPacks = [], defaultProv
|
|
|
959
1065
|
const config = {};
|
|
960
1066
|
if (pf.limit !== void 0) config.limit = pf.limit;
|
|
961
1067
|
if (!isEntityFeature) {
|
|
962
|
-
const reset =
|
|
963
|
-
|
|
1068
|
+
const reset = normalizeResetForCodegen(
|
|
1069
|
+
pf.resetInterval || pf.reset || "monthly"
|
|
1070
|
+
);
|
|
1071
|
+
if (reset !== void 0) config.reset = reset;
|
|
964
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;
|
|
965
1078
|
if (pf.overage) config.overage = pf.overage;
|
|
966
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;
|
|
967
1083
|
const configKeys = Object.keys(config);
|
|
968
1084
|
const hasExtras = configKeys.some((k) => k !== "limit");
|
|
969
1085
|
if (config.limit === null && !hasExtras) {
|
|
@@ -1042,8 +1158,8 @@ function generateConfig(plans, creditSystems = [], creditPacks = [], defaultProv
|
|
|
1042
1158
|
].filter(Boolean).join("\n");
|
|
1043
1159
|
}
|
|
1044
1160
|
|
|
1045
|
-
// src/
|
|
1046
|
-
function
|
|
1161
|
+
// src/lib/catalog-import.ts
|
|
1162
|
+
function determineConfigFormat(fullPath) {
|
|
1047
1163
|
const ext = extname2(fullPath);
|
|
1048
1164
|
if (ext === ".ts" || ext === ".mts" || ext === ".cts") return "ts";
|
|
1049
1165
|
if (ext === ".mjs") return "esm";
|
|
@@ -1055,6 +1171,32 @@ function determineFormat(fullPath) {
|
|
|
1055
1171
|
if (ext === ".js") return "esm";
|
|
1056
1172
|
return "ts";
|
|
1057
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
|
|
1058
1200
|
async function runPull(options) {
|
|
1059
1201
|
p3.intro(pc4.bgYellow(pc4.black(" pull ")));
|
|
1060
1202
|
let fullPath;
|
|
@@ -1073,109 +1215,57 @@ async function runPull(options) {
|
|
|
1073
1215
|
const apiKey = getApiKey(options.key);
|
|
1074
1216
|
const configSettings = await loadConfigSettings(options.config);
|
|
1075
1217
|
const testUrl = getTestApiUrl(configSettings.environments?.test);
|
|
1076
|
-
const liveUrl =
|
|
1218
|
+
const liveUrl = getLiveApiUrl(configSettings.environments?.live);
|
|
1077
1219
|
const filters = configSettings.filters || {};
|
|
1078
1220
|
let format;
|
|
1079
1221
|
try {
|
|
1080
|
-
format =
|
|
1222
|
+
format = determineConfigFormat(fullPath);
|
|
1081
1223
|
} catch (e) {
|
|
1082
1224
|
p3.log.error(pc4.red(e.message));
|
|
1083
1225
|
process.exit(1);
|
|
1084
1226
|
}
|
|
1085
1227
|
const s = p3.spinner();
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
plans
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
const configContent = generateConfig(
|
|
1107
|
-
plans,
|
|
1108
|
-
creditSystems,
|
|
1109
|
-
creditPacks,
|
|
1110
|
-
defaultProvider,
|
|
1111
|
-
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
|
|
1112
1248
|
);
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
const confirm4 = await p3.confirm({
|
|
1121
|
-
message: `Config file already exists at ${fullPath}. Overwrite?`,
|
|
1122
|
-
initialValue: false
|
|
1123
|
-
});
|
|
1124
|
-
if (p3.isCancel(confirm4) || !confirm4) {
|
|
1125
|
-
p3.outro(pc4.yellow("Operation cancelled"));
|
|
1126
|
-
process.exit(0);
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1129
|
-
await writeFile2(fullPath, configContent, "utf8");
|
|
1130
|
-
p3.log.success(pc4.green(`Wrote configuration to ${fullPath}`));
|
|
1131
|
-
printPullSummary(plans, creditSystems, creditPacks);
|
|
1132
|
-
} else {
|
|
1133
|
-
p3.log.step(pc4.cyan("Sandbox Mode: Pulling from SANDBOX environment"));
|
|
1134
|
-
const apiUrl = `${testUrl}/api/v1`;
|
|
1135
|
-
s.start(`Fetching plans from ${pc4.dim("sandbox")}...`);
|
|
1136
|
-
const plans = await fetchPlans({
|
|
1137
|
-
apiKey,
|
|
1138
|
-
apiUrl,
|
|
1139
|
-
...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
|
|
1140
1256
|
});
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
s.stop(`Fetched ${creditSystems.length} credit systems`);
|
|
1145
|
-
s.start(`Fetching credit packs...`);
|
|
1146
|
-
const creditPacks = await fetchCreditPacks(apiKey, apiUrl);
|
|
1147
|
-
s.stop(`Fetched ${creditPacks.length} credit packs`);
|
|
1148
|
-
const providers = new Set(
|
|
1149
|
-
plans.map((p9) => p9.provider).filter(Boolean)
|
|
1150
|
-
);
|
|
1151
|
-
const defaultProvider = providers.size === 1 ? Array.from(providers)[0] : void 0;
|
|
1152
|
-
const configContent = generateConfig(
|
|
1153
|
-
plans,
|
|
1154
|
-
creditSystems,
|
|
1155
|
-
creditPacks,
|
|
1156
|
-
defaultProvider,
|
|
1157
|
-
format
|
|
1158
|
-
);
|
|
1159
|
-
if (options.dryRun) {
|
|
1160
|
-
p3.note(configContent, "Generated Config (Dry Run)");
|
|
1161
|
-
printPullSummary(plans, creditSystems, creditPacks);
|
|
1162
|
-
p3.outro(pc4.yellow("Dry run complete. No changes made."));
|
|
1163
|
-
return;
|
|
1164
|
-
}
|
|
1165
|
-
if (existsSync3(fullPath) && !options.force) {
|
|
1166
|
-
const confirm4 = await p3.confirm({
|
|
1167
|
-
message: `Config file already exists. Overwrite?`,
|
|
1168
|
-
initialValue: false
|
|
1169
|
-
});
|
|
1170
|
-
if (p3.isCancel(confirm4) || !confirm4) {
|
|
1171
|
-
p3.outro(pc4.yellow("Operation cancelled"));
|
|
1172
|
-
process.exit(0);
|
|
1173
|
-
}
|
|
1257
|
+
if (p3.isCancel(confirm4) || !confirm4) {
|
|
1258
|
+
p3.outro(pc4.yellow("Operation cancelled"));
|
|
1259
|
+
process.exit(0);
|
|
1174
1260
|
}
|
|
1175
|
-
await writeFile2(fullPath, configContent, "utf8");
|
|
1176
|
-
p3.log.success(pc4.green(`Wrote configuration to ${fullPath}`));
|
|
1177
|
-
printPullSummary(plans, creditSystems, creditPacks);
|
|
1178
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
|
+
);
|
|
1179
1269
|
p3.outro(pc4.green("Pull complete! \u2728"));
|
|
1180
1270
|
}
|
|
1181
1271
|
function printPullSummary(plans, creditSystems, creditPacks = []) {
|
|
@@ -1231,7 +1321,7 @@ async function runDiff(options) {
|
|
|
1231
1321
|
const apiKey = getApiKey(options.key);
|
|
1232
1322
|
const configSettings = await loadConfigSettings(options.config);
|
|
1233
1323
|
const testUrl = getTestApiUrl(configSettings.environments?.test);
|
|
1234
|
-
const liveUrl =
|
|
1324
|
+
const liveUrl = getLiveApiUrl(configSettings.environments?.live);
|
|
1235
1325
|
const s = p4.spinner();
|
|
1236
1326
|
if (options.prod) {
|
|
1237
1327
|
p4.log.step(pc5.magenta("Production Mode: Comparing with PROD environment"));
|
|
@@ -1329,7 +1419,7 @@ import * as p6 from "@clack/prompts";
|
|
|
1329
1419
|
import pc7 from "picocolors";
|
|
1330
1420
|
import { existsSync as existsSync4 } from "fs";
|
|
1331
1421
|
import { writeFile as writeFile3 } from "fs/promises";
|
|
1332
|
-
import { join as join2, resolve as resolve3, isAbsolute as isAbsolute3
|
|
1422
|
+
import { join as join2, resolve as resolve3, isAbsolute as isAbsolute3 } from "path";
|
|
1333
1423
|
|
|
1334
1424
|
// src/lib/connect.ts
|
|
1335
1425
|
import * as p5 from "@clack/prompts";
|
|
@@ -1447,16 +1537,21 @@ async function runInit(options) {
|
|
|
1447
1537
|
}
|
|
1448
1538
|
}
|
|
1449
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 || {};
|
|
1450
1545
|
let apiKey = getApiKey(options.key);
|
|
1451
1546
|
if (!apiKey) {
|
|
1452
1547
|
p6.log.warn(
|
|
1453
1548
|
pc7.yellow("No API key found. Let's connect your account first.")
|
|
1454
1549
|
);
|
|
1455
1550
|
apiKey = await executeConnectFlow({
|
|
1456
|
-
apiUrl:
|
|
1457
|
-
dashboardUrl: getDashboardUrl(),
|
|
1551
|
+
apiUrl: testUrl,
|
|
1552
|
+
dashboardUrl: getDashboardUrl(configSettings.connect?.dashboardUrl),
|
|
1458
1553
|
noBrowser: false,
|
|
1459
|
-
timeout: 300
|
|
1554
|
+
timeout: configSettings.connect?.timeout || 300
|
|
1460
1555
|
}) || "";
|
|
1461
1556
|
if (!apiKey) {
|
|
1462
1557
|
p6.log.error(pc7.red("Could not obtain API key. Initialization aborted."));
|
|
@@ -1476,36 +1571,21 @@ async function runInit(options) {
|
|
|
1476
1571
|
const s = p6.spinner();
|
|
1477
1572
|
s.start("Generating project configuration...");
|
|
1478
1573
|
try {
|
|
1479
|
-
const
|
|
1480
|
-
const
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
format = "esm";
|
|
1488
|
-
} else if (ext === ".cjs") {
|
|
1489
|
-
throw new Error(
|
|
1490
|
-
"CommonJS config files are not supported. Use owo.config.js or owo.config.ts."
|
|
1491
|
-
);
|
|
1492
|
-
} else if (ext === ".js") {
|
|
1493
|
-
format = "esm";
|
|
1494
|
-
}
|
|
1495
|
-
const configContent = generateConfig(
|
|
1496
|
-
plans,
|
|
1497
|
-
creditSystems,
|
|
1498
|
-
[],
|
|
1499
|
-
void 0,
|
|
1500
|
-
format
|
|
1501
|
-
);
|
|
1502
|
-
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");
|
|
1503
1582
|
s.stop(pc7.green("Configuration created"));
|
|
1504
1583
|
p6.note(
|
|
1505
1584
|
`${pc7.dim("File:")} ${fullPath}
|
|
1506
1585
|
${pc7.dim("Format:")} ${format.toUpperCase()}
|
|
1507
|
-
${pc7.dim("Plans:")} ${plans.length} imported
|
|
1508
|
-
${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}`,
|
|
1509
1589
|
"\u2728 Project Initialized"
|
|
1510
1590
|
);
|
|
1511
1591
|
p6.outro(
|
|
@@ -1585,7 +1665,7 @@ async function runValidate(options) {
|
|
|
1585
1665
|
}
|
|
1586
1666
|
const configSettings = await loadConfigSettings(options.config);
|
|
1587
1667
|
const testUrl = getTestApiUrl(configSettings.environments?.test);
|
|
1588
|
-
const liveUrl =
|
|
1668
|
+
const liveUrl = getLiveApiUrl(configSettings.environments?.live);
|
|
1589
1669
|
const apiKey = getApiKey();
|
|
1590
1670
|
if (options.prod) {
|
|
1591
1671
|
p7.log.step(pc8.magenta("Production Mode: Checking PROD environment"));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "owosk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
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.
|
|
28
|
-
"owostack": "0.
|
|
27
|
+
"@owostack/types": "0.3.0",
|
|
28
|
+
"owostack": "0.3.0"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@types/node": "^22.19.10",
|