PageSourceSearch

https://rebilder.com/_next/static/immutable/chunks/3cj5677-3gptd.js

js rebilder.com collected 2026-10-02 00:33:00 UTC 29,802 bytes, 535 lines download raw bytes

1(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,43031,43867,e=>{"use strict";let t=`// lib/gateway-config.ts — wire the gateway to your source of truth
2import type { GatewayConfig } from '@rebilder/gateway'
3import { getProduct, getPolicies, getCollection } from './catalog' // your code
4import { getDocument, getDocumentIndex } from './content'          // your code
5
6export const gatewayConfig: GatewayConfig = {
7  storeId: 'store_123',
8  sources: {
9    // Commerce shaped. Wire the ones you have; a site with no catalog wires none.
10    product:  (url) => getProduct(url.pathname),      // null when not a PDP
11    policies: (url) => getPolicies(url.pathname),
12    catalog:  (url) => getCollection(url.pathname),
13    // Universal: any other page, and any index of them. Guides, services,
14    // locations, articles. Most of a site usually lives here.
15    document:   (url) => getDocument(url.pathname),
16    collection: (url) => getDocumentIndex(url.pathname),
17  },
18  onEvent: (event) => { /* queue to your analytics sink; fire-and-forget */ },
19}`,r=`// proxy.ts (Next 16) — middleware.ts on Next ≤15 is identical
20import { NextResponse } from 'next/server'
21import { createGatewayProxy } from '@rebilder/gateway/next'
22import { gatewayConfig } from './lib/gateway-config'
23
24// Pass your fallthrough. The proxy then returns a Response for every request,
25// and the HTML half of each negotiated URL gets \`Vary: Accept\` — see below for
26// why that matters more than it looks.
27const gateway = createGatewayProxy(gatewayConfig, () => NextResponse.next())
28
29export default gateway
30
31export const config = { matcher: ['/products/:path*', '/policies/:path*', '/collections/:path*'] }`,a=`// e.g. app/apps/rebilder/[[...path]]/route.ts — any Request/Response runtime works
32import { createShopifyAppProxyHandler } from '@rebilder/gateway/shopify'
33import { gatewayConfig } from '../../lib/gateway-config'
34
35export const GET = createShopifyAppProxyHandler(gatewayConfig, {
36  sharedSecret: process.env.SHOPIFY_APP_SECRET!,
37  pathPrefix: '/apps/rebilder', // as the path arrives at YOUR endpoint; strip is a no-op if absent
38})`,o=`Install @rebilder/gateway in this repository.
39
40WHAT IT DOES
41It is middleware. When an AI agent requests one of our URLs with
42\`Accept: text/markdown\`, it answers with a clean markdown rendering of that
43page's facts. Every other request — humans, Googlebot, anything that did not ask
44for markdown — falls through to the existing pipeline untouched. Same URL, same
45substance, different format.
46
47STEPS
481. Read the README of the installed package before writing anything. Do not
49   work from memory of this prompt; the API is in
50   node_modules/@rebilder/gateway/README.md.
512. Add the dependency with the package manager this repo already uses.
523. Create a gateway config exporting a \`GatewayConfig\`. Its \`sources\` resolvers
53   map a URL to our own data. There are five source kinds and every page on
54   this site is one of them. Three are commerce shaped: \`product\`, \`policies\`,
55   \`catalog\`. Two are universal: \`document\` for any other page, such as a
56   guide, an article, a service, a location or an FAQ, and \`collection\` for an
57   index of documents. A site with no catalog wires only the universal two, and
58   a site with both wires all five. Do not skip a section of the site because
59   it is not commerce. Wire the adapter for this repo's framework (\`/next\`,
60   \`/node\` for Express and Fastify, \`/edge\` for Workers, \`/shopify\`).
614. Pass the existing fallthrough into the adapter rather than calling it
62   yourself. That is what puts \`Vary: Accept\` on the HTML response. Without it a
63   shared cache can serve markdown to a human or stale HTML to an agent, and it
64   will not show up until it is in production behind a CDN.
655. Add a \`match\` router to \`sources\` if you can: one pure, synchronous function
66   from URL to source kind. It keeps the hot path to a single lookup and it is
67   what lets the adapter advertise the markdown alternate.
68
69IMPLEMENTATION REQUIREMENTS
70- Never invent a substantive value. Prices, stock, shipping costs, return
71  windows, policy text and dates on a commerce page, and opening hours,
72  turnaround times, eligibility rules, what a service includes and whether
73  booking is required on any other page, are read from our source of truth and
74  passed through unchanged. If you cannot find where a value lives,
75  leave that field unresolved, continue wiring supported fields, and report the missing source. Ask only when that missing information blocks the requested behavior. Do not use a placeholder that looks
76  real, and do not write an example value into a resolver.
77- A resolver returns \`null\` when the URL is not that kind of page. \`null\` means
78  "fall through to HTML", which is always a safe answer.
79- Do not change what the HTML pages render. This is additive.
80- Prefer the existing build and runtime. Add a build step, service or dependency when it solves a concrete integration need; explain the tradeoff and verify compatibility, bundle impact and self-hosting.
81
82WHEN YOU ARE DONE
83Tell me which URL patterns you wired and which you deliberately ski
83pped, then
84run this against one real URL of EACH kind you wired — not just the first one:
85
86  npx rebilder diff <url>     # shows the agent view and the browser view
87  npx rebilder check <url>    # grades the page, names what is missing
88
89Check source coverage across the URL patterns you intend to serve. Both commands run locally, upload
90nothing, and need no account.
91
92If you cannot answer "which URLs now serve markdown", the install is not done.`,n=["webflow","squarespace","wix","bigcommerce"],i=`Set up a Cloudflare Worker that puts @rebilder/gateway in front of my site.
93
94WHAT IT DOES
95The Worker sits on a route in front of the origin. When an AI agent requests a
96URL with \`Accept: text/markdown\` AND that URL is one I have described, it
97answers with clean markdown rendered from typed data. Everything else — humans,
98Googlebot, URLs I have not described — is forwarded to the origin unchanged.
99
100STEPS
1011. Scaffold a TypeScript Worker and add the dependency:
102     npm create cloudflare@latest my-rebilder-gateway -- --type=hello-world --ts
103     cd my-rebilder-gateway && npm install @rebilder/gateway
1042. Read node_modules/@rebilder/gateway/README.md before writing anything. Do
105   not work from memory of this prompt.
1063. Create \`src/content.ts\`: a \`Map<string, DocumentSource>\` keyed by pathname,
107   and a \`Map<string, CollectionSource>\` for index pages. Read real values from authoritative business sources — see the rules below.
1084. Create \`src/gateway-config.ts\` exporting a \`GatewayConfig\` whose \`document\`
109   and \`collection\` resolvers are \`Map.get\` on the normalised pathname, plus a
110   pure synchronous \`match\` router returning 'document', 'collection', or null.
1115. Make \`src/index.ts\`:
112     import { createGatewayFetchHandler } from '@rebilder/gateway/edge'
113     export default { fetch: createGatewayFetchHandler(gatewayConfig) }
1146. In wrangler.jsonc, set \`routes\` to my zone. Use the configured hostname; ask only if the deployment target is missing or ambiguous.
115
116IMPLEMENTATION REQUIREMENTS
117- Never invent a substantive value. Prices, opening hours, turnaround times,
118  what a service includes, whether booking is required — read these from authoritative business sources. Ask only for unavailable facts needed for the task. Do not write a plausible-looking
119  placeholder into content.ts; it will ship, and an agent will quote it.
120- Money is in MINOR UNITS. { amount: 180, currency: 'GBP' } is \xa31.80, not \xa3180.
121  Use the currency’s minor-unit exponent when converting major units; preserve exact decimal arithmetic and reject unsupported precision.
122- Serve the described pages from bundled or cached sources. If remote resolution is needed, bound its timeout, verify freshness and preserve the origin fallback.
123- A resolver returns null when the URL is not that kind of page. null means
124  "forward to the origin", which is always a safe answer.
125- Forward the origin's response as-is. Do not rewrite its status, do not turn a
126  502 into a friendly page, do not follow its redirects inside the Worker.
127- Do not change the origin. Preserve a rollback path that removes the Worker route and restores direct origin serving.
128
129WHEN YOU ARE DONE
130Tell me which pathnames now serve markdown and which pages I still need to
131describe. Then verify against the deployed site — one real URL of each kind:
132
133  curl -sI https://MY-DOMAIN/PATH -H 'Accept: text/markdown'   # expect text/markdown
134  curl -sI https://MY-DOMAIN/PATH                              # expect my normal HTML
135  npx rebilder check https://MY-DOMAIN/PATH                    # grades the page
136
137If you cannot answer "which URLs now serve markdown", the setup is not done.`;e.s(["AGENT_INSTALL_PROMPT",0,o,"CLOUDFLARE_AGENT_PROMPT",0,i,"NEXT_CONFIG_SNIPPET",0,t,"NEXT_INSTALL_CMD",0,"npm install @rebilder/gateway        # pnpm add / yarn add","NEXT_PROXY_SNIPPET",0,r,"SHOPIFY_HANDLER_SNIPPET",0,a,"SHOPIFY_MANAGED_INSTALL_URL",0,"https://api.rebilder.com/shopify/install","WORDPRESS_PLUGIN_DOWNLOAD",0,"/downloads/rebilder-wordpress-0.4.1.zip","isEdgeProxyPlatform",0,function(e){return null!=e&&n.includes(e)}],43867);let s=`// app/md/[[...path]]/route.ts
138import { createGatewayRouteHandler } from '@rebilder/gateway/next'
139import { gatewayConfig } from '../../../lib/gateway-config'
140
141export const GET = createGatewayRouteHandler(gatewayConfig, { stripPrefix: '/md' })`,c=`import express from 'express'
142import { createGatewayMiddleware } from '@rebilder/gateway/node'
143import { gatewayConfig } from './gateway-config'   // same GatewayConfig as every adapter
144
145const app = express()
146app.use(createGatewayMiddleware(gatewayConfig))    // before your routes
147// ... your existing routes serve HTML exactly as before`,l=`// Option A — Fastify's middleware compat layer (@fastify/middie):
148import middie from '@fastify/middie'
149await fastify.register(middie)
150fastify.use(createGatewayMiddleware(gatewayConfig))`,d=`// Option B — a 3-line onRequest hook over the raw req/res (no plugin needed):
151const gateway = createGatewayMiddleware(gatewayConfig)
152fastify.addHook('onRequest', (req, reply, done) => {
153  gateway(req.raw, reply.raw, done) // markdown answered on res; otherwise done() continues
154})`,p=`// worker.ts: deploy on a route in front of your site, e.g. example.com/*
155import { createGatewayFetchHandler } from '@rebilder/gateway/edge'
156import { gatewayConfig } from './gateway-config'
157
158export default { fetch: createGatewayFetchHandler(gatewayConfig) }`,u=`// app/llms.txt/route.ts
159import { createLlmsTxtRouteHandler } from '@rebilder/gateway/next'
160import { gatewayConfig } from '../../lib/gateway-config'
161
162export const GET = createLlmsTxtRouteHandler(gatewayConfig, {
163  baseUrl: 'https://store.example.com',
164  siteName: 'Acme Outdoors',
165  description: 'Trail footwear and gear, shipped from Bend, OR.',
166  sections: [{ title: 'Guides', links: [{ title: 'Sizing guide', url: 'https://store.example.com/pages/sizing' }] }],
167})`,g=`import type { GatewayConfig } from '@rebilder/gateway'
168import { sources } from './sources'
169
170export const gatewayConfig: GatewayConfig = {
171  storeId: 'my-site',
172  sources,
173  // /services/bike-fitting.md returns the markdown of /services/bike-fitting.
174  markdownUrls: true,
175  // title, description, canonical_url and last_updated from your source.
176  frontmatter: true,
177  // A markdown 404 for agents that ask for a page you do not have.
178  notFound: {
179    links: [
180      { title: 'Sitemap', url: '/sitemap.md' },
181      { title: 'llms.txt', url: '/llms.txt' },
182    ],
183    // Next.js and Node only: every page under /services/ has a source,
184    // so a /services/ URL with no source is not a page.
185    isMissing: (url) => url.pathname.startsWith('/services/'),
186  },
187}`,m=`// app/services/[slug]/page.tsx
188import type { Metadata } from 'next'
189import { markdownAlternateTypes } from '@rebilder/gateway/next'
190import { gatewayConfig } from '../../../lib/gateway-config'
191
192export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }): Promise<Metadata> {
193  const { slug } = await params
194  const url = \`https://example.com/services/\${slug}\`
195  return {
196    alternates: { canonical: url, types: markdownAlternateTypes(gatewayConfig, url) },
197  }
198}`,f=`// app/sitemap.md/route.ts
199import { createSitemapMdRouteHandler } from '@rebilder/gateway/next'
200import { gatewayConfig } from '../../lib/gateway-config'
201
202export const GET = createSitemapMdRouteHandler(gatewayConfig, {
203  baseUrl: 'https://example.com',
204  sections: [
205    { title: 'Services', links: [{ title: 'Bike fitting', url: 'https://example.com/services/bike-fitting' }] },
206  ],
207})`,h=`---
208title: Bike fitting
209description: A 90-minute fit on your own bike, with a written report.
210canonical_url: https://example.com/services/bike-fitting
211last_updated: "2026-09-28"
212---
213
214# [Bike fitting](https://example.com/services/bike-fitting)
215
216> A 90-minute fit on your own bike, with a written report.`,y=`# Page not found
217
218There is no page at this address.
219
220- [Sitemap](https://example.com/sitemap.md)
221- [llms.txt](https://example.com/llms.txt)`,w=`curl https://example.com/services/bike-fitting.md
222curl -s https://example.com/services/bike-fitting | grep -o '<link rel="alternate" type="text/markdown"[^>]*>'
223curl -H "Accept: text/markdown" https://example.com/services/no-such-page
224npx @vercel/agent-readability audit https://example.com`,v=`import { handleRequest, type GatewayConfig } from '@rebilder/gateway'
225import { createProtocolHandler } from '@rebilder/protocols'
226
227const sources = { product, policies, catalog } // ProtocolSources is structurally
228                                               // identical to GatewaySources —
229                                               // one wiring object serves both
230
231const config: GatewayConfig = {
232  storeId: 'store_123',
233  sources,
234  protocols: createProtocolHandler({
235    storeId: 'store_123',
236    sources,
237    checkout: { handoffUrl: (productUrl) => merchantCheckoutUrlFor(productUrl) },
238    // leave onEvent unset here — the gateway already emits one event per request
239  }),
240  onEvent: (event) => queue(event),
241}`,P=`import { handleRequest, type GatewayConfig, type AgentKeyRegistry } from '@rebilder/gateway'
242
243const registry: AgentKeyRegistry = { /* operator-populated — configure trusted platform keys */ }
244
245const config: GatewayConfig = {
246  storeId: 'store_123',
247  sources,
248  protocols: createProtocolHandler({ storeId: 'store_123', sources, checkout }),
249  verification: { keys: registry },   // require?: 'protocol' — the default and only v0 scope
250}`,E=`import { createFetchMiddleware } from '@rebilder/gateway/fetch'
251import { gatewayConfig } from './gateway-config'
252
253// Build once, at module scope.
254const gateway = createFetchMiddleware(gatewayConfig)
255
256// In any middleware that receives a Request and a next():
257//   return gateway(request, () => next())`,b=`// src/hooks.server.ts
258import type { Handle } from '@sveltejs/kit'
259import { createFetchMiddleware } from '@rebilder/gateway/fetch'
260import { gatewayConfig } from '$lib/gateway-config'
261
262const gateway = createFetchMiddleware(gatewayConfig)
263
264export const handle: Handle = ({ event, resolve }) => gateway(event.request, () => resolve(event))`,x=`// server/middleware/rebilder.ts (Nuxt and Nitro; h3 helpers are auto-imported)
265import { handleRequest, negotiationHeaders } from '@rebilder/gateway/fetch'
266import { gatewayConfig } from '../utils/gateway-config'
267
268export default defineEventHandler(async (event) => {
269  if (event.method !== 'GET' && event.method !== 'HEAD') return
270  const served = await handleRequest(toWebRequest(event), gatewayConfig)
271  if (served) return served
272  for (const [name, value] of negotiationHeaders(gatewayConfig, getRequestURL(event))) {
273    appendResponseHeader(event, name, value)
274  }
275})`,T=`// src/middleware.ts
276import { defineMiddleware } from 'astro:middleware'
277import { createFetchMiddleware } from '@rebilder/gateway/fetch'
278import { gatewayConfig } from './gateway-config'
279
280const gateway = createFetchMiddleware(gatewayConfig)
281
282export const onRequest = defineMiddleware((context, next) => gateway(context.request, () => next()))`,C=`// app/root.tsx
283import type { Route } from './+types/root'
284import { createFetchMiddleware } from '@rebilder/gateway/fetch'
285import { gatewayConfig } from './gateway-config.server'
286
287const gateway = createFetchMiddleware(gatewayConfig)
288
289export const middleware: Route.MiddlewareFunction[] = [({ request }, next) => gateway(request, next)]`,S=`// react-router.config.ts (React Router 7.9 or later; version 8 needs no flag)
290import type { Config } from '@react-router/dev/config'
291
292export default {
293  future: { v8_middleware: true },
294} satisfies Config`,I=`// server.ts: Remix v2 with a custom Express server
295import express from 'express'
296import { createRequestHandler } from '@remix-run/express'
297import { createGatewayMiddleware } from '@rebilder/gateway/node'
298import { gatewayConfig } from './app/gateway-config.server'
299
300const app = express()
301app.use(createGatewayMiddleware(gatewayConfig)) // before Remix
302app.all('*', createRequestHandler({ build: await import('./build/server/index.js') }))
303app.listen(3000)`,k=`import { Hono } from 'hono'
304import { createFetchMiddleware } from '@rebilder/gateway/fetch'
305import { gatewayConfig } from './gateway-config'
306
307const gateway = createFetchMiddleware(gatewayConfig)
308const app = new Hono()
309
310app.use(async (c, next) => {
311  let passed = false
312  const res = await gateway(c.req.raw, async () => {
313    passed = true
314    await next()
315    return c.res
316  })
317  if (!passed) return res // markdown, answered before any route ran
318  c.res = undefined // clear first, so Hono does not copy the old headers over ours
319  c.res = res
320})
321
322// ...your routes`,R=`// server.ts
323import { createFetchMiddleware } from '@rebilder/gateway/fetch'
324import { gatewayConfig } from './gateway-config'
325import { app } from './app' // your existing (request) => Response handler
326
327const gateway = createFetchMiddleware(gatewayConfig)
328
329Bun.serve({ fetch: (request) => gateway(request, () => app(request)) })`,_=`// main.ts
330import { createFetchMiddleware } from '@rebilder/gateway/fetch'
331import { gatewayConfig } from './gateway-config.ts'
332import { app } from './app.ts' // your existing (request) => Response handler
333
334const gateway = createFetchMiddleware(gatewayConfig)
335
336Deno.serve((request) => gateway(request, () => app(request)))`,N=`// netlify/edge-functions/rebilder.ts
337import type { Config, Context } from '@netlify/edge-functions'
338import { createFetchMiddleware } from '@rebilder/gateway/fetch'
339import { gatewayConfig } from '../../gateway-config.ts'
340
341const gateway = createFetchMiddleware(gatewayConfig)
342
343export default (request: Request, context: Context) => gateway(request, () => context.next())
344
345export const config: Config = { path: '/*', excludedPath: ['/*.css', '/*.js'] }`,A=`// middleware.ts at the project root (Vercel Routing Middleware, outside Next.js)
346import { next } from '@vercel/functions'
347import { handleRequest, negotiationHeaders } from '@rebilder/gateway/fetch'
348import { gatewayConfig } from './gateway-config'
349
350export default async function middleware(request: Request) {
351  const served = await handleRequest(request, gatewayConfig)
352  return served ?? next({ headers: Object.fromEntries(negotiationHeaders(gatewayConfig, new URL(request.url))) })
353}`,O=`// api/[...path].ts: a Vercel Function that answers the whole site itself
354import { createGatewayFetchHandler } from '@rebilder/gateway/edge'
355import { gatewayConfig } from '../gateway-config'
356import { app } from '../app' // your existing (request) => Response handler
357
358export default { fetch: createGatewayFetchHandler(gatewayConfig, { fallback: app }) }`,M=`import type { GatewayConfig } from '@rebilder/gateway'
359
360export const gatewayConfig: GatewayConfig = {
361  storeId: 'store_123',
362  sources: { /* … */ },
363  verification: { keys: myRegistry },      // required for platform-named rules
364  access: {
365    default: 'allow',
366    rules: [
367      { subject: 'chatgpt', action: 'allow' },
368      { subject: 'unverified', action: 'limit', limit: { requests: 60, windowSeconds: 60 } },
369      { subject: '*', action: 'allow' },
370    ],
371  },
372}
372`,L=`import type { AccessPolicy, GatewayConfig } from '@rebilder/gateway'
373
374let current: AccessPolicy = BOOT_POLICY
375setInterval(async () => { current = await fetchAndVerifyPolicy() }, 300_000)
376
377export const gatewayConfig: GatewayConfig = { /* … */, access: () => current }`,q=`import { compileAccessPolicy } from '@rebilder/gateway'
378
379const compiled = compileAccessPolicy(draft, { verificationConfigured: true })
380// Show compiled.rejected to the person editing the policy before you save it.`,D=`import { handleRequest, inspectGatewayConfig, inspectGatewayResponse } from '@rebilder/gateway'
381import { gatewayConfig } from './gateway-config'
382
383const wiring = inspectGatewayConfig(gatewayConfig)
384console.table(wiring.checks)
385
386// Use a public information page, not a transaction endpoint.
387const request = new Request('https://your-site.example/services', {
388  headers: { accept: 'text/markdown' },
389})
390const response = await handleRequest(request, gatewayConfig)
391console.table(inspectGatewayResponse(response))`,H=`// next.config.ts (inside the config object)
392async headers() {
393  return ['/', '/products/:path*', '/policies/:path*'].map((source) => ({
394    source,
395    headers: [
396      {
397        key: 'Vary',
398        value:
399          'rsc, next-router-state-tree, next-router-prefetch, next-router-segment-prefetch, Accept',
400      },
401    ],
402  }))
403}`,G=`const protocols = createProtocolHandler({ storeId, sources, checkout, onEvent })
404export default { fetch: async (req: Request) => (await protocols(req)) ?? new Response('Not found', { status: 404 }) }`,U=`import { createHttpEventSink } from '@rebilder/events'
405
406const sink = createHttpEventSink({
407  url: 'https://api.rebilder.com', // ingest base; the sink POSTs to \`\${url}/v1/events\`
408  apiKey: process.env.REBILDER_API_KEY!, // sent as \`Authorization: Bearer <apiKey>\`
409  // maxBatch: 20,           flush as soon as the queue reaches this many events
410  // flushIntervalMs: 2000,  flush timer while the queue is non-empty
411  // fetchImpl: fetch,       injectable for tests; defaults to globalThis.fetch
412  // onError: console.warn,  called for every dropped event or batch; never rethrown
413})
414
415sink.emit(event) // sync enqueue; invalid events dropped via onError, never thrown
416await sink.flush() // send the queue now; resolves even on failure
417await sink.close() // flush remaining events + stop the timer; later emits are dropped`,F=`import type { GatewayConfig } from '@rebilder/gateway'
418import { createHttpEventSink } from '@rebilder/events'
419
420const sink = createHttpEventSink({ url: 'https://api.rebilder.com', apiKey: '...' })
421
422export const gatewayConfig: GatewayConfig = {
423  storeId: 'my-store',
424  sources: {
425    /* ... */
426  },
427  onEvent: (event) => sink.emit(event),
428}`,W=`POST {url}/v1/events
429Authorization: Bearer <apiKey>
430Content-Type: application/json
431
432{ "events": RebilderEventV0[] }`,B=`import { createConsoleEventSink } from '@rebilder/events'
433
434const sink = createConsoleEventSink()
435sink.emit(event) // console.info('[rebilder-event] {"event_id":...}')`,j=`# 1. What an agent gets — clean markdown (note x-rebilder-path: markdown)
436curl -si -H 'Accept: text/markdown' https://trymumm.com/trust/refunds
437
438# 2. What a browser (or Googlebot) gets — the canonical HTML, unchanged
439curl -si https://trymumm.com/trust/refunds`,Y=`# [Alpine Trail Pack 28L](https://basecamp-supply.example/products/alpine-trail-pack-28l)
440
441- **Brand:** Basecamp Supply Co
442- **Price:** $148.00
443- **Availability:** In stock
444- **Shipping:** Free US shipping on orders over $75; standard shipping $6.95.`,K=`// lib/catalog.ts — your source of truth, typed with the gateway's re-exported types
445import type { ProductSource, PolicySource } from '@rebilder/gateway'
446
447const PRODUCTS: Record<string, ProductSource> = {
448  '/products/alpine-trail-pack-28l': {
449    url: 'https://store.example.com/products/alpine-trail-pack-28l',
450    title: 'Alpine Trail Pack 28L',
451    brand: 'Basecamp Supply Co',
452    description:
453      'A 28-liter technical daypack: suspended-mesh back panel, magnetic sternum buckle, 3L hydration sleeve, lifetime repair guarantee.',
454    price: { amount: 14800, currency: 'USD' }, // minor units — integer cents, never floats
455    availability: 'in_stock', // 'in_stock' | 'out_of_stock' | 'preorder' | 'backorder'
456    variants: [
457      {
458        id: 'BSC-ATP28-JUN',
459        title: 'Juniper Green',
460        price: { amount: 14800, currency: 'USD' },
461        availability: 'in_stock',
462        options: { Color: 'Juniper Green' },
463      },
464      {
465        id: 'BSC-ATP28-EMB',
466        title: 'Ember Orange',
467        price: { amount: 14800, currency: 'USD' },
468        availability: 'backorder',
469        options: { Color: 'Ember Orange' },
470      },
471    ],
472    shipping: {
473      summary: 'Free US shipping on orders over $75; standard shipping $6.95.',
474      freeThreshold: { amount: 7500, currency: 'USD' },
475      regions: ['US', 'CA'],
476      etaDays: [3, 6], // [min, max] delivery estimate in days
477    },
478    returns: {
479      summary: '60-day returns. Items must be unused with tags attached.',
480      windowDays: 60,
481      url: 'https://store.example.com/policies/returns',
482    },
483    images: [
484      { url: 'https://store.example.com/cdn/atp28-front.jpg', alt: 'Alpine Trail Pack 28L, front' },
485    ],
486    attributes: { Capacity: '28 L', Weight: '1.12 kg (2.47 lb)' },
487  },
488}
489
490const POLICIES: PolicySource[] = [
491  {
492    title: 'Shipping policy',
493    url: 'https://store.example.com/policies/shipping',
494    body: 'Orders placed before 12pm PT ship the same business day. Free US shipping over $75.',
495  },
496  {
497    title: 'Returns policy',
498    url: 'https://store.example.com/policies/returns',
499    body: '60-day returns. Items must be unused with tags attached. Refunds to the original payment method.',
500  },
501]
502
503export function getProduct(pathname: string): ProductSource | null {
504  return PRODUCTS[pathname] ?? null // null = "not a product page" — the gateway moves on
505}
506
507export function getPolicies(pathname: string): PolicySource[] | null {
508  return pathname.startsWith('/policies') ? POLICIES : null
509}`;function V(e){return`// lib/gateway-config.ts — the same config, with the event sink wired
510import type { GatewayConfig } from '@rebilder/gateway'
511import { createHttpEventSink } from '@rebilder/events'
512import { getProduct, getPolicies, getCollection } from './catalog' // your code
513import { getDocument, getDocumentIndex } from './content'          // your code
514
515// Module scope, not per request: the sink batches (20 events, or every 2s),
516// so a sink created inside a handler is discarded before it ever flushes.
517const sink = createHttpEventSink({
518  url: 'https://api.rebilder.com',
519  apiKey: process.env.REBILDER_API_KEY!, // set the env var; never a literal here
520})
521
522export const gatewayConfig: GatewayConfig = {
523  storeId: '${e}',
524  sources: {
525    // Commerce shaped. Wire the ones you have; a site with no catalog wires none.
526    product:  (url) => getProduct(url.pathname),      // null when not a PDP
527    policies: (url) => getPolicies(url.pathname),
528    catalog:  (url) => getCollection(url.pathname),
529    // Universal: any other page, and any index of them. Guides, services,
530    // locations, articles. Most of a site usually lives here.
531    document:   (url) => getDocument(url.pathname),
532    collection: (url) => getDocumentIndex(url.pathname),
533  },
534  onEvent: (event) => sink.emit(event),
535}`}let X=V("store_123");e.s(["ACCESS_COMPILE_SNIPPET",0,q,"ACCESS_GETTER_SNIPPET",0,L,"ACCESS_POLICY_SNIPPET",0,M,"AFTER_MARKDOWN_EXCERPT_SNIPPET",0,Y,"ASTRO_SNIPPET",0,T,"BUN_SNIPPET",0,R,"CATALOG_EXAMPLE_SNIPPET",0,K,"CONSOLE_SINK_SNIPPET",0,B,"CURL_VERIFY_SNIPPET",0,j,"DENO_SNIPPET",0,_,"DIAGNOSTICS_SNIPPET",0,D,"DISCOVERY_CONFIG_SNIPPET",0,g,"DISCOVERY_CURL_SNIPPET",0,w,"EVENTS_INSTALL_CMD",0,"npm install @rebilder/events        # pnpm add / yarn add","EXPRESS_SNIPPET",0,c,"FASTIFY_HOOK_SNIPPET",0,d,"FASTIFY_MIDDIE_SNIPPET",0,l,"FETCH_MIDDLEWARE_SNIPPET",0,E,"FRONTMATTER_EXAMPLE_SNIPPET",0,h,"GATEWAY_SINK_SNIPPET",0,F,"HEAD_ALTERNATE_SNIPPET",0,'<link rel="alternate" type="text/markdown" href="https://example.com/services/bike-fitting">',"HONO_SNIPPET",0,k,"HTTP_SINK_SNIPPET",0,U,"LLMS_TXT_ROUTE_SNIPPET",0,u,"MD_ROUTE_SNIPPET",0,s,"NETLIFY_SNIPPET",0,N,"NEXT_ALTERNATE_SNIPPET",0,m,"NEXT_VARY_HEADERS_SNIPPET",0,H,"NOT_FOUND_EXAMPLE_SNIPPET",0,y,"NUXT_SNIPPET",0,x,"PROTOCOLS_HOOK_SNIPPET",0,v,"PROTOCOLS_STANDALONE_SNIPPET",0,G,"REACT_ROUTER_FLAG_SNIPPET",0,S,"REACT_ROUTER_SNIPPET",0,C,"REMIX_SNIPPET",0,I,"SINK_CONFIG_SNIPPET",0,X,"SITEMAP_MD_ROUTE_SNIPPET",0,f,"SVELTEKIT_SNIPPET",0,b,"VERCEL_FUNCTION_SNIPPET",0,O,"VERCEL_MIDDLEWARE_SNIPPET",0,A,"VERIFICATION_CONFIG_SNIPPET",0,P,"WIRE_PROTOCOL_SNIPPET",0,W,"WORKER_SNIPPET",0,p,"sinkConfigSnippet",0,V,"sinkEnvLine",0,function(e){return`REBILDER_API_KEY=${e}`}],43031)},55085,(e,t,r)=>{"use strict";e.i(67652),Object.defineProperty(r,"__esModule",{value:!0});var a={default:function(){return d},getImageProps:function(){return l}};for(var o in a)Object.defineProperty(r,o,{enumerable:!0,get:a[o]});let n=e.r(36437),i=e.r(46609),s=e.r(4973),c=n._(e.r(81274));function l(e){let{props:t}=(0,i.getImgProps)(e,{defaultLoader:c.default,imgConf:{deviceSizes:[640,750,828,1080,1200,1920,2048,3840],imageSizes:[32,48,64,96,128,256,384],qualities:[75],path:"/_next/image",loader:"default",dangerouslyAllowSVG:!1,unoptimized:!1}});for(let[e,r]of Object.entries(t))void 0===r&&delete t[e];return{props:t}}let d=s.Image},11432,(e,t,r)=>{t.exports=e.r(55085)}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.