@keystrokehq/cli 0.0.38 → 0.0.40
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 +6 -2
- package/dist/{accept.handler-CykuBpt6.mjs → accept.handler-Ca7uzwxi.mjs} +3 -3
- package/dist/{admin-gRjPC3eD.mjs → admin-dG6GUb3q.mjs} +11 -11
- package/dist/{agents-BpyuvM9p.mjs → agents-sPFPgn4f.mjs} +8 -8
- package/dist/{api-sWkB_Wta.mjs → api-b0DzMwXP.mjs} +1 -1
- package/dist/{api-keys-BSKhdD_x.mjs → api-keys-4tXQbpkQ.mjs} +6 -6
- package/dist/{auth-DCgToFf5.mjs → auth-CWW1yAyX.mjs} +6 -6
- package/dist/{auth.handler-QRQAEUJC.mjs → auth.handler-BdIVmlEw.mjs} +4 -4
- package/dist/{authored-workflow-ref-BRCQgyWl.mjs → authored-workflow-ref-DpaMDcsV.mjs} +6 -6
- package/dist/{build-agents-CUzBnlAG-3ePFZiJ6.mjs → build-agents-CUzBnlAG-BlVdU8WI.mjs} +5 -5
- package/dist/{build-metadata-BB_L45ZS-DRQsV6JK.mjs → build-metadata-BB_L45ZS-DF9jjlo7.mjs} +6 -6
- package/dist/{build-progress-D_SQqdHA.mjs → build-progress-ClHW7cxW.mjs} +1 -1
- package/dist/{build-tasks-5eOvI19S-tbN6CRx9.mjs → build-tasks-5eOvI19S-DOJYTRNL.mjs} +3 -3
- package/dist/{build-workflows-C-gQM3l5-_zcBHE3M.mjs → build-workflows-C-gQM3l5-B1By02sw.mjs} +8 -8
- package/dist/{build.handler-DGQn_clk.mjs → build.handler-oSb0aOLO.mjs} +6 -6
- package/dist/{clear-cache.handler-gJpwslkK.mjs → clear-cache.handler-nH67vXdu.mjs} +1 -1
- package/dist/{clear.handler-CuXYvUj2.mjs → clear.handler-b7T3XjAx.mjs} +2 -2
- package/dist/{commander-B_8QwPpe.mjs → commander-DIOuj6NJ.mjs} +2 -2
- package/dist/{connect-DV9lhP6C.mjs → connect-Cg4oFCFZ.mjs} +3 -3
- package/dist/{connect.handler-D6JzuFuT.mjs → connect.handler-BsMTctjd.mjs} +241 -187
- package/dist/{context-Brc9VGV9.mjs → context-DaBLwEWi.mjs} +4 -4
- package/dist/{create.handler-D_tmjANR.mjs → create.handler-CAj7e5w2.mjs} +2 -2
- package/dist/{credential-env-map-5a41jLwM.mjs → credential-env-map-rXDibCDT.mjs} +1 -1
- package/dist/{credential-schema-mismatch-CStYUB2h.mjs → credential-schema-mismatch-BvcO7KgE.mjs} +1 -1
- package/dist/{credentials-DtwLbee6.mjs → credentials-Bud9r1JE.mjs} +1 -1
- package/dist/{credentials-UDrvrKj-.mjs → credentials-CZ7HaiPb.mjs} +11 -11
- package/dist/{current.handler-Cy91EeLU.mjs → current.handler-BJvDHSmV.mjs} +3 -3
- package/dist/{delete.handler-rUDDUrDQ.mjs → delete.handler-DivhWFrZ.mjs} +1 -1
- package/dist/{deploy-DgWPlEKO.mjs → deploy-9ySqfoem.mjs} +2 -2
- package/dist/{deploy-BiKBH25R.mjs → deploy-NSrCthrD.mjs} +1 -1
- package/dist/{deploy-progress-BDOCSm_U.mjs → deploy-progress-DccPUWfp.mjs} +1 -1
- package/dist/{deploy.handler-BDCHCk_A.mjs → deploy.handler-DltgOetG.mjs} +15 -15
- package/dist/{detect-env-access-CwkOYeYM-r4aynBU0.mjs → detect-env-access-CwkOYeYM-CetSMqeq.mjs} +1 -1
- package/dist/{diff.handler-CGERP-Qn.mjs → diff.handler-OIzXMsHB.mjs} +4 -4
- package/dist/{dist-BmbFJq8U.mjs → dist-BpLSQDJX.mjs} +12 -12
- package/dist/{env.handler--8FRrSlJ.mjs → env.handler-DdIhJ4mO.mjs} +9 -9
- package/dist/{error-boundary-D2DiCLAp.mjs → error-boundary-IUSz7k4x.mjs} +2 -2
- package/dist/{file-metadata-DQVDjr7M.mjs → file-metadata-bzAf3GqL.mjs} +1 -1
- package/dist/{iam-command-utils-D01Gw8-M.mjs → iam-command-utils-CPkuyDrD.mjs} +1 -1
- package/dist/{import-module-y0glInUe-EuAWaw9g.mjs → import-module-y0glInUe-CVKziY2H.mjs} +6 -6
- package/dist/{init-Mpe_8lA_.mjs → init-BuVaQkZl.mjs} +2 -2
- package/dist/{init.handler-BjLAIAmm.mjs → init.handler-CX3OQdjn.mjs} +3 -3
- package/dist/{inspect.handler-CXCi7fhH.mjs → inspect.handler-CgJkF6RH.mjs} +5 -5
- package/dist/{integration-catalog-mZs6EAlN.mjs → integration-catalog-DEHwWAO6.mjs} +2 -2
- package/dist/{integrations-D_IH5Ud1.mjs → integrations-DdKOCj3U.mjs} +8 -95
- package/dist/{invites-CWWz4wmY.mjs → invites-DWE6Zmj1.mjs} +5 -5
- package/dist/{invites.list.handler-CQLWSoWo.mjs → invites.list.handler-DO7Wq2u0.mjs} +4 -4
- package/dist/{invites.resend.handler-CeIGE_qM.mjs → invites.resend.handler-BcW922nx.mjs} +4 -4
- package/dist/{invites.revoke.handler-9K6jkym_.mjs → invites.revoke.handler-BdMoZOqx.mjs} +4 -4
- package/dist/keystroke.mjs +38 -42
- package/dist/{list-enrichment-dqbkXJzy.mjs → list-enrichment-mOKJXdJW.mjs} +1 -1
- package/dist/{list.handler-DUTNS8du.mjs → list.handler-6h-dCWy7.mjs} +3 -3
- package/dist/{list.handler-CDWPmiMy.mjs → list.handler-BWEBemPq.mjs} +3 -3
- package/dist/{list.handler-Cuw1fWO_.mjs → list.handler-C1Okanaq.mjs} +3 -3
- package/dist/{list.handler-D-rSyrX0.mjs → list.handler-CD6T_BXB.mjs} +3 -3
- package/dist/{list.handler-BvuxTFLe.mjs → list.handler-CGD1JBJW.mjs} +6 -6
- package/dist/{list.handler-Co32_F3n.mjs → list.handler-CXsHFhRg.mjs} +6 -6
- package/dist/{list.handler-Dz-Yeijp.mjs → list.handler-DYIKuoAv.mjs} +2 -2
- package/dist/{list.handler-DMvq96UA.mjs → list.handler-Dny_G7yA.mjs} +2 -2
- package/dist/{list2.handler-BpqKZTZk.mjs → list2.handler-v14fD-Wx.mjs} +3 -3
- package/dist/{listen-CeNwufij.mjs → listen-DWLGKM9p.mjs} +3 -3
- package/dist/{listen.handler-CfRoaOwu.mjs → listen.handler-BHY0khAc.mjs} +3 -3
- package/dist/{logs-B7k2_W1R.mjs → logs-CAgOxZQ1.mjs} +3 -3
- package/dist/{logs.handler-CSqOzxCU.mjs → logs.handler-BcGJIjn1.mjs} +5 -5
- package/dist/{members.add.handler-CBjoA6vG.mjs → members.add.handler-3y_jsYI5.mjs} +4 -4
- package/dist/{members.invite.handler-D8KcKJ9Y.mjs → members.invite.handler-CLbxTp-x.mjs} +4 -4
- package/dist/{members.list.handler-CB_qSJK0.mjs → members.list.handler--r0ibk1q.mjs} +4 -4
- package/dist/{members.remove.handler-DNhO81mo.mjs → members.remove.handler-DFfOjRmq.mjs} +4 -4
- package/dist/{members.update.handler-Bjdk_uz4.mjs → members.update.handler-pY5ZKxyE.mjs} +4 -4
- package/dist/{normalize-path-CojS-CgQ-aOM0agxS.mjs → normalize-path-CojS-CgQ-lQUBXXzi.mjs} +1 -1
- package/dist/official-providers-DF1Wt_-m.mjs +92 -0
- package/dist/{operations-HHwoArwE.mjs → operations-mpOhoA0C.mjs} +5 -5
- package/dist/{org-context-CNh2p2DP.mjs → org-context-BAbQ9nhH.mjs} +2 -2
- package/dist/{org-output-BcI17Uan.mjs → org-output-Chcob8vH.mjs} +2 -2
- package/dist/{org-f-qo68Em.mjs → org-xlZOYXfd.mjs} +17 -17
- package/dist/{orgs.create.handler-DOE9ZIed.mjs → orgs.create.handler-C_zVtI05.mjs} +3 -3
- package/dist/{orgs.get.handler-sWErVI7r.mjs → orgs.get.handler-CCr0tawz.mjs} +3 -3
- package/dist/{orgs.list.handler-Cp-mXsA0.mjs → orgs.list.handler-C6H6LEdf.mjs} +3 -3
- package/dist/{paused.handler-DWdoKYY8.mjs → paused.handler-BVrzjvyP.mjs} +4 -4
- package/dist/{projects-CCC36zbJ.mjs → projects-CpLiEcTK.mjs} +4 -4
- package/dist/{projects-ZNcKwds2.mjs → projects-DOYjjoZ-.mjs} +2 -2
- package/dist/{register.handler-Dxae5iq8.mjs → register.handler-CSpRM1p1.mjs} +41 -28
- package/dist/{requirements.handler-Bg3mRnER.mjs → requirements.handler-CA4zeT3J.mjs} +6 -6
- package/dist/{resolve-cli-credentials-GVOOedoQ.mjs → resolve-cli-credentials-BecTgRE7.mjs} +1 -1
- package/dist/{resolve-project-CoCN9xfi.mjs → resolve-project-Cto7y-K3.mjs} +2 -2
- package/dist/{run-polling-htHWhG0T.mjs → run-polling-DVis_pob.mjs} +3 -3
- package/dist/{run.handler-C-CM-xZG.mjs → run.handler-Dyo7_OIO.mjs} +7 -7
- package/dist/{runs-BRJPNq4B.mjs → runs-DFWRUETL.mjs} +3 -3
- package/dist/{search-CQMgdp51.mjs → search-ByKPk0l-.mjs} +15 -6
- package/dist/search.handler-CE2432ah.mjs +112 -0
- package/dist/{show.handler-DUDxnNiZ.mjs → show.handler-BD5i6EV5.mjs} +4 -4
- package/dist/{show.handler-D3nDc1MJ.mjs → show.handler-BupYRNqw.mjs} +3 -3
- package/dist/{show.handler-CdZF0aao.mjs → show.handler-C_d60AOd.mjs} +2 -2
- package/dist/{skills-sync.handler-_LVhIMRH.mjs → skills-sync.handler-CbQQaKv7.mjs} +1 -1
- package/dist/{skills.command-DSHGwXPX.mjs → skills.command-D-OoLKTF.mjs} +4 -4
- package/dist/{source-analysis-BBg2E_6G-wPP9mjQx.mjs → source-analysis-BBg2E_6G-CS88X3nS.mjs} +3 -3
- package/dist/{src-DI-ybNjR.mjs → src-DOCKWJRW.mjs} +59 -13
- package/dist/{status.handler-1hEzX5oB.mjs → status.handler-7411LjJt.mjs} +1 -1
- package/dist/{switch.handler-D135WwfB.mjs → switch.handler-CfCy8yzX.mjs} +3 -3
- package/dist/{sync-CFScllh3.mjs → sync-Dp57sXlR.mjs} +2 -2
- package/dist/{sync.handler-x8v53-TT.mjs → sync.handler-B6p_PFqf.mjs} +7 -7
- package/dist/{task-DTvLzUkA.mjs → task-DzwZiru5.mjs} +1 -1
- package/dist/{task-target-build-CtvRyVjH.mjs → task-target-build-bIN-ngtL.mjs} +5 -5
- package/dist/{task-target-deploy-m9LfE488.mjs → task-target-deploy-DhlZNykk.mjs} +1 -1
- package/dist/{task-target-deploy-dQYnMO8n-d2vdeqXH.mjs → task-target-deploy-dQYnMO8n-Cx_r9Kzk.mjs} +1 -1
- package/dist/task-target-deploy-runner.mjs +8 -8
- package/dist/{test-Dx4RXoLZ.mjs → test-BHj1LMHN.mjs} +3 -3
- package/dist/{test.handler-Mz_XOnJl.mjs → test.handler-BmrgrK08.mjs} +1 -1
- package/dist/{test.handler-BmvL5vF8.mjs → test.handler-mo5agj6w.mjs} +11 -11
- package/dist/{tool.handler-DsbpocYI.mjs → tool.handler-wH-lWk7T.mjs} +8 -8
- package/dist/{trigger-artifacts-BcRScRSp-BRpU-He5.mjs → trigger-artifacts-BcRScRSp-CbuG4AfM.mjs} +4 -4
- package/dist/{trigger-manifest-BVqjDhxU.mjs → trigger-manifest-EaOKzq4D.mjs} +2 -2
- package/dist/{upgrade-C9G6HksL.mjs → upgrade-BXgpsNcQ.mjs} +2 -2
- package/dist/{upload.handler-DscKDQ63.mjs → upload.handler-Y-yOXVYC.mjs} +9 -9
- package/dist/{users.get.handler-CaUv_maM.mjs → users.get.handler-BGOCxdkB.mjs} +3 -3
- package/dist/{users.list.handler-DzsOvAtd.mjs → users.list.handler-CeCdVYny.mjs} +3 -3
- package/dist/{users.set-role.handler-koRzA0V9.mjs → users.set-role.handler-ChUvfPm9.mjs} +3 -3
- package/dist/{utils-BaxDlCsW.mjs → utils-DZkAd_Yh.mjs} +2 -2
- package/dist/{validate.handler-BkBsS8BL.mjs → validate.handler-Cf6Hv_La.mjs} +7 -7
- package/dist/{workflow-build-Db6at6IA.mjs → workflow-build-BdjQ_VZx.mjs} +21 -21
- package/dist/{workflow-build-manifest-CV6bBmDO.mjs → workflow-build-manifest-EnRP3HRK.mjs} +3 -3
- package/dist/{workflow-bundler-Bs3zQNQv-Dy7lXxy3.mjs → workflow-bundler-Bs3zQNQv-DeOFaxmV.mjs} +2 -2
- package/dist/{workflows-B8VG6nKg.mjs → workflows-CLWyveLm.mjs} +16 -16
- package/dist/{writer-BLg0RuZa-Y6ExdYH9.mjs → writer-BLg0RuZa-ynLkRVCU.mjs} +5 -5
- package/package.json +7 -7
- package/dist/search.handler-Dn5jjyF-.mjs +0 -79
- package/dist/{agent-bundle-package-DWV6B_5q-B-qzc3zC.mjs → agent-bundle-package-DWV6B_5q-DyuZcU-M.mjs} +0 -0
- package/dist/{agent-manifest-DfWD5tvv.mjs → agent-manifest-IKErxq4q.mjs} +0 -0
- package/dist/{browser-Dvv5OQrt.mjs → browser-CvuyMLhI.mjs} +0 -0
- package/dist/{clear.handler-DnjvgyMj.mjs → clear.handler-C52FDzQh.mjs} +0 -0
- package/dist/{common-AK0q0Oz0.mjs → common-BcLVOrEe.mjs} +0 -0
- package/dist/{concurrency-gXn9Rw8x-CnBnF2cg.mjs → concurrency-gXn9Rw8x-DL-HGvhT.mjs} +0 -0
- package/dist/{credential-requirements-B5Alhu1v-DanlSKnT.mjs → credential-requirements-B5Alhu1v-C26qMgU_.mjs} +0 -0
- package/dist/{declared-credential-requirements-B6h4WRv4.mjs → declared-credential-requirements-D6KT-r-e.mjs} +0 -0
- package/dist/{default-urls-BoSm4s9C.mjs → default-urls-jMHepw2q.mjs} +0 -0
- package/dist/{dist-B5jy238v.mjs → dist-rsDq3fTk.mjs} +0 -0
- package/dist/{layout-B95Tku8F.mjs → layout-CqQq4MmI.mjs} +0 -0
- package/dist/{logs.handler-BIqJ0FED.mjs → logs.handler-BvOCKckB.mjs} +0 -0
- package/dist/{metadata-layout-Bv-B0nHj-CO8mjjSl.mjs → metadata-layout-Bv-B0nHj-qhsuNON1.mjs} +0 -0
- package/dist/{output-BPydP5tG.mjs → output-C0pbsv39.mjs} +0 -0
- package/dist/{oxc-B3KI3rf_-B9omBIuN.mjs → oxc-B3KI3rf_-ghZc3xZ5.mjs} +0 -0
- package/dist/{project-config-DudGRFPO.mjs → project-config-VloWJirJ.mjs} +1 -1
- /package/dist/{read-credential-keys-77a91T8M-I07NYwfH.mjs → read-credential-keys-77a91T8M-C4dOpzvX.mjs} +0 -0
- /package/dist/{render-operation-iF7Wblv2.mjs → render-operation-BhivW7cA.mjs} +0 -0
- /package/dist/{rolldown-runtime-twds-ZHy-RuJszab7.mjs → rolldown-runtime-twds-ZHy-BvwnxyIt.mjs} +0 -0
- /package/dist/{run-polling-1c0ckC1A.mjs → run-polling-CJWe6cxy.mjs} +0 -0
- /package/dist/{schema-Lbp5lGJu.mjs → schema-GwRMmuKB.mjs} +0 -0
- /package/dist/{schema-DFJiNWyd.mjs → schema-QbiBSbhG.mjs} +0 -0
- /package/dist/{schema-display-sZ6ConJd.mjs → schema-display-DKreWhh1.mjs} +0 -0
- /package/dist/{schemas-ClAIoIrX.mjs → schemas-COSVuCFH.mjs} +0 -0
- /package/dist/{skills.handler-DqLXJepA.mjs → skills.handler-CvXcuOf5.mjs} +0 -0
- /package/dist/{source-analysis-z2RSZw6X.mjs → source-analysis-BYwAbHx2.mjs} +0 -0
- /package/dist/{spinner-progress-fLaD0sjH.mjs → spinner-progress-QqK2bvTQ.mjs} +0 -0
- /package/dist/{upgrade.handler-DsFeAFF4.mjs → upgrade.handler-COptE2fK.mjs} +0 -0
- /package/dist/{upload-CE4H5R1h.mjs → upload-XFKnNumW.mjs} +0 -0
|
@@ -1,45 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { P as throwReportedCliExit, S as toErrorMessage, h as AUTH_HINT, p as ui, x as isNetworkError } from "./keystroke.mjs";
|
|
4
|
-
import { t as assertWorkflowProjectRoot } from "./project-config-
|
|
5
|
-
import { i as writeJson } from "./output-
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return catalog.lookupByPublicId(integrationId)?.name ?? integrationId;
|
|
13
|
-
}
|
|
14
|
-
function formatConnectionLabel(connection) {
|
|
15
|
-
return connection.label ?? connection.id;
|
|
16
|
-
}
|
|
17
|
-
function formatConnectionFlags(connection) {
|
|
18
|
-
const flags = [connection.recommended === true ? "recommended" : null, connection.advanced === true ? "advanced" : null].filter((flag) => flag !== null);
|
|
19
|
-
return flags.length > 0 ? `, ${flags.join(", ")}` : "";
|
|
20
|
-
}
|
|
21
|
-
function availableOAuthConnectionHint(connections) {
|
|
22
|
-
const oauthConnections = connections?.filter((connection) => connection.kind === "oauth") ?? [];
|
|
23
|
-
if (oauthConnections.length === 0) return "Run `keystroke integrations list --kind oauth` to see integrations with OAuth connection paths.";
|
|
24
|
-
return `Available OAuth connection IDs: ${oauthConnections.map((connection) => `${connection.id}${connection.recommended ? " (recommended)" : ""}`).join(", ")}.`;
|
|
25
|
-
}
|
|
26
|
-
function selectOAuthConnection(params) {
|
|
27
|
-
const { catalogEntry, requestedCredentialConnectionId, ctx, integrationId } = params;
|
|
28
|
-
const connections = catalogEntry?.connections ?? [];
|
|
29
|
-
if (requestedCredentialConnectionId) {
|
|
30
|
-
const selected = connections.find((connection) => connection.id === requestedCredentialConnectionId);
|
|
31
|
-
if (!selected) exitWithError(ctx, `Credential connection "${requestedCredentialConnectionId}" is not defined for "${integrationId}".`, {
|
|
32
|
-
code: "UNKNOWN_CREDENTIAL_CONNECTION",
|
|
33
|
-
hint: availableOAuthConnectionHint(connections)
|
|
34
|
-
});
|
|
35
|
-
if (selected.kind !== "oauth") exitWithError(ctx, `Credential connection "${selected.id}" for "${integrationId}" is "${selected.kind}", not oauth.`, {
|
|
36
|
-
code: "UNSUPPORTED_CREDENTIAL_CONNECTION",
|
|
37
|
-
hint: availableOAuthConnectionHint(connections)
|
|
38
|
-
});
|
|
39
|
-
return selected;
|
|
40
|
-
}
|
|
41
|
-
return connections.find((connection) => connection.kind === "oauth" && connection.recommended === true) ?? connections.find((connection) => connection.kind === "oauth");
|
|
42
|
-
}
|
|
3
|
+
import { P as throwReportedCliExit, S as toErrorMessage, h as AUTH_HINT, p as ui, x as isNetworkError, y as getHttpStatus } from "./keystroke.mjs";
|
|
4
|
+
import { t as assertWorkflowProjectRoot } from "./project-config-VloWJirJ.mjs";
|
|
5
|
+
import { i as writeJson } from "./output-C0pbsv39.mjs";
|
|
6
|
+
import { i as requireClient } from "./context-DaBLwEWi.mjs";
|
|
7
|
+
import { n as resolveWorkflowsDir } from "./resolve-project-Cto7y-K3.mjs";
|
|
8
|
+
import { t as openBrowser } from "./browser-CvuyMLhI.mjs";
|
|
9
|
+
import { i as InitiateConnectionResponseSchema, n as ConnectionStatusResponseSchema, r as InitiateConnectionRequestSchema } from "./api-b0DzMwXP.mjs";
|
|
10
|
+
import { t as getIntegrationCatalog } from "./integration-catalog-DEHwWAO6.mjs";
|
|
11
|
+
//#region src/commands/connect/connect.errors.ts
|
|
43
12
|
/**
|
|
44
13
|
* Per-reason CLI hint table for `failed` status responses.
|
|
45
14
|
*
|
|
@@ -64,7 +33,7 @@ const FAILURE_REASON_HINTS = {
|
|
|
64
33
|
function formatFailureHint(reason, label) {
|
|
65
34
|
return FAILURE_REASON_HINTS[reason].replaceAll("{label}", label);
|
|
66
35
|
}
|
|
67
|
-
function
|
|
36
|
+
function exitWithConnectError(ctx, message, opts) {
|
|
68
37
|
if (ctx.jsonMode) {
|
|
69
38
|
process.stdout.write(`${JSON.stringify({
|
|
70
39
|
error: message,
|
|
@@ -77,88 +46,265 @@ function exitWithError(ctx, message, opts) {
|
|
|
77
46
|
if (opts?.hint) ui.hint(opts.hint);
|
|
78
47
|
throwReportedCliExit(message);
|
|
79
48
|
}
|
|
49
|
+
function exitOnConnectionInitiateError(ctx, error, params) {
|
|
50
|
+
if (error instanceof Error && error.name === "CliExitError") throw error;
|
|
51
|
+
const status = getHttpStatus(error);
|
|
52
|
+
if (status === 404) exitWithConnectError(ctx, `Integration "${params.integrationLabel}" is not supported for platform OAuth.`, {
|
|
53
|
+
code: "UNSUPPORTED_INTEGRATION",
|
|
54
|
+
hint: `Currently supported official OAuth integrations: ${params.catalog.oauthPublicIds.join(", ")}. Custom OAuth connect flows are not available yet.`
|
|
55
|
+
});
|
|
56
|
+
if (status === 503) exitWithConnectError(ctx, `Platform credentials not configured for "${params.integrationLabel}".`, {
|
|
57
|
+
code: "PLATFORM_NOT_CONFIGURED",
|
|
58
|
+
hint: `Ask a Keystroke developer to configure the ${params.integrationLabel} account OAuth client for this environment.`
|
|
59
|
+
});
|
|
60
|
+
if (status === 401) exitWithConnectError(ctx, "Not authenticated.", {
|
|
61
|
+
code: "AUTH_ERROR",
|
|
62
|
+
hint: AUTH_HINT
|
|
63
|
+
});
|
|
64
|
+
if (status === 403) exitWithConnectError(ctx, `You do not have permission to connect ${params.integrationLabel} in the current organization.`, {
|
|
65
|
+
code: "FORBIDDEN",
|
|
66
|
+
hint: "Verify your active organization and your permissions in that organization."
|
|
67
|
+
});
|
|
68
|
+
if (status !== null && status >= 500) exitWithConnectError(ctx, `The Keystroke server failed while starting the ${params.integrationLabel} connection.`, {
|
|
69
|
+
code: "SERVER_ERROR",
|
|
70
|
+
hint: `Server returned HTTP ${status}. Check the server logs and try again.`
|
|
71
|
+
});
|
|
72
|
+
if (status !== null) exitWithConnectError(ctx, `Failed to initiate the ${params.integrationLabel} connection.`, {
|
|
73
|
+
code: "INITIATE_FAILED",
|
|
74
|
+
hint: `Server returned HTTP ${status}.`
|
|
75
|
+
});
|
|
76
|
+
if (isNetworkError(error)) exitWithConnectError(ctx, `Could not reach the Keystroke server to start the ${params.integrationLabel} connection.`, {
|
|
77
|
+
code: "NETWORK_ERROR",
|
|
78
|
+
hint: `Check that your local services are running and that the CLI is pointed at ${params.baseUrl}.`
|
|
79
|
+
});
|
|
80
|
+
exitWithConnectError(ctx, `Failed to initiate the ${params.integrationLabel} connection.`, {
|
|
81
|
+
code: "INITIATE_FAILED",
|
|
82
|
+
hint: toErrorMessage(error)
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
//#endregion
|
|
86
|
+
//#region src/commands/connect/connect.input.ts
|
|
87
|
+
function parseConnectionInput(rawInputs, ctx) {
|
|
88
|
+
const input = {};
|
|
89
|
+
for (const rawInput of rawInputs) {
|
|
90
|
+
const separatorIndex = rawInput.indexOf("=");
|
|
91
|
+
if (separatorIndex <= 0) exitWithConnectError(ctx, `Invalid --input value "${rawInput}".`, {
|
|
92
|
+
code: "USAGE_ERROR",
|
|
93
|
+
hint: "Use --input key=value. Repeat --input for multiple fields."
|
|
94
|
+
});
|
|
95
|
+
const key = rawInput.slice(0, separatorIndex).trim();
|
|
96
|
+
const value = rawInput.slice(separatorIndex + 1);
|
|
97
|
+
if (!key) exitWithConnectError(ctx, `Invalid --input value "${rawInput}".`, {
|
|
98
|
+
code: "USAGE_ERROR",
|
|
99
|
+
hint: "Input keys must be non-empty: --input key=value"
|
|
100
|
+
});
|
|
101
|
+
input[key] = value;
|
|
102
|
+
}
|
|
103
|
+
return input;
|
|
104
|
+
}
|
|
105
|
+
//#endregion
|
|
106
|
+
//#region src/commands/connect/connect.poll.ts
|
|
107
|
+
async function pollConnectionStatus(params) {
|
|
108
|
+
const { ctx, apiIntegrationId, integrationLabel, initiatedAt, timeoutSeconds, authUrl, oauthConnection } = params;
|
|
109
|
+
const client = ctx.client;
|
|
110
|
+
if (!client) exitWithConnectError(ctx, "Not authenticated.", {
|
|
111
|
+
code: "AUTH_ERROR",
|
|
112
|
+
hint: AUTH_HINT
|
|
113
|
+
});
|
|
114
|
+
ui.br();
|
|
115
|
+
ui.text(`Waiting for approval in ${integrationLabel}...`);
|
|
116
|
+
ui.text("Return to this terminal after you approve access.");
|
|
117
|
+
ui.text("Press Ctrl+C to cancel.");
|
|
118
|
+
const timeoutMs = timeoutSeconds * 1e3;
|
|
119
|
+
const pollIntervalMs = 2e3;
|
|
120
|
+
const startTime = Date.now();
|
|
121
|
+
let consecutivePollFailures = 0;
|
|
122
|
+
let pollingWarningShown = false;
|
|
123
|
+
while (Date.now() - startTime < timeoutMs) {
|
|
124
|
+
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
125
|
+
try {
|
|
126
|
+
const data = ConnectionStatusResponseSchema.parse(await client.connections.getStatus(apiIntegrationId, {
|
|
127
|
+
since: initiatedAt,
|
|
128
|
+
...oauthConnection ? { credentialConnectionId: oauthConnection.id } : {}
|
|
129
|
+
}));
|
|
130
|
+
consecutivePollFailures = 0;
|
|
131
|
+
if (data.status === "connected") {
|
|
132
|
+
ui.br();
|
|
133
|
+
ui.success(`Connected ${integrationLabel} successfully.`);
|
|
134
|
+
ui.hint(`Your ${integrationLabel} account is now available to Keystroke workflows.`);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (data.status === "failed") {
|
|
138
|
+
ui.br();
|
|
139
|
+
const headline = data.message ? `Could not finish the ${integrationLabel} connection: ${data.message}` : `Could not finish the ${integrationLabel} connection (${data.reason}).`;
|
|
140
|
+
ui.error(headline);
|
|
141
|
+
ui.hint(formatFailureHint(data.reason, integrationLabel));
|
|
142
|
+
throwReportedCliExit(headline);
|
|
143
|
+
}
|
|
144
|
+
} catch (error) {
|
|
145
|
+
if (error instanceof Error && error.name === "CliExitError") throw error;
|
|
146
|
+
const status = getHttpStatus(error);
|
|
147
|
+
if (status === 401) exitWithConnectError(ctx, "Your CLI session is no longer authenticated.", {
|
|
148
|
+
code: "AUTH_ERROR",
|
|
149
|
+
hint: AUTH_HINT
|
|
150
|
+
});
|
|
151
|
+
if (status === 403) exitWithConnectError(ctx, `You do not have permission to finish the ${integrationLabel} connection in the current organization.`, {
|
|
152
|
+
code: "FORBIDDEN",
|
|
153
|
+
hint: "Verify your active organization and your permissions in that organization."
|
|
154
|
+
});
|
|
155
|
+
consecutivePollFailures += 1;
|
|
156
|
+
if (!pollingWarningShown && consecutivePollFailures >= 3) {
|
|
157
|
+
pollingWarningShown = true;
|
|
158
|
+
ui.warn(`Still waiting for ${integrationLabel} authorization.`);
|
|
159
|
+
ui.hint(status !== null ? `Polling has hit temporary errors (latest HTTP ${status}). If you already approved access, wait a moment and try again.` : "Polling has hit temporary errors. If you already approved access, wait a moment and try again.");
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
ui.br();
|
|
164
|
+
ui.error(`Timed out waiting for ${integrationLabel} authorization.`);
|
|
165
|
+
ui.text("If authorization is still open in your browser, you can still finish it here:");
|
|
166
|
+
ui.text(` ${authUrl}`);
|
|
167
|
+
throwReportedCliExit(`Timed out waiting for ${integrationLabel} authorization.`);
|
|
168
|
+
}
|
|
169
|
+
//#endregion
|
|
170
|
+
//#region src/commands/connect/connect.scope.ts
|
|
80
171
|
/**
|
|
81
172
|
* Resolve the project id for this connect attempt.
|
|
82
173
|
*
|
|
83
174
|
* Precedence:
|
|
84
175
|
* 1. Explicit `--project-id <uuid>` flag.
|
|
85
176
|
* 2. `keystroke.config.ts` discovered from `--path` or by walking up
|
|
86
|
-
* from cwd.
|
|
87
|
-
* found.
|
|
177
|
+
* from cwd.
|
|
88
178
|
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
* organization scope.
|
|
179
|
+
* A discovered-but-invalid config is a usage error. Silent fallback to org
|
|
180
|
+
* scope would create credentials at a broader scope than the user likely meant.
|
|
92
181
|
*/
|
|
93
|
-
async function resolveConnectProjectId(options) {
|
|
182
|
+
async function resolveConnectProjectId(options, ctx) {
|
|
94
183
|
if (options.projectId) return options.projectId;
|
|
95
184
|
const workflowsDir = await resolveWorkflowsDir(options.path);
|
|
96
185
|
if (!workflowsDir) return null;
|
|
97
186
|
try {
|
|
98
187
|
return (await assertWorkflowProjectRoot(workflowsDir)).projectId;
|
|
99
|
-
} catch {
|
|
100
|
-
|
|
188
|
+
} catch (error) {
|
|
189
|
+
exitWithConnectError(ctx, `Could not read project configuration for ${workflowsDir}.${error instanceof Error ? ` ${error.message}` : ""}`, {
|
|
190
|
+
code: "PROJECT_CONFIG_ERROR",
|
|
191
|
+
hint: "Fix keystroke.config.ts, pass --project-id explicitly, or use --scope organization outside the project directory."
|
|
192
|
+
});
|
|
101
193
|
}
|
|
102
194
|
}
|
|
103
|
-
function
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
195
|
+
async function resolveConnectScopeRequest(options, ctx) {
|
|
196
|
+
if (options.projectId && (options.scope === "organization" || options.scope === "user")) exitWithConnectError(ctx, `--project-id cannot be used with --scope ${options.scope}.`, {
|
|
197
|
+
code: "USAGE_ERROR",
|
|
198
|
+
hint: "Use --scope project for project-scoped connections, or omit --project-id for organization/user scope."
|
|
199
|
+
});
|
|
200
|
+
if (options.scope === "organization" || options.scope === "user") return {
|
|
201
|
+
scopeForRequest: options.scope,
|
|
202
|
+
projectIdForRequest: void 0
|
|
203
|
+
};
|
|
204
|
+
const resolvedProjectId = await resolveConnectProjectId(options, ctx);
|
|
205
|
+
if (options.scope === "project" && !resolvedProjectId) exitWithConnectError(ctx, "--scope project requires a project context. Pass --project-id <uuid>, --path <dir>, or run inside a project directory.", {
|
|
206
|
+
code: "USAGE_ERROR",
|
|
207
|
+
hint: "Use `keystroke init` to create a project, or pick a different scope."
|
|
208
|
+
});
|
|
209
|
+
return {
|
|
210
|
+
scopeForRequest: options.scope,
|
|
211
|
+
projectIdForRequest: resolvedProjectId ?? void 0
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
//#endregion
|
|
215
|
+
//#region src/commands/connect/connect.selection.ts
|
|
216
|
+
function formatIntegrationLabel(catalog, integrationId) {
|
|
217
|
+
return catalog.lookupByPublicId(integrationId)?.name ?? integrationId;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Credential definition id sent to the connections API. Catalog aliases such as
|
|
221
|
+
* `slack` may differ from the server row id (`keystroke:slack`).
|
|
222
|
+
*/
|
|
223
|
+
function resolveConnectApiIntegrationId(integrationId, catalogEntry) {
|
|
224
|
+
return catalogEntry?.credentialSet.credentialDefinitionId ?? integrationId;
|
|
225
|
+
}
|
|
226
|
+
function formatConnectionLabel(connection) {
|
|
227
|
+
return connection.label ?? connection.id;
|
|
228
|
+
}
|
|
229
|
+
function formatConnectionFlags(connection) {
|
|
230
|
+
const flags = [connection.recommended === true ? "recommended" : null, connection.advanced === true ? "advanced" : null].filter((flag) => flag !== null);
|
|
231
|
+
return flags.length > 0 ? `, ${flags.join(", ")}` : "";
|
|
232
|
+
}
|
|
233
|
+
function availableOAuthConnectionHint(connections) {
|
|
234
|
+
const oauthConnections = connections?.filter((connection) => connection.kind === "oauth") ?? [];
|
|
235
|
+
if (oauthConnections.length === 0) return "Run `keystroke integrations list --kind oauth` to see integrations with OAuth connection paths.";
|
|
236
|
+
return `Available OAuth connection IDs: ${oauthConnections.map((connection) => `${connection.id}${connection.recommended ? " (recommended)" : ""}`).join(", ")}.`;
|
|
237
|
+
}
|
|
238
|
+
function selectOAuthConnection(params) {
|
|
239
|
+
const { catalogEntry, requestedCredentialConnectionId, ctx, integrationId } = params;
|
|
240
|
+
const connections = catalogEntry?.connections ?? [];
|
|
241
|
+
if (requestedCredentialConnectionId) {
|
|
242
|
+
const selected = connections.find((connection) => connection.id === requestedCredentialConnectionId);
|
|
243
|
+
if (!selected) exitWithConnectError(ctx, `Credential connection "${requestedCredentialConnectionId}" is not defined for "${integrationId}".`, {
|
|
244
|
+
code: "UNKNOWN_CREDENTIAL_CONNECTION",
|
|
245
|
+
hint: availableOAuthConnectionHint(connections)
|
|
110
246
|
});
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
code: "USAGE_ERROR",
|
|
115
|
-
hint: "Input keys must be non-empty: --input key=value"
|
|
247
|
+
if (selected.kind !== "oauth") exitWithConnectError(ctx, `Credential connection "${selected.id}" for "${integrationId}" is "${selected.kind}", not oauth.`, {
|
|
248
|
+
code: "UNSUPPORTED_CREDENTIAL_CONNECTION",
|
|
249
|
+
hint: availableOAuthConnectionHint(connections)
|
|
116
250
|
});
|
|
117
|
-
|
|
251
|
+
return selected;
|
|
118
252
|
}
|
|
119
|
-
return
|
|
253
|
+
return connections.find((connection) => connection.kind === "oauth" && connection.recommended === true) ?? connections.find((connection) => connection.kind === "oauth");
|
|
120
254
|
}
|
|
255
|
+
function resolveConnectTarget(params) {
|
|
256
|
+
const { catalog, ctx, integrationId, requestedCredentialConnectionId } = params;
|
|
257
|
+
const catalogEntry = catalog.lookupByPublicId(integrationId);
|
|
258
|
+
const oauthConnection = selectOAuthConnection({
|
|
259
|
+
catalogEntry,
|
|
260
|
+
requestedCredentialConnectionId,
|
|
261
|
+
ctx,
|
|
262
|
+
integrationId
|
|
263
|
+
});
|
|
264
|
+
return {
|
|
265
|
+
catalogEntry,
|
|
266
|
+
oauthConnection,
|
|
267
|
+
apiIntegrationId: resolveConnectApiIntegrationId(integrationId, catalogEntry),
|
|
268
|
+
integrationLabel: oauthConnection ? formatIntegrationLabel(catalog, integrationId) : integrationId
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
//#endregion
|
|
272
|
+
//#region src/commands/connect/connect.handler.ts
|
|
121
273
|
/**
|
|
122
274
|
* Handle the `keystroke connect <integrationId>` command.
|
|
123
275
|
*
|
|
124
276
|
* Initiates a platform OAuth flow:
|
|
125
277
|
* 1. Calls POST /api/v1/connections/:integrationId/initiate to get an auth URL + state token
|
|
126
278
|
* 2. Opens the browser to the auth URL
|
|
127
|
-
* 3. Polls GET /api/v1/connections/:integrationId/status?
|
|
279
|
+
* 3. Polls GET /api/v1/connections/:integrationId/status?since=... until connected or timeout
|
|
128
280
|
*/
|
|
129
281
|
async function handleConnect(options, ctx) {
|
|
130
282
|
const integrationId = options.integrationId?.trim().toLowerCase();
|
|
131
|
-
const { baseUrl
|
|
132
|
-
|
|
283
|
+
const { baseUrl } = ctx;
|
|
284
|
+
const client = requireClient(ctx);
|
|
285
|
+
if (!baseUrl) exitWithConnectError(ctx, "Not authenticated.", {
|
|
133
286
|
code: "AUTH_ERROR",
|
|
134
287
|
hint: AUTH_HINT
|
|
135
288
|
});
|
|
136
|
-
if (!integrationId)
|
|
289
|
+
if (!integrationId) exitWithConnectError(ctx, "Usage: keystroke connect <integrationId>", {
|
|
137
290
|
code: "USAGE_ERROR",
|
|
138
291
|
hint: "Example: keystroke connect github"
|
|
139
292
|
});
|
|
140
293
|
const catalog = await getIntegrationCatalog(ctx);
|
|
141
|
-
const catalogEntry =
|
|
142
|
-
|
|
143
|
-
catalogEntry,
|
|
144
|
-
requestedCredentialConnectionId: options.connection,
|
|
294
|
+
const { catalogEntry, oauthConnection, apiIntegrationId, integrationLabel } = resolveConnectTarget({
|
|
295
|
+
catalog,
|
|
145
296
|
ctx,
|
|
146
|
-
integrationId
|
|
297
|
+
integrationId,
|
|
298
|
+
requestedCredentialConnectionId: options.connection
|
|
147
299
|
});
|
|
148
|
-
const integrationLabel = Boolean(oauthConnection) ? formatIntegrationLabel(catalog, integrationId) : integrationId;
|
|
149
300
|
const connectionInput = parseConnectionInput(options.input ?? [], ctx);
|
|
150
301
|
if (!ctx.jsonMode) {
|
|
151
302
|
ui.text(`Connect ${integrationLabel}`);
|
|
303
|
+
ui.hint(`API URL: ${baseUrl}`);
|
|
152
304
|
if (oauthConnection && ((catalogEntry?.connections.length ?? 0) > 1 || options.connection)) ui.text(`Connection: ${formatConnectionLabel(oauthConnection)} (id: ${oauthConnection.id}${formatConnectionFlags(oauthConnection)})`);
|
|
153
305
|
ui.br();
|
|
154
306
|
}
|
|
155
|
-
const
|
|
156
|
-
if (options.scope === "project" && !resolvedProjectId) exitWithError(ctx, "--scope project requires a project context. Pass --project-id <uuid>, --path <dir>, or run inside a project directory.", {
|
|
157
|
-
code: "USAGE_ERROR",
|
|
158
|
-
hint: "Use `keystroke init` to create a project, or pick a different scope."
|
|
159
|
-
});
|
|
160
|
-
const scopeForRequest = options.scope;
|
|
161
|
-
const projectIdForRequest = scopeForRequest === "user" || scopeForRequest === "organization" ? void 0 : resolvedProjectId ?? void 0;
|
|
307
|
+
const { scopeForRequest, projectIdForRequest } = await resolveConnectScopeRequest(options, ctx);
|
|
162
308
|
let authUrl;
|
|
163
309
|
let initiatedAt;
|
|
164
310
|
try {
|
|
@@ -170,58 +316,20 @@ async function handleConnect(options, ctx) {
|
|
|
170
316
|
...options.name ? { name: options.name } : {}
|
|
171
317
|
});
|
|
172
318
|
const hasRequestBody = Object.keys(requestBody).length > 0;
|
|
173
|
-
const
|
|
174
|
-
method: "POST",
|
|
175
|
-
headers: {
|
|
176
|
-
Authorization: `Bearer ${apiKey}`,
|
|
177
|
-
...hasRequestBody ? { "Content-Type": "application/json" } : {}
|
|
178
|
-
},
|
|
179
|
-
...hasRequestBody ? { body: JSON.stringify(requestBody) } : {}
|
|
180
|
-
});
|
|
181
|
-
if (!response.ok) {
|
|
182
|
-
if (response.status === 404) exitWithError(ctx, `Integration "${integrationId}" is not supported for platform OAuth.`, {
|
|
183
|
-
code: "UNSUPPORTED_INTEGRATION",
|
|
184
|
-
hint: `Currently supported official OAuth integrations: ${catalog.oauthPublicIds.join(", ")}. Custom OAuth connect flows are not available yet.`
|
|
185
|
-
});
|
|
186
|
-
if (response.status === 503) exitWithError(ctx, `Platform credentials not configured for "${integrationId}".`, {
|
|
187
|
-
code: "PLATFORM_NOT_CONFIGURED",
|
|
188
|
-
hint: `Ask a Keystroke developer to configure the ${integrationLabel} account OAuth client for this environment.`
|
|
189
|
-
});
|
|
190
|
-
if (response.status === 401) exitWithError(ctx, "Not authenticated.", {
|
|
191
|
-
code: "AUTH_ERROR",
|
|
192
|
-
hint: AUTH_HINT
|
|
193
|
-
});
|
|
194
|
-
if (response.status === 403) exitWithError(ctx, `You do not have permission to connect ${integrationLabel} in the current organization.`, {
|
|
195
|
-
code: "FORBIDDEN",
|
|
196
|
-
hint: "Verify your active organization and your permissions in that organization."
|
|
197
|
-
});
|
|
198
|
-
if (response.status >= 500) exitWithError(ctx, `The Keystroke server failed while starting the ${integrationLabel} connection.`, {
|
|
199
|
-
code: "SERVER_ERROR",
|
|
200
|
-
hint: `Server returned HTTP ${response.status}. Check the server logs and try again.`
|
|
201
|
-
});
|
|
202
|
-
exitWithError(ctx, `Failed to initiate the ${integrationLabel} connection.`, {
|
|
203
|
-
code: "INITIATE_FAILED",
|
|
204
|
-
hint: `Server returned HTTP ${response.status}.`
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
const data = InitiateConnectionResponseSchema.parse(await response.json());
|
|
319
|
+
const data = InitiateConnectionResponseSchema.parse(await client.connections.initiate(apiIntegrationId, hasRequestBody ? requestBody : void 0));
|
|
208
320
|
authUrl = data.authUrl;
|
|
209
321
|
initiatedAt = data.initiatedAt;
|
|
210
322
|
} catch (error) {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
});
|
|
216
|
-
exitWithError(ctx, `Failed to initiate the ${integrationLabel} connection.`, {
|
|
217
|
-
code: "INITIATE_FAILED",
|
|
218
|
-
hint: toErrorMessage(error)
|
|
323
|
+
exitOnConnectionInitiateError(ctx, error, {
|
|
324
|
+
integrationLabel,
|
|
325
|
+
catalog,
|
|
326
|
+
baseUrl
|
|
219
327
|
});
|
|
220
328
|
}
|
|
221
329
|
if (ctx.jsonMode) {
|
|
222
330
|
writeJson({
|
|
223
331
|
status: "authorization_required",
|
|
224
|
-
integrationId,
|
|
332
|
+
integrationId: apiIntegrationId,
|
|
225
333
|
credentialConnectionId: oauthConnection?.id,
|
|
226
334
|
...oauthConnection ? { selectedConnection: {
|
|
227
335
|
id: oauthConnection.id,
|
|
@@ -247,69 +355,15 @@ async function handleConnect(options, ctx) {
|
|
|
247
355
|
ui.text("Open this URL manually to continue:");
|
|
248
356
|
ui.text(` ${authUrl}`);
|
|
249
357
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
while (Date.now() - startTime < timeoutMs) {
|
|
260
|
-
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
261
|
-
try {
|
|
262
|
-
const statusUrl = new URL(`${baseUrl}/api/v1/connections/${integrationId}/status`);
|
|
263
|
-
statusUrl.searchParams.set("since", String(initiatedAt));
|
|
264
|
-
if (oauthConnection) statusUrl.searchParams.set("credentialConnectionId", oauthConnection.id);
|
|
265
|
-
const response = await fetch(statusUrl.toString(), { headers: { Authorization: `Bearer ${apiKey}` } });
|
|
266
|
-
if (!response.ok) {
|
|
267
|
-
consecutivePollFailures += 1;
|
|
268
|
-
if (response.status === 401) exitWithError(ctx, "Your CLI session is no longer authenticated.", {
|
|
269
|
-
code: "AUTH_ERROR",
|
|
270
|
-
hint: AUTH_HINT
|
|
271
|
-
});
|
|
272
|
-
if (response.status === 403) exitWithError(ctx, `You do not have permission to finish the ${integrationLabel} connection in the current organization.`, {
|
|
273
|
-
code: "FORBIDDEN",
|
|
274
|
-
hint: "Verify your active organization and your permissions in that organization."
|
|
275
|
-
});
|
|
276
|
-
if (!pollingWarningShown && consecutivePollFailures >= 3) {
|
|
277
|
-
pollingWarningShown = true;
|
|
278
|
-
ui.warn(`Still waiting for ${integrationLabel} authorization.`);
|
|
279
|
-
ui.hint(`Polling has hit temporary errors (latest HTTP ${response.status}). If you already approved access, wait a moment and try again.`);
|
|
280
|
-
}
|
|
281
|
-
continue;
|
|
282
|
-
}
|
|
283
|
-
consecutivePollFailures = 0;
|
|
284
|
-
const data = ConnectionStatusResponseSchema.parse(await response.json());
|
|
285
|
-
if (data.status === "connected") {
|
|
286
|
-
ui.br();
|
|
287
|
-
ui.success(`Connected ${integrationLabel} successfully.`);
|
|
288
|
-
ui.hint(`Your ${integrationLabel} account is now available to Keystroke workflows.`);
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
if (data.status === "failed") {
|
|
292
|
-
ui.br();
|
|
293
|
-
const headline = data.message ? `Could not finish the ${integrationLabel} connection: ${data.message}` : `Could not finish the ${integrationLabel} connection (${data.reason}).`;
|
|
294
|
-
ui.error(headline);
|
|
295
|
-
ui.hint(formatFailureHint(data.reason, integrationLabel));
|
|
296
|
-
throwReportedCliExit(headline);
|
|
297
|
-
}
|
|
298
|
-
} catch (error) {
|
|
299
|
-
if (error instanceof Error && error.name === "CliExitError") throw error;
|
|
300
|
-
consecutivePollFailures += 1;
|
|
301
|
-
if (!pollingWarningShown && consecutivePollFailures >= 3) {
|
|
302
|
-
pollingWarningShown = true;
|
|
303
|
-
ui.warn(`Still waiting for ${integrationLabel} authorization.`);
|
|
304
|
-
ui.hint(`Polling has hit temporary errors. If you already approved access, wait a moment and try again.`);
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
ui.br();
|
|
309
|
-
ui.error(`Timed out waiting for ${integrationLabel} authorization.`);
|
|
310
|
-
ui.text("If authorization is still open in your browser, you can still finish it here:");
|
|
311
|
-
ui.text(` ${authUrl}`);
|
|
312
|
-
throwReportedCliExit(`Timed out waiting for ${integrationLabel} authorization.`);
|
|
358
|
+
await pollConnectionStatus({
|
|
359
|
+
ctx,
|
|
360
|
+
apiIntegrationId,
|
|
361
|
+
integrationLabel,
|
|
362
|
+
initiatedAt,
|
|
363
|
+
timeoutSeconds: options.timeout,
|
|
364
|
+
authUrl,
|
|
365
|
+
oauthConnection
|
|
366
|
+
});
|
|
313
367
|
}
|
|
314
368
|
//#endregion
|
|
315
369
|
export { handleConnect };
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import { n as __exportAll } from "./chunk-CH6r78ws.mjs";
|
|
4
4
|
import { A as CliExitError, L as logger, S as toErrorMessage, b as isAuthError, c as getProcessEnv, g as REAUTH_HINT, h as AUTH_HINT, k as AuthenticationError, p as ui, s as getEnv } from "./keystroke.mjs";
|
|
5
|
-
import { n as credentials } from "./dist-
|
|
6
|
-
import { t as resolveCliCredentials } from "./resolve-cli-credentials-
|
|
7
|
-
import { a as writeJsonError } from "./output-
|
|
5
|
+
import { n as credentials } from "./dist-rsDq3fTk.mjs";
|
|
6
|
+
import { t as resolveCliCredentials } from "./resolve-cli-credentials-BecTgRE7.mjs";
|
|
7
|
+
import { a as writeJsonError } from "./output-C0pbsv39.mjs";
|
|
8
8
|
//#region src/lib/context.ts
|
|
9
9
|
var context_exports = /* @__PURE__ */ __exportAll({
|
|
10
10
|
assertProjectConfigMatchesAuthenticatedOrg: () => assertProjectConfigMatchesAuthenticatedOrg,
|
|
@@ -38,7 +38,7 @@ async function resolveBaseContext(overrides = {}) {
|
|
|
38
38
|
const authContext = await resolveAuthContext(overrides);
|
|
39
39
|
let client = null;
|
|
40
40
|
if (authContext.apiKey && authContext.baseUrl) try {
|
|
41
|
-
const { createClient } = await import("./src-
|
|
41
|
+
const { createClient } = await import("./src-DOCKWJRW.mjs").then((n) => n.t);
|
|
42
42
|
client = createClient({
|
|
43
43
|
apiKey: authContext.apiKey,
|
|
44
44
|
baseUrl: authContext.baseUrl,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { P as throwReportedCliExit, S as toErrorMessage, p as ui } from "./keystroke.mjs";
|
|
4
|
-
import { i as writeJson } from "./output-
|
|
5
|
-
import { i as requireClient } from "./context-
|
|
4
|
+
import { i as writeJson } from "./output-C0pbsv39.mjs";
|
|
5
|
+
import { i as requireClient } from "./context-DaBLwEWi.mjs";
|
|
6
6
|
//#region src/commands/api-keys/create.handler.ts
|
|
7
7
|
async function handleApiKeysCreate(options, ctx) {
|
|
8
8
|
const client = requireClient(ctx);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { r as getKeystrokeProjectPath } from "./paths-DpHfoaXN-CdPimpky.mjs";
|
|
4
|
-
import "./dist-
|
|
4
|
+
import "./dist-rsDq3fTk.mjs";
|
|
5
5
|
import * as fs from "node:fs/promises";
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
//#region src/lib/credential-env-map.ts
|
package/dist/{credential-schema-mismatch-CStYUB2h.mjs → credential-schema-mismatch-BvcO7KgE.mjs}
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { i as writeJson } from "./output-
|
|
3
|
+
import { i as writeJson } from "./output-C0pbsv39.mjs";
|
|
4
4
|
//#region src/lib/credential-schema-mismatch.ts
|
|
5
5
|
/**
|
|
6
6
|
* Structured detection and rendering for `CredentialSchemaMismatchError`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { f as collectCredentialRequirementEntries } from "./credential-requirements-B5Alhu1v-
|
|
3
|
+
import { f as collectCredentialRequirementEntries } from "./credential-requirements-B5Alhu1v-C26qMgU_.mjs";
|
|
4
4
|
//#region ../../packages/workflow-deploy/dist/credentials/index.mjs
|
|
5
5
|
/**
|
|
6
6
|
* Resolves credential values from environment using KEYSTROKE_<KEY> convention.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { n as JsonOptionSchema, t as JSON_OPTION_CONFIG } from "./output-
|
|
4
|
-
import { t as createTypedCommand } from "./commander-
|
|
5
|
-
import { i as CredentialScopeValues, n as CredentialConnectionIdSchema, r as CredentialScopeSchema } from "./schema-
|
|
6
|
-
import { t as ConnectionKindValues } from "./api-
|
|
3
|
+
import { n as JsonOptionSchema, t as JSON_OPTION_CONFIG } from "./output-C0pbsv39.mjs";
|
|
4
|
+
import { t as createTypedCommand } from "./commander-DIOuj6NJ.mjs";
|
|
5
|
+
import { i as CredentialScopeValues, n as CredentialConnectionIdSchema, r as CredentialScopeSchema } from "./schema-QbiBSbhG.mjs";
|
|
6
|
+
import { t as ConnectionKindValues } from "./api-b0DzMwXP.mjs";
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
//#region ../../packages/shared-types/src/credentials/models/definition-records.ts
|
|
9
9
|
const JsonRecordSchema = z.record(z.string(), z.unknown());
|
|
@@ -265,13 +265,13 @@ function createCredentialsDefinitionsCommand() {
|
|
|
265
265
|
description: "Browse and inspect credential definitions (catalog metadata; not per-org credential sets)",
|
|
266
266
|
schema: CredentialDefinitionsListOptionsSchema,
|
|
267
267
|
optionsConfig: DEFINITIONS_LIST_OPTIONS_CONFIG,
|
|
268
|
-
loadHandler: async () => (await import("./list.handler-
|
|
268
|
+
loadHandler: async () => (await import("./list.handler-Dny_G7yA.mjs")).handleCredentialDefinitionsList,
|
|
269
269
|
subcommands: [createTypedCommand({
|
|
270
270
|
name: "list",
|
|
271
271
|
description: "List credential definitions",
|
|
272
272
|
schema: CredentialDefinitionsListOptionsSchema,
|
|
273
273
|
optionsConfig: DEFINITIONS_LIST_OPTIONS_CONFIG,
|
|
274
|
-
loadHandler: async () => (await import("./list.handler-
|
|
274
|
+
loadHandler: async () => (await import("./list.handler-Dny_G7yA.mjs")).handleCredentialDefinitionsList
|
|
275
275
|
}), createTypedCommand({
|
|
276
276
|
name: "show",
|
|
277
277
|
description: "Show one credential definition including auth schema",
|
|
@@ -282,7 +282,7 @@ function createCredentialsDefinitionsCommand() {
|
|
|
282
282
|
description: "Credential definition id, e.g. keystroke:aws-s3",
|
|
283
283
|
key: "id"
|
|
284
284
|
},
|
|
285
|
-
loadHandler: async () => (await import("./show.handler-
|
|
285
|
+
loadHandler: async () => (await import("./show.handler-BupYRNqw.mjs")).handleCredentialDefinitionShow
|
|
286
286
|
})]
|
|
287
287
|
});
|
|
288
288
|
}
|
|
@@ -329,7 +329,7 @@ function createCredentialsListCommand() {
|
|
|
329
329
|
description: "List credential sets on the server",
|
|
330
330
|
schema: ListOptionsSchema,
|
|
331
331
|
optionsConfig: LIST_OPTIONS_CONFIG,
|
|
332
|
-
loadHandler: async () => (await import("./list.handler-
|
|
332
|
+
loadHandler: async () => (await import("./list.handler-CXsHFhRg.mjs")).handleCredentialsList
|
|
333
333
|
});
|
|
334
334
|
}
|
|
335
335
|
//#endregion
|
|
@@ -348,7 +348,7 @@ function createCredentialsRequirementsCommand() {
|
|
|
348
348
|
description: "Show what credentials built workflows need (keys, KEYSTROKE_* env names, workflows) — from dist manifests, no API call",
|
|
349
349
|
schema: RequirementsOptionsSchema,
|
|
350
350
|
optionsConfig: REQUIREMENTS_OPTIONS_CONFIG,
|
|
351
|
-
loadHandler: async () => (await import("./requirements.handler-
|
|
351
|
+
loadHandler: async () => (await import("./requirements.handler-CA4zeT3J.mjs")).handleCredentialsRequirements
|
|
352
352
|
});
|
|
353
353
|
}
|
|
354
354
|
//#endregion
|
|
@@ -409,7 +409,7 @@ function createCredentialsUploadCommand() {
|
|
|
409
409
|
description: "Upload credentials from env vars to the server. Default: reads requirements from built workflow manifests. Use --integration for an official integration or --credential-set + --keys for a custom explicit upload.",
|
|
410
410
|
schema: UploadOptionsSchema,
|
|
411
411
|
optionsConfig: UPLOAD_OPTIONS_CONFIG,
|
|
412
|
-
loadHandler: async () => (await import("./upload.handler-
|
|
412
|
+
loadHandler: async () => (await import("./upload.handler-Y-yOXVYC.mjs")).handleCredentialsUpload
|
|
413
413
|
});
|
|
414
414
|
}
|
|
415
415
|
//#endregion
|
|
@@ -440,7 +440,7 @@ function createCredentialsCommand() {
|
|
|
440
440
|
}
|
|
441
441
|
},
|
|
442
442
|
handler: async (opts, ctx) => {
|
|
443
|
-
const { handleCredentialsList } = await import("./list.handler-
|
|
443
|
+
const { handleCredentialsList } = await import("./list.handler-CXsHFhRg.mjs");
|
|
444
444
|
await handleCredentialsList({
|
|
445
445
|
...opts,
|
|
446
446
|
scope: void 0,
|