@drawbridge/drawbridge-utils 0.0.121 → 0.0.124
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 +447 -127
- package/dist/connections/index.d.cts +605 -137
- package/dist/connections/index.d.ts +605 -137
- package/dist/connections/index.js +440 -120
- package/dist/providers.cjs +452 -164
- package/dist/providers.d.cts +40 -60
- package/dist/providers.d.ts +40 -60
- package/dist/providers.js +445 -157
- package/package.json +1 -1
package/dist/providers.d.cts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { mergeSettings } from './connections/index.cjs';
|
|
1
|
+
import { connections, mergeSettings } from './connections/index.cjs';
|
|
2
2
|
import { decrypt, encrypt } from './encrypt.cjs';
|
|
3
3
|
import './connections/oauth.cjs';
|
|
4
4
|
import 'node:crypto';
|
|
5
|
+
import './phone.cjs';
|
|
6
|
+
import 'libphonenumber-js';
|
|
5
7
|
import './http.cjs';
|
|
6
8
|
import './pricing.cjs';
|
|
7
9
|
import './plans.cjs';
|
|
@@ -16,8 +18,6 @@ import './billing.cjs';
|
|
|
16
18
|
import './transactions.cjs';
|
|
17
19
|
import '@drawbridge/drawbridge-telemetry';
|
|
18
20
|
import './email.cjs';
|
|
19
|
-
import './phone.cjs';
|
|
20
|
-
import 'libphonenumber-js';
|
|
21
21
|
import './safe-http.cjs';
|
|
22
22
|
import 'dns';
|
|
23
23
|
import 'node:http';
|
|
@@ -42,60 +42,41 @@ import './token.cjs';
|
|
|
42
42
|
// the others have already rotated away.
|
|
43
43
|
|
|
44
44
|
|
|
45
|
-
// WHAT AN ADMIN TYPES IN, per vendor.
|
|
45
|
+
// WHAT AN ADMIN TYPES IN, per vendor — READ FROM THE MANIFESTS.
|
|
46
46
|
//
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
//
|
|
47
|
+
// This was a table here, duplicating what every vendor file already knew. A
|
|
48
|
+
// vendor's credentials and its `requires` name the same things, and keeping
|
|
49
|
+
// them in two files meant a manifest could require a name that no admin screen
|
|
50
|
+
// offered to fill — the exact shape of "declared in one place, entered in
|
|
51
|
+
// another" these manifests exist to close.
|
|
50
52
|
//
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
// without a token — requiring it would make the whole drawbridge provider
|
|
65
|
-
// read not-live over something no merchant ever sees.
|
|
66
|
-
{ input : 'password', key : 'hubspotToken', env : 'HUBSPOT_ACCESS_TOKEN', label : 'HubSpot access token', message : 'Drawbridge\'s own CRM portal. Internal — no merchant sees this.', redact : true },
|
|
67
|
-
// Optional: SENDGRID_SEND_FROM_ADDRESS is not boot-required in sync
|
|
68
|
-
// either. Unset, it degrades to the account sender rather than
|
|
69
|
-
// refusing to start.
|
|
70
|
-
{ input : 'email', key : 'leadSender', env : 'SENDGRID_SEND_FROM_ADDRESS', label : 'Lead sender', message : 'The default for lead-facing mail when a merchant has not verified their own domain.' },
|
|
71
|
-
{ input : 'text', key : 'smsFrom', env : 'TWILIO_ACCOUNT_FROM', label : 'SMS number', required : true },
|
|
72
|
-
{ input : 'password', key : 'smsSid', env : 'TWILIO_ACCOUNT_SID', label : 'Twilio account SID', redact : true, required : true },
|
|
73
|
-
{ input : 'password', key : 'smsToken', env : 'TWILIO_AUTH_TOKEN', label : 'Twilio auth token', redact : true, required : true }
|
|
74
|
-
],
|
|
75
|
-
klaviyo : [
|
|
76
|
-
{ input : 'text', key : 'clientId', env : 'KLAVIYO_OAUTH_CLIENT_ID', label : 'Client ID', required : true },
|
|
77
|
-
{ input : 'password', key : 'clientSecret', env : 'KLAVIYO_OAUTH_CLIENT_SECRET', label : 'Client secret', redact : true, required : true }
|
|
78
|
-
],
|
|
79
|
-
mailchimp : [
|
|
80
|
-
{ input : 'text', key : 'clientId', env : 'MAILCHIMP_OAUTH_CLIENT_ID', label : 'Client ID', required : true },
|
|
81
|
-
{ input : 'password', key : 'clientSecret', env : 'MAILCHIMP_OAUTH_CLIENT_SECRET', label : 'Client secret', redact : true, required : true }
|
|
82
|
-
],
|
|
83
|
-
shopify : [
|
|
84
|
-
{ input : 'text', key : 'apiKey', env : 'SHOPIFY_API_KEY', label : 'API key', required : true },
|
|
85
|
-
{ input : 'password', key : 'apiSecret', env : 'SHOPIFY_API_SECRET', label : 'API secret', redact : true, required : true },
|
|
86
|
-
{ input : 'text', key : 'appHandle', env : 'SHOPIFY_APP_HANDLE', label : 'App handle', required : true },
|
|
87
|
-
{ input : 'text', key : 'listingUrl', env : 'SHOPIFY_APP_LISTING_URL', label : 'App listing URL', required : true }
|
|
88
|
-
]
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
// Object.hasOwn, not `FIELDS[ slug ] ||` — a bare property read walks the
|
|
92
|
-
// prototype chain, and FIELDS[ 'constructor' ] is a function whose .length is
|
|
93
|
-
// 1, so the route's "does this vendor exist" guard passed for it and reached
|
|
53
|
+
// Each field's `credential` is the NAME the rest of the system asks for that
|
|
54
|
+
// value by. It is not an environment variable and there is no fallback to one:
|
|
55
|
+
// the names simply began life as env vars and were kept as the vocabulary, so
|
|
56
|
+
// `requires` and auth.oauth.client did not have to change when the storage
|
|
57
|
+
// moved into the database.
|
|
58
|
+
//
|
|
59
|
+
// So the declaration lives on the manifest as `provider : { fields }`, build()
|
|
60
|
+
// checks its shape at import, and this module is now only the reading, memoizing
|
|
61
|
+
// and encrypting around it.
|
|
62
|
+
//
|
|
63
|
+
// Object.hasOwn, not `connections[ slug ] ||` — a bare property read walks the
|
|
64
|
+
// prototype chain, and connections[ 'constructor' ] is a function whose .length
|
|
65
|
+
// is 1, so the route's "does this vendor exist" guard passed for it and reached
|
|
94
66
|
// the database before throwing.
|
|
95
|
-
const providerFields = ( slug ) =>
|
|
67
|
+
const providerFields = ( slug ) => (
|
|
68
|
+
Object.hasOwn( connections, slug ) ? ( connections[ slug ].provider?.fields || [] ) : []
|
|
69
|
+
);
|
|
96
70
|
|
|
97
71
|
// The vendors an admin can configure, in a stable order.
|
|
98
|
-
|
|
72
|
+
//
|
|
73
|
+
// DERIVED FROM WHO DECLARES A PROVIDER BLOCK, not from the catalog: `webhook` is
|
|
74
|
+
// a connection with no vendor behind it — nothing to authenticate against and
|
|
75
|
+
// nothing to type — so it must not appear on a screen whose whole purpose is
|
|
76
|
+
// entering credentials.
|
|
77
|
+
const providerSlugs = () => Object.keys( connections )
|
|
78
|
+
.filter( ( slug ) => connections[ slug ].provider )
|
|
79
|
+
.sort();
|
|
99
80
|
|
|
100
81
|
// LIVE IS DERIVED, never stored. A stored flag is a second thing to keep in
|
|
101
82
|
// sync and goes stale the moment a row is edited by hand.
|
|
@@ -270,17 +251,16 @@ const saveProviderSettings = async ({ authenticated, clear, controller, settings
|
|
|
270
251
|
const providerEnvNames = () => new Set(
|
|
271
252
|
providerSlugs()
|
|
272
253
|
.flatMap( ( slug ) => providerFields( slug ) )
|
|
273
|
-
.map( ( field ) => field.
|
|
254
|
+
.map( ( field ) => field.credential )
|
|
274
255
|
.filter( Boolean )
|
|
275
256
|
);
|
|
276
257
|
|
|
277
|
-
// EVERY STORED CREDENTIAL,
|
|
258
|
+
// EVERY STORED CREDENTIAL, KEYED BY ITS NAME.
|
|
278
259
|
//
|
|
279
|
-
// Keyed by
|
|
280
|
-
// manifests already speak: `requires` names
|
|
281
|
-
// names them too. Handing availableConnections this map
|
|
282
|
-
//
|
|
283
|
-
// repo keep reading a plain synchronous object.
|
|
260
|
+
// Keyed by each field's `credential`, because that is the vocabulary the
|
|
261
|
+
// manifests already speak: `requires` names credentials, and auth.oauth.client
|
|
262
|
+
// names them too. Handing availableConnections this map is what makes stored
|
|
263
|
+
// credentials answer the question the manifests were already asking.
|
|
284
264
|
//
|
|
285
265
|
// A field with no value is OMITTED rather than set empty, so `requires` sees
|
|
286
266
|
// the same absence it would for an unset variable.
|
|
@@ -307,7 +287,7 @@ const providerCredentials = async ({ controller }) => {
|
|
|
307
287
|
|
|
308
288
|
const value = settings?.[ field.key ];
|
|
309
289
|
|
|
310
|
-
if( field.
|
|
290
|
+
if( field.credential && value ) credentials[ field.credential ] = value;
|
|
311
291
|
|
|
312
292
|
}
|
|
313
293
|
|
package/dist/providers.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { mergeSettings } from './connections/index.js';
|
|
1
|
+
import { connections, mergeSettings } from './connections/index.js';
|
|
2
2
|
import { decrypt, encrypt } from './encrypt.js';
|
|
3
3
|
import './connections/oauth.js';
|
|
4
4
|
import 'node:crypto';
|
|
5
|
+
import './phone.js';
|
|
6
|
+
import 'libphonenumber-js';
|
|
5
7
|
import './http.js';
|
|
6
8
|
import './pricing.js';
|
|
7
9
|
import './plans.js';
|
|
@@ -16,8 +18,6 @@ import './billing.js';
|
|
|
16
18
|
import './transactions.js';
|
|
17
19
|
import '@drawbridge/drawbridge-telemetry';
|
|
18
20
|
import './email.js';
|
|
19
|
-
import './phone.js';
|
|
20
|
-
import 'libphonenumber-js';
|
|
21
21
|
import './safe-http.js';
|
|
22
22
|
import 'dns';
|
|
23
23
|
import 'node:http';
|
|
@@ -42,60 +42,41 @@ import './token.js';
|
|
|
42
42
|
// the others have already rotated away.
|
|
43
43
|
|
|
44
44
|
|
|
45
|
-
// WHAT AN ADMIN TYPES IN, per vendor.
|
|
45
|
+
// WHAT AN ADMIN TYPES IN, per vendor — READ FROM THE MANIFESTS.
|
|
46
46
|
//
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
//
|
|
47
|
+
// This was a table here, duplicating what every vendor file already knew. A
|
|
48
|
+
// vendor's credentials and its `requires` name the same things, and keeping
|
|
49
|
+
// them in two files meant a manifest could require a name that no admin screen
|
|
50
|
+
// offered to fill — the exact shape of "declared in one place, entered in
|
|
51
|
+
// another" these manifests exist to close.
|
|
50
52
|
//
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
// without a token — requiring it would make the whole drawbridge provider
|
|
65
|
-
// read not-live over something no merchant ever sees.
|
|
66
|
-
{ input : 'password', key : 'hubspotToken', env : 'HUBSPOT_ACCESS_TOKEN', label : 'HubSpot access token', message : 'Drawbridge\'s own CRM portal. Internal — no merchant sees this.', redact : true },
|
|
67
|
-
// Optional: SENDGRID_SEND_FROM_ADDRESS is not boot-required in sync
|
|
68
|
-
// either. Unset, it degrades to the account sender rather than
|
|
69
|
-
// refusing to start.
|
|
70
|
-
{ input : 'email', key : 'leadSender', env : 'SENDGRID_SEND_FROM_ADDRESS', label : 'Lead sender', message : 'The default for lead-facing mail when a merchant has not verified their own domain.' },
|
|
71
|
-
{ input : 'text', key : 'smsFrom', env : 'TWILIO_ACCOUNT_FROM', label : 'SMS number', required : true },
|
|
72
|
-
{ input : 'password', key : 'smsSid', env : 'TWILIO_ACCOUNT_SID', label : 'Twilio account SID', redact : true, required : true },
|
|
73
|
-
{ input : 'password', key : 'smsToken', env : 'TWILIO_AUTH_TOKEN', label : 'Twilio auth token', redact : true, required : true }
|
|
74
|
-
],
|
|
75
|
-
klaviyo : [
|
|
76
|
-
{ input : 'text', key : 'clientId', env : 'KLAVIYO_OAUTH_CLIENT_ID', label : 'Client ID', required : true },
|
|
77
|
-
{ input : 'password', key : 'clientSecret', env : 'KLAVIYO_OAUTH_CLIENT_SECRET', label : 'Client secret', redact : true, required : true }
|
|
78
|
-
],
|
|
79
|
-
mailchimp : [
|
|
80
|
-
{ input : 'text', key : 'clientId', env : 'MAILCHIMP_OAUTH_CLIENT_ID', label : 'Client ID', required : true },
|
|
81
|
-
{ input : 'password', key : 'clientSecret', env : 'MAILCHIMP_OAUTH_CLIENT_SECRET', label : 'Client secret', redact : true, required : true }
|
|
82
|
-
],
|
|
83
|
-
shopify : [
|
|
84
|
-
{ input : 'text', key : 'apiKey', env : 'SHOPIFY_API_KEY', label : 'API key', required : true },
|
|
85
|
-
{ input : 'password', key : 'apiSecret', env : 'SHOPIFY_API_SECRET', label : 'API secret', redact : true, required : true },
|
|
86
|
-
{ input : 'text', key : 'appHandle', env : 'SHOPIFY_APP_HANDLE', label : 'App handle', required : true },
|
|
87
|
-
{ input : 'text', key : 'listingUrl', env : 'SHOPIFY_APP_LISTING_URL', label : 'App listing URL', required : true }
|
|
88
|
-
]
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
// Object.hasOwn, not `FIELDS[ slug ] ||` — a bare property read walks the
|
|
92
|
-
// prototype chain, and FIELDS[ 'constructor' ] is a function whose .length is
|
|
93
|
-
// 1, so the route's "does this vendor exist" guard passed for it and reached
|
|
53
|
+
// Each field's `credential` is the NAME the rest of the system asks for that
|
|
54
|
+
// value by. It is not an environment variable and there is no fallback to one:
|
|
55
|
+
// the names simply began life as env vars and were kept as the vocabulary, so
|
|
56
|
+
// `requires` and auth.oauth.client did not have to change when the storage
|
|
57
|
+
// moved into the database.
|
|
58
|
+
//
|
|
59
|
+
// So the declaration lives on the manifest as `provider : { fields }`, build()
|
|
60
|
+
// checks its shape at import, and this module is now only the reading, memoizing
|
|
61
|
+
// and encrypting around it.
|
|
62
|
+
//
|
|
63
|
+
// Object.hasOwn, not `connections[ slug ] ||` — a bare property read walks the
|
|
64
|
+
// prototype chain, and connections[ 'constructor' ] is a function whose .length
|
|
65
|
+
// is 1, so the route's "does this vendor exist" guard passed for it and reached
|
|
94
66
|
// the database before throwing.
|
|
95
|
-
const providerFields = ( slug ) =>
|
|
67
|
+
const providerFields = ( slug ) => (
|
|
68
|
+
Object.hasOwn( connections, slug ) ? ( connections[ slug ].provider?.fields || [] ) : []
|
|
69
|
+
);
|
|
96
70
|
|
|
97
71
|
// The vendors an admin can configure, in a stable order.
|
|
98
|
-
|
|
72
|
+
//
|
|
73
|
+
// DERIVED FROM WHO DECLARES A PROVIDER BLOCK, not from the catalog: `webhook` is
|
|
74
|
+
// a connection with no vendor behind it — nothing to authenticate against and
|
|
75
|
+
// nothing to type — so it must not appear on a screen whose whole purpose is
|
|
76
|
+
// entering credentials.
|
|
77
|
+
const providerSlugs = () => Object.keys( connections )
|
|
78
|
+
.filter( ( slug ) => connections[ slug ].provider )
|
|
79
|
+
.sort();
|
|
99
80
|
|
|
100
81
|
// LIVE IS DERIVED, never stored. A stored flag is a second thing to keep in
|
|
101
82
|
// sync and goes stale the moment a row is edited by hand.
|
|
@@ -270,17 +251,16 @@ const saveProviderSettings = async ({ authenticated, clear, controller, settings
|
|
|
270
251
|
const providerEnvNames = () => new Set(
|
|
271
252
|
providerSlugs()
|
|
272
253
|
.flatMap( ( slug ) => providerFields( slug ) )
|
|
273
|
-
.map( ( field ) => field.
|
|
254
|
+
.map( ( field ) => field.credential )
|
|
274
255
|
.filter( Boolean )
|
|
275
256
|
);
|
|
276
257
|
|
|
277
|
-
// EVERY STORED CREDENTIAL,
|
|
258
|
+
// EVERY STORED CREDENTIAL, KEYED BY ITS NAME.
|
|
278
259
|
//
|
|
279
|
-
// Keyed by
|
|
280
|
-
// manifests already speak: `requires` names
|
|
281
|
-
// names them too. Handing availableConnections this map
|
|
282
|
-
//
|
|
283
|
-
// repo keep reading a plain synchronous object.
|
|
260
|
+
// Keyed by each field's `credential`, because that is the vocabulary the
|
|
261
|
+
// manifests already speak: `requires` names credentials, and auth.oauth.client
|
|
262
|
+
// names them too. Handing availableConnections this map is what makes stored
|
|
263
|
+
// credentials answer the question the manifests were already asking.
|
|
284
264
|
//
|
|
285
265
|
// A field with no value is OMITTED rather than set empty, so `requires` sees
|
|
286
266
|
// the same absence it would for an unset variable.
|
|
@@ -307,7 +287,7 @@ const providerCredentials = async ({ controller }) => {
|
|
|
307
287
|
|
|
308
288
|
const value = settings?.[ field.key ];
|
|
309
289
|
|
|
310
|
-
if( field.
|
|
290
|
+
if( field.credential && value ) credentials[ field.credential ] = value;
|
|
311
291
|
|
|
312
292
|
}
|
|
313
293
|
|