atmn 2.0.32 → 2.0.34
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/bin.js +1408 -188
- package/dist/index.js +220 -19
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/actions/pull/webhooks/appendWebhook.ts +84 -0
- package/src/actions/pull/webhooks/applyWebhooksPull.ts +100 -0
- package/src/actions/pull/webhooks/locateWebhook.ts +22 -0
- package/src/actions/pull/webhooks/removeWebhookEnv.ts +141 -0
- package/src/actions/pull/webhooks/types.ts +20 -0
- package/src/actions/pull/webhooks/updateWebhook.ts +138 -0
- package/src/actions/pull.ts +32 -2
- package/src/actions/push/pushLanesError.ts +47 -0
- package/src/actions/push.ts +220 -60
- package/src/actions/webhooks/applyWebhooks.ts +52 -0
- package/src/actions/webhooks/isDashboardWebhook.ts +9 -0
- package/src/actions/webhooks/newWebhookId.ts +4 -0
- package/src/actions/webhooks/previewWebhooks.ts +40 -0
- package/src/actions/webhooks/resolveWebhookEnv.ts +34 -0
- package/src/actions/webhooks/resolveWebhooksForEnv.ts +29 -0
- package/src/actions/webhooks/types/webhookEnv.ts +9 -0
- package/src/actions/webhooks/webhookSecretName.ts +22 -0
- package/src/actions/webhooks/writeWebhookSecrets.ts +55 -0
- package/src/cli.ts +20 -1
- package/src/config/loadConfig.ts +3 -0
- package/src/generated/apiRoutes.ts +165 -1
- package/src/generated/client.ts +239 -1
- package/src/generated/emit.ts +20 -1
- package/src/generated/emitRuntime.ts +8 -0
- package/src/generated/isLocalWebhookUrl.ts +64 -0
- package/src/generated/lintRules.ts +95 -0
- package/src/generated/lintRuntime.ts +113 -10
- package/src/generated/sandboxName.ts +52 -0
- package/src/generated/skills.ts +10 -10
- package/src/generated/webhooks.ts +36 -0
- package/src/generated/wire.ts +32 -5
- package/src/index.ts +1 -0
- package/src/render/renderPreview.ts +17 -2
- package/src/render/renderWebhooks.ts +92 -0
- package/src/surgery/appendPropertyEdit.ts +9 -3
- package/src/surgery/patchFixturePaths.ts +57 -5
package/dist/index.js
CHANGED
|
@@ -16,6 +16,59 @@ var featureGrant = (input) => ({
|
|
|
16
16
|
});
|
|
17
17
|
// src/generated/variants.ts
|
|
18
18
|
var variant = (input) => input;
|
|
19
|
+
// src/generated/webhooks.ts
|
|
20
|
+
var webhook = (input) => input;
|
|
21
|
+
// src/generated/isLocalWebhookUrl.ts
|
|
22
|
+
var PRIVATE_IPV4_RANGES = [
|
|
23
|
+
[0, 32],
|
|
24
|
+
[2130706432, 8],
|
|
25
|
+
[167772160, 8],
|
|
26
|
+
[2886729728, 12],
|
|
27
|
+
[3232235520, 16],
|
|
28
|
+
[2851995648, 16]
|
|
29
|
+
];
|
|
30
|
+
var parseIpv4 = (host) => {
|
|
31
|
+
const parts = host.split(".");
|
|
32
|
+
if (parts.length !== 4)
|
|
33
|
+
return null;
|
|
34
|
+
if (parts.some((part) => !/^\d+$/.test(part) || Number(part) > 255)) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
return parts.reduce((acc, part) => acc * 256 + Number(part), 0);
|
|
38
|
+
};
|
|
39
|
+
var isPrivateIpv4 = (address) => PRIVATE_IPV4_RANGES.some(([base, prefixBits]) => {
|
|
40
|
+
const mask = prefixBits === 0 ? 0 : 4294967295 << 32 - prefixBits >>> 0;
|
|
41
|
+
return (address & mask) >>> 0 === base;
|
|
42
|
+
});
|
|
43
|
+
var isLocalIpv6 = (host) => {
|
|
44
|
+
if (host === "::1" || host === "::")
|
|
45
|
+
return true;
|
|
46
|
+
if (/^fe[89ab][0-9a-f]:/.test(host))
|
|
47
|
+
return true;
|
|
48
|
+
if (/^f[cd][0-9a-f]{0,2}:/.test(host))
|
|
49
|
+
return true;
|
|
50
|
+
const [, high, low] = host.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/) ?? [];
|
|
51
|
+
if (!high || !low)
|
|
52
|
+
return false;
|
|
53
|
+
return isPrivateIpv4(Number.parseInt(high, 16) * 65536 + Number.parseInt(low, 16));
|
|
54
|
+
};
|
|
55
|
+
var isLocalWebhookUrl = (url) => {
|
|
56
|
+
let hostname;
|
|
57
|
+
try {
|
|
58
|
+
hostname = new URL(url).hostname.toLowerCase().replace(/\.$/, "");
|
|
59
|
+
} catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
if (hostname.startsWith("[") && hostname.endsWith("]")) {
|
|
63
|
+
return isLocalIpv6(hostname.slice(1, -1));
|
|
64
|
+
}
|
|
65
|
+
if (hostname === "localhost" || hostname.endsWith(".localhost") || hostname.endsWith(".local")) {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
const ipv4 = parseIpv4(hostname);
|
|
69
|
+
return ipv4 !== null && isPrivateIpv4(ipv4);
|
|
70
|
+
};
|
|
71
|
+
|
|
19
72
|
// src/generated/lintRules.ts
|
|
20
73
|
var LINT_RULES = {
|
|
21
74
|
features: {
|
|
@@ -319,6 +372,10 @@ var LINT_RULES = {
|
|
|
319
372
|
keys: {
|
|
320
373
|
minLength: 1,
|
|
321
374
|
maxLength: 64
|
|
375
|
+
},
|
|
376
|
+
values: {
|
|
377
|
+
minLength: 1,
|
|
378
|
+
maxLength: 128
|
|
322
379
|
}
|
|
323
380
|
},
|
|
324
381
|
"plans.billingControls.usageLimits": {
|
|
@@ -342,6 +399,10 @@ var LINT_RULES = {
|
|
|
342
399
|
keys: {
|
|
343
400
|
minLength: 1,
|
|
344
401
|
maxLength: 64
|
|
402
|
+
},
|
|
403
|
+
values: {
|
|
404
|
+
minLength: 1,
|
|
405
|
+
maxLength: 128
|
|
345
406
|
}
|
|
346
407
|
},
|
|
347
408
|
"plans.freeTrial": {
|
|
@@ -1312,6 +1373,10 @@ var LINT_RULES = {
|
|
|
1312
1373
|
keys: {
|
|
1313
1374
|
minLength: 1,
|
|
1314
1375
|
maxLength: 64
|
|
1376
|
+
},
|
|
1377
|
+
values: {
|
|
1378
|
+
minLength: 1,
|
|
1379
|
+
maxLength: 128
|
|
1315
1380
|
}
|
|
1316
1381
|
},
|
|
1317
1382
|
"plans.variants.customize.billingControls.usageLimits": {
|
|
@@ -1335,6 +1400,10 @@ var LINT_RULES = {
|
|
|
1335
1400
|
keys: {
|
|
1336
1401
|
minLength: 1,
|
|
1337
1402
|
maxLength: 64
|
|
1403
|
+
},
|
|
1404
|
+
values: {
|
|
1405
|
+
minLength: 1,
|
|
1406
|
+
maxLength: 128
|
|
1338
1407
|
}
|
|
1339
1408
|
},
|
|
1340
1409
|
"plans.variants.customize.freeTrial": {
|
|
@@ -2161,6 +2230,80 @@ var LINT_RULES = {
|
|
|
2161
2230
|
exclusiveMinimum: 0
|
|
2162
2231
|
}
|
|
2163
2232
|
}
|
|
2233
|
+
},
|
|
2234
|
+
webhooks: {
|
|
2235
|
+
label: "webhook",
|
|
2236
|
+
idField: "id",
|
|
2237
|
+
required: ["events", "id", "url"],
|
|
2238
|
+
fields: {
|
|
2239
|
+
id: {
|
|
2240
|
+
minLength: 1,
|
|
2241
|
+
maxLength: 256,
|
|
2242
|
+
pattern: "^[a-zA-Z0-9_-]+$"
|
|
2243
|
+
},
|
|
2244
|
+
events: {
|
|
2245
|
+
minItems: 1
|
|
2246
|
+
}
|
|
2247
|
+
},
|
|
2248
|
+
rules: [
|
|
2249
|
+
{
|
|
2250
|
+
kind: "unique",
|
|
2251
|
+
field: "id",
|
|
2252
|
+
because: "Two webhooks claiming one id race to define the same endpoint."
|
|
2253
|
+
},
|
|
2254
|
+
{
|
|
2255
|
+
kind: "unique",
|
|
2256
|
+
field: "id",
|
|
2257
|
+
asEnvName: true,
|
|
2258
|
+
because: "Each webhook's signing secret is saved as AUTUMN_WEBHOOK_<ID>_SECRET, so these two would overwrite each other's secret. Rename one."
|
|
2259
|
+
},
|
|
2260
|
+
{
|
|
2261
|
+
kind: "rejects",
|
|
2262
|
+
field: "url",
|
|
2263
|
+
check: "isLocalWebhookUrl",
|
|
2264
|
+
because: "Autumn delivers from the internet, so localhost and private-network addresses can never be reached. Use a public URL or a tunnel (e.g. ngrok)."
|
|
2265
|
+
},
|
|
2266
|
+
{
|
|
2267
|
+
kind: "uniformPrefix",
|
|
2268
|
+
field: "events",
|
|
2269
|
+
prefix: "vercel.",
|
|
2270
|
+
because: "vercel.* events can't be mixed with other events in one webhook: they're delivered from a separate app. Make one webhook for each."
|
|
2271
|
+
},
|
|
2272
|
+
{
|
|
2273
|
+
kind: "nonEmpty",
|
|
2274
|
+
field: "url",
|
|
2275
|
+
warning: true,
|
|
2276
|
+
because: "With no environment key the webhook is registered nowhere. Add `live`, `sandbox` or a sandbox's slug."
|
|
2277
|
+
},
|
|
2278
|
+
{
|
|
2279
|
+
kind: "knownValues",
|
|
2280
|
+
field: "events",
|
|
2281
|
+
values: [
|
|
2282
|
+
"customer.products.updated",
|
|
2283
|
+
"customer.threshold_reached",
|
|
2284
|
+
"balances.usage_alert_triggered",
|
|
2285
|
+
"balances.limit_reached",
|
|
2286
|
+
"billing.auto_topup_failed",
|
|
2287
|
+
"billing.auto_topup_succeeded",
|
|
2288
|
+
"billing.updated",
|
|
2289
|
+
"invoice.finalized",
|
|
2290
|
+
"vercel.resources.deleted",
|
|
2291
|
+
"vercel.resources.provisioned",
|
|
2292
|
+
"vercel.resources.rotate_secrets",
|
|
2293
|
+
"vercel.webhooks.event"
|
|
2294
|
+
],
|
|
2295
|
+
warning: true,
|
|
2296
|
+
because: "isn't known to this atmn version; the server will check it."
|
|
2297
|
+
}
|
|
2298
|
+
]
|
|
2299
|
+
},
|
|
2300
|
+
"webhooks.url": {
|
|
2301
|
+
keys: {
|
|
2302
|
+
pattern: "^[a-z0-9_-]+$"
|
|
2303
|
+
},
|
|
2304
|
+
values: {
|
|
2305
|
+
pattern: "^[Hh][Tt][Tt][Pp][Ss]:\\/\\/"
|
|
2306
|
+
}
|
|
2164
2307
|
}
|
|
2165
2308
|
};
|
|
2166
2309
|
|
|
@@ -2331,7 +2474,8 @@ var entryRuleFailures = ({
|
|
|
2331
2474
|
entry,
|
|
2332
2475
|
rule,
|
|
2333
2476
|
document,
|
|
2334
|
-
parent
|
|
2477
|
+
parent,
|
|
2478
|
+
checks
|
|
2335
2479
|
}) => {
|
|
2336
2480
|
switch (rule.kind) {
|
|
2337
2481
|
case "requiredWhen": {
|
|
@@ -2371,9 +2515,29 @@ var entryRuleFailures = ({
|
|
|
2371
2515
|
}
|
|
2372
2516
|
case "nonEmpty": {
|
|
2373
2517
|
const value = entry[rule.field];
|
|
2374
|
-
|
|
2518
|
+
const empty = Array.isArray(value) ? value.length === 0 : isEntry(value) && Object.keys(value).length === 0;
|
|
2519
|
+
return empty ? [`${rule.field} is empty. ${rule.because}`] : [];
|
|
2520
|
+
}
|
|
2521
|
+
case "knownValues": {
|
|
2522
|
+
const value = entry[rule.field];
|
|
2523
|
+
if (!Array.isArray(value))
|
|
2524
|
+
return [];
|
|
2525
|
+
return value.filter((item) => typeof item === "string" && !rule.values.includes(item)).map((item) => `\`${item}\` ${rule.because}`);
|
|
2526
|
+
}
|
|
2527
|
+
case "uniformPrefix": {
|
|
2528
|
+
const value = entry[rule.field];
|
|
2529
|
+
if (!Array.isArray(value))
|
|
2530
|
+
return [];
|
|
2531
|
+
const prefixed = value.filter((item) => typeof item === "string" && item.startsWith(rule.prefix)).length;
|
|
2532
|
+
return prefixed === 0 || prefixed === value.length ? [] : [rule.because];
|
|
2533
|
+
}
|
|
2534
|
+
case "rejects": {
|
|
2535
|
+
const value = entry[rule.field];
|
|
2536
|
+
const check = checks[rule.check];
|
|
2537
|
+
if (check === undefined)
|
|
2375
2538
|
return [];
|
|
2376
|
-
|
|
2539
|
+
const stated = typeof value === "string" ? [value] : isEntry(value) ? Object.values(value).filter((item) => typeof item === "string") : [];
|
|
2540
|
+
return stated.filter((item) => check(item)).map((item) => `${rule.field} ${show(item)} is refused. ${rule.because}`);
|
|
2377
2541
|
}
|
|
2378
2542
|
case "compare": {
|
|
2379
2543
|
const a = entry[rule.field];
|
|
@@ -2435,7 +2599,7 @@ var checkUnique = ({
|
|
|
2435
2599
|
trail,
|
|
2436
2600
|
issues
|
|
2437
2601
|
}) => {
|
|
2438
|
-
const seen = new
|
|
2602
|
+
const seen = new Map;
|
|
2439
2603
|
for (const [index, entry] of entries.entries()) {
|
|
2440
2604
|
if (!isEntry(entry))
|
|
2441
2605
|
continue;
|
|
@@ -2446,15 +2610,25 @@ var checkUnique = ({
|
|
|
2446
2610
|
const pair = rule.alongside === undefined ? undefined : entry[rule.alongside];
|
|
2447
2611
|
if (rule.alongside !== undefined && typeof pair !== "string")
|
|
2448
2612
|
continue;
|
|
2449
|
-
const
|
|
2450
|
-
|
|
2613
|
+
const normalized = rule.asEnvName ? value.toUpperCase().replace(/-/g, "_") : value;
|
|
2614
|
+
const composite = rule.alongside === undefined ? normalized : `${normalized}@${pair}`;
|
|
2615
|
+
const first = seen.get(composite);
|
|
2616
|
+
if (rule.asEnvName && first !== undefined) {
|
|
2617
|
+
if (first !== value)
|
|
2618
|
+
issues.push({
|
|
2619
|
+
path: render([...trail, crumbFor({ node, key, entry, index })]),
|
|
2620
|
+
message: `${fieldName} ${show(value)} and ${show(first)} both read as ${normalized} in an env var name. ${rule.because}`
|
|
2621
|
+
});
|
|
2622
|
+
continue;
|
|
2623
|
+
}
|
|
2624
|
+
if (first !== undefined) {
|
|
2451
2625
|
const label = rule.alongside === undefined ? `${fieldName} ${show(value)}` : `${fieldName} ${show(value)} with ${rule.alongside} ${show(pair)}`;
|
|
2452
2626
|
issues.push({
|
|
2453
2627
|
path: render([...trail, crumbFor({ node, key, entry, index })]),
|
|
2454
2628
|
message: `${label} is used more than once. ${rule.because}`
|
|
2455
2629
|
});
|
|
2456
2630
|
}
|
|
2457
|
-
seen.
|
|
2631
|
+
seen.set(composite, value);
|
|
2458
2632
|
}
|
|
2459
2633
|
};
|
|
2460
2634
|
var pinOf = ({
|
|
@@ -2595,13 +2769,15 @@ var checkEntry = ({
|
|
|
2595
2769
|
checkVariants({ entry, variants: node.variants, at, issues: walk.issues });
|
|
2596
2770
|
}
|
|
2597
2771
|
for (const rule of node.rules ?? []) {
|
|
2772
|
+
const warning = "warning" in rule && rule.warning === true;
|
|
2598
2773
|
for (const message of entryRuleFailures({
|
|
2599
2774
|
entry,
|
|
2600
2775
|
rule,
|
|
2601
2776
|
document: walk.document,
|
|
2602
|
-
parent
|
|
2777
|
+
parent,
|
|
2778
|
+
checks: walk.checks
|
|
2603
2779
|
})) {
|
|
2604
|
-
walk.issues.push({ path: at, message });
|
|
2780
|
+
walk.issues.push({ path: at, message, ...warning ? { warning } : {} });
|
|
2605
2781
|
}
|
|
2606
2782
|
}
|
|
2607
2783
|
};
|
|
@@ -2664,7 +2840,17 @@ var walkValue = ({
|
|
|
2664
2840
|
return;
|
|
2665
2841
|
if (walk.hints.recordPaths.has(path)) {
|
|
2666
2842
|
const keys = walk.rules[path]?.keys;
|
|
2843
|
+
const values = walk.rules[path]?.values;
|
|
2667
2844
|
for (const [recordKey, child] of Object.entries(value)) {
|
|
2845
|
+
if (values && !isEntry(child) && !Array.isArray(child)) {
|
|
2846
|
+
for (const message of constraintFailures({
|
|
2847
|
+
name: `${key}.${recordKey}`,
|
|
2848
|
+
value: child,
|
|
2849
|
+
constraints: values
|
|
2850
|
+
})) {
|
|
2851
|
+
walk.issues.push({ path: render(trail), message });
|
|
2852
|
+
}
|
|
2853
|
+
}
|
|
2668
2854
|
if (keys) {
|
|
2669
2855
|
for (const message of constraintFailures({
|
|
2670
2856
|
name: `${key} key ${show(recordKey)}`,
|
|
@@ -2690,9 +2876,10 @@ var walkValue = ({
|
|
|
2690
2876
|
var lintDocument = ({
|
|
2691
2877
|
document,
|
|
2692
2878
|
rules,
|
|
2693
|
-
hints
|
|
2879
|
+
hints,
|
|
2880
|
+
checks = {}
|
|
2694
2881
|
}) => {
|
|
2695
|
-
const walk = { document, rules, hints, issues: [] };
|
|
2882
|
+
const walk = { document, rules, hints, checks, issues: [] };
|
|
2696
2883
|
walkEntry({ entry: document, path: "", trail: [], walk });
|
|
2697
2884
|
return walk.issues;
|
|
2698
2885
|
};
|
|
@@ -2827,7 +3014,8 @@ var CATALOG_HINTS = hintsOf({
|
|
|
2827
3014
|
"plans.variants.customize.upsertLicenses.customize.addItems.featureOverride.creditSchema.multipliers",
|
|
2828
3015
|
"plans.variants.customize.upsertLicenses.customize.addItems.featureOverride.creditSchema.multipliers.*.match",
|
|
2829
3016
|
"plans.variants.customize.upsertLicenses.customize.addItems.featureOverride.markups.modelMarkups",
|
|
2830
|
-
"plans.variants.customize.upsertLicenses.customize.addItems.featureOverride.markups.providerMarkups"
|
|
3017
|
+
"plans.variants.customize.upsertLicenses.customize.addItems.featureOverride.markups.providerMarkups",
|
|
3018
|
+
"webhooks.url"
|
|
2831
3019
|
],
|
|
2832
3020
|
frozenPaths: [
|
|
2833
3021
|
"plans.licenses.metadata",
|
|
@@ -2844,15 +3032,19 @@ var stated = (config) => ({
|
|
|
2844
3032
|
} : {},
|
|
2845
3033
|
...config.rewards !== undefined ? { rewards: config.rewards } : {},
|
|
2846
3034
|
...config.referralPrograms !== undefined ? { referralPrograms: config.referralPrograms } : {},
|
|
2847
|
-
...config.settings !== undefined ? { settings: config.settings } : {}
|
|
3035
|
+
...config.settings !== undefined ? { settings: config.settings } : {},
|
|
3036
|
+
...config.webhooks !== undefined ? { webhooks: config.webhooks } : {}
|
|
2848
3037
|
});
|
|
2849
3038
|
var SINGLETON_KEYS = ["settings"];
|
|
3039
|
+
var LIST_KEYS = ["webhooks"];
|
|
3040
|
+
var WARNINGS_KEY = "lint_warnings";
|
|
2850
3041
|
var CONFIG_KEYS = [
|
|
2851
3042
|
"features",
|
|
2852
3043
|
"plans",
|
|
2853
3044
|
"rewards",
|
|
2854
3045
|
"referralPrograms",
|
|
2855
|
-
"settings"
|
|
3046
|
+
"settings",
|
|
3047
|
+
"webhooks"
|
|
2856
3048
|
];
|
|
2857
3049
|
var unknownKeyIssue = (key) => key === "planVersions" ? {
|
|
2858
3050
|
path: key,
|
|
@@ -2862,10 +3054,14 @@ var unknownKeyIssue = (key) => key === "planVersions" ? {
|
|
|
2862
3054
|
message: `${key} is not a config field. The fields are ${CONFIG_KEYS.join(", ")}.`
|
|
2863
3055
|
};
|
|
2864
3056
|
var splitWire = (document) => ({
|
|
2865
|
-
catalog: Object.fromEntries(Object.entries(document).filter(([key]) => !SINGLETON_KEYS.includes(key))),
|
|
3057
|
+
catalog: Object.fromEntries(Object.entries(document).filter(([key]) => !SINGLETON_KEYS.includes(key) && !LIST_KEYS.includes(key) && key !== WARNINGS_KEY)),
|
|
2866
3058
|
singletons: {
|
|
2867
3059
|
settings: document.settings === undefined ? undefined : { config: document.settings }
|
|
2868
|
-
}
|
|
3060
|
+
},
|
|
3061
|
+
lists: {
|
|
3062
|
+
webhooks: document.webhooks
|
|
3063
|
+
},
|
|
3064
|
+
warnings: document[WARNINGS_KEY] ?? []
|
|
2869
3065
|
});
|
|
2870
3066
|
var atmn = (config) => {
|
|
2871
3067
|
const unknownKeys = Object.keys(config).filter((key) => !CONFIG_KEYS.includes(key));
|
|
@@ -2875,21 +3071,26 @@ var atmn = (config) => {
|
|
|
2875
3071
|
const issues = lintDocument({
|
|
2876
3072
|
document,
|
|
2877
3073
|
rules: LINT_RULES,
|
|
2878
|
-
hints: CATALOG_HINTS
|
|
3074
|
+
hints: CATALOG_HINTS,
|
|
3075
|
+
checks: { isLocalWebhookUrl }
|
|
2879
3076
|
});
|
|
2880
|
-
|
|
2881
|
-
|
|
3077
|
+
const errors = issues.filter((issue) => issue.warning !== true);
|
|
3078
|
+
if (errors.length > 0)
|
|
3079
|
+
throw new ConfigError(errors);
|
|
3080
|
+
const warnings = issues.filter((issue) => issue.warning === true);
|
|
2882
3081
|
return {
|
|
2883
3082
|
...toWire({
|
|
2884
3083
|
value: document,
|
|
2885
3084
|
path: "",
|
|
2886
3085
|
hints: CATALOG_HINTS
|
|
2887
3086
|
}),
|
|
3087
|
+
...warnings.length > 0 ? { [WARNINGS_KEY]: warnings } : {},
|
|
2888
3088
|
skip_deletions: false,
|
|
2889
3089
|
migration: { draft: true }
|
|
2890
3090
|
};
|
|
2891
3091
|
};
|
|
2892
3092
|
export {
|
|
3093
|
+
webhook,
|
|
2893
3094
|
variant,
|
|
2894
3095
|
referralProgram,
|
|
2895
3096
|
plan,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"7.0.0-dev.20260511.1","root":["../src/bin.ts","../src/cli.ts","../src/index.ts","../src/version.ts","../src/actions/env.ts","../src/actions/login.ts","../src/actions/pull.ts","../src/actions/push.ts","../src/actions/api/callApi.ts","../src/actions/api/registerApiCommands.ts","../src/actions/env/fetchOrgInfo.ts","../src/actions/env/types/orgInfo.ts","../src/actions/init/runInit.ts","../src/actions/login/keyless.ts","../src/actions/pull/appendPlanVersionFixture.ts","../src/actions/pull/applyMappings.ts","../src/actions/pull/applyPreview.ts","../src/actions/pull/applySettingsPreview.ts","../src/actions/pull/changedFixtureKeys.ts","../src/actions/pull/elementStatesPlanId.ts","../src/actions/pull/listSourceFiles.ts","../src/actions/pull/locateFixture.ts","../src/actions/pull/pruneUnpulledPlanIds.ts","../src/actions/pull/resolveCollectionTarget.ts","../src/actions/pull/rewriteConfig.ts","../src/actions/pull/scaffoldConfig.ts","../src/actions/push/backfillInternalIds.ts","../src/actions/push/deprecatedFields.ts","../src/actions/reset/runReset.ts","../src/actions/sandbox/createSandbox.ts","../src/actions/sandbox/deleteSandbox.ts","../src/actions/sandbox/listSandboxes.ts","../src/actions/sandbox/useSandbox.ts","../src/actions/sandbox/withSandboxScopeHint.ts","../src/actions/sandbox/types/sandboxClient.ts","../src/actions/skills/ignoreBundledSkills.ts","../src/actions/skills/skills.ts","../src/auth/announceAuthorizationUrl.ts","../src/auth/buildAuthorizationUrl.ts","../src/auth/callbackPages.ts","../src/auth/createOrgApiKeys.ts","../src/auth/keyless.ts","../src/auth/oauthConfig.ts","../src/auth/runOAuthFlow.ts","../src/auth/browser/openSystemBrowser.ts","../src/auth/browser/tryOpenBrowser.ts","../src/auth/browser/watchLauncher.ts","../src/auth/types/browserOpener.ts","../src/auth/types/impersonationTokens.ts","../src/auth/types/oauthTokens.ts","../src/auth/types/orgApiKeys.ts","../src/config/configPackageName.ts","../src/config/legacyConfig.ts","../src/config/loadConfig.ts","../src/env/assertSandboxTarget.ts","../src/env/loadEnv.ts","../src/env/resolveTarget.ts","../src/env/sandboxKeyName.ts","../src/generated/apiRoutes.ts","../src/generated/client.ts","../src/generated/emit.ts","../src/generated/emitRuntime.ts","../src/generated/features.ts","../src/generated/labels.ts","../src/generated/licenses.ts","../src/generated/lintRules.ts","../src/generated/lintRuntime.ts","../src/generated/mappingAssignments.ts","../src/generated/plans.ts","../src/generated/referralPrograms.ts","../src/generated/rewards.ts","../src/generated/settings.ts","../src/generated/skills.ts","../src/generated/variants.ts","../src/generated/wire.ts","../src/http/autumnFetch.ts","../src/project/chooseConfigDir.ts","../src/project/resolveProject.ts","../src/project/rootMarker.ts","../src/prompt/prompt.ts","../src/prompt/select.ts","../src/render/renderEnv.ts","../src/render/renderPreview.ts","../src/render/renderSandboxes.ts","../src/render/stripTerminalControls.ts","../src/repo/findRepoRoot.ts","../src/surgery/appendPropertyEdit.ts","../src/surgery/appendToArray.ts","../src/surgery/appendToBinding.ts","../src/surgery/appendToCollection.ts","../src/surgery/appendToFixtureArray.ts","../src/surgery/arrayBinding.ts","../src/surgery/deleteFixtureLiteral.ts","../src/surgery/deleteReference.ts","../src/surgery/ensureBuilderImport.ts","../src/surgery/findFixture.ts","../src/surgery/fixtureEdit.ts","../src/surgery/fixtureLocation.ts","../src/surgery/insertCollection.ts","../src/surgery/insertFirstProperty.ts","../src/surgery/patchFixturePaths.ts","../src/surgery/patchFixtureProperty.ts","../src/surgery/patchSingletonProperty.ts","../src/surgery/readFixtureValue.ts","../src/surgery/replaceFixture.ts","../src/surgery/setFixtureProperty.ts","../src/surgery/staticFixtureRule.ts","../test/apiCommand.test.ts","../test/authorizationUrl.test.ts","../test/autumnFetch.test.ts","../test/backfill.test.ts","../test/backfillInlineVariants.test.ts","../test/backfillSlug.test.ts","../test/backfillVariants.test.ts","../test/chooseConfigDir.test.ts","../test/cliTargetFlags.test.ts","../test/client.test.ts","../test/configPackageName.test.ts","../test/emitFixture.test.ts","../test/env.test.ts","../test/envWriter.test.ts","../test/ignoreBundledSkills.test.ts","../test/init.test.ts","../test/keyless.test.ts","../test/legacyConfig.test.ts","../test/lintDocument.test.ts","../test/loadConfigNode.test.ts","../test/loadConfigV2.test.ts","../test/locateFixtureUnique.test.ts","../test/login.test.ts","../test/nodeNextTypes.test.ts","../test/patchFixturePaths.test.ts","../test/plans.test.ts","../test/previewIsEmpty.test.ts","../test/prompt.test.ts","../test/pull.test.ts","../test/pullByReference.test.ts","../test/pullFieldLevel.test.ts","../test/pullMappings.test.ts","../test/pullOmitDefaults.test.ts","../test/pullPlans.test.ts","../test/pullStatesSlugs.test.ts","../test/pullTwoCollections.test.ts","../test/readFixtureValue.test.ts","../test/renameHint.test.ts","../test/renderPreview.test.ts","../test/renderSandboxes.test.ts","../test/renderSettings.test.ts","../test/reset.test.ts","../test/resolveCollectionTarget.test.ts","../test/resolveProject.test.ts","../test/resolveTarget.test.ts","../test/sandboxActions.test.ts","../test/sandboxKeyName.test.ts","../test/sandboxUse.test.ts","../test/settingsActions.test.ts","../test/settingsWire.test.ts","../test/skills.test.ts","../test/watchLauncher.test.ts","../test/wireDocument.test.ts","../test/helpers/targetFor.ts","../test/surgery/appendToCollection.test.ts","../test/surgery/deleteFixtureLiteral.test.ts","../test/surgery/deleteReference.test.ts","../test/surgery/findFixture.test.ts","../test/surgery/fixtureLocation.test.ts","../test/surgery/insertCollection.test.ts","../test/surgery/insertFirstProperty.test.ts","../test/surgery/patchFixtureProperty.test.ts","../test/surgery/patchSingletonProperty.test.ts","../test/surgery/replaceFixture.test.ts","../test/surgery/staticFixtureRule.test.ts"]}
|
|
1
|
+
{"version":"7.0.0-dev.20260511.1","root":["../src/bin.ts","../src/cli.ts","../src/index.ts","../src/version.ts","../src/actions/env.ts","../src/actions/login.ts","../src/actions/pull.ts","../src/actions/push.ts","../src/actions/api/callApi.ts","../src/actions/api/registerApiCommands.ts","../src/actions/env/fetchOrgInfo.ts","../src/actions/env/types/orgInfo.ts","../src/actions/init/runInit.ts","../src/actions/login/keyless.ts","../src/actions/pull/appendPlanVersionFixture.ts","../src/actions/pull/applyMappings.ts","../src/actions/pull/applyPreview.ts","../src/actions/pull/applySettingsPreview.ts","../src/actions/pull/changedFixtureKeys.ts","../src/actions/pull/elementStatesPlanId.ts","../src/actions/pull/listSourceFiles.ts","../src/actions/pull/locateFixture.ts","../src/actions/pull/pruneUnpulledPlanIds.ts","../src/actions/pull/resolveCollectionTarget.ts","../src/actions/pull/rewriteConfig.ts","../src/actions/pull/scaffoldConfig.ts","../src/actions/pull/webhooks/appendWebhook.ts","../src/actions/pull/webhooks/applyWebhooksPull.ts","../src/actions/pull/webhooks/locateWebhook.ts","../src/actions/pull/webhooks/removeWebhookEnv.ts","../src/actions/pull/webhooks/types.ts","../src/actions/pull/webhooks/updateWebhook.ts","../src/actions/push/backfillInternalIds.ts","../src/actions/push/deprecatedFields.ts","../src/actions/push/pushLanesError.ts","../src/actions/reset/runReset.ts","../src/actions/sandbox/createSandbox.ts","../src/actions/sandbox/deleteSandbox.ts","../src/actions/sandbox/listSandboxes.ts","../src/actions/sandbox/useSandbox.ts","../src/actions/sandbox/withSandboxScopeHint.ts","../src/actions/sandbox/types/sandboxClient.ts","../src/actions/skills/ignoreBundledSkills.ts","../src/actions/skills/skills.ts","../src/actions/webhooks/applyWebhooks.ts","../src/actions/webhooks/isDashboardWebhook.ts","../src/actions/webhooks/newWebhookId.ts","../src/actions/webhooks/previewWebhooks.ts","../src/actions/webhooks/resolveWebhookEnv.ts","../src/actions/webhooks/resolveWebhooksForEnv.ts","../src/actions/webhooks/webhookSecretName.ts","../src/actions/webhooks/writeWebhookSecrets.ts","../src/actions/webhooks/types/webhookEnv.ts","../src/auth/announceAuthorizationUrl.ts","../src/auth/buildAuthorizationUrl.ts","../src/auth/callbackPages.ts","../src/auth/createOrgApiKeys.ts","../src/auth/keyless.ts","../src/auth/oauthConfig.ts","../src/auth/runOAuthFlow.ts","../src/auth/browser/openSystemBrowser.ts","../src/auth/browser/tryOpenBrowser.ts","../src/auth/browser/watchLauncher.ts","../src/auth/types/browserOpener.ts","../src/auth/types/impersonationTokens.ts","../src/auth/types/oauthTokens.ts","../src/auth/types/orgApiKeys.ts","../src/config/configPackageName.ts","../src/config/legacyConfig.ts","../src/config/loadConfig.ts","../src/env/assertSandboxTarget.ts","../src/env/loadEnv.ts","../src/env/resolveTarget.ts","../src/env/sandboxKeyName.ts","../src/generated/apiRoutes.ts","../src/generated/client.ts","../src/generated/emit.ts","../src/generated/emitRuntime.ts","../src/generated/features.ts","../src/generated/isLocalWebhookUrl.ts","../src/generated/labels.ts","../src/generated/licenses.ts","../src/generated/lintRules.ts","../src/generated/lintRuntime.ts","../src/generated/mappingAssignments.ts","../src/generated/plans.ts","../src/generated/referralPrograms.ts","../src/generated/rewards.ts","../src/generated/sandboxName.ts","../src/generated/settings.ts","../src/generated/skills.ts","../src/generated/variants.ts","../src/generated/webhooks.ts","../src/generated/wire.ts","../src/http/autumnFetch.ts","../src/project/chooseConfigDir.ts","../src/project/resolveProject.ts","../src/project/rootMarker.ts","../src/prompt/prompt.ts","../src/prompt/select.ts","../src/render/renderEnv.ts","../src/render/renderPreview.ts","../src/render/renderSandboxes.ts","../src/render/renderWebhooks.ts","../src/render/stripTerminalControls.ts","../src/repo/findRepoRoot.ts","../src/surgery/appendPropertyEdit.ts","../src/surgery/appendToArray.ts","../src/surgery/appendToBinding.ts","../src/surgery/appendToCollection.ts","../src/surgery/appendToFixtureArray.ts","../src/surgery/arrayBinding.ts","../src/surgery/deleteFixtureLiteral.ts","../src/surgery/deleteReference.ts","../src/surgery/ensureBuilderImport.ts","../src/surgery/findFixture.ts","../src/surgery/fixtureEdit.ts","../src/surgery/fixtureLocation.ts","../src/surgery/insertCollection.ts","../src/surgery/insertFirstProperty.ts","../src/surgery/patchFixturePaths.ts","../src/surgery/patchFixtureProperty.ts","../src/surgery/patchSingletonProperty.ts","../src/surgery/readFixtureValue.ts","../src/surgery/replaceFixture.ts","../src/surgery/setFixtureProperty.ts","../src/surgery/staticFixtureRule.ts","../test/apiCommand.test.ts","../test/authorizationUrl.test.ts","../test/autumnFetch.test.ts","../test/backfill.test.ts","../test/backfillInlineVariants.test.ts","../test/backfillSlug.test.ts","../test/backfillVariants.test.ts","../test/chooseConfigDir.test.ts","../test/cliTargetFlags.test.ts","../test/client.test.ts","../test/configPackageName.test.ts","../test/emitFixture.test.ts","../test/env.test.ts","../test/envWriter.test.ts","../test/ignoreBundledSkills.test.ts","../test/init.test.ts","../test/keyless.test.ts","../test/legacyConfig.test.ts","../test/lintDocument.test.ts","../test/loadConfigNode.test.ts","../test/loadConfigV2.test.ts","../test/locateFixtureUnique.test.ts","../test/login.test.ts","../test/nodeNextTypes.test.ts","../test/patchFixturePaths.test.ts","../test/plans.test.ts","../test/previewIsEmpty.test.ts","../test/prompt.test.ts","../test/pull.test.ts","../test/pullByReference.test.ts","../test/pullFieldLevel.test.ts","../test/pullMappings.test.ts","../test/pullOmitDefaults.test.ts","../test/pullPlans.test.ts","../test/pullStatesSlugs.test.ts","../test/pullTwoCollections.test.ts","../test/readFixtureValue.test.ts","../test/renameHint.test.ts","../test/renderPreview.test.ts","../test/renderSandboxes.test.ts","../test/renderSettings.test.ts","../test/reset.test.ts","../test/resolveCollectionTarget.test.ts","../test/resolveProject.test.ts","../test/resolveTarget.test.ts","../test/sandboxActions.test.ts","../test/sandboxKeyName.test.ts","../test/sandboxUse.test.ts","../test/settingsActions.test.ts","../test/settingsWire.test.ts","../test/skills.test.ts","../test/watchLauncher.test.ts","../test/wireDocument.test.ts","../test/helpers/targetFor.ts","../test/surgery/appendToCollection.test.ts","../test/surgery/deleteFixtureLiteral.test.ts","../test/surgery/deleteReference.test.ts","../test/surgery/findFixture.test.ts","../test/surgery/fixtureLocation.test.ts","../test/surgery/insertCollection.test.ts","../test/surgery/insertFirstProperty.test.ts","../test/surgery/patchFixtureProperty.test.ts","../test/surgery/patchSingletonProperty.test.ts","../test/surgery/replaceFixture.test.ts","../test/surgery/staticFixtureRule.test.ts","../test/webhooks/webhooksEnv.test.ts","../test/webhooks/webhooksLint.test.ts","../test/webhooks/webhooksPull.test.ts","../test/webhooks/webhooksPush.test.ts"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "atmn",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.34",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "The CLI for Autumn — define your pricing in code, sync it to Autumn, and keep everything in version control.",
|
|
6
6
|
"bin": {
|
|
@@ -49,5 +49,5 @@
|
|
|
49
49
|
"open": "10.2.0",
|
|
50
50
|
"yaml": "2.9.0"
|
|
51
51
|
},
|
|
52
|
-
"gitHead": "
|
|
52
|
+
"gitHead": "c29d787ec5b5f0c7414a3dca13b36fdcb40b6579"
|
|
53
53
|
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { SYNCED_LISTS } from "../../../generated/emit";
|
|
2
|
+
import { emitFixture } from "../../../generated/emitRuntime";
|
|
3
|
+
import { appendToBinding } from "../../../surgery/appendToBinding";
|
|
4
|
+
import { appendToCollection } from "../../../surgery/appendToCollection";
|
|
5
|
+
import { ensureBuilderImport } from "../../../surgery/ensureBuilderImport";
|
|
6
|
+
import {
|
|
7
|
+
insertCollection,
|
|
8
|
+
rootSpreadNames,
|
|
9
|
+
} from "../../../surgery/insertCollection";
|
|
10
|
+
import { resolveCollectionTarget } from "../resolveCollectionTarget";
|
|
11
|
+
import type { PullFiles, RemoteWebhook } from "./types";
|
|
12
|
+
|
|
13
|
+
const SPEC = SYNCED_LISTS.webhooks;
|
|
14
|
+
const COLLECTION = "webhooks";
|
|
15
|
+
|
|
16
|
+
/** The fixture a remote webhook reads as from one env: its url under that env alone. */
|
|
17
|
+
const fixtureRowOf = ({
|
|
18
|
+
webhook,
|
|
19
|
+
envKey,
|
|
20
|
+
}: {
|
|
21
|
+
webhook: RemoteWebhook;
|
|
22
|
+
envKey: string;
|
|
23
|
+
}): Record<string, unknown> => ({
|
|
24
|
+
id: webhook.id,
|
|
25
|
+
url: { [envKey]: webhook.url },
|
|
26
|
+
events: webhook.events,
|
|
27
|
+
...(webhook.description ? { description: webhook.description } : {}),
|
|
28
|
+
...(webhook.disabled ? { disabled: true } : {}),
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
/** Rule 1: a remote webhook the config never names is appended for this env. */
|
|
32
|
+
export const appendWebhook = ({
|
|
33
|
+
pull,
|
|
34
|
+
webhook,
|
|
35
|
+
envKey,
|
|
36
|
+
}: {
|
|
37
|
+
pull: PullFiles;
|
|
38
|
+
webhook: RemoteWebhook;
|
|
39
|
+
envKey: string;
|
|
40
|
+
}): string | null => {
|
|
41
|
+
const { configPath, files } = pull;
|
|
42
|
+
const configSource = files.get(configPath) ?? "";
|
|
43
|
+
const withKey = insertCollection({
|
|
44
|
+
source: configSource,
|
|
45
|
+
collection: COLLECTION,
|
|
46
|
+
});
|
|
47
|
+
if (withKey === null)
|
|
48
|
+
return "append to `webhooks` by hand: no atmn({...}) call";
|
|
49
|
+
// A spread may already hold `webhooks`; a second key after it would override it.
|
|
50
|
+
const spreads = rootSpreadNames({ source: configSource });
|
|
51
|
+
if (withKey !== configSource && spreads.length > 0)
|
|
52
|
+
return `append to \`webhooks\` by hand: atmn() spreads \`${spreads.join("`, `")}\`, which may already hold it`;
|
|
53
|
+
files.set(configPath, withKey);
|
|
54
|
+
const target = resolveCollectionTarget({
|
|
55
|
+
configPath,
|
|
56
|
+
files,
|
|
57
|
+
collection: COLLECTION,
|
|
58
|
+
});
|
|
59
|
+
if (target === null)
|
|
60
|
+
return "append to `webhooks` by hand: it is not an array literal";
|
|
61
|
+
const text = (indent: string) =>
|
|
62
|
+
emitFixture({
|
|
63
|
+
spec: SPEC,
|
|
64
|
+
row: fixtureRowOf({ webhook, envKey }),
|
|
65
|
+
includeMappings: false,
|
|
66
|
+
indent,
|
|
67
|
+
});
|
|
68
|
+
const source = files.get(target.file) ?? "";
|
|
69
|
+
const updated =
|
|
70
|
+
target.kind === "inline"
|
|
71
|
+
? appendToCollection({ source, collection: COLLECTION, text })
|
|
72
|
+
: appendToBinding({ source, name: target.name, text });
|
|
73
|
+
if (updated === null)
|
|
74
|
+
return "append to `webhooks` by hand: it is not an array literal";
|
|
75
|
+
files.set(
|
|
76
|
+
target.file,
|
|
77
|
+
ensureBuilderImport({
|
|
78
|
+
source: updated,
|
|
79
|
+
builder: SPEC.builder,
|
|
80
|
+
collection: COLLECTION,
|
|
81
|
+
}),
|
|
82
|
+
);
|
|
83
|
+
return null;
|
|
84
|
+
};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { isDashboardWebhook } from "../../webhooks/isDashboardWebhook";
|
|
2
|
+
import { newWebhookId } from "../../webhooks/newWebhookId";
|
|
3
|
+
import { appendWebhook } from "./appendWebhook";
|
|
4
|
+
import { removeWebhookEnv } from "./removeWebhookEnv";
|
|
5
|
+
import type {
|
|
6
|
+
PullFiles,
|
|
7
|
+
RemoteWebhook,
|
|
8
|
+
StatedWebhook,
|
|
9
|
+
WebhookEditResult,
|
|
10
|
+
} from "./types";
|
|
11
|
+
import { updateWebhook } from "./updateWebhook";
|
|
12
|
+
|
|
13
|
+
const merge = (target: WebhookEditResult, source: WebhookEditResult): void => {
|
|
14
|
+
target.lines.push(...source.lines);
|
|
15
|
+
target.warnings.push(...source.warnings);
|
|
16
|
+
target.unlocated.push(...source.unlocated);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* One env's webhooks written back into the config. Only `url[envKey]` is
|
|
21
|
+
* touched on the url map; every other env's key, comment and ordering stays.
|
|
22
|
+
* A dashboard webhook is matched to the config by URL, never duplicated: the
|
|
23
|
+
* next push adopts it by that URL, keeping its signing secret.
|
|
24
|
+
*/
|
|
25
|
+
export const applyWebhooksPull = ({
|
|
26
|
+
pull,
|
|
27
|
+
remote,
|
|
28
|
+
stated,
|
|
29
|
+
envKey,
|
|
30
|
+
newId = newWebhookId,
|
|
31
|
+
}: {
|
|
32
|
+
pull: PullFiles;
|
|
33
|
+
remote: RemoteWebhook[];
|
|
34
|
+
/** The config's webhooks as evaluated; absent when it states none. */
|
|
35
|
+
stated: StatedWebhook[] | undefined;
|
|
36
|
+
envKey: string;
|
|
37
|
+
/** Mints the id a dashboard webhook is written under. */
|
|
38
|
+
newId?: () => string;
|
|
39
|
+
}): WebhookEditResult => {
|
|
40
|
+
const result: WebhookEditResult = { lines: [], warnings: [], unlocated: [] };
|
|
41
|
+
const statedById = new Map((stated ?? []).map((row) => [row.id, row]));
|
|
42
|
+
// An id the config states is the config's, whatever its shape.
|
|
43
|
+
const fromDashboard = (webhook: RemoteWebhook): boolean =>
|
|
44
|
+
!statedById.has(webhook.id) && isDashboardWebhook(webhook);
|
|
45
|
+
const present = new Set<string>();
|
|
46
|
+
|
|
47
|
+
for (const webhook of remote) {
|
|
48
|
+
if (fromDashboard(webhook)) {
|
|
49
|
+
const represented = (stated ?? []).find(
|
|
50
|
+
(row) => row.url?.[envKey] === webhook.url,
|
|
51
|
+
);
|
|
52
|
+
if (represented !== undefined) {
|
|
53
|
+
present.add(represented.id);
|
|
54
|
+
merge(
|
|
55
|
+
result,
|
|
56
|
+
updateWebhook({
|
|
57
|
+
pull,
|
|
58
|
+
webhook: { ...webhook, id: represented.id },
|
|
59
|
+
stated: represented,
|
|
60
|
+
envKey,
|
|
61
|
+
}),
|
|
62
|
+
);
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (webhook.events.length === 0) {
|
|
66
|
+
result.lines.push(
|
|
67
|
+
`· webhook ${webhook.id} receives every event; give it an event list in the dashboard, or add it to your config, to manage it here`,
|
|
68
|
+
);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
const id = newId();
|
|
72
|
+
const failure = appendWebhook({
|
|
73
|
+
pull,
|
|
74
|
+
webhook: { ...webhook, id },
|
|
75
|
+
envKey,
|
|
76
|
+
});
|
|
77
|
+
if (failure === null)
|
|
78
|
+
result.lines.push(
|
|
79
|
+
`+ webhook ${id} (made in the dashboard; push adopts it by URL)`,
|
|
80
|
+
);
|
|
81
|
+
else result.unlocated.push({ id, action: failure });
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
present.add(webhook.id);
|
|
85
|
+
const row = statedById.get(webhook.id);
|
|
86
|
+
if (row !== undefined) {
|
|
87
|
+
merge(result, updateWebhook({ pull, webhook, stated: row, envKey }));
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
const failure = appendWebhook({ pull, webhook, envKey });
|
|
91
|
+
if (failure === null) result.lines.push(`+ webhook ${webhook.id}`);
|
|
92
|
+
else result.unlocated.push({ id: webhook.id, action: failure });
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
for (const row of stated ?? []) {
|
|
96
|
+
if (present.has(row.id) || row.url?.[envKey] === undefined) continue;
|
|
97
|
+
merge(result, removeWebhookEnv({ pull, stated: row, envKey }));
|
|
98
|
+
}
|
|
99
|
+
return result;
|
|
100
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { SYNCED_LISTS } from "../../../generated/emit";
|
|
2
|
+
import { type LocatedFixture, locateFixture } from "../locateFixture";
|
|
3
|
+
import type { PullFiles } from "./types";
|
|
4
|
+
|
|
5
|
+
const SPEC = SYNCED_LISTS.webhooks;
|
|
6
|
+
|
|
7
|
+
/** A `webhook({...})` call with this id, even when some values are code. */
|
|
8
|
+
export const locateWebhook = ({
|
|
9
|
+
pull,
|
|
10
|
+
id,
|
|
11
|
+
}: {
|
|
12
|
+
pull: PullFiles;
|
|
13
|
+
id: string;
|
|
14
|
+
}): LocatedFixture | null =>
|
|
15
|
+
locateFixture({
|
|
16
|
+
configPath: pull.configPath,
|
|
17
|
+
files: pull.files,
|
|
18
|
+
builder: SPEC.builder,
|
|
19
|
+
idField: SPEC.idField,
|
|
20
|
+
id,
|
|
21
|
+
allowDynamic: true,
|
|
22
|
+
});
|