@blamejs/blamejs-shop 0.0.70 → 0.0.75
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/CHANGELOG.md +10 -0
- package/lib/announcement-bar.js +753 -0
- package/lib/banner-ab-tests.js +806 -0
- package/lib/bin-locations.js +791 -0
- package/lib/blog-articles.js +1173 -0
- package/lib/carrier-accounts.js +805 -0
- package/lib/cart-recovery.js +1133 -0
- package/lib/category-navigation.js +934 -0
- package/lib/consent-ledger.js +539 -0
- package/lib/customer-impersonation.js +743 -0
- package/lib/customer-merge.js +879 -0
- package/lib/demand-forecast.js +1121 -0
- package/lib/dispute-resolution.js +886 -0
- package/lib/email-ab-tests.js +918 -0
- package/lib/email-engagement-score.js +649 -0
- package/lib/event-log.js +713 -0
- package/lib/fulfillment-sla.js +791 -0
- package/lib/index.js +42 -0
- package/lib/inventory-audits.js +852 -0
- package/lib/line-gift-wrap.js +430 -0
- package/lib/loyalty-earn-rules.js +786 -0
- package/lib/marketing-budget.js +792 -0
- package/lib/operator-activity-feed.js +977 -0
- package/lib/operator-approvals.js +942 -0
- package/lib/operator-help-center.js +1020 -0
- package/lib/operator-inbox.js +889 -0
- package/lib/operator-sessions.js +701 -0
- package/lib/order-exchanges.js +602 -0
- package/lib/product-compare.js +804 -0
- package/lib/pwa-manifest.js +1005 -0
- package/lib/referral-leaderboard.js +612 -0
- package/lib/sales-tax-filings.js +807 -0
- package/lib/search-ranking.js +859 -0
- package/lib/shipping-insurance.js +757 -0
- package/lib/shrinkage-report.js +1182 -0
- package/lib/sidebar-widgets.js +952 -0
- package/lib/smart-restocking.js +1048 -0
- package/lib/split-shipments.js +7 -1
- package/lib/stock-receipts.js +834 -0
- package/lib/subscription-analytics.js +1032 -0
- package/lib/suggestion-box.js +921 -0
- package/lib/tax-remittance.js +625 -0
- package/lib/vendor-invoices.js +1021 -0
- package/lib/winback-campaigns.js +1350 -0
- package/lib/wishlist-digest.js +1133 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,16 @@ upgrading across more than a few patches at a time.
|
|
|
8
8
|
|
|
9
9
|
## v0.0.x
|
|
10
10
|
|
|
11
|
+
- v0.0.75 (2026-05-22) — **Sixteen new primitives across operator tooling, vendor / inventory ops, marketing automation, and storefront content.** Sixteen primitives ship together. Operator + admin: customerImpersonation, carrierAccounts, operatorApprovals, customerMerge, operatorHelpCenter, eventLog. Vendor + inventory: vendorInvoices, inventoryAudits, smartRestocking, taxRemittance. Marketing + retention: winbackCampaigns, wishlistDigest. Storefront: blogArticles, categoryNavigation, productCompare, lineGiftWrap. **Added:** *`customerImpersonation` primitive — operator login-as-customer with audit* — 32-byte plaintext token returned once; namespaceHash at rest. 60-min default TTL. Capability gate via operatorRoles.hasPermission. notifyCustomer fan-out via injected notifications. actionsRecord builds the audit trail. Migration `0190`. · *`carrierAccounts` primitive — per-operator carrier API account management* — Carrier enum: ups / fedex / usps / dhl / canada_post / royal_mail / australia_post. All secrets hashed via namespaceHash under per-field namespaces. rotateCredentials with 24h grace. verifyCredentials timing-safe. Migration `0191`. · *`operatorApprovals` primitive — multi-step approval workflows* — Defines workflows with required_approvers + required_capability + escalation_after_hours. castVote dedup via UNIQUE(request_id, approver_id). Status FSM pending / approved / rejected / executed / cancelled / escalated. Migration `0192`. · *`vendorInvoices` primitive — vendor-issued invoices with PO reconciliation* — FSM received → approved → paid with disputed + voided side branches. Partial-pay first-class. UNIQUE(vendor_slug, invoice_number) for dedup. reconcileAgainstPOs returns variance summary. agingReport bucketing. Migration `0193`. · *`customerMerge` primitive — operator merge of duplicate customer accounts* — Reparents orders + subscriptions + loyalty + reviews + addresses + paymentMethods atomically (pre-flight all, then write all). 7-day rollback window. Jaro-Winkler-scored findDuplicateCandidates. customer_merge_redirects table for forwarding. Migration `0194`. · *`productCompare` primitive — storefront 2-4 product comparison* — Cap of 4 per session. compareTable returns per-attribute rows for the table render. Default attributes: price / sku / brand / vendor / weight / dimensions / inventory_status. defineCompareAttribute adds custom rows. popularCompares for analytics. Migration `0195`. · *`winbackCampaigns` primitive — multi-step re-engagement for lapsed customers* — Operator defines lapse_days_min + lapse_days_max + steps (delay + template + optional coupon). scanForLapsedCustomers finds candidates; enrollCustomer schedules; dispatchTick advances. markRecovered halts further steps. metricsForCampaign returns recovery rate + avg time-to-purchase. Migration `0196`. · *`inventoryAudits` primitive — periodic full-inventory audits* — Kinds: full / quarterly / spot. Scopes: all / category / vendor / location. recordScanLine + markRecount + finalizeAudit. Variance write-through composes inventoryLocations.adjustStock with `inventory-audit:<slug>` reason. compareToPriorAudit returns per-(sku, location) deltas. Migration `0197`. · *`wishlistDigest` primitive — scheduled weekly / monthly wishlist email digests* — Per-customer enrollment + cadence. next_dispatch_at computed via Intl.DateTimeFormat with two-pass DST-fold refinement. composeDigest returns HTML + text. Suppressed customers keep cadence ETA on rails but no email fires. Migration `0198`. · *`eventLog` primitive — universal append-only application event stream* — Drop-silent on bad input. Severity: debug / info / warning / critical. query with HMAC cursor. tail + topKinds + metricsForKind + purgeOlderThan (exclude_critical opt-in). Distinct from analytics (customer events) and operatorAuditLog (operator mutations). Migration `0199`. · *`operatorHelpCenter` primitive — in-admin operator help articles* — audience_roles closed allow-list against operatorRoles.PERMISSIONS. searchSuggest title 3 / section 2 / body 1 weighted ranker. recordHelpfulVote dedup at UNIQUE(slug, operator_id). Migration `0200`. · *`categoryNavigation` primitive — hierarchical storefront category tree* — self-FK parent_slug + CHECK(slug != parent_slug). tree returns nested shape. breadcrumbsFor returns ancestor chain. move walks ancestor chain to refuse cycles (bounded MAX_TREE_DEPTH=16). reorderSiblings requires the complete member set. Migration `0201`. · *`lineGiftWrap` primitive — per-line gift wrap selection* — Distinct from giftOptions (one wrap for the whole order). UNIQUE(order_id, line_id) UPSERT. gift_message ≤ 500 chars + control-byte refusal; recipient_name ≤ 120. feeForOrder sums per-line wrap fees via injected giftOptions. renderPackingSlipLines HTML-escapes every operator field. Migration `0202`. · *`smartRestocking` primitive — EOQ + safety-stock recommendations* — Composes demandForecast + reorderThresholds + costLayers + vendors. recommendOrderQty returns EOQ formula `sqrt(2DS/H)` + service-level safety-stock + reorder point + cost estimate. Service levels: 0.90 / 0.95 / 0.99. definePolicy + applyPolicy assigns SKUs to policies. Migration `0203`. · *`taxRemittance` primitive — per-jurisdiction tax payment tracking* — Records remittances with payment_method enum (bank_transfer / credit_card / ach / wire / check). reconcileWithFiling returns variance. lateRemittances threshold + recordPenalty + metricsForJurisdiction on-time rate. Migration `0204`. · *`blogArticles` primitive — operator-published blog posts* — Author + tags + featured_product_ids + SEO meta + publish FSM (draft → published → archived → draft). Markdown render through b.template.escapeHtml + b.safeUrl. relatedArticles tag-overlap ranking. byAuthor + popularArticles + recordView. Migration `0189`.
|
|
12
|
+
|
|
13
|
+
- v0.0.74 (2026-05-22) — **`emailEngagementScore` primitive + republish 0.0.73.** 0.0.73 source landed on `main` but the npm publish workflow stopped on a smoke check — the email-engagement-score test was committed without its lib counterpart. 0.0.74 adds the missing `emailEngagementScore` primitive and republishes the full v0.0.73 surface so `npm install @blamejs/blamejs-shop@0.0.74` pulls every primitive cleanly. **Added:** *`emailEngagementScore` primitive — per-customer 0-100 email engagement grade* — `bShop.emailEngagementScore.create({ query?, emailCampaigns?, emailSuppressions? })` returns `{ recordEngagementEvent, getScore, recompute, recomputeAll, unengagedCustomers, metricsForBand, historyForCustomer }`. Six event types with calibrated weights (opened +5, clicked +15, unsubscribed -50, spam_reported -75, bounced -10, not_opened_in_window -3). Score starts at 50 baseline, clamped to [0, 100]. Four bands: unengaged (0-19) / lapsed (20-49) / engaged (50-74) / highly_engaged (75-100). Click implies open in the open_rate denominator (compensates for image-blocking clients). Monotonic per-customer `_resolveOccurredAt` to break same-millisecond ties. Migration `0187_email_engagement_score.sql`. **Fixed:** *Republish to npm — 0.0.73 source on `main` reached operators via `git clone` but not via `npm install`* — `npm install @blamejs/blamejs-shop@0.0.73` resolves to a missing version because the publish workflow exited early when the CI smoke gate couldn't find `lib/email-engagement-score.js` (its test file was committed alongside v0.0.73 but the lib file itself was untracked at commit time). 0.0.74 ships the full surface so operators upgrading by version number get every primitive.
|
|
14
|
+
|
|
15
|
+
- v0.0.73 (2026-05-22) — **Twenty new primitives across operator ops, commerce, storefront, and compliance.** Twenty primitives ship together. Operator surfaces: marketingBudget, operatorSessions, operatorInbox, operatorActivityFeed, disputeResolution, shrinkageReport, demandForecast, fulfillmentSLA, salesTaxFilings, binLocations. Commerce: orderExchanges, searchRanking, shippingInsurance, cartRecovery, emailABTests, bannerABTests, referralLeaderboard. Storefront: pwaManifest, sidebarWidgets, announcementBar, stockReceipts, suggestionBox. Subscriptions: subscriptionAnalytics. Compliance: consentLedger. **Added:** *`marketingBudget` primitive — per-channel spend + ROAS* — Eleven channel kinds with per-channel currency lock. Integer-bps ROAS. UTC month budget reconciliation. Migration `0172`. · *`orderExchanges` primitive — different-item exchange FSM* — Six-state FSM with two-arm convergence. closeExchange requires both delivered_at and returned_at non-null. approveExchange opens an inventory hold pre-commit. Migration `0164`. · *`disputeResolution` primitive — chargeback lifecycle* — Four dispute kinds, seven evidence kinds, four outcomes. FSM open / submitted / lost / written_off. Migration `0173`. · *`operatorSessions` primitive — staff login with MFA + lockout* — 32-byte base64url bearer, hashed via namespaceHash. 8-hour TTL. Per-IP binding. Lockout after 5 failures in 15 minutes. Migration `0165`. · *`shippingInsurance` primitive — per-shipment insurance + claims* — Basis-point premium math. Insurance FSM active / cancelled / expired. Claim FSM filed / approved / denied. Four claim types. Migration `0166`. · *`pwaManifest` primitive — PWA manifest + service-worker config* — Display + orientation enums. Byte-stable JSON output via sorted-key serialise. URLs gated via b.safeUrl. Migration `0168`. · *`searchRanking` primitive — operator-tunable search reranker* — Boost/demote weights + manual pins per query. CTR + conversion math. Session ids hashed via namespaceHash. Migration `0167`. · *`emailABTests` primitive — subject + body A/B with Wilson CI* — Deterministic SHA3-512 assignment with 100k-bucket weight mapping. Sticky via the existing sent ledger row. Migration `0169`. · *`operatorInbox` primitive — in-admin notification feed* — Severity enum info / warning / urgent / critical. Exactly-one-of operator_id / role addressing. HMAC cursor pagination. Migration `0175`. · *`demandForecast` primitive — per-SKU demand prediction* — Four model kinds (SMA / WMA / exponential_smoothing / linear_regression). Band-coherence CHECKs. Migration `0179`. · *`stockReceipts` primitive — customer QR-scan delivery confirmation* — 32-byte token hashed at rest. Receipt FSM issued / scanned / completed / expired. Line FSM pending / received / damaged / partial. Migration `0177`. · *`bannerABTests` primitive — promo banner A/B with Wilson CI* — Deterministic per-session assignment. FSM running / paused / concluded / archived. Migration `0174`. · *`cartRecovery` primitive — abandon-cart email sequences* — Operator-defined step schedule. Composes cartAbandonment + email + emailSuppressions. markRecovered halts further steps. Migration `0171`. · *`sidebarWidgets` primitive — placement-targeted storefront blocks* — Nine widget kinds. Audience filter with optional customerSegments handle. Schedule-window gating + drop-silent counters. Migration `0176`. · *`consentLedger` primitive — append-only GDPR consent audit trail* — Nine consent kinds across cookies / marketing / data-sharing / data-processing. Two states (granted / withdrawn). Six sources. CSV / JSON audit export. Migration `0185`. · *`announcementBar` primitive — top-strip storefront message* — Four themes ranked urgency / promo / info / success. Schedule window + audience filter. Session-based dismissal dedup via UNIQUE(slug, session_id_hash). Migration `0180`. · *`shrinkageReport` primitive — loss-prevention dashboard* — Aggregates inventoryWriteoffs by reason / period / location / sku. Sample-stddev anomaly detection. Mixed-currency aggregation refusal. Migration `0170`. · *`subscriptionAnalytics` primitive — MRR / churn / cohort retention* — MRR cadence normalization across plan frequencies. Churn rate voluntary / involuntary / total. Cohort retention by month-zero. Migration `0178`. · *`operatorActivityFeed` primitive — staff-side timeline* — Aggregates operatorAuditLog + supportTickets + operatorInbox + operatorSessions. Cross-operator teamFeed. currentlyOnline 5-minute gate. Migration `0188`. · *`referralLeaderboard` primitive — top-referrer rankings + tier bonuses* — Reads from referrals primitive for ranking. Composes loyalty.earn for tier bonus payouts. UNIQUE(customer_id, period_label, tier) is the re-award gate. Migration `0182`. · *`fulfillmentSLA` primitive — order ship + deliver SLA tracking* — Per-priority policies (standard / expedited / overnight / same_day) with cutoff_local_time + timezone via Intl.DateTimeFormat. Severity bands minor / major / critical. Migration `0183`. · *`binLocations` primitive — warehouse bin / aisle / shelf assignments* — Auto-primary policy + pickPathSort by (aisle, shelf, level). Audit log with variance computation. Bin condition states clean / needs_audit / damaged / unusable. Migration `0186`. · *`salesTaxFilings` primitive — quarterly / monthly filings prep* — Aggregates orders + tax + taxRates + taxExempt into per-jurisdiction filings. FSM draft / computed / submitted / paid / amended. Banker's-rounded integer math on re-derive. Migration `0184`. · *`suggestionBox` primitive — customer feature-request box with up/downvote* — Categories: product_idea / feature_request / improvement / complaint / general. Status FSM open / under_consideration / planned / shipped / declined / duplicate. Vote dedup via UNIQUE(suggestion_id, session_id_hash). Migration `0181`.
|
|
16
|
+
|
|
17
|
+
- v0.0.72 (2026-05-22) — **`loyaltyEarnRules` primitive — per-action point earning rules.** `loyaltyEarnRules` defines HOW points are earned across eight trigger events: `per_dollar_spent`, `per_purchase`, `per_review`, `per_referral_redeemed`, `birthday`, `signup_bonus`, `first_purchase`, `abandoned_cart_recovered`. Distinct from the existing `loyalty` (ledger) and `tierBenefits` (perks) primitives. **Added:** *`loyaltyEarnRules` primitive — per-action point earning rules with optional per-event caps* — `bShop.loyaltyEarnRules.create({ query?, loyalty? })` returns `{ defineRule, getRule, listRules, updateRule, archiveRule, evaluateForEvent, awardForEvent, metricsForRule, applyBatch }`. Triggers: `per_dollar_spent / per_purchase / per_review / per_referral_redeemed / birthday / signup_bonus / first_purchase / abandoned_cart_recovered`. `evaluateForEvent` returns the points calculation (multiply + floor + zero-floor); `awardForEvent` composes the injected `loyalty.earn` handle and rolls back the audit row on ledger failure. Per-event cap (`max_per_event`) clips runaway awards. `customer_status_in` allowlist filters which customer tiers a rule applies to. UNIQUE(`rule_slug`, `customer_id`, `trigger_event_ref`) dedups re-submitted events. `applyBatch` runs multiple awards atomically with partial-failure reporting. Migration `0163_loyalty_earn_rules.sql`.
|
|
18
|
+
|
|
19
|
+
- v0.0.71 (2026-05-22) — **`splitShipments` — monotonic `proposed_at` so back-to-back plans sort newest-first.** Single-fix release. `splitShipments.planSplit` calls landing in the same wall-clock millisecond now get strictly-increasing `proposed_at` stamps via a process-local monotonic clock. Without the fix, `splitsForOrder(order_id)` returned the rows in nondeterministic order under burst-write conditions — CI runners hit the collision more reliably than local clocks. **Fixed:** *`splitShipments` — process-local monotonic `_now` so consecutive `planSplit` calls sort deterministically* — Two `planSplit` calls inside the same millisecond shared a `proposed_at` value, and the secondary tiebreaker (UUID v7 id) was scrambled by the intra-ms random suffix. The primitive now bumps `_now()` by 1ms when `Date.now()` returns a stale value, so `splitsForOrder` reliably returns newest-first under any insert burstiness. Same fix pattern as `orderNotes` / `productBulkOps` / `cookieConsent` / `liveChat` / `sms-dispatcher` / others — applies cleanly to any primitive where `Date.now()` precision drives sort order.
|
|
20
|
+
|
|
11
21
|
- v0.0.70 (2026-05-22) — **Six new primitives: click and collect, customer surveys, email templates, knowledge base, pixel events, sitemap generator.** Six primitives ship in one release covering store pickup (`clickAndCollect`), customer feedback (`customerSurveys`), operator-editable transactional email templates (`emailTemplates`), self-serve help center (`knowledgeBase`), server-side conversion pixel tracking (`pixelEvents`), and storefront sitemap generation (`sitemapGenerator`). **Added:** *`clickAndCollect` primitive — buy-online-pickup-in-store workflow* — `bShop.clickAndCollect.create({ query?, order?, inventoryLocations?, notifications? })` returns `{ definePickupLocation, availableLocations, scheduleAtLocation, markReadyForPickup, markPickedUp, markNoShow, pickupsForLocation, customerSchedules }`. Five-state FSM: scheduled → ready → picked_up + no_show + cancelled terminals. Capacity gated on one-hour buckets; lead-time gate per location. `markReadyForPickup` enqueues a pickup-ready notification through the injected handle (drop-silent on failure so a notifications outage can't roll back the hold shelf). `markPickedUp` drives the parent order to delivered via `order.transition(id, 'mark_delivered')` (swallows fsm/illegal-transition for idempotency). Signature hashed via `namespaceHash('click-and-collect-signature', raw)`. Migration `0126_click_and_collect.sql`. · *`customerSurveys` primitive — post-purchase NPS / CSAT / CES surveys* — `bShop.customerSurveys.create({ query? })` returns `{ defineSurvey, getSurvey, archiveSurvey, issueInvitation, getInvitation, invitationsForCustomer, submitResponse, responsesForSurvey, rollup, closeInvitation, cleanupExpired }`. Kinds: nps / csat / ces / custom. Trigger events: after_delivery / after_support_close / after_refund / manual. NPS / CSAT / CES enforce primary-question shape (`max === 10 / 5 / 7` respectively). NPS rollup = `round(%promoters - %detractors)`, CSAT = top-2-box positive_pct + mean, CES = mean + agree_pct. Invitation tokens 32-byte base64url plaintext returned exactly once, stored only as SHA3-512 namespaceHash. Migration `0128_customer_surveys.sql`. · *`emailTemplates` primitive — operator-editable transactional email templates* — `bShop.emailTemplates.create({ query? })` returns `{ defineTemplate, getTemplate, listTemplates, updateTemplate, publishVersion, archiveTemplate, renderTemplate, versionsFor, validateVariables }`. Closed 11-kind enum (order_confirmation / order_shipped / order_delivered / order_refunded / password_reset / account_verification / abandoned_cart / wishlist_discount / review_request / welcome / generic). `{{var_name}}` substitution composes `b.template.escapeHtml`; `{{var_name|raw}}` slots require schema vouching at definition time. Locale fallback to `en`. Migration `0125_email_templates.sql`. · *`knowledgeBase` primitive — self-serve customer help center with search ranking* — `bShop.knowledgeBase.create({ query?, defaultLocale?, cursorSecret? })` returns `{ defineArticle, getArticle, listArticles, updateArticle, publishArticle, unpublishArticle, archiveArticle, recordView, recordVote, voteAggregateForArticle, popularArticles, searchSuggest }`. Locale fallback chain. `searchSuggest` ranks by title 3 + tag 2 + body 1 weighted score; archived + unpublished excluded. Vote dedup at the `UNIQUE(slug, session_id_hash)` index. In-process markdown subset composes `b.template.escapeHtml` + `b.safeUrl.parse` (https-only + /-rooted internal). Session ids hashed via `namespaceHash` under `kb-view-session` / `kb-vote-session`. Migration `0162_knowledge_base.sql`. · *`pixelEvents` primitive — server-side conversion-tracking pixel / event API* — `bShop.pixelEvents.create({ query? })` returns `{ registerProvider, recordEvent, dispatchTick, markDispatched, markFailed, eventsForOrder, dispatchedInPeriod, failedEvents, metricsForProvider }`. Provider enum: meta_capi / google_ec / tiktok_events / pinterest_capi / snap_capi. Event names: purchase / add_to_cart / view_content / lead / complete_registration / search. Customer email + phone SHA-256-hashed (per provider spec — NOT namespaceHash; ad platforms accept SHA-256 of the normalised value). Five-step retry back-off on transient failures. Migration `0123_pixel_events.sql`. · *`sitemapGenerator` primitive — storefront sitemap.xml + sitemap-index.xml* — `bShop.sitemapGenerator.create({ query?, catalog?, collections?, storefrontPages?, custom? })` returns `{ defineSection, sections, archiveSection, validateOriginUrl, generate, recordGeneration, lastGeneration }`. Splits at 50,000 URLs or 50 MB serialized per chunk (whichever hits first). Path percent-encoding + XML escape on every emitted `<loc>`. Per-section sources: product / collection / storefront_page / custom. `validateOriginUrl` gates via `b.safeUrl` (https-only). Migration `0130_sitemap_generator.sql`.
|
|
12
22
|
|
|
13
23
|
- v0.0.69 (2026-05-22) — **Twelve new primitives + return-labels CI smoke fix.** Twelve primitives ship in one release plus a CI smoke fix that unblocks the npm publish workflow. The smoke fix bumps a too-tight 50ms `waitUntil` in `return-labels.test.js` to 5s so it survives the GitHub Actions runner's slower scheduling. New primitives cover orders (order ratings, packing slips, print queue), customers (wishlist sharing, customer activity feed, push notifications, order escalation), inventory (allocations, drop-ship forwarding, auto-replenishment), operator tooling (operator roles, clickstream events, damage photos). **Added:** *`orderRatings` primitive — per-order rating for shipping / packaging / recommend* — `bShop.orderRatings.create({ query? })` returns `{ submitRating, getRating, ratingsForCustomer, aggregateForPeriod, flagComment, responseToCustomer, topPositiveRatings, topNegativeRatings }`. Ratings 1..5 across three dimensions. UNIQUE(order_id) so one rating per order. Comment + operator response HTML-escaped on render. flagComment moderates abuse; responseToCustomer is the operator's public reply. Migration `0151_order_ratings.sql`. · *`wishlistSharing` primitive — share-a-wishlist links + group wishlists* — `bShop.wishlistSharing.create({ query?, wishlist? })` returns `{ createShareLink, revokeShareLink, viewShared, recordView, createGroupWishlist, joinGroupWishlist, leaveGroupWishlist, groupWishlistsForCustomer, listSharesForOwner, listGroupMembers }`. Tokens are 32-byte base64url plaintext returned once, hashed at rest via `namespaceHash` under per-domain namespaces. Privacy enum: public / unlisted / friends_only. Group wishlists let multiple customers co-author a list. Migration `0150_wishlist_sharing.sql`. · *`inventoryAllocations` primitive — soft-reserve holds for in-progress carts* — `bShop.inventoryAllocations.create({ query?, inventoryLocations? })` returns `{ holdForCart, releaseHold, releaseAllForCart, commitHold, extendHold, availableForSku, holdsForCart, cleanupExpiredHolds, metricsForSku }`. Holds prevent overselling during checkout. `availableForSku` returns committed - on_hold. `commitHold` composes `inventoryLocations.adjustStock` to commit the reservation as a real stock movement. TTL-bound; `cleanupExpiredHolds` walks expired rows and frees the inventory. Migration `0152_inventory_allocations.sql`. · *`dropshipForwarding` primitive — drop-ship vendor order-forwarding flow* — `bShop.dropshipForwarding.create({ query?, vendors?, orderTracking? })` returns `{ bindSkuToVendor, forwardOrder, markVendorAccepted, markVendorShipped, markVendorDelivered, markVendorFailed, markVendorReturned, getForwarding, forwardingsForOrder, pendingForwardings, metricsForVendor }`. Six-state FSM: queued / accepted / shipped / delivered / failed / returned. Composes `b.fsm` for transition validation. `forwardOrder` writes per-vendor forwarding rows. Migration `0154_dropship_forwarding.sql`. · *`damagePhotos` primitive — image attachments for damage / quality-control events* — `bShop.damagePhotos.create({ query? })` returns `{ recordPhoto, getPhoto, photosForSubject, archivePhoto, replacePhoto, metricsForKind, findDuplicatesBySha }`. Subject kinds: writeoff / return / quality_check / damaged_receipt / customer_complaint. SHA3-512 + size + content_type per upload. content_type allowlist: image/jpeg, image/png, image/webp, image/heic. `findDuplicatesBySha` returns prior uploads with the same digest (fraud detection signal). Migration `0159_damage_photos.sql`. · *`pushNotifications` primitive — APNs / FCM / Web Push outbound* — `bShop.pushNotifications.create({ query? })` returns `{ registerProvider, registerDevice, revokeDevice, recordOptIn, recordOptOut, isOptedIn, enqueueNotification, markDelivered, markFailed, dispatchTick, notificationsForCustomer, devicesForCustomer, metricsForProvider }`. Marketing channel uses opt-IN; transactional + alert use opt-OUT. Device class / provider kind compatibility enforced (ios↔apns, android↔fcm, web↔web_push, desktop↔fcm|web_push). Retry budget 5 with [1m, 5m, 30m, 2h, 12h] back-off. Migration `0148_push_notifications.sql`. · *`autoReplenish` primitive — auto-PO when reorder thresholds fire* — `bShop.autoReplenish.create({ query?, reorderThresholds?, purchaseOrders?, vendors? })` returns `{ definePolicy, tickReplenishment, getPolicy, listPolicies, archivePolicy, updatePolicy, replenishmentHistory, markPolicyTriggered }`. `tickReplenishment` finds reorder candidates via `reorderThresholds.scanAll` + groups by vendor + submits PO via `purchaseOrders.createDraft + submitToVendor`. Per-policy gates: min/max PO value, max_concurrent_open_pos cap, vendor-archived skip. Schedule: hourly / daily / weekly. Migration `0155_auto_replenish.sql`. · *`operatorRoles` primitive — staff-side RBAC* — `bShop.operatorRoles.create({ query?, operatorAuditLog? })` returns `{ defineRole, assignRoleToOperator, revokeRoleFromOperator, rolesForOperator, operatorsWithRole, hasPermission, listRoles, updateRole, archiveRole, listPermissions, permissionUsageLog, recordPermissionUse }`. 15-permission closed allow-list (orders.* / customers.* / catalog.* / inventory.write / vendors.manage / settings.write / billing.view / reports.read / users.* / support.handle). Multi-role union; expires_at honored. Migration `0157_operator_roles.sql`. · *`clickstream` primitive — server-side storefront analytics events* — `bShop.clickstream.create({ query? })` returns `{ recordPageView, recordEvent, sessionPath, topPages, topClicks, funnelAnalysis, bouncerate, dwellByPage, cleanupOlderThan }`. Tracks page views + clicks + form submits + scroll depth + dwell without third-party scripts. Event kinds: click / form_submit / form_abandon / video_play / video_complete / scroll_depth / dwell. Query strings + URL fragments stripped at write so PII in query params never reaches the table. Drop-silent on bad input. Migration `0161_clickstream.sql`. · *`customerActivity` primitive — per-customer aggregated activity timeline* — `bShop.customerActivity.create({ query?, cursorSecret?, order?, wishlist?, loyalty?, supportTickets?, reviews? })` returns `{ forCustomer, recentActivity, summarize, lastActivityAt, inactiveCustomers, purgeStaleCache }`. Aggregates events from order / wishlist / loyalty / support / reviews into one feed for the operator's customer-detail page. Missing peers skipped silently. `summarize` returns 30/90/365-day kind counts with cache hit/miss. Migration `0153_customer_activity_cache.sql`. · *`packingSlips` primitive — warehouse packing-slip rendering + print queue* — `bShop.packingSlips.create({ query?, order, giftOptions? })` returns `{ renderHtml, renderPdfPayload, recordPrint, printsForOrder, enqueueForLocation, dequeueForLocation, bulkRenderForLocation }`. Inlined Code-128 barcode SVG renderer (no external library dependency). HTML-escapes every operator + customer field. Gift options: hide_prices strips price/total columns; gift_message + recipient_name rendered inert against hostile input. Composite PK on the queue table as idempotency guard. Migration `0149_packing_slips.sql`. · *`printQueue` primitive — warehouse print job queue scheduler* — `bShop.printQueue.create({ query? })` returns `{ enqueueJob, claimJob, markComplete, markFailed, cancelJob, getJob, jobsForStation, pendingByKind, cleanupCompleted, stationActivity, dailyMetrics }`. Job kinds: packing_slip / shipping_label / invoice / packing_label / return_label / pickup_slip. `claimJob` returns next queued job (FIFO with priority tiebreak), flips `in_progress`. station_filter restricts which stations can claim a job. Retry budget on markFailed. Migration `0158_print_queue.sql`. **Fixed:** *`return-labels.test.js` — bumped a 50ms `waitUntil` timeout to 5s for CI runner scheduling* — GitHub Actions Ubuntu / macOS runners under contention sometimes need more than 50ms between `Date.now()` ticks to clear a monotonic-clock guard. The two `waitUntil` calls in `_listQueries` now use a 5000ms budget so the CI smoke gate doesn't drop the npm publish workflow. Local runs were always fast enough; only CI saw the failure.
|