grammyjs / grammyjs/session

feat: track session changes via deep proxification

Open
#3 2 comments 0 reactions 1 assignee Claimed by @roziscoding View on GitHub
Dominant language
TypeScript
Stars
2
Forks
0
PR merge metrics
No merged PRs in 30d

Description

> I suggest slightly reworking the session persistence condition. Currently, on any read, we write to persist the session, which produces unnecessary write operations. We can deeply proxy the session object to track mutations more precisely.
>
> This is just a raw example of proxying; it can be adjusted only for objects and arrays (JSON serializable) and with `if`'s for performance reasons.
> ```ts
> const mutated = Symbol("mutated");
>
> // for Set, Map, and Array
> const mutation_methods = new Set([
> "set",
> "add",
> "delete",
> "clear",
> "push",
> "pop",
> "shift",
> "unshift",
> "splice",
> "sort",
> "reverse",
> "fill",
> "copyWithin",
> ]);
>
> /**
> * Creates a proxy wrapper around an object to track mutations and handle cleanup
> * @param {any} object - The target object to proxify
> * @param {Function} [dispose] - Optional disposal function that runs during cleanup
> * @returns {Proxy} Proxied object that tracks mutations
> *
> * @example
> * const obj = { count: 0 };
> * const proxiedObj = proxify(obj, () => {
> * console.log('cleanup');
> * });
> */
> export function proxify(
> object: any,
> dispose?: () => Promise | void,
> ): T & { [Symbol.asyncDispose]: () => Promise; [mutated]: boolean } {
> object[Symbol.asyncDispose] = dispose;
> object[mutated] = false;
>
> const handler: ProxyHandler = {
> get(target, key: string) {
> if (typeof target[key] === "object" && target[key] !== null) {
> return new Proxy(target[key], handler);
> }
> if (typeof target[key] === "function") {
> return (...args: unknown[]) => {
> if (mutation_methods.has(key)) {
> object[mutated] = true;
> }
> return target[key](...args);
> };
> }
> return target[key];
> },
> set(target, prop: string, value) {
> object[mutated] = true;
> target[prop] = value;
> return true;
> },
> };
>
> return new Proxy(object, handler);
> }
>
> proxify.is_mutated = mutated;
> ```
>
> usage with `using`:
> ```ts
> async function app() {
> await using tracked_state = proxify(state, async () => {
> if (state[proxify.is_mutated]) {
> console.log("saving state");
> state[proxify.is_mutated] = false;
> await db.set(["state"], state);
> }
> });
>
>
> tracked_state.a = 1; // -> mutation
>
> } // -> save
> ```

_Originally posted by @shevernitskiy in [#712](https://github.com/grammyjs/grammY/issues/712#issuecomment-2629472714)_

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.