{"id":31376512,"url":"https://github.com/substrate-system/signs","last_synced_at":"2026-01-20T17:01:16.449Z","repository":{"id":300654014,"uuid":"1005925690","full_name":"substrate-system/signs","owner":"substrate-system","description":"Smaller, simpler signals","archived":false,"fork":false,"pushed_at":"2025-09-23T04:26:20.000Z","size":106,"stargazers_count":0,"open_issues_count":4,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-23T07:57:33.994Z","etag":null,"topics":["signals"],"latest_commit_sha":null,"homepage":"https://substrate-system.github.io/signs/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/substrate-system.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-21T05:19:13.000Z","updated_at":"2025-09-23T04:26:23.000Z","dependencies_parsed_at":"2025-06-22T23:24:55.086Z","dependency_job_id":"5620554b-0b35-4493-93f5-c580956842ab","html_url":"https://github.com/substrate-system/signs","commit_stats":null,"previous_names":["substrate-system/signs"],"tags_count":6,"template":false,"template_full_name":"nichoth/template-ts","purl":"pkg:github/substrate-system/signs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/substrate-system%2Fsigns","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/substrate-system%2Fsigns/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/substrate-system%2Fsigns/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/substrate-system%2Fsigns/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/substrate-system","download_url":"https://codeload.github.com/substrate-system/signs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/substrate-system%2Fsigns/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28607624,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-20T16:10:39.856Z","status":"ssl_error","status_checked_at":"2026-01-20T16:10:39.493Z","response_time":117,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["signals"],"created_at":"2025-09-28T03:53:33.434Z","updated_at":"2026-01-20T17:01:16.414Z","avatar_url":"https://github.com/substrate-system.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# signs\n[![tests](https://img.shields.io/github/actions/workflow/status/substrate-system/signs/nodejs.yml?style=flat-square)](https://github.com/substrate-system/signs/actions/workflows/nodejs.yml)\n[![types](https://img.shields.io/npm/types/@substrate-system/signs?style=flat-square)](README.md)\n[![module](https://img.shields.io/badge/module-ESM%2FCJS-blue?style=flat-square)](README.md)\n[![semantic versioning](https://img.shields.io/badge/semver-2.0.0-blue?logo=semver\u0026style=flat-square)](https://semver.org/)\n[![Common Changelog](https://nichoth.github.io/badge/common-changelog.svg)](./CHANGELOG.md)\n[![install size](https://flat.badgen.net/packagephobia/install/@substrate-system/signs?)](https://packagephobia.com/result?p=@substrate-system/signs)\n[![GZip size](https://flat.badgen.net/bundlephobia/minzip/@substrate-system/signs)](https://bundlephobia.com/package/@substrate-system/signs)\n[![dependencies](https://img.shields.io/badge/dependencies-zero-brightgreen.svg?style=flat-square)](package.json)\n\n\nA smaller, simpler [signals](https://github.com/tc39/proposal-signals).\n\nThis is not as magical or robust as other implementations, but it is very small.\nLook at [alien-signals](https://github.com/stackblitz/alien-signals) or\n[@preact/signals](https://github.com/preactjs/signals) if you need more\nmagic or functionality.\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch2\u003eContents\u003c/h2\u003e\u003c/summary\u003e\n\n\u003c!-- toc --\u003e\n\n- [Install](#install)\n- [Example](#example)\n- [API](#api)\n  * [`sign`](#sign)\n  * [`sign.peek`](#signpeek)\n  * [`effect`](#effect)\n  * [`computed`](#computed)\n  * [`batch`](#batch)\n- [Modules](#modules)\n  * [ESM](#esm)\n  * [Common JS](#common-js)\n  * [pre-built JS](#pre-built-js)\n- [Develop](#develop)\n  * [Example](#example-1)\n  * [Filesizes](#filesizes)\n  * [Test](#test)\n- [See also](#see-also)\n\n\u003c!-- tocstop --\u003e\n\n\u003c/details\u003e\n\n## Install\n\n```sh\nnpm i -S @substrate-system/signs\n```\n\n## Example\n\nCounting clicks.\n\nSee [the live demo of this](https://substrate-system.github.io/signs/).\n\nThis example is only 886 bytes after minifying and gzipping.\n\n```ts\nimport { effect, sign } from '@substrate-system/signs'\nconst qs = document.querySelector.bind(document)\n\nconst count = sign(0)\n\nqs('#root').innerHTML = `\n    \u003ch1 class=\"count\"\u003e${count.value}\u003c/h1\u003e\n    \u003cbutton class=\"plus\"\u003ePlus\u003c/button\u003e\n    \u003cbutton class=\"reset\"\u003eReset\u003c/button\u003e\n`\n\neffect(() =\u003e {\n    qs('h1').innerHTML = count.value\n})\n\nqs('button.reset').addEventListener('click', ev =\u003e {\n    ev.preventDefault()\n    count.value = 0\n})\n\nqs('button.plus').addEventListener('click', ev =\u003e {\n    ev.preventDefault()\n    count.value++\n})\n```\n\n## API\n\n### `sign`\n\nCreate a new `sign`.\n\n```ts\ntype Sign\u003cT\u003e = {\n    value:T\n    peek:()=\u003eT\n}\n\nfunction sign\u003cT\u003e (value:T, options?: SignOptions):Sign\u003cT\u003e\n```\n\n### `sign.peek`\n\nGet the sign's current value, but do not subscribe to that sign.\n\n```ts\ntype Sign\u003cT\u003e = {\n    value:T\n    peek:()=\u003eT\n}\n```\n\n#### `.peek` Example\n\n```js\nimport { sign, effect } from '@substrate-system/signs'\nconst delta = sign(0)\nconst count = sign(0)\n\neffect(() =\u003e {\n    // Update `count` without subscribing to `count`:\n    count.value = count.peek() + delta.value;\n})\n\n// rerun the effect\ndelta.value = 1\n\n// Do not rerun the effect,\n// b/c we used `.peek`, not `.value`\ncount.value = 10\n```\n\n### `effect`\n\nCall the subscriber function any time the sign's value changes.\n\n```ts\nfunction effect (fn:()=\u003eany):()=\u003evoid\n```\n\n### `computed`\n\nCreate a new sign that will update whenever the root sign changes.\n\n```ts\nfunction computed\u003cT\u003e (fn:()=\u003eT):Sign\u003cT\u003e\n```\n\n#### `computed` example\n\n```js\nimport { sign, computed } from '@substrate-system/signs'\n\nconst hello = sign('hello')\nconst derived = computed(() =\u003e {\n    return hello.value + ' world'\n})\n\nhello.value = 'goodbye'\n\nconsole.log('derived value', derived.value)\n// =\u003e 'goodbye world'\n```\n\n### `batch`\n\nCombine multiple signal writes into one single update that is triggered\nwhen the callback completes.\n\n```ts\nfunction batch\u003cT\u003e (fn:()=\u003eT):T\n```\n\n#### `batch` Example\n\n```js\nimport { sign, computed, effect, batch } from '@substrate-system/signs'\n\nconst name = sign('Jane')\nconst surname = sign('Doe')\nconst fullName = computed(() =\u003e name.value + ' ' + surname.value)\n\n// Will be called initially and once after the batch completes\neffect(() =\u003e console.log(fullName.value))\n// =\u003e Jane Doe\n// =\u003e Foo Bar\n\n// Combines both signal writes into one update.\nbatch(() =\u003e {\n    name.value = 'Foo'\n    surname.value = 'Bar'\n})\n```\n\n\n## Modules\n\nThis exposes ESM and common JS via [package.json `exports` field](https://nodejs.org/api/packages.html#exports).\n\n### ESM\n```ts\nimport { sign, effect, computed, batch, CycleError } from '@substrate-system/signs'\n```\n\n### Common JS\n```js\nconst { sign, effect, computed, batch, CycleError } = require('@substrate-system/signs')\n```\n\n### pre-built JS\nThis package exposes minified JS files too. Copy them to a location that is\naccessible to your web server, then link to them in HTML.\n\n#### copy\n```sh\ncp ./node_modules/@substrate-system/signs/dist/index.min.js ./public/signs.min.js\n```\n\n#### HTML\n```html\n\u003cscript type=\"module\" src=\"/signs.min.js\"\u003e\u003c/script\u003e\n```\n\n## Develop\n\n### Example\n\nStart a localhost server of the `example` directory:\n\n```sh\nnpm start\n```\n\n### Filesizes\n\nA convenient script that will tell you the filesize of the example app:\n\n```sh\nnpm run size\n```\n\n### Test\n\n```sh\nnpm test | npx tap-spec\n```\n\n## See also\n\n* [alien-signals](https://github.com/stackblitz/alien-signals)\n* [Ryan K Carniato - Revolutionary Signals](https://youtu.be/Jp7QBjY5K34)\n* [Learn Why JavaScript Frameworks Love Signals By Implementing Them](https://youtu.be/1TSLEzNzGQM)\n* [preactjs.com -- Signals](https://preactjs.com/guide/v10/signals/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsubstrate-system%2Fsigns","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsubstrate-system%2Fsigns","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsubstrate-system%2Fsigns/lists"}