Repository navigation
Add Shopify on Cloudflare template - #1075
Uzair-Ahmed-Dahraj wants to merge 14 commits into
Conversation
A production-ready Shopify embedded-app starter on Cloudflare Workers: Hono routing, session-token (JWT) auth via App Bridge v4, Drizzle ORM on D1, KV-backed Shopify session storage, R2 file storage, and a React 18 + Polaris frontend. Includes a public /preview page, unit tests, and a Playwright smoke test.
519fc8a to
77aa82c
Compare
Adds a 16:9 screenshot (3200x1800) of the template's public /preview page and references it in the README above the dash-content marker, matching workers-for-platforms-template. The committed asset is also what a Cloudflare team member can upload to set cloudflare.preview_image_url during review.
… shopify-on-cloudflare-template Ports devkindhq/shopify-on-cloudflare#9 into the template: 1. Webhook HMAC verification compared the computed digest against the X-Shopify-Hmac-Sha256 header with plain !== (early-exit string compare), leaving it open to timing attacks. Replaced with crypto.subtle.timingSafeEqual (Workers runtime extension, per developers.cloudflare.com/workers/runtime-apis/web-crypto) with a constant-time XOR-fold fallback for non-Workers runtimes (vitest/Node). Adds a wrong-length-signature test covering the no-early-exit path. 2. Bumps @cloudflare/vite-plugin 1.46.0 -> 1.52.1 and wrangler 4.113.0 -> 4.123.0 (peer dep of the new vite-plugin). Clears all 8 high-severity npm audit advisories (undici chain). Remaining 6 moderates are drizzle-kit/react-router major-bump chains, documented as out of scope upstream. 3. Adds the security-audit note above registerWebhooks (verified safe: outbound registration, not inbound handling). Verified: templates lint, prettier, lockfile lint, turbo check + cf-typegen (build + deploy dry-run), vitest 21/21, wrangler types idempotent vs committed worker-configuration.d.ts.
fix(security): timing-safe webhook HMAC + clear high-severity deps (port of shopify-on-cloudflare#9)
…dflare-template # Conflicts: # pnpm-lock.yaml # templates.json
…with new pin-all-deps CI gate - Resolve pnpm-lock.yaml and templates.json conflicts against upstream main - Comply with new syncpack 'pin all deps' rule (upstream cloudflare#1114): exact-pin all shopify template deps - versionGroups for peer-dep-constrained stack (same mechanism as remix's React 18): * React ^18 (@shopify/app-bridge-react@4 + @shopify/polaris@10 peer-cap at 18) * eslint 8.57.1 + eslint-plugin-react-hooks 4.6.0 (eslint-config-airbnb is eslint-8-only) * hono 4.13.2 (high advisories <=4.12.33: JWT auth-bypass GHSA-r38q-p5jb-mjvw, XSS GHSA-f9qg-mpr5-mhfp) * react-router-dom 7.18.2 (high advisory <=7.17.0: turbo-stream RCE) - Cross-template syncpack alignment (HighestSemverMismatch): bump @typescript-eslint/plugin-react-swc in remix, to-do-list, workflows, x402 - Fix E2E backlink locator: exact match (GitHub link text contains 'devkindhq', broke strict mode) Gates: check:deps/templates/lockfiles/prettier OK; turbo check+cf-typegen 3/3; vitest 21/21; playwright 5/5; npm audit 0 high/0 critical
The pin-all-deps gate (upstream cloudflare#1114) only needed our two mismatched dev tools brought in line with what upstream already uses. Bumping the four other templates up was not required. Reverts remix-starter, to-do-list-kv, workflows-starter and x402-proxy to upstream, and sets ours to @typescript-eslint 8.50.0 and @vitejs/plugin-react-swc 4.0.0. Regenerates templates.json, package-lock.json and pnpm-lock.yaml. Security posture is unchanged: wrangler 4.123.0, @cloudflare/vite-plugin 1.52.1, vitest 4.1.10, hono 4.13.2 and react-router-dom 7.18.2 are all kept, and none of the moved packages is in an advisory chain. npm audit reports 0 high, 4 moderate (drizzle-kit -> esbuild only).
Resolve upstream conflict without touching other templates
Upstream cloudflare#1137 pinned all 37 templates to wrangler 4.127.0, because Wrangler 4.126.0 and later emit CI annotations that link Preview deployments to their source repo, commit and PR. It regenerated the derived files and dropped the Remix wrangler-3 version group. pnpm-lock.yaml and templates.json conflicted. Both are generated registries with one entry per template, so both intents fit: took upstream's copy of each, then regenerated so our template's entry is re-added. Our template joins the bump: - wrangler 4.123.0 -> 4.127.0 - package-lock.json and pnpm-lock.yaml regenerated - templates.json hash now 39611d13 - worker-configuration.d.ts regenerated under 4.127.0, matching what upstream did for every other template Verified: frozen-lockfile up to date, check:deps, check:templates, check:lockfiles, check:prettier, version validator, 21/21 tests, vite build, wrangler deploy --dry-run, wrangler types idempotent. Diff vs upstream/main touches no other template.
|
@deloreyj When you have a moment, could you approve the workflows on this PR and add the CI has not run on this PR yet. All workflow runs have sat at I have just merged Verified locally before pushing:
The diff against Live preview (no Shopify login needed): https://cloudflare-shopify-starter-template.ali-d43.workers.dev/preview Happy to rebase or change anything you would prefer done differently. |
The template carried an ESLint config from a repo with no Prettier, where `eslint --fix` was the de facto formatter (spaces, single quotes). This monorepo already formats with Prettier via .editorconfig (tabs, double quotes), enforced by check:prettier. Two formatters, opposite settings, same files. That produced 426 errors (no-tabs 206, indent 101, quotes 65, react/jsx-indent 44, and 10 more), and worse: `lint` shipped with --fix, so running it rewrote 6 files and made check:prettier fail. A contributor running the template's own lint script broke CI. Fixed both ways ESLint was formatting: - extends eslint-config-prettier, which disables the conflicting rules, and dropped the explicit "quotes" override. Pinned 10.1.8 to match x402-proxy-template, so cross-template alignment is unchanged. - removed --fix from the lint script, so it can only report. None of the 7 upstream templates with a lint script use --fix. Verified: eslint 0 errors (was 426), `npm run lint` changes 0 files (was 6), check:prettier passes after running lint, plus check:deps, check:templates, check:lockfiles, frozen-lockfile, 21/21 unit tests, vite build, wrangler deploy --dry-run, and 5/5 Playwright e2e.
Eight upstream commits, including the Cloudflare Docs voice agent template and a run of live-demo peer dependency fixes. pnpm-lock.yaml and templates.json conflicted, as they do on every upstream merge: both are generated registries with one entry per template. Resolved by taking upstream's copy of each, then regenerating so our entry is re-added. No dependency changes were needed this time, since our pins already match upstream (wrangler 4.127.0, vite-plugin 1.52.1, vitest 4.1.10, typescript 5.9.3). templates.json now carries a trailing newline upstream, though the CLI writer still emits none. Matched the committed file so our diff is only the added entry. Verified: frozen-lockfile up to date, check:deps, check:templates, check:lockfiles, check:prettier, templates.json not rewritten by the tooling, wrangler types idempotent, eslint 0 errors, 21/21 unit tests, vite build, wrangler deploy --dry-run, 5/5 Playwright e2e. Diff vs upstream/main touches no other template.
One upstream commit (cloudflare#1151) that publishes the Cloudflare Docs voice agent template and updates its package_json_hash. templates.json was the only conflict: upstream edited the voice-agent hash line, and our entry sits immediately after it, so git saw overlapping edits in the same region. Kept upstream's new hash (49cdbd36) and re-appended our entry. No dependency changes needed; our pins already match upstream (wrangler 4.127.0, vite-plugin 1.52.1, vitest 4.1.10, typescript 5.9.3). pnpm-lock .yaml was untouched upstream, so it did not conflict. Verified: frozen-lockfile up to date, check:deps, check:templates, check:lockfiles, check:prettier, templates.json not rewritten by the tooling, wrangler types idempotent, eslint 0 errors, 21/21 unit tests, vite build, wrangler deploy --dry-run, 5/5 Playwright e2e. Diff vs upstream/main touches no other template.
Upstream cloudflare#1155 moved all 41 templates to Wrangler 4.136.1, so check:deps fails until ours matches. The bump also rewrites worker-configuration.d.ts, which check:turbo compares with git diff --exit-code.
Kept both new templates.json entries: upstream's grpc-container-template and ours. The file is a registry keyed by name, so neither replaces the other.
Description
Adds a new template:
shopify-on-cloudflare-template— a production-ready Shopify embedded-app starter on Cloudflare Workers (Hono, D1 + Drizzle ORM, KV-backed Shopify session storage, R2, React 18 + Polaris), with session-token (JWT) auth via App Bridge v4, a public/previewpage, unit tests, and a Playwright smoke test.Built and maintained by Devkind. Source repository: https://github.com/devkindhq/shopify-on-cloudflare
The app's authenticated home page only renders inside the Shopify Admin iframe, so the link above goes to the public
/previewroute, which shows what the template is and how it is built.Checklist
-templatepackage.jsonis populated<!-- dash-content-start -->and<!-- dash-content-end -->to designate the Dash readme preview.gitignorefile existspackage.jsoncontains adeploycommandpackage.jsoncontainsprivate: trueand noversionfieldNotes for reviewers
hostparam + API key via App Bridge), so the Playwright smoke tests cover the parts that hold without a Shopify session: the public/previewpage, the health endpoint, and therequireShopmiddleware rejecting unauthenticated/api/*requests.wrangler.jsoncships placeholder binding IDs (YOUR_DATABASE_ID,YOUR_KV_NAMESPACE_ID); the README documents creating the D1/KV/R2 resources.pnpm -w checkgates (templates lint, prettier, npm-lockfiles),pnpm install --frozen-lockfile, cf-typegen idempotency, template unit tests (20 passing), andvite build && wrangler deploy --dry-run.