Build on the supported package contract
Use @absolutejs/sync-pack-mentions through its supported public entry points.
@absolutejs/sync-pack-mentionsv0.1.4betaData & Sync@mention parser pack for @absolutejs/sync — extracts @usernames from a body, writes per-actor mention rows, fires an onMention hook that composes with the notifications pack
bun add @absolutejs/sync-pack-mentions@username parser pack for @absolutejs/sync. Owns a mentions table, parses bodies for @usernames, writes per-actor mention rows, and fires an onMention hook the host wires into other packs.
The onMention hook is the seam. Packs in @absolutejs/sync-packs never call each other's mutations directly; the host wires them together. This pack provides the parser + the collection; you decide whether mentions fire notifications, emails, Slack pings, or anything else.
ownsTables — mentions
Collections — mentions (per-actor view, filterable by sourceKind / unresolvedOnly)
Mutations — mentions:record { sourceKind, sourceId, body, authorId? }, mentions:resolve { id }, mentions:dismiss { id }
Permissions — only the mentioned actor reads, updates, deletes their rows; insert is host-trusted (the pack itself writes on the author's behalf)
The host calls mentions:record right after its own post mutation succeeds, then onMention fires once per parsed mention. From inside the hook, the host can engine.runMutation('notifications:notify', …) to compose with @absolutejs/sync-pack-notifications.
Mention rows are idempotent ((sourceKind, sourceId, mentionedActorId) is the primary key), so re-calling mentions:record on an edit of the same source body does not re-fire onMention for the same target. Self-mentions are skipped automatically.
Outcomes
Use @absolutejs/sync-pack-mentions through its supported public entry points.
Hardening checklist
Follow in order
# @absolutejs/sync-pack-mentions
import { createSyncEngine } from '@absolutejs/sync/engine';
import { createMentionsPack } from '@absolutejs/sync-pack-mentions';
const engine = createSyncEngine();
engine.registerPack(
createMentionsPack({
getActorId: (ctx) => ctx.session.userId,
resolveActorId: async (username) => userIdByUsername(username),
onMention: async ({ mention }, ctx) => {
await engine.runMutation(
'notifications:notify',
{
targetActorId: mention.mentionedActorId,
kind: 'mention',
title: 'You were mentioned',
body: mention.snippet,
href: `/comments/${mention.sourceId}`,
},
ctx,
);
},
}),
);Supported entry points declared by this package manifest.
Package entry point declared in package.json.
Scripts declared by this package manifest.
Search the declarations exported by the current package type files. Expand a symbol to inspect its source-backed signature.
One row per (sourceKind, sourceId, mentionedActorId).
type MentionRow = {
/** `${sourceKind}:${sourceId}:${mentionedActorId}` — deterministic so re-recording is idempotent. */
id: string;
/** Host-level category for the row that originated the mention ("comment", "doc", "task", …). */
sourceKind: string;
/** Host-level id of the row that originated the mention. */
sourceId: string;
/** Who wrote the body containing the mention. `null` for system-generated content. */
authorId: string | null;
/** The actor id the `@username` resolved to. */
mentionedActorId: string;
/** The raw username text (without the `@`). */
username: string;
/** A short excerpt of the body around the mention — useful for inbox previews. */
snippet: string;
createdAt: number;
/** Stamped by `mentions:resolve` (host's onMention hook is free to call it). */
resolvedAt: number | null;
};@absolutejs/sync-pack-mentions