{"id":20513818,"url":"https://github.com/webreflection/proxy-pants","last_synced_at":"2025-09-12T23:30:57.418Z","repository":{"id":43933934,"uuid":"436406723","full_name":"WebReflection/proxy-pants","owner":"WebReflection","description":"Secured and reliable Proxy based utilities for more or less common tasks.","archived":false,"fork":false,"pushed_at":"2023-10-18T13:58:28.000Z","size":241,"stargazers_count":114,"open_issues_count":0,"forks_count":3,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-07-25T00:34:46.609Z","etag":null,"topics":["proxy","security","utilities","utility"],"latest_commit_sha":null,"homepage":"https://javascript.plainenglish.io/about-trusting-javascript-execution-8c6b478d6021","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/WebReflection.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2021-12-08T22:11:15.000Z","updated_at":"2025-04-05T09:43:44.000Z","dependencies_parsed_at":"2023-02-19T06:40:27.128Z","dependency_job_id":"cb785c5e-c754-403a-a96e-89f7ab5a30c3","html_url":"https://github.com/WebReflection/proxy-pants","commit_stats":null,"previous_names":[],"tags_count":37,"template":false,"template_full_name":null,"purl":"pkg:github/WebReflection/proxy-pants","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WebReflection%2Fproxy-pants","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WebReflection%2Fproxy-pants/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WebReflection%2Fproxy-pants/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WebReflection%2Fproxy-pants/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/WebReflection","download_url":"https://codeload.github.com/WebReflection/proxy-pants/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WebReflection%2Fproxy-pants/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274893250,"owners_count":25369278,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-12T02:00:09.324Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["proxy","security","utilities","utility"],"created_at":"2024-11-15T21:13:21.142Z","updated_at":"2025-09-12T23:30:57.152Z","avatar_url":"https://github.com/WebReflection.png","language":"JavaScript","readme":"# proxy-pants\n\n[![build status](https://github.com/WebReflection/proxy-pants/actions/workflows/node.js.yml/badge.svg)](https://github.com/WebReflection/proxy-pants/actions) [![Coverage Status](https://coveralls.io/repos/github/WebReflection/proxy-pants/badge.svg?branch=main)](https://coveralls.io/github/WebReflection/proxy-pants?branch=main) [![CSP strict](https://webreflection.github.io/csp/strict.svg)](https://webreflection.github.io/csp/#-csp-strict)\n\n\u003csup\u003e**Social Media Photo by [lan deng](https://unsplash.com/@landall) on [Unsplash](https://unsplash.com/)**\u003c/sup\u003e\n\nSecured and reliable Proxy based utilities for more or less common tasks:\n\n  * **[accessor](#accessor)** to trap one or more accessors for any object\n  * **[applier \u0026 caller](#applier--caller)** to trap any borrowed callback/utility without needing to use `.call` or `.apply` to pass the context\n  * **[bound](#bound)** to bind one or more methods all at once\n  * **[bread \u0026 crumbs](#bread--crumbs)** to track operations through paths (i.e. `a.b.c.d`) and namespaces\n  * **[cache](#cache)** to compute once any accessed property through a proxied, and secured, map\n  * **[chain](#chain)** to trap once all inherited descriptors down the prototypal chain and automatically ensure the right accessor or method\n  * **[dsm](#dsm)** to virtually trap `dataset` / `*set` accessors as *DOMStringMap* like references per each element. Please note this utility is not secured\n  * **[extender](#extender)** to extend any object through weakly referenced behaviors, providing a new way to deal with state machines too, through the following features:\n    * **methods** are always the same bound reference\n    * **properties** are defined per extender and never directly attached to the source\n    * **accessors** are also defined per each extender\n    * multiple extenders calls to the same source preserve previous state, and any source can pass through multiple extenders without ever conflicting\n  * **[fetch](#fetch)** to shortcut `fetch(url).json` and other methods as direct accessors, defaulting to `void` when the response is not *ok*\n  * **[own](#own)** to destructure only own properties\n  * **[secure](#secure)** to ensure local classes cannot be patched at runtime down their prototypal chain\n  * **[watcher](#watcher)** the good old [Object.prototype.watch](https://cgi.cse.unsw.edu.au/~cs2041/doc/MDN_javascript_reference/Web/JavaScript/Reference/Global_Objects/Object/watch.html) and [unwatch](https://cgi.cse.unsw.edu.au/~cs2041/doc/MDN_javascript_reference/Web/JavaScript/Reference/Global_Objects/Object/unwatch.html) methods to simplify selective reactive state handling\n  * **[weak-cache](#weak-cache)** same as [cache](#cache) but the returned reference is weakly retained\n  * **[weak-proxy](#weak-proxy)** same as *Proxy* but it's register to the finalization registry so that if the `handler` contains a `collected(target)` callback, that will be invoked once the proxy reference is gone\n\n\n### accessor\n\nTrap one or more accessors for any object.\n\n```js\n// import {accessor} from 'proxy-pants/accessor';\nimport {accessor} from 'proxy-pants';\n\nconst {textContent} = accessor(document.body);\n\n// get the current body text\ntextContent();\n\n// set the new one\ntextContent('proxy pants!');\n```\n\n\n\n### applier \u0026 caller\n\nTrap any borrowed callback/utility without needing to use `.call` or `.apply` to pass the context.\n\n```js\n// import {applier, caller} from 'proxy-pants/function';\nimport {applier, caller} from 'proxy-pants';\n\nconst {hasOwnProperty, toString} = caller(Object.prototype);\n\n// true\nhasOwnProperty({any: 'object'}, 'any');\n\n// [object Null]\ntoString(null);\n\nconst {fromCharCode} = applier(String);\n\nconst charCodes = (...args) =\u003e fromCharCode(null, args);\n// \u003c=\u003e\ncharCodes(60, 61, 62);\n```\n\n\n\n### bound\n\nBind one or more methods all at once.\n\n```js\n// import {bound} from 'proxy-pants/bound';\nimport {bound} from 'proxy-pants';\n\nconst map = new Map;\nconst {get, set, has} = bound(map);\n\n// false\nhas('some');\n\n// the map\nset('some', 'value');\n\n// true\nhas('some');\n\n// 'value'\nget('some');\n```\n\n\n\n### bread \u0026 crumbs\n\nTrack operations through paths (i.e. `a.b.c.d`) and namespaces.\n\n```js\n// import {bread, crumbs} from 'proxy-pants/breadcrumbs';\nimport {bread, crumbs} from 'proxy-pants';\n\nconst namespace = {\n  some: 'value',\n  method(...args) {\n    return this.some + args.length;\n  },\n  Class: class {}\n};\n\nconst facade = crumbs({\n  apply(path, args) {\n    return bread(namespace, path)(...args);\n  },\n  construct(path, args) {\n    const Class = bread(namespace, path);\n    return new Class;\n  },\n  get(path, key) {\n    return bread(namespace, path)[key];\n  },\n  has(path, key) {\n    return key in bread(namespace, path);\n  },\n  set(path, key, value) {\n    bread(namespace, path)[key] = value;\n    return true;\n  },\n  // alias for deleteProperty(path, key) {}\n  delete(path, key) {\n    return delete bread(namespace, path)[key];\n  }\n});\n\nfacade.some;            // value\nfacade.method(1, 2, 3); // some3\nnew facade.Class;       // [object Namespace]\n'some' in facade;       // true\nfacade.test = 'ok';\nfacade.test;            // ok\ndelete facade.test;     // true\n```\n\n\n\n### cache\n\nA secured `Map` wrapper to retrieve any *property* once, through the given callback.\n\n```js\n// import {cache} from 'proxy-pants/cache';\nimport {cache} from 'proxy-pants';\n\nconst uids = cache((name) =\u003e (name + Math.random()));\n\nuids.a;             // \"a0.23456787654\"\nuids.b;             // \"b0.87654334567\"\nuids.a === uids.a;  // true\n'a' in uids;        // true\ndelete uids.a;      // true\n'a' in uids;        // false\n```\n\n\n\n### chain\n\nTrap once all inherited descriptors down the prototypal chain and automatically ensure the right accessor or method.\n\n```js\n// import {chain} from 'proxy-pants/chain';\nimport {chain} from 'proxy-pants';\n\nconst asNode = chain(Node);\nconst asElement = chain(Element);\n\nasNode(document.createTextNode('accessor')).data;\nasElement(document.body).querySelector('method');\n```\n\n\n\n### dsm\n\nVirtually trap `dataset` / `*set` accessors as *DOMStringMap* like references per each element.\n\n```js\n// import {dsm} from 'proxy-pants/dsm';\nimport {dsm} from 'proxy-pants';\n\nconst {ngset: ng, vset: v} = dsm(element);\n\n// set ng-value attribute\nng.value = 123;\n\n// remove ng-some-thing attribute\ndelete ng.someThing;\n\n// logs v-if attribute, if any\nconsole.log(v.if);\n```\n\n\n\n### extender\n\nExtend any object through weakly referenced behaviors, providing a new way to deal with state machines too, through the following features:\n\n  * **methods** are always the same bound reference\n  * **properties** are defined per extender and never directly attached to the source\n  * **accessors** are also defined per each extender\n  * multiple extenders calls to the same source preserve previous state, and any source can pass through multiple extenders without ever conflicting\n\n```js\n// import {extender} from 'proxy-pants/extender';\nimport {extender} from 'proxy-pants';\n\nconst Magic = extender({\n  // properties are per extender and weakly related\n  isMagic: true,\n\n  // accessors context is the original source/target\n  get magic() {\n    // this === source\n    return Magic(this).isMagic;\n  },\n\n  // methods are always same bound method reference (except init)\n  hasMagic() {\n    // this === source\n    return $(this).magic;\n  },\n\n  // a special method that helps setting up any reference once\n  // bear in mind Magic(ref).init() won't be defined as own method\n  init() {\n    // this is implicitly invoked only the first time Magic(this) is used\n  }\n});\n\n// it can be simplified per module as ...\nconst $ = Magic;\n\nconst source = {};\nconst target = Magic(source);\n\ntarget.isMagic;         // true\ntarget.magic;           // true\ntarget.hasMagic();      // true\n\n// introspection\nMagic.extends(source);  // true\nMagic.extends(target);  // true\n```\n\n\n### fetch\n\nShortcut for `fetch(url).json` or any other *Response* method as direct accessor.\n\n```js\nimport {fetch} from 'proxy-pants';\n\nconst data = await fetch(restAIP).json!.data;\nconst text = await fetch(page).text || '';\n```\n\n\n### own\n\nDestructure only own properties.\n\n```js\n// import {own} from 'proxy-pants/own';\nimport {own} from 'proxy-pants';\n\nconst created = Object.create(\n  {inherited: true},\n  {prop: {value: true}}\n);\n\nconst {inherited, prop} = own(created);\n\nconsole.assert(!inherited);\nconsole.assert(prop);\n```\n\n\n\n### secure\n\nEnsure local classes cannot be patched at runtime down their prototypal chain.\n\n```js\n// import {secure} from 'proxy-pants/secure';\nimport {secure} from 'proxy-pants';\n\nconst {\n  Map,\n  WekMap\n} = secure(globalThis);\n\n// both instances now can be used without\n// possible issues down the prototypal chain\nconst map = new Map;\nconst wm = new WeakMap;\n```\n\n\n### watcher\n\nThe good old [Object.prototype.watch](https://cgi.cse.unsw.edu.au/~cs2041/doc/MDN_javascript_reference/Web/JavaScript/Reference/Global_Objects/Object/watch.html) and [unwatch](https://cgi.cse.unsw.edu.au/~cs2041/doc/MDN_javascript_reference/Web/JavaScript/Reference/Global_Objects/Object/unwatch.html) methods to simplify selective reactive state handling.\n\n```js\n\n// import {watcher} from 'proxy-pants/watcher';\nimport {watcher} from 'proxy-pants';\n\nconst watched = watcher({a: {b: 1}});\nwatched.watch('c', function (prop, oldVal, newVal) {\n  prop;     // 'c'\n  oldVal;   // undefined\n  newVal;   // 2\n  this.unwatch(prop); // this is the proxied target\n});\nwatched.c = 2;\n\nwatched.a.watch('b', console.log);\nwatched.a.b = 3;  // will log\n```\n\n\n\n### weak-cache\n\nA secured [WeakValue](https://github.com/WebReflection/weak-value#readme) wrapper to retrieve any *property* once, through the given callback, and reteain the result weakly.\n\n```js\n// import {wcache} from 'proxy-pants/wcache';\nimport {wcache} from 'proxy-pants';\n\n// the value has to be an object/reference\nconst uids = wcache((name) =\u003e new String((name + Math.random())));\n\nuids.a;             // new String(\"a0.23456787654\")\nuids.b;             // new String(\"b0.87654334567\")\nuids.a === uids.a;  // true\n'a' in uids;        // true\ndelete uids.a;      // true\n'a' in uids;        // false\n```\n\n### weak-proxy\n\nSame proxy constructor but with automatic registration that will invoke a `collected(target)` callback once that happens.\n\n```js\n// import {WeakProxy} from 'proxy-pants/weak-proxy';\nimport {WeakProxy} from 'proxy-pants';\n\nlet ref = new WeakProxy(globalThis, {\n  collected(ref) {\n    console.assert(ref === globalThis);\n  }\n});\n\n// whenever `ref` is collected\nref = null;\n// the assertion in the `collected` handler will be true\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebreflection%2Fproxy-pants","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwebreflection%2Fproxy-pants","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebreflection%2Fproxy-pants/lists"}