@drawbridge/drawbridge-utils 0.0.175 → 0.0.177
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/admin-B9ZaLvan.d.cts +697 -0
- package/dist/admin-C3HtEM6h.d.ts +697 -0
- package/dist/billing-Bc4yo9XG.d.cts +175 -0
- package/dist/billing-mNsKflmQ.d.ts +175 -0
- package/dist/billing.d.cts +1 -1
- package/dist/billing.d.ts +1 -1
- package/dist/connections/index.cjs +5928 -1920
- package/dist/connections/index.d.cts +20 -9163
- package/dist/connections/index.d.ts +20 -9163
- package/dist/connections/index.js +5917 -1921
- package/dist/connections/oauth.cjs +4 -4
- package/dist/connections/oauth.d.cts +10 -8
- package/dist/connections/oauth.d.ts +10 -8
- package/dist/connections/oauth.js +4 -4
- package/dist/features.cjs +10260 -42
- package/dist/features.d.cts +55 -42
- package/dist/features.d.ts +55 -42
- package/dist/features.js +10254 -42
- package/dist/http.cjs +10 -1
- package/dist/http.d.cts +10 -1
- package/dist/http.d.ts +10 -1
- package/dist/http.js +10 -1
- package/dist/index-B546oDNo.d.ts +13809 -0
- package/dist/index-C59xHago.d.cts +13809 -0
- package/dist/oauth/index.d.cts +1 -1
- package/dist/oauth/index.d.ts +1 -1
- package/dist/oauth-BJDh0sdM.d.cts +527 -0
- package/dist/oauth-DveZMLHx.d.ts +527 -0
- package/dist/partner-BOZltuh2.d.ts +94 -0
- package/dist/partner-ed2OfW1J.d.cts +94 -0
- package/dist/plans.cjs +10256 -51
- package/dist/plans.d.cts +37 -10
- package/dist/plans.d.ts +37 -10
- package/dist/plans.js +10262 -51
- package/dist/pricing.cjs +10401 -209
- package/dist/pricing.d.cts +34 -17
- package/dist/pricing.d.ts +34 -17
- package/dist/pricing.js +10407 -209
- package/dist/providers.cjs +5433 -1755
- package/dist/providers.d.cts +13 -15
- package/dist/providers.d.ts +13 -15
- package/dist/providers.js +5436 -1752
- package/dist/sendgrid.cjs +10 -1
- package/dist/sendgrid.js +10 -1
- package/dist/shopify/admin.cjs +562 -0
- package/dist/shopify/admin.d.cts +3 -0
- package/dist/shopify/admin.d.ts +3 -0
- package/dist/shopify/admin.js +528 -0
- package/dist/shopify/billing.cjs +166 -0
- package/dist/shopify/billing.d.cts +3 -0
- package/dist/shopify/billing.d.ts +3 -0
- package/dist/shopify/billing.js +140 -0
- package/dist/shopify/constants.cjs +63 -0
- package/dist/shopify/constants.d.cts +58 -0
- package/dist/shopify/constants.d.ts +58 -0
- package/dist/shopify/constants.js +32 -0
- package/dist/shopify/oauth.cjs +509 -0
- package/dist/shopify/oauth.d.cts +7 -0
- package/dist/shopify/oauth.d.ts +7 -0
- package/dist/shopify/oauth.js +466 -0
- package/dist/shopify/partner.cjs +156 -0
- package/dist/shopify/partner.d.cts +3 -0
- package/dist/shopify/partner.d.ts +3 -0
- package/dist/shopify/partner.js +130 -0
- package/dist/shopify/storefront.cjs +611 -0
- package/dist/shopify/storefront.d.cts +3 -0
- package/dist/shopify/storefront.d.ts +3 -0
- package/dist/shopify/storefront.js +576 -0
- package/dist/storefront-C8FKOGeD.d.cts +659 -0
- package/dist/storefront-DJFGLqPl.d.ts +659 -0
- package/dist/twilio.cjs +10 -1
- package/dist/twilio.js +10 -1
- package/package.json +98 -68
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { request } from './http.cjs';
|
|
2
|
+
import { SHOPIFY_APP_API_VERSION } from './shopify/constants.cjs';
|
|
3
|
+
|
|
4
|
+
// Shopify App Pricing usage billing goes through the App Events API
|
|
5
|
+
// (api.shopify.com), NOT the shop-scoped Admin Billing API. Events are
|
|
6
|
+
// app-level: authenticated with the app's own client credentials and addressed
|
|
7
|
+
// by `shop_id`, so no merchant admin token or subscription line item is needed.
|
|
8
|
+
// An event whose `event_handle` matches a meter configured in the app's pricing
|
|
9
|
+
// is billed as `value × the meter's per-unit rate` within the current cycle.
|
|
10
|
+
// There is no capped amount — accrual is uncapped.
|
|
11
|
+
|
|
12
|
+
const APP_API = 'https://api.shopify.com';
|
|
13
|
+
|
|
14
|
+
// Env-overridable so a stable App Events version can be adopted without a
|
|
15
|
+
// republish; defaults to the only documented version today ('unstable').
|
|
16
|
+
const APP_API_VERSION = process.env.SHOPIFY_APP_API_VERSION || SHOPIFY_APP_API_VERSION;
|
|
17
|
+
|
|
18
|
+
// App-level bearer tokens from client_credentials, cached per clientId until
|
|
19
|
+
// just before they expire — one process can serve several apps' credentials,
|
|
20
|
+
// and a shared slot would send app A's token for app B's billing event.
|
|
21
|
+
// Cleared + re-fetched on a 401.
|
|
22
|
+
const cachedTokens = {};
|
|
23
|
+
|
|
24
|
+
const fetchAppToken = async ({ clientId, clientSecret, fetcher }) => {
|
|
25
|
+
|
|
26
|
+
const data = await request({
|
|
27
|
+
fetcher,
|
|
28
|
+
method : 'POST',
|
|
29
|
+
url : APP_API + '/auth/access_token',
|
|
30
|
+
body : {
|
|
31
|
+
client_id : clientId,
|
|
32
|
+
client_secret : clientSecret,
|
|
33
|
+
grant_type : 'client_credentials'
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
if( ! data?.access_token ){
|
|
38
|
+
|
|
39
|
+
throw new Error( 'Shopify app token request failed: no access token returned' );
|
|
40
|
+
|
|
41
|
+
}
|
|
42
|
+
const ttl = ( data.expires_in ? data.expires_in * 1000 : 60 * 60 * 1000 );
|
|
43
|
+
|
|
44
|
+
cachedTokens[ clientId ] = {
|
|
45
|
+
expiresAt : Date.now() + ttl - ( 60 * 1000 ),
|
|
46
|
+
token : data.access_token
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
return data.access_token;
|
|
50
|
+
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const getAppToken = async ({ clientId, clientSecret, fetcher }) => {
|
|
54
|
+
|
|
55
|
+
const cached = cachedTokens[ clientId ];
|
|
56
|
+
|
|
57
|
+
if( cached && cached.expiresAt > Date.now() ){
|
|
58
|
+
|
|
59
|
+
return cached.token;
|
|
60
|
+
|
|
61
|
+
}
|
|
62
|
+
return fetchAppToken({ clientId, clientSecret, fetcher });
|
|
63
|
+
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const toShopGid = ( shopId ) => (
|
|
67
|
+
String( shopId ).startsWith( 'gid://' ) ? String( shopId ) : ( 'gid://shopify/Shop/' + shopId )
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
// Send an event to the Shopify App Events API for an app-installed store. When
|
|
71
|
+
// `eventHandle` matches a usage meter in the app's pricing config, Shopify bills
|
|
72
|
+
// `value × the meter's per-unit rate` — so this doubles as the usage-billing call.
|
|
73
|
+
// `value` is the event quantity (e.g. the commission in cents).
|
|
74
|
+
//
|
|
75
|
+
// `eventHandle` is REQUIRED — deliberately no default. The handle is the string
|
|
76
|
+
// that decides whether the event bills or is silently ingested as a plain
|
|
77
|
+
// custom event, so every caller must pass the value it verified (the shopify
|
|
78
|
+
// manifest's events.order.handle for order billing); a package-level fallback
|
|
79
|
+
// is exactly the second unvalidated copy that let handle drift go unnoticed.
|
|
80
|
+
// `SHOPIFY_USAGE_ORDERS_EVENT_HANDLE` in lib/constants.js remains the recorded
|
|
81
|
+
// contract value the manifest must agree with. `idempotencyKey` (e.g. the
|
|
82
|
+
// order id) dedupes retries — Shopify's window is 24h for custom events but
|
|
83
|
+
// PERMANENT for billing events. Retries once on a 401 (stale cached token).
|
|
84
|
+
//
|
|
85
|
+
// `revision` suffixes the idempotency key ('.r' + revision) for a corrective
|
|
86
|
+
// resend once a key has been spent — a 202 consumes the key whether or not the
|
|
87
|
+
// event actually billed. The encoding lives HERE, and only here, because both
|
|
88
|
+
// drawbridge-sync's billing handler and drawbridge-api's recovery migration
|
|
89
|
+
// resend the same orders: two hand-rolled copies of the suffix would drift, and
|
|
90
|
+
// against a permanent idempotency ledger a drifted key either double-bills a
|
|
91
|
+
// merchant or misses the key it meant to supersede. Callers pass the bare order
|
|
92
|
+
// id plus revision and never build keys themselves.
|
|
93
|
+
//
|
|
94
|
+
// `clientId` / `clientSecret` are the app's own credentials — read from the
|
|
95
|
+
// encrypted `provider` record by the calling app, never from the environment —
|
|
96
|
+
// and back the client_credentials grant this authenticates with.
|
|
97
|
+
//
|
|
98
|
+
// `reference` is an optional opaque tracing attribute (e.g. the order document
|
|
99
|
+
// id) carried alongside the required `value`. Attributes allow at most 15
|
|
100
|
+
// scalar keys and must never contain personal data — pass ids, not people.
|
|
101
|
+
const sendAppEvent = async ({ fetcher, clientId, clientSecret, eventHandle, idempotencyKey, reference, revision, shopId, timestamp, value }) => {
|
|
102
|
+
|
|
103
|
+
if( ! shopId || ! eventHandle || ! ( Number( value ) > 0 ) ){
|
|
104
|
+
|
|
105
|
+
throw new Error( 'sendAppEvent requires shopId, eventHandle, and a positive value' );
|
|
106
|
+
|
|
107
|
+
}
|
|
108
|
+
// Checked here, not in fetchAppToken, so a missing credential fails the same
|
|
109
|
+
// way on every call. Deferred to the grant it would ride the module-level
|
|
110
|
+
// cached token until that expired, turning a config error into an
|
|
111
|
+
// intermittent billing outage against a PERMANENT idempotency ledger.
|
|
112
|
+
if( ! clientId || ! clientSecret ){
|
|
113
|
+
|
|
114
|
+
throw new Error( 'sendAppEvent requires clientId and clientSecret' );
|
|
115
|
+
|
|
116
|
+
}
|
|
117
|
+
// The 64-char cap truncates the BASE, never the suffix — a cap that ate
|
|
118
|
+
// '.rN' would collide a corrective resend with the spent original. The
|
|
119
|
+
// Math.max keeps the slice bound non-negative should a revision ever
|
|
120
|
+
// arrive long enough to swallow the whole budget.
|
|
121
|
+
const suffix = ( revision ? '.r' + revision : '' );
|
|
122
|
+
|
|
123
|
+
const key = idempotencyKey && (
|
|
124
|
+
String( idempotencyKey ).slice( 0, Math.max( 0, 64 - suffix.length ) ) + suffix
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
const body = {
|
|
128
|
+
attributes : {
|
|
129
|
+
value : Number( value ),
|
|
130
|
+
...( reference && {
|
|
131
|
+
reference : String( reference ).slice( 0, 128 )
|
|
132
|
+
})
|
|
133
|
+
},
|
|
134
|
+
event_handle : eventHandle,
|
|
135
|
+
shop_id : toShopGid( shopId ),
|
|
136
|
+
timestamp : timestamp || new Date().toISOString(),
|
|
137
|
+
...( key && {
|
|
138
|
+
idempotency_key : key
|
|
139
|
+
})
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const send = async ( token ) => request({
|
|
143
|
+
method : 'POST',
|
|
144
|
+
url : APP_API + '/app/' + APP_API_VERSION + '/events',
|
|
145
|
+
headers : {
|
|
146
|
+
'Authorization' : 'Bearer ' + token
|
|
147
|
+
},
|
|
148
|
+
body
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
|
|
153
|
+
return await send( await getAppToken({ clientId, clientSecret, fetcher }) );
|
|
154
|
+
|
|
155
|
+
} catch ( error ) {
|
|
156
|
+
|
|
157
|
+
if( error?.status === 401 ){
|
|
158
|
+
|
|
159
|
+
delete cachedTokens[ clientId ];
|
|
160
|
+
|
|
161
|
+
return send( await fetchAppToken({ clientId, clientSecret, fetcher }) );
|
|
162
|
+
|
|
163
|
+
}
|
|
164
|
+
throw error;
|
|
165
|
+
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
declare const shopifyBilling_sendAppEvent: typeof sendAppEvent;
|
|
171
|
+
declare namespace shopifyBilling {
|
|
172
|
+
export { shopifyBilling_sendAppEvent as sendAppEvent };
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export { shopifyBilling as a, sendAppEvent as s };
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { request } from './http.js';
|
|
2
|
+
import { SHOPIFY_APP_API_VERSION } from './shopify/constants.js';
|
|
3
|
+
|
|
4
|
+
// Shopify App Pricing usage billing goes through the App Events API
|
|
5
|
+
// (api.shopify.com), NOT the shop-scoped Admin Billing API. Events are
|
|
6
|
+
// app-level: authenticated with the app's own client credentials and addressed
|
|
7
|
+
// by `shop_id`, so no merchant admin token or subscription line item is needed.
|
|
8
|
+
// An event whose `event_handle` matches a meter configured in the app's pricing
|
|
9
|
+
// is billed as `value × the meter's per-unit rate` within the current cycle.
|
|
10
|
+
// There is no capped amount — accrual is uncapped.
|
|
11
|
+
|
|
12
|
+
const APP_API = 'https://api.shopify.com';
|
|
13
|
+
|
|
14
|
+
// Env-overridable so a stable App Events version can be adopted without a
|
|
15
|
+
// republish; defaults to the only documented version today ('unstable').
|
|
16
|
+
const APP_API_VERSION = process.env.SHOPIFY_APP_API_VERSION || SHOPIFY_APP_API_VERSION;
|
|
17
|
+
|
|
18
|
+
// App-level bearer tokens from client_credentials, cached per clientId until
|
|
19
|
+
// just before they expire — one process can serve several apps' credentials,
|
|
20
|
+
// and a shared slot would send app A's token for app B's billing event.
|
|
21
|
+
// Cleared + re-fetched on a 401.
|
|
22
|
+
const cachedTokens = {};
|
|
23
|
+
|
|
24
|
+
const fetchAppToken = async ({ clientId, clientSecret, fetcher }) => {
|
|
25
|
+
|
|
26
|
+
const data = await request({
|
|
27
|
+
fetcher,
|
|
28
|
+
method : 'POST',
|
|
29
|
+
url : APP_API + '/auth/access_token',
|
|
30
|
+
body : {
|
|
31
|
+
client_id : clientId,
|
|
32
|
+
client_secret : clientSecret,
|
|
33
|
+
grant_type : 'client_credentials'
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
if( ! data?.access_token ){
|
|
38
|
+
|
|
39
|
+
throw new Error( 'Shopify app token request failed: no access token returned' );
|
|
40
|
+
|
|
41
|
+
}
|
|
42
|
+
const ttl = ( data.expires_in ? data.expires_in * 1000 : 60 * 60 * 1000 );
|
|
43
|
+
|
|
44
|
+
cachedTokens[ clientId ] = {
|
|
45
|
+
expiresAt : Date.now() + ttl - ( 60 * 1000 ),
|
|
46
|
+
token : data.access_token
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
return data.access_token;
|
|
50
|
+
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const getAppToken = async ({ clientId, clientSecret, fetcher }) => {
|
|
54
|
+
|
|
55
|
+
const cached = cachedTokens[ clientId ];
|
|
56
|
+
|
|
57
|
+
if( cached && cached.expiresAt > Date.now() ){
|
|
58
|
+
|
|
59
|
+
return cached.token;
|
|
60
|
+
|
|
61
|
+
}
|
|
62
|
+
return fetchAppToken({ clientId, clientSecret, fetcher });
|
|
63
|
+
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const toShopGid = ( shopId ) => (
|
|
67
|
+
String( shopId ).startsWith( 'gid://' ) ? String( shopId ) : ( 'gid://shopify/Shop/' + shopId )
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
// Send an event to the Shopify App Events API for an app-installed store. When
|
|
71
|
+
// `eventHandle` matches a usage meter in the app's pricing config, Shopify bills
|
|
72
|
+
// `value × the meter's per-unit rate` — so this doubles as the usage-billing call.
|
|
73
|
+
// `value` is the event quantity (e.g. the commission in cents).
|
|
74
|
+
//
|
|
75
|
+
// `eventHandle` is REQUIRED — deliberately no default. The handle is the string
|
|
76
|
+
// that decides whether the event bills or is silently ingested as a plain
|
|
77
|
+
// custom event, so every caller must pass the value it verified (the shopify
|
|
78
|
+
// manifest's events.order.handle for order billing); a package-level fallback
|
|
79
|
+
// is exactly the second unvalidated copy that let handle drift go unnoticed.
|
|
80
|
+
// `SHOPIFY_USAGE_ORDERS_EVENT_HANDLE` in lib/constants.js remains the recorded
|
|
81
|
+
// contract value the manifest must agree with. `idempotencyKey` (e.g. the
|
|
82
|
+
// order id) dedupes retries — Shopify's window is 24h for custom events but
|
|
83
|
+
// PERMANENT for billing events. Retries once on a 401 (stale cached token).
|
|
84
|
+
//
|
|
85
|
+
// `revision` suffixes the idempotency key ('.r' + revision) for a corrective
|
|
86
|
+
// resend once a key has been spent — a 202 consumes the key whether or not the
|
|
87
|
+
// event actually billed. The encoding lives HERE, and only here, because both
|
|
88
|
+
// drawbridge-sync's billing handler and drawbridge-api's recovery migration
|
|
89
|
+
// resend the same orders: two hand-rolled copies of the suffix would drift, and
|
|
90
|
+
// against a permanent idempotency ledger a drifted key either double-bills a
|
|
91
|
+
// merchant or misses the key it meant to supersede. Callers pass the bare order
|
|
92
|
+
// id plus revision and never build keys themselves.
|
|
93
|
+
//
|
|
94
|
+
// `clientId` / `clientSecret` are the app's own credentials — read from the
|
|
95
|
+
// encrypted `provider` record by the calling app, never from the environment —
|
|
96
|
+
// and back the client_credentials grant this authenticates with.
|
|
97
|
+
//
|
|
98
|
+
// `reference` is an optional opaque tracing attribute (e.g. the order document
|
|
99
|
+
// id) carried alongside the required `value`. Attributes allow at most 15
|
|
100
|
+
// scalar keys and must never contain personal data — pass ids, not people.
|
|
101
|
+
const sendAppEvent = async ({ fetcher, clientId, clientSecret, eventHandle, idempotencyKey, reference, revision, shopId, timestamp, value }) => {
|
|
102
|
+
|
|
103
|
+
if( ! shopId || ! eventHandle || ! ( Number( value ) > 0 ) ){
|
|
104
|
+
|
|
105
|
+
throw new Error( 'sendAppEvent requires shopId, eventHandle, and a positive value' );
|
|
106
|
+
|
|
107
|
+
}
|
|
108
|
+
// Checked here, not in fetchAppToken, so a missing credential fails the same
|
|
109
|
+
// way on every call. Deferred to the grant it would ride the module-level
|
|
110
|
+
// cached token until that expired, turning a config error into an
|
|
111
|
+
// intermittent billing outage against a PERMANENT idempotency ledger.
|
|
112
|
+
if( ! clientId || ! clientSecret ){
|
|
113
|
+
|
|
114
|
+
throw new Error( 'sendAppEvent requires clientId and clientSecret' );
|
|
115
|
+
|
|
116
|
+
}
|
|
117
|
+
// The 64-char cap truncates the BASE, never the suffix — a cap that ate
|
|
118
|
+
// '.rN' would collide a corrective resend with the spent original. The
|
|
119
|
+
// Math.max keeps the slice bound non-negative should a revision ever
|
|
120
|
+
// arrive long enough to swallow the whole budget.
|
|
121
|
+
const suffix = ( revision ? '.r' + revision : '' );
|
|
122
|
+
|
|
123
|
+
const key = idempotencyKey && (
|
|
124
|
+
String( idempotencyKey ).slice( 0, Math.max( 0, 64 - suffix.length ) ) + suffix
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
const body = {
|
|
128
|
+
attributes : {
|
|
129
|
+
value : Number( value ),
|
|
130
|
+
...( reference && {
|
|
131
|
+
reference : String( reference ).slice( 0, 128 )
|
|
132
|
+
})
|
|
133
|
+
},
|
|
134
|
+
event_handle : eventHandle,
|
|
135
|
+
shop_id : toShopGid( shopId ),
|
|
136
|
+
timestamp : timestamp || new Date().toISOString(),
|
|
137
|
+
...( key && {
|
|
138
|
+
idempotency_key : key
|
|
139
|
+
})
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const send = async ( token ) => request({
|
|
143
|
+
method : 'POST',
|
|
144
|
+
url : APP_API + '/app/' + APP_API_VERSION + '/events',
|
|
145
|
+
headers : {
|
|
146
|
+
'Authorization' : 'Bearer ' + token
|
|
147
|
+
},
|
|
148
|
+
body
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
|
|
153
|
+
return await send( await getAppToken({ clientId, clientSecret, fetcher }) );
|
|
154
|
+
|
|
155
|
+
} catch ( error ) {
|
|
156
|
+
|
|
157
|
+
if( error?.status === 401 ){
|
|
158
|
+
|
|
159
|
+
delete cachedTokens[ clientId ];
|
|
160
|
+
|
|
161
|
+
return send( await fetchAppToken({ clientId, clientSecret, fetcher }) );
|
|
162
|
+
|
|
163
|
+
}
|
|
164
|
+
throw error;
|
|
165
|
+
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
declare const shopifyBilling_sendAppEvent: typeof sendAppEvent;
|
|
171
|
+
declare namespace shopifyBilling {
|
|
172
|
+
export { shopifyBilling_sendAppEvent as sendAppEvent };
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export { shopifyBilling as a, sendAppEvent as s };
|
package/dist/billing.d.cts
CHANGED
|
@@ -13,7 +13,7 @@ import { createLogger } from '@drawbridge/drawbridge-telemetry';
|
|
|
13
13
|
//
|
|
14
14
|
// Sits on top of transactions.js (the generic credit/debit money rail) and
|
|
15
15
|
// usage.js (the action-ledger + usage-totals primitives). Shopify order fees are
|
|
16
|
-
// NOT billed here — they meter through
|
|
16
|
+
// NOT billed here — they meter through the Shopify client's usage records and stay
|
|
17
17
|
// Shopify-only by design. The Stripe meter EMIT for actions also stays in the
|
|
18
18
|
// Stripe layer (utils must not depend on Stripe); billing.action.sum gives that
|
|
19
19
|
// layer the authoritative number to report.
|
package/dist/billing.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ import { createLogger } from '@drawbridge/drawbridge-telemetry';
|
|
|
13
13
|
//
|
|
14
14
|
// Sits on top of transactions.js (the generic credit/debit money rail) and
|
|
15
15
|
// usage.js (the action-ledger + usage-totals primitives). Shopify order fees are
|
|
16
|
-
// NOT billed here — they meter through
|
|
16
|
+
// NOT billed here — they meter through the Shopify client's usage records and stay
|
|
17
17
|
// Shopify-only by design. The Stripe meter EMIT for actions also stays in the
|
|
18
18
|
// Stripe layer (utils must not depend on Stripe); billing.action.sum gives that
|
|
19
19
|
// layer the authoritative number to report.
|