@mindstudio-ai/remy 0.1.304 → 0.1.305

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.
@@ -46,6 +46,7 @@ All fields are nested under the `"web"` key.
46
46
  | `prerender` | `object` | — | Opt into prerendering the listed routes/patterns for crawlers/unfurlers. See "Prerendering" below. |
47
47
  | `mounts` | `array` | — | Serve other same-workspace apps under path prefixes of this app's hosts. See "Mounting other apps" below. |
48
48
  | `redirects` | `array` | — | Path-level redirects. See "Redirects" below. |
49
+ | `rewrites` | `array` | — | Serve different content at the same URL. See "Rewrites" below. |
49
50
  | `trailingSlash` | `"strip"` \| `"append"` | — | Enforce a canonical trailing-slash form with a 308. Off by default. |
50
51
 
51
52
  ### Frontend SDK
@@ -168,11 +169,26 @@ Declare moved URLs in `web.json` — never ship a component that redirects clien
168
169
 
169
170
  `trailingSlash` picks the canonical form (`"strip"`: `/about/` → `/about`; `"append"`: the reverse, skipping the root and paths with file extensions). Off by default. Write `source` patterns without trailing slashes either way — normalization and matching resolve in one hop. Sources under `/_/` are rejected, as are self-referential and two-rule loops. A redirecting path is never prerendered, so don't list one in `prerender.paths`.
170
171
 
172
+ ### Rewrites
173
+
174
+ Serve different content at the same URL — no redirect. The way to give a clean path to a file that isn't in the build output:
175
+
176
+ ```json
177
+ { "web": { "rewrites": [
178
+ { "source": "/sitemap.xml", "destination": "/_/files/public/site/sitemap.xml" },
179
+ { "source": "/docs/*rest", "destination": "/help/*rest" }
180
+ ] } }
181
+ ```
182
+
183
+ `destination` is either `/_/files/public/<store>/<key>` (the object's bytes served inline — use this for anything the app generates at runtime and uploads: sitemaps, `robots.txt`, `llms.txt`, `.well-known/*`; the store must be public, private is rejected at build) or another path in the build output. Same `source` syntax as redirects, first match wins. Objects over 10 MB fall back to a CDN redirect. External URLs are not supported (use `mounts`), nor are other `/_/` surfaces.
184
+
185
+ Redirects resolve before everything; rewrites resolve at the content lookup, after prerendering — so a path with both gets the redirect.
186
+
171
187
  ### Mounting other apps
172
188
 
173
189
  Rare: `mounts` serves another same-workspace app under a path prefix of this app's hosts — `{ "web": { "mounts": [{ "path": "/docs", "app": "docs-site" }] } }` (`app` = the target's `custom_subdomain` or appId). The child is served first-class (its own bundle, session, backend, prerendering) and needs no mount-specific config; the two serving conventions above are what make an app mountable.
174
190
 
175
- Under a mount the child's own `web.json` governs its SEO and routing: its `prerender.paths` gates its mounted pages, its `prerender.invalidate` purges them, its `redirects`/`trailingSlash` apply within the prefix (written against its own paths, with the prefix added back to relative destinations), and its `sitemap.xml` is served with URLs rewritten to the mount and advertised in the parent's `robots.txt`. The child's `robots.txt` *rules* don't carry over (the build log lists them prefixed for the parent to adopt), and canonicals must be written from the page's own location a hardcoded absolute canonical points crawlers back at the child's host and undoes the mount.
191
+ Under a mount the child's own `web.json` governs its routing: its `prerender.paths` gates its mounted pages, its `prerender.invalidate` purges them, and its `redirects`/`rewrites`/`trailingSlash` apply within the prefix (written against its own paths). SEO files are NOT handled for you the child must generate its sitemap with the mounted URLs, and the parent must advertise it in its own `robots.txt` or sitemap index. Canonicals must be written from the page's own location; a hardcoded absolute canonical points crawlers back at the child's host and undoes the mount.
176
192
 
177
193
  ## API Interface
178
194
 
@@ -39,7 +39,7 @@ These are things we already know about and have decided to accept:
39
39
  - use [wouter](https://github.com/molefrog/wouter) for React routing instead of reaching for react-router
40
40
  - uploading user files should always happen via `platform.uploadFile()` from `@mindstudio-ai/interface` — not custom S3 code, not FormData to a method endpoint
41
41
  - for build-time prerendering of purely static sites (marketing pages with no dynamic content — distinct from the platform's crawler prerendering, below), roll your own with a post-build `renderToString` script — do not use `vite-prerender-plugin` (it bundles the prerender script as a client chunk, adding ~800KB to the user-facing bundle with no way to prevent it)
42
- - **Prerendering for crawlers/unfurlers is a platform feature — don't design around it.** For SEO / link-unfurl / AI-crawler visibility on a non-static SPA, the platform already handles it: routes opt in via `web.json` (`{ "web": { "prerender": { "paths": ["/blog/*"] } } }`), the SPA signals readiness by setting `data-prerender-ready` on the html element, deploys invalidate the snapshot cache automatically, and content that changes outside deploys is invalidated at runtime with `await prerender.invalidate([...])` from `@mindstudio-ai/agent` (called from the mutating method). It serves cached headless snapshots of the live SPA to bots — it is NOT build-time rendering. Do not recommend post-build render scripts, rebuild-on-content-change, or third-party prerender services for this. An app mounted under another app's path prefix keeps its own `prerender.paths` and its own `prerender.invalidate` — don't recommend moving prerender config to the parent, and don't hand-roll sitemap/robots rewriting for a mount (the platform rewrites the mounted sitemap and advertises it in the parent's robots.txt). The developer's main context carries the full interfaces reference with exact semantics — tell them to consult it rather than improvising.
42
+ - **Prerendering for crawlers/unfurlers is a platform feature — don't design around it.** For SEO / link-unfurl / AI-crawler visibility on a non-static SPA, the platform already handles it: routes opt in via `web.json` (`{ "web": { "prerender": { "paths": ["/blog/*"] } } }`), the SPA signals readiness by setting `data-prerender-ready` on the html element, deploys invalidate the snapshot cache automatically, and content that changes outside deploys is invalidated at runtime with `await prerender.invalidate([...])` from `@mindstudio-ai/agent` (called from the mutating method). It serves cached headless snapshots of the live SPA to bots — it is NOT build-time rendering. Do not recommend post-build render scripts, rebuild-on-content-change, or third-party prerender services for this. An app mounted under another app's path prefix keeps its own `prerender.paths` and its own `prerender.invalidate` — don't recommend moving prerender config to the parent. SEO files under a mount are NOT automatic: the child generates its sitemap with the mounted URLs (point its base-URL config at the mount) and the parent advertises it in its own robots.txt or sitemap index. To give a generated file a clean path (`/sitemap.xml`, `/robots.txt`, `/llms.txt`, `.well-known/*`) use a `web.json` rewrite to `/_/files/public/<store>/<key>` — never a redirect, which moves the URL, and never a client-side component. The developer's main context carries the full interfaces reference with exact semantics — tell them to consult it rather than improvising.
43
43
 
44
44
  ### Common pitfalls (always flag these)
45
45
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindstudio-ai/remy",
3
- "version": "0.1.304",
3
+ "version": "0.1.305",
4
4
  "description": "Remy coding agent",
5
5
  "repository": {
6
6
  "type": "git",