atmn 2.0.41 → 2.0.43

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 (40) hide show
  1. package/dist/bin.js +405 -392
  2. package/dist/index.js +20 -21
  3. package/dist/tsconfig.tsbuildinfo +1 -1
  4. package/package.json +2 -2
  5. package/src/actions/pull/webhooks/appendWebhook.ts +6 -4
  6. package/src/actions/pull/webhooks/applyWebhooksPull.ts +28 -105
  7. package/src/actions/pull/webhooks/deleteWebhook.ts +59 -0
  8. package/src/actions/pull/webhooks/locateWebhook.ts +9 -1
  9. package/src/actions/pull/webhooks/readWebhookEnvs.ts +7 -12
  10. package/src/actions/pull/webhooks/types.ts +3 -2
  11. package/src/actions/pull/webhooks/updateWebhook.ts +37 -42
  12. package/src/actions/pull/webhooks/webhookEnvSkipWarning.ts +29 -0
  13. package/src/actions/pull/webhooks/webhookPullEnvs.ts +5 -5
  14. package/src/actions/pull.ts +1 -1
  15. package/src/actions/push.ts +30 -12
  16. package/src/actions/webhooks/applyWebhooks.ts +41 -10
  17. package/src/actions/webhooks/previewWebhookEnvs.ts +213 -0
  18. package/src/actions/webhooks/resolveWebhooksForEnv.ts +5 -16
  19. package/src/actions/webhooks/types/webhookEnv.ts +1 -3
  20. package/src/actions/webhooks/webhookEnvFailures.ts +27 -0
  21. package/src/actions/webhooks/webhookSecretName.ts +10 -9
  22. package/src/actions/webhooks/writeWebhookSecrets.ts +5 -2
  23. package/src/auth/runOAuthFlow.ts +1 -1
  24. package/src/cli.ts +23 -25
  25. package/src/generated/apiRoutes.ts +43 -12
  26. package/src/generated/client.ts +10 -10
  27. package/src/generated/emit.ts +4 -4
  28. package/src/generated/emitRuntime.ts +3 -3
  29. package/src/generated/lintRules.ts +16 -20
  30. package/src/generated/lintRuntime.ts +10 -0
  31. package/src/generated/skills.ts +10 -10
  32. package/src/generated/webhooks.ts +7 -9
  33. package/src/generated/wire.ts +0 -1
  34. package/src/render/renderPreview.ts +25 -9
  35. package/src/render/renderWebhooks.ts +9 -3
  36. package/src/actions/pull/webhooks/removeWebhookEnv.ts +0 -141
  37. package/src/actions/webhooks/isDashboardWebhook.ts +0 -9
  38. package/src/actions/webhooks/newWebhookId.ts +0 -4
  39. package/src/actions/webhooks/previewWebhooks.ts +0 -40
  40. package/src/actions/webhooks/resolveWebhookEnv.ts +0 -34
@@ -1,141 +0,0 @@
1
- import { SYNCED_LISTS } from "../../../generated/emit";
2
- import { deleteFixtureLiteral } from "../../../surgery/deleteFixtureLiteral";
3
- import { deleteReference } from "../../../surgery/deleteReference";
4
- import { fixtureObjectOf } from "../../../surgery/findFixture";
5
- import { patchFixturePaths } from "../../../surgery/patchFixturePaths";
6
- import {
7
- fixtureKeyOf,
8
- readFixtureValue,
9
- } from "../../../surgery/readFixtureValue";
10
- import { resolveCollectionTarget } from "../resolveCollectionTarget";
11
- import { locateWebhook } from "./locateWebhook";
12
- import type { PullFiles, StatedWebhook, WebhookEditResult } from "./types";
13
- import { nonLiteralUrlWarning } from "./updateWebhook";
14
-
15
- const SPEC = SYNCED_LISTS.webhooks;
16
-
17
- /** Read from source, not the evaluated config: a key whose code evaluates to
18
- * undefined is still a key the user wrote. */
19
- const urlMapIsEmpty = ({
20
- pull,
21
- id,
22
- }: {
23
- pull: PullFiles;
24
- id: string;
25
- }): boolean => {
26
- const located = locateWebhook({ pull, id });
27
- const object = located === null ? null : fixtureObjectOf(located.node);
28
- const member = object
29
- ?.namedChildren()
30
- .find(
31
- (child) =>
32
- child.kind() === "pair" &&
33
- child.field("key") !== null &&
34
- fixtureKeyOf({ node: child.field("key") as never }) === "url",
35
- );
36
- const value = member?.field("value");
37
- if (value === null || value === undefined) return false;
38
- const read = readFixtureValue({ node: value });
39
- return (
40
- typeof read === "object" && read !== null && Object.keys(read).length === 0
41
- );
42
- };
43
-
44
- /** The whole `webhook({...})`, and any export reference left pointing at it. */
45
- const deleteWebhook = ({
46
- pull,
47
- id,
48
- }: {
49
- pull: PullFiles;
50
- id: string;
51
- }): boolean => {
52
- const located = locateWebhook({ pull, id });
53
- if (located === null) return false;
54
- const removed = deleteFixtureLiteral({
55
- source: located.source,
56
- builder: SPEC.builder,
57
- idField: SPEC.idField,
58
- id,
59
- });
60
- if (removed === null) return false;
61
- pull.files.set(located.file, removed.source);
62
- if (removed.exportedName !== undefined) {
63
- const referenceFiles = new Set([pull.configPath]);
64
- const target = resolveCollectionTarget({
65
- configPath: pull.configPath,
66
- files: pull.files,
67
- collection: "webhooks",
68
- });
69
- if (target !== null) referenceFiles.add(target.file);
70
- for (const file of referenceFiles)
71
- pull.files.set(
72
- file,
73
- deleteReference({
74
- source: pull.files.get(file) ?? "",
75
- name: removed.exportedName,
76
- }),
77
- );
78
- }
79
- return true;
80
- };
81
-
82
- /**
83
- * Rule 4: the server has no such webhook in this env, so the env's key goes;
84
- * a map left empty registers the webhook nowhere, so the webhook goes too.
85
- */
86
- export const removeWebhookEnv = ({
87
- pull,
88
- stated,
89
- envKey,
90
- }: {
91
- pull: PullFiles;
92
- stated: StatedWebhook;
93
- envKey: string;
94
- }): WebhookEditResult => {
95
- const result: WebhookEditResult = { lines: [], warnings: [], unlocated: [] };
96
- const located = locateWebhook({ pull, id: stated.id });
97
- const patched =
98
- located === null
99
- ? null
100
- : patchFixturePaths({
101
- source: located.source,
102
- builder: SPEC.builder,
103
- idField: SPEC.idField,
104
- id: stated.id,
105
- assignments: [{ path: ["url", envKey], text: null }],
106
- });
107
- if (located === null || patched === null) {
108
- result.unlocated.push({
109
- id: stated.id,
110
- action: `remove url.${envKey} by hand`,
111
- });
112
- return result;
113
- }
114
- if (patched.skipped.length > 0) {
115
- result.warnings.push(
116
- nonLiteralUrlWarning({
117
- id: stated.id,
118
- envKey,
119
- server: undefined,
120
- config: stated.url?.[envKey],
121
- }),
122
- );
123
- return result;
124
- }
125
- if (patched.source === located.source) return result;
126
- pull.files.set(located.file, patched.source);
127
- if (urlMapIsEmpty({ pull, id: stated.id })) {
128
- if (deleteWebhook({ pull, id: stated.id })) {
129
- result.lines.push(`- webhook ${stated.id}`);
130
- return result;
131
- }
132
- // Only a literal can be deleted; saying so beats leaving `url: {}` behind.
133
- result.unlocated.push({
134
- id: stated.id,
135
- action: "delete the webhook by hand: its url map is now empty",
136
- });
137
- return result;
138
- }
139
- result.lines.push(`- webhook ${stated.id} url.${envKey}`);
140
- return result;
141
- };
@@ -1,9 +0,0 @@
1
- /** Svix's own endpoint id: `ep_` and a 27-character KSUID. */
2
- const SVIX_ENDPOINT_ID = /^ep_[0-9A-Za-z]{27}$/;
3
-
4
- /**
5
- * A webhook made in the dashboard has no id of ours, so the API lists it under
6
- * Svix's endpoint id. A config never manages one.
7
- */
8
- export const isDashboardWebhook = ({ id }: { id: string }): boolean =>
9
- SVIX_ENDPOINT_ID.test(id);
@@ -1,4 +0,0 @@
1
- import { generateKsuid } from "@autumn/ksuid";
2
-
3
- /** The shape the server's `generateId("wh")` mints: `wh_` and a KSUID. */
4
- export const newWebhookId = (): string => generateKsuid({ prefix: "wh_" });
@@ -1,40 +0,0 @@
1
- import type { AutumnClient, SyncWebhooksParams } from "../../generated/client";
2
- import type { WebhooksPreview } from "../../render/renderWebhooks";
3
- import { resolveWebhooksForEnv } from "./resolveWebhooksForEnv";
4
- import type { WebhookEnv } from "./types/webhookEnv";
5
-
6
- export type WebhooksLane = {
7
- preview: WebhooksPreview;
8
- /** Exactly what the preview was asked about, so the sync applies the same set. */
9
- body: SyncWebhooksParams;
10
- env: WebhookEnv;
11
- };
12
-
13
- /** Absent when the config states no `webhooks`: an omitted list manages nothing. */
14
- export const previewWebhooks = async ({
15
- client,
16
- rows,
17
- webhookEnv,
18
- }: {
19
- client: AutumnClient;
20
- rows: Record<string, unknown>[] | undefined;
21
- webhookEnv: (() => Promise<WebhookEnv>) | undefined;
22
- }): Promise<WebhooksLane | undefined> => {
23
- if (rows === undefined) return undefined;
24
- if (webhookEnv === undefined)
25
- throw new Error("webhooks need the target environment to pick each url.");
26
- const env = await webhookEnv();
27
- const webhooks = resolveWebhooksForEnv({
28
- rows,
29
- envKey: env.key,
30
- });
31
- const body = { webhooks };
32
- const { changes, errors } = await client.previewSyncWebhooks(body);
33
- // Refused items (several dashboard webhooks on one URL, say) fail the lane
34
- // here, beside every other lane's errors, rather than at apply.
35
- if (errors.length > 0)
36
- throw new Error(
37
- errors.map(({ id, message }) => `${id}: ${message}`).join("\n"),
38
- );
39
- return { preview: { changes }, body, env };
40
- };
@@ -1,34 +0,0 @@
1
- import type { Target } from "../../env/resolveTarget";
2
- import { sandboxSlug } from "../../generated/sandboxName";
3
- import type { FetchOrgInfo, OrgInfo } from "../env/types/orgInfo";
4
- import type { WebhookEnv } from "./types/webhookEnv";
5
-
6
- /** `/organization/me`, asked at most once per command. */
7
- const memoized = (fetchOrgInfo: FetchOrgInfo): FetchOrgInfo => {
8
- let pending: Promise<OrgInfo> | undefined;
9
- return () => {
10
- pending ??= fetchOrgInfo();
11
- return pending;
12
- };
13
- };
14
-
15
- /**
16
- * `-p` is `live` and the default sandbox is `sandbox`, with no lookup. A named
17
- * sandbox is keyed by its slug, which only its name gives: one lookup.
18
- */
19
- export const resolveWebhookEnv = async ({
20
- target,
21
- prod,
22
- fetchOrgInfo,
23
- }: {
24
- target: Target;
25
- prod: boolean;
26
- fetchOrgInfo: FetchOrgInfo;
27
- }): Promise<WebhookEnv> => {
28
- const orgInfo = memoized(fetchOrgInfo);
29
- const orgId = async () => (await orgInfo()).id;
30
- if (prod) return { key: "live", live: true, orgId };
31
- if (target.sandboxId === undefined)
32
- return { key: "sandbox", live: false, orgId };
33
- return { key: sandboxSlug((await orgInfo()).name), live: false, orgId };
34
- };