@intercom/cli 0.13.0 → 0.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/dist/index.js +58 -6
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
View it from the CLI with `intercom changelog`.
|
|
9
9
|
|
|
10
|
+
## [0.14.1] - 2026-10-27
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- `intercom auth signup` no longer reads its CSRF token from the old signup page, which is moving to the new signup site. It now gets the token from the signup state endpoint, so signup keeps working after the old page redirects.
|
|
15
|
+
|
|
16
|
+
## [0.14.0] - 2026-09-02
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- `intercom fin workflows upload --verify` compares the workflow the server saved against the file just uploaded and exits non-zero listing any field that did not survive the round-trip, matching `fin procedures upload --verify`.
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- `--verify` combined with `--dry-run` on a `fin procedures upload` no longer fails: dry-run sends no request, so there is nothing saved to compare against and the verification step is skipped.
|
|
25
|
+
|
|
10
26
|
## [0.13.0] - 2026-09-01
|
|
11
27
|
|
|
12
28
|
### Changed
|
package/dist/index.js
CHANGED
|
@@ -933,6 +933,19 @@ async function fetchCsrfToken(url, timeoutMs = API_TIMEOUT_MS, init) {
|
|
|
933
933
|
if (!match) throw new Error("Could not find CSRF token");
|
|
934
934
|
return { token: match[1], cookies: extractCookies(response) };
|
|
935
935
|
}
|
|
936
|
+
async function fetchSignupCsrfToken(baseUrl, timeoutMs) {
|
|
937
|
+
const url = `${baseUrl}/ember/signups/state`;
|
|
938
|
+
const response = await fetchWithTimeout(
|
|
939
|
+
url,
|
|
940
|
+
{ headers: { Accept: "application/json" } },
|
|
941
|
+
{ timeoutMs }
|
|
942
|
+
);
|
|
943
|
+
if (!response.ok)
|
|
944
|
+
throw new AuthError(`Failed to fetch ${url}: ${response.status}`);
|
|
945
|
+
const data = await response.json();
|
|
946
|
+
if (!data.csrf_token) throw new AuthError("Could not find CSRF token");
|
|
947
|
+
return { token: data.csrf_token, cookies: extractCookies(response) };
|
|
948
|
+
}
|
|
936
949
|
async function signup(options) {
|
|
937
950
|
const {
|
|
938
951
|
baseUrl,
|
|
@@ -943,9 +956,8 @@ async function signup(options) {
|
|
|
943
956
|
plan = "advanced",
|
|
944
957
|
timeoutMs = API_TIMEOUT_MS
|
|
945
958
|
} = options;
|
|
946
|
-
const
|
|
947
|
-
|
|
948
|
-
csrfUrl,
|
|
959
|
+
const { token: csrfToken, cookies } = await fetchSignupCsrfToken(
|
|
960
|
+
baseUrl,
|
|
949
961
|
timeoutMs
|
|
950
962
|
);
|
|
951
963
|
const solutionId = PLAN_SOLUTION_IDS[plan] ?? PLAN_SOLUTION_IDS["advanced"];
|
|
@@ -3075,7 +3087,7 @@ back missing or changed is reported.`
|
|
|
3075
3087
|
}
|
|
3076
3088
|
const result = await client.postFormData("/fin-sdk/upload", formData);
|
|
3077
3089
|
render(result, opts, () => formatJson(result));
|
|
3078
|
-
if (opts.verify) {
|
|
3090
|
+
if (opts.verify && !isDryRun()) {
|
|
3079
3091
|
verifySaved(filePath, fileContent.toString("utf8"), result);
|
|
3080
3092
|
}
|
|
3081
3093
|
});
|
|
@@ -3570,17 +3582,23 @@ shows which version that is).`
|
|
|
3570
3582
|
console.log(text.replace(/\n+$/, ""));
|
|
3571
3583
|
}
|
|
3572
3584
|
});
|
|
3573
|
-
workflows.command("upload <file>").description('Upload a workflow YAML file (creates if id is "new", updates if numeric)').option("--json", "Output as JSON").option("--jq <expr>", "Filter JSON output with jq expression").option("--verbose", "Show HTTP request/response details").addHelpText(
|
|
3585
|
+
workflows.command("upload <file>").description('Upload a workflow YAML file (creates if id is "new", updates if numeric)').option("--verify", "Fail if the saved workflow differs from the file uploaded").option("--json", "Output as JSON").option("--jq <expr>", "Filter JSON output with jq expression").option("--verbose", "Show HTTP request/response details").addHelpText(
|
|
3574
3586
|
"after",
|
|
3575
3587
|
`
|
|
3576
3588
|
Examples:
|
|
3577
3589
|
$ intercom fin workflows upload ./welcome.yaml
|
|
3578
3590
|
$ intercom fin workflows get wf-42 > local.yaml; vim local.yaml; intercom fin workflows upload local.yaml
|
|
3579
3591
|
$ intercom fin workflows upload ./new.yaml --json | jq .visual_builder_url
|
|
3592
|
+
$ intercom fin workflows upload ./welcome.yaml --verify
|
|
3580
3593
|
|
|
3581
3594
|
The YAML file's id field determines whether this creates or updates:
|
|
3582
3595
|
id: "new" \u2192 creates a new workflow
|
|
3583
|
-
id: <int> \u2192 updates the existing workflow with that id
|
|
3596
|
+
id: <int> \u2192 updates the existing workflow with that id
|
|
3597
|
+
|
|
3598
|
+
--verify compares the workflow the server saved against the file just uploaded
|
|
3599
|
+
and exits non-zero listing any field that did not survive the round-trip. Fields
|
|
3600
|
+
the server adds (ids, defaults) are ignored; only content that was sent and came
|
|
3601
|
+
back missing or changed is reported.`
|
|
3584
3602
|
).action(async function(filePath) {
|
|
3585
3603
|
const opts = this.optsWithGlobals();
|
|
3586
3604
|
const client = await resolveClient(opts);
|
|
@@ -3600,6 +3618,9 @@ The YAML file's id field determines whether this creates or updates:
|
|
|
3600
3618
|
"Visual Builder URL": result.visual_builder_url != null ? String(result.visual_builder_url) : void 0
|
|
3601
3619
|
})
|
|
3602
3620
|
);
|
|
3621
|
+
if (opts.verify && !isDryRun()) {
|
|
3622
|
+
verifySaved2(filePath, fileContent, result);
|
|
3623
|
+
}
|
|
3603
3624
|
});
|
|
3604
3625
|
workflows.command("enable <id>").description("Set a workflow's state to live").option("--json", "Output as JSON").option("--jq <expr>", "Filter JSON output with jq expression").option("--verbose", "Show HTTP request/response details").addHelpText(
|
|
3605
3626
|
"after",
|
|
@@ -3715,6 +3736,37 @@ async function getVersionYaml2(client, id, versionId) {
|
|
|
3715
3736
|
}
|
|
3716
3737
|
return typeof content === "string" ? content : stringifyYaml3(content);
|
|
3717
3738
|
}
|
|
3739
|
+
function withoutExpectedChanges(sent) {
|
|
3740
|
+
if (sent == null || typeof sent !== "object" || Array.isArray(sent)) {
|
|
3741
|
+
return sent;
|
|
3742
|
+
}
|
|
3743
|
+
const rest = { ...sent };
|
|
3744
|
+
delete rest.type;
|
|
3745
|
+
delete rest.version;
|
|
3746
|
+
if (String(rest.id ?? "").toLowerCase() === "new") {
|
|
3747
|
+
delete rest.id;
|
|
3748
|
+
}
|
|
3749
|
+
return rest;
|
|
3750
|
+
}
|
|
3751
|
+
function verifySaved2(filePath, sentYaml, result) {
|
|
3752
|
+
if (typeof result.new_file_content !== "string") {
|
|
3753
|
+
throw new CLIError("Cannot verify: the server did not return the saved workflow");
|
|
3754
|
+
}
|
|
3755
|
+
const drift = findDrift(
|
|
3756
|
+
withoutExpectedChanges(parseYaml3(sentYaml)),
|
|
3757
|
+
parseYaml3(result.new_file_content)
|
|
3758
|
+
);
|
|
3759
|
+
if (drift.length === 0) {
|
|
3760
|
+
console.error(`Verified: the saved workflow matches ${filePath}`);
|
|
3761
|
+
return;
|
|
3762
|
+
}
|
|
3763
|
+
for (const path of drift) {
|
|
3764
|
+
console.error(` ${path}`);
|
|
3765
|
+
}
|
|
3766
|
+
throw new CLIError(
|
|
3767
|
+
`${drift.length} field(s) did not survive the upload (listed above). Compare with \`intercom fin workflows get ${result.id ?? "<id>"}\`.`
|
|
3768
|
+
);
|
|
3769
|
+
}
|
|
3718
3770
|
|
|
3719
3771
|
// src/commands/fin/simulations.ts
|
|
3720
3772
|
import { readFile as readFile5 } from "fs/promises";
|