@drawbridge/drawbridge-agents 0.1.43 → 0.1.49
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.
|
@@ -31,6 +31,15 @@ skill) so it stops living only in tribal memory.
|
|
|
31
31
|
|
|
32
32
|
- All socket emits from sync go through `drawbridge-sync/lib/emit.js` — never call
|
|
33
33
|
`io.to().emit()` directly from a worker.
|
|
34
|
+
- An `sms` identity row is **never created `verified`**: api's purchase route writes
|
|
35
|
+
`status:'pending'` + the `business` details, sync's `queue/identity.js` verify job is the
|
|
36
|
+
ONLY writer of `'verified'` (after Twilio Toll-Free Verification approval, via the utils
|
|
37
|
+
twilio transport — it also renders and uploads the opt-in evidence at submission), and
|
|
38
|
+
sync's `queue/notification.js` sends from `'verified'` rows only. An api route (or script)
|
|
39
|
+
minting `'verified'` ships a number Twilio blocks outright — it looks live and delivers
|
|
40
|
+
nothing. (Collection renamed `networking` → `identity` 2026-09-03, pre-data; the plan
|
|
41
|
+
feature key stays `organization:networking` because custom-plan documents can store
|
|
42
|
+
granted keys — that string is data, never rename it without a migration.)
|
|
34
43
|
- Cascade cleanup of dependent rows belongs in a sync change-stream listener, not inline in the
|
|
35
44
|
API route that triggered the delete (see `cascade-cleanup.md`).
|
|
36
45
|
- A collection with no `queue/<collection>.js` handler is watched but its events are **silently
|
|
@@ -127,6 +136,16 @@ skill) so it stops living only in tribal memory.
|
|
|
127
136
|
admin-negotiated actions values, so read the dry run). The legacy keys are copy-only until the
|
|
128
137
|
overrides cleanup release, and sync (reader) deploys before stripe (writer) on any shape change.
|
|
129
138
|
Detail: drawbridge-docs `reference/billing.md`.
|
|
139
|
+
- **Stripe response shapes follow drawbridge-stripe's `apiVersion` pin, not the Stripe docs
|
|
140
|
+
default** (stripe ↔ api ↔ sync ↔ webhooks). The shared client pins a preview version
|
|
141
|
+
(`drawbridge-stripe/index.js`, currently `2026-01-28.preview`), and pinned versions change
|
|
142
|
+
embedded-object shapes — e.g. a promotion code carries its coupon as a bare id under
|
|
143
|
+
`promotion.coupon`; there is no embedded `coupon` object. Reading the docs-default shape fails
|
|
144
|
+
SILENTLY (optional chaining just skips the branch): the promo entry validation shipped with its
|
|
145
|
+
currency and product-restriction refusals dead this way (Asana 1211453698575738). Before reading
|
|
146
|
+
a Stripe field a consumer hasn't read before, verify it against a real response at the pin
|
|
147
|
+
(`curl` with the `Stripe-Version` header); treat any pin bump as a shape-change release across
|
|
148
|
+
every consumer.
|
|
130
149
|
- **No Stripe product backs actions (≥0.1.45).** Invoice items carry
|
|
131
150
|
currency/quantity/unit_amount_decimal/tax_behavior/description directly; the account keeps exactly
|
|
132
151
|
one product — the plan product behind `STRIPE_PRICE_*`. Never reintroduce a product-presence guard
|
|
@@ -134,6 +153,17 @@ skill) so it stops living only in tribal memory.
|
|
|
134
153
|
would have zeroed every invoice once the products were archived.
|
|
135
154
|
- **The v2 pricing-plan layer (`bpp_*`, billing cadences) is never touched by script.** Canceling a
|
|
136
155
|
billing cadence is terminal and unrecoverable. Dashboard, by hand, only.
|
|
156
|
+
- **The Shopify meter handle is a config contract no code validates** (shopify ↔ Partner
|
|
157
|
+
Dashboard ↔ sync/utils). `SHOPIFY_USAGE_ORDERS_EVENT_HANDLE` in `@drawbridge/shopify`
|
|
158
|
+
(`drawbridge-orders`) must exactly match — case-sensitive, handle not display name — a usage
|
|
159
|
+
meter on the App Pricing plan version each merchant has APPROVED (meters are never
|
|
160
|
+
retroactive). A mismatch, a missing meter, or a merchant on a pre-meter plan still 202s every
|
|
161
|
+
event, logs it as a plain app event, and bills nothing; no error surfaces anywhere in code
|
|
162
|
+
(the 19/99 write-off). Any change to the handle constant, the Partner Dashboard pricing
|
|
163
|
+
config, or a plan version requires verifying a fresh order classifies as a billing event in
|
|
164
|
+
Dev Dashboard → Logs (type "App billing event"). The trace key both sides share is
|
|
165
|
+
`billed.transaction` = the event's `reference` = `drawbridge-orders.<orderId>`. Detail:
|
|
166
|
+
drawbridge-docs `reference/shopify-app.md` (Billing).
|
|
137
167
|
- **A subscription must open with the plan item.** It used to open with the metered actions price
|
|
138
168
|
and attach the plan afterwards with `always_invoice`. With no metered item, Stripe rejects an
|
|
139
169
|
itemless subscription, so the plan goes in at creation — changing the first invoice's shape.
|
|
@@ -294,6 +324,15 @@ skill) so it stops living only in tribal memory.
|
|
|
294
324
|
in the tree. Keep the pins aligned.
|
|
295
325
|
- Shared packages that wrap a stateful SDK (Sentry, redis, mongodb) must direct-dep it at an
|
|
296
326
|
exact pin, never a loose peer range (see `sentry-sdk.md`).
|
|
327
|
+
- **A publish must rebuild `dist/` in the same command** — every published package needs a
|
|
328
|
+
`prepublishOnly` script (tsup + tests), because a bare `npm publish` ships whatever stale
|
|
329
|
+
`dist/` sits on disk with the current `package.json` version stamped on it: the version says
|
|
330
|
+
one thing, the code says another, and nothing errors anywhere. utils `0.0.100/0.0.101`
|
|
331
|
+
silently dropped the multipart upload exports this way, and utils `0.0.139` shipped the old
|
|
332
|
+
2GB `maximumUploadBytes` under a version everyone believed carried 50MB (2026-09-04; `0.0.139`
|
|
333
|
+
is poisoned — never pin it). utils ≥0.0.140 has the guard; add it to any `@drawbridge/*`
|
|
334
|
+
package before its next publish (`shopify` flagged 2026-09-04). After ANY publish, verify the
|
|
335
|
+
tarball, not the git tree: `npm pack`/curl the tarball and grep `dist/` for the change.
|
|
297
336
|
- `@drawbridge/components` `Video` (≥0.0.62) owns the whole pre-playback story; consumers must NOT
|
|
298
337
|
re-add their own poster layer or mount gate. `poster` renders as an SSR placeholder (opt into
|
|
299
338
|
`priority` for fetchpriority=high when it's the LCP element), `defer` gates only the player —
|
|
@@ -384,6 +423,21 @@ renaming one orphans what is already enqueued and starts a parallel stream nobod
|
|
|
384
423
|
with no error. `bullmq-identity.test.js` in sync spells out the routing table so moving a
|
|
385
424
|
step between queues requires editing it deliberately.
|
|
386
425
|
|
|
426
|
+
**`grant_refused` is minted in utils, keyed on in sync (utils ↔ sync).** Only the two
|
|
427
|
+
dead-grant paths in drawbridge-utils — a refused refresh (`connections/oauth.js`) and an
|
|
428
|
+
unrenewable expiry (`connections/token.js`) — set `error.code = 'grant_refused'`; a network
|
|
429
|
+
failure never does. Sync's step-runner errors the connection on that code during a
|
|
430
|
+
`lifecycle.health` step (the shell mints the token, so the hook can't). Minting the code
|
|
431
|
+
anywhere transient flips healthy connections to error on a blip; renaming it in either repo
|
|
432
|
+
means dead grants retry into Sentry forever (the Shopify 08-16 incident, ecosystem-wide).
|
|
433
|
+
|
|
434
|
+
**The SMS inbound URL is one string two repos must agree on (api ↔ sync ↔ webhooks).**
|
|
435
|
+
`APP_CLIENT_WEBHOOKS_URI + '/connection/drawbridge/sms'` is written to each purchased
|
|
436
|
+
number by api (`route/organization-networking.js`) and re-asserted by sync's daily identity
|
|
437
|
+
sweep (`queue/identity.js`), which re-points any number whose Twilio config drifts. Change
|
|
438
|
+
the path in one place and the sweep "repairs" every number to the wrong URL — inbound SMS
|
|
439
|
+
(STOP included) goes dark with all rows reading healthy.
|
|
440
|
+
|
|
387
441
|
## Import surfaces
|
|
388
442
|
|
|
389
443
|
- Import names against a package's **actual exports** — a missing export resolves to `undefined`
|
package/package.json
CHANGED