@drawbridge/drawbridge-utils 0.0.142 → 0.0.143

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.
@@ -4112,7 +4112,7 @@ var shopify_default2 = {
4112
4112
  // against the ones the app now needs, and queues a webhook
4113
4113
  // reconciliation.
4114
4114
  health: async ({ connection: connection2, workflow }, { adminToken, logger: logger2, read, reconcileScopes, resolveSettings, rotateToken, shopify } = {}) => {
4115
- var _a, _b;
4115
+ var _a, _b, _c;
4116
4116
  const request2 = {
4117
4117
  connectionId: workflow.connection,
4118
4118
  organizationId: workflow.organization,
@@ -4134,7 +4134,7 @@ var shopify_default2 = {
4134
4134
  const writes = [];
4135
4135
  let source = connection2.source || null;
4136
4136
  let sourceRepaired = false;
4137
- let metered = (source == null ? void 0 : source.metered) ?? null;
4137
+ let metered;
4138
4138
  let shopCurrency = null;
4139
4139
  let billingProbeFailed = false;
4140
4140
  try {
@@ -4153,21 +4153,21 @@ var shopify_default2 = {
4153
4153
  domain: connection2.shop
4154
4154
  });
4155
4155
  if (subscriptions.length && subscriptions.every((subscription) => typeof subscription.metered === "boolean")) {
4156
- metered = subscriptions.some((subscription) => subscription.metered);
4156
+ metered = ((_a = subscriptions.find((subscription) => subscription.usageLineItemId)) == null ? void 0 : _a.usageLineItemId) || null;
4157
4157
  }
4158
4158
  } catch (probeError) {
4159
4159
  billingProbeFailed = true;
4160
- (_a = logger2 == null ? void 0 : logger2.warn) == null ? void 0 : _a.call(logger2, "shopify.health.billing.probe.failed", {
4160
+ (_b = logger2 == null ? void 0 : logger2.warn) == null ? void 0 : _b.call(logger2, "shopify.health.billing.probe.failed", {
4161
4161
  connectionId: connection2.id,
4162
4162
  message: probeError == null ? void 0 : probeError.message,
4163
4163
  shop: connection2.shop
4164
4164
  });
4165
4165
  }
4166
- if (sourceRepaired || metered !== null && metered !== (((_b = connection2.source) == null ? void 0 : _b.metered) ?? null)) {
4166
+ if (sourceRepaired || metered !== void 0 && metered !== (((_c = connection2.source) == null ? void 0 : _c.metered) ?? void 0)) {
4167
4167
  writes.push({
4168
4168
  collection: "connection",
4169
4169
  data: {
4170
- $set: sourceRepaired ? { source: { ...source, ...metered !== null && { metered } } } : { "source.metered": metered }
4170
+ $set: sourceRepaired ? { source: { ...source, ...metered !== void 0 && { metered } } } : { "source.metered": metered }
4171
4171
  },
4172
4172
  operation: "update",
4173
4173
  query: { id: connection2.id }
@@ -4187,11 +4187,12 @@ var shopify_default2 = {
4187
4187
  options: { jobId: "connection.update.register." + workflow.connection + "." + (0, import_node_crypto5.randomUUID)() },
4188
4188
  queue: "connection"
4189
4189
  }],
4190
- message: ((scopesMissing == null ? void 0 : scopesMissing.length) ? "Health check: ping ok, webhooks reconciled \u2014 connection errored, granted scopes are missing: " + scopesMissing.join(", ") + "." : refreshTokenRotated ? "Health check passed \u2014 refresh token rotated, ping ok, webhooks reconciled." : "Health check passed \u2014 ping ok, webhooks reconciled.") + (sourceRepaired ? " Billing source repaired from the live shop." : "") + (metered === false ? " No usage line on the store's approved plan \u2014 order billing needs the merchant to approve the updated plan." : ""),
4190
+ message: ((scopesMissing == null ? void 0 : scopesMissing.length) ? "Health check: ping ok, webhooks reconciled \u2014 connection errored, granted scopes are missing: " + scopesMissing.join(", ") + "." : refreshTokenRotated ? "Health check passed \u2014 refresh token rotated, ping ok, webhooks reconciled." : "Health check passed \u2014 ping ok, webhooks reconciled.") + (sourceRepaired ? " Billing source repaired from the live shop." : "") + (metered === null ? " No usage line on the store's approved plan \u2014 order billing needs the merchant to approve the updated plan." : ""),
4191
4191
  request: request2,
4192
4192
  response: {
4193
4193
  billingProbeFailed,
4194
- metered,
4194
+ metered: metered ?? null,
4195
+ meterProbed: metered !== void 0,
4195
4196
  pingedAt: /* @__PURE__ */ new Date(),
4196
4197
  refreshTokenExpiresAt: refreshTokenExpiresAt || null,
4197
4198
  refreshTokenRotated,
@@ -4483,11 +4484,13 @@ var shopify_default2 = {
4483
4484
  }
4484
4485
  ] : [],
4485
4486
  // The store's ACTIVE approval carries no usage component — stamped by
4486
- // the daily health check and the approval webhook (`source.metered`).
4487
- // Approved pricing is never retroactive, so the fix is a fresh approval.
4488
- // Gated on an EXPLICIT false a connection the probe hasn't reached
4489
- // (or couldn't read) shows nothing rather than nagging on silence.
4490
- ...(data2 == null ? void 0 : data2.status) === "active" && ((_a = data2 == null ? void 0 : data2.source) == null ? void 0 : _a.metered) === false ? [
4487
+ // the daily health check and the approval webhook (`source.metered`:
4488
+ // the usage line's id when present, null when probed-and-absent).
4489
+ // Approved pricing is never retroactive, so the fix is a fresh
4490
+ // approval. Gated on an EXPLICIT null a connection the probe hasn't
4491
+ // reached (or couldn't read) has no key and shows nothing rather than
4492
+ // nagging on silence.
4493
+ ...(data2 == null ? void 0 : data2.status) === "active" && ((_a = data2 == null ? void 0 : data2.source) == null ? void 0 : _a.metered) === null ? [
4491
4494
  {
4492
4495
  action: "billing",
4493
4496
  message: "Order billing isn't set up for this store, so campaign-attributed orders aren't being charged. Approve the updated plan to fix it \u2014 one click here, one confirmation on Shopify.",
@@ -4866,14 +4866,18 @@ var shopify = {
4866
4866
  // holds a live admin token, so a missing source is one lookup away
4867
4867
  // from fixed.
4868
4868
  //
4869
- // `metered` rides on the same pass: whether the merchant's ACTIVE
4870
- // approval carries a usage line item. A meter added to the app's
4871
- // pricing config is never retroactive it bills only from the
4872
- // moment the merchant approves the plan version that carries it —
4873
- // so an approval with no usage line means every order's usage event
4874
- // is 202-accepted and silently never billed. Stamped on the
4875
- // connection so tasks() can tell the merchant to re-approve, and
4876
- // probed every run so a re-approval clears the card within a day.
4869
+ // `metered` rides on the same pass: the usage LINE ITEM ID from the
4870
+ // merchant's ACTIVE approval an id is proof of WHICH approval
4871
+ // carries the meter, where a boolean was only an assertion. Three
4872
+ // states: a gid string (probed, usage line present), null (probed
4873
+ // and absent the unbillable state tasks() nags on), or no key at
4874
+ // all (never probed silence, never treated as evidence). A meter
4875
+ // added to the app's pricing config is never retroactive — it
4876
+ // bills only from the moment the merchant approves the plan
4877
+ // version that carries it — so a null here means every order's
4878
+ // usage event is 202-accepted and silently never billed. Probed
4879
+ // every run, so a re-approval both clears the card within a day
4880
+ // and refreshes the id it re-minted.
4877
4881
  //
4878
4882
  // Best-effort by design: the ping above already proved access, so a
4879
4883
  // blip in either lookup must not error a healthy connection — the
@@ -4886,7 +4890,9 @@ var shopify = {
4886
4890
 
4887
4891
  let source = connection.source || null;
4888
4892
  let sourceRepaired = false;
4889
- let metered = source?.metered ?? null;
4893
+ // undefined = no verdict this run; a string/null verdict comes
4894
+ // only from a successful probe of an ACTIVE approval.
4895
+ let metered;
4890
4896
  let shopCurrency = null;
4891
4897
  let billingProbeFailed = false;
4892
4898
 
@@ -4913,14 +4919,16 @@ var shopify = {
4913
4919
 
4914
4920
  // Only an ACTIVE approval says anything about metering — no
4915
4921
  // subscriptions (mid-install, plan pending) leaves the stamp
4916
- // untouched rather than asserting false from silence. The
4922
+ // untouched rather than asserting null from silence. The
4917
4923
  // every-boolean guard is version skew insurance: an older
4918
- // @drawbridge/shopify returns subscriptions without the flag,
4919
- // and reading that silence as false would nag every healthy
4920
- // merchant to re-approve a plan that is fine.
4924
+ // @drawbridge/shopify returns subscriptions without the flag
4925
+ // (and without usageLineItemId), and reading that silence as
4926
+ // unmetered would nag every healthy merchant to re-approve a
4927
+ // plan that is fine — the flag being boolean proves an SDK
4928
+ // that also reports the line id.
4921
4929
  if( subscriptions.length && subscriptions.every( ( subscription ) => typeof subscription.metered === 'boolean' ) ){
4922
4930
 
4923
- metered = subscriptions.some( ( subscription ) => subscription.metered );
4931
+ metered = subscriptions.find( ( subscription ) => subscription.usageLineItemId )?.usageLineItemId || null;
4924
4932
 
4925
4933
  }
4926
4934
 
@@ -4936,13 +4944,16 @@ var shopify = {
4936
4944
 
4937
4945
  }
4938
4946
 
4939
- if( sourceRepaired || ( metered !== null && metered !== ( connection.source?.metered ?? null ) ) ){
4947
+ // A verdict writes only when it CHANGES the stored one the daily
4948
+ // run stays idempotent, and undefined (no verdict) never touches
4949
+ // the stamp.
4950
+ if( sourceRepaired || ( metered !== undefined && metered !== ( connection.source?.metered ?? undefined ) ) ){
4940
4951
 
4941
4952
  writes.push({
4942
4953
  collection : 'connection',
4943
4954
  data : {
4944
4955
  $set : sourceRepaired
4945
- ? { source : { ...source, ...( metered !== null && { metered }) } }
4956
+ ? { source : { ...source, ...( metered !== undefined && { metered }) } }
4946
4957
  : { 'source.metered' : metered }
4947
4958
  },
4948
4959
  operation : 'update',
@@ -4972,11 +4983,12 @@ var shopify = {
4972
4983
  : 'Health check passed — ping ok, webhooks reconciled.'
4973
4984
  )
4974
4985
  + ( sourceRepaired ? ' Billing source repaired from the live shop.' : '' )
4975
- + ( metered === false ? ' No usage line on the store\'s approved plan — order billing needs the merchant to approve the updated plan.' : '' ),
4986
+ + ( metered === null ? ' No usage line on the store\'s approved plan — order billing needs the merchant to approve the updated plan.' : '' ),
4976
4987
  request,
4977
4988
  response : {
4978
4989
  billingProbeFailed,
4979
- metered,
4990
+ metered : metered ?? null,
4991
+ meterProbed : metered !== undefined,
4980
4992
  pingedAt : new Date(),
4981
4993
  refreshTokenExpiresAt : refreshTokenExpiresAt || null,
4982
4994
  refreshTokenRotated,
@@ -5321,11 +5333,13 @@ var shopify = {
5321
5333
  : []
5322
5334
  ),
5323
5335
  // The store's ACTIVE approval carries no usage component — stamped by
5324
- // the daily health check and the approval webhook (`source.metered`).
5325
- // Approved pricing is never retroactive, so the fix is a fresh approval.
5326
- // Gated on an EXPLICIT false a connection the probe hasn't reached
5327
- // (or couldn't read) shows nothing rather than nagging on silence.
5328
- ...( data?.status === 'active' && data?.source?.metered === false
5336
+ // the daily health check and the approval webhook (`source.metered`:
5337
+ // the usage line's id when present, null when probed-and-absent).
5338
+ // Approved pricing is never retroactive, so the fix is a fresh
5339
+ // approval. Gated on an EXPLICIT null a connection the probe hasn't
5340
+ // reached (or couldn't read) has no key and shows nothing rather than
5341
+ // nagging on silence.
5342
+ ...( data?.status === 'active' && data?.source?.metered === null
5329
5343
  ? [
5330
5344
  {
5331
5345
  action : 'billing',
@@ -4866,14 +4866,18 @@ var shopify = {
4866
4866
  // holds a live admin token, so a missing source is one lookup away
4867
4867
  // from fixed.
4868
4868
  //
4869
- // `metered` rides on the same pass: whether the merchant's ACTIVE
4870
- // approval carries a usage line item. A meter added to the app's
4871
- // pricing config is never retroactive it bills only from the
4872
- // moment the merchant approves the plan version that carries it —
4873
- // so an approval with no usage line means every order's usage event
4874
- // is 202-accepted and silently never billed. Stamped on the
4875
- // connection so tasks() can tell the merchant to re-approve, and
4876
- // probed every run so a re-approval clears the card within a day.
4869
+ // `metered` rides on the same pass: the usage LINE ITEM ID from the
4870
+ // merchant's ACTIVE approval an id is proof of WHICH approval
4871
+ // carries the meter, where a boolean was only an assertion. Three
4872
+ // states: a gid string (probed, usage line present), null (probed
4873
+ // and absent the unbillable state tasks() nags on), or no key at
4874
+ // all (never probed silence, never treated as evidence). A meter
4875
+ // added to the app's pricing config is never retroactive — it
4876
+ // bills only from the moment the merchant approves the plan
4877
+ // version that carries it — so a null here means every order's
4878
+ // usage event is 202-accepted and silently never billed. Probed
4879
+ // every run, so a re-approval both clears the card within a day
4880
+ // and refreshes the id it re-minted.
4877
4881
  //
4878
4882
  // Best-effort by design: the ping above already proved access, so a
4879
4883
  // blip in either lookup must not error a healthy connection — the
@@ -4886,7 +4890,9 @@ var shopify = {
4886
4890
 
4887
4891
  let source = connection.source || null;
4888
4892
  let sourceRepaired = false;
4889
- let metered = source?.metered ?? null;
4893
+ // undefined = no verdict this run; a string/null verdict comes
4894
+ // only from a successful probe of an ACTIVE approval.
4895
+ let metered;
4890
4896
  let shopCurrency = null;
4891
4897
  let billingProbeFailed = false;
4892
4898
 
@@ -4913,14 +4919,16 @@ var shopify = {
4913
4919
 
4914
4920
  // Only an ACTIVE approval says anything about metering — no
4915
4921
  // subscriptions (mid-install, plan pending) leaves the stamp
4916
- // untouched rather than asserting false from silence. The
4922
+ // untouched rather than asserting null from silence. The
4917
4923
  // every-boolean guard is version skew insurance: an older
4918
- // @drawbridge/shopify returns subscriptions without the flag,
4919
- // and reading that silence as false would nag every healthy
4920
- // merchant to re-approve a plan that is fine.
4924
+ // @drawbridge/shopify returns subscriptions without the flag
4925
+ // (and without usageLineItemId), and reading that silence as
4926
+ // unmetered would nag every healthy merchant to re-approve a
4927
+ // plan that is fine — the flag being boolean proves an SDK
4928
+ // that also reports the line id.
4921
4929
  if( subscriptions.length && subscriptions.every( ( subscription ) => typeof subscription.metered === 'boolean' ) ){
4922
4930
 
4923
- metered = subscriptions.some( ( subscription ) => subscription.metered );
4931
+ metered = subscriptions.find( ( subscription ) => subscription.usageLineItemId )?.usageLineItemId || null;
4924
4932
 
4925
4933
  }
4926
4934
 
@@ -4936,13 +4944,16 @@ var shopify = {
4936
4944
 
4937
4945
  }
4938
4946
 
4939
- if( sourceRepaired || ( metered !== null && metered !== ( connection.source?.metered ?? null ) ) ){
4947
+ // A verdict writes only when it CHANGES the stored one the daily
4948
+ // run stays idempotent, and undefined (no verdict) never touches
4949
+ // the stamp.
4950
+ if( sourceRepaired || ( metered !== undefined && metered !== ( connection.source?.metered ?? undefined ) ) ){
4940
4951
 
4941
4952
  writes.push({
4942
4953
  collection : 'connection',
4943
4954
  data : {
4944
4955
  $set : sourceRepaired
4945
- ? { source : { ...source, ...( metered !== null && { metered }) } }
4956
+ ? { source : { ...source, ...( metered !== undefined && { metered }) } }
4946
4957
  : { 'source.metered' : metered }
4947
4958
  },
4948
4959
  operation : 'update',
@@ -4972,11 +4983,12 @@ var shopify = {
4972
4983
  : 'Health check passed — ping ok, webhooks reconciled.'
4973
4984
  )
4974
4985
  + ( sourceRepaired ? ' Billing source repaired from the live shop.' : '' )
4975
- + ( metered === false ? ' No usage line on the store\'s approved plan — order billing needs the merchant to approve the updated plan.' : '' ),
4986
+ + ( metered === null ? ' No usage line on the store\'s approved plan — order billing needs the merchant to approve the updated plan.' : '' ),
4976
4987
  request,
4977
4988
  response : {
4978
4989
  billingProbeFailed,
4979
- metered,
4990
+ metered : metered ?? null,
4991
+ meterProbed : metered !== undefined,
4980
4992
  pingedAt : new Date(),
4981
4993
  refreshTokenExpiresAt : refreshTokenExpiresAt || null,
4982
4994
  refreshTokenRotated,
@@ -5321,11 +5333,13 @@ var shopify = {
5321
5333
  : []
5322
5334
  ),
5323
5335
  // The store's ACTIVE approval carries no usage component — stamped by
5324
- // the daily health check and the approval webhook (`source.metered`).
5325
- // Approved pricing is never retroactive, so the fix is a fresh approval.
5326
- // Gated on an EXPLICIT false a connection the probe hasn't reached
5327
- // (or couldn't read) shows nothing rather than nagging on silence.
5328
- ...( data?.status === 'active' && data?.source?.metered === false
5336
+ // the daily health check and the approval webhook (`source.metered`:
5337
+ // the usage line's id when present, null when probed-and-absent).
5338
+ // Approved pricing is never retroactive, so the fix is a fresh
5339
+ // approval. Gated on an EXPLICIT null a connection the probe hasn't
5340
+ // reached (or couldn't read) has no key and shows nothing rather than
5341
+ // nagging on silence.
5342
+ ...( data?.status === 'active' && data?.source?.metered === null
5329
5343
  ? [
5330
5344
  {
5331
5345
  action : 'billing',
@@ -4038,7 +4038,7 @@ var shopify_default2 = {
4038
4038
  // against the ones the app now needs, and queues a webhook
4039
4039
  // reconciliation.
4040
4040
  health: async ({ connection: connection2, workflow }, { adminToken, logger: logger2, read, reconcileScopes, resolveSettings, rotateToken, shopify } = {}) => {
4041
- var _a, _b;
4041
+ var _a, _b, _c;
4042
4042
  const request2 = {
4043
4043
  connectionId: workflow.connection,
4044
4044
  organizationId: workflow.organization,
@@ -4060,7 +4060,7 @@ var shopify_default2 = {
4060
4060
  const writes = [];
4061
4061
  let source = connection2.source || null;
4062
4062
  let sourceRepaired = false;
4063
- let metered = (source == null ? void 0 : source.metered) ?? null;
4063
+ let metered;
4064
4064
  let shopCurrency = null;
4065
4065
  let billingProbeFailed = false;
4066
4066
  try {
@@ -4079,21 +4079,21 @@ var shopify_default2 = {
4079
4079
  domain: connection2.shop
4080
4080
  });
4081
4081
  if (subscriptions.length && subscriptions.every((subscription) => typeof subscription.metered === "boolean")) {
4082
- metered = subscriptions.some((subscription) => subscription.metered);
4082
+ metered = ((_a = subscriptions.find((subscription) => subscription.usageLineItemId)) == null ? void 0 : _a.usageLineItemId) || null;
4083
4083
  }
4084
4084
  } catch (probeError) {
4085
4085
  billingProbeFailed = true;
4086
- (_a = logger2 == null ? void 0 : logger2.warn) == null ? void 0 : _a.call(logger2, "shopify.health.billing.probe.failed", {
4086
+ (_b = logger2 == null ? void 0 : logger2.warn) == null ? void 0 : _b.call(logger2, "shopify.health.billing.probe.failed", {
4087
4087
  connectionId: connection2.id,
4088
4088
  message: probeError == null ? void 0 : probeError.message,
4089
4089
  shop: connection2.shop
4090
4090
  });
4091
4091
  }
4092
- if (sourceRepaired || metered !== null && metered !== (((_b = connection2.source) == null ? void 0 : _b.metered) ?? null)) {
4092
+ if (sourceRepaired || metered !== void 0 && metered !== (((_c = connection2.source) == null ? void 0 : _c.metered) ?? void 0)) {
4093
4093
  writes.push({
4094
4094
  collection: "connection",
4095
4095
  data: {
4096
- $set: sourceRepaired ? { source: { ...source, ...metered !== null && { metered } } } : { "source.metered": metered }
4096
+ $set: sourceRepaired ? { source: { ...source, ...metered !== void 0 && { metered } } } : { "source.metered": metered }
4097
4097
  },
4098
4098
  operation: "update",
4099
4099
  query: { id: connection2.id }
@@ -4113,11 +4113,12 @@ var shopify_default2 = {
4113
4113
  options: { jobId: "connection.update.register." + workflow.connection + "." + randomUUID() },
4114
4114
  queue: "connection"
4115
4115
  }],
4116
- message: ((scopesMissing == null ? void 0 : scopesMissing.length) ? "Health check: ping ok, webhooks reconciled \u2014 connection errored, granted scopes are missing: " + scopesMissing.join(", ") + "." : refreshTokenRotated ? "Health check passed \u2014 refresh token rotated, ping ok, webhooks reconciled." : "Health check passed \u2014 ping ok, webhooks reconciled.") + (sourceRepaired ? " Billing source repaired from the live shop." : "") + (metered === false ? " No usage line on the store's approved plan \u2014 order billing needs the merchant to approve the updated plan." : ""),
4116
+ message: ((scopesMissing == null ? void 0 : scopesMissing.length) ? "Health check: ping ok, webhooks reconciled \u2014 connection errored, granted scopes are missing: " + scopesMissing.join(", ") + "." : refreshTokenRotated ? "Health check passed \u2014 refresh token rotated, ping ok, webhooks reconciled." : "Health check passed \u2014 ping ok, webhooks reconciled.") + (sourceRepaired ? " Billing source repaired from the live shop." : "") + (metered === null ? " No usage line on the store's approved plan \u2014 order billing needs the merchant to approve the updated plan." : ""),
4117
4117
  request: request2,
4118
4118
  response: {
4119
4119
  billingProbeFailed,
4120
- metered,
4120
+ metered: metered ?? null,
4121
+ meterProbed: metered !== void 0,
4121
4122
  pingedAt: /* @__PURE__ */ new Date(),
4122
4123
  refreshTokenExpiresAt: refreshTokenExpiresAt || null,
4123
4124
  refreshTokenRotated,
@@ -4409,11 +4410,13 @@ var shopify_default2 = {
4409
4410
  }
4410
4411
  ] : [],
4411
4412
  // The store's ACTIVE approval carries no usage component — stamped by
4412
- // the daily health check and the approval webhook (`source.metered`).
4413
- // Approved pricing is never retroactive, so the fix is a fresh approval.
4414
- // Gated on an EXPLICIT false a connection the probe hasn't reached
4415
- // (or couldn't read) shows nothing rather than nagging on silence.
4416
- ...(data2 == null ? void 0 : data2.status) === "active" && ((_a = data2 == null ? void 0 : data2.source) == null ? void 0 : _a.metered) === false ? [
4413
+ // the daily health check and the approval webhook (`source.metered`:
4414
+ // the usage line's id when present, null when probed-and-absent).
4415
+ // Approved pricing is never retroactive, so the fix is a fresh
4416
+ // approval. Gated on an EXPLICIT null a connection the probe hasn't
4417
+ // reached (or couldn't read) has no key and shows nothing rather than
4418
+ // nagging on silence.
4419
+ ...(data2 == null ? void 0 : data2.status) === "active" && ((_a = data2 == null ? void 0 : data2.source) == null ? void 0 : _a.metered) === null ? [
4417
4420
  {
4418
4421
  action: "billing",
4419
4422
  message: "Order billing isn't set up for this store, so campaign-attributed orders aren't being charged. Approve the updated plan to fix it \u2014 one click here, one confirmation on Shopify.",
@@ -4018,7 +4018,7 @@ var shopify_default2 = {
4018
4018
  // against the ones the app now needs, and queues a webhook
4019
4019
  // reconciliation.
4020
4020
  health: async ({ connection: connection2, workflow }, { adminToken, logger: logger2, read, reconcileScopes, resolveSettings, rotateToken, shopify } = {}) => {
4021
- var _a, _b;
4021
+ var _a, _b, _c;
4022
4022
  const request2 = {
4023
4023
  connectionId: workflow.connection,
4024
4024
  organizationId: workflow.organization,
@@ -4040,7 +4040,7 @@ var shopify_default2 = {
4040
4040
  const writes = [];
4041
4041
  let source = connection2.source || null;
4042
4042
  let sourceRepaired = false;
4043
- let metered = (source == null ? void 0 : source.metered) ?? null;
4043
+ let metered;
4044
4044
  let shopCurrency = null;
4045
4045
  let billingProbeFailed = false;
4046
4046
  try {
@@ -4059,21 +4059,21 @@ var shopify_default2 = {
4059
4059
  domain: connection2.shop
4060
4060
  });
4061
4061
  if (subscriptions.length && subscriptions.every((subscription) => typeof subscription.metered === "boolean")) {
4062
- metered = subscriptions.some((subscription) => subscription.metered);
4062
+ metered = ((_a = subscriptions.find((subscription) => subscription.usageLineItemId)) == null ? void 0 : _a.usageLineItemId) || null;
4063
4063
  }
4064
4064
  } catch (probeError) {
4065
4065
  billingProbeFailed = true;
4066
- (_a = logger2 == null ? void 0 : logger2.warn) == null ? void 0 : _a.call(logger2, "shopify.health.billing.probe.failed", {
4066
+ (_b = logger2 == null ? void 0 : logger2.warn) == null ? void 0 : _b.call(logger2, "shopify.health.billing.probe.failed", {
4067
4067
  connectionId: connection2.id,
4068
4068
  message: probeError == null ? void 0 : probeError.message,
4069
4069
  shop: connection2.shop
4070
4070
  });
4071
4071
  }
4072
- if (sourceRepaired || metered !== null && metered !== (((_b = connection2.source) == null ? void 0 : _b.metered) ?? null)) {
4072
+ if (sourceRepaired || metered !== void 0 && metered !== (((_c = connection2.source) == null ? void 0 : _c.metered) ?? void 0)) {
4073
4073
  writes.push({
4074
4074
  collection: "connection",
4075
4075
  data: {
4076
- $set: sourceRepaired ? { source: { ...source, ...metered !== null && { metered } } } : { "source.metered": metered }
4076
+ $set: sourceRepaired ? { source: { ...source, ...metered !== void 0 && { metered } } } : { "source.metered": metered }
4077
4077
  },
4078
4078
  operation: "update",
4079
4079
  query: { id: connection2.id }
@@ -4093,11 +4093,12 @@ var shopify_default2 = {
4093
4093
  options: { jobId: "connection.update.register." + workflow.connection + "." + (0, import_node_crypto5.randomUUID)() },
4094
4094
  queue: "connection"
4095
4095
  }],
4096
- message: ((scopesMissing == null ? void 0 : scopesMissing.length) ? "Health check: ping ok, webhooks reconciled \u2014 connection errored, granted scopes are missing: " + scopesMissing.join(", ") + "." : refreshTokenRotated ? "Health check passed \u2014 refresh token rotated, ping ok, webhooks reconciled." : "Health check passed \u2014 ping ok, webhooks reconciled.") + (sourceRepaired ? " Billing source repaired from the live shop." : "") + (metered === false ? " No usage line on the store's approved plan \u2014 order billing needs the merchant to approve the updated plan." : ""),
4096
+ message: ((scopesMissing == null ? void 0 : scopesMissing.length) ? "Health check: ping ok, webhooks reconciled \u2014 connection errored, granted scopes are missing: " + scopesMissing.join(", ") + "." : refreshTokenRotated ? "Health check passed \u2014 refresh token rotated, ping ok, webhooks reconciled." : "Health check passed \u2014 ping ok, webhooks reconciled.") + (sourceRepaired ? " Billing source repaired from the live shop." : "") + (metered === null ? " No usage line on the store's approved plan \u2014 order billing needs the merchant to approve the updated plan." : ""),
4097
4097
  request: request2,
4098
4098
  response: {
4099
4099
  billingProbeFailed,
4100
- metered,
4100
+ metered: metered ?? null,
4101
+ meterProbed: metered !== void 0,
4101
4102
  pingedAt: /* @__PURE__ */ new Date(),
4102
4103
  refreshTokenExpiresAt: refreshTokenExpiresAt || null,
4103
4104
  refreshTokenRotated,
@@ -4389,11 +4390,13 @@ var shopify_default2 = {
4389
4390
  }
4390
4391
  ] : [],
4391
4392
  // The store's ACTIVE approval carries no usage component — stamped by
4392
- // the daily health check and the approval webhook (`source.metered`).
4393
- // Approved pricing is never retroactive, so the fix is a fresh approval.
4394
- // Gated on an EXPLICIT false a connection the probe hasn't reached
4395
- // (or couldn't read) shows nothing rather than nagging on silence.
4396
- ...(data2 == null ? void 0 : data2.status) === "active" && ((_a = data2 == null ? void 0 : data2.source) == null ? void 0 : _a.metered) === false ? [
4393
+ // the daily health check and the approval webhook (`source.metered`:
4394
+ // the usage line's id when present, null when probed-and-absent).
4395
+ // Approved pricing is never retroactive, so the fix is a fresh
4396
+ // approval. Gated on an EXPLICIT null a connection the probe hasn't
4397
+ // reached (or couldn't read) has no key and shows nothing rather than
4398
+ // nagging on silence.
4399
+ ...(data2 == null ? void 0 : data2.status) === "active" && ((_a = data2 == null ? void 0 : data2.source) == null ? void 0 : _a.metered) === null ? [
4397
4400
  {
4398
4401
  action: "billing",
4399
4402
  message: "Order billing isn't set up for this store, so campaign-attributed orders aren't being charged. Approve the updated plan to fix it \u2014 one click here, one confirmation on Shopify.",
package/dist/providers.js CHANGED
@@ -3974,7 +3974,7 @@ var shopify_default2 = {
3974
3974
  // against the ones the app now needs, and queues a webhook
3975
3975
  // reconciliation.
3976
3976
  health: async ({ connection: connection2, workflow }, { adminToken, logger: logger2, read, reconcileScopes, resolveSettings, rotateToken, shopify } = {}) => {
3977
- var _a, _b;
3977
+ var _a, _b, _c;
3978
3978
  const request2 = {
3979
3979
  connectionId: workflow.connection,
3980
3980
  organizationId: workflow.organization,
@@ -3996,7 +3996,7 @@ var shopify_default2 = {
3996
3996
  const writes = [];
3997
3997
  let source = connection2.source || null;
3998
3998
  let sourceRepaired = false;
3999
- let metered = (source == null ? void 0 : source.metered) ?? null;
3999
+ let metered;
4000
4000
  let shopCurrency = null;
4001
4001
  let billingProbeFailed = false;
4002
4002
  try {
@@ -4015,21 +4015,21 @@ var shopify_default2 = {
4015
4015
  domain: connection2.shop
4016
4016
  });
4017
4017
  if (subscriptions.length && subscriptions.every((subscription) => typeof subscription.metered === "boolean")) {
4018
- metered = subscriptions.some((subscription) => subscription.metered);
4018
+ metered = ((_a = subscriptions.find((subscription) => subscription.usageLineItemId)) == null ? void 0 : _a.usageLineItemId) || null;
4019
4019
  }
4020
4020
  } catch (probeError) {
4021
4021
  billingProbeFailed = true;
4022
- (_a = logger2 == null ? void 0 : logger2.warn) == null ? void 0 : _a.call(logger2, "shopify.health.billing.probe.failed", {
4022
+ (_b = logger2 == null ? void 0 : logger2.warn) == null ? void 0 : _b.call(logger2, "shopify.health.billing.probe.failed", {
4023
4023
  connectionId: connection2.id,
4024
4024
  message: probeError == null ? void 0 : probeError.message,
4025
4025
  shop: connection2.shop
4026
4026
  });
4027
4027
  }
4028
- if (sourceRepaired || metered !== null && metered !== (((_b = connection2.source) == null ? void 0 : _b.metered) ?? null)) {
4028
+ if (sourceRepaired || metered !== void 0 && metered !== (((_c = connection2.source) == null ? void 0 : _c.metered) ?? void 0)) {
4029
4029
  writes.push({
4030
4030
  collection: "connection",
4031
4031
  data: {
4032
- $set: sourceRepaired ? { source: { ...source, ...metered !== null && { metered } } } : { "source.metered": metered }
4032
+ $set: sourceRepaired ? { source: { ...source, ...metered !== void 0 && { metered } } } : { "source.metered": metered }
4033
4033
  },
4034
4034
  operation: "update",
4035
4035
  query: { id: connection2.id }
@@ -4049,11 +4049,12 @@ var shopify_default2 = {
4049
4049
  options: { jobId: "connection.update.register." + workflow.connection + "." + randomUUID() },
4050
4050
  queue: "connection"
4051
4051
  }],
4052
- message: ((scopesMissing == null ? void 0 : scopesMissing.length) ? "Health check: ping ok, webhooks reconciled \u2014 connection errored, granted scopes are missing: " + scopesMissing.join(", ") + "." : refreshTokenRotated ? "Health check passed \u2014 refresh token rotated, ping ok, webhooks reconciled." : "Health check passed \u2014 ping ok, webhooks reconciled.") + (sourceRepaired ? " Billing source repaired from the live shop." : "") + (metered === false ? " No usage line on the store's approved plan \u2014 order billing needs the merchant to approve the updated plan." : ""),
4052
+ message: ((scopesMissing == null ? void 0 : scopesMissing.length) ? "Health check: ping ok, webhooks reconciled \u2014 connection errored, granted scopes are missing: " + scopesMissing.join(", ") + "." : refreshTokenRotated ? "Health check passed \u2014 refresh token rotated, ping ok, webhooks reconciled." : "Health check passed \u2014 ping ok, webhooks reconciled.") + (sourceRepaired ? " Billing source repaired from the live shop." : "") + (metered === null ? " No usage line on the store's approved plan \u2014 order billing needs the merchant to approve the updated plan." : ""),
4053
4053
  request: request2,
4054
4054
  response: {
4055
4055
  billingProbeFailed,
4056
- metered,
4056
+ metered: metered ?? null,
4057
+ meterProbed: metered !== void 0,
4057
4058
  pingedAt: /* @__PURE__ */ new Date(),
4058
4059
  refreshTokenExpiresAt: refreshTokenExpiresAt || null,
4059
4060
  refreshTokenRotated,
@@ -4345,11 +4346,13 @@ var shopify_default2 = {
4345
4346
  }
4346
4347
  ] : [],
4347
4348
  // The store's ACTIVE approval carries no usage component — stamped by
4348
- // the daily health check and the approval webhook (`source.metered`).
4349
- // Approved pricing is never retroactive, so the fix is a fresh approval.
4350
- // Gated on an EXPLICIT false a connection the probe hasn't reached
4351
- // (or couldn't read) shows nothing rather than nagging on silence.
4352
- ...(data2 == null ? void 0 : data2.status) === "active" && ((_a = data2 == null ? void 0 : data2.source) == null ? void 0 : _a.metered) === false ? [
4349
+ // the daily health check and the approval webhook (`source.metered`:
4350
+ // the usage line's id when present, null when probed-and-absent).
4351
+ // Approved pricing is never retroactive, so the fix is a fresh
4352
+ // approval. Gated on an EXPLICIT null a connection the probe hasn't
4353
+ // reached (or couldn't read) has no key and shows nothing rather than
4354
+ // nagging on silence.
4355
+ ...(data2 == null ? void 0 : data2.status) === "active" && ((_a = data2 == null ? void 0 : data2.source) == null ? void 0 : _a.metered) === null ? [
4353
4356
  {
4354
4357
  action: "billing",
4355
4358
  message: "Order billing isn't set up for this store, so campaign-attributed orders aren't being charged. Approve the updated plan to fix it \u2014 one click here, one confirmation on Shopify.",
package/package.json CHANGED
@@ -216,5 +216,5 @@
216
216
  "prepublishOnly": ". \"$HOME/.nvm/nvm.sh\" && nvm use && tsup && node --test"
217
217
  },
218
218
  "types": "dist/index.d.ts",
219
- "version": "0.0.142"
219
+ "version": "0.0.143"
220
220
  }