You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Define and implement the Save and Send-Test adapter/callback model for @singleton-sd/post-kit-editor. The package must never persist anything itself and must never hold GitHub credentials or a long-lived PostKit API key in browser JavaScript — the consumer application supplies both behaviours and owns all authentication.
Scope
Save contract
Finalise the onSave prop declared in the scaffold:
exportinterfaceSaveResult{ok: boolean;/** Message shown to the user on failure. */message?: string;}
onSave: (files: SerializedTemplateSource)=>Promise<SaveResult|void>;
SerializedTemplateSource is the output of serializeTemplateSource() from EmailBuilder.js canvas and lossless template source load/serialize #40 — the three file contents as strings, ready for the consumer to commit to its own repository. Also pass the parsed TemplateSourceFiles alongside it so a consumer can act on structured data without re-parsing.
The editor renders a Save control that:
serialises the current working state,
invokes onSave,
shows an in-progress state while the promise is pending,
shows success or the returned/thrown failure message on settle,
re-enables the control afterwards in both outcomes.
A rejected promise is treated as failure with the error's message; it must never surface as an unhandled rejection.
The editor renders a Send-test control only when onSendTest is supplied.
The control collects a recipient address, validates it is non-empty and syntactically plausible, and invokes the callback.
Same pending/success/failure treatment as Save.
The editor performs no HTTP request of its own for test sending.
Dirty-state tracking
Track whether the working state differs from the template prop it was seeded with.
Expose it via an optional onDirtyChange?: (dirty: boolean) => void prop so the host application can guard navigation.
Reset dirty state after a successful save.
Documentation
Add a README section stating explicitly:
This package never stores templates and never talks to a backend.
Save is Git-backed persistence owned by the consumer repository.
Test sending must route through a trusted server-side path in the consumer application; a long-lived PostKit API key must never be present in browser code.
Include a short snippet showing a consumer's onSendTest calling its own server endpoint, which in turn uses @singleton-sd/post-kit-client server-side.
Constraints
The package must not read or write the filesystem, call GitHub, call the PostKit API, or read credentials from any browser global.
No configuration option may accept an API key, token, or credential. If a reviewer can pass a secret into this package's props, the design is wrong.
Do not implement retry, queuing, or optimistic persistence — a single invocation per user action.
Do not implement runtime email sending logic in this package.
Do not implement validation gating here; the validation issue wires validation into these controls.
Keep controls framework-shell agnostic: no router-based navigation guards, only the onDirtyChange callback.
Acceptance criteria
onSave receives serialised file contents plus the structured TemplateSourceFiles and is the only save path.
The Save control shows pending, success, and failure states, and re-enables in all outcomes.
A rejected onSave promise is handled and surfaced as a failure message with no unhandled rejection.
The Send-test control renders only when onSendTest is provided, validates the recipient address, and mirrors the same pending/success/failure treatment.
The package makes no network request and accesses no credential, in any code path.
No prop or option accepts an API key, token, or credential.
onDirtyChange fires on first modification and resets after a successful save.
README documents the persistence boundary, the browser-credential prohibition, and the server-side test-send pattern.
Component tests cover: successful save, rejected save, save-in-progress disabling, send-test hidden without the callback, and invalid recipient rejection.
pnpm -r --if-present run test passes.
Agent implementation notes
Read serializeTemplateSource() from #40 — its output is the Save payload and must not be re-derived here. Read packages/post-kit-client/README.md for the server-side-only usage pattern to reference in the documented snippet, and Epic #5's "Persistence boundary" and "Test-send boundary" sections for the exact boundaries. Branch: feat/<issue-number>-editor-save-send-test.
Parent: #5
Depends on: #40
Goal
Define and implement the Save and Send-Test adapter/callback model for
@singleton-sd/post-kit-editor. The package must never persist anything itself and must never hold GitHub credentials or a long-lived PostKit API key in browser JavaScript — the consumer application supplies both behaviours and owns all authentication.Scope
Save contract
Finalise the
onSaveprop declared in the scaffold:SerializedTemplateSourceis the output ofserializeTemplateSource()from EmailBuilder.js canvas and lossless template source load/serialize #40 — the three file contents as strings, ready for the consumer to commit to its own repository. Also pass the parsedTemplateSourceFilesalongside it so a consumer can act on structured data without re-parsing.onSave,Send-test contract
onSendTestis supplied.Dirty-state tracking
templateprop it was seeded with.onDirtyChange?: (dirty: boolean) => voidprop so the host application can guard navigation.Documentation
Add a README section stating explicitly:
onSendTestcalling its own server endpoint, which in turn uses@singleton-sd/post-kit-clientserver-side.Constraints
onDirtyChangecallback.Acceptance criteria
onSavereceives serialised file contents plus the structuredTemplateSourceFilesand is the only save path.onSavepromise is handled and surfaced as a failure message with no unhandled rejection.onSendTestis provided, validates the recipient address, and mirrors the same pending/success/failure treatment.onDirtyChangefires on first modification and resets after a successful save.pnpm -r --if-present run testpasses.Agent implementation notes
Read
serializeTemplateSource()from #40 — its output is the Save payload and must not be re-derived here. Readpackages/post-kit-client/README.mdfor the server-side-only usage pattern to reference in the documented snippet, and Epic #5's "Persistence boundary" and "Test-send boundary" sections for the exact boundaries. Branch:feat/<issue-number>-editor-save-send-test.