@xlsft/grammy-reactive 0.7.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +7 -0
- package/dist/jsx/index.d.ts +3 -0
- package/dist/jsx/index.d.ts.map +1 -0
- package/dist/jsx/index.js +2 -0
- package/dist/jsx/index.js.map +1 -0
- package/dist/jsx/jsx-dev-runtime.d.ts +2 -0
- package/dist/jsx/jsx-dev-runtime.d.ts.map +1 -0
- package/dist/jsx/jsx-dev-runtime.js +2 -0
- package/dist/jsx/jsx-dev-runtime.js.map +1 -0
- package/dist/jsx/jsx-runtime.d.ts +2 -0
- package/dist/jsx/jsx-runtime.d.ts.map +1 -0
- package/dist/jsx/jsx-runtime.js +2 -0
- package/dist/jsx/jsx-runtime.js.map +1 -0
- package/dist/jsx/runtime/jsx.d.ts +10 -0
- package/dist/jsx/runtime/jsx.d.ts.map +1 -0
- package/dist/jsx/runtime/jsx.errors.d.ts +4 -0
- package/dist/jsx/runtime/jsx.errors.d.ts.map +1 -0
- package/dist/jsx/runtime/jsx.errors.js +7 -0
- package/dist/jsx/runtime/jsx.errors.js.map +1 -0
- package/dist/jsx/runtime/jsx.js +209 -0
- package/dist/jsx/runtime/jsx.js.map +1 -0
- package/dist/jsx/runtime/jsx.runtime.d.ts +18 -0
- package/dist/jsx/runtime/jsx.runtime.d.ts.map +1 -0
- package/dist/jsx/runtime/jsx.runtime.js +3 -0
- package/dist/jsx/runtime/jsx.runtime.js.map +1 -0
- package/dist/lib/helpers/context.helper.d.ts +3 -0
- package/dist/lib/helpers/context.helper.d.ts.map +1 -0
- package/dist/lib/helpers/index.d.ts +2 -0
- package/dist/lib/helpers/index.d.ts.map +1 -0
- package/dist/lib/index.d.ts +12 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +45 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/jsx-runtime.d.ts +2 -0
- package/dist/lib/jsx-runtime.d.ts.map +1 -0
- package/dist/lib/plugin/index.d.ts +4 -0
- package/dist/lib/plugin/index.d.ts.map +1 -0
- package/dist/lib/plugin/index.js +40 -0
- package/dist/lib/plugin/index.js.map +1 -0
- package/dist/lib/render/components/Error.d.ts +26 -0
- package/dist/lib/render/components/Error.d.ts.map +1 -0
- package/dist/lib/render/components/Error.js +25 -0
- package/dist/lib/render/components/Error.js.map +1 -0
- package/dist/lib/render/message.render.d.ts +40 -0
- package/dist/lib/render/message.render.d.ts.map +1 -0
- package/dist/lib/render/message.render.js +60 -0
- package/dist/lib/render/message.render.js.map +1 -0
- package/dist/lib/render/node/fragmemt.render.d.ts +34 -0
- package/dist/lib/render/node/fragmemt.render.d.ts.map +1 -0
- package/dist/lib/render/node/fragmemt.render.js +56 -0
- package/dist/lib/render/node/fragmemt.render.js.map +1 -0
- package/dist/lib/render/node/intrinsic.render.d.ts +37 -0
- package/dist/lib/render/node/intrinsic.render.d.ts.map +1 -0
- package/dist/lib/render/node/intrinsic.render.js +167 -0
- package/dist/lib/render/node/intrinsic.render.js.map +1 -0
- package/dist/lib/render/node/plain.render.d.ts +27 -0
- package/dist/lib/render/node/plain.render.d.ts.map +1 -0
- package/dist/lib/render/node/plain.render.js +32 -0
- package/dist/lib/render/node/plain.render.js.map +1 -0
- package/dist/lib/render/tag.render.d.ts +24 -0
- package/dist/lib/render/tag.render.d.ts.map +1 -0
- package/dist/lib/render/tag.render.js +27 -0
- package/dist/lib/render/tag.render.js.map +1 -0
- package/dist/lib/state/create.state.d.ts +8 -0
- package/dist/lib/state/create.state.d.ts.map +1 -0
- package/dist/lib/state/create.state.js +61 -0
- package/dist/lib/state/create.state.js.map +1 -0
- package/dist/lib/state/events/onclick.event.d.ts +21 -0
- package/dist/lib/state/events/onclick.event.d.ts.map +1 -0
- package/dist/lib/state/events/onclick.event.js +36 -0
- package/dist/lib/state/events/onclick.event.js.map +1 -0
- package/dist/lib/state/hooks/callback.hooks.d.ts +2 -0
- package/dist/lib/state/hooks/callback.hooks.d.ts.map +1 -0
- package/dist/lib/state/hooks/create.d.ts +7 -0
- package/dist/lib/state/hooks/create.d.ts.map +1 -0
- package/dist/lib/state/hooks/create.hooks.d.ts +29 -0
- package/dist/lib/state/hooks/create.hooks.d.ts.map +1 -0
- package/dist/lib/state/hooks/create.hooks.js +38 -0
- package/dist/lib/state/hooks/create.hooks.js.map +1 -0
- package/dist/lib/state/hooks/effect.hooks.d.ts +5 -0
- package/dist/lib/state/hooks/effect.hooks.d.ts.map +1 -0
- package/dist/lib/state/hooks/get.hooks.d.ts +25 -0
- package/dist/lib/state/hooks/get.hooks.d.ts.map +1 -0
- package/dist/lib/state/hooks/get.hooks.js +33 -0
- package/dist/lib/state/hooks/get.hooks.js.map +1 -0
- package/dist/lib/state/hooks/index.d.ts +7 -0
- package/dist/lib/state/hooks/index.d.ts.map +1 -0
- package/dist/lib/state/hooks/memo.hooks.d.ts +2 -0
- package/dist/lib/state/hooks/memo.hooks.d.ts.map +1 -0
- package/dist/lib/state/hooks/reducer.hooks.d.ts +3 -0
- package/dist/lib/state/hooks/reducer.hooks.d.ts.map +1 -0
- package/dist/lib/state/hooks/ref.hooks.d.ts +4 -0
- package/dist/lib/state/hooks/ref.hooks.d.ts.map +1 -0
- package/dist/lib/state/hooks/reset.hooks.d.ts +16 -0
- package/dist/lib/state/hooks/reset.hooks.d.ts.map +1 -0
- package/dist/lib/state/hooks/reset.hooks.js +19 -0
- package/dist/lib/state/hooks/reset.hooks.js.map +1 -0
- package/dist/lib/state/hooks/set.hooks.d.ts +23 -0
- package/dist/lib/state/hooks/set.hooks.d.ts.map +1 -0
- package/dist/lib/state/hooks/set.hooks.js +28 -0
- package/dist/lib/state/hooks/set.hooks.js.map +1 -0
- package/dist/lib/state/hooks/state.hooks.d.ts +50 -0
- package/dist/lib/state/hooks/state.hooks.d.ts.map +1 -0
- package/dist/lib/state/lifecycle/error.state.d.ts +7 -0
- package/dist/lib/state/lifecycle/error.state.d.ts.map +1 -0
- package/dist/lib/state/lifecycle/error.state.js +55 -0
- package/dist/lib/state/lifecycle/error.state.js.map +1 -0
- package/dist/lib/state/lifecycle/mount.state.d.ts +10 -0
- package/dist/lib/state/lifecycle/mount.state.d.ts.map +1 -0
- package/dist/lib/state/lifecycle/mount.state.js +84 -0
- package/dist/lib/state/lifecycle/mount.state.js.map +1 -0
- package/dist/lib/state/lifecycle/rerender.state.d.ts +10 -0
- package/dist/lib/state/lifecycle/rerender.state.d.ts.map +1 -0
- package/dist/lib/state/lifecycle/rerender.state.js +86 -0
- package/dist/lib/state/lifecycle/rerender.state.js.map +1 -0
- package/dist/lib/state/lifecycle/unmount.state.d.ts +9 -0
- package/dist/lib/state/lifecycle/unmount.state.d.ts.map +1 -0
- package/dist/lib/state/lifecycle/unmount.state.js +33 -0
- package/dist/lib/state/lifecycle/unmount.state.js.map +1 -0
- package/dist/types/grammy.types.d.ts +29 -0
- package/dist/types/grammy.types.d.ts.map +1 -0
- package/dist/types/grammy.types.js +3 -0
- package/dist/types/grammy.types.js.map +1 -0
- package/dist/types/hooks.types.d.ts +27 -0
- package/dist/types/hooks.types.d.ts.map +1 -0
- package/dist/types/jsx.types.d.ts +240 -0
- package/dist/types/jsx.types.d.ts.map +1 -0
- package/dist/types/jsx.types.js +29 -0
- package/dist/types/jsx.types.js.map +1 -0
- package/dist/types/lib.types.d.ts +80 -0
- package/dist/types/lib.types.d.ts.map +1 -0
- package/dist/types/lib.types.js +1 -0
- package/dist/types/lib.types.js.map +1 -0
- package/dist/types/plugin.types.d.ts +81 -0
- package/dist/types/plugin.types.d.ts.map +1 -0
- package/dist/types/plugin.types.js +1 -0
- package/dist/types/plugin.types.js.map +1 -0
- package/dist/utils/generateUniqueId.d.ts +29 -0
- package/dist/utils/generateUniqueId.d.ts.map +1 -0
- package/dist/utils/generateUniqueId.js +41 -0
- package/dist/utils/generateUniqueId.js.map +1 -0
- package/dist/utils/getEmoji.d.ts +26 -0
- package/dist/utils/getEmoji.d.ts.map +1 -0
- package/dist/utils/getEmoji.js +33 -0
- package/dist/utils/getEmoji.js.map +1 -0
- package/dist/utils/getPlainText.d.ts +23 -0
- package/dist/utils/getPlainText.d.ts.map +1 -0
- package/dist/utils/getPlainText.js +30 -0
- package/dist/utils/getPlainText.js.map +1 -0
- package/dist/utils/global.d.ts +13 -0
- package/dist/utils/global.d.ts.map +1 -0
- package/dist/utils/global.js +7 -0
- package/dist/utils/global.js.map +1 -0
- package/dist/utils/index.d.ts +9 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +10 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/isAbortError.d.ts +2 -0
- package/dist/utils/isAbortError.d.ts.map +1 -0
- package/dist/utils/isEmoji.d.ts +25 -0
- package/dist/utils/isEmoji.d.ts.map +1 -0
- package/dist/utils/isEmoji.js +27 -0
- package/dist/utils/isEmoji.js.map +1 -0
- package/dist/utils/isEqual.d.ts +42 -0
- package/dist/utils/isEqual.d.ts.map +1 -0
- package/dist/utils/isEqual.js +142 -0
- package/dist/utils/isEqual.js.map +1 -0
- package/dist/utils/isIntrinsicElement.d.ts +23 -0
- package/dist/utils/isIntrinsicElement.d.ts.map +1 -0
- package/dist/utils/isIntrinsicElement.js +25 -0
- package/dist/utils/isIntrinsicElement.js.map +1 -0
- package/dist/utils/isMessageNotFount.d.ts +2 -0
- package/dist/utils/isMessageNotFount.d.ts.map +1 -0
- package/dist/utils/isUnixTime.d.ts +32 -0
- package/dist/utils/isUnixTime.d.ts.map +1 -0
- package/dist/utils/isUnixTime.js +38 -0
- package/dist/utils/isUnixTime.js.map +1 -0
- package/dist/utils/sanitizeHtmlString.d.ts +24 -0
- package/dist/utils/sanitizeHtmlString.d.ts.map +1 -0
- package/dist/utils/sanitizeHtmlString.js +29 -0
- package/dist/utils/sanitizeHtmlString.js.map +1 -0
- package/dist/utils/withComponentScope.d.ts +2 -0
- package/dist/utils/withComponentScope.d.ts.map +1 -0
- package/dist/utils/withRuntime.d.ts +4 -0
- package/dist/utils/withRuntime.d.ts.map +1 -0
- package/package.json +62 -0
- package/readme.md +373 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type IntrinsicElements } from "~/types/jsx.types";
|
|
2
|
+
/**
|
|
3
|
+
* Checks whether a string is a valid intrinsic JSX element name.
|
|
4
|
+
*
|
|
5
|
+
* This utility acts as a runtime type guard for intrinsic JSX tags
|
|
6
|
+
* supported by the renderer.
|
|
7
|
+
*
|
|
8
|
+
* When the check succeeds, TypeScript narrows `name` to
|
|
9
|
+
* `keyof IntrinsicElements`, making it safe to use in intrinsic
|
|
10
|
+
* element factories, render dispatchers, and JSX runtime pipelines.
|
|
11
|
+
*
|
|
12
|
+
* @param {string} name - The element name to validate.
|
|
13
|
+
* @returns {name is keyof IntrinsicElements}
|
|
14
|
+
* `true` if the name is a supported intrinsic element.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* if (isIntrinsicElement(tag)) {
|
|
18
|
+
* // tag is narrowed to keyof IntrinsicElements
|
|
19
|
+
* createIntrinsicElement({ tag, props });
|
|
20
|
+
* }
|
|
21
|
+
*/
|
|
22
|
+
export declare function isIntrinsicElement(name: string): name is keyof IntrinsicElements;
|
|
23
|
+
//# sourceMappingURL=isIntrinsicElement.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isIntrinsicElement.d.ts","sourceRoot":"","sources":["../../src/utils/isIntrinsicElement.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE9E;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,IAAI,MAAM,iBAAiB,CAEhF"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { intrinsicElements } from "~/types/jsx.types";
|
|
2
|
+
/**
|
|
3
|
+
* Checks whether a string is a valid intrinsic JSX element name.
|
|
4
|
+
*
|
|
5
|
+
* This utility acts as a runtime type guard for intrinsic JSX tags
|
|
6
|
+
* supported by the renderer.
|
|
7
|
+
*
|
|
8
|
+
* When the check succeeds, TypeScript narrows `name` to
|
|
9
|
+
* `keyof IntrinsicElements`, making it safe to use in intrinsic
|
|
10
|
+
* element factories, render dispatchers, and JSX runtime pipelines.
|
|
11
|
+
*
|
|
12
|
+
* @param {string} name - The element name to validate.
|
|
13
|
+
* @returns {name is keyof IntrinsicElements}
|
|
14
|
+
* `true` if the name is a supported intrinsic element.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* if (isIntrinsicElement(tag)) {
|
|
18
|
+
* // tag is narrowed to keyof IntrinsicElements
|
|
19
|
+
* createIntrinsicElement({ tag, props });
|
|
20
|
+
* }
|
|
21
|
+
*/
|
|
22
|
+
export function isIntrinsicElement(name) {
|
|
23
|
+
return name in intrinsicElements;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=isIntrinsicElement.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isIntrinsicElement.js","sourceRoot":"","sources":["../../src/utils/isIntrinsicElement.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAA0B,MAAM,mBAAmB,CAAC;AAE9E;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC3C,OAAO,IAAI,IAAI,iBAAiB,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isMessageNotFount.d.ts","sourceRoot":"","sources":["../../src/utils/isMessageNotFount.ts"],"names":[],"mappings":"AAEA,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAQzD"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks whether a numeric value is a valid Unix timestamp.
|
|
3
|
+
*
|
|
4
|
+
* Supports both:
|
|
5
|
+
* - Unix time in **seconds**
|
|
6
|
+
* - Unix time in **milliseconds**
|
|
7
|
+
*
|
|
8
|
+
* Millisecond timestamps are automatically normalized to seconds
|
|
9
|
+
* before range validation.
|
|
10
|
+
*
|
|
11
|
+
* @remarks
|
|
12
|
+
* The accepted range is:
|
|
13
|
+
* - minimum: Unix epoch (`0`)
|
|
14
|
+
* - maximum: year `3000-01-01T00:00:00Z`
|
|
15
|
+
*
|
|
16
|
+
* @param {number} time - The timestamp value to validate.
|
|
17
|
+
* @returns {boolean} `true` if the value is a finite valid Unix timestamp.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* isUnixTime(1712745600); // true
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* isUnixTime(1712745600000); // true
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* isUnixTime(NaN); // false
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* isUnixTime(-1); // false
|
|
30
|
+
*/
|
|
31
|
+
export declare function isUnixTime(time: number): boolean;
|
|
32
|
+
//# sourceMappingURL=isUnixTime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isUnixTime.d.ts","sourceRoot":"","sources":["../../src/utils/isUnixTime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAKhD"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks whether a numeric value is a valid Unix timestamp.
|
|
3
|
+
*
|
|
4
|
+
* Supports both:
|
|
5
|
+
* - Unix time in **seconds**
|
|
6
|
+
* - Unix time in **milliseconds**
|
|
7
|
+
*
|
|
8
|
+
* Millisecond timestamps are automatically normalized to seconds
|
|
9
|
+
* before range validation.
|
|
10
|
+
*
|
|
11
|
+
* @remarks
|
|
12
|
+
* The accepted range is:
|
|
13
|
+
* - minimum: Unix epoch (`0`)
|
|
14
|
+
* - maximum: year `3000-01-01T00:00:00Z`
|
|
15
|
+
*
|
|
16
|
+
* @param {number} time - The timestamp value to validate.
|
|
17
|
+
* @returns {boolean} `true` if the value is a finite valid Unix timestamp.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* isUnixTime(1712745600); // true
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* isUnixTime(1712745600000); // true
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* isUnixTime(NaN); // false
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* isUnixTime(-1); // false
|
|
30
|
+
*/
|
|
31
|
+
export function isUnixTime(time) {
|
|
32
|
+
if (typeof time !== "number" || !Number.isFinite(time))
|
|
33
|
+
return false;
|
|
34
|
+
const min = 0, max = 32503680000;
|
|
35
|
+
const t = time > 1e12 ? Math.floor(time / 1000) : time;
|
|
36
|
+
return t >= min && t <= max;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=isUnixTime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isUnixTime.js","sourceRoot":"","sources":["../../src/utils/isUnixTime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY;IACnC,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACrE,MAAM,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,WAAW,CAAC;IACjC,MAAM,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACvD,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,CAAC;AAChC,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Escapes unsafe characters in a string for safe HTML rendering.
|
|
3
|
+
*
|
|
4
|
+
* This utility replaces the core HTML-sensitive characters:
|
|
5
|
+
* - `&` → `&`
|
|
6
|
+
* - `<` → `<`
|
|
7
|
+
* - `>` → `>`
|
|
8
|
+
*
|
|
9
|
+
* It is primarily used during the final message serialization phase
|
|
10
|
+
* to ensure that plain text content cannot break Telegram HTML markup.
|
|
11
|
+
*
|
|
12
|
+
* @param {string} unsafe - The raw string to sanitize.
|
|
13
|
+
* @returns {string} The escaped HTML-safe string.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* sanitizeHtmlString("<b>Hello</b>");
|
|
17
|
+
* // "<b>Hello</b>"
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* sanitizeHtmlString("Tom & Jerry");
|
|
21
|
+
* // "Tom & Jerry"
|
|
22
|
+
*/
|
|
23
|
+
export declare function sanitizeHtmlString(unsafe: string): string;
|
|
24
|
+
//# sourceMappingURL=sanitizeHtmlString.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitizeHtmlString.d.ts","sourceRoot":"","sources":["../../src/utils/sanitizeHtmlString.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAKzD"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Escapes unsafe characters in a string for safe HTML rendering.
|
|
3
|
+
*
|
|
4
|
+
* This utility replaces the core HTML-sensitive characters:
|
|
5
|
+
* - `&` → `&`
|
|
6
|
+
* - `<` → `<`
|
|
7
|
+
* - `>` → `>`
|
|
8
|
+
*
|
|
9
|
+
* It is primarily used during the final message serialization phase
|
|
10
|
+
* to ensure that plain text content cannot break Telegram HTML markup.
|
|
11
|
+
*
|
|
12
|
+
* @param {string} unsafe - The raw string to sanitize.
|
|
13
|
+
* @returns {string} The escaped HTML-safe string.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* sanitizeHtmlString("<b>Hello</b>");
|
|
17
|
+
* // "<b>Hello</b>"
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* sanitizeHtmlString("Tom & Jerry");
|
|
21
|
+
* // "Tom & Jerry"
|
|
22
|
+
*/
|
|
23
|
+
export function sanitizeHtmlString(unsafe) {
|
|
24
|
+
return unsafe
|
|
25
|
+
.replaceAll("&", "&")
|
|
26
|
+
.replaceAll("<", "<")
|
|
27
|
+
.replaceAll(">", ">");
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=sanitizeHtmlString.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitizeHtmlString.js","sourceRoot":"","sources":["../../src/utils/sanitizeHtmlString.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC7C,OAAO,MAAM;SACR,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC;SACxB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC;SACvB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withComponentScope.d.ts","sourceRoot":"","sources":["../../src/utils/withComponentScope.ts"],"names":[],"mappings":"AAEA,wBAAsB,kBAAkB,CAAC,CAAC,EACtC,QAAQ,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAC3B,OAAO,CAAC,CAAC,CAAC,CAyBZ"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { HookRuntime } from "~/types/hooks.types";
|
|
2
|
+
import type { ReactiveContext } from "~/types/plugin.types";
|
|
3
|
+
export declare function withRuntime<C extends ReactiveContext>(runtime: HookRuntime, callback: () => Promise<void>): Promise<void>;
|
|
4
|
+
//# sourceMappingURL=withRuntime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withRuntime.d.ts","sourceRoot":"","sources":["../../src/utils/withRuntime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAG5D,wBAAgB,WAAW,CAAC,CAAC,SAAS,eAAe,EACjD,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,iBAkBhC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "module",
|
|
3
|
+
"name": "@xlsft/grammy-reactive",
|
|
4
|
+
"description": "React-like stateful library for grammY",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"version": "0.7.34",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=14.17.0"
|
|
9
|
+
},
|
|
10
|
+
"author": "xlsft",
|
|
11
|
+
"homepage": "https://cv.xlsft.ru/en/projects/grammy-reactive",
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/xlsft/grammy-reactive.git"
|
|
15
|
+
},
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/xlsft/grammy-reactive/issues"
|
|
18
|
+
},
|
|
19
|
+
"module": "true",
|
|
20
|
+
"main": "./dist/lib/index.js",
|
|
21
|
+
"types": "./dist/lib/index.d.ts",
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./dist/lib/index.d.ts",
|
|
25
|
+
"import": "./dist/lib/index.js"
|
|
26
|
+
},
|
|
27
|
+
"./jsx": {
|
|
28
|
+
"types": "./dist/jsx/index.d.ts",
|
|
29
|
+
"import": "./dist/jsx/index.js"
|
|
30
|
+
},
|
|
31
|
+
"./jsx/jsx-runtime": {
|
|
32
|
+
"types": "./dist/jsx/jsx-runtime.d.ts",
|
|
33
|
+
"import": "./dist/jsx/jsx-runtime.js"
|
|
34
|
+
},
|
|
35
|
+
"./jsx/jsx-dev-runtime": {
|
|
36
|
+
"types": "./dist/jsx/jsx-dev-runtime.d.ts",
|
|
37
|
+
"import": "./dist/jsx/jsx-dev-runtime.js"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"files": [
|
|
41
|
+
"dist"
|
|
42
|
+
],
|
|
43
|
+
"scripts": {
|
|
44
|
+
"dev": "bun run --watch examples/main.tsx",
|
|
45
|
+
"build": "tsc -p tsconfig.build.json",
|
|
46
|
+
"publish": "npm publish --access public"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/node": "^25.6.0",
|
|
50
|
+
"typescript": "^5"
|
|
51
|
+
},
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"grammy": ">=1.0.0 <2"
|
|
54
|
+
},
|
|
55
|
+
"keywords": [
|
|
56
|
+
"declarative",
|
|
57
|
+
"library",
|
|
58
|
+
"jsx",
|
|
59
|
+
"grammy",
|
|
60
|
+
"bot"
|
|
61
|
+
]
|
|
62
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
# @xlsft/grammy-reactive
|
|
2
|
+
|
|
3
|
+
> React-like stateful library for **grammY** with JSX, hooks, lifecycle, effects, and component error boundaries.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# ✨ Features
|
|
8
|
+
|
|
9
|
+
- ⚛️ JSX component system
|
|
10
|
+
- 🪝 React-like hooks API
|
|
11
|
+
- 🔁 Stateful rerendering
|
|
12
|
+
- 🧠 Persistent component-local hook storage
|
|
13
|
+
- 🧹 `useEffect` with cleanup support
|
|
14
|
+
- 💥 Error boundaries for root + nested components
|
|
15
|
+
- ⛔ Abortable rerenders via `AbortController`
|
|
16
|
+
- 🧩 Async component support
|
|
17
|
+
- 📦 Component path–scoped state isolation
|
|
18
|
+
- 🤖 Deep access to `grammY` context via runtime hooks
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
# 🚀 Quick Start
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Bun
|
|
28
|
+
bun add @xlsft/grammy-reactive
|
|
29
|
+
|
|
30
|
+
# npm
|
|
31
|
+
npm install @xlsft/grammy-reactive
|
|
32
|
+
|
|
33
|
+
# pnpm
|
|
34
|
+
pnpm add @xlsft/grammy-reactive
|
|
35
|
+
|
|
36
|
+
# yarn
|
|
37
|
+
yarn add @xlsft/grammy-reactive
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Add JSX runtime to `tsconfig.json`
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"compilerOptions": {
|
|
45
|
+
"jsxImportSource": "@xlsft/grammy-reactive/jsx",
|
|
46
|
+
"jsx": "react-jsx",
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Basic Message Component
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
import { Bot, Context } from "grammy";
|
|
58
|
+
import { defineMessageHandler, useState, reactive, type ReactiveFlavor } from "@xlsft/grammy-reactive";
|
|
59
|
+
|
|
60
|
+
const bot = new Bot<ReactiveFlavor<Context>>(process.env.TG_TOKEN!);
|
|
61
|
+
bot.use(reactive());
|
|
62
|
+
|
|
63
|
+
const startHandler = defineMessageHandler(async () => {
|
|
64
|
+
const [count, setCount] = useState(0);
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<>
|
|
68
|
+
<h>Counter</h>
|
|
69
|
+
<blockquote>
|
|
70
|
+
Value: <b>{count}</b>
|
|
71
|
+
</blockquote>
|
|
72
|
+
<button onClick={() => setCount(c => c + 1)}>
|
|
73
|
+
Increment
|
|
74
|
+
</button>
|
|
75
|
+
</>
|
|
76
|
+
);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
bot.command("start", startHandler);
|
|
80
|
+
```
|
|
81
|
+
---
|
|
82
|
+
# 📔 Full documentation
|
|
83
|
+
|
|
84
|
+
WIP
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
# 🧠 Core Mental Model
|
|
89
|
+
|
|
90
|
+
Every message handler creates a **persistent message runtime instance**.
|
|
91
|
+
|
|
92
|
+
This runtime stores:
|
|
93
|
+
|
|
94
|
+
- current Telegram message state
|
|
95
|
+
- hook values
|
|
96
|
+
- effect queue
|
|
97
|
+
- cleanup callbacks
|
|
98
|
+
- component tree path
|
|
99
|
+
- abort controller
|
|
100
|
+
- grammY context
|
|
101
|
+
|
|
102
|
+
Each rerender reuses the same runtime.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
# 🪝 Hooks API
|
|
107
|
+
|
|
108
|
+
The framework ships with a familiar React-like hooks layer:
|
|
109
|
+
|
|
110
|
+
- `useState` → local reactive state
|
|
111
|
+
- `useMemo` → memoized computed values
|
|
112
|
+
- `useCallback` → stable callback references
|
|
113
|
+
- `useReducer` → complex state transitions
|
|
114
|
+
- `useEffect` → post-commit side effects + cleanup
|
|
115
|
+
|
|
116
|
+
...etc
|
|
117
|
+
|
|
118
|
+
### All hooks are:
|
|
119
|
+
|
|
120
|
+
- component-path scoped
|
|
121
|
+
- persistent across rerenders
|
|
122
|
+
- safe inside async components
|
|
123
|
+
- automatically restored by render order
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
# 🔘 Inline Buttons
|
|
129
|
+
|
|
130
|
+
Inline buttons are a **first-class reactive UI primitive**.
|
|
131
|
+
|
|
132
|
+
They behave like component event handlers and automatically participate in the lifecycle runtime.
|
|
133
|
+
|
|
134
|
+
```tsx
|
|
135
|
+
<button color="primary" onClick={() => setCount(c => c + 1)}>
|
|
136
|
+
Increment
|
|
137
|
+
</button>
|
|
138
|
+
```
|
|
139
|
+
```tsx
|
|
140
|
+
<button variant="copy" value="Copy this text!">
|
|
141
|
+
Copy what text?
|
|
142
|
+
</button>
|
|
143
|
+
```
|
|
144
|
+
```tsx
|
|
145
|
+
<button variant="url" url="https://google.com">
|
|
146
|
+
Go to google
|
|
147
|
+
</button>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
# 🧩 Stateful Component Example
|
|
152
|
+
|
|
153
|
+
```tsx
|
|
154
|
+
import {
|
|
155
|
+
defineMessageHandler,
|
|
156
|
+
useEffect,
|
|
157
|
+
useState,
|
|
158
|
+
useContext,
|
|
159
|
+
} from "~/lib";
|
|
160
|
+
|
|
161
|
+
export default defineMessageHandler(async () => {
|
|
162
|
+
const [seconds, setSeconds] = useState(0);
|
|
163
|
+
const ctx = useContext();
|
|
164
|
+
|
|
165
|
+
useEffect(() => {
|
|
166
|
+
const interval = setInterval(() => {
|
|
167
|
+
setSeconds(s => s + 1);
|
|
168
|
+
}, 1000);
|
|
169
|
+
|
|
170
|
+
return () => clearInterval(interval);
|
|
171
|
+
}, []);
|
|
172
|
+
|
|
173
|
+
return <b>Running for {seconds}s</b>;
|
|
174
|
+
});
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
# 🔄 Lifecycle Model
|
|
180
|
+
|
|
181
|
+
The framework uses a **render → commit → effects** lifecycle.
|
|
182
|
+
|
|
183
|
+
```mermaid
|
|
184
|
+
flowchart TD
|
|
185
|
+
A[Handler / Event] --> B[Render JSX Tree]
|
|
186
|
+
B --> C[Commit to Telegram]
|
|
187
|
+
C --> D[Flush useEffect Queue]
|
|
188
|
+
D --> E[Wait for User Events]
|
|
189
|
+
E -->|setState| B
|
|
190
|
+
E -->|unmount| F[Run Cleanup]
|
|
191
|
+
F --> G[Delete Message]
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
# 🧠 Hook Storage Architecture
|
|
197
|
+
|
|
198
|
+
Hooks are stored by **component path key**.
|
|
199
|
+
|
|
200
|
+
```mermaid
|
|
201
|
+
flowchart LR
|
|
202
|
+
A[Runtime] --> B[hooks: Map]
|
|
203
|
+
B --> C[0]
|
|
204
|
+
B --> D[0.0]
|
|
205
|
+
B --> E[0.1]
|
|
206
|
+
C --> F[Parent hooks]
|
|
207
|
+
D --> G[Child A hooks]
|
|
208
|
+
E --> H[Child B hooks]
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
This guarantees:
|
|
212
|
+
|
|
213
|
+
- sibling isolation
|
|
214
|
+
- nested component stability
|
|
215
|
+
- deterministic hook ordering
|
|
216
|
+
- subtree-safe rerenders
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
# 🧬 State Management Principles
|
|
221
|
+
|
|
222
|
+
## 1) Component Path Isolation
|
|
223
|
+
Each component subtree owns its own hook array.
|
|
224
|
+
|
|
225
|
+
This prevents collisions between:
|
|
226
|
+
|
|
227
|
+
```tsx
|
|
228
|
+
<A />
|
|
229
|
+
<B />
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Both may safely use:
|
|
233
|
+
|
|
234
|
+
```tsx
|
|
235
|
+
useState()
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
without shared state.
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## 2) Functional Updates Preferred
|
|
243
|
+
Always prefer:
|
|
244
|
+
|
|
245
|
+
```tsx
|
|
246
|
+
setCount(prev => prev + 1)
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
over:
|
|
250
|
+
|
|
251
|
+
```tsx
|
|
252
|
+
setCount(count + 1)
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
This avoids stale closures in async effects.
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## 3) Effects Are Commit-Phase Only
|
|
260
|
+
`useEffect` runs **after successful Telegram message update**.
|
|
261
|
+
|
|
262
|
+
This guarantees UI consistency.
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
# 💥 Error Boundaries
|
|
267
|
+
|
|
268
|
+
The framework automatically catches:
|
|
269
|
+
|
|
270
|
+
- root handler exceptions
|
|
271
|
+
- nested component exceptions
|
|
272
|
+
- rerender errors
|
|
273
|
+
- effect cleanup errors
|
|
274
|
+
- event handler errors
|
|
275
|
+
|
|
276
|
+
Fallback UI renders `InternalError` safely.
|
|
277
|
+
|
|
278
|
+
```mermaid
|
|
279
|
+
flowchart TD
|
|
280
|
+
A[Render Component] --> B{Throws?}
|
|
281
|
+
B -->|No| C[Continue Render]
|
|
282
|
+
B -->|Yes| D[Render InternalError]
|
|
283
|
+
D --> E[Commit Fallback UI]
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
# ⛔ Abort + Rerender Semantics
|
|
289
|
+
|
|
290
|
+
Every message runtime owns its own `AbortController`.
|
|
291
|
+
|
|
292
|
+
Before rerender:
|
|
293
|
+
|
|
294
|
+
1. previous controller is aborted
|
|
295
|
+
2. new controller is created
|
|
296
|
+
3. stale async updates are cancelled
|
|
297
|
+
|
|
298
|
+
```mermaid
|
|
299
|
+
sequenceDiagram
|
|
300
|
+
participant U as User
|
|
301
|
+
participant R as Runtime
|
|
302
|
+
participant T as Telegram
|
|
303
|
+
|
|
304
|
+
U->>R: setState()
|
|
305
|
+
R->>R: abort previous controller
|
|
306
|
+
R->>R: render new tree
|
|
307
|
+
R->>T: editMessageText()
|
|
308
|
+
R->>R: flushEffects()
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
# 📐 Best Practices
|
|
314
|
+
|
|
315
|
+
## ✅ Prefer split effects
|
|
316
|
+
|
|
317
|
+
```tsx
|
|
318
|
+
useEffect(startInterval, []);
|
|
319
|
+
useEffect(syncReaction, [seconds]);
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
instead of mixing unrelated side effects.
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
## ✅ Use reducer for flows
|
|
327
|
+
Use `useReducer` for:
|
|
328
|
+
|
|
329
|
+
- wizards
|
|
330
|
+
- menus
|
|
331
|
+
- calculators
|
|
332
|
+
- async status machines
|
|
333
|
+
- pagination
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
## ✅ Memoize callbacks for child props
|
|
338
|
+
|
|
339
|
+
```tsx
|
|
340
|
+
const onSave = useCallback(() => save(id), [id]);
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
# 🏗️ Architecture Summary
|
|
346
|
+
|
|
347
|
+
```mermaid
|
|
348
|
+
flowchart TD
|
|
349
|
+
A[defineMessageHandler] --> B[createMessageState]
|
|
350
|
+
B --> C[withRuntime]
|
|
351
|
+
C --> D[createMessageRender]
|
|
352
|
+
D --> E[Telegram Commit]
|
|
353
|
+
E --> F[flushEffects]
|
|
354
|
+
F --> G[cleanupEffects on unmount]
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
# ❤️ Philosophy
|
|
360
|
+
|
|
361
|
+
The goal is simple:
|
|
362
|
+
|
|
363
|
+
> Bring **React-like declarative stateful UI architecture** into Telegram bots without losing grammY power.
|
|
364
|
+
|
|
365
|
+
This library treats a Telegram message as a **live reactive UI surface**.
|
|
366
|
+
|
|
367
|
+
State, effects, rerenders, and cleanup behave like a real component runtime.
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
# 📄 License
|
|
372
|
+
|
|
373
|
+
MIT
|