@samva/vite 0.5.0 → 0.7.0

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/AGENTS.md CHANGED
@@ -1,88 +1,87 @@
1
- # Samva Vite consumer guide
1
+ # @samva/vite agent guide
2
2
 
3
- Install `@samva/markup`, `@samva/vite`, and the Vite peer in the template project. Add
4
- `samvaEditor()` to `vite.config.ts` for the visual editor. Use `@samva/vite/build` only for
5
- programmatic template builds and `@samva/vite/emit` only for module-preview integration.
3
+ `@samva/vite` is the local authoring toolchain for Samva templates written with `@samva/markup`: a
4
+ Vite plugin that serves the visual editor, and programmatic entry points that build, render, and
5
+ export a template project. It compiles nothing itself; every render goes through
6
+ `@samva/markup/compiler`'s `compileEmailProject`, the same compile step a hosted Samva build runs, so
7
+ a local render does not drift from a published one. Publishing and hosted synchronization are not
8
+ here: they are ordinary Git plus `samva templates publish` from `@samva/cli` (see
9
+ `samva templates --help`).
6
10
 
7
- The CLI loads `@samva/vite/build` from the current project. Keep these authoring dependencies in the
8
- project lockfile so local preview, check, and build use the same compiler version as the project.
11
+ ## Entry points
9
12
 
10
- This package is plain TypeScript like `@samva/markup`, and adds no runtime framework of its own to
11
- a template project. `@samva/vite/build` and the preview surfaces answer with discriminated results
12
- carrying an `ok` field, and `@samva/vite/emit` passes the compiler's better-result `Result`
13
- through. A missing `vite`, or an entry that does not default-export a template definition, throws.
13
+ - `@samva/vite` — `samvaEditor()`, the plugin you add to `vite.config.ts`. Options are typed by
14
+ `SamvaEditorPluginOptions`; the README lists them.
15
+ - `@samva/vite/build` — `buildTemplates()` and `createTemplateBuildSession()` for programmatic
16
+ checks and builds. The `samva` CLI loads this module from your project, not from its own bundle.
17
+ - `@samva/vite/project` — the folder-of-templates surface: `loadEmailCatalog()`,
18
+ `renderEmailFixtures()`, `createEmailProjectSession()`, `exportEmailProject()`.
19
+ - `@samva/vite/email` — `createEmailRenderer()` and `renderEmailProject()` for rendering one email
20
+ project from source.
21
+ - `@samva/vite/emit` — module-preview integration for structured SMS and WhatsApp entries.
14
22
 
15
- Hosted synchronization is ordinary Git. A CLI-created project has a repository-local Samva
16
- credential helper, and `samva templates publish` accepts only a clean exact commit reachable from
17
- the fetched `origin` default branch. Publish creates an immutable receipt; it does not push or
18
- rewrite history.
23
+ Install `@samva/markup`, `@samva/vite`, and the `vite` peer as dev dependencies of the template
24
+ project and keep them in its lockfile. The CLI's `templates check`, `templates build`, and the
25
+ editor all resolve these packages from the project, so the lockfile is what pins the compiler
26
+ version your previews, checks, and builds use.
19
27
 
20
- Template discovery is `.tsx` only. The local email editor writes the canonical TSX entry with a
21
- revision check and a fresh comparison against disk; SMS and WhatsApp stay read-only. A change
22
- published without a client is what the editor reads as a foreign edit, so nothing the editor itself
23
- did may reach it that way. A save and a fixture switch both run in the store's mutation queue, so no
24
- rebuild can straddle one and publish the difference anonymously; the editor's write comes back
25
- through the file watcher like any other edit, and a changed file that still holds the bytes its
26
- entry was built from re-evaluates nothing. Watcher events arrive in bursts and one rebuild re-reads
27
- the whole project, so a rebuild that has not started yet covers every event queued before it. Every discovered entry is imported once through the dev
28
- server's own SSR graph, and a default export that is a template definition takes the email lane —
29
- compiled and rendered through `compileEmailProject`, so a local render cannot drift from a published
30
- one. Email requires an executable definition. Structured SMS/WhatsApp entries emit SML, and
31
- for SMS and WhatsApp an invalid current TSX keeps and visibly labels the last successful emission
32
- while the same file remains discovered; deleting the file removes it.
28
+ ## How you hurt yourself here
33
29
 
34
- The email document is one executed render of one declared fixture: the fixture names the template
35
- declares, the fixture being viewed, the render stamped with `data-samva-instance`, and the compile
36
- and client findings taken from rendering every declared fixture as it will be delivered. An entry
37
- that does not build keeps its place with a null render and the findings that stopped it. Its
38
- revision is a digest of authored source and what the declared fixtures render, so source locations
39
- cannot stay pinned after a formatting-only edit. It stays put when only the viewed fixture changes. The dev server is not an https origin, so a local
40
- render points at the editor's own asset route by path — every render here is a preview or the input
41
- to a finding, and the base a publication serves from is a build input rather than authored.
30
+ - **Expecting your Vite config to apply to email rendering.** Every email render, in the editor,
31
+ the CLI, and the programmatic entry points, runs in an evaluator this package roots at its own
32
+ directory with no config file, so your `vite.config.ts` aliases and plugins never reach an email
33
+ template. Bare imports resolve from the package root, which is what makes `@samva/markup` resolve
34
+ under both hoisted and per-package installs. Import shared helpers by relative path; an alias that
35
+ works elsewhere in your app fails here.
36
+ - **Side effects at module scope.** Discovery imports every `.tsx` under the templates directory
37
+ and asks whether its default export is a template definition, and a rebuild re-reads the whole
38
+ project. Top-level code in every module, helpers included, runs whenever the project is
39
+ evaluated; keep it free of I/O and mutable global state.
40
+ - **Relying on a file path as template identity.** Identity is the `id` the definition declares.
41
+ Two definitions declaring one id is a reported error, and moving a file does not change its id.
42
+ Helper modules need no marker or exclusion list: a module is a template only if its default export
43
+ is a definition.
44
+ - **Exporting for delivery with the default asset base.** `exportEmailProject` renders with relative
45
+ URLs and writes each page at `templates/<id>/<fixture>.html` beside a content-addressed `assets/`
46
+ directory, so its default base, `DEFAULT_EXPORT_ASSET_BASE`, only works when those files are
47
+ browsed from disk. An inbox has no directory to resolve a relative URL against, so delivery refuses
48
+ one. For an export you will send, pass the https origin that will serve the assets.
49
+ - **Reusing a renderer without a stable namespace.** `createEmailRenderer` keeps one evaluator
50
+ across renders, as a dev server does, and gives each project its own module-id namespace. Omit
51
+ `namespace` and every `load` takes a fresh one, which isolates unrelated projects but grows the
52
+ graph on every reload. A watch loop over one project passes the same `namespace` each time so its
53
+ ids stay stable. Each `load` re-evaluates its own namespace's modules; `invalidate()` also drops
54
+ the modules namespaces share. `close()` releases the evaluator.
55
+ - **Expecting the email editor to overwrite concurrent edits.** The editor writes back to the
56
+ entry's canonical `.tsx` source after checking that the file on disk is still the revision it
57
+ read, so a change you saved elsewhere is not overwritten; reload the entry and retry. SMS and
58
+ WhatsApp entries are read-only in the editor.
42
59
 
43
- Object email projects compile through `@samva/vite/email`. It is an adapter: the whole compile step
44
- is `@samva/markup/compiler`'s `compileEmailProject`, the same call the hosted build makes, and this
45
- package owns only module resolution and evaluation. The asset base is an explicit input, so a
46
- build and an export can address the same content from different origins. Both entry points evaluate
47
- the compiler's generated wrapper rather than the authored entry: the render has to happen inside the
48
- graph the project's stylesheets registered into.
60
+ ## Rules
49
61
 
50
- `createEmailRenderer` keeps one evaluator across renders, as a dev server does, and gives each
51
- project its own id namespace so their modules coexist. Anything the compiler rewrote into
52
- JavaScript — a stylesheet, an imported asset — is served under a `.js` id; its authored extension
53
- would be claimed by Vite's CSS or asset pipeline. A caller that reloads the same project passes a
54
- stable `namespace` so ids survive the reload and `invalidate()` is what makes changed source take
55
- effect; omitting it takes a fresh namespace, which is what isolates unrelated projects.
62
+ - **Template entries are `.tsx`.** Discovery ignores every other extension.
63
+ - **Template ids and fixture keys match `TEMPLATE_NAME_PATTERN`** from `@samva/markup/template`,
64
+ because both are written into export paths. Code that builds a path from them imports that
65
+ pattern instead of restating it.
66
+ - **Fixtures are validated against the template's own schema before they render.** A bad fixture is
67
+ a finding on that template, not a runtime surprise at send time.
68
+ - **One failure stays with its template.** A refused render reports against its fixture, and an
69
+ email entry that does not build stays in the catalog with a null render and the findings that
70
+ stopped it. SMS and WhatsApp entries that stop compiling keep their last successful preview,
71
+ labeled stale, until the file compiles again or is deleted.
72
+ - **Results are values.** `@samva/vite/build` and the preview surfaces return discriminated results
73
+ with an `ok` field, and `@samva/vite/emit` passes through the compiler's better-result `Result`. A
74
+ missing `vite` peer, or an entry whose default export is not a template definition where one is
75
+ required, throws.
76
+ - **The asset base is a build input, not authored source.** The same content can be built for one
77
+ origin and exported for another. The dev server is not an https origin, so editor previews
78
+ reference assets through the editor's own route by path.
56
79
 
57
- `@samva/vite/project` is the folder-of-templates surface. A project holds many definitions with
58
- shared components and CSS between them; which `.tsx` files are templates is decided by evaluating
59
- the compiler's generated wrapper and asking whether the default export is a template definition, so
60
- an ordinary helper module needs no marker and no exclusion list. Identity is the id the definition
61
- declares, never its path, and two definitions declaring one id is a reported error. Fixtures are
62
- validated against the template's own schema before they render, so a bad fixture is a source defect
63
- the author sees locally.
80
+ ## Proving your setup
64
81
 
65
- `exportEmailProject` renders in the compiler's export mode (`relativeUrls: true`). It writes one
66
- page at `templates/<id>/<fixture>.html` and every asset once under `assets/`, so its default
67
- `../../assets` base is the path from a page's own directory to those bytes. Delivery keeps
68
- refusing a relative reference — an inbox has no directory to resolve one against — so an export
69
- destined for sending names the https origin it will be served from instead. Either way the export
70
- writes each asset under its content address and records the base, so the manifest is the whole
71
- mapping.
72
-
73
- A refused render reports against the one fixture rather than throwing at the caller: one template
74
- that cannot render must not take the rest of the catalog with it.
75
-
76
- The evaluator roots itself at this package's own directory and refuses an ambient Vite config.
77
- Virtual ids have no directory, so bare imports resolve against the server root; rooting here is what
78
- makes `@samva/markup` resolve under a per-package install as well as a hoisted one.
79
-
80
- A golden-digest test in `tests/email-parity.test.ts` pins this adapter's output against the same
81
- value the hosted build asserts in `apps/agents/tests/workerd/email-parity.test.ts`.
82
-
83
- ## Verification
84
-
85
- `bun run --filter @samva/vite test:browser` builds the plugin and embedded editor, then runs the
86
- Chromium source-editing integration tests. `test:browser:cross` runs Chromium, Firefox, and WebKit.
87
- These tests own temporary template projects and plugin servers; the editor library's browser suite
88
- tests its standalone host separately.
82
+ - `samva templates check --dir <templates-dir>` executes every declared fixture and reports
83
+ findings; `--watch` keeps it running while you edit.
84
+ - `vite` with `samvaEditor()` configured serves the editor at the configured `route`; every entry
85
+ should appear with its fixtures.
86
+ - `exportEmailProject({ dir, out })` writes browsable HTML and text for every fixture and a
87
+ `catalog.json` with the asset mapping and findings, without Samva credentials.
package/README.md CHANGED
@@ -152,5 +152,3 @@ Export writes `templates/<id>/<fixture>.html` and `.txt`, content-addressed file
152
152
  and `catalog.json` with the asset mapping and findings. The default `../../assets` base resolves
153
153
  from each exported page. For delivery, supply the actual HTTPS `assetBase` and serve those bytes
154
154
  there; relative URLs are for local export. External HTTPS images stay external references.
155
-
156
- The runnable `examples/email-starter` workspace exercises the authoring setup.