feat: track session changes via deep proxification
- 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.