@grammyjs/menu
Advanced tools
Comparing version 1.0.1 to 1.0.2
@@ -437,3 +437,3 @@ import { Context, Filter, InlineKeyboardButton, InlineKeyboardMarkup, LoginUrl, Middleware, MiddlewareObj } from "./deps.node.js"; | ||
* is shown to the user that the menu was outdated. Long story short, you | ||
* can use this option to personalise what notification to display. You can | ||
* can use this option to personalize what notification to display. You can | ||
* pass a string as the message to display to the user. | ||
@@ -455,3 +455,4 @@ * | ||
* Fingerprint function that lets you generate a unique string every time a | ||
* menu is rendered. Used to determine if a menu is outdated. | ||
* menu is rendered. Used to determine if a menu is outdated. If specified, | ||
* replaces the built-in heuristic. | ||
* | ||
@@ -468,5 +469,8 @@ * The built-in heuristic that determines whether a menu is outdated takes | ||
* can use this option to supply the neccessary data that lets the menu | ||
* plugin determine more accurately if the menu is outdated. | ||
* plugin determine more accurately if the menu is outdated. Similarly, if | ||
* any of these things differ but you want to consider the menu to be up to | ||
* date, you can also use this option to signal that. | ||
* | ||
* By default, no fingerprinting is used. | ||
* In other words, specifying a fingerprint function will replace the above | ||
* heuristic entirely by your own implementation. | ||
*/ | ||
@@ -473,0 +477,0 @@ fingerprint?: DynamicString<C>; |
@@ -307,2 +307,6 @@ "use strict"; | ||
}; | ||
if (options.onMenuOutdated === false && | ||
options.fingerprint !== undefined) { | ||
throw new Error("Cannot use a fingerprint function when outdated detection is disabled!"); | ||
} | ||
} | ||
@@ -387,4 +391,6 @@ /** | ||
} | ||
const callback_data = `${this.id}/${row}/${col}/${payload}/`; | ||
return { callback_data, text }; | ||
return { | ||
callback_data: `${this.id}/${row}/${col}/${payload}/`, | ||
text, | ||
}; | ||
} | ||
@@ -404,8 +410,13 @@ else | ||
// Inject hash values to detect keyboard changes | ||
const data = [ | ||
...lengths, | ||
...toNums(btn.text), | ||
...toNums(fingerprint), | ||
]; | ||
btn.callback_data += tinyHash(data); | ||
let type; | ||
let data; | ||
if (fingerprint) { | ||
type = "f"; | ||
data = toNums(fingerprint); | ||
} | ||
else { | ||
type = "h"; | ||
data = [...lengths, ...toNums(btn.text)]; | ||
} | ||
btn.callback_data += type + tinyHash(data); | ||
} | ||
@@ -448,7 +459,14 @@ } | ||
composer.on("callback_query:data").lazy(async (ctx) => { | ||
const [path, rowStr, colStr, payload, ...rest] = ctx | ||
// Extract data from callback query data | ||
const [id, rowStr, colStr, payload, ...rest] = ctx | ||
.callbackQuery.data.split("/"); | ||
const [type, ...h] = rest.join("/"); | ||
const hash = h.join(""); | ||
// Skip handling if this is not a known format | ||
if (!rowStr || !colStr) | ||
return []; | ||
const menu = this.index.get(path); | ||
if (type !== "h" && type !== "f") | ||
return []; | ||
// Get matched menu from index | ||
const menu = this.index.get(id); | ||
if (menu === undefined) | ||
@@ -459,12 +477,15 @@ return []; | ||
if (row < 0 || col < 0) { | ||
throw new Error(`Invalid button position '${row}/${col}'`); | ||
const msg = `Invalid button position '${rowStr}/${colStr}'`; | ||
throw new Error(msg); | ||
} | ||
const reply_markup = menu; | ||
const outdated = menu.options.onMenuOutdated; | ||
// provide payload on `ctx.match` if it is not empty | ||
if (payload) | ||
ctx.match = payload; | ||
// Create middleware that installs `ctx.menu` | ||
const navInstaller = this.makeNavInstaller(menu); | ||
/** Defines what happens if the used menu is outdated */ | ||
function menuIsOutdated() { | ||
const outdated = reply_markup.options.onMenuOutdated; | ||
if (outdated === false) | ||
throw new Error("cannot happen"); | ||
return typeof outdated !== "string" | ||
@@ -474,6 +495,13 @@ ? [navInstaller, outdated] | ||
ctx.answerCallbackQuery({ text: outdated }), | ||
ctx.editMessageReplyMarkup({ reply_markup }), | ||
ctx.editMessageReplyMarkup({ reply_markup: menu }), | ||
]); | ||
} | ||
const check = this.options.onMenuOutdated !== false; | ||
// Check fingerprint if used | ||
const fingerprint = await uniform(ctx, menu.options.fingerprint); | ||
const useFp = fingerprint !== ""; | ||
if (useFp !== (type === "f")) | ||
return menuIsOutdated(); | ||
if (useFp && tinyHash(toNums(fingerprint)) !== hash) { | ||
return menuIsOutdated(); | ||
} | ||
// Create renderer and perform rendering | ||
@@ -483,2 +511,3 @@ const renderer = createRenderer(ctx, (btn) => btn); | ||
// Check dimension | ||
const check = !useFp && outdated !== false; | ||
if (check && (row >= range.length || col >= range[row].length)) { | ||
@@ -494,15 +523,12 @@ return menuIsOutdated(); | ||
} | ||
// Check payloads | ||
const expectedPayload = await uniform(ctx, btn.payload); | ||
if (check && payload !== expectedPayload) | ||
return menuIsOutdated(); | ||
// Check hashes | ||
const hash = rest.join("/"); | ||
const lengths = [range.length, ...range.map((row) => row.length)]; | ||
const label = await uniform(ctx, btn.text); | ||
const fingerprint = await uniform(ctx, menu.options.fingerprint); | ||
const data = [...lengths, ...toNums(label), ...toNums(fingerprint)]; | ||
const expectedHash = tinyHash(data); | ||
if (check && hash !== expectedHash) | ||
return menuIsOutdated(); | ||
// Check dimensions | ||
if (check) { | ||
const rowCount = range.length; | ||
const rowLengths = range.map((row) => row.length); | ||
const label = await uniform(ctx, btn.text); | ||
const data = [rowCount, ...rowLengths, ...toNums(label)]; | ||
const expectedHash = tinyHash(data); | ||
if (hash !== expectedHash) | ||
return menuIsOutdated(); | ||
} | ||
// Run handler | ||
@@ -523,3 +549,3 @@ const handler = btn.middleware; | ||
let injectMenu = false; | ||
let targetMenu = undefined; | ||
let targetMenu = menu; | ||
ctx.api.config.use((prev, method, payload, signal) => { | ||
@@ -526,0 +552,0 @@ var _b, _c; |
@@ -1,1 +0,1 @@ | ||
export * from './menu.js'; | ||
export * from "./menu.js"; |
{ | ||
"name": "@grammyjs/menu", | ||
"description": "Interactive menus for grammY", | ||
"version": "1.0.1", | ||
"version": "1.0.2", | ||
"author": "KnorpelSenf", | ||
@@ -6,0 +6,0 @@ "license": "MIT", |
51012
1254