@blamejs/blamejs-shop 0.1.4 → 0.1.5
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 +2 -0
- package/README.md +26 -0
- package/lib/admin.js +70 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,8 @@ upgrading across more than a few patches at a time.
|
|
|
8
8
|
|
|
9
9
|
## v0.1.x
|
|
10
10
|
|
|
11
|
+
- v0.1.5 (2026-05-25) — **Tell operators how to turn each integration on.** Every third-party integration (Stripe card checkout, Apple/Google Pay, Sign in with Google) is off by default and only activates when you supply its credentials. This release documents exactly what to set for each — in the README, in a new .env.example, and in the admin console itself. A signed-in operator opens /admin/integrations to see, at a glance, which integrations are live and the precise environment variables (or one-time action) needed to enable the rest. Nothing is enabled without your keys. **Added:** *Admin integrations status page* — `/admin/integrations` lists each integration with a live Enabled / Not configured status and the exact variables or action to turn it on — Stripe keys, the payment-method-domain registration for wallets, the Google OAuth client + redirect URI. Read-only; secrets are never rendered. Linked from the admin landing. · *Operator setup docs* — A README "Optional integrations" section and a top-level `.env.example` enumerate every environment variable, what capability it unlocks, and the external setup (e.g. the Google OAuth redirect URI, the Stripe webhook path). Both note that Apple sign-in + PayPal are planned and that Shop Pay / "Sign in with Shop" isn't available to a self-hosted store.
|
|
12
|
+
|
|
11
13
|
- v0.1.4 (2026-05-25) — **Sign in with Google.** Customers can sign in with Google alongside passkeys. The account login page gains a Continue with Google button; the OIDC authorization-code flow (PKCE, state, nonce, ID-token verification) runs through the framework's OAuth adapter, and the verified identity becomes a shop session. Accounts are keyed on the provider's stable subject, and an existing account is only ever linked on an email the provider has verified — an unverified email that collides with an existing account is refused rather than linked. A cart built before signing in is adopted into the account, so checkout attaches the order to the customer. **Added:** *Google sign-in* — Mounts `/account/login/google` + `/account/auth/google/callback` when the operator sets `GOOGLE_OAUTH_CLIENT_ID`, `GOOGLE_OAUTH_CLIENT_SECRET`, and `SHOP_ORIGIN`. The in-flight state (CSRF state + nonce + PKCE verifier) rides a sealed, /account-scoped, SameSite=Lax cookie; the callback verifies the state before exchanging the code. A forged or stale callback is dropped to the login page. On success the guest session cart is adopted into the account (`cart.setCustomer`), matching the passkey path. · *Federated identity model + safe account linking* — `customers.signInWithOIDC` resolves a verified sign-in to a customer: an existing `(provider, subject)` link, else — only on a provider-verified email — an existing account with that email, else a new account. It never links to an existing account on an unverified email (account-takeover defense). New `customer_oauth_identities` table (migration 0205) + `customers.byOAuthIdentity`.
|
|
12
14
|
|
|
13
15
|
- v0.1.2 (2026-05-25) — **Apple Pay and Google Pay express checkout.** The pay page now offers one-tap wallet checkout. Stripe's Express Checkout Element renders Apple Pay and Google Pay buttons above the card form on eligible devices, confirming the same PaymentIntent as the card path — so the webhook and order flow are unchanged. To turn the wallets on, the operator registers the shop's web domain with Stripe once via the admin API; Stripe performs Apple merchant validation and hosts the domain-association file, so no Apple Developer account is needed. **Added:** *Wallet buttons on the pay page* — The Stripe Express Checkout Element mounts above the card form and auto-renders Apple Pay / Google Pay (and Link) when the device and the shop's registered domain make them available. It stays hidden until Stripe reports an available wallet, and confirms the existing per-order PaymentIntent — the payment-completion path (webhook → order FSM) is identical to the card flow. · *Payment-method domain registration* — `POST /admin/payment-method-domains` (with `{ "domain_name": "shop.example.com" }`) registers a domain with Stripe to enable the wallets; `GET /admin/payment-method-domains` lists registered domains and their per-method status. The payment adapter gains `registerPaymentMethodDomain` + `listPaymentMethodDomains`. Apex, www, and each subdomain register separately; a live-mode registration also covers sandbox.
|
package/README.md
CHANGED
|
@@ -146,6 +146,32 @@ curl -X POST https://your-shop.example.com/admin/products \
|
|
|
146
146
|
|
|
147
147
|
See [`docs/deploy-cloudflare.md`](docs/deploy-cloudflare.md) for the full deploy recipe.
|
|
148
148
|
|
|
149
|
+
## Optional integrations — what to set to enable each
|
|
150
|
+
|
|
151
|
+
Every third-party integration is **off by default** and lights up only when you
|
|
152
|
+
supply its credentials. Nothing here phones home or is enabled without your
|
|
153
|
+
keys; the storefront runs fully (browse, cart, accounts) with none of them. Set
|
|
154
|
+
the values as deployment secrets (`wrangler secret put …`) or environment
|
|
155
|
+
variables. A signed-in operator can see the live on/off status of each at
|
|
156
|
+
**`/admin/integrations`**. See [`.env.example`](.env.example) for the full list.
|
|
157
|
+
|
|
158
|
+
| Integration | What it enables | Set this | Notes |
|
|
159
|
+
|-------------|-----------------|----------|-------|
|
|
160
|
+
| **Admin console** | The bearer-token JSON API + the `/admin` browser console (sign-in, setup wizard, dashboard). | `ADMIN_API_KEY` (≥ 16 chars — use 32 random bytes) | Sign in at `/admin` by pasting the key. Without it the admin surface doesn't mount. |
|
|
161
|
+
| **Card checkout (Stripe)** | Checkout + the Payment Element on the pay page; refunds; subscription billing. | `STRIPE_API_KEY` (`sk_…`), `STRIPE_WEBHOOK_SECRET` (`whsec_…`), `STRIPE_PUBLISHABLE_KEY` (`pk_…`) | Point your Stripe webhook at `/api/webhooks/stripe`. Without these the shop stays browsable but checkout doesn't mount. |
|
|
162
|
+
| **Apple Pay & Google Pay** | One-tap wallet buttons (Express Checkout Element) on the pay page. | Stripe (above) **+** register each web domain: `POST /admin/payment-method-domains {"domain_name":"shop.example.com"}` | Stripe performs Apple merchant validation and hosts the association file — **no Apple Developer account needed**. Apex, `www`, and each subdomain register separately; a live-mode registration also covers sandbox. |
|
|
163
|
+
| **Sign in with Google** | A *Continue with Google* button on `/account/login` (OIDC). | `GOOGLE_OAUTH_CLIENT_ID`, `GOOGLE_OAUTH_CLIENT_SECRET`, `SHOP_ORIGIN` (e.g. `https://shop.example.com`) | Create a Google Cloud **OAuth 2.0 Web** client; add `<SHOP_ORIGIN>/account/auth/google/callback` as an Authorized redirect URI; consent-screen scopes `openid email profile`. The button appears only when all three are set. |
|
|
164
|
+
|
|
165
|
+
**Planned / not available:**
|
|
166
|
+
|
|
167
|
+
- **Sign in with Apple** — the flow is wired in the framework, but it needs an
|
|
168
|
+
Apple Developer Program membership ($99/yr) and an ES256 client-secret minted
|
|
169
|
+
from your `.p8` key. Config-optional; shipping behind those credentials.
|
|
170
|
+
- **PayPal** — a separate adapter (Orders v2 + its own webhook); planned.
|
|
171
|
+
- **Shop Pay / "Sign in with Shop"** — **not available** to a self-hosted,
|
|
172
|
+
non-Shopify store: the credentials only issue from a Shopify Admin and payment
|
|
173
|
+
flows through Shopify Payments. There is no path to enable it here.
|
|
174
|
+
|
|
149
175
|
## Vendoring blamejs
|
|
150
176
|
|
|
151
177
|
`blamejs.shop` vendors blamejs as a shallow git clone of the release tag
|
package/lib/admin.js
CHANGED
|
@@ -1037,6 +1037,19 @@ function mount(router, deps) {
|
|
|
1037
1037
|
_redirect(res, "/admin");
|
|
1038
1038
|
});
|
|
1039
1039
|
|
|
1040
|
+
// Integrations status — what's live + what to set to enable the rest.
|
|
1041
|
+
// `deps.integrations` is the live on/off map computed at the entry
|
|
1042
|
+
// point from the environment (admin.js never reads process.env).
|
|
1043
|
+
router.get("/admin/integrations", async function (req, res) {
|
|
1044
|
+
if (!_htmlAuthed(req, expectedToken)) {
|
|
1045
|
+
return _sendHtml(res, 200, renderAdminLogin({ shop_name: deps.shop_name }));
|
|
1046
|
+
}
|
|
1047
|
+
_sendHtml(res, 200, renderAdminIntegrations({
|
|
1048
|
+
shop_name: deps.shop_name,
|
|
1049
|
+
status: deps.integrations || {},
|
|
1050
|
+
}));
|
|
1051
|
+
});
|
|
1052
|
+
|
|
1040
1053
|
if (config) {
|
|
1041
1054
|
router.get("/admin/setup", async function (req, res) {
|
|
1042
1055
|
if (!_htmlAuthed(req, expectedToken)) return _redirect(res, "/admin");
|
|
@@ -1365,6 +1378,7 @@ function renderAdminLanding(opts) {
|
|
|
1365
1378
|
"<h2>Admin</h2>" +
|
|
1366
1379
|
"<div class=\"nav-cards\">" +
|
|
1367
1380
|
"<a class=\"nav-card\" href=\"/admin/setup\"><h3>Setup wizard</h3><p>Shop identity, currency, and contact details.</p></a>" +
|
|
1381
|
+
"<a class=\"nav-card\" href=\"/admin/integrations\"><h3>Integrations</h3><p>Payments, wallets, and sign-in — what's live and what to set.</p></a>" +
|
|
1368
1382
|
"<a class=\"nav-card\" href=\"/admin/dashboard\"><h3>Dashboard</h3><p>Sales, revenue, and recent orders at a glance.</p></a>" +
|
|
1369
1383
|
"</div>" +
|
|
1370
1384
|
"<div class=\"actions-row\"><form method=\"post\" action=\"/admin/logout\"><button type=\"submit\" class=\"btn btn--ghost\">Sign out</button></form></div>" +
|
|
@@ -1401,11 +1415,64 @@ function renderAdminSetup(opts) {
|
|
|
1401
1415
|
return _renderAdminShell(opts.shop_name, "Setup", body);
|
|
1402
1416
|
}
|
|
1403
1417
|
|
|
1418
|
+
// Each integration is off until the operator supplies its credentials.
|
|
1419
|
+
// `opts.status` carries the live booleans (computed at the entry point
|
|
1420
|
+
// from the environment); this page shows what's on and exactly what to
|
|
1421
|
+
// set to turn the rest on. Read-only — secrets are never rendered.
|
|
1422
|
+
var INTEGRATIONS_CATALOG = [
|
|
1423
|
+
{ key: "stripe", name: "Card checkout (Stripe)", enables: "Checkout, the Payment Element, refunds, and subscription billing.",
|
|
1424
|
+
set: "STRIPE_API_KEY, STRIPE_WEBHOOK_SECRET, STRIPE_PUBLISHABLE_KEY (point the Stripe webhook at /api/webhooks/stripe)." },
|
|
1425
|
+
{ key: "express_checkout", name: "Apple Pay & Google Pay", enables: "One-tap wallet buttons on the pay page.",
|
|
1426
|
+
set: "Configure Stripe (above), then register each domain: POST /admin/payment-method-domains {\"domain_name\":\"shop.example.com\"}. No Apple Developer account needed." },
|
|
1427
|
+
{ key: "google_signin", name: "Sign in with Google", enables: "A “Continue with Google” button on the account login page.",
|
|
1428
|
+
set: "GOOGLE_OAUTH_CLIENT_ID, GOOGLE_OAUTH_CLIENT_SECRET, SHOP_ORIGIN. Add <SHOP_ORIGIN>/account/auth/google/callback as a Google OAuth redirect URI." },
|
|
1429
|
+
];
|
|
1430
|
+
|
|
1431
|
+
function renderAdminIntegrations(opts) {
|
|
1432
|
+
opts = opts || {};
|
|
1433
|
+
var status = opts.status || {};
|
|
1434
|
+
var rows = INTEGRATIONS_CATALOG.map(function (it) {
|
|
1435
|
+
// Three states: "enabled" (live), "action" (credentials present but a
|
|
1436
|
+
// one-time operator action — e.g. registering a domain with Stripe —
|
|
1437
|
+
// is still required before it's actually live), "off" (not configured).
|
|
1438
|
+
var st = status[it.key] || "off";
|
|
1439
|
+
var pill, detail;
|
|
1440
|
+
if (st === "enabled") {
|
|
1441
|
+
pill = "<span class=\"status-pill paid\">Enabled</span>";
|
|
1442
|
+
detail = "<span class=\"meta\">Live.</span>";
|
|
1443
|
+
} else if (st === "action") {
|
|
1444
|
+
pill = "<span class=\"status-pill pending\">Action needed</span>";
|
|
1445
|
+
detail = "<span class=\"meta\">" + _htmlEscape(it.set) + "</span>";
|
|
1446
|
+
} else {
|
|
1447
|
+
pill = "<span class=\"status-pill cancelled\">Not configured</span>";
|
|
1448
|
+
detail = "<span class=\"meta\">" + _htmlEscape(it.set) + "</span>";
|
|
1449
|
+
}
|
|
1450
|
+
return "<tr>" +
|
|
1451
|
+
"<td><strong>" + _htmlEscape(it.name) + "</strong><br><span class=\"meta\">" + _htmlEscape(it.enables) + "</span></td>" +
|
|
1452
|
+
"<td>" + pill + "</td>" +
|
|
1453
|
+
"<td>" + detail + "</td>" +
|
|
1454
|
+
"</tr>";
|
|
1455
|
+
}).join("");
|
|
1456
|
+
var body =
|
|
1457
|
+
"<section>" +
|
|
1458
|
+
"<h2>Integrations</h2>" +
|
|
1459
|
+
"<p class=\"meta\">Every integration is off until you supply its credentials — set them as deployment secrets, then redeploy. Nothing is enabled without your keys.</p>" +
|
|
1460
|
+
"<div class=\"panel\"><table>" +
|
|
1461
|
+
"<thead><tr><th>Integration</th><th>Status</th><th>To enable</th></tr></thead>" +
|
|
1462
|
+
"<tbody>" + rows + "</tbody>" +
|
|
1463
|
+
"</table></div>" +
|
|
1464
|
+
"<p class=\"meta\" style=\"margin-top:1.25rem;\">Sign in with Apple and PayPal are planned. “Sign in with Shop” / Shop Pay isn't available to a self-hosted store. See the README “Optional integrations” section for full setup steps.</p>" +
|
|
1465
|
+
"<div class=\"actions-row\"><a class=\"btn btn--ghost\" href=\"/admin\">Back</a></div>" +
|
|
1466
|
+
"</section>";
|
|
1467
|
+
return _renderAdminShell(opts.shop_name, "Integrations", body);
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1404
1470
|
module.exports = {
|
|
1405
1471
|
mount: mount,
|
|
1406
1472
|
AUDIT_NAMESPACE: AUDIT_NAMESPACE,
|
|
1407
1473
|
renderDashboard: renderDashboard,
|
|
1408
|
-
renderAdminLogin:
|
|
1409
|
-
renderAdminLanding:
|
|
1410
|
-
renderAdminSetup:
|
|
1474
|
+
renderAdminLogin: renderAdminLogin,
|
|
1475
|
+
renderAdminLanding: renderAdminLanding,
|
|
1476
|
+
renderAdminSetup: renderAdminSetup,
|
|
1477
|
+
renderAdminIntegrations: renderAdminIntegrations,
|
|
1411
1478
|
};
|
package/package.json
CHANGED