atmn 0.0.4 → 0.0.6
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/cli.cjs +603 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +581 -51
- package/dist/index.cjs +48 -0
- package/dist/index.d.cts +175 -0
- package/dist/index.d.ts +175 -0
- package/dist/index.js +42 -0
- package/package.json +8 -6
- package/dist/app.d.ts +0 -6
- package/dist/app.js +0 -7
- package/dist/commands/auth.d.ts +0 -1
- package/dist/commands/auth.js +0 -63
- package/dist/commands/init.d.ts +0 -3
- package/dist/commands/init.js +0 -26
- package/dist/commands/pull.d.ts +0 -3
- package/dist/commands/pull.js +0 -28
- package/dist/commands/push.d.ts +0 -5
- package/dist/commands/push.js +0 -47
- package/dist/constants.d.ts +0 -3
- package/dist/constants.js +0 -55
- package/dist/core/api.d.ts +0 -27
- package/dist/core/api.js +0 -75
- package/dist/core/auth.d.ts +0 -1
- package/dist/core/auth.js +0 -8
- package/dist/core/builders/features.d.ts +0 -2
- package/dist/core/builders/features.js +0 -10
- package/dist/core/builders/products.d.ts +0 -7
- package/dist/core/builders/products.js +0 -71
- package/dist/core/config.d.ts +0 -2
- package/dist/core/config.js +0 -25
- package/dist/core/pull.d.ts +0 -17
- package/dist/core/pull.js +0 -22
- package/dist/core/push.d.ts +0 -7
- package/dist/core/push.js +0 -67
- package/dist/core/utils.d.ts +0 -3
- package/dist/core/utils.js +0 -26
package/dist/cli.cjs
ADDED
|
@@ -0,0 +1,603 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var commander = require('commander');
|
|
5
|
+
var chalk6 = require('chalk');
|
|
6
|
+
var axios = require('axios');
|
|
7
|
+
var fs = require('fs');
|
|
8
|
+
var path = require('path');
|
|
9
|
+
var createJiti = require('jiti');
|
|
10
|
+
var url = require('url');
|
|
11
|
+
var open = require('open');
|
|
12
|
+
var prompts = require('@inquirer/prompts');
|
|
13
|
+
|
|
14
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
15
|
+
|
|
16
|
+
var chalk6__default = /*#__PURE__*/_interopDefault(chalk6);
|
|
17
|
+
var axios__default = /*#__PURE__*/_interopDefault(axios);
|
|
18
|
+
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
19
|
+
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
20
|
+
var createJiti__default = /*#__PURE__*/_interopDefault(createJiti);
|
|
21
|
+
var open__default = /*#__PURE__*/_interopDefault(open);
|
|
22
|
+
|
|
23
|
+
// ../node_modules/.pnpm/tsup@8.5.0_jiti@2.4.2_postcss@8.5.6_tsx@4.20.3_typescript@5.8.3_yaml@2.8.0/node_modules/tsup/assets/cjs_shims.js
|
|
24
|
+
var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.src || new URL("main.js", document.baseURI).href;
|
|
25
|
+
var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
26
|
+
|
|
27
|
+
// source/constants.ts
|
|
28
|
+
var FRONTEND_URL = "http://app.useautumn.com";
|
|
29
|
+
var BACKEND_URL = "https://api.useautumn.com";
|
|
30
|
+
var DEFAULT_CONFIG = `import {
|
|
31
|
+
feature,
|
|
32
|
+
product,
|
|
33
|
+
priceItem,
|
|
34
|
+
featureItem,
|
|
35
|
+
pricedFeatureItem,
|
|
36
|
+
} from 'atmn';
|
|
37
|
+
|
|
38
|
+
const seats = feature({
|
|
39
|
+
id: 'seats',
|
|
40
|
+
name: 'Seats',
|
|
41
|
+
type: 'continuous_use',
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const messages = feature({
|
|
45
|
+
id: 'messages',
|
|
46
|
+
name: 'Messages',
|
|
47
|
+
type: 'single_use',
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const pro = product({
|
|
51
|
+
id: 'pro',
|
|
52
|
+
name: 'Pro',
|
|
53
|
+
items: [
|
|
54
|
+
// 500 messages per month
|
|
55
|
+
featureItem({
|
|
56
|
+
feature_id: messages.id,
|
|
57
|
+
included_usage: 500,
|
|
58
|
+
interval: 'month',
|
|
59
|
+
}),
|
|
60
|
+
|
|
61
|
+
// $10 per seat per month
|
|
62
|
+
pricedFeatureItem({
|
|
63
|
+
feature_id: seats.id,
|
|
64
|
+
price: 10,
|
|
65
|
+
interval: 'month',
|
|
66
|
+
}),
|
|
67
|
+
|
|
68
|
+
// $50 / month
|
|
69
|
+
priceItem({
|
|
70
|
+
price: 50,
|
|
71
|
+
interval: 'month',
|
|
72
|
+
}),
|
|
73
|
+
],
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const autumnConfig = {
|
|
77
|
+
features: [seats, messages],
|
|
78
|
+
products: [pro],
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export default autumnConfig;
|
|
82
|
+
`;
|
|
83
|
+
function snakeCaseToCamelCase(value) {
|
|
84
|
+
return value.replace(/_([a-z])/g, (match, letter) => letter.toUpperCase());
|
|
85
|
+
}
|
|
86
|
+
function idToVar(id) {
|
|
87
|
+
return id.replace(/[-_](.)/g, (_, letter) => letter.toUpperCase()).replace(/^[^a-zA-Z_$]/, "_").replace(/[^a-zA-Z0-9_$]/g, "");
|
|
88
|
+
}
|
|
89
|
+
function storeToEnv(prodKey, sandboxKey) {
|
|
90
|
+
const envPath = `${process.cwd()}/.env`;
|
|
91
|
+
const envVars = `# AUTUMN_SECRET_KEY=${prodKey}
|
|
92
|
+
AUTUMN_SECRET_KEY=${sandboxKey}
|
|
93
|
+
`;
|
|
94
|
+
if (fs__default.default.existsSync(envPath)) {
|
|
95
|
+
fs__default.default.appendFileSync(envPath, envVars);
|
|
96
|
+
console.log(chalk6__default.default.green(".env file found. Appended keys."));
|
|
97
|
+
} else {
|
|
98
|
+
fs__default.default.writeFileSync(envPath, envVars);
|
|
99
|
+
console.log(chalk6__default.default.green(".env file not found. Created new .env file and wrote keys."));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function readFromEnv() {
|
|
103
|
+
const envPath = `${process.cwd()}/.env`;
|
|
104
|
+
if (!fs__default.default.existsSync(envPath)) {
|
|
105
|
+
return void 0;
|
|
106
|
+
}
|
|
107
|
+
const envContent = fs__default.default.readFileSync(envPath, "utf-8");
|
|
108
|
+
const match = envContent.match(/^AUTUMN_SECRET_KEY=(.*)$/m);
|
|
109
|
+
return match ? match[1] : void 0;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// source/core/api.ts
|
|
113
|
+
var INTERNAL_BASE = BACKEND_URL;
|
|
114
|
+
var EXTERNAL_BASE = `${BACKEND_URL}/v1`;
|
|
115
|
+
async function request({
|
|
116
|
+
method,
|
|
117
|
+
base,
|
|
118
|
+
path: path2,
|
|
119
|
+
data,
|
|
120
|
+
headers,
|
|
121
|
+
customAuth,
|
|
122
|
+
throwOnError = true
|
|
123
|
+
}) {
|
|
124
|
+
const apiKey = readFromEnv();
|
|
125
|
+
try {
|
|
126
|
+
const response = await axios__default.default.request({
|
|
127
|
+
method,
|
|
128
|
+
url: `${base}${path2}`,
|
|
129
|
+
data,
|
|
130
|
+
headers: {
|
|
131
|
+
"Content-Type": "application/json",
|
|
132
|
+
...headers,
|
|
133
|
+
Authorization: customAuth || `Bearer ${apiKey}`
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
return response.data;
|
|
137
|
+
} catch (error) {
|
|
138
|
+
if (throwOnError) {
|
|
139
|
+
throw error;
|
|
140
|
+
}
|
|
141
|
+
console.error(
|
|
142
|
+
chalk6__default.default.red("Error occured when making API request:"),
|
|
143
|
+
chalk6__default.default.red(error.response.data.message || error.response.data.error)
|
|
144
|
+
);
|
|
145
|
+
process.exit(1);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
async function internalRequest({
|
|
149
|
+
method,
|
|
150
|
+
path: path2,
|
|
151
|
+
data,
|
|
152
|
+
headers,
|
|
153
|
+
customAuth
|
|
154
|
+
}) {
|
|
155
|
+
return await request({
|
|
156
|
+
method,
|
|
157
|
+
base: INTERNAL_BASE,
|
|
158
|
+
path: path2,
|
|
159
|
+
data,
|
|
160
|
+
headers,
|
|
161
|
+
customAuth
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
async function externalRequest({
|
|
165
|
+
method,
|
|
166
|
+
path: path2,
|
|
167
|
+
data,
|
|
168
|
+
headers,
|
|
169
|
+
customAuth,
|
|
170
|
+
throwOnError = false
|
|
171
|
+
}) {
|
|
172
|
+
return await request({
|
|
173
|
+
method,
|
|
174
|
+
base: EXTERNAL_BASE,
|
|
175
|
+
path: path2,
|
|
176
|
+
data,
|
|
177
|
+
headers,
|
|
178
|
+
customAuth,
|
|
179
|
+
throwOnError
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
async function deleteFeature(id) {
|
|
183
|
+
return await externalRequest({
|
|
184
|
+
method: "DELETE",
|
|
185
|
+
path: `/features/${id}`
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
async function deleteProduct(id) {
|
|
189
|
+
return await externalRequest({
|
|
190
|
+
method: "DELETE",
|
|
191
|
+
path: `/products/${id}`
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
async function updateCLIStripeKeys(stripeTestKey, stripeLiveKey, stripeFlowAuthKey) {
|
|
195
|
+
return await internalRequest({
|
|
196
|
+
method: "POST",
|
|
197
|
+
path: "/dev/cli/stripe",
|
|
198
|
+
data: {
|
|
199
|
+
stripeTestKey,
|
|
200
|
+
stripeLiveKey,
|
|
201
|
+
successUrl: "https://useautumn.com",
|
|
202
|
+
defaultCurrency: "usd"
|
|
203
|
+
},
|
|
204
|
+
customAuth: stripeFlowAuthKey
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// source/core/pull.ts
|
|
209
|
+
async function getAllProducts() {
|
|
210
|
+
const { list } = await externalRequest({
|
|
211
|
+
method: "GET",
|
|
212
|
+
path: "/products"
|
|
213
|
+
});
|
|
214
|
+
return list.map((product) => product);
|
|
215
|
+
}
|
|
216
|
+
async function getFeatures() {
|
|
217
|
+
const { list } = await externalRequest({
|
|
218
|
+
method: "GET",
|
|
219
|
+
path: "/features"
|
|
220
|
+
});
|
|
221
|
+
return list.map((feature) => feature);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// source/core/builders/products.ts
|
|
225
|
+
var ItemBuilders = {
|
|
226
|
+
priced_feature: pricedFeatureItemBuilder,
|
|
227
|
+
feature: featureItemBuilder,
|
|
228
|
+
price: priceItemBuilder
|
|
229
|
+
};
|
|
230
|
+
function importBuilder() {
|
|
231
|
+
return `
|
|
232
|
+
import {
|
|
233
|
+
feature,
|
|
234
|
+
product,
|
|
235
|
+
featureItem,
|
|
236
|
+
pricedFeatureItem,
|
|
237
|
+
priceItem,
|
|
238
|
+
} from 'atmn';
|
|
239
|
+
`;
|
|
240
|
+
}
|
|
241
|
+
function exportBuilder(productIds, featureIds) {
|
|
242
|
+
const snippet = `
|
|
243
|
+
const autumnConfig = {
|
|
244
|
+
products: [${productIds.map((id) => `${idToVar(id)}`).join(", ")}],
|
|
245
|
+
features: [${featureIds.map((id) => `${idToVar(id)}`).join(", ")}]
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export default autumnConfig;
|
|
249
|
+
`;
|
|
250
|
+
return snippet;
|
|
251
|
+
}
|
|
252
|
+
function productBuilder(product) {
|
|
253
|
+
const snippet = `
|
|
254
|
+
export const ${idToVar(product.id)} = product({
|
|
255
|
+
id: '${product.id}',
|
|
256
|
+
name: '${product.name}',
|
|
257
|
+
items: [${product.items.map(
|
|
258
|
+
(item) => `${ItemBuilders[item.type](item)}`
|
|
259
|
+
).join(" ")} ]
|
|
260
|
+
})
|
|
261
|
+
`;
|
|
262
|
+
return snippet;
|
|
263
|
+
}
|
|
264
|
+
function pricedFeatureItemBuilder(item) {
|
|
265
|
+
const intervalLine = item.interval == null ? "" : `
|
|
266
|
+
interval: '${item.interval}',`;
|
|
267
|
+
const snippet = `
|
|
268
|
+
pricedFeatureItem({
|
|
269
|
+
feature_id: ${idToVar(item.feature_id)}.id,
|
|
270
|
+
price: ${item.price},${intervalLine}
|
|
271
|
+
included_usage: ${item.included_usage},
|
|
272
|
+
billing_units: ${item.billing_units},
|
|
273
|
+
usage_model: '${item.usage_model}',
|
|
274
|
+
}),
|
|
275
|
+
`;
|
|
276
|
+
return snippet;
|
|
277
|
+
}
|
|
278
|
+
function featureItemBuilder(item) {
|
|
279
|
+
const intervalLine = item.interval == null ? "" : `
|
|
280
|
+
interval: '${item.interval}',`;
|
|
281
|
+
const snippet = `
|
|
282
|
+
featureItem({
|
|
283
|
+
feature_id: ${idToVar(item.feature_id)}.id,
|
|
284
|
+
included_usage: ${item.included_usage},${intervalLine}
|
|
285
|
+
}),
|
|
286
|
+
`;
|
|
287
|
+
return snippet;
|
|
288
|
+
}
|
|
289
|
+
function priceItemBuilder(item) {
|
|
290
|
+
const intervalLine = item.interval == null ? "" : `
|
|
291
|
+
interval: '${item.interval}',`;
|
|
292
|
+
const snippet = `
|
|
293
|
+
priceItem({
|
|
294
|
+
price: ${item.price},${intervalLine}
|
|
295
|
+
}),
|
|
296
|
+
`;
|
|
297
|
+
return snippet;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// source/core/builders/features.ts
|
|
301
|
+
function featureBuilder(feature) {
|
|
302
|
+
const snippet = `
|
|
303
|
+
export const ${idToVar(feature.id)} = feature({
|
|
304
|
+
id: '${feature.id}',
|
|
305
|
+
name: '${feature.name}',
|
|
306
|
+
type: '${feature.type}',
|
|
307
|
+
})`;
|
|
308
|
+
return snippet;
|
|
309
|
+
}
|
|
310
|
+
async function loadAutumnConfigFile() {
|
|
311
|
+
const configPath = path__default.default.join(process.cwd(), "autumn.config.ts");
|
|
312
|
+
const absolutePath = path.resolve(configPath);
|
|
313
|
+
const fileUrl = url.pathToFileURL(absolutePath).href;
|
|
314
|
+
const jiti = createJiti__default.default(importMetaUrl);
|
|
315
|
+
const mod = await jiti.import(fileUrl);
|
|
316
|
+
const def = mod.default || mod;
|
|
317
|
+
if (!def.products || !Array.isArray(def.products)) {
|
|
318
|
+
throw new Error(
|
|
319
|
+
"You must export a products field that is an array of products."
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
if (!def.features || !Array.isArray(def.features)) {
|
|
323
|
+
throw new Error(
|
|
324
|
+
"You must export a features field that is an array of products."
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
return def;
|
|
328
|
+
}
|
|
329
|
+
function writeConfig(config) {
|
|
330
|
+
const configPath = path__default.default.join(process.cwd(), "autumn.config.ts");
|
|
331
|
+
fs__default.default.writeFileSync(configPath, config);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// source/commands/pull.ts
|
|
335
|
+
async function Pull({ config }) {
|
|
336
|
+
console.log(chalk6__default.default.green("Pulling products and features from Autumn..."));
|
|
337
|
+
const products = await getAllProducts();
|
|
338
|
+
const features = await getFeatures();
|
|
339
|
+
const productSnippets = products.map(
|
|
340
|
+
(product) => productBuilder(product)
|
|
341
|
+
);
|
|
342
|
+
const featureSnippets = features.map(
|
|
343
|
+
(feature) => featureBuilder(feature)
|
|
344
|
+
);
|
|
345
|
+
const autumnConfig = `
|
|
346
|
+
${importBuilder()}
|
|
347
|
+
|
|
348
|
+
// Features
|
|
349
|
+
${featureSnippets.join("\n")}
|
|
350
|
+
|
|
351
|
+
// Products
|
|
352
|
+
${productSnippets.join("\n")}
|
|
353
|
+
|
|
354
|
+
// Remember to update this when you make changes!
|
|
355
|
+
${exportBuilder(
|
|
356
|
+
products.map((product) => product.id),
|
|
357
|
+
features.map((feature) => snakeCaseToCamelCase(feature.id))
|
|
358
|
+
)}
|
|
359
|
+
`;
|
|
360
|
+
writeConfig(autumnConfig);
|
|
361
|
+
console.log(chalk6__default.default.green("Success! Config has been updated."));
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// source/core/auth.ts
|
|
365
|
+
async function getOTP(otp) {
|
|
366
|
+
const response = await internalRequest({
|
|
367
|
+
method: "GET",
|
|
368
|
+
path: `/dev/otp/${otp}`
|
|
369
|
+
});
|
|
370
|
+
return response;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// source/commands/auth.ts
|
|
374
|
+
var passwordTheme = {
|
|
375
|
+
style: {
|
|
376
|
+
answer: (text) => {
|
|
377
|
+
return chalk6__default.default.magenta("*".repeat(text.length));
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
var inputTheme = {
|
|
382
|
+
style: {
|
|
383
|
+
answer: (text) => {
|
|
384
|
+
return chalk6__default.default.magenta(text);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
async function AuthCommand() {
|
|
389
|
+
if (readFromEnv()) {
|
|
390
|
+
let shouldReauth = await prompts.confirm({
|
|
391
|
+
message: "You are already authenticated. Would you like to re-authenticate?",
|
|
392
|
+
theme: inputTheme
|
|
393
|
+
});
|
|
394
|
+
if (!shouldReauth) {
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
open__default.default(`${FRONTEND_URL}/dev/cli`);
|
|
399
|
+
const otp = await prompts.input({
|
|
400
|
+
message: "Enter OTP:",
|
|
401
|
+
theme: inputTheme
|
|
402
|
+
});
|
|
403
|
+
const keyInfo = await getOTP(otp);
|
|
404
|
+
if (!keyInfo.stripe_connected) {
|
|
405
|
+
let connectStripe = await prompts.confirm({
|
|
406
|
+
message: "It seems like your organization doesn't have any Stripe keys connected. Would you like to connect them now?",
|
|
407
|
+
theme: inputTheme
|
|
408
|
+
});
|
|
409
|
+
if (connectStripe) {
|
|
410
|
+
let stripeTestKey = await prompts.password({
|
|
411
|
+
message: "Enter Stripe Test Secret Key:",
|
|
412
|
+
mask: "*",
|
|
413
|
+
theme: passwordTheme
|
|
414
|
+
});
|
|
415
|
+
await updateCLIStripeKeys(
|
|
416
|
+
stripeTestKey,
|
|
417
|
+
stripeTestKey,
|
|
418
|
+
keyInfo.stripeFlowAuthKey
|
|
419
|
+
);
|
|
420
|
+
} else {
|
|
421
|
+
console.log(
|
|
422
|
+
chalk6__default.default.yellow(
|
|
423
|
+
"Okay, no worries. Go to the Autumn dashboard when you're ready!"
|
|
424
|
+
)
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
storeToEnv(keyInfo.prodKey, keyInfo.sandboxKey);
|
|
429
|
+
console.log(
|
|
430
|
+
chalk6__default.default.green(
|
|
431
|
+
"Success! Keys have been stored locally. You may now use the CLI."
|
|
432
|
+
)
|
|
433
|
+
);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// source/commands/init.ts
|
|
437
|
+
async function Init({ config }) {
|
|
438
|
+
let apiKey = readFromEnv();
|
|
439
|
+
if (apiKey) {
|
|
440
|
+
console.log(chalk6__default.default.green("API key found. Pulling latest config..."));
|
|
441
|
+
await Pull({ config });
|
|
442
|
+
console.log(chalk6__default.default.green("Project initialized and config pulled successfully!"));
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
console.log(chalk6__default.default.yellow("No API key found. Running authentication..."));
|
|
446
|
+
await AuthCommand();
|
|
447
|
+
apiKey = readFromEnv();
|
|
448
|
+
if (apiKey) {
|
|
449
|
+
await Pull({ config });
|
|
450
|
+
console.log(chalk6__default.default.green("Project initialized! You are now authenticated and config has been pulled."));
|
|
451
|
+
} else {
|
|
452
|
+
console.log(chalk6__default.default.red("Authentication did not yield an API key. Please check your setup."));
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// source/core/push.ts
|
|
457
|
+
async function checkForDeletables(currentFeatures, currentProducts) {
|
|
458
|
+
const features = await getFeatures();
|
|
459
|
+
const featureIds = features.map((feature) => feature.id);
|
|
460
|
+
const currentFeatureIds = currentFeatures.map((feature) => feature.id);
|
|
461
|
+
const featuresToDelete = featureIds.filter(
|
|
462
|
+
(featureId) => !currentFeatureIds.includes(featureId)
|
|
463
|
+
);
|
|
464
|
+
const products = await getAllProducts();
|
|
465
|
+
const productIds = products.map((product) => product.id);
|
|
466
|
+
const currentProductIds = currentProducts.map((product) => product.id);
|
|
467
|
+
const productsToDelete = productIds.filter(
|
|
468
|
+
(productId) => !currentProductIds.includes(productId)
|
|
469
|
+
);
|
|
470
|
+
return { featuresToDelete, productsToDelete };
|
|
471
|
+
}
|
|
472
|
+
async function upsertFeature(feature) {
|
|
473
|
+
try {
|
|
474
|
+
const response = await externalRequest({
|
|
475
|
+
method: "POST",
|
|
476
|
+
path: `/features`,
|
|
477
|
+
data: feature,
|
|
478
|
+
throwOnError: true
|
|
479
|
+
// data: {
|
|
480
|
+
// ...feature,
|
|
481
|
+
// config: {
|
|
482
|
+
// filters: [{property: '', operator: '', value: []}],
|
|
483
|
+
// usage_type: 'single_use',
|
|
484
|
+
// },
|
|
485
|
+
// },
|
|
486
|
+
});
|
|
487
|
+
return response.data;
|
|
488
|
+
} catch (error) {
|
|
489
|
+
const response = await externalRequest({
|
|
490
|
+
method: "POST",
|
|
491
|
+
path: `/features/${feature.id}`,
|
|
492
|
+
data: feature
|
|
493
|
+
// data: {
|
|
494
|
+
// ...feature,
|
|
495
|
+
// config: {
|
|
496
|
+
// filters: [{property: '', operator: '', value: []}],
|
|
497
|
+
// usage_type: 'single_use',
|
|
498
|
+
// },
|
|
499
|
+
// },
|
|
500
|
+
});
|
|
501
|
+
return response.data;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
async function upsertProduct(product) {
|
|
505
|
+
try {
|
|
506
|
+
const response = await externalRequest({
|
|
507
|
+
method: "POST",
|
|
508
|
+
path: `/products`,
|
|
509
|
+
data: product,
|
|
510
|
+
throwOnError: true
|
|
511
|
+
});
|
|
512
|
+
return response.data;
|
|
513
|
+
} catch (error) {
|
|
514
|
+
const response = await externalRequest({
|
|
515
|
+
method: "POST",
|
|
516
|
+
path: `/products/${product.id}`,
|
|
517
|
+
data: product
|
|
518
|
+
});
|
|
519
|
+
return response.data;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// source/commands/push.ts
|
|
524
|
+
async function Push({
|
|
525
|
+
config,
|
|
526
|
+
yes,
|
|
527
|
+
prod
|
|
528
|
+
}) {
|
|
529
|
+
let { features, products } = config;
|
|
530
|
+
let { featuresToDelete, productsToDelete } = await checkForDeletables(
|
|
531
|
+
features,
|
|
532
|
+
products
|
|
533
|
+
);
|
|
534
|
+
for (let productId of productsToDelete) {
|
|
535
|
+
let shouldDelete = yes || await prompts.confirm({
|
|
536
|
+
message: `Delete product [${productId}]?`
|
|
537
|
+
});
|
|
538
|
+
if (shouldDelete) {
|
|
539
|
+
await deleteProduct(productId);
|
|
540
|
+
console.log(chalk6__default.default.green(`Product [${productId}] deleted successfully!`));
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
for (let feature of features) {
|
|
544
|
+
console.log(chalk6__default.default.green(`Pushing feature [${feature.id}]`));
|
|
545
|
+
await upsertFeature(feature);
|
|
546
|
+
console.log(chalk6__default.default.green(`Pushed feature [${feature.id}]`));
|
|
547
|
+
}
|
|
548
|
+
for (let product of products) {
|
|
549
|
+
console.log(chalk6__default.default.green(`Pushing product [${product.id}]`));
|
|
550
|
+
await upsertProduct(product);
|
|
551
|
+
console.log(chalk6__default.default.green(`Pushed product [${product.id}]`));
|
|
552
|
+
}
|
|
553
|
+
for (let featureId of featuresToDelete) {
|
|
554
|
+
let shouldDelete = yes || await prompts.confirm({
|
|
555
|
+
message: `Delete feature [${featureId}]?`
|
|
556
|
+
});
|
|
557
|
+
if (shouldDelete) {
|
|
558
|
+
await deleteFeature(featureId);
|
|
559
|
+
console.log(chalk6__default.default.green(`Feature [${featureId}] deleted successfully!`));
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
const env = prod ? "prod" : "sandbox";
|
|
563
|
+
console.log(
|
|
564
|
+
chalk6__default.default.magentaBright(`Success! Changes have been pushed to ${env}.`)
|
|
565
|
+
);
|
|
566
|
+
if (prod) {
|
|
567
|
+
console.log(
|
|
568
|
+
chalk6__default.default.magentaBright(
|
|
569
|
+
`You can view the products at ${FRONTEND_URL}/products`
|
|
570
|
+
)
|
|
571
|
+
);
|
|
572
|
+
} else {
|
|
573
|
+
console.log(
|
|
574
|
+
chalk6__default.default.magentaBright(
|
|
575
|
+
`You can view the products at ${FRONTEND_URL}/sandbox/products`
|
|
576
|
+
)
|
|
577
|
+
);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
var VERSION = "1.0.0b";
|
|
581
|
+
commander.program.command("push").description("Push changes to Autumn").option("-p, --prod", "Push to production").option("-y, --yes", "Confirm all deletions").action(async (options) => {
|
|
582
|
+
const config = await loadAutumnConfigFile();
|
|
583
|
+
await Push({ config, yes: options.yes, prod: options.prod });
|
|
584
|
+
});
|
|
585
|
+
commander.program.command("pull").description("Pull changes from Autumn").option("-p, --prod", "Pull from production").action(async () => {
|
|
586
|
+
const config = await loadAutumnConfigFile();
|
|
587
|
+
await Pull({ config });
|
|
588
|
+
});
|
|
589
|
+
commander.program.command("init").description("Initialize an Autumn project.").action(async () => {
|
|
590
|
+
writeConfig(DEFAULT_CONFIG);
|
|
591
|
+
const config = await loadAutumnConfigFile();
|
|
592
|
+
await Init({ config });
|
|
593
|
+
});
|
|
594
|
+
commander.program.command("login").description("Authenticate with Autumn").option("-p, --prod", "Authenticate with production").action(async () => {
|
|
595
|
+
await AuthCommand();
|
|
596
|
+
});
|
|
597
|
+
commander.program.command("dashboard").description("Open the Autumn dashboard in your browser").action(() => {
|
|
598
|
+
open__default.default(`${FRONTEND_URL}`);
|
|
599
|
+
});
|
|
600
|
+
commander.program.command("version").description("Show the version of Autumn").action(() => {
|
|
601
|
+
console.log(chalk6__default.default.green(`Autumn v${VERSION}`));
|
|
602
|
+
});
|
|
603
|
+
commander.program.parse();
|
package/dist/cli.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/cli.d.ts
CHANGED