{"_id":"@bemedev/signals","_rev":"2-805a1bbad9eae4005999f9d054ab6c45","name":"@bemedev/signals","dist-tags":{"latest":"0.0.2"},"versions":{"0.0.1":{"name":"@bemedev/signals","version":"0.0.1","keywords":["signal","signals","deepsignals","alien-signals","alien-deepsignals"],"author":{"url":"https://bemedev.vercel.app","name":"chlbri","email":"bri_lvi@icloud.com"},"license":"MIT","_id":"@bemedev/signals@0.0.1","maintainers":[{"name":"bemedev","email":"bri_lvi@icloud.com"}],"contributors":[{"url":"https://bemedev.vercel.app","name":"chlbri","email":"bri_lvi@icloud.com"}],"homepage":"https://github.com/chlbri/signals#readme","bugs":{"url":"https://github.com/chlbri/signals/issues"},"dist":{"shasum":"830c9281179a44425a681df28be9930ae396e341","tarball":"https://registry.npmjs.org/@bemedev/signals/-/signals-0.0.1.tgz","fileCount":27,"integrity":"sha512-DvvD8CIx7bTVGhf2TCvOWfKKlScMN0n4xUBgFdNDf+uS8zfdVPy10/ijhTJi+RDOnK4mbAzf28W3OD6tTzCyLg==","signatures":[{"sig":"MEQCICd7dqoTLjHhy8qgwD+q7oOCxfyJQXguCf2swVxz1dMBAiAi17qfoMBdu7jKYy3WN0QQTF1aTBz1hQHZtqSTHId/cA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":240156},"main":"lib/index.js","type":"module","types":"lib/index.d.ts","module":"lib/index.js","engines":{"node":">=24"},"gitHead":"e8127c1ca48d916906f5509e6913f63f10e0fa68","scripts":{"ci":"CI_START=$(date +%s) && pnpm run config:off && pnpm run lint && pnpm run test && echo \"\n✅ CI takes $(($(date +%s) - CI_START))s\n\"","rm":"pnpx rimraf ./node_modules ./pnpm-lock.yaml","fmt":"oxfmt","p-q":"pretty-quick","lint":"pnpm run fmt && pnpm run lint:fix","size":"size-limit","test":"pnpm run test:coverage","_lint":"oxlint","build":"pnpm run rm:lib && pnpm run rolldown","rinit":"pnpm run rm && pnpm run config","config":"pnpm install","rm:lib":"pnpx rimraf ./lib","prepare":"husky","pretest":"pnpm run build && pnpm run size","test:ui":"vitest --ui","upgrade":"pnpm dlx @bemedev/upgrade-npm-package && pnpm run config:vitest","ci:admin":"pnpm run rm && pnpm run upgrade:fast && pnpm run ci","lint:fix":"oxlint --fix","posttest":"pnpm run fmt","rolldown":"rolldown -c","fmt:check":"oxfmt --check","rinit:off":"pnpm run rm && pnpm run config:off","test:only":"pnpm run test:coverage --no-coverage","test:type":"pnpm run test:coverage -c \"vitest.config.type.ts\" --no-coverage","config:off":"pnpm run config --offline","lint:watch":"onchange --await-write-finish 1500 -d 10000 -v \"**/*.ts\" -- pnpm run lint","test:watch":"vitest","build:watch":"onchange --await-write-finish 1500 -d 10000 -v \"**/*.ts\" -- pnpm run build","test:no-type":"pnpm run test:coverage -c \"vitest.config.notype.ts\" --no-coverage","upgrade:fast":"pnpm up --latest && pnpm run config:vitest","config:vitest":"pnpm add -D @vitest/coverage-v8@3.2.4 @vitest/ui@3.2.4 vitest@3.2.4","test:coverage":"vitest run","prepublishOnly":"","test:type:watch":"vitest -c \"vitest.config.type.ts\""},"_npmUser":{"name":"bemedev","email":"bri_lvi@icloud.com"},"repository":{"url":"git+https://github.com/chlbri/signals.git","type":"git"},"size-limit":[{"path":"lib/*.js","limit":"10 KB"},{"path":"lib/*.cjs","limit":"10 KB"}],"_npmVersion":"11.9.0","description":"Deep structural reactivity for plain objects / arrays / Sets built on top of alien-signals","directories":{},"_nodeVersion":"24.14.0","dependencies":{"alien-signals":"^3.1.2"},"_hasShrinkwrap":false,"devDependencies":{"glob":"^13.0.6","husky":"^9.1.7","oxfmt":"^0.42.0","tslib":"^2.8.1","oxlint":"^1.57.0","vitest":"^3.2.4","globals":"^17.4.0","onchange":"^7.1.0","prettier":"^3.8.1","rolldown":"1.0.0-rc.12","@vitest/ui":"3.2.4","size-limit":"^12.0.1","typescript":"^6.0.2","@types/node":"^25.5.0","@bemedev/fsf":"^1.0.1","pretty-quick":"^4.2.2","@size-limit/file":"^12.0.1","@vitest/coverage-v8":"^3.2.4","@bemedev/vitest-alias":"^0.0.3","@rollup/plugin-inject":"^5.0.5","@bemedev/vitest-exclude":"^0.1.1","@bemedev/rolldown-config":"^0.1.3","@bemedev/vitest-extended":"^1.5.3"},"_npmOperationalInternal":{"tmp":"tmp/signals_0.0.1_1774457555309_0.1478106814603406","host":"s3://npm-registry-packages-npm-production"}},"0.0.2":{"name":"@bemedev/signals","version":"0.0.2","description":"Deep structural reactivity for plain objects / arrays / Sets built on top of alien-signals","author":{"name":"chlbri","email":"bri_lvi@icloud.com","url":"https://bemedev.vercel.app"},"repository":{"type":"git","url":"git+https://github.com/chlbri/signals.git"},"license":"MIT","type":"module","main":"lib/index.js","types":"lib/index.d.ts","module":"lib/index.js","maintainers":[{"name":"bemedev","email":"bri_lvi@icloud.com"}],"contributors":[{"name":"chlbri","email":"bri_lvi@icloud.com","url":"https://bemedev.vercel.app"}],"keywords":["signal","signals","deepsignals","alien-signals","alien-deepsignals"],"engines":{"node":">=24"},"scripts":{"build":"pnpm run rm:lib && pnpm run rolldown","ci":"CI_START=$(date +%s) && pnpm run config:off && pnpm run lint && pnpm run test && echo \"\n✅ CI takes $(($(date +%s) - CI_START))s\n\"","ci:admin":"pnpm run rm && pnpm run upgrade:fast && pnpm run ci","config":"pnpm install","config:off":"pnpm run config --offline","config:vitest":"pnpm add -D @vitest/coverage-v8@3.2.4 @vitest/ui@3.2.4 vitest@3.2.4","_lint":"oxlint","lint:fix":"oxlint --fix","lint":"pnpm run fmt && pnpm run lint:fix","lint:watch":"onchange --await-write-finish 1500 -d 10000 -v \"**/*.ts\" -- pnpm run lint","build:watch":"onchange --await-write-finish 1500 -d 10000 -v \"**/*.ts\" -- pnpm run build","p-q":"pretty-quick","posttest":"pnpm run fmt","prepare":"husky","prepublishOnly":"","pretest":"pnpm run build && pnpm run size","fmt":"oxfmt","fmt:check":"oxfmt --check","rinit":"pnpm run rm && pnpm run config","rinit:off":"pnpm run rm && pnpm run config:off","rm":"pnpx rimraf ./node_modules ./pnpm-lock.yaml","rm:lib":"pnpx rimraf ./lib","rolldown":"rolldown -c","test:coverage":"vitest run","test":"pnpm run test:coverage","test:no-type":"pnpm run test:coverage -c \"vitest.config.notype.ts\" --no-coverage","test:only":"pnpm run test:coverage --no-coverage","test:type":"pnpm run test:coverage -c \"vitest.config.type.ts\" --no-coverage","test:type:watch":"vitest -c \"vitest.config.type.ts\"","test:ui":"vitest --ui","test:watch":"vitest","upgrade":"pnpm dlx @bemedev/upgrade-npm-package && pnpm run config:vitest","size":"size-limit","upgrade:fast":"pnpm up --latest && pnpm run config:vitest"},"size-limit":[{"path":"lib/*.js","limit":"10 KB"},{"path":"lib/*.cjs","limit":"10 KB"}],"dependencies":{"alien-signals":"^3.1.2"},"devDependencies":{"@bemedev/fsf":"^1.0.1","@bemedev/rolldown-config":"^0.4.2","@bemedev/vitest-alias":"^0.0.3","@bemedev/vitest-exclude":"^0.1.1","@bemedev/vitest-extended":"^1.5.3","@rollup/plugin-inject":"^5.0.5","@size-limit/file":"^12.0.1","@types/node":"^25.5.0","@vitest/coverage-v8":"^3.2.4","@vitest/ui":"3.2.4","glob":"^13.0.6","globals":"^17.4.0","husky":"^9.1.7","onchange":"^7.1.0","oxfmt":"^0.42.0","oxlint":"^1.57.0","prettier":"^3.8.1","pretty-quick":"^4.2.2","rolldown":"1.0.0-rc.12","size-limit":"^12.0.1","tslib":"^2.8.1","typescript":"^6.0.2","vitest":"^3.2.4"},"gitHead":"669dee70c21f064c2eaeac12fd1f345170f9672a","_id":"@bemedev/signals@0.0.2","bugs":{"url":"https://github.com/chlbri/signals/issues"},"homepage":"https://github.com/chlbri/signals#readme","_nodeVersion":"24.14.0","_npmVersion":"11.9.0","dist":{"integrity":"sha512-GZYXekr2Bj6QkV6FqHiROFO3mZY6hilJxMpm4xYYemHGCetNV41Ao3sqacvBxkcawiwXg6ujP3qAHw5wjsER0w==","shasum":"1500b2296c54d52496d11f3bf7b78c59a4cb9da3","tarball":"https://registry.npmjs.org/@bemedev/signals/-/signals-0.0.2.tgz","fileCount":27,"unpackedSize":240156,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIElpvh3ptoGQSZkDlbCoPdCvTPU1TQ9XISgKeLh60RN6AiEAoeZCaLOzD0lbfiw4jgTUXBIKQ0bzxD2zvJzM4DuMQYE="}]},"_npmUser":{"name":"bemedev","email":"bri_lvi@icloud.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/signals_0.0.2_1774498403302_0.7589828815063291"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-25T16:52:35.251Z","modified":"2026-03-26T04:13:23.611Z","0.0.1":"2026-03-25T16:52:35.568Z","0.0.2":"2026-03-26T04:13:23.497Z"},"bugs":{"url":"https://github.com/chlbri/signals/issues"},"author":{"name":"chlbri","email":"bri_lvi@icloud.com","url":"https://bemedev.vercel.app"},"license":"MIT","homepage":"https://github.com/chlbri/signals#readme","keywords":["signal","signals","deepsignals","alien-signals","alien-deepsignals"],"repository":{"type":"git","url":"git+https://github.com/chlbri/signals.git"},"description":"Deep structural reactivity for plain objects / arrays / Sets built on top of alien-signals","contributors":[{"name":"chlbri","email":"bri_lvi@icloud.com","url":"https://bemedev.vercel.app"}],"maintainers":[{"name":"bemedev","email":"bri_lvi@icloud.com"}],"readme":"# @bemedev/signals\n\nDeep structural reactivity for plain objects, arrays and Sets — built on\ntop of [alien-signals](https://www.npmjs.com/package/alien-signals),\n**without any frontend-framework dependency**.\n\nInspired by\n[`@ng-org/alien-deepsignals`](https://www.npmjs.com/package/@ng-org/alien-deepsignals).\nAll the core deep-reactivity logic is preserved.\n\n> **Credits** — original deep-signal implementation by\n> [Laurin Weger](https://www.npmjs.com/package/@ng-org/alien-deepsignals)\n> (Par le Peuple / NextGraph.org). Licensed under Apache-2.0 OR MIT.\n\n<br/>\n\n## Installation\n\n```bash\npnpm add @bemedev/signals\n# or\nnpm install @bemedev/signals\n# or\nyarn add @bemedev/signals\n```\n\n> Requires Node.js ≥ 24.\n\n<br/>\n\n## Quick start\n\n```ts\nimport {\n  deepSignal,\n  computed,\n  batch,\n  effect,\n  watch,\n} from '@bemedev/signals';\n\nconst state = deepSignal({\n  user: { firstName: 'Ada', lastName: 'Lovelace' },\n  scores: [10, 20, 30],\n});\n\n// Derived value — recomputes lazily\nconst fullName = computed(\n  () => `${state.user.firstName} ${state.user.lastName}`,\n);\nconsole.log(fullName()); // \"Ada Lovelace\"\n\n// Reactive side-effect\neffect(() =>\n  console.log(\n    'Score sum:',\n    state.scores.reduce((a, b) => a + b, 0),\n  ),\n);\n// → \"Score sum: 60\"\n\n// Batch multiple writes → effects/computed run only once\nbatch(() => {\n  state.user.firstName = 'Grace';\n  state.scores.push(40);\n});\n// → \"Score sum: 100\"\n\n// Watch deep mutations\nconst { stopListening } = watch(state, ({ patches, newValue }) => {\n  console.log('patches:', patches);\n  console.log('newValue:', newValue);\n});\n\nstate.user.lastName = 'Hopper'; // triggers watch callback\nstopListening(); // unsubscribe\n```\n\n<br/>\n\n## API\n\n### `deepSignal(value, options?)`\n\nWraps a plain object, array or `Set` in a deep-reactive proxy. Nested\nobjects/arrays/Sets are wrapped automatically.\n\n```ts\nconst state = deepSignal({ count: 0, tags: new Set(['ts']) });\nstate.count = 1; // reactive mutation\nstate.tags.add('js'); // reactive Set mutation\n```\n\n**Options** (`DeepSignalOptions`):\n\n| Option                           | Type                             | Description                                                                                   |\n| -------------------------------- | -------------------------------- | --------------------------------------------------------------------------------------------- |\n| `propGenerator`                  | `DeepSignalPropGenFn`            | Called when new objects attach; may return additional properties                              |\n| `syntheticIdPropertyName`        | `string`                         | Property name used as identifier inside `Set` patches                                         |\n| `readOnlyProps`                  | `string[]`                       | Properties that are read-only once attached                                                   |\n| `replaceProxiesInBranchOnChange` | `boolean`                        | Replace proxies on the path to a mutated property — required for identity checks (e.g. React) |\n| `subscriberFactories`            | `Set<ExternalSubscriberFactory>` | External `onGet`/`onSet` hooks                                                                |\n\n---\n\n### `watch(source, callback, options?)`\n\nHigh-level watcher that fires whenever the deep signal mutates.\n\n```ts\nconst { stopListening, registerCleanup } = watch(\n  state,\n  ({ patches, version, newValue }) => {\n    /* ... */\n  },\n  { immediate: false, once: false, triggerInstantly: false },\n);\n```\n\n**`WatchOptions`**:\n\n| Option             | Default | Description                                                                             |\n| ------------------ | ------- | --------------------------------------------------------------------------------------- |\n| `immediate`        | `false` | Fire callback immediately after `watch()` is called                                     |\n| `once`             | `false` | Auto-unsubscribe after first event                                                      |\n| `triggerInstantly` | `false` | Call callback synchronously on every property change instead of batching in a microtask |\n\n---\n\n### `computed(getter)`\n\nLazy derived signal — re-export from `alien-signals`.\n\n```ts\nconst double = computed(() => state.count * 2);\nconsole.log(double()); // reads the cached value or recomputes\n```\n\n---\n\n### `batch(fn)`\n\nDefers all downstream recomputations until `fn` returns.\n\n```ts\nbatch(() => {\n  state.a = 1;\n  state.b = 2;\n}); // effects/computed run once, not twice\n```\n\n---\n\n### `effect(fn)`\n\nRuns `fn` immediately and re-runs it whenever any signal read inside it\nchanges. Re-export from `alien-signals`.\n\n---\n\n### `getRaw(proxy)`\n\nUnwraps a deep-signal proxy and returns the underlying raw object.\n\n---\n\n### `isDeepSignal(value)`\n\nType guard — returns `true` if `value` is a deep-signal proxy created by\n`deepSignal()`.\n\n---\n\n### `shallow(value)`\n\nMarks an object so that it is **not** made deeply reactive when assigned\ninto a deep signal.\n\n```ts\nconst state = deepSignal({ config: shallow({ debug: true }) });\n// state.config is NOT a reactive proxy\n```\n\n---\n\n### `addWithId(set, item)`\n\nHelper to add an item to a `Set` that lives inside a deep signal, ensuring\nthe correct synthetic-id bookkeeping.\n\n---\n\n### `subscribeDeepMutations(rootId, callback, triggerInstantly?)`\n\nLow-level subscription API. Use `watch()` unless you need direct access to\nthe patch stream.\n\n<br/>\n\n## Types\n\n| Type                 | Description                                                 |\n| -------------------- | ----------------------------------------------------------- |\n| `DeepSignal<T>`      | A deeply reactive version of `T`                            |\n| `DeepPatch`          | A single structural change (`add` / `remove` with a `path`) |\n| `DeepPatchBatch`     | A versioned batch of `DeepPatch` entries                    |\n| `WatchPatchEvent<T>` | Payload received by a `watch` callback                      |\n| `DeepSignalOptions`  | Options for `deepSignal()`                                  |\n\n<br/>\n\n## Licence\n\nMIT\n\n## CHANGELOG\n\nRead [CHANGELOG.md](CHANGELOG.md) for more details about the changes.\n\n<br/>\n\n## Auteur\n\nchlbri (bri_lvi@icloud.com)\n\n[My github](https://github.com/chlbri?tab=repositories)\n\n[<svg width=\"98\" height=\"96\" xmlns=\"http://www.w3.org/2000/svg\"><path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z\" fill=\"#24292f\"/></svg>](https://github.com/chlbri?tab=repositories)\n\n<br/>\n\n## Liens\n\n- [Documentation](https://github.com/chlbri/new-package)\n","readmeFilename":"README.md"}