@ryhrm-gz/xincodo-lib
Version:
Utilities for working with Xincodo body documents.
242 lines (172 loc) • 5.75 kB
Markdown
---
name: save-before-publish-checks
description: >
Load when wiring pre-save or pre-publish checks with safeMigrateBody,
migrateBody, BodyMigrationError, BodyMigrationIssue, lintBody,
BodyLintReport, lint severity policy, persisted JSON handling, future
version rejection, and excluding DB persistence or request handling.
type: lifecycle
library: "@ryhrm-gz/xincodo-lib"
library_version: "0.1.0"
requires:
- building-and-parsing-body
- validating-body
sources:
- "ryhrm-gz/xincodo-lib:README.md"
- "ryhrm-gz/xincodo-lib:src/migration.ts"
- "ryhrm-gz/xincodo-lib:src/lint.ts"
- "ryhrm-gz/xincodo-lib:tests/migration.test.ts"
- "ryhrm-gz/xincodo-lib:tests/lint.test.ts"
---
# Save Before Publish Checks
This skill builds on `building-and-parsing-body` and `validating-body`.
Use it to check `Body` data at save or publish boundaries. Do not design
database persistence, request handlers, or upload flows in this skill.
## Setup
```ts
import { lintBody, safeMigrateBody } from "@ryhrm-gz/xincodo-lib";
export function checkBodyBeforePublish(value: unknown) {
const migrated = safeMigrateBody(value);
if (!migrated.success) {
return { ok: false as const, stage: "migration", issue: migrated.issue };
}
const report = lintBody(migrated.output);
if (!report.valid) {
return { ok: false as const, stage: "lint", report };
}
return { ok: true as const, body: migrated.output, warnings: report.warnings };
}
```
Default blocking policy: migration failures and lint errors block. Lint
warnings are surfaced for application policy.
## Core Patterns
### Check persisted JSON before save
```ts
import { lintBody, safeMigrateBody } from "@ryhrm-gz/xincodo-lib";
const migrated = safeMigrateBody(savedBodyJson);
if (!migrated.success) {
throw new Error(migrated.issue.message);
}
const report = lintBody(migrated.output);
if (!report.valid) {
throw new Error(report.errors.map((issue) => issue.message).join("\n"));
}
```
Treat persisted values as unknown input. Do not cast them directly to `Body`.
### Return user-facing check results
```ts
import { lintBody, safeMigrateBody } from "@ryhrm-gz/xincodo-lib";
export function checkBody(value: unknown) {
const migrated = safeMigrateBody(value);
if (!migrated.success) {
return {
canPublish: false,
errors: [migrated.issue.message],
warnings: [] as string[],
};
}
const report = lintBody(migrated.output);
return {
canPublish: report.valid,
errors: report.errors.map((issue) => issue.message),
warnings: report.warnings.map((issue) => issue.message),
};
}
```
This keeps severity policy explicit without mixing in transport or storage.
### Use throwing migration only inside controlled code
```ts
import { BodyMigrationError, migrateBody } from "@ryhrm-gz/xincodo-lib";
try {
const body = migrateBody(rawBody);
console.log(body.version);
} catch (error) {
if (error instanceof BodyMigrationError) {
console.error(error.issue.message);
}
}
```
For UI-facing save or publish checks, prefer `safeMigrateBody`.
## Common Mistakes
### HIGH Using throwing migration at app boundary
Wrong:
```ts
import { lintBody, migrateBody } from "@ryhrm-gz/xincodo-lib";
const body = migrateBody(rawBody);
const report = lintBody(body);
```
Correct:
```ts
import { lintBody, safeMigrateBody } from "@ryhrm-gz/xincodo-lib";
const migrated = safeMigrateBody(rawBody);
if (!migrated.success) {
return { ok: false as const, issue: migrated.issue };
}
const report = lintBody(migrated.output);
```
`migrateBody` throws `BodyMigrationError`; `safeMigrateBody` returns a result
that is better for user-facing save and publish checks.
Source: `src/migration.ts`; `tests/migration.test.ts`
### CRITICAL Trusting persisted JSON directly
Wrong:
```ts
import { lintBody, type Body } from "@ryhrm-gz/xincodo-lib";
const body = savedArticle.body as Body;
const report = lintBody(body);
```
Correct:
```ts
import { lintBody, safeMigrateBody } from "@ryhrm-gz/xincodo-lib";
const migrated = safeMigrateBody(savedArticle.body);
if (!migrated.success) {
return { ok: false as const, issue: migrated.issue };
}
const report = lintBody(migrated.output);
```
Saved Body JSON should be treated as unknown input and passed through
`safeMigrateBody` before linting or rendering.
Source: maintainer interview
### HIGH Treating future versions as migratable
Wrong:
```ts
import { BODY_VERSION, safeMigrateBody } from "@ryhrm-gz/xincodo-lib";
const result = safeMigrateBody({ version: BODY_VERSION + 1, content: [] });
if (!result.success) {
await saveRawBody(rawBody);
}
```
Correct:
```ts
import { safeMigrateBody } from "@ryhrm-gz/xincodo-lib";
const result = safeMigrateBody(rawBody);
if (!result.success) {
throw new Error(result.issue.message);
}
```
Versions greater than `BODY_VERSION` are unsupported because there is no
downgrade path.
Source: `src/migration.ts`; `tests/migration.test.ts`
### CRITICAL Mixing storage concerns into skill scope
Wrong:
```ts
await xincodo.saveArticle({
body,
databaseUrl,
});
```
Correct:
```ts
import { lintBody, safeMigrateBody } from "@ryhrm-gz/xincodo-lib";
const migrated = safeMigrateBody(rawBody);
if (!migrated.success) {
throw new Error(migrated.issue.message);
}
const report = lintBody(migrated.output);
```
The library can validate Body data before persistence, but DB schema,
request handling, and upload flows are outside its scope.
Source: maintainer interview
## References
- [Migration issues and lint severities](references/migration-issues-and-lint-severities.md)
See also: `building-and-parsing-body/SKILL.md` — persisted JSON should go
through `safeMigrateBody` before lint and publish checks can run.