@drawbridge/drawbridge-utils 0.0.173 → 0.0.175
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/connections/index.cjs +460 -242
- package/dist/connections/index.d.cts +630 -319
- package/dist/connections/index.d.ts +630 -319
- package/dist/connections/index.js +459 -241
- package/dist/providers.cjs +460 -244
- package/dist/providers.d.cts +6 -6
- package/dist/providers.d.ts +6 -6
- package/dist/providers.js +460 -244
- package/package.json +1 -1
package/dist/providers.cjs
CHANGED
|
@@ -509,7 +509,7 @@ var detectCountry = (value) => {
|
|
|
509
509
|
}
|
|
510
510
|
};
|
|
511
511
|
|
|
512
|
-
// lib/connections/segment
|
|
512
|
+
// lib/connections/segment.js
|
|
513
513
|
var import_node_crypto2 = require("crypto");
|
|
514
514
|
var row = ({ connection: connection2, data: data2, manifest, row: described }) => {
|
|
515
515
|
var _a, _b;
|
|
@@ -602,7 +602,7 @@ var driftEnqueues = async ({ applied, read, segment, workflow }) => {
|
|
|
602
602
|
}];
|
|
603
603
|
};
|
|
604
604
|
|
|
605
|
-
// lib/connections/
|
|
605
|
+
// lib/connections/manifests/attentive.js
|
|
606
606
|
var api = async (path, { fetcher = fetch, method = "GET", payload, token }) => {
|
|
607
607
|
const response = await fetcher("https://api.attentivemobile.com" + path, {
|
|
608
608
|
...payload && { body: JSON.stringify(payload) },
|
|
@@ -941,26 +941,6 @@ var attentive_default2 = {
|
|
|
941
941
|
webhook: false
|
|
942
942
|
},
|
|
943
943
|
icon: attentive_default,
|
|
944
|
-
// DRAWBRIDGE'S OWN CREDENTIALS for this vendor, as opposed to a merchant's —
|
|
945
|
-
// what an admin types on the provider screen, and the only declaration of it.
|
|
946
|
-
// It lives beside `requires`, which names the same variables: the manifest
|
|
947
|
-
// says what it needs and this says how someone supplies it, so a credential
|
|
948
|
-
// cannot be required by a vendor that offers nowhere to enter it.
|
|
949
|
-
//
|
|
950
|
-
// `redact` marks a secret — never returned by the api, and blank on save means
|
|
951
|
-
// keep the stored value. `required` drives the live check.
|
|
952
|
-
provider: {
|
|
953
|
-
vendors: {
|
|
954
|
-
attentive: {
|
|
955
|
-
fields: [
|
|
956
|
-
{ input: "text", key: "clientId", credential: "ATTENTIVE_OAUTH_CLIENT_ID", label: "Client ID", message: "From our app's registration in the Attentive developer portal.", required: true },
|
|
957
|
-
{ input: "password", key: "clientSecret", credential: "ATTENTIVE_OAUTH_CLIENT_SECRET", label: "Client secret", message: "Beside the Client ID in the Attentive developer portal.", redact: true, required: true }
|
|
958
|
-
],
|
|
959
|
-
icon: attentive_default,
|
|
960
|
-
name: "Attentive"
|
|
961
|
-
}
|
|
962
|
-
}
|
|
963
|
-
},
|
|
964
944
|
requires: [
|
|
965
945
|
"ATTENTIVE_OAUTH_CLIENT_ID",
|
|
966
946
|
"ATTENTIVE_OAUTH_CLIENT_SECRET"
|
|
@@ -1051,6 +1031,11 @@ var attentive_default2 = {
|
|
|
1051
1031
|
}
|
|
1052
1032
|
];
|
|
1053
1033
|
},
|
|
1034
|
+
// THE VENDORS THIS CONNECTION SPENDS, by slug. Each is declared once in
|
|
1035
|
+
// lib/connections/vendors/, and named here by whoever uses it — the block that
|
|
1036
|
+
// used to sit here declared them inline, so two manifests naming one vendor had
|
|
1037
|
+
// to be reconciled at import by mergeVendors().
|
|
1038
|
+
vendors: ["attentive"],
|
|
1054
1039
|
title: "Attentive",
|
|
1055
1040
|
// ATTENTIVE'S SEGMENTS INDEX. There is no documented per-segment url, and the
|
|
1056
1041
|
// only identifier we hold is the API's externalId, which their UI may not
|
|
@@ -1068,7 +1053,7 @@ var attentive_default2 = {
|
|
|
1068
1053
|
}
|
|
1069
1054
|
};
|
|
1070
1055
|
|
|
1071
|
-
// lib/connections/
|
|
1056
|
+
// lib/connections/manifests/drawbridge.js
|
|
1072
1057
|
var import_node_crypto4 = require("crypto");
|
|
1073
1058
|
|
|
1074
1059
|
// lib/connections/inbound.js
|
|
@@ -2005,7 +1990,7 @@ var MINIMUM_ACTION_CENTS = Math.round(
|
|
|
2005
1990
|
sending.sms.segmentCostCents / channels.sms.actionsPerSegment * MARKUP * 1e3
|
|
2006
1991
|
) / 1e3;
|
|
2007
1992
|
|
|
2008
|
-
// lib/connections/
|
|
1993
|
+
// lib/connections/manifests/drawbridge.js
|
|
2009
1994
|
var STOP_KEYWORDS = ["STOP", "STOPALL", "UNSUBSCRIBE", "CANCEL", "END", "QUIT"];
|
|
2010
1995
|
var START_KEYWORDS = ["START", "UNSTOP", "YES"];
|
|
2011
1996
|
var sendgridInbound = {
|
|
@@ -2702,70 +2687,6 @@ var drawbridge_default2 = {
|
|
|
2702
2687
|
},
|
|
2703
2688
|
// PRIVATE: never in the catalog, always available to the builder.
|
|
2704
2689
|
private: true,
|
|
2705
|
-
// THE PLATFORM'S OWN SENDING CREDENTIALS — SendGrid, Twilio, and the internal
|
|
2706
|
-
// HubSpot portal. No merchant ever sees these; they are what an admin types on
|
|
2707
|
-
// the provider screen so that Drawbridge itself can send.
|
|
2708
|
-
//
|
|
2709
|
-
// They belong on THIS manifest because this is the connection that sends: the
|
|
2710
|
-
// email, sms and segment hooks below are the only things that spend them, and
|
|
2711
|
-
// a private connection is still where a vendor fact lives. They are THREE
|
|
2712
|
-
// VENDORS, not one, and each is its own row and its own admin card — so
|
|
2713
|
-
// SendGrid reads live on a deployment that never configured Twilio, instead
|
|
2714
|
-
// of one card for all three that could only ever be as live as its weakest.
|
|
2715
|
-
//
|
|
2716
|
-
// UNLIKE every public vendor, none of these appear in `requires` — see the
|
|
2717
|
-
// comment there. Availability and configuration are different questions, and a
|
|
2718
|
-
// missing CRM token must not take every base workflow step away.
|
|
2719
|
-
//
|
|
2720
|
-
// ponytail: the field keys keep the names they had on the shared row
|
|
2721
|
-
// (smsSid, hubspotToken) so the readers destructuring vendorSettings() did
|
|
2722
|
-
// not move. Rename them to sid/token when those readers are next touched.
|
|
2723
|
-
provider: {
|
|
2724
|
-
vendors: {
|
|
2725
|
-
sendgrid: {
|
|
2726
|
-
fields: [
|
|
2727
|
-
{ input: "email", key: "accountSender", credential: "SENDGRID_FROM_ADDRESS", label: "Account sender", message: "Verification codes and security alerts send from here.", required: true },
|
|
2728
|
-
{ input: "password", key: "apiKey", credential: "SENDGRID_API_KEY", label: "SendGrid API key", message: "SendGrid dashboard, Settings, API Keys \u2014 full access for sends.", redact: true, required: true },
|
|
2729
|
-
// Optional: SENDGRID_SEND_FROM_ADDRESS is not boot-required in sync
|
|
2730
|
-
// either. Unset, it degrades to the account sender rather than
|
|
2731
|
-
// refusing to start.
|
|
2732
|
-
// NOT redacted, because it is a PUBLIC key. Marking it secret would
|
|
2733
|
-
// be theatre, and it would stop an operator reading back the value
|
|
2734
|
-
// they need to compare against the SendGrid console.
|
|
2735
|
-
//
|
|
2736
|
-
// Optional: absent, the event webhook answers 500 on verify rather
|
|
2737
|
-
// than accepting unverified deliveries, and nothing else notices.
|
|
2738
|
-
{ input: "text", key: "eventKey", credential: "SENDGRID_EVENT_WEBHOOK_KEY", label: "Event webhook key", message: "SendGrid, Settings, Mail Settings, Event Webhook \u2014 the verification key shown once signature verification is enabled. Public, not a secret." },
|
|
2739
|
-
{ input: "email", key: "leadSender", credential: "SENDGRID_SEND_FROM_ADDRESS", label: "Lead sender", message: "The default for lead-facing mail when a merchant has not verified their own domain." }
|
|
2740
|
-
],
|
|
2741
|
-
icon: sendgrid_default,
|
|
2742
|
-
name: "SendGrid"
|
|
2743
|
-
},
|
|
2744
|
-
// Missing, SMS is LOCKED DOWN rather than broken: every send path
|
|
2745
|
-
// refuses cleanly (queue/notification.js cancels, the otc stream skips
|
|
2746
|
-
// and logs), the number-purchase routes deny, and identityDefaults.sms
|
|
2747
|
-
// hides the org's SMS settings entirely. The card reads not live, which
|
|
2748
|
-
// is the truth about Twilio and says nothing about email.
|
|
2749
|
-
twilio: {
|
|
2750
|
-
fields: [
|
|
2751
|
-
{ input: "text", key: "smsFrom", credential: "TWILIO_ACCOUNT_FROM", label: "SMS number", message: "Without Twilio credentials, SMS is disabled across the platform.", required: true },
|
|
2752
|
-
{ input: "password", key: "smsSid", credential: "TWILIO_ACCOUNT_SID", label: "Twilio account SID", message: "Twilio console home \u2014 the AC\u2026 identifier on the account dashboard.", redact: true, required: true },
|
|
2753
|
-
{ input: "password", key: "smsToken", credential: "TWILIO_AUTH_TOKEN", label: "Twilio auth token", message: "Beside the account SID on the Twilio console dashboard.", redact: true, required: true }
|
|
2754
|
-
],
|
|
2755
|
-
icon: twilio_default,
|
|
2756
|
-
name: "Twilio"
|
|
2757
|
-
},
|
|
2758
|
-
// The CRM sync is best-effort internal tooling and no-ops without a
|
|
2759
|
-
// token. Not live here costs nothing a merchant can see.
|
|
2760
|
-
hubspot: {
|
|
2761
|
-
fields: [
|
|
2762
|
-
{ input: "password", key: "hubspotToken", credential: "HUBSPOT_ACCESS_TOKEN", label: "HubSpot access token", message: "Drawbridge's own CRM portal. Internal \u2014 no merchant sees this.", redact: true, required: true }
|
|
2763
|
-
],
|
|
2764
|
-
icon: hubspot_default,
|
|
2765
|
-
name: "HubSpot"
|
|
2766
|
-
}
|
|
2767
|
-
}
|
|
2768
|
-
},
|
|
2769
2690
|
// NOTHING, and HUBSPOT_ACCESS_TOKEN in particular must not be here.
|
|
2770
2691
|
//
|
|
2771
2692
|
// `requires` gates AVAILABILITY: a name in it that is unset removes the whole
|
|
@@ -2964,6 +2885,16 @@ var drawbridge_default2 = {
|
|
|
2964
2885
|
}
|
|
2965
2886
|
},
|
|
2966
2887
|
tasks: () => [],
|
|
2888
|
+
// THE VENDORS THIS CONNECTION SPENDS, by slug. Each is declared once in
|
|
2889
|
+
// lib/connections/vendors/, and named here by whoever uses it — the block that
|
|
2890
|
+
// used to sit here declared them inline, so two manifests naming one vendor had
|
|
2891
|
+
// to be reconciled at import by mergeVendors().
|
|
2892
|
+
//
|
|
2893
|
+
// THREE, and they have nothing to do with each other: drawbridge is the
|
|
2894
|
+
// platform's own sender and spends SendGrid for email, Twilio for SMS and
|
|
2895
|
+
// HubSpot for CRM. They were bundled under one manifest only because one
|
|
2896
|
+
// connection happens to use all three.
|
|
2897
|
+
vendors: ["sendgrid", "twilio", "hubspot"],
|
|
2967
2898
|
title: "Drawbridge"
|
|
2968
2899
|
};
|
|
2969
2900
|
|
|
@@ -2981,7 +2912,7 @@ var missingScopes = ({ granted, required }) => {
|
|
|
2981
2912
|
return list(required).filter((scope) => !held.has(scope));
|
|
2982
2913
|
};
|
|
2983
2914
|
|
|
2984
|
-
// lib/connections/
|
|
2915
|
+
// lib/connections/manifests/klaviyo.js
|
|
2985
2916
|
var api2 = async (path, { fetcher = fetch, method = "GET", payload, token }) => {
|
|
2986
2917
|
const response = await fetcher("https://a.klaviyo.com/api" + path, {
|
|
2987
2918
|
...payload && { body: JSON.stringify(payload) },
|
|
@@ -3595,24 +3526,6 @@ var klaviyo_default2 = {
|
|
|
3595
3526
|
webhook: false
|
|
3596
3527
|
},
|
|
3597
3528
|
icon: klaviyo_default,
|
|
3598
|
-
// DRAWBRIDGE'S OWN CREDENTIALS for this vendor, as opposed to a merchant's —
|
|
3599
|
-
// what an admin types on the provider screen. Declared here rather than in a
|
|
3600
|
-
// table in lib/providers.js, so a vendor's credentials sit beside the
|
|
3601
|
-
// `requires` that names the same variables. Keyed by the VENDOR that holds
|
|
3602
|
-
// them — here the vendor and the connection are the same thing, which is not
|
|
3603
|
-
// true of every manifest.
|
|
3604
|
-
provider: {
|
|
3605
|
-
vendors: {
|
|
3606
|
-
klaviyo: {
|
|
3607
|
-
fields: [
|
|
3608
|
-
{ input: "text", key: "clientId", credential: "KLAVIYO_OAUTH_CLIENT_ID", label: "Client ID", message: "From our app in the Klaviyo developer portal (developers.klaviyo.com).", required: true },
|
|
3609
|
-
{ input: "password", key: "clientSecret", credential: "KLAVIYO_OAUTH_CLIENT_SECRET", label: "Client secret", message: "Beside the Client ID on the Klaviyo app.", redact: true, required: true }
|
|
3610
|
-
],
|
|
3611
|
-
icon: klaviyo_default,
|
|
3612
|
-
name: "Klaviyo"
|
|
3613
|
-
}
|
|
3614
|
-
}
|
|
3615
|
-
},
|
|
3616
3529
|
requires: [
|
|
3617
3530
|
"KLAVIYO_OAUTH_CLIENT_ID",
|
|
3618
3531
|
"KLAVIYO_OAUTH_CLIENT_SECRET"
|
|
@@ -3751,6 +3664,11 @@ var klaviyo_default2 = {
|
|
|
3751
3664
|
}]
|
|
3752
3665
|
];
|
|
3753
3666
|
},
|
|
3667
|
+
// THE VENDORS THIS CONNECTION SPENDS, by slug. Each is declared once in
|
|
3668
|
+
// lib/connections/vendors/, and named here by whoever uses it — the block that
|
|
3669
|
+
// used to sit here declared them inline, so two manifests naming one vendor had
|
|
3670
|
+
// to be reconciled at import by mergeVendors().
|
|
3671
|
+
vendors: ["klaviyo"],
|
|
3754
3672
|
title: "Klaviyo",
|
|
3755
3673
|
// KLAVIYO PUBLISHES NO DASHBOARD URLS in its API reference. What is on record
|
|
3756
3674
|
// is its own help centre on a list: "you can find a list's ID in the URL in
|
|
@@ -3764,7 +3682,7 @@ var klaviyo_default2 = {
|
|
|
3764
3682
|
}
|
|
3765
3683
|
};
|
|
3766
3684
|
|
|
3767
|
-
// lib/connections/
|
|
3685
|
+
// lib/connections/manifests/mailchimp.js
|
|
3768
3686
|
var import_node_crypto5 = require("crypto");
|
|
3769
3687
|
|
|
3770
3688
|
// lib/connections/icons/mailchimp.js
|
|
@@ -3774,7 +3692,7 @@ var mailchimp_default = `<svg width="500" height="500" viewBox="0 0 500 500" fil
|
|
|
3774
3692
|
<path d="M360.476 284.243C360.35 283.835 359.618 281.204 358.647 278.052L356.621 272.648C360.575 266.696 360.645 261.405 360.124 258.393C359.531 254.519 357.693 250.944 354.89 248.205C351.766 244.94 345.363 241.563 336.385 239.044L331.671 237.736C331.643 237.524 331.418 226.619 331.235 221.933C331.08 218.555 330.798 213.264 329.152 208.058C327.182 200.993 323.791 194.858 319.527 190.876C331.277 178.717 338.594 165.307 338.58 153.81C338.538 131.703 311.379 124.976 277.902 138.851L270.824 141.863C270.795 141.835 258.004 129.283 257.821 129.128C219.63 95.8334 100.327 228.476 138.49 260.687L146.835 267.737C144.581 273.775 143.781 280.259 144.499 286.664C145.414 295.543 149.973 304.029 157.375 310.6C164.411 316.82 173.684 320.788 182.648 320.774C197.494 354.998 231.408 375.965 271.175 377.161C313.842 378.427 349.641 358.403 364.67 322.435C365.641 319.916 369.806 308.546 369.806 298.513C369.792 288.409 364.093 284.229 360.476 284.243ZM185.913 311.149C184.613 311.381 183.293 311.48 181.973 311.445C169.083 311.079 155.166 299.483 153.787 285.735C152.253 270.537 160.02 258.829 173.783 256.071C175.415 255.72 177.414 255.537 179.552 255.635C187.264 256.085 198.606 261.996 201.209 278.784C203.517 293.63 199.858 308.785 185.913 311.149ZM171.545 246.953C163.179 248.499 155.744 253.244 150.817 260.18C148.045 257.873 142.909 253.426 142.008 251.681C134.635 237.693 150.043 210.478 160.823 195.111C187.405 157.145 229.086 128.424 248.393 133.603C251.517 134.503 261.902 146.563 261.902 146.563C261.902 146.563 242.623 157.244 224.724 172.16C200.646 190.735 182.423 217.697 171.545 246.953ZM306.792 305.464C306.937 305.403 307.057 305.295 307.134 305.157C307.211 305.019 307.239 304.86 307.214 304.704C307.205 304.61 307.178 304.519 307.133 304.436C307.088 304.353 307.027 304.28 306.954 304.221C306.88 304.162 306.796 304.118 306.705 304.092C306.614 304.066 306.519 304.059 306.426 304.071C306.426 304.071 286.246 307.054 267.179 300.089C269.247 293.348 274.792 295.754 283.137 296.444C296.108 297.209 309.116 295.802 321.623 292.279C330.25 289.788 341.592 284.905 350.401 277.953C353.384 284.497 354.425 291.674 354.425 291.674C354.425 291.674 356.719 291.265 358.647 292.447C360.476 293.573 361.799 295.895 360.898 301.89C359.027 313.119 354.271 322.224 346.235 330.611C341.236 336.036 335.277 340.492 328.659 343.754C324.983 345.691 321.151 347.32 317.205 348.623C286.964 358.487 256.006 347.638 246.029 324.321C245.224 322.535 244.556 320.691 244.03 318.804C239.781 303.438 243.383 285.032 254.655 273.408C255.372 272.676 256.09 271.804 256.09 270.706C256.09 269.806 255.499 268.835 255.007 268.131C251.066 262.418 237.374 252.666 240.132 233.795C242.088 220.23 253.951 210.689 265.012 211.252L267.826 211.421C272.611 211.702 276.79 212.307 280.73 212.49C287.344 212.758 293.268 211.801 300.304 205.947C302.683 203.949 304.582 202.246 307.791 201.711C308.128 201.627 308.973 201.359 310.647 201.416C312.365 201.485 314.032 202.015 315.474 202.949C321.103 206.693 321.905 215.783 322.214 222.439C322.383 226.225 322.848 235.414 322.988 238.031C323.354 244.054 324.944 244.912 328.125 245.954C329.94 246.573 331.615 246.995 334.077 247.713C341.521 249.781 345.968 251.934 348.754 254.65C350.198 256.049 351.13 257.893 351.4 259.885C352.315 266.316 346.432 274.252 330.925 281.457C313.954 289.324 293.367 291.322 279.154 289.732L274.173 289.169C262.774 287.649 256.315 302.34 263.14 312.402C267.545 318.889 279.52 323.11 291.523 323.11C319.006 323.139 340.142 311.402 348.023 301.242L348.642 300.356C349.008 299.765 348.712 299.469 348.22 299.779C341.817 304.169 313.279 321.619 282.771 316.384C282.771 316.384 279.056 315.765 275.678 314.442C273.005 313.429 267.362 310.811 266.686 305.042C291.27 312.683 306.792 305.478 306.792 305.464ZM220.671 194.971C230.127 184.051 241.765 174.538 252.206 169.219C252.558 169.022 252.938 169.43 252.741 169.754C251.46 172 250.476 174.403 249.814 176.902C249.73 177.282 250.138 177.592 250.461 177.353C256.963 172.934 268.248 168.192 278.155 167.601C278.251 167.584 278.351 167.601 278.436 167.65C278.521 167.698 278.586 167.775 278.621 167.866C278.656 167.957 278.658 168.058 278.627 168.151C278.596 168.244 278.533 168.323 278.451 168.375C276.809 169.634 275.342 171.105 274.088 172.751C273.891 173.032 274.074 173.44 274.426 173.44C281.378 173.483 291.186 175.903 297.56 179.491C297.982 179.745 297.673 180.575 297.209 180.462C287.527 178.253 271.724 176.564 255.288 180.575C240.597 184.149 229.396 189.666 221.248 195.618C220.826 195.899 220.333 195.351 220.671 194.971Z" fill="#231E15"/>
|
|
3775
3693
|
</svg>`;
|
|
3776
3694
|
|
|
3777
|
-
// lib/connections/
|
|
3695
|
+
// lib/connections/manifests/mailchimp.js
|
|
3778
3696
|
var base = (dc) => {
|
|
3779
3697
|
if (!dc) throw new Error("This Mailchimp connection has no data centre stored, so there is no host to call");
|
|
3780
3698
|
return "https://" + dc + ".api.mailchimp.com/3.0";
|
|
@@ -4172,21 +4090,6 @@ var mailchimp_default2 = {
|
|
|
4172
4090
|
webhook: false
|
|
4173
4091
|
},
|
|
4174
4092
|
icon: mailchimp_default,
|
|
4175
|
-
// DRAWBRIDGE'S OWN CREDENTIALS for this vendor, as opposed to a merchant's —
|
|
4176
|
-
// what an admin types on the provider screen, beside the `requires` naming the
|
|
4177
|
-
// same variables.
|
|
4178
|
-
provider: {
|
|
4179
|
-
vendors: {
|
|
4180
|
-
mailchimp: {
|
|
4181
|
-
fields: [
|
|
4182
|
-
{ input: "text", key: "clientId", credential: "MAILCHIMP_OAUTH_CLIENT_ID", label: "Client ID", message: "From our registered app \u2014 Mailchimp account, Extras, Registered apps.", required: true },
|
|
4183
|
-
{ input: "password", key: "clientSecret", credential: "MAILCHIMP_OAUTH_CLIENT_SECRET", label: "Client secret", message: "Beside the Client ID on the registered app.", redact: true, required: true }
|
|
4184
|
-
],
|
|
4185
|
-
icon: mailchimp_default,
|
|
4186
|
-
name: "Mailchimp"
|
|
4187
|
-
}
|
|
4188
|
-
}
|
|
4189
|
-
},
|
|
4190
4093
|
// The OAuth client this deployment registered. Without both, the vendor drops
|
|
4191
4094
|
// out of availableConnections rather than offering a Connect button that
|
|
4192
4095
|
// cannot complete.
|
|
@@ -4289,6 +4192,11 @@ var mailchimp_default2 = {
|
|
|
4289
4192
|
}
|
|
4290
4193
|
];
|
|
4291
4194
|
},
|
|
4195
|
+
// THE VENDORS THIS CONNECTION SPENDS, by slug. Each is declared once in
|
|
4196
|
+
// lib/connections/vendors/, and named here by whoever uses it — the block that
|
|
4197
|
+
// used to sit here declared them inline, so two manifests naming one vendor had
|
|
4198
|
+
// to be reconciled at import by mergeVendors().
|
|
4199
|
+
vendors: ["mailchimp"],
|
|
4292
4200
|
title: "Mailchimp",
|
|
4293
4201
|
// THE MERCHANT'S OWN ADMIN. Mailchimp's list schema states the shape outright:
|
|
4294
4202
|
// the web_id field is "The ID used in the Mailchimp web application. View this
|
|
@@ -4308,7 +4216,7 @@ var mailchimp_default2 = {
|
|
|
4308
4216
|
}
|
|
4309
4217
|
};
|
|
4310
4218
|
|
|
4311
|
-
// lib/connections/
|
|
4219
|
+
// lib/connections/manifests/shopify.js
|
|
4312
4220
|
var import_node_crypto6 = require("crypto");
|
|
4313
4221
|
var import_nanoid3 = require("nanoid");
|
|
4314
4222
|
|
|
@@ -4390,7 +4298,7 @@ var slugify = (value, nochars = false) => {
|
|
|
4390
4298
|
);
|
|
4391
4299
|
};
|
|
4392
4300
|
|
|
4393
|
-
// lib/connections/
|
|
4301
|
+
// lib/connections/manifests/shopify.js
|
|
4394
4302
|
var toLine = ({
|
|
4395
4303
|
price,
|
|
4396
4304
|
product_id: productId,
|
|
@@ -4881,8 +4789,10 @@ var shopify_default2 = {
|
|
|
4881
4789
|
} : null;
|
|
4882
4790
|
const source = (connection2 == null ? void 0 : connection2.source) ? { domain: connection2.source.domain, id: connection2.source.id } : void 0;
|
|
4883
4791
|
const createsOrder = !backfill && (isConversion || Boolean(discount));
|
|
4884
|
-
const
|
|
4885
|
-
const
|
|
4792
|
+
const mintedOrder = !(existingOrder == null ? void 0 : existingOrder.id) && createsOrder ? mintId() : null;
|
|
4793
|
+
const orderDocId = (existingOrder == null ? void 0 : existingOrder.id) || (mintedOrder == null ? void 0 : mintedOrder.id) || null;
|
|
4794
|
+
const mintedRedemption = discount ? mintId() : null;
|
|
4795
|
+
const redemptionDocId = (mintedRedemption == null ? void 0 : mintedRedemption.id) || null;
|
|
4886
4796
|
const writes = [];
|
|
4887
4797
|
if (createsOrder) {
|
|
4888
4798
|
writes.push({
|
|
@@ -4896,6 +4806,7 @@ var shopify_default2 = {
|
|
|
4896
4806
|
discount,
|
|
4897
4807
|
fee,
|
|
4898
4808
|
gross,
|
|
4809
|
+
_id: mintedOrder == null ? void 0 : mintedOrder._id,
|
|
4899
4810
|
id: orderDocId,
|
|
4900
4811
|
lead: leadId,
|
|
4901
4812
|
lines,
|
|
@@ -4955,6 +4866,7 @@ var shopify_default2 = {
|
|
|
4955
4866
|
customer,
|
|
4956
4867
|
discount,
|
|
4957
4868
|
gross,
|
|
4869
|
+
_id: mintedRedemption == null ? void 0 : mintedRedemption._id,
|
|
4958
4870
|
id: redemptionDocId,
|
|
4959
4871
|
lead: leadId,
|
|
4960
4872
|
order: orderDocId,
|
|
@@ -5075,7 +4987,8 @@ var shopify_default2 = {
|
|
|
5075
4987
|
"source.domain": connection2.shop
|
|
5076
4988
|
};
|
|
5077
4989
|
const existing = (read == null ? void 0 : read.get) ? await read.get({ collection: "product", query }) : null;
|
|
5078
|
-
const
|
|
4990
|
+
const mintedProduct = (existing == null ? void 0 : existing.id) ? null : mintId();
|
|
4991
|
+
const productId = (existing == null ? void 0 : existing.id) || mintedProduct.id;
|
|
5079
4992
|
return {
|
|
5080
4993
|
enqueues: [{
|
|
5081
4994
|
data: { product: productId, providerId, shop: connection2.shop },
|
|
@@ -5097,6 +5010,7 @@ var shopify_default2 = {
|
|
|
5097
5010
|
data: {
|
|
5098
5011
|
$addToSet: { connections: connection2.id },
|
|
5099
5012
|
$setOnInsert: {
|
|
5013
|
+
...mintedProduct && { _id: mintedProduct._id },
|
|
5100
5014
|
id: productId,
|
|
5101
5015
|
provider: { id: providerId, slug: "shopify" },
|
|
5102
5016
|
"source.id": connection2.id,
|
|
@@ -5513,41 +5427,6 @@ var shopify_default2 = {
|
|
|
5513
5427
|
},
|
|
5514
5428
|
icon: shopify_default,
|
|
5515
5429
|
inbound,
|
|
5516
|
-
// DRAWBRIDGE'S OWN CREDENTIALS for this vendor, as opposed to a merchant's —
|
|
5517
|
-
// what an admin types on the provider screen. The four names below are exactly
|
|
5518
|
-
// what `requires` gates on, which is the point of declaring them together: a
|
|
5519
|
-
// name required by the manifest and enterable nowhere is a vendor that can
|
|
5520
|
-
// never go live from the admin screen.
|
|
5521
|
-
provider: {
|
|
5522
|
-
vendors: {
|
|
5523
|
-
shopify: {
|
|
5524
|
-
fields: [
|
|
5525
|
-
{ input: "text", key: "apiKey", credential: "SHOPIFY_API_KEY", label: "API key", message: "The app's Client ID \u2014 Dev Dashboard, the app, Settings.", required: true },
|
|
5526
|
-
{ input: "password", key: "apiSecret", credential: "SHOPIFY_API_SECRET", label: "API secret", message: "The app's Client secret, beside the Client ID in the app's settings.", redact: true, required: true },
|
|
5527
|
-
{ input: "text", key: "appHandle", credential: "SHOPIFY_APP_HANDLE", label: "App handle", message: "The app's URL handle (for example drawbridge-development), from the app's configuration.", required: true },
|
|
5528
|
-
{ input: "text", key: "listingUrl", credential: "SHOPIFY_APP_LISTING_URL", label: "App listing URL", message: 'Where "View on the Shopify App Store" sends merchants \u2014 the public listing, or the Dev Dashboard install link for the dev app.', required: true },
|
|
5529
|
-
// The usage meter's event handle, when the plan config's meter ever
|
|
5530
|
-
// changes: stored value overrides the built-in default
|
|
5531
|
-
// (events.order.handle) at the mint point, and `format : 'slug'`
|
|
5532
|
-
// normalizes it on save — a handle can carry no spaces or capitals,
|
|
5533
|
-
// and classification against it is case-sensitive. Optional: empty
|
|
5534
|
-
// means the default, and the sender still refuses any handle that
|
|
5535
|
-
// disagrees with the transaction it minted.
|
|
5536
|
-
{ format: "slug", input: "text", key: "orderEventHandle", label: "Order event handle", message: "Must match the usage meter's Handle field on the plan exactly \u2014 lowercase and hyphens. Leave empty to use drawbridge-orders.", required: false, setting: true },
|
|
5537
|
-
// The Partner API credential set — the ONE place meter billing is
|
|
5538
|
-
// observable (CHARGE_USAGE accrual events). Org id and numeric app
|
|
5539
|
-
// id come from the Partner Dashboard; the token from Settings →
|
|
5540
|
-
// Partner API clients (Manage-apps permission). All optional: the
|
|
5541
|
-
// accrual probe simply stays off until they exist.
|
|
5542
|
-
{ input: "text", key: "partnerOrgId", label: "Partner organization ID", message: "The number in the Partner Dashboard URL \u2014 partners.shopify.com/<this number>/\u2026 \u2014 NOT the admin organization_id from the app listing link.", required: false, setting: true },
|
|
5543
|
-
{ input: "text", key: "partnerAppId", label: "Partner app ID (numeric)", message: "The numeric id in the app's Partner Dashboard URL \u2014 not the Client ID.", required: false, setting: true },
|
|
5544
|
-
{ input: "password", key: "partnerToken", label: "Partner API token", message: "Partner Dashboard, Settings, Partner API clients \u2014 create one with Manage apps and paste the prtapi_ token.", redact: true, required: false, setting: true }
|
|
5545
|
-
],
|
|
5546
|
-
icon: shopify_default,
|
|
5547
|
-
name: "Shopify"
|
|
5548
|
-
}
|
|
5549
|
-
}
|
|
5550
|
-
},
|
|
5551
5430
|
// A pre-launch integration: it only surfaces once the App Store listing
|
|
5552
5431
|
// exists and the app is fully configured. Requiring all four means it can
|
|
5553
5432
|
// never render half-configured — and absence of any one excludes the
|
|
@@ -5751,6 +5630,13 @@ var shopify_default2 = {
|
|
|
5751
5630
|
] : []
|
|
5752
5631
|
];
|
|
5753
5632
|
},
|
|
5633
|
+
// THE VENDORS THIS CONNECTION SPENDS, by slug. Declared once in
|
|
5634
|
+
// lib/connections/vendors/shopify.js, and named here by whoever uses it.
|
|
5635
|
+
//
|
|
5636
|
+
// SHOPIFY_API_SECRET is spent by drawbridge-shopify-app and drawbridge-webhooks
|
|
5637
|
+
// too, which is the clearest case for why a vendor is not owned by whichever
|
|
5638
|
+
// connection happened to declare it first.
|
|
5639
|
+
vendors: ["shopify"],
|
|
5754
5640
|
title: "Shopify",
|
|
5755
5641
|
// THE VENDOR'S OWN ADMIN, one function per thing worth linking to. It lives
|
|
5756
5642
|
// here rather than at the top level so a second link (a product, an order)
|
|
@@ -5777,7 +5663,7 @@ var shopify_default2 = {
|
|
|
5777
5663
|
}
|
|
5778
5664
|
};
|
|
5779
5665
|
|
|
5780
|
-
// lib/connections/
|
|
5666
|
+
// lib/connections/manifests/webhook.js
|
|
5781
5667
|
var import_node_crypto7 = __toESM(require("crypto"), 1);
|
|
5782
5668
|
|
|
5783
5669
|
// lib/safe-http.js
|
|
@@ -5922,7 +5808,7 @@ var safeRequest = async ({
|
|
|
5922
5808
|
}
|
|
5923
5809
|
};
|
|
5924
5810
|
|
|
5925
|
-
// lib/connections/
|
|
5811
|
+
// lib/connections/manifests/webhook.js
|
|
5926
5812
|
var RESPONSE_LIMIT = 64 * 1024;
|
|
5927
5813
|
var signature = ({ body, settings }) => {
|
|
5928
5814
|
var _a;
|
|
@@ -6112,9 +5998,369 @@ var webhook_default = {
|
|
|
6112
5998
|
title: "Webhook signing"
|
|
6113
5999
|
}
|
|
6114
6000
|
],
|
|
6001
|
+
// THE VENDORS THIS CONNECTION SPENDS, by slug. Each is declared once in
|
|
6002
|
+
// lib/connections/vendors/, and named here by whoever uses it — the block that
|
|
6003
|
+
// used to sit here declared them inline, so two manifests naming one vendor had
|
|
6004
|
+
// to be reconciled at import by mergeVendors().
|
|
6005
|
+
//
|
|
6006
|
+
// Empty: webhook has no third party behind it — nothing to authenticate
|
|
6007
|
+
// against and nothing for an admin to type.
|
|
6008
|
+
vendors: [],
|
|
6115
6009
|
title: "Webhooks"
|
|
6116
6010
|
};
|
|
6117
6011
|
|
|
6012
|
+
// lib/connections/vendors/attentive.js
|
|
6013
|
+
var attentive_default3 = {
|
|
6014
|
+
// WHAT AN ADMIN TYPES on the provider screen. `credential` names the env var a
|
|
6015
|
+
// field falls back to, and is the only place that name is written now — it used
|
|
6016
|
+
// to appear three times per manifest.
|
|
6017
|
+
fields: [
|
|
6018
|
+
{
|
|
6019
|
+
credential: "ATTENTIVE_OAUTH_CLIENT_ID",
|
|
6020
|
+
input: "text",
|
|
6021
|
+
key: "clientId",
|
|
6022
|
+
label: "Client ID",
|
|
6023
|
+
message: "From our app's registration in the Attentive developer portal.",
|
|
6024
|
+
required: true
|
|
6025
|
+
},
|
|
6026
|
+
{
|
|
6027
|
+
credential: "ATTENTIVE_OAUTH_CLIENT_SECRET",
|
|
6028
|
+
input: "password",
|
|
6029
|
+
key: "clientSecret",
|
|
6030
|
+
label: "Client secret",
|
|
6031
|
+
message: "Beside the Client ID in the Attentive developer portal.",
|
|
6032
|
+
redact: true,
|
|
6033
|
+
required: true
|
|
6034
|
+
}
|
|
6035
|
+
],
|
|
6036
|
+
// The same mark the connection carries. One vendor, one icon — mergeVendors
|
|
6037
|
+
// used to throw when two manifests disagreed about this.
|
|
6038
|
+
icon: attentive_default,
|
|
6039
|
+
name: "Attentive",
|
|
6040
|
+
slug: "attentive",
|
|
6041
|
+
// WHERE THE FACTS CAME FROM. Was review.api / .dashboard / .scopes on the
|
|
6042
|
+
// manifest. They are per-vendor documentation, which is exactly why drawbridge
|
|
6043
|
+
// answered two of them with an object keyed by vendor while the other four
|
|
6044
|
+
// answered with a string — two incompatible shapes for one key, and the shape
|
|
6045
|
+
// was saying where the data belonged.
|
|
6046
|
+
urls: {
|
|
6047
|
+
api: "https://docs.attentive.com/reference/listsegments",
|
|
6048
|
+
dashboard: "https://docs.attentive.com/docs/segments",
|
|
6049
|
+
scopes: "https://docs.attentive.com/docs/authentication"
|
|
6050
|
+
}
|
|
6051
|
+
};
|
|
6052
|
+
|
|
6053
|
+
// lib/connections/vendors/hubspot.js
|
|
6054
|
+
var hubspot_default2 = {
|
|
6055
|
+
// WHAT AN ADMIN TYPES on the provider screen. `credential` names the env var a
|
|
6056
|
+
// field falls back to, and is the only place that name is written now — it used
|
|
6057
|
+
// to appear three times per manifest.
|
|
6058
|
+
fields: [
|
|
6059
|
+
{
|
|
6060
|
+
credential: "HUBSPOT_ACCESS_TOKEN",
|
|
6061
|
+
input: "password",
|
|
6062
|
+
key: "hubspotToken",
|
|
6063
|
+
label: "HubSpot access token",
|
|
6064
|
+
message: "Drawbridge's own CRM portal. Internal \u2014 no merchant sees this.",
|
|
6065
|
+
redact: true,
|
|
6066
|
+
required: true
|
|
6067
|
+
}
|
|
6068
|
+
],
|
|
6069
|
+
// The vendor's own mark rather than the connection's: drawbridge fronts three
|
|
6070
|
+
// vendors and none of them is Drawbridge.
|
|
6071
|
+
icon: hubspot_default,
|
|
6072
|
+
name: "HubSpot",
|
|
6073
|
+
slug: "hubspot",
|
|
6074
|
+
// WHERE THE FACTS CAME FROM. Was review.api / .dashboard / .scopes on the
|
|
6075
|
+
// manifest. They are per-vendor documentation, which is exactly why drawbridge
|
|
6076
|
+
// answered two of them with an object keyed by vendor while the other four
|
|
6077
|
+
// answered with a string — two incompatible shapes for one key, and the shape
|
|
6078
|
+
// was saying where the data belonged.
|
|
6079
|
+
urls: {
|
|
6080
|
+
api: "https://developers.hubspot.com/docs/reference/api/crm/objects/contacts",
|
|
6081
|
+
dashboard: "https://knowledge.hubspot.com/contacts/create-contacts",
|
|
6082
|
+
scopes: false
|
|
6083
|
+
}
|
|
6084
|
+
};
|
|
6085
|
+
|
|
6086
|
+
// lib/connections/vendors/klaviyo.js
|
|
6087
|
+
var klaviyo_default3 = {
|
|
6088
|
+
// WHAT AN ADMIN TYPES on the provider screen. `credential` names the env var a
|
|
6089
|
+
// field falls back to, and is the only place that name is written now — it used
|
|
6090
|
+
// to appear three times per manifest.
|
|
6091
|
+
fields: [
|
|
6092
|
+
{
|
|
6093
|
+
credential: "KLAVIYO_OAUTH_CLIENT_ID",
|
|
6094
|
+
input: "text",
|
|
6095
|
+
key: "clientId",
|
|
6096
|
+
label: "Client ID",
|
|
6097
|
+
message: "From our app in the Klaviyo developer portal (developers.klaviyo.com).",
|
|
6098
|
+
required: true
|
|
6099
|
+
},
|
|
6100
|
+
{
|
|
6101
|
+
credential: "KLAVIYO_OAUTH_CLIENT_SECRET",
|
|
6102
|
+
input: "password",
|
|
6103
|
+
key: "clientSecret",
|
|
6104
|
+
label: "Client secret",
|
|
6105
|
+
message: "Beside the Client ID on the Klaviyo app.",
|
|
6106
|
+
redact: true,
|
|
6107
|
+
required: true
|
|
6108
|
+
}
|
|
6109
|
+
],
|
|
6110
|
+
// The same mark the connection carries. One vendor, one icon — mergeVendors
|
|
6111
|
+
// used to throw when two manifests disagreed about this.
|
|
6112
|
+
icon: klaviyo_default,
|
|
6113
|
+
name: "Klaviyo",
|
|
6114
|
+
slug: "klaviyo",
|
|
6115
|
+
// WHERE THE FACTS CAME FROM. Was review.api / .dashboard / .scopes on the
|
|
6116
|
+
// manifest. They are per-vendor documentation, which is exactly why drawbridge
|
|
6117
|
+
// answered two of them with an object keyed by vendor while the other four
|
|
6118
|
+
// answered with a string — two incompatible shapes for one key, and the shape
|
|
6119
|
+
// was saying where the data belonged.
|
|
6120
|
+
urls: {
|
|
6121
|
+
api: "https://developers.klaviyo.com/en/reference/api_overview",
|
|
6122
|
+
dashboard: "https://help.klaviyo.com/hc/en-us/articles/115005078647",
|
|
6123
|
+
scopes: "https://developers.klaviyo.com/en/docs/authenticate_"
|
|
6124
|
+
}
|
|
6125
|
+
};
|
|
6126
|
+
|
|
6127
|
+
// lib/connections/vendors/mailchimp.js
|
|
6128
|
+
var mailchimp_default3 = {
|
|
6129
|
+
// WHAT AN ADMIN TYPES on the provider screen. `credential` names the env var a
|
|
6130
|
+
// field falls back to, and is the only place that name is written now — it used
|
|
6131
|
+
// to appear three times per manifest.
|
|
6132
|
+
fields: [
|
|
6133
|
+
{
|
|
6134
|
+
credential: "MAILCHIMP_OAUTH_CLIENT_ID",
|
|
6135
|
+
input: "text",
|
|
6136
|
+
key: "clientId",
|
|
6137
|
+
label: "Client ID",
|
|
6138
|
+
message: "From our registered app \u2014 Mailchimp account, Extras, Registered apps.",
|
|
6139
|
+
required: true
|
|
6140
|
+
},
|
|
6141
|
+
{
|
|
6142
|
+
credential: "MAILCHIMP_OAUTH_CLIENT_SECRET",
|
|
6143
|
+
input: "password",
|
|
6144
|
+
key: "clientSecret",
|
|
6145
|
+
label: "Client secret",
|
|
6146
|
+
message: "Beside the Client ID on the registered app.",
|
|
6147
|
+
redact: true,
|
|
6148
|
+
required: true
|
|
6149
|
+
}
|
|
6150
|
+
],
|
|
6151
|
+
// The same mark the connection carries. One vendor, one icon — mergeVendors
|
|
6152
|
+
// used to throw when two manifests disagreed about this.
|
|
6153
|
+
icon: mailchimp_default,
|
|
6154
|
+
name: "Mailchimp",
|
|
6155
|
+
slug: "mailchimp",
|
|
6156
|
+
// WHERE THE FACTS CAME FROM. Was review.api / .dashboard / .scopes on the
|
|
6157
|
+
// manifest. They are per-vendor documentation, which is exactly why drawbridge
|
|
6158
|
+
// answered two of them with an object keyed by vendor while the other four
|
|
6159
|
+
// answered with a string — two incompatible shapes for one key, and the shape
|
|
6160
|
+
// was saying where the data belonged.
|
|
6161
|
+
urls: {
|
|
6162
|
+
api: "https://mailchimp.com/developer/marketing/guides/access-user-data-oauth-2/",
|
|
6163
|
+
dashboard: "https://mailchimp.com/help/manage-tags/",
|
|
6164
|
+
scopes: false
|
|
6165
|
+
}
|
|
6166
|
+
};
|
|
6167
|
+
|
|
6168
|
+
// lib/connections/vendors/sendgrid.js
|
|
6169
|
+
var sendgrid_default2 = {
|
|
6170
|
+
// WHAT AN ADMIN TYPES on the provider screen. `credential` names the env var a
|
|
6171
|
+
// field falls back to, and is the only place that name is written now — it used
|
|
6172
|
+
// to appear three times per manifest.
|
|
6173
|
+
fields: [
|
|
6174
|
+
{
|
|
6175
|
+
credential: "SENDGRID_FROM_ADDRESS",
|
|
6176
|
+
input: "email",
|
|
6177
|
+
key: "accountSender",
|
|
6178
|
+
label: "Account sender",
|
|
6179
|
+
message: "Verification codes and security alerts send from here.",
|
|
6180
|
+
required: true
|
|
6181
|
+
},
|
|
6182
|
+
{
|
|
6183
|
+
credential: "SENDGRID_API_KEY",
|
|
6184
|
+
input: "password",
|
|
6185
|
+
key: "apiKey",
|
|
6186
|
+
label: "SendGrid API key",
|
|
6187
|
+
message: "SendGrid dashboard, Settings, API Keys \u2014 full access for sends.",
|
|
6188
|
+
redact: true,
|
|
6189
|
+
required: true
|
|
6190
|
+
},
|
|
6191
|
+
{
|
|
6192
|
+
credential: "SENDGRID_EVENT_WEBHOOK_KEY",
|
|
6193
|
+
input: "text",
|
|
6194
|
+
key: "eventKey",
|
|
6195
|
+
label: "Event webhook key",
|
|
6196
|
+
message: "SendGrid, Settings, Mail Settings, Event Webhook \u2014 the verification key shown once signature verification is enabled. Public, not a secret."
|
|
6197
|
+
},
|
|
6198
|
+
{
|
|
6199
|
+
credential: "SENDGRID_SEND_FROM_ADDRESS",
|
|
6200
|
+
input: "email",
|
|
6201
|
+
key: "leadSender",
|
|
6202
|
+
label: "Lead sender",
|
|
6203
|
+
message: "The default for lead-facing mail when a merchant has not verified their own domain."
|
|
6204
|
+
}
|
|
6205
|
+
],
|
|
6206
|
+
// The vendor's own mark rather than the connection's: drawbridge fronts three
|
|
6207
|
+
// vendors and none of them is Drawbridge.
|
|
6208
|
+
icon: sendgrid_default,
|
|
6209
|
+
name: "SendGrid",
|
|
6210
|
+
slug: "sendgrid",
|
|
6211
|
+
// WHERE THE FACTS CAME FROM. Was review.api / .dashboard / .scopes on the
|
|
6212
|
+
// manifest. They are per-vendor documentation, which is exactly why drawbridge
|
|
6213
|
+
// answered two of them with an object keyed by vendor while the other four
|
|
6214
|
+
// answered with a string — two incompatible shapes for one key, and the shape
|
|
6215
|
+
// was saying where the data belonged.
|
|
6216
|
+
urls: {
|
|
6217
|
+
api: "https://www.twilio.com/docs/sendgrid/api-reference/mail-send/mail-send",
|
|
6218
|
+
dashboard: "https://www.twilio.com/docs/sendgrid/ui/analytics-and-reporting/email-activity-feed",
|
|
6219
|
+
scopes: false
|
|
6220
|
+
}
|
|
6221
|
+
};
|
|
6222
|
+
|
|
6223
|
+
// lib/connections/vendors/shopify.js
|
|
6224
|
+
var shopify_default3 = {
|
|
6225
|
+
// WHAT AN ADMIN TYPES on the provider screen. `credential` names the env var a
|
|
6226
|
+
// field falls back to, and is the only place that name is written now — it used
|
|
6227
|
+
// to appear three times per manifest.
|
|
6228
|
+
fields: [
|
|
6229
|
+
{
|
|
6230
|
+
credential: "SHOPIFY_API_KEY",
|
|
6231
|
+
input: "text",
|
|
6232
|
+
key: "apiKey",
|
|
6233
|
+
label: "API key",
|
|
6234
|
+
message: "The app's Client ID \u2014 Dev Dashboard, the app, Settings.",
|
|
6235
|
+
required: true
|
|
6236
|
+
},
|
|
6237
|
+
{
|
|
6238
|
+
credential: "SHOPIFY_API_SECRET",
|
|
6239
|
+
input: "password",
|
|
6240
|
+
key: "apiSecret",
|
|
6241
|
+
label: "API secret",
|
|
6242
|
+
message: "The app's Client secret, beside the Client ID in the app's settings.",
|
|
6243
|
+
redact: true,
|
|
6244
|
+
required: true
|
|
6245
|
+
},
|
|
6246
|
+
{
|
|
6247
|
+
credential: "SHOPIFY_APP_HANDLE",
|
|
6248
|
+
input: "text",
|
|
6249
|
+
key: "appHandle",
|
|
6250
|
+
label: "App handle",
|
|
6251
|
+
message: "The app's URL handle (for example drawbridge-development), from the app's configuration.",
|
|
6252
|
+
required: true
|
|
6253
|
+
},
|
|
6254
|
+
{
|
|
6255
|
+
credential: "SHOPIFY_APP_LISTING_URL",
|
|
6256
|
+
input: "text",
|
|
6257
|
+
key: "listingUrl",
|
|
6258
|
+
label: "App listing URL",
|
|
6259
|
+
message: 'Where "View on the Shopify App Store" sends merchants \u2014 the public listing, or the Dev Dashboard install link for the dev app.',
|
|
6260
|
+
required: true
|
|
6261
|
+
},
|
|
6262
|
+
{
|
|
6263
|
+
format: "slug",
|
|
6264
|
+
input: "text",
|
|
6265
|
+
key: "orderEventHandle",
|
|
6266
|
+
label: "Order event handle",
|
|
6267
|
+
message: "Must match the usage meter's Handle field on the plan exactly \u2014 lowercase and hyphens. Leave empty to use drawbridge-orders.",
|
|
6268
|
+
required: false,
|
|
6269
|
+
setting: true
|
|
6270
|
+
},
|
|
6271
|
+
{
|
|
6272
|
+
input: "text",
|
|
6273
|
+
key: "partnerOrgId",
|
|
6274
|
+
label: "Partner organization ID",
|
|
6275
|
+
message: "The number in the Partner Dashboard URL \u2014 partners.shopify.com/<this number>/\u2026 \u2014 NOT the admin organization_id from the app listing link.",
|
|
6276
|
+
required: false,
|
|
6277
|
+
setting: true
|
|
6278
|
+
},
|
|
6279
|
+
{
|
|
6280
|
+
input: "text",
|
|
6281
|
+
key: "partnerAppId",
|
|
6282
|
+
label: "Partner app ID (numeric)",
|
|
6283
|
+
message: "The numeric id in the app's Partner Dashboard URL \u2014 not the Client ID.",
|
|
6284
|
+
required: false,
|
|
6285
|
+
setting: true
|
|
6286
|
+
},
|
|
6287
|
+
{
|
|
6288
|
+
input: "password",
|
|
6289
|
+
key: "partnerToken",
|
|
6290
|
+
label: "Partner API token",
|
|
6291
|
+
message: "Partner Dashboard, Settings, Partner API clients \u2014 create one with Manage apps and paste the prtapi_ token.",
|
|
6292
|
+
redact: true,
|
|
6293
|
+
required: false,
|
|
6294
|
+
setting: true
|
|
6295
|
+
}
|
|
6296
|
+
],
|
|
6297
|
+
// The same mark the connection carries. One vendor, one icon — mergeVendors
|
|
6298
|
+
// used to throw when two manifests disagreed about this.
|
|
6299
|
+
icon: shopify_default,
|
|
6300
|
+
name: "Shopify",
|
|
6301
|
+
slug: "shopify",
|
|
6302
|
+
// WHERE THE FACTS CAME FROM. Was review.api / .dashboard / .scopes on the
|
|
6303
|
+
// manifest. They are per-vendor documentation, which is exactly why drawbridge
|
|
6304
|
+
// answered two of them with an object keyed by vendor while the other four
|
|
6305
|
+
// answered with a string — two incompatible shapes for one key, and the shape
|
|
6306
|
+
// was saying where the data belonged.
|
|
6307
|
+
urls: {
|
|
6308
|
+
api: "https://shopify.dev/docs/api/admin-graphql",
|
|
6309
|
+
dashboard: "https://help.shopify.com/en/manual/apps",
|
|
6310
|
+
scopes: "https://shopify.dev/docs/api/usage/access-scopes"
|
|
6311
|
+
}
|
|
6312
|
+
};
|
|
6313
|
+
|
|
6314
|
+
// lib/connections/vendors/twilio.js
|
|
6315
|
+
var twilio_default2 = {
|
|
6316
|
+
// WHAT AN ADMIN TYPES on the provider screen. `credential` names the env var a
|
|
6317
|
+
// field falls back to, and is the only place that name is written now — it used
|
|
6318
|
+
// to appear three times per manifest.
|
|
6319
|
+
fields: [
|
|
6320
|
+
{
|
|
6321
|
+
credential: "TWILIO_ACCOUNT_FROM",
|
|
6322
|
+
input: "text",
|
|
6323
|
+
key: "smsFrom",
|
|
6324
|
+
label: "SMS number",
|
|
6325
|
+
message: "Without Twilio credentials, SMS is disabled across the platform.",
|
|
6326
|
+
required: true
|
|
6327
|
+
},
|
|
6328
|
+
{
|
|
6329
|
+
credential: "TWILIO_ACCOUNT_SID",
|
|
6330
|
+
input: "password",
|
|
6331
|
+
key: "smsSid",
|
|
6332
|
+
label: "Twilio account SID",
|
|
6333
|
+
message: "Twilio console home \u2014 the AC\u2026 identifier on the account dashboard.",
|
|
6334
|
+
redact: true,
|
|
6335
|
+
required: true
|
|
6336
|
+
},
|
|
6337
|
+
{
|
|
6338
|
+
credential: "TWILIO_AUTH_TOKEN",
|
|
6339
|
+
input: "password",
|
|
6340
|
+
key: "smsToken",
|
|
6341
|
+
label: "Twilio auth token",
|
|
6342
|
+
message: "Beside the account SID on the Twilio console dashboard.",
|
|
6343
|
+
redact: true,
|
|
6344
|
+
required: true
|
|
6345
|
+
}
|
|
6346
|
+
],
|
|
6347
|
+
// The vendor's own mark rather than the connection's: drawbridge fronts three
|
|
6348
|
+
// vendors and none of them is Drawbridge.
|
|
6349
|
+
icon: twilio_default,
|
|
6350
|
+
name: "Twilio",
|
|
6351
|
+
slug: "twilio",
|
|
6352
|
+
// WHERE THE FACTS CAME FROM. Was review.api / .dashboard / .scopes on the
|
|
6353
|
+
// manifest. They are per-vendor documentation, which is exactly why drawbridge
|
|
6354
|
+
// answered two of them with an object keyed by vendor while the other four
|
|
6355
|
+
// answered with a string — two incompatible shapes for one key, and the shape
|
|
6356
|
+
// was saying where the data belonged.
|
|
6357
|
+
urls: {
|
|
6358
|
+
api: "https://www.twilio.com/docs/messaging/api/message-resource",
|
|
6359
|
+
dashboard: "https://www.twilio.com/docs/messaging/guides/debugging-tools",
|
|
6360
|
+
scopes: false
|
|
6361
|
+
}
|
|
6362
|
+
};
|
|
6363
|
+
|
|
6118
6364
|
// lib/connections/index.js
|
|
6119
6365
|
var QUEUES = ["connection", "notification", "segment", "webhook"];
|
|
6120
6366
|
var implemented = (hooks, path) => {
|
|
@@ -6135,8 +6381,35 @@ var checkIcon = (owner, icon) => {
|
|
|
6135
6381
|
throw new Error(owner + " icon wraps a raster \u2014 re-export it as vector shapes");
|
|
6136
6382
|
}
|
|
6137
6383
|
};
|
|
6384
|
+
var vendors = Object.freeze(Object.fromEntries(
|
|
6385
|
+
[attentive_default3, hubspot_default2, klaviyo_default3, mailchimp_default3, sendgrid_default2, shopify_default3, twilio_default2].map((vendor) => [vendor.slug, vendor])
|
|
6386
|
+
));
|
|
6387
|
+
var buildVendor = (vendor) => {
|
|
6388
|
+
if (!(vendor == null ? void 0 : vendor.slug)) throw new Error("A vendor needs a slug");
|
|
6389
|
+
if (!vendor.name) throw new Error("vendor " + vendor.slug + " has no name");
|
|
6390
|
+
checkIcon("vendor " + vendor.slug, vendor.icon);
|
|
6391
|
+
if (!Array.isArray(vendor.fields) || !vendor.fields.length) {
|
|
6392
|
+
throw new Error("vendor " + vendor.slug + " has no fields \u2014 a vendor nothing is typed into holds nothing");
|
|
6393
|
+
}
|
|
6394
|
+
for (const field2 of vendor.fields) {
|
|
6395
|
+
if (!(field2 == null ? void 0 : field2.key) || !(field2 == null ? void 0 : field2.label)) {
|
|
6396
|
+
throw new Error("vendor " + vendor.slug + " declares a field with no key or label");
|
|
6397
|
+
}
|
|
6398
|
+
if (!INPUTS.includes(field2.input)) {
|
|
6399
|
+
throw new Error(vendor.slug + "." + field2.key + " needs an input the admin form can render \u2014 one of " + INPUTS.join(", "));
|
|
6400
|
+
}
|
|
6401
|
+
if (field2.input === "password" && !field2.redact) {
|
|
6402
|
+
throw new Error(vendor.slug + "." + field2.key + " is a password and must declare redact : true \u2014 the api would hand the value back");
|
|
6403
|
+
}
|
|
6404
|
+
}
|
|
6405
|
+
return Object.freeze(vendor);
|
|
6406
|
+
};
|
|
6407
|
+
for (const [slug2, vendor] of Object.entries(vendors)) {
|
|
6408
|
+
if (vendor.slug !== slug2) throw new Error("vendor file " + slug2 + " declares slug " + vendor.slug);
|
|
6409
|
+
buildVendor(vendor);
|
|
6410
|
+
}
|
|
6138
6411
|
var build = (manifest) => {
|
|
6139
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s
|
|
6412
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s;
|
|
6140
6413
|
if (!(manifest == null ? void 0 : manifest.slug)) throw new Error("A connection needs a slug");
|
|
6141
6414
|
if (!(manifest == null ? void 0 : manifest.title)) throw new Error(manifest.slug + " needs a title");
|
|
6142
6415
|
if (!(manifest == null ? void 0 : manifest.private) && !(manifest == null ? void 0 : manifest.feature)) throw new Error(manifest.slug + " needs a plan feature key");
|
|
@@ -6166,53 +6439,42 @@ var build = (manifest) => {
|
|
|
6166
6439
|
}
|
|
6167
6440
|
}
|
|
6168
6441
|
}
|
|
6169
|
-
|
|
6170
|
-
|
|
6442
|
+
checkIcon(manifest.slug, manifest == null ? void 0 : manifest.icon);
|
|
6443
|
+
if (!Array.isArray(manifest.vendors)) {
|
|
6444
|
+
throw new Error(manifest.slug + " must declare vendors \u2014 an array of vendor slugs, empty when it spends none");
|
|
6171
6445
|
}
|
|
6172
6446
|
const declaredKeys = /* @__PURE__ */ new Set();
|
|
6173
|
-
for (const
|
|
6174
|
-
if (!(
|
|
6175
|
-
|
|
6176
|
-
if (!Array.isArray(declared.fields) || !declared.fields.length) {
|
|
6177
|
-
throw new Error(manifest.slug + " declares vendor " + vendor + " with no fields \u2014 a vendor nothing is typed into holds nothing");
|
|
6447
|
+
for (const slug2 of manifest.vendors) {
|
|
6448
|
+
if (!Object.hasOwn(vendors, slug2)) {
|
|
6449
|
+
throw new Error(manifest.slug + " spends vendor " + slug2 + ", which has no file in lib/connections/vendors");
|
|
6178
6450
|
}
|
|
6179
|
-
for (const field2 of
|
|
6180
|
-
if (!(field2 == null ? void 0 : field2.key) || !(field2 == null ? void 0 : field2.label)) {
|
|
6181
|
-
throw new Error(manifest.slug + " declares a provider field with no key or label");
|
|
6182
|
-
}
|
|
6183
|
-
if (!INPUTS.includes(field2.input)) {
|
|
6184
|
-
throw new Error(manifest.slug + ".provider." + field2.key + " needs an input the admin form can render \u2014 one of " + INPUTS.join(", "));
|
|
6185
|
-
}
|
|
6186
|
-
if (field2.input === "password" && !field2.redact) {
|
|
6187
|
-
throw new Error(manifest.slug + ".provider." + field2.key + " is a password and must declare redact : true \u2014 the api would hand the value back");
|
|
6188
|
-
}
|
|
6451
|
+
for (const field2 of vendors[slug2].fields) {
|
|
6189
6452
|
if (declaredKeys.has(field2.key)) {
|
|
6190
|
-
throw new Error(manifest.slug + "
|
|
6453
|
+
throw new Error(manifest.slug + " spends " + field2.key + " under two vendors \u2014 vendorSettings() merges them and one would win");
|
|
6191
6454
|
}
|
|
6192
6455
|
declaredKeys.add(field2.key);
|
|
6193
6456
|
}
|
|
6194
6457
|
}
|
|
6195
|
-
checkIcon(manifest.slug, manifest == null ? void 0 : manifest.icon);
|
|
6196
6458
|
if (!GROUPS.includes(manifest == null ? void 0 : manifest.group)) {
|
|
6197
6459
|
throw new Error(manifest.slug + " needs a group \u2014 one of " + GROUPS.join(", "));
|
|
6198
6460
|
}
|
|
6199
|
-
if ((
|
|
6461
|
+
if ((_c = manifest == null ? void 0 : manifest.connect) == null ? void 0 : _c.type) {
|
|
6200
6462
|
throw new Error(manifest.slug + " declares connect.type \u2014 that is auth.type now");
|
|
6201
6463
|
}
|
|
6202
|
-
if (!AUTH_TYPES.includes((
|
|
6464
|
+
if (!AUTH_TYPES.includes((_d = manifest == null ? void 0 : manifest.auth) == null ? void 0 : _d.type)) {
|
|
6203
6465
|
throw new Error(manifest.slug + " needs auth.type \u2014 one of " + AUTH_TYPES.join(", "));
|
|
6204
6466
|
}
|
|
6205
6467
|
if (manifest.auth.type === "oauth") {
|
|
6206
6468
|
for (const field2 of OAUTH_FIELDS) {
|
|
6207
|
-
if (!((
|
|
6469
|
+
if (!((_e = manifest.auth.oauth) == null ? void 0 : _e[field2])) {
|
|
6208
6470
|
throw new Error(manifest.slug + " is oauth and must declare auth.oauth." + field2);
|
|
6209
6471
|
}
|
|
6210
6472
|
}
|
|
6211
|
-
if (typeof ((
|
|
6473
|
+
if (typeof ((_g = (_f = manifest.hooks) == null ? void 0 : _f.auth) == null ? void 0 : _g.token) !== "function") {
|
|
6212
6474
|
throw new Error(manifest.slug + " is oauth and must implement hooks.auth.token \u2014 point it at authToken() or wrap it");
|
|
6213
6475
|
}
|
|
6214
6476
|
for (const url of OAUTH_URLS) {
|
|
6215
|
-
if (!((
|
|
6477
|
+
if (!((_i = (_h = manifest.auth.oauth) == null ? void 0 : _h.urls) == null ? void 0 : _i[url])) {
|
|
6216
6478
|
throw new Error(manifest.slug + " is oauth and must declare auth.oauth.urls." + url);
|
|
6217
6479
|
}
|
|
6218
6480
|
}
|
|
@@ -6222,16 +6484,16 @@ var build = (manifest) => {
|
|
|
6222
6484
|
);
|
|
6223
6485
|
}
|
|
6224
6486
|
}
|
|
6225
|
-
if (implemented(manifest.hooks, "inbound.event") && typeof ((
|
|
6487
|
+
if (implemented(manifest.hooks, "inbound.event") && typeof ((_k = (_j = manifest.hooks) == null ? void 0 : _j.inbound) == null ? void 0 : _k.event) !== "function" && !((_m = (_l = manifest.inbound) == null ? void 0 : _l.headers) == null ? void 0 : _m.event)) {
|
|
6226
6488
|
throw new Error(manifest.slug + " implements inbound.event but declares no inbound.headers.event");
|
|
6227
6489
|
}
|
|
6228
|
-
if (implemented(manifest.hooks, "inbound.verify") && !((
|
|
6490
|
+
if (implemented(manifest.hooks, "inbound.verify") && !((_o = (_n = manifest.inbound) == null ? void 0 : _n.headers) == null ? void 0 : _o.signature)) {
|
|
6229
6491
|
throw new Error(manifest.slug + " implements inbound.verify but declares no inbound.headers.signature");
|
|
6230
6492
|
}
|
|
6231
6493
|
if (typeof (manifest == null ? void 0 : manifest.status) !== "function") {
|
|
6232
6494
|
throw new Error(manifest.slug + " must declare status( data ) \u2014 return null to accept the connection's own status, or { message, status } to override it");
|
|
6233
6495
|
}
|
|
6234
|
-
if (!Array.isArray((
|
|
6496
|
+
if (!Array.isArray((_p = manifest == null ? void 0 : manifest.content) == null ? void 0 : _p.guide) || !manifest.content.guide.length) {
|
|
6235
6497
|
throw new Error(manifest.slug + " needs content.guide \u2014 an array of steps for its page");
|
|
6236
6498
|
}
|
|
6237
6499
|
if (typeof (manifest == null ? void 0 : manifest.status) !== "function") {
|
|
@@ -6243,8 +6505,8 @@ var build = (manifest) => {
|
|
|
6243
6505
|
}
|
|
6244
6506
|
for (const [domain, verbs] of Object.entries(HOOKS)) {
|
|
6245
6507
|
for (const verb of verbs) {
|
|
6246
|
-
const hook = (
|
|
6247
|
-
if (((
|
|
6508
|
+
const hook = (_r = (_q = manifest.hooks) == null ? void 0 : _q[domain]) == null ? void 0 : _r[verb];
|
|
6509
|
+
if (((_s = manifest.hooks) == null ? void 0 : _s[domain]) === false) continue;
|
|
6248
6510
|
if (hook !== false && !implemented({ [domain]: { [verb]: hook } }, domain + "." + verb)) {
|
|
6249
6511
|
throw new Error(manifest.slug + " must answer hooks." + domain + "." + verb + " \u2014 false, a function, or {} if another repo implements it");
|
|
6250
6512
|
}
|
|
@@ -6289,44 +6551,6 @@ var connections = Object.freeze({
|
|
|
6289
6551
|
shopify: build(shopify_default2),
|
|
6290
6552
|
webhook: build(webhook_default)
|
|
6291
6553
|
});
|
|
6292
|
-
var canonical = (field2) => JSON.stringify(Object.fromEntries(Object.entries(field2).sort()));
|
|
6293
|
-
var mergeVendors = (catalog) => {
|
|
6294
|
-
var _a;
|
|
6295
|
-
const merged = {};
|
|
6296
|
-
const claimed = /* @__PURE__ */ new Map();
|
|
6297
|
-
for (const [slug2, manifest] of Object.entries(catalog)) {
|
|
6298
|
-
for (const [vendor, declared] of Object.entries(((_a = manifest.provider) == null ? void 0 : _a.vendors) || {})) {
|
|
6299
|
-
const held = merged[vendor] || (merged[vendor] = { fields: [], icon: declared.icon, name: declared.name });
|
|
6300
|
-
if (held.name !== declared.name) {
|
|
6301
|
-
throw new Error(slug2 + " names vendor " + vendor + ' "' + declared.name + '" but another manifest names it "' + held.name + '"');
|
|
6302
|
-
}
|
|
6303
|
-
if (held.icon !== declared.icon) {
|
|
6304
|
-
throw new Error(slug2 + " declares a different icon for vendor " + vendor + " than another manifest \u2014 one vendor, one mark");
|
|
6305
|
-
}
|
|
6306
|
-
for (const field2 of declared.fields) {
|
|
6307
|
-
const existing = held.fields.find((entry) => entry.key === field2.key);
|
|
6308
|
-
if (existing) {
|
|
6309
|
-
if (canonical(existing) !== canonical(field2)) {
|
|
6310
|
-
throw new Error(slug2 + " declares " + vendor + "." + field2.key + " differently from another manifest \u2014 a field two connections spend is declared identically in both");
|
|
6311
|
-
}
|
|
6312
|
-
continue;
|
|
6313
|
-
}
|
|
6314
|
-
if (field2.credential) {
|
|
6315
|
-
const owner = claimed.get(field2.credential);
|
|
6316
|
-
if (owner) {
|
|
6317
|
-
throw new Error(field2.credential + " is claimed by both " + owner + " and " + vendor + "." + field2.key + " \u2014 one would silently overwrite the other");
|
|
6318
|
-
}
|
|
6319
|
-
claimed.set(field2.credential, vendor + "." + field2.key);
|
|
6320
|
-
}
|
|
6321
|
-
held.fields.push(field2);
|
|
6322
|
-
}
|
|
6323
|
-
}
|
|
6324
|
-
}
|
|
6325
|
-
return Object.freeze(Object.fromEntries(
|
|
6326
|
-
Object.entries(merged).map(([vendor, held]) => [vendor, Object.freeze({ ...held, fields: Object.freeze(held.fields) })])
|
|
6327
|
-
));
|
|
6328
|
-
};
|
|
6329
|
-
var vendors = mergeVendors(connections);
|
|
6330
6554
|
(() => {
|
|
6331
6555
|
var _a;
|
|
6332
6556
|
const routes = {};
|
|
@@ -6374,12 +6598,6 @@ var publicConnectionKeys = Object.freeze([
|
|
|
6374
6598
|
// excerpt, guide, and any vendor redirect copy.
|
|
6375
6599
|
"content",
|
|
6376
6600
|
"createdAt",
|
|
6377
|
-
// THE MERCHANT'S OWN SWITCH. `enabled : false` is a connection the merchant
|
|
6378
|
-
// paused — kept, configured, and not run — as distinct from a vendor the
|
|
6379
|
-
// platform switched off (which the api overlays as an error). Absent means
|
|
6380
|
-
// on; the dashboard renders Paused from it and the sync gates refuse a paused
|
|
6381
|
-
// connection the way they refuse a missing one.
|
|
6382
|
-
"enabled",
|
|
6383
6601
|
// The connection DOCUMENT's own errors array — scope-drift entries written by
|
|
6384
6602
|
// drawbridge-sync. NOT the manifest's error copy, which is content.errors:
|
|
6385
6603
|
// the document is spread OVER the resolved manifest downstream, so the two
|
|
@@ -6440,8 +6658,7 @@ var providerSettings = async ({ controller, includeDisabled = false, slug: slug2
|
|
|
6440
6658
|
};
|
|
6441
6659
|
var vendorEnabled = async ({ controller, vendor }) => (await providerRow({ controller, slug: vendor })).enabled;
|
|
6442
6660
|
var vendorSettings = async ({ controller, slug: slug2 }) => {
|
|
6443
|
-
|
|
6444
|
-
const declared = Object.hasOwn(connections, slug2) ? Object.keys(((_a = connections[slug2].provider) == null ? void 0 : _a.vendors) || {}) : [];
|
|
6661
|
+
const declared = Object.hasOwn(connections, slug2) ? connections[slug2].vendors || [] : [];
|
|
6445
6662
|
let merged = {};
|
|
6446
6663
|
for (const vendor of declared) {
|
|
6447
6664
|
merged = { ...merged, ...await providerSettings({ controller, slug: vendor }) };
|
|
@@ -6449,8 +6666,7 @@ var vendorSettings = async ({ controller, slug: slug2 }) => {
|
|
|
6449
6666
|
return merged;
|
|
6450
6667
|
};
|
|
6451
6668
|
var vendorsEnabled = async ({ controller, slug: slug2 }) => {
|
|
6452
|
-
|
|
6453
|
-
const declared = Object.hasOwn(connections, slug2) ? Object.keys(((_a = connections[slug2].provider) == null ? void 0 : _a.vendors) || {}) : [];
|
|
6669
|
+
const declared = Object.hasOwn(connections, slug2) ? connections[slug2].vendors || [] : [];
|
|
6454
6670
|
for (const vendor of declared) {
|
|
6455
6671
|
if (!await vendorEnabled({ controller, vendor })) return false;
|
|
6456
6672
|
}
|