Skip to content

Save and Send-Test adapter/callback model #46

Description

@patoperpetua

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 onSave prop declared in the scaffold:

export interface SaveResult {
  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.

Send-test contract

onSendTest?: (
  files: SerializedTemplateSource,
  recipient: string,
) => Promise<SendTestResult | void>;
  • 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent-readyMeets every criterion in docs/github-source-of-truth.md, section 4 — safe for an agent to claimenhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions