Gramforge API reference
Exports of @gramforge/core. Back to the module
Functions
blockquote
functionblockquote(...children: readonly Inline[]): BlockquoteNode
bold
functionbold(...children: readonly Inline[]): BoldNode
code
functioncode(value: string): CodeNode
expandableBlockquote
functionexpandableBlockquote(...children: readonly Inline[]): ExpandableBlockquoteNode
gram
functiongram(strings: TemplateStringsArray, ...values: readonly GramValue[]): RichTextNode[]
italic
functionitalic(...children: readonly Inline[]): ItalicNode
link
functionlink(href: string, ...children: readonly Inline[]): LinkNode
mentionUser
functionmentionUser(userId: number, label: string): MentionNode
mentionUsername
functionmentionUsername(username: string): MentionNode
pre
functionpre(value: string, language?: PreLanguage): PreNode
spoiler
functionspoiler(...children: readonly Inline[]): SpoilerNode
strikethrough
functionstrikethrough(...children: readonly Inline[]): StrikethroughNode
text
functiontext(value: string): TextNode
underline
functionunderline(...children: readonly Inline[]): UnderlineNode
defineCallbackAction
functionValidate `actionId` at call time and return an explicitly-typed def. An invalid `actionId` is a programmer bug (a hardcoded literal that violates the `/^[a-z0-9]{1,8}$/` budget), not an expected runtime path, so this throws a descriptive `Error` rather than returning a result DU.
<TPayload extends Record<string, unknown>>(input: { actionId: string; payloadSchema: z.ZodType<TPayload>; fields: readonly (keyof TPayload & string)[]; }): CallbackActionDef<TPayload>decodeCallbackData
functionDecode a `callback_data` string against a namespace. Generic `TPayload` is the caller's asserted payload type; the actual shape is enforced by the matched action's zod schema, and the validated result is branded to `TPayload` only after a successful `safeParse`.
<TPayload, TActions extends Record<string, AnyCallbackActionDef> = Record<string, AnyCallbackActionDef>>(callbackData: string, namespace: CallbackNamespace<TActions>, deps: CallbackDecodeDeps): Promise<CallbackDecodeResult<TPayload>>
encodeCallbackAction
functionEncode via a namespace + action key. The key is narrowed to the namespace's declared action names (a bogus key is a compile-time error, not a runtime one); payload is a free `TPayload` here — `callbackButton` is the entry point that ties payload shape to the chosen action.
<TPayload extends Record<string, unknown>, TActions extends Record<string, AnyCallbackActionDef>>(namespace: CallbackNamespace<TActions>, actionKey: keyof TActions & string, payload: TPayload, deps: CallbackEncodeDeps): Promise<string>
callbackButton
functionBuild one inline button for a bound action + typed payload. `payload` is statically tied to the action's declared payload shape, so a missing/extra field is a compile-time error.
<TPayload extends Record<string, unknown>>(text: string, action: BoundCallbackAction<TPayload>, payload: TPayload, deps: CallbackEncodeDeps): Promise<InlineKeyboardButton>
inlineKeyboard
functionShape a list of rows into an `InlineKeyboardMarkup`.
inlineKeyboard(rows: readonly (readonly InlineKeyboardButton[])[]): InlineKeyboardMarkup
keyboardRow
functionShape a list of buttons into a single keyboard row.
keyboardRow(buttons: readonly InlineKeyboardButton[]): readonly InlineKeyboardButton[]
defineCallbackNamespace
functionValidate `namespaceId` at call time (programmer bug on failure → throw) and bind every action to the namespace id.
<TActions extends Record<string, AnyCallbackActionDef>>(input: { namespaceId: string; actions: TActions; }): CallbackNamespace<TActions>createInMemoryPointerStore
functionA non-durable, non-evicting `PointerStore` backed by a `Map`. TEST-ONLY: it holds envelopes in process memory with no persistence, no eviction, and no cross-process visibility. Do NOT use in production — decode must survive a process restart, which this store does not.
createInMemoryPointerStore(): PointerStore
toChatId
functiontoChatId(value: number): IdResult<ChatId>
toMessageId
functiontoMessageId(value: number): IdResult<MessageId>
nodeText
functionThe rendered plain text of a single node (its leaves concatenated in order).
nodeText(node: RichTextNode): string
renderedLength
functionUTF-16 code-unit length of the rendered text (the unit Telegram counts).
renderedLength(nodes: readonly RichTextNode[]): number
renderPlainText
functionThe rendered plain text of a node sequence.
renderPlainText(nodes: readonly RichTextNode[]): string
resetDiagnostics
functionTest-only: clear the dedup set between tests.
resetDiagnostics(): void
setDiagnosticHook
functionsetDiagnosticHook(fn: ((e: DiagnosticEvent) => void) | null): void
warnDegraded
functionwarnDegraded(context: string, detail: string): void
warnNotImplemented
functionwarnNotImplemented(category: string, detail: string): void
warnUnexpected
functionwarnUnexpected(context: string, detail: string, data?: Record<string, unknown>): void
createCaptionText
functioncreateCaptionText(nodes: readonly RichTextNode[]): CaptionTextResult
createMessageText
functioncreateMessageText(nodes: readonly RichTextNode[]): MessageTextResult
messageNodes
functionRead the validated nodes back out of a branded message/caption value.
messageNodes(message: MessageText | CaptionText): readonly RichTextNode[]
messageText
functionRead the rendered plain text back out of a branded message/caption value.
messageText(message: MessageText | CaptionText): string
collapsible
functioncollapsible(summary: readonly RichTextNode[], children: readonly RichBlockNode[]): CollapsibleBlock
heading
functionheading(level: 1 | 2 | 3 | 4, children: readonly RichTextNode[]): HeadingBlock
math
functionmath(latex: string): MathBlock
table
functiontable(header: readonly (readonly RichTextNode[])[], rows: readonly (readonly (readonly RichTextNode[])[])[]): TableBlock
parseRichText
functionparseRichText(value: unknown): ParseRichTextResult
Types
GramValue
typeA value interpolable into a `gram` template.
type GramValue = RichTextNode | readonly RichTextNode[] | string
Inline
typeA child accepted by the builders: a node, or a bare string (wrapped as text).
type Inline = RichTextNode | string
Brand
typetype Brand = Brand<T, B>
CallbackActionDef
typeA declared callback action: id + payload schema + positional field order.
type CallbackActionDef = CallbackActionDef<TPayload>
CallbackDecodeDeps
typeDependencies a decode call needs. `hmacSecrets` is a `[current, ...previous]` list verified in order so a caller can grace-period a secret rotation; passing just `[current]` is the simpler valid default.
type CallbackDecodeDeps = {
readonly pointerStore: PointerStore;
readonly hmacSecrets: readonly Uint8Array[];
readonly now: () => number;
}CallbackDecodeResult
typeThe six mutually-exclusive outcomes of decoding a `callback_data` string.
type CallbackDecodeResult = CallbackDecodeResult<TPayload>
CallbackEncodeDeps
typeDependencies an encode call needs: store + signing secret + clock + TTL.
type CallbackEncodeDeps = {
readonly pointerStore: PointerStore;
readonly hmacSecret: Uint8Array;
readonly now: () => number;
readonly ttlMs: number;
}CallbackActionId
typeA short (1-8 char) action id, part of the compact wire format.
type CallbackActionId = string & z.BRAND<"CallbackActionId">
CallbackNamespaceId
typeA short (1-4 char) namespace id, part of the compact wire format.
type CallbackNamespaceId = string & z.BRAND<"CallbackNamespaceId">
CallbackToken
typeA fixed 22-char base64url (128-bit) pointer-store token.
type CallbackToken = string & z.BRAND<"CallbackToken">
InlineKeyboardButton
typeThe minimal Bot API inline button shape `core` produces.
type InlineKeyboardButton = {
readonly text: string;
readonly callback_data: string;
}InlineKeyboardMarkup
typeA grid of button rows, ready to drop into `reply_markup`.
type InlineKeyboardMarkup = {
readonly inline_keyboard: readonly (readonly InlineKeyboardButton[])[];
}BoundCallbackAction
typeAn action bound to its namespace — self-contained for encoding.
type BoundCallbackAction = BoundCallbackAction<TPayload>
CallbackNamespace
typeA compile-time registry of bound actions keyed by declaration name.
type CallbackNamespace = CallbackNamespace<TActions>
PointerEnvelope
typeThe signed-at-rest record a pointer token resolves to. `notAfter` is embedded here (not on the wire) and checked post-lookup so a still-resolvable token for a button that should be considered dead decodes as `expired`, not `ok`.
type PointerEnvelope = {
readonly namespaceId: CallbackNamespaceId;
readonly actionId: CallbackActionId;
/** `JSON.stringify` of the zod-validated payload. */
readonly payloadJson: string;
/** Epoch ms; caller-chosen TTL horizon. */
readonly notAfter: number;
}PointerStore
typeCaller-supplied storage for spillover envelopes. `put` overwrite is a caller bug (tokens are 128-bit random, collision is cryptographically negligible), not something the codec guards against.
type PointerStore = {
put(token: CallbackToken, envelope: PointerEnvelope): Promise<void>;
get(token: CallbackToken): Promise<PointerEnvelope | undefined>;
}ChatId
typeA Telegram chat identifier (may be negative for groups/channels).
type ChatId = Brand<number, "ChatId">
IdResult
typetype IdResult = IdResult<T>
MessageId
typeA Telegram message identifier within a chat.
type MessageId = Brand<number, "MessageId">
DiagnosticKind
typeRuntime diagnostics — the house alternative to deferred-work comments. Three functions: `warnNotImplemented`, `warnDegraded`, `warnUnexpected`. Each fires once per stable key (except `warnUnexpected`, which always fires), is greppable, and can be piped into a UI panel via {@link setDiagnosticHook}. Usage: warnDegraded("MyModule.fallback", "linear interp — cubic deferred, spec:120-140"); warnNotImplemented("MyModule.featureX", "spec §4 not yet lowered"); warnUnexpected("MyModule.parse", "expected number, got string", { value });
type DiagnosticKind = "not-implemented" | "degraded" | "unexpected"
CaptionTextResult
typetype CaptionTextResult = | { kind: "ok"; value: CaptionText }
| { kind: "too-long"; limit: typeof CAPTION_TEXT_LIMIT; actual: number }MessageTextResult
typetype MessageTextResult = | { kind: "ok"; value: MessageText }
| { kind: "too-long"; limit: typeof MESSAGE_TEXT_LIMIT; actual: number }RichBlockNode
typetype RichBlockNode = HeadingBlock | MathBlock | TableBlock | CollapsibleBlock
BlockquoteChild
typeNodes permitted directly inside a blockquote (excludes both blockquote variants).
type BlockquoteChild = | TextNode | CodeNode | PreNode | BoldNode | ItalicNode | UnderlineNode | StrikethroughNode | SpoilerNode | LinkNode | MentionNode
MentionTarget
typeMention target: by
type MentionTarget = | { readonly kind: "username"; readonly username: string }
| { readonly kind: "user-id"; readonly userId: number; readonly label: string }ParseRichTextResult
typetype ParseRichTextResult = | { kind: "ok"; value: RichTextNode[] }
| { kind: "invalid"; message: string }PreLanguage
typeLanguage tag for a `pre` block, modeled as a discriminated union (no `.optional`).
type PreLanguage = | { readonly kind: "known"; readonly value: string }
| { readonly kind: "unknown" }RichTextNode
typetype RichTextNode = | TextNode | CodeNode | PreNode | BoldNode | ItalicNode | UnderlineNode | StrikethroughNode | SpoilerNode | LinkNode | MentionNode | BlockquoteNode | ExpandableBlockquoteNode
Interfaces
DiagnosticEvent
interfaceinterface DiagnosticEvent
kind
propertykind: DiagnosticKind
category
propertycategory: string
detail
propertydetail: string
stack
propertystack: string
data
propertydata: Record<string, unknown>
timestamp
propertytimestamp: number
CaptionText
interfaceA RichText document proven to fit within the 1024-code-unit caption limit.
interface CaptionText
[CAPTION_TEXT_BRAND]
property[CAPTION_TEXT_BRAND]: true
nodes
propertynodes: readonly RichTextNode[]
text
propertytext: string
MessageText
interfaceA RichText document proven to fit within the 4096-code-unit message limit.
interface MessageText
[MESSAGE_TEXT_BRAND]
property[MESSAGE_TEXT_BRAND]: true
nodes
propertynodes: readonly RichTextNode[]
text
propertytext: string
CollapsibleBlock
interfaceinterface CollapsibleBlock
kind
propertykind: "collapsible"
summary
propertysummary: readonly RichTextNode[]
children
propertychildren: readonly RichBlockNode[]
HeadingBlock
interfaceinterface HeadingBlock
kind
propertykind: "heading"
level
propertylevel: 1 | 2 | 3 | 4
children
propertychildren: readonly RichTextNode[]
MathBlock
interfaceinterface MathBlock
kind
propertykind: "math"
latex
propertylatex: string
TableBlock
interfaceinterface TableBlock
kind
propertykind: "table"
header
propertyheader: readonly (readonly RichTextNode[])[]
rows
propertyrows: readonly (readonly (readonly RichTextNode[])[])[]
BlockquoteNode
interfaceinterface BlockquoteNode
kind
propertykind: "blockquote"
children
propertychildren: readonly BlockquoteChild[]
BoldNode
interfaceinterface BoldNode
kind
propertykind: "bold"
children
propertychildren: readonly RichTextNode[]
CodeNode
interfaceinterface CodeNode
kind
propertykind: "code"
value
propertyvalue: string
ExpandableBlockquoteNode
interfaceinterface ExpandableBlockquoteNode
kind
propertykind: "expandable-blockquote"
children
propertychildren: readonly BlockquoteChild[]
ItalicNode
interfaceinterface ItalicNode
kind
propertykind: "italic"
children
propertychildren: readonly RichTextNode[]
LinkNode
interfaceinterface LinkNode
kind
propertykind: "link"
href
propertyhref: string
children
propertychildren: readonly RichTextNode[]
MentionNode
interfaceinterface MentionNode
kind
propertykind: "mention"
target
propertytarget: MentionTarget
PreNode
interfaceinterface PreNode
kind
propertykind: "pre"
language
propertylanguage: PreLanguage
children
propertychildren: readonly TextNode[]
SpoilerNode
interfaceinterface SpoilerNode
kind
propertykind: "spoiler"
children
propertychildren: readonly RichTextNode[]
StrikethroughNode
interfaceinterface StrikethroughNode
kind
propertykind: "strikethrough"
children
propertychildren: readonly RichTextNode[]
TextNode
interfaceinterface TextNode
kind
propertykind: "text"
value
propertyvalue: string
UnderlineNode
interfaceinterface UnderlineNode
kind
propertykind: "underline"
children
propertychildren: readonly RichTextNode[]
Constants
CALLBACK_DATA_MAX_BYTES
constHard Bot API ceiling on `callback_data`, in UTF-8 bytes (Bot API 10.1).
const CALLBACK_DATA_MAX_BYTES: 64
CallbackActionIdSchema
constconst CallbackActionIdSchema: z.ZodType<CallbackActionId, z.ZodTypeDef, string>
CallbackNamespaceIdSchema
constconst CallbackNamespaceIdSchema: z.ZodType<CallbackNamespaceId, z.ZodTypeDef, string>
CallbackTokenSchema
constconst CallbackTokenSchema: z.ZodType<CallbackToken, z.ZodTypeDef, string>
InlineKeyboardButtonSchema
constconst InlineKeyboardButtonSchema: z.ZodType<InlineKeyboardButton, z.ZodTypeDef, InlineKeyboardButton>
InlineKeyboardMarkupSchema
constconst InlineKeyboardMarkupSchema: z.ZodType<InlineKeyboardMarkup, z.ZodTypeDef, InlineKeyboardMarkup>
CAPTION_TEXT_LIMIT
constconst CAPTION_TEXT_LIMIT: 1024
MESSAGE_TEXT_LIMIT
constconst MESSAGE_TEXT_LIMIT: 4096
CollapsibleBlockSchema
constconst CollapsibleBlockSchema: z.ZodType<CollapsibleBlock, z.ZodTypeDef, CollapsibleBlock>
HeadingBlockSchema
constconst HeadingBlockSchema: z.ZodType<HeadingBlock, z.ZodTypeDef, HeadingBlock>
MathBlockSchema
constconst MathBlockSchema: z.ZodType<MathBlock, z.ZodTypeDef, MathBlock>
RichBlockNodeSchema
constconst RichBlockNodeSchema: z.ZodType<RichBlockNode, z.ZodTypeDef, RichBlockNode>
TableBlockSchema
constconst TableBlockSchema: z.ZodType<TableBlock, z.ZodTypeDef, TableBlock>
BlockquoteChildSchema
constThe blockquote child union: every node kind except the two blockquote variants.
const BlockquoteChildSchema: z.ZodType<BlockquoteChild, z.ZodTypeDef, BlockquoteChild>
BlockquoteNodeSchema
constconst BlockquoteNodeSchema: z.ZodType<BlockquoteNode, z.ZodTypeDef, BlockquoteNode>
BoldNodeSchema
constconst BoldNodeSchema: z.ZodType<BoldNode, z.ZodTypeDef, BoldNode>
CodeNodeSchema
constconst CodeNodeSchema: z.ZodType<CodeNode, z.ZodTypeDef, CodeNode>
ExpandableBlockquoteNodeSchema
constconst ExpandableBlockquoteNodeSchema: z.ZodType<ExpandableBlockquoteNode, z.ZodTypeDef, ExpandableBlockquoteNode>
ItalicNodeSchema
constconst ItalicNodeSchema: z.ZodType<ItalicNode, z.ZodTypeDef, ItalicNode>
LinkNodeSchema
constconst LinkNodeSchema: z.ZodType<LinkNode, z.ZodTypeDef, LinkNode>
MentionNodeSchema
constconst MentionNodeSchema: z.ZodType<MentionNode, z.ZodTypeDef, MentionNode>
PreNodeSchema
constconst PreNodeSchema: z.ZodType<PreNode, z.ZodTypeDef, PreNode>
RichTextNodeSchema
constconst RichTextNodeSchema: z.ZodType<RichTextNode, z.ZodTypeDef, RichTextNode>
RichTextSchema
constconst RichTextSchema: z.ZodType<RichTextNode[], z.ZodTypeDef, RichTextNode[]>
SpoilerNodeSchema
constconst SpoilerNodeSchema: z.ZodType<SpoilerNode, z.ZodTypeDef, SpoilerNode>
StrikethroughNodeSchema
constconst StrikethroughNodeSchema: z.ZodType<StrikethroughNode, z.ZodTypeDef, StrikethroughNode>
TextNodeSchema
constconst TextNodeSchema: z.ZodType<TextNode, z.ZodTypeDef, TextNode>
UnderlineNodeSchema
constconst UnderlineNodeSchema: z.ZodType<UnderlineNode, z.ZodTypeDef, UnderlineNode>