@drawbridge/drawbridge-utils 0.0.176 → 0.0.178

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.
Files changed (69) hide show
  1. package/dist/admin-B9ZaLvan.d.cts +697 -0
  2. package/dist/admin-C3HtEM6h.d.ts +697 -0
  3. package/dist/billing-Bc4yo9XG.d.cts +175 -0
  4. package/dist/billing-mNsKflmQ.d.ts +175 -0
  5. package/dist/billing.d.cts +1 -1
  6. package/dist/billing.d.ts +1 -1
  7. package/dist/connections/index.cjs +3391 -271
  8. package/dist/connections/index.d.cts +13 -4
  9. package/dist/connections/index.d.ts +13 -4
  10. package/dist/connections/index.js +3388 -270
  11. package/dist/features.cjs +3080 -241
  12. package/dist/features.d.cts +13 -4
  13. package/dist/features.d.ts +13 -4
  14. package/dist/features.js +3120 -275
  15. package/dist/http.cjs +10 -1
  16. package/dist/http.d.cts +10 -1
  17. package/dist/http.d.ts +10 -1
  18. package/dist/http.js +10 -1
  19. package/dist/{index-qY18QITf.d.cts → index-C2rxasGZ.d.cts} +2670 -354
  20. package/dist/{index-B8JhYfvU.d.ts → index-DOYCXtd7.d.ts} +2670 -354
  21. package/dist/oauth/index.d.cts +1 -1
  22. package/dist/oauth/index.d.ts +1 -1
  23. package/dist/oauth-BJDh0sdM.d.cts +527 -0
  24. package/dist/oauth-DveZMLHx.d.ts +527 -0
  25. package/dist/partner-BOZltuh2.d.ts +94 -0
  26. package/dist/partner-ed2OfW1J.d.cts +94 -0
  27. package/dist/plans.cjs +3079 -240
  28. package/dist/plans.d.cts +13 -4
  29. package/dist/plans.d.ts +13 -4
  30. package/dist/plans.js +3120 -275
  31. package/dist/pricing.cjs +3112 -273
  32. package/dist/pricing.d.cts +13 -4
  33. package/dist/pricing.d.ts +13 -4
  34. package/dist/pricing.js +3117 -272
  35. package/dist/providers.cjs +3082 -262
  36. package/dist/providers.d.cts +12 -3
  37. package/dist/providers.d.ts +12 -3
  38. package/dist/providers.js +3086 -260
  39. package/dist/sendgrid.cjs +10 -1
  40. package/dist/sendgrid.js +10 -1
  41. package/dist/shopify/admin.cjs +562 -0
  42. package/dist/shopify/admin.d.cts +3 -0
  43. package/dist/shopify/admin.d.ts +3 -0
  44. package/dist/shopify/admin.js +528 -0
  45. package/dist/shopify/billing.cjs +166 -0
  46. package/dist/shopify/billing.d.cts +3 -0
  47. package/dist/shopify/billing.d.ts +3 -0
  48. package/dist/shopify/billing.js +140 -0
  49. package/dist/shopify/constants.cjs +63 -0
  50. package/dist/shopify/constants.d.cts +58 -0
  51. package/dist/shopify/constants.d.ts +58 -0
  52. package/dist/shopify/constants.js +32 -0
  53. package/dist/shopify/oauth.cjs +509 -0
  54. package/dist/shopify/oauth.d.cts +7 -0
  55. package/dist/shopify/oauth.d.ts +7 -0
  56. package/dist/shopify/oauth.js +466 -0
  57. package/dist/shopify/partner.cjs +156 -0
  58. package/dist/shopify/partner.d.cts +3 -0
  59. package/dist/shopify/partner.d.ts +3 -0
  60. package/dist/shopify/partner.js +130 -0
  61. package/dist/shopify/storefront.cjs +611 -0
  62. package/dist/shopify/storefront.d.cts +3 -0
  63. package/dist/shopify/storefront.d.ts +3 -0
  64. package/dist/shopify/storefront.js +576 -0
  65. package/dist/storefront-C8FKOGeD.d.cts +659 -0
  66. package/dist/storefront-DJFGLqPl.d.ts +659 -0
  67. package/dist/twilio.cjs +10 -1
  68. package/dist/twilio.js +10 -1
  69. package/package.json +98 -68
@@ -1,4 +1,4 @@
1
- import { generate, hash } from '../token.cjs';
1
+ import { hash, generate } from '../token.cjs';
2
2
  export { compare } from '../token.cjs';
3
3
  import 'crypto';
4
4
 
@@ -1,4 +1,4 @@
1
- import { generate, hash } from '../token.js';
1
+ import { hash, generate } from '../token.js';
2
2
  export { compare } from '../token.js';
3
3
  import 'crypto';
4
4
 
@@ -0,0 +1,527 @@
1
+ import { encrypt, decrypt } from './encrypt.cjs';
2
+ import { a as adminFetch } from './admin-B9ZaLvan.cjs';
3
+ import { SHOPIFY_REQUIRED_SCOPES, SHOPIFY_ADMIN_API_VERSION, ACCESS_TOKEN_REFRESH_BUFFER_MS, REFRESH_TOKEN_LIFETIME_MS } from './shopify/constants.cjs';
4
+
5
+ // The app's client_id / client_secret live encrypted in the `provider`
6
+ // collection and are read at the point of use by the calling app — this
7
+ // package never reads them from the environment. Every credential is
8
+ // therefore a required parameter, and a missing one MUST throw here rather
9
+ // than fall through: Shopify answers a token grant carrying no client_id with
10
+ // an opaque OAuth error page, which reads as "the app is gone" rather than
11
+ // "the caller passed no credential" — a config error with nothing in the logs
12
+ // to say so.
13
+
14
+ const required = ( name, value ) => {
15
+
16
+ if( ! value ){
17
+
18
+ throw new Error( 'Shopify ' + name + ' is required' );
19
+
20
+ }
21
+ return value;
22
+
23
+ };
24
+
25
+ // Diff a store's granted scopes (the `scope` string Shopify returns from
26
+ // token exchange, persisted on the shop record's settings) against the
27
+ // canonical required list. Shopify omits implied grants — write_foo covers
28
+ // read_foo (same for the unauthenticated_ pair) — so a required read scope
29
+ // counts as satisfied when its write counterpart was granted. Returns the
30
+ // required scopes the store is missing; non-empty means the merchant needs
31
+ // to re-open the app in Shopify admin (managed install re-prompts there).
32
+ const missingScopes = ( granted ) => {
33
+
34
+ const grantedSet = new Set(
35
+ ( Array.isArray( granted ) ? granted : String( granted || '' ).split( ',' ) )
36
+ .map( ( scope ) => scope.trim() )
37
+ .filter( Boolean )
38
+ );
39
+
40
+ const satisfied = ( scope ) =>
41
+ grantedSet.has( scope ) || grantedSet.has( scope.replace( /(^|_)read_/, '$1write_' ) );
42
+
43
+ return SHOPIFY_REQUIRED_SCOPES.filter( ( scope ) => ! satisfied( scope ) );
44
+
45
+ };
46
+
47
+ // Bare-fetch admin endpoint health check used by refreshAdminToken to
48
+ // validate a freshly-rotated access token before persisting it. Throws on
49
+ // failure so refreshAdminToken aborts the connection update if the new
50
+ // token doesn't authenticate. A minimal GraphQL query rather than a REST
51
+ // resource fetch — the Admin REST API is legacy and App-Store review
52
+ // requires GraphQL-only.
53
+
54
+ const ping = async ({ fetcher, adminAccessToken, domain }) => {
55
+
56
+ const response = await fetch(
57
+ `https://${ domain }/admin/api/${ SHOPIFY_ADMIN_API_VERSION }/graphql.json`,
58
+ {
59
+ body : JSON.stringify({ query : '{ shop { name } }' }),
60
+ headers : {
61
+ 'Content-Type' : 'application/json',
62
+ 'X-Shopify-Access-Token' : adminAccessToken
63
+ },
64
+ method : 'POST'
65
+ }
66
+ );
67
+
68
+ if( ! response.ok ){
69
+
70
+ const text = await response.text().catch( () => '' );
71
+ const error = new Error( response.status + ': ' + text );
72
+
73
+ error.status = response.status;
74
+
75
+ throw error;
76
+
77
+ }
78
+ // GraphQL can 200 with a top-level errors array (e.g. a token that
79
+ // authenticates but can't query) — treat that as a failed ping too.
80
+ const { errors } = await response.json().catch( () => ({}) );
81
+
82
+ if( errors?.length ){
83
+
84
+ throw new Error( 'GraphQL: ' + ( errors[ 0 ]?.message || 'unknown error' ) );
85
+
86
+ }
87
+ };
88
+
89
+ // Shopify's OAuth token endpoint reports a failed grant one of two ways: a
90
+ // JSON body ({ error, error_description }, the documented shape) or — for
91
+ // some rejections, e.g. a client_id whose app no longer exists at the shop —
92
+ // a rendered HTML error page whose <title> reads "NNN - Oauth error <code>".
93
+ // Extract a stable code from either so callers can act on it (see
94
+ // application_cannot_be_found in drawbridge-sync's health check) instead of
95
+ // string-matching the raw page body.
96
+ const OAUTH_ERROR_TITLE_PATTERN = /Oauth error (\w+)/i;
97
+
98
+ const parseOAuthErrorCode = ( text ) => {
99
+
100
+ try {
101
+
102
+ const parsed = JSON.parse( text );
103
+
104
+ if( parsed?.error ) return parsed.error;
105
+
106
+ } catch {}
107
+ return text.match( OAUTH_ERROR_TITLE_PATTERN )?.[ 1 ] || null;
108
+
109
+ };
110
+
111
+ const shopifyOAuthFetch = async ( url, body ) => {
112
+
113
+ const response = await fetch( url, {
114
+ method : 'POST',
115
+ headers : {
116
+ 'Content-Type' : 'application/json'
117
+ },
118
+ body : JSON.stringify( body )
119
+ });
120
+
121
+ if( ! response.ok ){
122
+
123
+ const text = await response.text().catch( () => '' );
124
+ const error = new Error( response.status + ': ' + text );
125
+
126
+ error.status = response.status;
127
+ error.code = parseOAuthErrorCode( text );
128
+
129
+ throw error;
130
+
131
+ }
132
+ return response.json();
133
+
134
+ };
135
+
136
+ // Install-time token-setup calls (shop lookup, storefront access tokens)
137
+ // go through the Admin GraphQL client in admin.js — the REST endpoints
138
+ // they used to hit are legacy and App-Store review requires GraphQL-only.
139
+
140
+ // Fetch the shop record (currency, id, name, myshopifyDomain) for a connected store.
141
+ // `id` is returned as the bare numeric string (the GID tail) — it persists
142
+ // to connection.source.id, and billing's toShopGid() re-derives the GID.
143
+
144
+ const getShop = async ({ fetcher, adminAccessToken, shop }) => {
145
+
146
+ const data = await adminFetch({
147
+ fetcher,
148
+ adminAccessToken,
149
+ domain : shop,
150
+ query : `{
151
+ shop {
152
+ currencyCode
153
+ id
154
+ myshopifyDomain
155
+ name
156
+ }
157
+ }`
158
+ });
159
+
160
+ const shopData = data?.shop;
161
+
162
+ if( ! shopData?.id ){
163
+
164
+ throw new Error( 'Shopify shop lookup failed: no shop returned' );
165
+
166
+ }
167
+ return {
168
+ currency : shopData.currencyCode || null,
169
+ id : shopData.id.split( '/' ).pop(),
170
+ myshopifyDomain : shopData.myshopifyDomain,
171
+ name : shopData.name
172
+ };
173
+
174
+ };
175
+
176
+ // Issue a Storefront access token titled 'Drawbridge', reaping any prior
177
+ // Drawbridge-titled tokens first — Shopify caps these at 100/shop and they're
178
+ // immutable, so a fresh OAuth scope set requires minting a new one.
179
+
180
+ const createStorefrontToken = async ({ fetcher, adminAccessToken, shop }) => {
181
+
182
+ try {
183
+
184
+ const listed = await adminFetch({
185
+ fetcher,
186
+ adminAccessToken,
187
+ domain : shop,
188
+ query : `{
189
+ shop {
190
+ storefrontAccessTokens(first: 100) {
191
+ edges {
192
+ node {
193
+ id
194
+ title
195
+ }
196
+ }
197
+ }
198
+ }
199
+ }`
200
+ });
201
+
202
+ const existing = ( listed?.shop?.storefrontAccessTokens?.edges || [] ).map( ( edge ) => edge?.node );
203
+ const orphaned = existing.filter( ( token ) => token?.title === 'Drawbridge' );
204
+
205
+ await Promise.allSettled(
206
+ orphaned.map( ( token ) => adminFetch({
207
+ adminAccessToken,
208
+ domain : shop,
209
+ query : `
210
+ mutation StorefrontAccessTokenDelete($input: StorefrontAccessTokenDeleteInput!) {
211
+ storefrontAccessTokenDelete(input: $input) {
212
+ deletedStorefrontAccessTokenId
213
+ userErrors {
214
+ field
215
+ message
216
+ }
217
+ }
218
+ }
219
+ `,
220
+ variables : {
221
+ input : {
222
+ id : token.id
223
+ }
224
+ }
225
+ }) )
226
+ );
227
+
228
+ } catch {}
229
+
230
+ const created = await adminFetch({
231
+ fetcher,
232
+ adminAccessToken,
233
+ domain : shop,
234
+ query : `
235
+ mutation StorefrontAccessTokenCreate($input: StorefrontAccessTokenInput!) {
236
+ storefrontAccessTokenCreate(input: $input) {
237
+ storefrontAccessToken {
238
+ accessToken
239
+ }
240
+ userErrors {
241
+ field
242
+ message
243
+ }
244
+ }
245
+ }
246
+ `,
247
+ variables : {
248
+ input : {
249
+ title : 'Drawbridge'
250
+ }
251
+ }
252
+ });
253
+
254
+ const createErrors = created?.storefrontAccessTokenCreate?.userErrors;
255
+
256
+ if( createErrors?.length ){
257
+
258
+ throw new Error( 'Shopify storefront token create failed: ' + createErrors[ 0 ].message );
259
+
260
+ }
261
+ return created?.storefrontAccessTokenCreate?.storefrontAccessToken?.accessToken || null;
262
+
263
+ };
264
+
265
+ // A Shopify connection carries its token blob one of two ways:
266
+ // * legacy 1:1 install — the token blob lives on `connection.settings` directly.
267
+ // * embedded / multi-org — `connection.settings` is a pointer `{ ref:'shop', shop }`
268
+ // and the token of record lives on the shared per-shop `shop` record: the offline
269
+ // session in `shop.settings` (accessToken/expires/refreshToken/refreshTokenExpires)
270
+ // and the long-lived storefront token in `shop.storefront` ({ token }). N org
271
+ // connections for the same store share that one record.
272
+ // resolveTokenContext normalizes both into a single settings blob the callers read
273
+ // (getAdminToken / product sync / storefront reads) and records where a token rotation
274
+ // must be written back (`target`). Following the pointer needs a `controller` to read
275
+ // the shop record; callers all pass one.
276
+
277
+ const resolveTokenContext = async ({ connection, controller }) => {
278
+
279
+ const decrypted = connection?.settings ? decrypt( connection.settings ) : {};
280
+
281
+ // Legacy: the token blob is the connection's own settings. `raw` carries the
282
+ // stored (encrypted) blob so a rotation can compare-and-swap against it.
283
+ if( decrypted?.ref !== 'shop' ){
284
+
285
+ return {
286
+ raw : connection?.settings || null,
287
+ session : null,
288
+ settings : decrypted,
289
+ shop : null,
290
+ target : 'connection'
291
+ };
292
+
293
+ }
294
+ const shop = decrypted.shop;
295
+
296
+ // Pointer with no way (or nothing) to resolve — surface an empty blob so callers
297
+ // treat it as "no token" rather than throwing.
298
+ if( ! controller || ! shop ){
299
+
300
+ return { raw : null, session : {}, settings : {}, shop, target : 'shop' };
301
+
302
+ }
303
+ const record = await controller.get({ collection : 'shop', query : { shop } });
304
+ const session = record?.settings ? decrypt( record.settings ) : {};
305
+ const storefront = record?.storefront ? decrypt( record.storefront ) : null;
306
+
307
+ return {
308
+ raw : record?.settings || null,
309
+ session,
310
+ settings : {
311
+ adminAccessToken : session.accessToken || null,
312
+ refreshToken : session.refreshToken || null,
313
+ refreshTokenExpiresAt : session.refreshTokenExpires || null,
314
+ storefrontAccessToken : storefront?.token || null,
315
+ tokenExpiresAt : session.expires || null
316
+ },
317
+ shop,
318
+ target : 'shop'
319
+ };
320
+
321
+ };
322
+
323
+ // Returns the resolved token blob for a connection (admin + storefront tokens and
324
+ // their expiries), following the shared-per-shop pointer when present. Backward
325
+ // compatible: a legacy connection's settings pass straight through.
326
+
327
+ const resolveConnectionSettings = async ({ fetcher, connection, controller }) => {
328
+
329
+ const { settings } = await resolveTokenContext({ connection, controller });
330
+
331
+ return settings;
332
+
333
+ };
334
+
335
+ // Rotates an admin access token using the stored refresh_token grant.
336
+ // Shopify expiring-token installs return a fresh access_token + a fresh
337
+ // refresh_token each refresh — and rotation RETIRES the old pair at Shopify
338
+ // the moment the grant returns. Ordering and concurrency both follow from
339
+ // that:
340
+ // * PERSIST BEFORE PING — the old pair is already dead once the grant
341
+ // returns, so failing to persist (e.g. a transient ping blip) would
342
+ // strand the only working refresh token forever. Persist first; ping
343
+ // after, purely as a visible health signal (a throw here fails the job,
344
+ // which retries against the persisted, valid pair).
345
+ // * COMPARE-AND-SWAP on the stored blob — the shared shop record has many
346
+ // writers (every org's health check, eager getAdminToken rotation, the
347
+ // embedded app's session writes). The write-back is keyed on the exact
348
+ // blob that was read; on a miss we converge on DB truth: if another
349
+ // writer rotated first, THEIR pair is the live one — return it and don't
350
+ // overwrite.
351
+
352
+ const refreshAdminToken = async ({ fetcher, clientId, clientSecret, connection, controller }) => {
353
+
354
+ const { raw, session, settings, shop, target } = await resolveTokenContext({ connection, controller });
355
+ const domain = connection?.shop || settings.source?.domain || settings.domain || shop;
356
+ const { refreshToken } = settings;
357
+
358
+ const data = await shopifyOAuthFetch(
359
+ `https://${ domain }/admin/oauth/access_token`,
360
+ {
361
+ grant_type : 'refresh_token',
362
+ // Throw before the grant: rotation RETIRES the old pair the moment it
363
+ // returns, so a credential-less call that Shopify rejects opaquely is
364
+ // the one failure mode worth being loud about.
365
+ client_id : required( 'clientId', clientId ),
366
+ client_secret : required( 'clientSecret', clientSecret ),
367
+ refresh_token : refreshToken
368
+ }
369
+ );
370
+
371
+ const adminAccessToken = data.access_token;
372
+ const newRefreshToken = data.refresh_token;
373
+ const expiresIn = data.expires_in;
374
+ const tokenExpiresAt = expiresIn ? new Date( Date.now() + ( expiresIn * 1000 ) ) : null;
375
+ const refreshTokenExpiresAt = new Date( Date.now() + REFRESH_TOKEN_LIFETIME_MS );
376
+
377
+ let liveToken = adminAccessToken;
378
+
379
+ if( target === 'shop' ){
380
+
381
+ // Token of record is the shared `shop` record's offline session blob. Rotate
382
+ // in place, preserving the non-token session fields (id/state/scope/isOnline).
383
+ // The storefront token lives on a separate `shop.storefront` field, untouched.
384
+ const written = await controller.update({
385
+ collection : 'shop',
386
+ data : {
387
+ $set : {
388
+ settings : encrypt({
389
+ ...session,
390
+ accessToken : adminAccessToken,
391
+ expires : tokenExpiresAt,
392
+ refreshToken : newRefreshToken,
393
+ refreshTokenExpires : refreshTokenExpiresAt
394
+ })
395
+ }
396
+ },
397
+ query : {
398
+ shop,
399
+ ...( raw && { settings : raw } )
400
+ }
401
+ });
402
+
403
+ if( ! written ){
404
+
405
+ const current = await controller.get({ collection : 'shop', query : { shop } });
406
+
407
+ if( ! current?.settings ){
408
+
409
+ throw new Error( 'Shopify token refresh write-back failed: shop record missing for ' + shop );
410
+
411
+ }
412
+ const currentSession = decrypt( current.settings );
413
+
414
+ // A different live token means another writer's rotation landed (or ours
415
+ // did, under a controller that doesn't return the doc) — that pair is the
416
+ // token of record now.
417
+ if( currentSession?.accessToken && currentSession.accessToken !== settings.adminAccessToken ){
418
+
419
+ liveToken = currentSession.accessToken;
420
+
421
+ } else {
422
+
423
+ throw new Error( 'Shopify token refresh write-back failed for ' + shop );
424
+
425
+ }
426
+ }
427
+ } else {
428
+
429
+ const written = await controller.update({
430
+ collection : 'connection',
431
+ data : {
432
+ $set : {
433
+ settings : encrypt({
434
+ ...settings,
435
+ adminAccessToken,
436
+ refreshToken : newRefreshToken,
437
+ refreshTokenExpiresAt,
438
+ tokenExpiresAt
439
+ })
440
+ }
441
+ },
442
+ query : {
443
+ id : connection.id,
444
+ ...( raw && { settings : raw } )
445
+ }
446
+ });
447
+
448
+ if( ! written ){
449
+
450
+ const current = await controller.get({ collection : 'connection', query : { id : connection.id } });
451
+ const currentSettings = current?.settings ? decrypt( current.settings ) : null;
452
+
453
+ if( currentSettings?.adminAccessToken && currentSettings.adminAccessToken !== settings.adminAccessToken ){
454
+
455
+ liveToken = currentSettings.adminAccessToken;
456
+
457
+ } else {
458
+
459
+ throw new Error( 'Shopify token refresh write-back failed for connection ' + connection?.id );
460
+
461
+ }
462
+ }
463
+ }
464
+ // Health signal only — the pair is already persisted (see header comment).
465
+ await ping({ adminAccessToken : liveToken, domain });
466
+
467
+ return liveToken;
468
+
469
+ };
470
+
471
+ // Returns a live admin access token for the connection, resolving the token of
472
+ // record (connection or shared shop record). For refresh-token installs, rotates
473
+ // eagerly when `tokenExpiresAt` is within ACCESS_TOKEN_REFRESH_BUFFER_MS — Shopify
474
+ // rejects expired tokens immediately, so we never make the actual API call with one.
475
+ // Takes the app credentials only to hand them to that rotation — callers should
476
+ // always pass them, since whether a given call rotates depends on the clock.
477
+
478
+ const getAdminToken = async ({ fetcher, clientId, clientSecret, connection, controller }) => {
479
+
480
+ // VALIDATED HERE even though this function's own body never uses them.
481
+ //
482
+ // It only forwards them to refreshAdminToken, which throws — so without this
483
+ // a caller that omits them succeeds for as long as the stored token is fresh
484
+ // and fails weeks later, at rotation, on a code path nobody changed. Failing
485
+ // on the first call instead makes a missing credential a bug you find while
486
+ // writing the call site rather than an incident.
487
+ required( 'clientId', clientId );
488
+ required( 'clientSecret', clientSecret );
489
+
490
+ const settings = await resolveConnectionSettings({ connection, controller });
491
+ const { adminAccessToken, refreshToken, tokenExpiresAt } = settings;
492
+
493
+ if( ! adminAccessToken ){
494
+
495
+ return null;
496
+
497
+ }
498
+ if( ! refreshToken ){
499
+
500
+ return adminAccessToken;
501
+
502
+ }
503
+ const needsRefresh = ! tokenExpiresAt ||
504
+ new Date( tokenExpiresAt ) < new Date( Date.now() + ACCESS_TOKEN_REFRESH_BUFFER_MS );
505
+
506
+ if( needsRefresh ){
507
+
508
+ return refreshAdminToken({ clientId, clientSecret, connection, controller });
509
+
510
+ }
511
+ return adminAccessToken;
512
+
513
+ };
514
+
515
+ declare const shopifyOauth_SHOPIFY_REQUIRED_SCOPES: typeof SHOPIFY_REQUIRED_SCOPES;
516
+ declare const shopifyOauth_createStorefrontToken: typeof createStorefrontToken;
517
+ declare const shopifyOauth_getAdminToken: typeof getAdminToken;
518
+ declare const shopifyOauth_getShop: typeof getShop;
519
+ declare const shopifyOauth_missingScopes: typeof missingScopes;
520
+ declare const shopifyOauth_ping: typeof ping;
521
+ declare const shopifyOauth_refreshAdminToken: typeof refreshAdminToken;
522
+ declare const shopifyOauth_resolveConnectionSettings: typeof resolveConnectionSettings;
523
+ declare namespace shopifyOauth {
524
+ export { shopifyOauth_SHOPIFY_REQUIRED_SCOPES as SHOPIFY_REQUIRED_SCOPES, shopifyOauth_createStorefrontToken as createStorefrontToken, shopifyOauth_getAdminToken as getAdminToken, shopifyOauth_getShop as getShop, shopifyOauth_missingScopes as missingScopes, shopifyOauth_ping as ping, shopifyOauth_refreshAdminToken as refreshAdminToken, shopifyOauth_resolveConnectionSettings as resolveConnectionSettings };
525
+ }
526
+
527
+ export { getShop as a, resolveConnectionSettings as b, createStorefrontToken as c, getAdminToken as g, missingScopes as m, ping as p, refreshAdminToken as r, shopifyOauth as s };