Skip to content

Render Word manifests from one template per environment - #595

Open
kcarnold wants to merge 1 commit into
mainfrom
claude/word-addin-staging-localhost-giwvt3
Open

Render Word manifests from one template per environment#595
kcarnold wants to merge 1 commit into
mainfrom
claude/word-addin-staging-localhost-giwvt3

Conversation

@kcarnold

Copy link
Copy Markdown
Contributor

Adds a staging manifest so beta testers can run staging in Word, and replaces the build-time regex transform with a template so the three manifests can't drift.

Why not a runtime picker

Word has no equivalent of the Google Docs sidebar's source picker. The gdocs sidebar has no origin of its own, so "which environment" is entirely a property of the injected bundle. Word's task pane is a real browsing context at SourceLocation — injecting a staging bundle into a page served from app.thoughtful-ai.com would still leave you on the prod origin, with the prod backend, prod cookies and prod logs. So each deploy target genuinely needs its own manifest.

What replaced the string surgery

The manifest was a checked-in dev file rewritten at build time:

content.replace(/-dev/g, '').replace(idDev, idProd).replace(urlDev, urlProd)

That has no spelling for a third environment, and it only rewrote strings someone remembered to write in the -dev form — CommandsGroup.Label was plain "Thoughtful", so the ribbon group already looked identical in dev and prod. Undetected drift, in the one file whose job is to tell the environments apart.

Now:

  • frontend/manifest/template.xml — the structure, once. Placeholders {{APP_ID}}, {{APP_NAME}}, {{BASE_URL}}.
  • frontend/manifest/environments.ts — the differences, once.
  • frontend/manifest/environments.test.ts — the guard the regex couldn't provide.
Environment File Origin DisplayName
prod manifest.xml app.thoughtful-ai.com Thoughtful
staging manifest-staging.xml staging.thoughtful-ai.com Beta Thoughtful
dev manifest-dev.xml localhost:3000 Dev Thoughtful

Each has its own add-in id, so all three can be installed side by side.

Two behaviour changes worth reviewing

Every build emits all three manifests, instead of --mode picking one. Which manifest you need depends on who is installing it, not on the flags that produced the build. The old coupling meant the image the Dockerfile builds carried a manifest naming the prod origin no matter where it was deployed — a staging deployment would have handed out a prod manifest.

Names put the distinguishing word first. The Add-ins menu truncates DisplayName to roughly ten characters, so Thoughtful-dev and Thoughtful both render as Thoughtful there and a dev install is indistinguishable from a real one. The task pane header shows the full string, so only the menu is affected. Prod's name is unchanged.

What the test enforces

Per environment: no leftover placeholders, no mention of any other environment's origin or id, and every DefaultValue URL built from that environment's base (bar Microsoft's own "learn more" link). That last one catches a hardcoded origin added to the template later — which the old transform would have shipped silently. Plus distinct ids, distinct filenames, and distinct first-ten-characters of the display name.

Verification

  • npm test — 239 passed (17 new)
  • npm run typecheck, npm run lint — clean (3 pre-existing warnings, unrelated)
  • npm run test:build after a clean build + build:google-docs — all three manifests present and well-formed, gdocs build doesn't clobber them
  • All three parse as XML with the expected id/name/origin
  • Prod's rendered manifest is byte-identical to the old transform's output, apart from a generated-file banner comment and a trailing newline

office-addin-manifest validate couldn't run here — it calls a Microsoft web service that this sandbox's egress proxy blocks (403). Worth running once on dist/manifest-staging.xml before handing it to testers: npm run validate:staging.

Not fixed here

Commands.Url points at {{BASE_URL}}/commands/commands.html, but the build emits commands.html at the root of dist/, so the FunctionFile 404s. This predates the template — it was the same in the checked-in manifest — and it's left alone rather than folded silently into a refactor. Noted in frontend/manifest/README.md.

Separately, and outside this PR's scope: the gdocs bundle compiles GDOCS_BACKEND_URL to the prod origin in every non-dev build, so picking "staging" in the sidebar picker loads staging's bundle but talks to the prod backend.


Generated by Claude Code

Word has no equivalent of the Google Docs sidebar's runtime source picker:
the task pane loads whatever origin SourceLocation names, so each deploy
target needs its own manifest. Add a staging manifest for beta testers
without duplicating the manifest three ways.

The manifest was a checked-in dev file rewritten by regex at build time
(`.replace(/-dev/g, '')` plus id/URL swaps). That transform had no
spelling for a third environment, and it only rewrote strings someone
remembered to write in the -dev form — CommandsGroup.Label was plain
"Thoughtful", so the ribbon group looked identical in dev and prod.

Replace it with manifest/template.xml (structure, once) plus
manifest/environments.ts (the differences, once), rendered into dist/ by
the existing Vite plugin. environments.test.ts asserts what the regex
couldn't: distinct ids, no environment's manifest mentioning another's
origin, and every URL built from that environment's base.

Every build now emits all three manifests rather than choosing one by
--mode. Which manifest you need depends on who is installing it, and the
old coupling meant the image the Dockerfile builds carried a manifest
naming the prod origin regardless of where it was deployed.

Name the environments "Thoughtful", "Beta Thoughtful" and "Dev
Thoughtful": the Add-ins menu truncates DisplayName to about ten
characters, so a trailing marker is invisible exactly where you need it
to tell a dev install from a real one. Prod's manifest is byte-identical
to the old transform's output apart from the generated-file banner.

Also point the start/validate scripts at the rendered manifests — they
named frontend/manifest.xml, which has never existed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PNuWdfW5eePAWvepBdHfje
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants