@drawbridge/drawbridge-utils 0.0.134 → 0.0.135
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 +81 -5
- package/dist/connections/index.d.cts +100 -4
- package/dist/connections/index.d.ts +100 -4
- package/dist/connections/index.js +81 -5
- package/dist/connections/oauth.cjs +8 -2
- package/dist/connections/oauth.d.cts +14 -3
- package/dist/connections/oauth.d.ts +14 -3
- package/dist/connections/oauth.js +8 -2
- package/dist/providers.cjs +81 -5
- package/dist/providers.js +81 -5
- package/dist/twilio.cjs +51 -0
- package/dist/twilio.d.cts +67 -0
- package/dist/twilio.d.ts +67 -0
- package/dist/twilio.js +51 -0
- package/package.json +1 -1
|
@@ -464,8 +464,14 @@ var authToken = async ({
|
|
|
464
464
|
});
|
|
465
465
|
const body = await response.json().catch(() => ({}));
|
|
466
466
|
if (!response.ok) {
|
|
467
|
-
throw
|
|
468
|
-
|
|
467
|
+
throw Object.assign(
|
|
468
|
+
new Error(
|
|
469
|
+
renewing ? "The vendor refused the refresh token (" + response.status + ") \u2014 reconnect the connection" : "The vendor refused the exchange (" + response.status + ")" + ((body == null ? void 0 : body.error) ? ": " + body.error : "")
|
|
470
|
+
),
|
|
471
|
+
{
|
|
472
|
+
status: response.status,
|
|
473
|
+
...renewing && { code: "grant_refused" }
|
|
474
|
+
}
|
|
469
475
|
);
|
|
470
476
|
}
|
|
471
477
|
if (!renewing && !body.access_token) throw new Error("The vendor returned no access token");
|
|
@@ -521,7 +527,10 @@ var accessToken = async ({
|
|
|
521
527
|
}
|
|
522
528
|
if (!force && !isStale(settings, now)) return settings.accessToken;
|
|
523
529
|
if (!settings.refreshToken) {
|
|
524
|
-
throw
|
|
530
|
+
throw Object.assign(
|
|
531
|
+
new Error("This connection has expired and cannot be renewed automatically. Reconnect it."),
|
|
532
|
+
{ code: "grant_refused" }
|
|
533
|
+
);
|
|
525
534
|
}
|
|
526
535
|
const minted = await manifest.hooks.auth.token({
|
|
527
536
|
clientId,
|
|
@@ -2735,8 +2744,62 @@ var klaviyo_default2 = {
|
|
|
2735
2744
|
sms: false,
|
|
2736
2745
|
inbound: false,
|
|
2737
2746
|
// Nothing to set up or tear down at the vendor: the grant is the whole
|
|
2738
|
-
// integration
|
|
2739
|
-
lifecycle
|
|
2747
|
+
// integration. What CAN rot is the grant itself, so health is the one
|
|
2748
|
+
// lifecycle hook Klaviyo carries.
|
|
2749
|
+
lifecycle: {
|
|
2750
|
+
// Nothing to set up, tear down, or re-register at the vendor — the
|
|
2751
|
+
// grant is the whole integration.
|
|
2752
|
+
cleanup: false,
|
|
2753
|
+
register: false,
|
|
2754
|
+
rehydrate: false,
|
|
2755
|
+
// KEEP THE GRANT PROVEN AND WARM. The shell mints a fresh access
|
|
2756
|
+
// token before every hook run — for Klaviyo that spends the refresh
|
|
2757
|
+
// token, which is the only question that reaches Klaviyo (see
|
|
2758
|
+
// auth.probe) — so this body running at all proves the grant still
|
|
2759
|
+
// rotates, and the daily run keeps it inside Klaviyo's 90-day idle
|
|
2760
|
+
// window. A dead grant never gets here: the shell's mint throws
|
|
2761
|
+
// `grant_refused` and the step runner errors the connection itself.
|
|
2762
|
+
//
|
|
2763
|
+
// The one call below proves the minted token is HONOURED — mint and
|
|
2764
|
+
// acceptance are different facts, and /accounts is already the call
|
|
2765
|
+
// the connect flow makes (auth.connect), so it needs no new scope.
|
|
2766
|
+
health: async ({ connection: connection2, token }, { fetcher, read } = {}) => {
|
|
2767
|
+
const request2 = { connectionId: connection2.id };
|
|
2768
|
+
try {
|
|
2769
|
+
await api2("/accounts", { fetcher, token });
|
|
2770
|
+
return {
|
|
2771
|
+
message: "Health check passed \u2014 token minted and accepted.",
|
|
2772
|
+
request: request2,
|
|
2773
|
+
response: { pingedAt: /* @__PURE__ */ new Date() }
|
|
2774
|
+
};
|
|
2775
|
+
} catch (error) {
|
|
2776
|
+
if ([401, 403].includes(error.status) && read) {
|
|
2777
|
+
const current = await read.get({ collection: "connection", query: { id: connection2.id } });
|
|
2778
|
+
if (current) {
|
|
2779
|
+
const others = (current.errors || []).filter((entry) => entry.source !== "oauth");
|
|
2780
|
+
error.writes = [{
|
|
2781
|
+
collection: "connection",
|
|
2782
|
+
data: {
|
|
2783
|
+
$set: {
|
|
2784
|
+
errors: [
|
|
2785
|
+
...others,
|
|
2786
|
+
{
|
|
2787
|
+
message: "Klaviyo no longer accepts this connection. Reconnect Klaviyo to resume syncing.",
|
|
2788
|
+
source: "oauth"
|
|
2789
|
+
}
|
|
2790
|
+
],
|
|
2791
|
+
status: "error"
|
|
2792
|
+
}
|
|
2793
|
+
},
|
|
2794
|
+
operation: "update",
|
|
2795
|
+
query: { id: connection2.id }
|
|
2796
|
+
}];
|
|
2797
|
+
}
|
|
2798
|
+
}
|
|
2799
|
+
throw error;
|
|
2800
|
+
}
|
|
2801
|
+
}
|
|
2802
|
+
},
|
|
2740
2803
|
resources: {
|
|
2741
2804
|
// The lists a merchant can sync into, for the picker on their
|
|
2742
2805
|
// connection.
|
|
@@ -2812,6 +2875,19 @@ var klaviyo_default2 = {
|
|
|
2812
2875
|
return ((_a = data2 == null ? void 0 : data2.settings) == null ? void 0 : _a.list) ? data2.status : "pending";
|
|
2813
2876
|
},
|
|
2814
2877
|
steps: {
|
|
2878
|
+
connection: {
|
|
2879
|
+
// The daily grant check — same step type and workflow shape as
|
|
2880
|
+
// Shopify's, provisioned as a system workflow per connection.
|
|
2881
|
+
health: {
|
|
2882
|
+
check: () => ({
|
|
2883
|
+
description: "Keeps the Klaviyo grant working \u2014 spends the refresh token daily so a revoked or idle grant is reported instead of discovered by a failing sync.",
|
|
2884
|
+
hook: "lifecycle.health",
|
|
2885
|
+
key: "Klaviyo Connection Health",
|
|
2886
|
+
queue: "connection",
|
|
2887
|
+
system: true
|
|
2888
|
+
})
|
|
2889
|
+
}
|
|
2890
|
+
},
|
|
2815
2891
|
contacts: {
|
|
2816
2892
|
// A DECLARATION, not the work. It names the hook that does the work, and
|
|
2817
2893
|
// says where that hook's values belong. Nested like the hooks, and the
|
|
@@ -741,8 +741,12 @@ const accessToken = async ({
|
|
|
741
741
|
|
|
742
742
|
// Expired with no way to mint another. Said plainly rather than returning
|
|
743
743
|
// a token the vendor will refuse — the merchant has to reconnect and the
|
|
744
|
-
// error should say so.
|
|
745
|
-
|
|
744
|
+
// error should say so. Same `code` as a refused refresh: both mean the
|
|
745
|
+
// grant is dead and only reconnecting revives it.
|
|
746
|
+
throw Object.assign(
|
|
747
|
+
new Error( 'This connection has expired and cannot be renewed automatically. Reconnect it.' ),
|
|
748
|
+
{ code : 'grant_refused' }
|
|
749
|
+
);
|
|
746
750
|
|
|
747
751
|
}
|
|
748
752
|
|
|
@@ -2941,8 +2945,84 @@ var klaviyo = {
|
|
|
2941
2945
|
inbound : false,
|
|
2942
2946
|
|
|
2943
2947
|
// Nothing to set up or tear down at the vendor: the grant is the whole
|
|
2944
|
-
// integration
|
|
2945
|
-
lifecycle
|
|
2948
|
+
// integration. What CAN rot is the grant itself, so health is the one
|
|
2949
|
+
// lifecycle hook Klaviyo carries.
|
|
2950
|
+
lifecycle : {
|
|
2951
|
+
|
|
2952
|
+
// Nothing to set up, tear down, or re-register at the vendor — the
|
|
2953
|
+
// grant is the whole integration.
|
|
2954
|
+
cleanup : false,
|
|
2955
|
+
register : false,
|
|
2956
|
+
rehydrate : false,
|
|
2957
|
+
|
|
2958
|
+
// KEEP THE GRANT PROVEN AND WARM. The shell mints a fresh access
|
|
2959
|
+
// token before every hook run — for Klaviyo that spends the refresh
|
|
2960
|
+
// token, which is the only question that reaches Klaviyo (see
|
|
2961
|
+
// auth.probe) — so this body running at all proves the grant still
|
|
2962
|
+
// rotates, and the daily run keeps it inside Klaviyo's 90-day idle
|
|
2963
|
+
// window. A dead grant never gets here: the shell's mint throws
|
|
2964
|
+
// `grant_refused` and the step runner errors the connection itself.
|
|
2965
|
+
//
|
|
2966
|
+
// The one call below proves the minted token is HONOURED — mint and
|
|
2967
|
+
// acceptance are different facts, and /accounts is already the call
|
|
2968
|
+
// the connect flow makes (auth.connect), so it needs no new scope.
|
|
2969
|
+
health : async ( { connection, token }, { fetcher, read } = {} ) => {
|
|
2970
|
+
|
|
2971
|
+
const request = { connectionId : connection.id };
|
|
2972
|
+
|
|
2973
|
+
try {
|
|
2974
|
+
|
|
2975
|
+
await api$1( '/accounts', { fetcher, token });
|
|
2976
|
+
|
|
2977
|
+
return {
|
|
2978
|
+
message : 'Health check passed — token minted and accepted.',
|
|
2979
|
+
request,
|
|
2980
|
+
response : { pingedAt : new Date() }
|
|
2981
|
+
};
|
|
2982
|
+
|
|
2983
|
+
} catch ( error ) {
|
|
2984
|
+
|
|
2985
|
+
// The token we JUST minted was refused — a revoked or
|
|
2986
|
+
// downgraded grant, never a transient. The write rides out
|
|
2987
|
+
// on the rejection (the shell performs a thrown error's
|
|
2988
|
+
// effects) because the step must still fail.
|
|
2989
|
+
if( [ 401, 403 ].includes( error.status ) && read ){
|
|
2990
|
+
|
|
2991
|
+
const current = await read.get({ collection : 'connection', query : { id : connection.id } });
|
|
2992
|
+
|
|
2993
|
+
if( current ){
|
|
2994
|
+
|
|
2995
|
+
const others = ( current.errors || [] ).filter( ( entry ) => entry.source !== 'oauth' );
|
|
2996
|
+
|
|
2997
|
+
error.writes = [ {
|
|
2998
|
+
collection : 'connection',
|
|
2999
|
+
data : {
|
|
3000
|
+
$set : {
|
|
3001
|
+
errors : [
|
|
3002
|
+
...others,
|
|
3003
|
+
{
|
|
3004
|
+
message : 'Klaviyo no longer accepts this connection. Reconnect Klaviyo to resume syncing.',
|
|
3005
|
+
source : 'oauth'
|
|
3006
|
+
}
|
|
3007
|
+
],
|
|
3008
|
+
status : 'error'
|
|
3009
|
+
}
|
|
3010
|
+
},
|
|
3011
|
+
operation : 'update',
|
|
3012
|
+
query : { id : connection.id }
|
|
3013
|
+
} ];
|
|
3014
|
+
|
|
3015
|
+
}
|
|
3016
|
+
|
|
3017
|
+
}
|
|
3018
|
+
|
|
3019
|
+
throw error;
|
|
3020
|
+
|
|
3021
|
+
}
|
|
3022
|
+
|
|
3023
|
+
}
|
|
3024
|
+
|
|
3025
|
+
},
|
|
2946
3026
|
|
|
2947
3027
|
resources : {
|
|
2948
3028
|
|
|
@@ -3049,6 +3129,22 @@ var klaviyo = {
|
|
|
3049
3129
|
|
|
3050
3130
|
steps : {
|
|
3051
3131
|
|
|
3132
|
+
connection : {
|
|
3133
|
+
|
|
3134
|
+
// The daily grant check — same step type and workflow shape as
|
|
3135
|
+
// Shopify's, provisioned as a system workflow per connection.
|
|
3136
|
+
health : {
|
|
3137
|
+
check : () => ({
|
|
3138
|
+
description : 'Keeps the Klaviyo grant working — spends the refresh token daily so a revoked or idle grant is reported instead of discovered by a failing sync.',
|
|
3139
|
+
hook : 'lifecycle.health',
|
|
3140
|
+
key : 'Klaviyo Connection Health',
|
|
3141
|
+
queue : 'connection',
|
|
3142
|
+
system : true
|
|
3143
|
+
})
|
|
3144
|
+
}
|
|
3145
|
+
|
|
3146
|
+
},
|
|
3147
|
+
|
|
3052
3148
|
contacts : {
|
|
3053
3149
|
|
|
3054
3150
|
// A DECLARATION, not the work. It names the hook that does the work, and
|
|
@@ -741,8 +741,12 @@ const accessToken = async ({
|
|
|
741
741
|
|
|
742
742
|
// Expired with no way to mint another. Said plainly rather than returning
|
|
743
743
|
// a token the vendor will refuse — the merchant has to reconnect and the
|
|
744
|
-
// error should say so.
|
|
745
|
-
|
|
744
|
+
// error should say so. Same `code` as a refused refresh: both mean the
|
|
745
|
+
// grant is dead and only reconnecting revives it.
|
|
746
|
+
throw Object.assign(
|
|
747
|
+
new Error( 'This connection has expired and cannot be renewed automatically. Reconnect it.' ),
|
|
748
|
+
{ code : 'grant_refused' }
|
|
749
|
+
);
|
|
746
750
|
|
|
747
751
|
}
|
|
748
752
|
|
|
@@ -2941,8 +2945,84 @@ var klaviyo = {
|
|
|
2941
2945
|
inbound : false,
|
|
2942
2946
|
|
|
2943
2947
|
// Nothing to set up or tear down at the vendor: the grant is the whole
|
|
2944
|
-
// integration
|
|
2945
|
-
lifecycle
|
|
2948
|
+
// integration. What CAN rot is the grant itself, so health is the one
|
|
2949
|
+
// lifecycle hook Klaviyo carries.
|
|
2950
|
+
lifecycle : {
|
|
2951
|
+
|
|
2952
|
+
// Nothing to set up, tear down, or re-register at the vendor — the
|
|
2953
|
+
// grant is the whole integration.
|
|
2954
|
+
cleanup : false,
|
|
2955
|
+
register : false,
|
|
2956
|
+
rehydrate : false,
|
|
2957
|
+
|
|
2958
|
+
// KEEP THE GRANT PROVEN AND WARM. The shell mints a fresh access
|
|
2959
|
+
// token before every hook run — for Klaviyo that spends the refresh
|
|
2960
|
+
// token, which is the only question that reaches Klaviyo (see
|
|
2961
|
+
// auth.probe) — so this body running at all proves the grant still
|
|
2962
|
+
// rotates, and the daily run keeps it inside Klaviyo's 90-day idle
|
|
2963
|
+
// window. A dead grant never gets here: the shell's mint throws
|
|
2964
|
+
// `grant_refused` and the step runner errors the connection itself.
|
|
2965
|
+
//
|
|
2966
|
+
// The one call below proves the minted token is HONOURED — mint and
|
|
2967
|
+
// acceptance are different facts, and /accounts is already the call
|
|
2968
|
+
// the connect flow makes (auth.connect), so it needs no new scope.
|
|
2969
|
+
health : async ( { connection, token }, { fetcher, read } = {} ) => {
|
|
2970
|
+
|
|
2971
|
+
const request = { connectionId : connection.id };
|
|
2972
|
+
|
|
2973
|
+
try {
|
|
2974
|
+
|
|
2975
|
+
await api$1( '/accounts', { fetcher, token });
|
|
2976
|
+
|
|
2977
|
+
return {
|
|
2978
|
+
message : 'Health check passed — token minted and accepted.',
|
|
2979
|
+
request,
|
|
2980
|
+
response : { pingedAt : new Date() }
|
|
2981
|
+
};
|
|
2982
|
+
|
|
2983
|
+
} catch ( error ) {
|
|
2984
|
+
|
|
2985
|
+
// The token we JUST minted was refused — a revoked or
|
|
2986
|
+
// downgraded grant, never a transient. The write rides out
|
|
2987
|
+
// on the rejection (the shell performs a thrown error's
|
|
2988
|
+
// effects) because the step must still fail.
|
|
2989
|
+
if( [ 401, 403 ].includes( error.status ) && read ){
|
|
2990
|
+
|
|
2991
|
+
const current = await read.get({ collection : 'connection', query : { id : connection.id } });
|
|
2992
|
+
|
|
2993
|
+
if( current ){
|
|
2994
|
+
|
|
2995
|
+
const others = ( current.errors || [] ).filter( ( entry ) => entry.source !== 'oauth' );
|
|
2996
|
+
|
|
2997
|
+
error.writes = [ {
|
|
2998
|
+
collection : 'connection',
|
|
2999
|
+
data : {
|
|
3000
|
+
$set : {
|
|
3001
|
+
errors : [
|
|
3002
|
+
...others,
|
|
3003
|
+
{
|
|
3004
|
+
message : 'Klaviyo no longer accepts this connection. Reconnect Klaviyo to resume syncing.',
|
|
3005
|
+
source : 'oauth'
|
|
3006
|
+
}
|
|
3007
|
+
],
|
|
3008
|
+
status : 'error'
|
|
3009
|
+
}
|
|
3010
|
+
},
|
|
3011
|
+
operation : 'update',
|
|
3012
|
+
query : { id : connection.id }
|
|
3013
|
+
} ];
|
|
3014
|
+
|
|
3015
|
+
}
|
|
3016
|
+
|
|
3017
|
+
}
|
|
3018
|
+
|
|
3019
|
+
throw error;
|
|
3020
|
+
|
|
3021
|
+
}
|
|
3022
|
+
|
|
3023
|
+
}
|
|
3024
|
+
|
|
3025
|
+
},
|
|
2946
3026
|
|
|
2947
3027
|
resources : {
|
|
2948
3028
|
|
|
@@ -3049,6 +3129,22 @@ var klaviyo = {
|
|
|
3049
3129
|
|
|
3050
3130
|
steps : {
|
|
3051
3131
|
|
|
3132
|
+
connection : {
|
|
3133
|
+
|
|
3134
|
+
// The daily grant check — same step type and workflow shape as
|
|
3135
|
+
// Shopify's, provisioned as a system workflow per connection.
|
|
3136
|
+
health : {
|
|
3137
|
+
check : () => ({
|
|
3138
|
+
description : 'Keeps the Klaviyo grant working — spends the refresh token daily so a revoked or idle grant is reported instead of discovered by a failing sync.',
|
|
3139
|
+
hook : 'lifecycle.health',
|
|
3140
|
+
key : 'Klaviyo Connection Health',
|
|
3141
|
+
queue : 'connection',
|
|
3142
|
+
system : true
|
|
3143
|
+
})
|
|
3144
|
+
}
|
|
3145
|
+
|
|
3146
|
+
},
|
|
3147
|
+
|
|
3052
3148
|
contacts : {
|
|
3053
3149
|
|
|
3054
3150
|
// A DECLARATION, not the work. It names the hook that does the work, and
|
|
@@ -390,8 +390,14 @@ var authToken = async ({
|
|
|
390
390
|
});
|
|
391
391
|
const body = await response.json().catch(() => ({}));
|
|
392
392
|
if (!response.ok) {
|
|
393
|
-
throw
|
|
394
|
-
|
|
393
|
+
throw Object.assign(
|
|
394
|
+
new Error(
|
|
395
|
+
renewing ? "The vendor refused the refresh token (" + response.status + ") \u2014 reconnect the connection" : "The vendor refused the exchange (" + response.status + ")" + ((body == null ? void 0 : body.error) ? ": " + body.error : "")
|
|
396
|
+
),
|
|
397
|
+
{
|
|
398
|
+
status: response.status,
|
|
399
|
+
...renewing && { code: "grant_refused" }
|
|
400
|
+
}
|
|
395
401
|
);
|
|
396
402
|
}
|
|
397
403
|
if (!renewing && !body.access_token) throw new Error("The vendor returned no access token");
|
|
@@ -447,7 +453,10 @@ var accessToken = async ({
|
|
|
447
453
|
}
|
|
448
454
|
if (!force && !isStale(settings, now)) return settings.accessToken;
|
|
449
455
|
if (!settings.refreshToken) {
|
|
450
|
-
throw
|
|
456
|
+
throw Object.assign(
|
|
457
|
+
new Error("This connection has expired and cannot be renewed automatically. Reconnect it."),
|
|
458
|
+
{ code: "grant_refused" }
|
|
459
|
+
);
|
|
451
460
|
}
|
|
452
461
|
const minted = await manifest.hooks.auth.token({
|
|
453
462
|
clientId,
|
|
@@ -2661,8 +2670,62 @@ var klaviyo_default2 = {
|
|
|
2661
2670
|
sms: false,
|
|
2662
2671
|
inbound: false,
|
|
2663
2672
|
// Nothing to set up or tear down at the vendor: the grant is the whole
|
|
2664
|
-
// integration
|
|
2665
|
-
lifecycle
|
|
2673
|
+
// integration. What CAN rot is the grant itself, so health is the one
|
|
2674
|
+
// lifecycle hook Klaviyo carries.
|
|
2675
|
+
lifecycle: {
|
|
2676
|
+
// Nothing to set up, tear down, or re-register at the vendor — the
|
|
2677
|
+
// grant is the whole integration.
|
|
2678
|
+
cleanup: false,
|
|
2679
|
+
register: false,
|
|
2680
|
+
rehydrate: false,
|
|
2681
|
+
// KEEP THE GRANT PROVEN AND WARM. The shell mints a fresh access
|
|
2682
|
+
// token before every hook run — for Klaviyo that spends the refresh
|
|
2683
|
+
// token, which is the only question that reaches Klaviyo (see
|
|
2684
|
+
// auth.probe) — so this body running at all proves the grant still
|
|
2685
|
+
// rotates, and the daily run keeps it inside Klaviyo's 90-day idle
|
|
2686
|
+
// window. A dead grant never gets here: the shell's mint throws
|
|
2687
|
+
// `grant_refused` and the step runner errors the connection itself.
|
|
2688
|
+
//
|
|
2689
|
+
// The one call below proves the minted token is HONOURED — mint and
|
|
2690
|
+
// acceptance are different facts, and /accounts is already the call
|
|
2691
|
+
// the connect flow makes (auth.connect), so it needs no new scope.
|
|
2692
|
+
health: async ({ connection: connection2, token }, { fetcher, read } = {}) => {
|
|
2693
|
+
const request2 = { connectionId: connection2.id };
|
|
2694
|
+
try {
|
|
2695
|
+
await api2("/accounts", { fetcher, token });
|
|
2696
|
+
return {
|
|
2697
|
+
message: "Health check passed \u2014 token minted and accepted.",
|
|
2698
|
+
request: request2,
|
|
2699
|
+
response: { pingedAt: /* @__PURE__ */ new Date() }
|
|
2700
|
+
};
|
|
2701
|
+
} catch (error) {
|
|
2702
|
+
if ([401, 403].includes(error.status) && read) {
|
|
2703
|
+
const current = await read.get({ collection: "connection", query: { id: connection2.id } });
|
|
2704
|
+
if (current) {
|
|
2705
|
+
const others = (current.errors || []).filter((entry) => entry.source !== "oauth");
|
|
2706
|
+
error.writes = [{
|
|
2707
|
+
collection: "connection",
|
|
2708
|
+
data: {
|
|
2709
|
+
$set: {
|
|
2710
|
+
errors: [
|
|
2711
|
+
...others,
|
|
2712
|
+
{
|
|
2713
|
+
message: "Klaviyo no longer accepts this connection. Reconnect Klaviyo to resume syncing.",
|
|
2714
|
+
source: "oauth"
|
|
2715
|
+
}
|
|
2716
|
+
],
|
|
2717
|
+
status: "error"
|
|
2718
|
+
}
|
|
2719
|
+
},
|
|
2720
|
+
operation: "update",
|
|
2721
|
+
query: { id: connection2.id }
|
|
2722
|
+
}];
|
|
2723
|
+
}
|
|
2724
|
+
}
|
|
2725
|
+
throw error;
|
|
2726
|
+
}
|
|
2727
|
+
}
|
|
2728
|
+
},
|
|
2666
2729
|
resources: {
|
|
2667
2730
|
// The lists a merchant can sync into, for the picker on their
|
|
2668
2731
|
// connection.
|
|
@@ -2738,6 +2801,19 @@ var klaviyo_default2 = {
|
|
|
2738
2801
|
return ((_a = data2 == null ? void 0 : data2.settings) == null ? void 0 : _a.list) ? data2.status : "pending";
|
|
2739
2802
|
},
|
|
2740
2803
|
steps: {
|
|
2804
|
+
connection: {
|
|
2805
|
+
// The daily grant check — same step type and workflow shape as
|
|
2806
|
+
// Shopify's, provisioned as a system workflow per connection.
|
|
2807
|
+
health: {
|
|
2808
|
+
check: () => ({
|
|
2809
|
+
description: "Keeps the Klaviyo grant working \u2014 spends the refresh token daily so a revoked or idle grant is reported instead of discovered by a failing sync.",
|
|
2810
|
+
hook: "lifecycle.health",
|
|
2811
|
+
key: "Klaviyo Connection Health",
|
|
2812
|
+
queue: "connection",
|
|
2813
|
+
system: true
|
|
2814
|
+
})
|
|
2815
|
+
}
|
|
2816
|
+
},
|
|
2741
2817
|
contacts: {
|
|
2742
2818
|
// A DECLARATION, not the work. It names the hook that does the work, and
|
|
2743
2819
|
// says where that hook's values belong. Nested like the hooks, and the
|
|
@@ -94,8 +94,14 @@ var authToken = async ({
|
|
|
94
94
|
});
|
|
95
95
|
const body = await response.json().catch(() => ({}));
|
|
96
96
|
if (!response.ok) {
|
|
97
|
-
throw
|
|
98
|
-
|
|
97
|
+
throw Object.assign(
|
|
98
|
+
new Error(
|
|
99
|
+
renewing ? "The vendor refused the refresh token (" + response.status + ") \u2014 reconnect the connection" : "The vendor refused the exchange (" + response.status + ")" + ((body == null ? void 0 : body.error) ? ": " + body.error : "")
|
|
100
|
+
),
|
|
101
|
+
{
|
|
102
|
+
status: response.status,
|
|
103
|
+
...renewing && { code: "grant_refused" }
|
|
104
|
+
}
|
|
99
105
|
);
|
|
100
106
|
}
|
|
101
107
|
if (!renewing && !body.access_token) throw new Error("The vendor returned no access token");
|
|
@@ -173,9 +173,20 @@ const authToken = async ({
|
|
|
173
173
|
// The two paths fail differently for the merchant: a refused exchange is
|
|
174
174
|
// "try connecting again", a refused refresh is "reconnect this connection",
|
|
175
175
|
// and collapsing them sends somebody to the wrong screen.
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
176
|
+
//
|
|
177
|
+
// `code` marks the refused REFRESH machine-readably — the health-check
|
|
178
|
+
// shell errors the connection on it rather than retrying a dead grant
|
|
179
|
+
// into the log forever. Only the renewing branch: a refused exchange is
|
|
180
|
+
// a connect-flow failure with a person watching.
|
|
181
|
+
throw Object.assign(
|
|
182
|
+
new Error( renewing
|
|
183
|
+
? 'The vendor refused the refresh token (' + response.status + ') — reconnect the connection'
|
|
184
|
+
: 'The vendor refused the exchange (' + response.status + ')' + ( body?.error ? ': ' + body.error : '' )
|
|
185
|
+
),
|
|
186
|
+
{
|
|
187
|
+
status : response.status,
|
|
188
|
+
...( renewing && { code : 'grant_refused' })
|
|
189
|
+
}
|
|
179
190
|
);
|
|
180
191
|
|
|
181
192
|
}
|
|
@@ -173,9 +173,20 @@ const authToken = async ({
|
|
|
173
173
|
// The two paths fail differently for the merchant: a refused exchange is
|
|
174
174
|
// "try connecting again", a refused refresh is "reconnect this connection",
|
|
175
175
|
// and collapsing them sends somebody to the wrong screen.
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
176
|
+
//
|
|
177
|
+
// `code` marks the refused REFRESH machine-readably — the health-check
|
|
178
|
+
// shell errors the connection on it rather than retrying a dead grant
|
|
179
|
+
// into the log forever. Only the renewing branch: a refused exchange is
|
|
180
|
+
// a connect-flow failure with a person watching.
|
|
181
|
+
throw Object.assign(
|
|
182
|
+
new Error( renewing
|
|
183
|
+
? 'The vendor refused the refresh token (' + response.status + ') — reconnect the connection'
|
|
184
|
+
: 'The vendor refused the exchange (' + response.status + ')' + ( body?.error ? ': ' + body.error : '' )
|
|
185
|
+
),
|
|
186
|
+
{
|
|
187
|
+
status : response.status,
|
|
188
|
+
...( renewing && { code : 'grant_refused' })
|
|
189
|
+
}
|
|
179
190
|
);
|
|
180
191
|
|
|
181
192
|
}
|
|
@@ -69,8 +69,14 @@ var authToken = async ({
|
|
|
69
69
|
});
|
|
70
70
|
const body = await response.json().catch(() => ({}));
|
|
71
71
|
if (!response.ok) {
|
|
72
|
-
throw
|
|
73
|
-
|
|
72
|
+
throw Object.assign(
|
|
73
|
+
new Error(
|
|
74
|
+
renewing ? "The vendor refused the refresh token (" + response.status + ") \u2014 reconnect the connection" : "The vendor refused the exchange (" + response.status + ")" + ((body == null ? void 0 : body.error) ? ": " + body.error : "")
|
|
75
|
+
),
|
|
76
|
+
{
|
|
77
|
+
status: response.status,
|
|
78
|
+
...renewing && { code: "grant_refused" }
|
|
79
|
+
}
|
|
74
80
|
);
|
|
75
81
|
}
|
|
76
82
|
if (!renewing && !body.access_token) throw new Error("The vendor returned no access token");
|
package/dist/providers.cjs
CHANGED
|
@@ -370,8 +370,14 @@ var authToken = async ({
|
|
|
370
370
|
});
|
|
371
371
|
const body = await response.json().catch(() => ({}));
|
|
372
372
|
if (!response.ok) {
|
|
373
|
-
throw
|
|
374
|
-
|
|
373
|
+
throw Object.assign(
|
|
374
|
+
new Error(
|
|
375
|
+
renewing ? "The vendor refused the refresh token (" + response.status + ") \u2014 reconnect the connection" : "The vendor refused the exchange (" + response.status + ")" + ((body == null ? void 0 : body.error) ? ": " + body.error : "")
|
|
376
|
+
),
|
|
377
|
+
{
|
|
378
|
+
status: response.status,
|
|
379
|
+
...renewing && { code: "grant_refused" }
|
|
380
|
+
}
|
|
375
381
|
);
|
|
376
382
|
}
|
|
377
383
|
if (!renewing && !body.access_token) throw new Error("The vendor returned no access token");
|
|
@@ -427,7 +433,10 @@ var accessToken = async ({
|
|
|
427
433
|
}
|
|
428
434
|
if (!force && !isStale(settings, now)) return settings.accessToken;
|
|
429
435
|
if (!settings.refreshToken) {
|
|
430
|
-
throw
|
|
436
|
+
throw Object.assign(
|
|
437
|
+
new Error("This connection has expired and cannot be renewed automatically. Reconnect it."),
|
|
438
|
+
{ code: "grant_refused" }
|
|
439
|
+
);
|
|
431
440
|
}
|
|
432
441
|
const minted = await manifest.hooks.auth.token({
|
|
433
442
|
clientId,
|
|
@@ -2641,8 +2650,62 @@ var klaviyo_default2 = {
|
|
|
2641
2650
|
sms: false,
|
|
2642
2651
|
inbound: false,
|
|
2643
2652
|
// Nothing to set up or tear down at the vendor: the grant is the whole
|
|
2644
|
-
// integration
|
|
2645
|
-
lifecycle
|
|
2653
|
+
// integration. What CAN rot is the grant itself, so health is the one
|
|
2654
|
+
// lifecycle hook Klaviyo carries.
|
|
2655
|
+
lifecycle: {
|
|
2656
|
+
// Nothing to set up, tear down, or re-register at the vendor — the
|
|
2657
|
+
// grant is the whole integration.
|
|
2658
|
+
cleanup: false,
|
|
2659
|
+
register: false,
|
|
2660
|
+
rehydrate: false,
|
|
2661
|
+
// KEEP THE GRANT PROVEN AND WARM. The shell mints a fresh access
|
|
2662
|
+
// token before every hook run — for Klaviyo that spends the refresh
|
|
2663
|
+
// token, which is the only question that reaches Klaviyo (see
|
|
2664
|
+
// auth.probe) — so this body running at all proves the grant still
|
|
2665
|
+
// rotates, and the daily run keeps it inside Klaviyo's 90-day idle
|
|
2666
|
+
// window. A dead grant never gets here: the shell's mint throws
|
|
2667
|
+
// `grant_refused` and the step runner errors the connection itself.
|
|
2668
|
+
//
|
|
2669
|
+
// The one call below proves the minted token is HONOURED — mint and
|
|
2670
|
+
// acceptance are different facts, and /accounts is already the call
|
|
2671
|
+
// the connect flow makes (auth.connect), so it needs no new scope.
|
|
2672
|
+
health: async ({ connection: connection2, token }, { fetcher, read } = {}) => {
|
|
2673
|
+
const request2 = { connectionId: connection2.id };
|
|
2674
|
+
try {
|
|
2675
|
+
await api2("/accounts", { fetcher, token });
|
|
2676
|
+
return {
|
|
2677
|
+
message: "Health check passed \u2014 token minted and accepted.",
|
|
2678
|
+
request: request2,
|
|
2679
|
+
response: { pingedAt: /* @__PURE__ */ new Date() }
|
|
2680
|
+
};
|
|
2681
|
+
} catch (error) {
|
|
2682
|
+
if ([401, 403].includes(error.status) && read) {
|
|
2683
|
+
const current = await read.get({ collection: "connection", query: { id: connection2.id } });
|
|
2684
|
+
if (current) {
|
|
2685
|
+
const others = (current.errors || []).filter((entry) => entry.source !== "oauth");
|
|
2686
|
+
error.writes = [{
|
|
2687
|
+
collection: "connection",
|
|
2688
|
+
data: {
|
|
2689
|
+
$set: {
|
|
2690
|
+
errors: [
|
|
2691
|
+
...others,
|
|
2692
|
+
{
|
|
2693
|
+
message: "Klaviyo no longer accepts this connection. Reconnect Klaviyo to resume syncing.",
|
|
2694
|
+
source: "oauth"
|
|
2695
|
+
}
|
|
2696
|
+
],
|
|
2697
|
+
status: "error"
|
|
2698
|
+
}
|
|
2699
|
+
},
|
|
2700
|
+
operation: "update",
|
|
2701
|
+
query: { id: connection2.id }
|
|
2702
|
+
}];
|
|
2703
|
+
}
|
|
2704
|
+
}
|
|
2705
|
+
throw error;
|
|
2706
|
+
}
|
|
2707
|
+
}
|
|
2708
|
+
},
|
|
2646
2709
|
resources: {
|
|
2647
2710
|
// The lists a merchant can sync into, for the picker on their
|
|
2648
2711
|
// connection.
|
|
@@ -2718,6 +2781,19 @@ var klaviyo_default2 = {
|
|
|
2718
2781
|
return ((_a = data2 == null ? void 0 : data2.settings) == null ? void 0 : _a.list) ? data2.status : "pending";
|
|
2719
2782
|
},
|
|
2720
2783
|
steps: {
|
|
2784
|
+
connection: {
|
|
2785
|
+
// The daily grant check — same step type and workflow shape as
|
|
2786
|
+
// Shopify's, provisioned as a system workflow per connection.
|
|
2787
|
+
health: {
|
|
2788
|
+
check: () => ({
|
|
2789
|
+
description: "Keeps the Klaviyo grant working \u2014 spends the refresh token daily so a revoked or idle grant is reported instead of discovered by a failing sync.",
|
|
2790
|
+
hook: "lifecycle.health",
|
|
2791
|
+
key: "Klaviyo Connection Health",
|
|
2792
|
+
queue: "connection",
|
|
2793
|
+
system: true
|
|
2794
|
+
})
|
|
2795
|
+
}
|
|
2796
|
+
},
|
|
2721
2797
|
contacts: {
|
|
2722
2798
|
// A DECLARATION, not the work. It names the hook that does the work, and
|
|
2723
2799
|
// says where that hook's values belong. Nested like the hooks, and the
|
package/dist/providers.js
CHANGED
|
@@ -326,8 +326,14 @@ var authToken = async ({
|
|
|
326
326
|
});
|
|
327
327
|
const body = await response.json().catch(() => ({}));
|
|
328
328
|
if (!response.ok) {
|
|
329
|
-
throw
|
|
330
|
-
|
|
329
|
+
throw Object.assign(
|
|
330
|
+
new Error(
|
|
331
|
+
renewing ? "The vendor refused the refresh token (" + response.status + ") \u2014 reconnect the connection" : "The vendor refused the exchange (" + response.status + ")" + ((body == null ? void 0 : body.error) ? ": " + body.error : "")
|
|
332
|
+
),
|
|
333
|
+
{
|
|
334
|
+
status: response.status,
|
|
335
|
+
...renewing && { code: "grant_refused" }
|
|
336
|
+
}
|
|
331
337
|
);
|
|
332
338
|
}
|
|
333
339
|
if (!renewing && !body.access_token) throw new Error("The vendor returned no access token");
|
|
@@ -383,7 +389,10 @@ var accessToken = async ({
|
|
|
383
389
|
}
|
|
384
390
|
if (!force && !isStale(settings, now)) return settings.accessToken;
|
|
385
391
|
if (!settings.refreshToken) {
|
|
386
|
-
throw
|
|
392
|
+
throw Object.assign(
|
|
393
|
+
new Error("This connection has expired and cannot be renewed automatically. Reconnect it."),
|
|
394
|
+
{ code: "grant_refused" }
|
|
395
|
+
);
|
|
387
396
|
}
|
|
388
397
|
const minted = await manifest.hooks.auth.token({
|
|
389
398
|
clientId,
|
|
@@ -2597,8 +2606,62 @@ var klaviyo_default2 = {
|
|
|
2597
2606
|
sms: false,
|
|
2598
2607
|
inbound: false,
|
|
2599
2608
|
// Nothing to set up or tear down at the vendor: the grant is the whole
|
|
2600
|
-
// integration
|
|
2601
|
-
lifecycle
|
|
2609
|
+
// integration. What CAN rot is the grant itself, so health is the one
|
|
2610
|
+
// lifecycle hook Klaviyo carries.
|
|
2611
|
+
lifecycle: {
|
|
2612
|
+
// Nothing to set up, tear down, or re-register at the vendor — the
|
|
2613
|
+
// grant is the whole integration.
|
|
2614
|
+
cleanup: false,
|
|
2615
|
+
register: false,
|
|
2616
|
+
rehydrate: false,
|
|
2617
|
+
// KEEP THE GRANT PROVEN AND WARM. The shell mints a fresh access
|
|
2618
|
+
// token before every hook run — for Klaviyo that spends the refresh
|
|
2619
|
+
// token, which is the only question that reaches Klaviyo (see
|
|
2620
|
+
// auth.probe) — so this body running at all proves the grant still
|
|
2621
|
+
// rotates, and the daily run keeps it inside Klaviyo's 90-day idle
|
|
2622
|
+
// window. A dead grant never gets here: the shell's mint throws
|
|
2623
|
+
// `grant_refused` and the step runner errors the connection itself.
|
|
2624
|
+
//
|
|
2625
|
+
// The one call below proves the minted token is HONOURED — mint and
|
|
2626
|
+
// acceptance are different facts, and /accounts is already the call
|
|
2627
|
+
// the connect flow makes (auth.connect), so it needs no new scope.
|
|
2628
|
+
health: async ({ connection: connection2, token }, { fetcher, read } = {}) => {
|
|
2629
|
+
const request2 = { connectionId: connection2.id };
|
|
2630
|
+
try {
|
|
2631
|
+
await api2("/accounts", { fetcher, token });
|
|
2632
|
+
return {
|
|
2633
|
+
message: "Health check passed \u2014 token minted and accepted.",
|
|
2634
|
+
request: request2,
|
|
2635
|
+
response: { pingedAt: /* @__PURE__ */ new Date() }
|
|
2636
|
+
};
|
|
2637
|
+
} catch (error) {
|
|
2638
|
+
if ([401, 403].includes(error.status) && read) {
|
|
2639
|
+
const current = await read.get({ collection: "connection", query: { id: connection2.id } });
|
|
2640
|
+
if (current) {
|
|
2641
|
+
const others = (current.errors || []).filter((entry) => entry.source !== "oauth");
|
|
2642
|
+
error.writes = [{
|
|
2643
|
+
collection: "connection",
|
|
2644
|
+
data: {
|
|
2645
|
+
$set: {
|
|
2646
|
+
errors: [
|
|
2647
|
+
...others,
|
|
2648
|
+
{
|
|
2649
|
+
message: "Klaviyo no longer accepts this connection. Reconnect Klaviyo to resume syncing.",
|
|
2650
|
+
source: "oauth"
|
|
2651
|
+
}
|
|
2652
|
+
],
|
|
2653
|
+
status: "error"
|
|
2654
|
+
}
|
|
2655
|
+
},
|
|
2656
|
+
operation: "update",
|
|
2657
|
+
query: { id: connection2.id }
|
|
2658
|
+
}];
|
|
2659
|
+
}
|
|
2660
|
+
}
|
|
2661
|
+
throw error;
|
|
2662
|
+
}
|
|
2663
|
+
}
|
|
2664
|
+
},
|
|
2602
2665
|
resources: {
|
|
2603
2666
|
// The lists a merchant can sync into, for the picker on their
|
|
2604
2667
|
// connection.
|
|
@@ -2674,6 +2737,19 @@ var klaviyo_default2 = {
|
|
|
2674
2737
|
return ((_a = data2 == null ? void 0 : data2.settings) == null ? void 0 : _a.list) ? data2.status : "pending";
|
|
2675
2738
|
},
|
|
2676
2739
|
steps: {
|
|
2740
|
+
connection: {
|
|
2741
|
+
// The daily grant check — same step type and workflow shape as
|
|
2742
|
+
// Shopify's, provisioned as a system workflow per connection.
|
|
2743
|
+
health: {
|
|
2744
|
+
check: () => ({
|
|
2745
|
+
description: "Keeps the Klaviyo grant working \u2014 spends the refresh token daily so a revoked or idle grant is reported instead of discovered by a failing sync.",
|
|
2746
|
+
hook: "lifecycle.health",
|
|
2747
|
+
key: "Klaviyo Connection Health",
|
|
2748
|
+
queue: "connection",
|
|
2749
|
+
system: true
|
|
2750
|
+
})
|
|
2751
|
+
}
|
|
2752
|
+
},
|
|
2677
2753
|
contacts: {
|
|
2678
2754
|
// A DECLARATION, not the work. It names the hook that does the work, and
|
|
2679
2755
|
// says where that hook's values belong. Nested like the hooks, and the
|
package/dist/twilio.cjs
CHANGED
|
@@ -174,6 +174,57 @@ var twilio = {
|
|
|
174
174
|
sid: result == null ? void 0 : result.sid
|
|
175
175
|
};
|
|
176
176
|
},
|
|
177
|
+
// THE NUMBER AS TWILIO HOLDS IT NOW. Same IncomingPhoneNumber resource the
|
|
178
|
+
// purchase and release above use (api.twilio.com 2010-04-01, GET
|
|
179
|
+
// /IncomingPhoneNumbers/{sid}.json) — a 404 means the number is no longer
|
|
180
|
+
// on the account, which the health sweep must distinguish from a transient,
|
|
181
|
+
// so it is answered as { gone : true } rather than thrown.
|
|
182
|
+
numberConfig: async ({ accountSid, authToken, request: request2 = request, sid }) => {
|
|
183
|
+
if (!accountSid || !authToken) throw new Error("Twilio credentials missing \u2014 accountSid, authToken");
|
|
184
|
+
if (!sid) throw new Error("Twilio config read needs the IncomingPhoneNumber sid");
|
|
185
|
+
let result;
|
|
186
|
+
try {
|
|
187
|
+
result = await request2({
|
|
188
|
+
method: "GET",
|
|
189
|
+
url: "https://api.twilio.com/2010-04-01/Accounts/" + accountSid + "/IncomingPhoneNumbers/" + sid + ".json",
|
|
190
|
+
headers: {
|
|
191
|
+
"Authorization": "Basic " + Buffer.from(accountSid + ":" + authToken).toString("base64")
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
} catch (error) {
|
|
195
|
+
if ((error == null ? void 0 : error.status) === 404) return { gone: true };
|
|
196
|
+
throw error;
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
gone: false,
|
|
200
|
+
number: result == null ? void 0 : result.phone_number,
|
|
201
|
+
smsMethod: result == null ? void 0 : result.sms_method,
|
|
202
|
+
smsUrl: result == null ? void 0 : result.sms_url,
|
|
203
|
+
status: result == null ? void 0 : result.status
|
|
204
|
+
};
|
|
205
|
+
},
|
|
206
|
+
// RE-POINT AN OWNED NUMBER'S INBOUND WEBHOOK — POST on the same resource,
|
|
207
|
+
// the exact fields purchase sets. The health sweep's repair arm.
|
|
208
|
+
updateNumber: async ({ accountSid, authToken, request: request2 = request, sid, smsUrl }) => {
|
|
209
|
+
if (!accountSid || !authToken) throw new Error("Twilio credentials missing \u2014 accountSid, authToken");
|
|
210
|
+
if (!sid) throw new Error("Twilio update needs the IncomingPhoneNumber sid");
|
|
211
|
+
if (!smsUrl) throw new Error("Twilio update needs the smsUrl to point the number at");
|
|
212
|
+
const result = await request2({
|
|
213
|
+
method: "POST",
|
|
214
|
+
type: "form",
|
|
215
|
+
url: "https://api.twilio.com/2010-04-01/Accounts/" + accountSid + "/IncomingPhoneNumbers/" + sid + ".json",
|
|
216
|
+
headers: {
|
|
217
|
+
"Authorization": "Basic " + Buffer.from(accountSid + ":" + authToken).toString("base64")
|
|
218
|
+
},
|
|
219
|
+
body: {
|
|
220
|
+
SmsUrl: smsUrl,
|
|
221
|
+
SmsMethod: "POST"
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
return {
|
|
225
|
+
smsUrl: result == null ? void 0 : result.sms_url
|
|
226
|
+
};
|
|
227
|
+
},
|
|
177
228
|
releaseNumber: async ({ accountSid, authToken, request: request2 = request, sid }) => {
|
|
178
229
|
if (!accountSid || !authToken) throw new Error("Twilio credentials missing \u2014 accountSid, authToken");
|
|
179
230
|
if (!sid) throw new Error("Twilio release needs the IncomingPhoneNumber sid");
|
package/dist/twilio.d.cts
CHANGED
|
@@ -159,6 +159,73 @@ const twilio = {
|
|
|
159
159
|
|
|
160
160
|
},
|
|
161
161
|
|
|
162
|
+
// THE NUMBER AS TWILIO HOLDS IT NOW. Same IncomingPhoneNumber resource the
|
|
163
|
+
// purchase and release above use (api.twilio.com 2010-04-01, GET
|
|
164
|
+
// /IncomingPhoneNumbers/{sid}.json) — a 404 means the number is no longer
|
|
165
|
+
// on the account, which the health sweep must distinguish from a transient,
|
|
166
|
+
// so it is answered as { gone : true } rather than thrown.
|
|
167
|
+
numberConfig : async ({ accountSid, authToken, request: request$1 = request, sid }) => {
|
|
168
|
+
|
|
169
|
+
if( ! accountSid || ! authToken ) throw new Error( 'Twilio credentials missing — accountSid, authToken' );
|
|
170
|
+
if( ! sid ) throw new Error( 'Twilio config read needs the IncomingPhoneNumber sid' );
|
|
171
|
+
|
|
172
|
+
let result;
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
|
|
176
|
+
result = await request$1({
|
|
177
|
+
method : 'GET',
|
|
178
|
+
url : 'https://api.twilio.com/2010-04-01/Accounts/' + accountSid + '/IncomingPhoneNumbers/' + sid + '.json',
|
|
179
|
+
headers : {
|
|
180
|
+
'Authorization' : 'Basic ' + Buffer.from( accountSid + ':' + authToken ).toString( 'base64' )
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
} catch ( error ) {
|
|
185
|
+
|
|
186
|
+
if( error?.status === 404 ) return { gone : true };
|
|
187
|
+
|
|
188
|
+
throw error;
|
|
189
|
+
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return {
|
|
193
|
+
gone : false,
|
|
194
|
+
number : result?.phone_number,
|
|
195
|
+
smsMethod : result?.sms_method,
|
|
196
|
+
smsUrl : result?.sms_url,
|
|
197
|
+
status : result?.status
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
// RE-POINT AN OWNED NUMBER'S INBOUND WEBHOOK — POST on the same resource,
|
|
203
|
+
// the exact fields purchase sets. The health sweep's repair arm.
|
|
204
|
+
updateNumber : async ({ accountSid, authToken, request: request$1 = request, sid, smsUrl }) => {
|
|
205
|
+
|
|
206
|
+
if( ! accountSid || ! authToken ) throw new Error( 'Twilio credentials missing — accountSid, authToken' );
|
|
207
|
+
if( ! sid ) throw new Error( 'Twilio update needs the IncomingPhoneNumber sid' );
|
|
208
|
+
if( ! smsUrl ) throw new Error( 'Twilio update needs the smsUrl to point the number at' );
|
|
209
|
+
|
|
210
|
+
const result = await request$1({
|
|
211
|
+
method : 'POST',
|
|
212
|
+
type : 'form',
|
|
213
|
+
url : 'https://api.twilio.com/2010-04-01/Accounts/' + accountSid + '/IncomingPhoneNumbers/' + sid + '.json',
|
|
214
|
+
headers : {
|
|
215
|
+
'Authorization' : 'Basic ' + Buffer.from( accountSid + ':' + authToken ).toString( 'base64' )
|
|
216
|
+
},
|
|
217
|
+
body : {
|
|
218
|
+
SmsUrl : smsUrl,
|
|
219
|
+
SmsMethod : 'POST'
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
smsUrl : result?.sms_url
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
},
|
|
228
|
+
|
|
162
229
|
releaseNumber : async ({ accountSid, authToken, request: request$1 = request, sid }) => {
|
|
163
230
|
|
|
164
231
|
if( ! accountSid || ! authToken ) throw new Error( 'Twilio credentials missing — accountSid, authToken' );
|
package/dist/twilio.d.ts
CHANGED
|
@@ -159,6 +159,73 @@ const twilio = {
|
|
|
159
159
|
|
|
160
160
|
},
|
|
161
161
|
|
|
162
|
+
// THE NUMBER AS TWILIO HOLDS IT NOW. Same IncomingPhoneNumber resource the
|
|
163
|
+
// purchase and release above use (api.twilio.com 2010-04-01, GET
|
|
164
|
+
// /IncomingPhoneNumbers/{sid}.json) — a 404 means the number is no longer
|
|
165
|
+
// on the account, which the health sweep must distinguish from a transient,
|
|
166
|
+
// so it is answered as { gone : true } rather than thrown.
|
|
167
|
+
numberConfig : async ({ accountSid, authToken, request: request$1 = request, sid }) => {
|
|
168
|
+
|
|
169
|
+
if( ! accountSid || ! authToken ) throw new Error( 'Twilio credentials missing — accountSid, authToken' );
|
|
170
|
+
if( ! sid ) throw new Error( 'Twilio config read needs the IncomingPhoneNumber sid' );
|
|
171
|
+
|
|
172
|
+
let result;
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
|
|
176
|
+
result = await request$1({
|
|
177
|
+
method : 'GET',
|
|
178
|
+
url : 'https://api.twilio.com/2010-04-01/Accounts/' + accountSid + '/IncomingPhoneNumbers/' + sid + '.json',
|
|
179
|
+
headers : {
|
|
180
|
+
'Authorization' : 'Basic ' + Buffer.from( accountSid + ':' + authToken ).toString( 'base64' )
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
} catch ( error ) {
|
|
185
|
+
|
|
186
|
+
if( error?.status === 404 ) return { gone : true };
|
|
187
|
+
|
|
188
|
+
throw error;
|
|
189
|
+
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return {
|
|
193
|
+
gone : false,
|
|
194
|
+
number : result?.phone_number,
|
|
195
|
+
smsMethod : result?.sms_method,
|
|
196
|
+
smsUrl : result?.sms_url,
|
|
197
|
+
status : result?.status
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
// RE-POINT AN OWNED NUMBER'S INBOUND WEBHOOK — POST on the same resource,
|
|
203
|
+
// the exact fields purchase sets. The health sweep's repair arm.
|
|
204
|
+
updateNumber : async ({ accountSid, authToken, request: request$1 = request, sid, smsUrl }) => {
|
|
205
|
+
|
|
206
|
+
if( ! accountSid || ! authToken ) throw new Error( 'Twilio credentials missing — accountSid, authToken' );
|
|
207
|
+
if( ! sid ) throw new Error( 'Twilio update needs the IncomingPhoneNumber sid' );
|
|
208
|
+
if( ! smsUrl ) throw new Error( 'Twilio update needs the smsUrl to point the number at' );
|
|
209
|
+
|
|
210
|
+
const result = await request$1({
|
|
211
|
+
method : 'POST',
|
|
212
|
+
type : 'form',
|
|
213
|
+
url : 'https://api.twilio.com/2010-04-01/Accounts/' + accountSid + '/IncomingPhoneNumbers/' + sid + '.json',
|
|
214
|
+
headers : {
|
|
215
|
+
'Authorization' : 'Basic ' + Buffer.from( accountSid + ':' + authToken ).toString( 'base64' )
|
|
216
|
+
},
|
|
217
|
+
body : {
|
|
218
|
+
SmsUrl : smsUrl,
|
|
219
|
+
SmsMethod : 'POST'
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
smsUrl : result?.sms_url
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
},
|
|
228
|
+
|
|
162
229
|
releaseNumber : async ({ accountSid, authToken, request: request$1 = request, sid }) => {
|
|
163
230
|
|
|
164
231
|
if( ! accountSid || ! authToken ) throw new Error( 'Twilio credentials missing — accountSid, authToken' );
|
package/dist/twilio.js
CHANGED
|
@@ -149,6 +149,57 @@ var twilio = {
|
|
|
149
149
|
sid: result == null ? void 0 : result.sid
|
|
150
150
|
};
|
|
151
151
|
},
|
|
152
|
+
// THE NUMBER AS TWILIO HOLDS IT NOW. Same IncomingPhoneNumber resource the
|
|
153
|
+
// purchase and release above use (api.twilio.com 2010-04-01, GET
|
|
154
|
+
// /IncomingPhoneNumbers/{sid}.json) — a 404 means the number is no longer
|
|
155
|
+
// on the account, which the health sweep must distinguish from a transient,
|
|
156
|
+
// so it is answered as { gone : true } rather than thrown.
|
|
157
|
+
numberConfig: async ({ accountSid, authToken, request: request2 = request, sid }) => {
|
|
158
|
+
if (!accountSid || !authToken) throw new Error("Twilio credentials missing \u2014 accountSid, authToken");
|
|
159
|
+
if (!sid) throw new Error("Twilio config read needs the IncomingPhoneNumber sid");
|
|
160
|
+
let result;
|
|
161
|
+
try {
|
|
162
|
+
result = await request2({
|
|
163
|
+
method: "GET",
|
|
164
|
+
url: "https://api.twilio.com/2010-04-01/Accounts/" + accountSid + "/IncomingPhoneNumbers/" + sid + ".json",
|
|
165
|
+
headers: {
|
|
166
|
+
"Authorization": "Basic " + Buffer.from(accountSid + ":" + authToken).toString("base64")
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
} catch (error) {
|
|
170
|
+
if ((error == null ? void 0 : error.status) === 404) return { gone: true };
|
|
171
|
+
throw error;
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
gone: false,
|
|
175
|
+
number: result == null ? void 0 : result.phone_number,
|
|
176
|
+
smsMethod: result == null ? void 0 : result.sms_method,
|
|
177
|
+
smsUrl: result == null ? void 0 : result.sms_url,
|
|
178
|
+
status: result == null ? void 0 : result.status
|
|
179
|
+
};
|
|
180
|
+
},
|
|
181
|
+
// RE-POINT AN OWNED NUMBER'S INBOUND WEBHOOK — POST on the same resource,
|
|
182
|
+
// the exact fields purchase sets. The health sweep's repair arm.
|
|
183
|
+
updateNumber: async ({ accountSid, authToken, request: request2 = request, sid, smsUrl }) => {
|
|
184
|
+
if (!accountSid || !authToken) throw new Error("Twilio credentials missing \u2014 accountSid, authToken");
|
|
185
|
+
if (!sid) throw new Error("Twilio update needs the IncomingPhoneNumber sid");
|
|
186
|
+
if (!smsUrl) throw new Error("Twilio update needs the smsUrl to point the number at");
|
|
187
|
+
const result = await request2({
|
|
188
|
+
method: "POST",
|
|
189
|
+
type: "form",
|
|
190
|
+
url: "https://api.twilio.com/2010-04-01/Accounts/" + accountSid + "/IncomingPhoneNumbers/" + sid + ".json",
|
|
191
|
+
headers: {
|
|
192
|
+
"Authorization": "Basic " + Buffer.from(accountSid + ":" + authToken).toString("base64")
|
|
193
|
+
},
|
|
194
|
+
body: {
|
|
195
|
+
SmsUrl: smsUrl,
|
|
196
|
+
SmsMethod: "POST"
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
return {
|
|
200
|
+
smsUrl: result == null ? void 0 : result.sms_url
|
|
201
|
+
};
|
|
202
|
+
},
|
|
152
203
|
releaseNumber: async ({ accountSid, authToken, request: request2 = request, sid }) => {
|
|
153
204
|
if (!accountSid || !authToken) throw new Error("Twilio credentials missing \u2014 accountSid, authToken");
|
|
154
205
|
if (!sid) throw new Error("Twilio release needs the IncomingPhoneNumber sid");
|
package/package.json
CHANGED