npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@bethinkpl/reorder

v1.8.0

Published

Customized version of @reorderjs/reorder.

Readme

@bethinkpl/reorder

Customized fork of @reorder/reorderjs.

Changes

New features

  • added day granularity for frequency intervals

Improvements / Fixes

  • prevents executing POST /store/carts/{cartId}/complete for carts containing subscription items
  • behaviour of POST /store/carts/{cartId}/subscribe matches it's non-subscription counterpart more closely (dropped subscription field, supports query params and uses same defaults)
  • shipping address is optional when item(s) in subscription cart don't require shipping (i.e.: item.requires_shipping = false)
  • exposed setPaymentSessionData hook in processRenewalCycleWorkflow for provider-agnostic payment handling during renewals
  • exposed the same setPaymentSessionData hook in runDunningRetryWorkflow (input: { subscription: { id, payment_context } }) so dunning retries use the host app's payment session payload, falling back to the stock Stripe payload when no handler is registered
  • dunning now emits five lifecycle events (names exported as DunningEvents from @bethinkpl/reorder/modules/dunning) for the host app to notify customers on: subscription.dunning_started ({ subscription_id, dunning_case_id, renewal_cycle_id, attempt_count, next_retry_at }, fired only when a case is created — a repeated failure on the same renewal cycle re-enters the existing case and stays silent), subscription.dunning_attempt_failed ({ subscription_id, dunning_case_id, attempt_no, error_code, next_retry_at }, fired when a counted retry failed and another one is scheduled; no-budget reschedules stay silent - a tick that charged nothing and handed its attempt slot back never tells the customer their payment failed), subscription.payment_failed ({ subscription_id, dunning_case_id, recovery_reason }, fired only by the run that actually moves the subscription to payment_failed, from either the exhausted retry loop or the admin "mark unrecovered" action — a later settlement of an already-payment_failed subscription stays silent), subscription.dunning_parked ({ subscription_id, dunning_case_id, attempt_no, park_reason, error_code }, fired when a retry is handed to an operator instead of being settled or rescheduled; park_reason is one of setup_failure, requires_action, customer_payment_stalled, unreached_provider or indeterminate_provider_response) and subscription.dunning_recovered ({ subscription_id, dunning_case_id, renewal_order_id, recovery_reason }, fired when a case closes as recovered — recovery_reason is payment_recovered when a scheduled retry collected it and customer_payment when the customer paid the renewal order themselves through the host app, which also settles the renewal cycle, advances the billing dates and hands the subscription back to active). Delivery is at-most-once and immediate: each event is dispatched as soon as its emitting step runs, once the module writes that triggered it have committed, so a later step failing in the same workflow (e.g. the lock release) cannot retract an event that already went out, and a rejecting bus is never retried. Emitting never fails the workflow either — an event bus that rejects is logged as an alertable dunning error and the case keeps its state
  • renewals and dunning retries capture through the payment module directly, which emits nothing: payment.captured (and any host invoicing, tax or email hanging off it) arrives only when the provider's own webhook for that charge is delivered and the host's provider maps it to a successful action. With a missing or mis-signed webhook endpoint the subscription still renews and a dunning case still reads recovered, and nothing errors
  • a scheduled dunning retry now steps aside instead of destroying a payment the customer is in the middle of: before it touches the renewal order it reads every payment session on every payment collection of that order, and when one is still live (status pending, pending_authorization or requires_more, created less than 60 minutes ago and not past its own data.expiresAt) or a sibling collection holds somebody else's authorization (authorized or partially_authorized), the tick charges nothing - it aborts its attempt row, hands the attempt slot back to the budget and reschedules itself 60 minutes later without notifying the customer, never touching the case setup-failure streak and only parking the case (park_reason: "customer_payment_stalled") once 24 ticks in a row have stepped aside (an admin retry now is skipped the same way; the skips are counted in metadata.session_conflict_count, which is informational and cleared as soon as a retry reaches the provider). Sessions a retry creates mark themselves with context: { dunning_case_id, dunning_attempt_id } and sessions a renewal run creates with context: { renewal_cycle_id }, so neither ever reads the other's session - or its own leftovers, including an authorization a failed capture left behind - as a customer's. A host app that creates its own payment sessions on a renewal order is protected as long as it sets neither marker on them, and it can mark a session context: { initiated_by: "customer" } to be treated as the customer's whatever else it carries
  • the daily renewal job applies the same guard before it reuses an order a previous run already created: if the customer is mid-checkout on it, the run is skipped before it records anything - no attempt row, no new failure, no dunning case - so the cycle keeps the failed status it already had and the next window picks it up again. The job counts the skip as blocked rather than failed (failure_kind: "customer_payment_in_progress", never alertable)
  • completing subscription cart no longer requires payment method to be already saved at that point of time, instead it's info is backfilled after payment is captured
  • renewal orders recompute the subscription plan discount instead of billing full catalog price (frozen pricing_snapshot first, live plan config on plan change), with a combined-discount clamp applied on both checkout and renewals
  • exposed resolveRenewalAdjustments hook in processRenewalCycleWorkflow so the host app can add its own (code-less) discounts to renewal orders, and subscriptionCreated hook in createSubscriptionFromCartWorkflow for reacting to genuine subscription creation
  • source_snapshot now truthfully captures the initial order's adjustments and tax lines (audit-only — renewals deliberately no longer replay them)
  • renewal cycles stranded in PROCESSING by an unhandled failure between steps are now marked FAILED via compensation, keeping them retryable

QoL

  • addition of eslint lint rules
  • improved test setup

Content of README.md WIP