@tstdl/base 0.93.181 → 0.93.183

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (353) hide show
  1. package/api/server/api-request-token.provider.js +1 -1
  2. package/api/server/gateway.js +8 -3
  3. package/authentication/authentication.api.d.ts +13 -40
  4. package/authentication/authentication.api.js +5 -14
  5. package/authentication/client/authentication.service.d.ts +6 -14
  6. package/authentication/client/authentication.service.js +22 -4
  7. package/authentication/client/module.d.ts +1 -1
  8. package/authentication/client/module.js +4 -4
  9. package/authentication/models/index.d.ts +1 -0
  10. package/authentication/models/index.js +1 -0
  11. package/authentication/models/totp-results.model.d.ts +11 -0
  12. package/authentication/models/totp-results.model.js +37 -0
  13. package/authentication/server/authentication.api-controller.d.ts +3 -3
  14. package/authentication/server/authentication.api-controller.js +31 -4
  15. package/authentication/server/authentication.service.d.ts +5 -14
  16. package/authentication/server/authentication.service.js +6 -4
  17. package/core.d.ts +0 -5
  18. package/core.js +0 -8
  19. package/document-management/api/document-management.api.d.ts +2 -2
  20. package/document-management/service-models/document.service-model.d.ts +1 -1
  21. package/examples/config.d.ts +25 -0
  22. package/examples/config.js +26 -0
  23. package/notification/server/module.d.ts +1 -1
  24. package/notification/server/module.js +1 -1
  25. package/package.json +5 -5
  26. package/signals/api.d.ts +5 -1
  27. package/signals/api.js +3 -1
  28. package/signals/implementation/api.d.ts +13 -5
  29. package/signals/implementation/api.js +7 -1
  30. package/signals/implementation/asserts.d.ts +2 -2
  31. package/signals/implementation/asserts.js +3 -3
  32. package/signals/implementation/computed.d.ts +7 -34
  33. package/signals/implementation/computed.js +14 -83
  34. package/signals/implementation/configure.js +6 -2
  35. package/signals/implementation/effect.d.ts +65 -46
  36. package/signals/implementation/effect.js +97 -62
  37. package/signals/implementation/index.d.ts +2 -4
  38. package/signals/implementation/index.js +2 -4
  39. package/signals/implementation/linked_signal.d.ts +36 -0
  40. package/signals/implementation/linked_signal.js +34 -0
  41. package/signals/implementation/primitive/computed.d.ts +55 -0
  42. package/signals/implementation/primitive/computed.js +107 -0
  43. package/signals/implementation/primitive/effect.d.ts +26 -0
  44. package/signals/implementation/primitive/effect.js +31 -0
  45. package/signals/implementation/{equality.d.ts → primitive/equality.d.ts} +1 -1
  46. package/signals/implementation/{equality.js → primitive/equality.js} +1 -1
  47. package/signals/implementation/primitive/errors.d.ts +10 -0
  48. package/signals/implementation/{errors.js → primitive/errors.js} +3 -4
  49. package/signals/implementation/primitive/formatter.d.ts +19 -0
  50. package/signals/implementation/primitive/formatter.js +136 -0
  51. package/signals/implementation/{graph.d.ts → primitive/graph.d.ts} +68 -36
  52. package/signals/implementation/primitive/graph.js +386 -0
  53. package/signals/implementation/primitive/linked_signal.d.ts +46 -0
  54. package/signals/implementation/primitive/linked_signal.js +110 -0
  55. package/signals/implementation/primitive/signal.d.ts +31 -0
  56. package/signals/implementation/primitive/signal.js +80 -0
  57. package/signals/implementation/primitive/untracked.d.ts +12 -0
  58. package/signals/implementation/primitive/untracked.js +23 -0
  59. package/signals/implementation/{watch.d.ts → primitive/watch.d.ts} +1 -2
  60. package/signals/implementation/{watch.js → primitive/watch.js} +22 -16
  61. package/signals/implementation/resource/api.d.ts +275 -0
  62. package/signals/implementation/resource/api.js +26 -0
  63. package/signals/implementation/resource/debounce.d.ts +13 -0
  64. package/signals/implementation/resource/debounce.js +113 -0
  65. package/signals/implementation/resource/from_snapshots.d.ts +16 -0
  66. package/signals/implementation/resource/from_snapshots.js +44 -0
  67. package/signals/implementation/resource/index.d.ts +11 -0
  68. package/signals/implementation/resource/index.js +11 -0
  69. package/signals/implementation/resource/resource.d.ts +110 -0
  70. package/signals/implementation/resource/resource.js +402 -0
  71. package/signals/implementation/root_effect_scheduler.d.ts +50 -0
  72. package/signals/implementation/root_effect_scheduler.js +66 -0
  73. package/signals/implementation/signal.d.ts +42 -18
  74. package/signals/implementation/signal.js +29 -49
  75. package/signals/implementation/to-observable.d.ts +12 -5
  76. package/signals/implementation/to-observable.js +12 -2
  77. package/signals/implementation/to-signal.d.ts +9 -18
  78. package/signals/implementation/to-signal.js +46 -13
  79. package/signals/implementation/untracked.d.ts +1 -1
  80. package/signals/implementation/untracked.js +3 -11
  81. package/signals/operators/debounce.d.ts +8 -0
  82. package/signals/operators/debounce.js +19 -0
  83. package/signals/operators/derive-async.js +43 -15
  84. package/signals/operators/index.d.ts +2 -0
  85. package/signals/operators/index.js +2 -0
  86. package/signals/operators/throttle.d.ts +8 -0
  87. package/signals/operators/throttle.js +31 -0
  88. package/ai/genkit/tests/multi-region.test.d.ts +0 -2
  89. package/ai/genkit/tests/multi-region.test.js +0 -179
  90. package/ai/genkit/tests/token-limit-fallback.test.d.ts +0 -2
  91. package/ai/genkit/tests/token-limit-fallback.test.js +0 -209
  92. package/ai/prompts/tests/prompt-builder.test.d.ts +0 -1
  93. package/ai/prompts/tests/prompt-builder.test.js +0 -22
  94. package/ai/tests/instructions-formatter.test.d.ts +0 -1
  95. package/ai/tests/instructions-formatter.test.js +0 -116
  96. package/ai/tests/steering.test.d.ts +0 -1
  97. package/ai/tests/steering.test.js +0 -37
  98. package/api/client/tests/api-client.test.d.ts +0 -1
  99. package/api/client/tests/api-client.test.js +0 -194
  100. package/api/server/tests/csrf.middleware.test.d.ts +0 -1
  101. package/api/server/tests/csrf.middleware.test.js +0 -91
  102. package/authentication/tests/authentication-password-requirements.validator.test.d.ts +0 -1
  103. package/authentication/tests/authentication-password-requirements.validator.test.js +0 -29
  104. package/authentication/tests/authentication.api-controller.test.d.ts +0 -1
  105. package/authentication/tests/authentication.api-controller.test.js +0 -156
  106. package/authentication/tests/authentication.api-request-token.provider.test.d.ts +0 -1
  107. package/authentication/tests/authentication.api-request-token.provider.test.js +0 -48
  108. package/authentication/tests/authentication.client-error-handling.test.d.ts +0 -1
  109. package/authentication/tests/authentication.client-error-handling.test.js +0 -123
  110. package/authentication/tests/authentication.client-middleware.test.d.ts +0 -1
  111. package/authentication/tests/authentication.client-middleware.test.js +0 -118
  112. package/authentication/tests/authentication.client-service-methods.test.d.ts +0 -1
  113. package/authentication/tests/authentication.client-service-methods.test.js +0 -177
  114. package/authentication/tests/authentication.client-service-refresh.test.d.ts +0 -1
  115. package/authentication/tests/authentication.client-service-refresh.test.js +0 -153
  116. package/authentication/tests/authentication.client-service.test.d.ts +0 -1
  117. package/authentication/tests/authentication.client-service.test.js +0 -76
  118. package/authentication/tests/authentication.refresh-busy-loop.test.d.ts +0 -1
  119. package/authentication/tests/authentication.refresh-busy-loop.test.js +0 -84
  120. package/authentication/tests/authentication.service.test.d.ts +0 -1
  121. package/authentication/tests/authentication.service.test.js +0 -167
  122. package/authentication/tests/authentication.test-ancillary-service.d.ts +0 -9
  123. package/authentication/tests/authentication.test-ancillary-service.js +0 -27
  124. package/authentication/tests/brute-force-protection.test.d.ts +0 -1
  125. package/authentication/tests/brute-force-protection.test.js +0 -211
  126. package/authentication/tests/helper.test.d.ts +0 -1
  127. package/authentication/tests/helper.test.js +0 -122
  128. package/authentication/tests/password-requirements.error.test.d.ts +0 -1
  129. package/authentication/tests/password-requirements.error.test.js +0 -14
  130. package/authentication/tests/remember.api.test.d.ts +0 -1
  131. package/authentication/tests/remember.api.test.js +0 -117
  132. package/authentication/tests/remember.service.test.d.ts +0 -1
  133. package/authentication/tests/remember.service.test.js +0 -83
  134. package/authentication/tests/subject.service.test.d.ts +0 -1
  135. package/authentication/tests/subject.service.test.js +0 -140
  136. package/authentication/tests/suspended-subject.test.d.ts +0 -1
  137. package/authentication/tests/suspended-subject.test.js +0 -120
  138. package/authentication/tests/totp.enrollment.test.d.ts +0 -1
  139. package/authentication/tests/totp.enrollment.test.js +0 -123
  140. package/authentication/tests/totp.login.test.d.ts +0 -1
  141. package/authentication/tests/totp.login.test.js +0 -213
  142. package/authentication/tests/totp.recovery-codes.test.d.ts +0 -1
  143. package/authentication/tests/totp.recovery-codes.test.js +0 -97
  144. package/authentication/tests/totp.status.test.d.ts +0 -1
  145. package/authentication/tests/totp.status.test.js +0 -72
  146. package/cancellation/tests/coverage.test.d.ts +0 -1
  147. package/cancellation/tests/coverage.test.js +0 -49
  148. package/cancellation/tests/leak.test.d.ts +0 -1
  149. package/cancellation/tests/leak.test.js +0 -35
  150. package/cancellation/tests/token.test.d.ts +0 -1
  151. package/cancellation/tests/token.test.js +0 -136
  152. package/circuit-breaker/tests/circuit-breaker.test.d.ts +0 -1
  153. package/circuit-breaker/tests/circuit-breaker.test.js +0 -116
  154. package/cryptography/tests/cryptography.test.d.ts +0 -1
  155. package/cryptography/tests/cryptography.test.js +0 -175
  156. package/cryptography/tests/jwt.test.d.ts +0 -1
  157. package/cryptography/tests/jwt.test.js +0 -54
  158. package/cryptography/tests/modern.test.d.ts +0 -1
  159. package/cryptography/tests/modern.test.js +0 -105
  160. package/cryptography/tests/module.test.d.ts +0 -1
  161. package/cryptography/tests/module.test.js +0 -100
  162. package/cryptography/tests/totp.test.d.ts +0 -1
  163. package/cryptography/tests/totp.test.js +0 -108
  164. package/document-management/tests/ai-config-hierarchy.test.d.ts +0 -1
  165. package/document-management/tests/ai-config-hierarchy.test.js +0 -59
  166. package/document-management/tests/ai-config-integration.test.d.ts +0 -1
  167. package/document-management/tests/ai-config-integration.test.js +0 -125
  168. package/document-management/tests/ai-config-merge.test.d.ts +0 -1
  169. package/document-management/tests/ai-config-merge.test.js +0 -46
  170. package/document-management/tests/document-management-ai-overrides.test.d.ts +0 -1
  171. package/document-management/tests/document-management-ai-overrides.test.js +0 -63
  172. package/document-management/tests/document-management-core.test.d.ts +0 -1
  173. package/document-management/tests/document-management-core.test.js +0 -157
  174. package/document-management/tests/document-management.api.test.d.ts +0 -1
  175. package/document-management/tests/document-management.api.test.js +0 -101
  176. package/document-management/tests/document-statistics.service.test.d.ts +0 -1
  177. package/document-management/tests/document-statistics.service.test.js +0 -498
  178. package/document-management/tests/document-validation-ai-overrides.test.d.ts +0 -1
  179. package/document-management/tests/document-validation-ai-overrides.test.js +0 -87
  180. package/document-management/tests/document.service.test.d.ts +0 -1
  181. package/document-management/tests/document.service.test.js +0 -143
  182. package/document-management/tests/enum-helpers.test.d.ts +0 -1
  183. package/document-management/tests/enum-helpers.test.js +0 -452
  184. package/document-management/tests/helper.d.ts +0 -24
  185. package/document-management/tests/helper.js +0 -39
  186. package/errors/tests/format.test.d.ts +0 -1
  187. package/errors/tests/format.test.js +0 -84
  188. package/http/tests/server-timing.test.d.ts +0 -1
  189. package/http/tests/server-timing.test.js +0 -42
  190. package/injector/tests/advanced.test.d.ts +0 -1
  191. package/injector/tests/advanced.test.js +0 -116
  192. package/injector/tests/async-init.test.d.ts +0 -1
  193. package/injector/tests/async-init.test.js +0 -77
  194. package/injector/tests/basic.test.d.ts +0 -1
  195. package/injector/tests/basic.test.js +0 -114
  196. package/injector/tests/hierarchical.test.d.ts +0 -1
  197. package/injector/tests/hierarchical.test.js +0 -59
  198. package/injector/tests/leak.test.d.ts +0 -1
  199. package/injector/tests/leak.test.js +0 -45
  200. package/injector/tests/lifecycles.test.d.ts +0 -1
  201. package/injector/tests/lifecycles.test.js +0 -109
  202. package/logger/tests/pretty-print.test.d.ts +0 -1
  203. package/logger/tests/pretty-print.test.js +0 -60
  204. package/notification/tests/notification-api.test.d.ts +0 -1
  205. package/notification/tests/notification-api.test.js +0 -124
  206. package/notification/tests/notification-client.test.d.ts +0 -1
  207. package/notification/tests/notification-client.test.js +0 -101
  208. package/notification/tests/notification-flow.test.d.ts +0 -1
  209. package/notification/tests/notification-flow.test.js +0 -296
  210. package/notification/tests/notification-sse.service.test.d.ts +0 -1
  211. package/notification/tests/notification-sse.service.test.js +0 -43
  212. package/notification/tests/notification-type.service.test.d.ts +0 -1
  213. package/notification/tests/notification-type.service.test.js +0 -41
  214. package/object-storage/s3/tests/s3.object-storage.integration.test.d.ts +0 -1
  215. package/object-storage/s3/tests/s3.object-storage.integration.test.js +0 -303
  216. package/orm/tests/build-jsonb.test.d.ts +0 -1
  217. package/orm/tests/build-jsonb.test.js +0 -39
  218. package/orm/tests/data-types.test.d.ts +0 -1
  219. package/orm/tests/data-types.test.js +0 -39
  220. package/orm/tests/database-extension.test.d.ts +0 -1
  221. package/orm/tests/database-extension.test.js +0 -63
  222. package/orm/tests/database-migration.test.d.ts +0 -1
  223. package/orm/tests/database-migration.test.js +0 -83
  224. package/orm/tests/decorators.test.d.ts +0 -1
  225. package/orm/tests/decorators.test.js +0 -77
  226. package/orm/tests/encryption.test.d.ts +0 -1
  227. package/orm/tests/encryption.test.js +0 -31
  228. package/orm/tests/query-complex.test.d.ts +0 -1
  229. package/orm/tests/query-complex.test.js +0 -172
  230. package/orm/tests/query-converter-complex.test.d.ts +0 -1
  231. package/orm/tests/query-converter-complex.test.js +0 -131
  232. package/orm/tests/query-converter.test.d.ts +0 -1
  233. package/orm/tests/query-converter.test.js +0 -123
  234. package/orm/tests/repository-advanced.test.d.ts +0 -1
  235. package/orm/tests/repository-advanced.test.js +0 -189
  236. package/orm/tests/repository-attributes.test.d.ts +0 -1
  237. package/orm/tests/repository-attributes.test.js +0 -83
  238. package/orm/tests/repository-compound-primary-key.test.d.ts +0 -2
  239. package/orm/tests/repository-compound-primary-key.test.js +0 -226
  240. package/orm/tests/repository-comprehensive.test.d.ts +0 -1
  241. package/orm/tests/repository-comprehensive.test.js +0 -162
  242. package/orm/tests/repository-coverage.test.d.ts +0 -2
  243. package/orm/tests/repository-coverage.test.js +0 -242
  244. package/orm/tests/repository-cti-complex.test.d.ts +0 -1
  245. package/orm/tests/repository-cti-complex.test.js +0 -151
  246. package/orm/tests/repository-cti-embedded.test.d.ts +0 -1
  247. package/orm/tests/repository-cti-embedded.test.js +0 -178
  248. package/orm/tests/repository-cti-extensive.test.d.ts +0 -2
  249. package/orm/tests/repository-cti-extensive.test.js +0 -279
  250. package/orm/tests/repository-cti-mapping.test.d.ts +0 -2
  251. package/orm/tests/repository-cti-mapping.test.js +0 -108
  252. package/orm/tests/repository-cti-search.test.d.ts +0 -1
  253. package/orm/tests/repository-cti-search.test.js +0 -141
  254. package/orm/tests/repository-cti-soft-delete.test.d.ts +0 -2
  255. package/orm/tests/repository-cti-soft-delete.test.js +0 -103
  256. package/orm/tests/repository-cti-transactions.test.d.ts +0 -1
  257. package/orm/tests/repository-cti-transactions.test.js +0 -112
  258. package/orm/tests/repository-cti-upsert-many.test.d.ts +0 -2
  259. package/orm/tests/repository-cti-upsert-many.test.js +0 -115
  260. package/orm/tests/repository-cti.test.d.ts +0 -2
  261. package/orm/tests/repository-cti.test.js +0 -390
  262. package/orm/tests/repository-edge-cases.test.d.ts +0 -1
  263. package/orm/tests/repository-edge-cases.test.js +0 -178
  264. package/orm/tests/repository-expiration.test.d.ts +0 -2
  265. package/orm/tests/repository-expiration.test.js +0 -140
  266. package/orm/tests/repository-extra-coverage.test.d.ts +0 -2
  267. package/orm/tests/repository-extra-coverage.test.js +0 -402
  268. package/orm/tests/repository-mapping.test.d.ts +0 -2
  269. package/orm/tests/repository-mapping.test.js +0 -65
  270. package/orm/tests/repository-regression.test.d.ts +0 -1
  271. package/orm/tests/repository-regression.test.js +0 -288
  272. package/orm/tests/repository-search-coverage.test.d.ts +0 -1
  273. package/orm/tests/repository-search-coverage.test.js +0 -107
  274. package/orm/tests/repository-search.test.d.ts +0 -1
  275. package/orm/tests/repository-search.test.js +0 -105
  276. package/orm/tests/repository-soft-delete.test.d.ts +0 -1
  277. package/orm/tests/repository-soft-delete.test.js +0 -118
  278. package/orm/tests/repository-transactions-nested.test.d.ts +0 -1
  279. package/orm/tests/repository-transactions-nested.test.js +0 -178
  280. package/orm/tests/repository-types.test.d.ts +0 -1
  281. package/orm/tests/repository-types.test.js +0 -184
  282. package/orm/tests/repository-undelete.test.d.ts +0 -2
  283. package/orm/tests/repository-undelete.test.js +0 -201
  284. package/orm/tests/schema-converter.test.d.ts +0 -1
  285. package/orm/tests/schema-converter.test.js +0 -82
  286. package/orm/tests/schema-generation.test.d.ts +0 -2
  287. package/orm/tests/schema-generation.test.js +0 -174
  288. package/orm/tests/sql-helpers.test.d.ts +0 -1
  289. package/orm/tests/sql-helpers.test.js +0 -67
  290. package/orm/tests/transaction-safety.test.d.ts +0 -1
  291. package/orm/tests/transaction-safety.test.js +0 -81
  292. package/orm/tests/transactional.test.d.ts +0 -1
  293. package/orm/tests/transactional.test.js +0 -215
  294. package/orm/tests/utils.test.d.ts +0 -1
  295. package/orm/tests/utils.test.js +0 -70
  296. package/pdf/tests/utils.test.d.ts +0 -1
  297. package/pdf/tests/utils.test.js +0 -187
  298. package/process/tests/spawn.test.d.ts +0 -1
  299. package/process/tests/spawn.test.js +0 -182
  300. package/rate-limit/tests/postgres-rate-limiter.test.d.ts +0 -1
  301. package/rate-limit/tests/postgres-rate-limiter.test.js +0 -84
  302. package/renderer/tests/renderer.test.d.ts +0 -1
  303. package/renderer/tests/renderer.test.js +0 -88
  304. package/rpc/tests/rpc.integration.test.d.ts +0 -1
  305. package/rpc/tests/rpc.integration.test.js +0 -615
  306. package/signals/implementation/errors.d.ts +0 -2
  307. package/signals/implementation/graph.js +0 -312
  308. package/signals/implementation/writable-signal.d.ts +0 -48
  309. package/signals/implementation/writable-signal.js +0 -32
  310. package/task-queue/tests/coverage-branch.test.d.ts +0 -1
  311. package/task-queue/tests/coverage-branch.test.js +0 -395
  312. package/task-queue/tests/coverage-enhancement.test.d.ts +0 -1
  313. package/task-queue/tests/coverage-enhancement.test.js +0 -150
  314. package/task-queue/tests/dag.test.d.ts +0 -1
  315. package/task-queue/tests/dag.test.js +0 -188
  316. package/task-queue/tests/dependencies.test.d.ts +0 -1
  317. package/task-queue/tests/dependencies.test.js +0 -296
  318. package/task-queue/tests/enqueue-batch.test.d.ts +0 -1
  319. package/task-queue/tests/enqueue-batch.test.js +0 -125
  320. package/task-queue/tests/enqueue-item.test.d.ts +0 -1
  321. package/task-queue/tests/enqueue-item.test.js +0 -12
  322. package/task-queue/tests/fan-out-spawning.test.d.ts +0 -1
  323. package/task-queue/tests/fan-out-spawning.test.js +0 -94
  324. package/task-queue/tests/idempotent-replacement.test.d.ts +0 -1
  325. package/task-queue/tests/idempotent-replacement.test.js +0 -114
  326. package/task-queue/tests/missing-idempotent-tasks.test.d.ts +0 -1
  327. package/task-queue/tests/missing-idempotent-tasks.test.js +0 -39
  328. package/task-queue/tests/optimization-edge-cases.test.d.ts +0 -1
  329. package/task-queue/tests/optimization-edge-cases.test.js +0 -124
  330. package/task-queue/tests/queue-generic.test.d.ts +0 -1
  331. package/task-queue/tests/queue-generic.test.js +0 -8
  332. package/task-queue/tests/queue.test.d.ts +0 -1
  333. package/task-queue/tests/queue.test.js +0 -756
  334. package/task-queue/tests/shutdown.test.d.ts +0 -1
  335. package/task-queue/tests/shutdown.test.js +0 -41
  336. package/task-queue/tests/task-context.test.d.ts +0 -1
  337. package/task-queue/tests/task-context.test.js +0 -7
  338. package/task-queue/tests/task-union.test.d.ts +0 -1
  339. package/task-queue/tests/task-union.test.js +0 -18
  340. package/task-queue/tests/transactions.test.d.ts +0 -1
  341. package/task-queue/tests/transactions.test.js +0 -47
  342. package/task-queue/tests/typing.test.d.ts +0 -1
  343. package/task-queue/tests/typing.test.js +0 -9
  344. package/task-queue/tests/worker.test.d.ts +0 -1
  345. package/task-queue/tests/worker.test.js +0 -258
  346. package/task-queue/tests/zombie-parent.test.d.ts +0 -1
  347. package/task-queue/tests/zombie-parent.test.js +0 -45
  348. package/task-queue/tests/zombie-recovery.test.d.ts +0 -1
  349. package/task-queue/tests/zombie-recovery.test.js +0 -51
  350. package/utils/tests/backoff.test.d.ts +0 -1
  351. package/utils/tests/backoff.test.js +0 -41
  352. package/utils/tests/retry-with-backoff.test.d.ts +0 -1
  353. package/utils/tests/retry-with-backoff.test.js +0 -49
@@ -0,0 +1,402 @@
1
+ /**
2
+ * @license
3
+ * Copyright Google LLC All Rights Reserved.
4
+ *
5
+ * Use of this source code is governed by an MIT-style license that can be
6
+ * found in the LICENSE file at https://angular.dev/license
7
+ */
8
+ /* eslint-disable */
9
+ /** biome-ignore-all lint: <explanation> */
10
+ import { isDevMode } from '../../../core.js';
11
+ import { registerFinalization } from '../../../memory/finalization.js';
12
+ import { computed } from '../computed.js';
13
+ import { effect } from '../effect.js';
14
+ import { linkedSignal } from '../linked_signal.js';
15
+ import { signal, signalAsReadonlyFn } from '../signal.js';
16
+ import { untracked } from '../untracked.js';
17
+ import { ResourceDependencyError, ResourceParamsStatus } from './api.js';
18
+ export function resource(options) {
19
+ const oldNameForParams = options.request;
20
+ const params = options.params ?? oldNameForParams ?? (() => null);
21
+ return new ResourceImpl(params, getLoader(options), options.defaultValue, options.equal ? wrapEqualityFn(options.equal) : undefined, options.debugName, options.injector);
22
+ }
23
+ /**
24
+ * Base class which implements `.value` as a `WritableSignal` by delegating `.set` and `.update`.
25
+ */
26
+ class BaseWritableResource {
27
+ value;
28
+ isLoading;
29
+ constructor(value, debugName) {
30
+ this.value = value;
31
+ this.value.set = this.set.bind(this);
32
+ this.value.update = this.update.bind(this);
33
+ this.value.asReadonly = signalAsReadonlyFn;
34
+ this.isLoading = computed(() => this.status() === 'loading' || this.status() === 'reloading', isDevMode() ? createDebugNameObject(debugName, 'isLoading') : undefined);
35
+ }
36
+ isError = computed(() => this.status() === 'error');
37
+ update(updateFn) {
38
+ this.set(updateFn(untracked(this.value)));
39
+ }
40
+ // Use a computed here to avoid triggering reactive consumers if the value changes while staying
41
+ // either defined or undefined.
42
+ isValueDefined = computed(() => {
43
+ // Check if it's in an error state first to prevent the error from bubbling up.
44
+ if (this.isError()) {
45
+ return false;
46
+ }
47
+ return this.value() !== undefined;
48
+ });
49
+ _snapshot;
50
+ get snapshot() {
51
+ return (this._snapshot ??= computed(() => {
52
+ const status = this.status();
53
+ if (status === 'error') {
54
+ return { status: 'error', error: this.error() };
55
+ }
56
+ else {
57
+ return { status, value: this.value() };
58
+ }
59
+ }));
60
+ }
61
+ hasValue() {
62
+ return this.isValueDefined();
63
+ }
64
+ asReadonly() {
65
+ return this;
66
+ }
67
+ }
68
+ /**
69
+ * Implementation for `resource()` which uses a `linkedSignal` to manage the resource's state.
70
+ */
71
+ export class ResourceImpl extends BaseWritableResource {
72
+ /**
73
+ * The current state of the resource. Status, value, and error are derived from this.
74
+ */
75
+ state;
76
+ /**
77
+ * Combines the current request with a reload counter which allows the resource to be reloaded on
78
+ * imperative command.
79
+ */
80
+ extRequest;
81
+ effectRef;
82
+ loaderFn;
83
+ defaultValue;
84
+ equal;
85
+ debugName;
86
+ pendingController;
87
+ resolvePendingTask = undefined;
88
+ destroyed = false;
89
+ unregisterOnDestroy;
90
+ status;
91
+ error;
92
+ constructor(request, loaderFn, defaultValue, equal, debugName, injector, getInitialStream) {
93
+ if (isInParamsFunction()) {
94
+ throw invalidResourceCreationInParams();
95
+ }
96
+ super(
97
+ // Feed a computed signal for the value to `BaseWritableResource`, which will upgrade it to a
98
+ // `WritableSignal` that delegates to `ResourceImpl.set`.
99
+ computed(() => {
100
+ const streamValue = this.state().stream?.();
101
+ if (!streamValue) {
102
+ return defaultValue;
103
+ }
104
+ // Prevents `hasValue()` from throwing an error when a reload happened in the error state
105
+ if (this.state().status === 'loading' && this.error()) {
106
+ return defaultValue;
107
+ }
108
+ if (!isResolved(streamValue)) {
109
+ throw new ResourceValueError(this.error());
110
+ }
111
+ return streamValue.value;
112
+ }, { equal, ...(isDevMode() ? createDebugNameObject(debugName, 'value') : undefined) }), debugName);
113
+ this.loaderFn = loaderFn;
114
+ this.defaultValue = defaultValue;
115
+ this.equal = equal;
116
+ this.debugName = debugName;
117
+ this.extRequest = linkedSignal(() => {
118
+ try {
119
+ setInParamsFunction(true);
120
+ return { request: request(paramsContext), reload: 0 };
121
+ }
122
+ catch (error) {
123
+ rethrowFatalErrors(error);
124
+ if (error === ResourceParamsStatus.IDLE) {
125
+ return { status: 'idle', reload: 0 };
126
+ }
127
+ else if (error === ResourceParamsStatus.LOADING) {
128
+ return { status: 'loading', reload: 0 };
129
+ }
130
+ return { error: error, reload: 0 };
131
+ }
132
+ finally {
133
+ setInParamsFunction(false);
134
+ }
135
+ }, isDevMode() ? createDebugNameObject(debugName, 'extRequest') : undefined);
136
+ // The main resource state is managed in a `linkedSignal`, which allows the resource to change
137
+ // state instantaneously when the request signal changes.
138
+ this.state = linkedSignal({
139
+ // Whenever the request changes,
140
+ source: this.extRequest,
141
+ // Compute the state of the resource given a change in status.
142
+ computation: (extRequest, previous) => {
143
+ let { request, status, error } = extRequest;
144
+ let stream;
145
+ if (error) {
146
+ status = 'resolved';
147
+ stream = signal({ error: encapsulateResourceError(error) }, isDevMode() ? createDebugNameObject(this.debugName, 'stream') : undefined);
148
+ }
149
+ else if (!status) {
150
+ if (!previous) {
151
+ stream = getInitialStream?.(extRequest.request);
152
+ // Clear getInitialStream so it doesn't hold onto memory
153
+ getInitialStream = undefined;
154
+ status = request === undefined ? 'idle' : stream ? 'resolved' : 'loading';
155
+ }
156
+ else {
157
+ status = request === undefined ? 'idle' : 'loading';
158
+ if (previous.value.extRequest.request === request) {
159
+ stream = previous.value.stream;
160
+ }
161
+ }
162
+ }
163
+ return {
164
+ extRequest,
165
+ status,
166
+ previousStatus: previous ? projectStatusOfState(previous.value) : 'idle',
167
+ stream,
168
+ };
169
+ },
170
+ ...(isDevMode() ? createDebugNameObject(debugName, 'state') : undefined),
171
+ });
172
+ this.effectRef = effect(this.loadEffect.bind(this), {
173
+ injector,
174
+ manualCleanup: true,
175
+ ...(isDevMode() ? createDebugNameObject(debugName, 'loadEffect') : undefined),
176
+ });
177
+ this.status = computed(() => projectStatusOfState(this.state()), isDevMode() ? createDebugNameObject(debugName, 'status') : undefined);
178
+ this.error = computed(() => {
179
+ const stream = this.state().stream?.();
180
+ return stream && !isResolved(stream) ? stream.error : undefined;
181
+ }, isDevMode() ? createDebugNameObject(debugName, 'error') : undefined);
182
+ registerFinalization(this, () => this.destroy());
183
+ }
184
+ /**
185
+ * Called either directly via `WritableResource.set` or via `.value.set()`.
186
+ */
187
+ set(value) {
188
+ if (this.destroyed) {
189
+ return;
190
+ }
191
+ const error = untracked(this.error);
192
+ const state = untracked(this.state);
193
+ if (!error) {
194
+ const current = untracked(this.value);
195
+ if (state.status === 'local' &&
196
+ (this.equal ? this.equal(current, value) : current === value)) {
197
+ return;
198
+ }
199
+ }
200
+ // Enter Local state with the user-defined value.
201
+ this.state.set({
202
+ extRequest: state.extRequest,
203
+ status: 'local',
204
+ previousStatus: 'local',
205
+ stream: signal({ value }, isDevMode() ? createDebugNameObject(this.debugName, 'stream') : undefined),
206
+ });
207
+ // We're departing from whatever state the resource was in previously, so cancel any in-progress
208
+ // loading operations.
209
+ this.abortInProgressLoad();
210
+ }
211
+ reload() {
212
+ // We don't want to restart in-progress loads.
213
+ const { status } = untracked(this.state);
214
+ if (status === 'idle' || status === 'loading') {
215
+ return false;
216
+ }
217
+ // Increment the request reload to trigger the `state` linked signal to switch us to `Reload`
218
+ this.extRequest.update(({ request, reload }) => ({ request, reload: reload + 1 }));
219
+ return true;
220
+ }
221
+ destroy() {
222
+ this.destroyed = true;
223
+ this.unregisterOnDestroy();
224
+ this.effectRef.destroy();
225
+ this.abortInProgressLoad();
226
+ // Destroyed resources enter Idle state.
227
+ this.state.set({
228
+ extRequest: { request: undefined, reload: 0 },
229
+ status: 'idle',
230
+ previousStatus: 'idle',
231
+ stream: undefined,
232
+ });
233
+ }
234
+ async loadEffect() {
235
+ const extRequest = this.extRequest();
236
+ // Capture the previous status before any state transitions. Note that this is `untracked` since
237
+ // we do not want the effect to depend on the state of the resource, only on the request.
238
+ const { status: currentStatus, previousStatus } = untracked(this.state);
239
+ if (extRequest.request === undefined) {
240
+ // Nothing to load (and we should already be in a non-loading state).
241
+ return;
242
+ }
243
+ else if (currentStatus !== 'loading') {
244
+ // We're not in a loading or reloading state, so this loading request is stale.
245
+ return;
246
+ }
247
+ // Cancel any previous loading attempts.
248
+ this.abortInProgressLoad();
249
+ const { signal: abortSignal } = (this.pendingController = new AbortController());
250
+ try {
251
+ // The actual loading is run through `untracked` - only the request side of `resource` is
252
+ // reactive. This avoids any confusion with signals tracking or not tracking depending on
253
+ // which side of the `await` they are.
254
+ const stream = await untracked(() => {
255
+ return this.loaderFn({
256
+ params: extRequest.request,
257
+ abortSignal,
258
+ previous: {
259
+ status: previousStatus,
260
+ },
261
+ });
262
+ });
263
+ // If this request has been aborted, or the current request no longer
264
+ // matches this load, then we should ignore this resolution.
265
+ if (abortSignal.aborted || untracked(this.extRequest) !== extRequest) {
266
+ return;
267
+ }
268
+ this.state.set({
269
+ extRequest,
270
+ status: 'resolved',
271
+ previousStatus: 'resolved',
272
+ stream,
273
+ });
274
+ }
275
+ catch (err) {
276
+ rethrowFatalErrors(err);
277
+ if (abortSignal.aborted || untracked(this.extRequest) !== extRequest) {
278
+ return;
279
+ }
280
+ this.state.set({
281
+ extRequest,
282
+ status: 'resolved',
283
+ previousStatus: 'error',
284
+ stream: signal({ error: encapsulateResourceError(err) }, isDevMode() ? createDebugNameObject(this.debugName, 'stream') : undefined),
285
+ });
286
+ }
287
+ }
288
+ abortInProgressLoad() {
289
+ untracked(() => this.pendingController?.abort());
290
+ this.pendingController = undefined;
291
+ // Once the load is aborted, we no longer want to block stability on its resolution.
292
+ this.resolvePendingTask?.();
293
+ this.resolvePendingTask = undefined;
294
+ }
295
+ }
296
+ /**
297
+ * Wraps an equality function to handle either value being `undefined`.
298
+ */
299
+ function wrapEqualityFn(equal) {
300
+ return (a, b) => (a === undefined || b === undefined ? a === b : equal(a, b));
301
+ }
302
+ function getLoader(options) {
303
+ if (isStreamingResourceOptions(options)) {
304
+ return options.stream;
305
+ }
306
+ return async (params) => {
307
+ try {
308
+ return signal({ value: await options.loader(params) }, isDevMode() ? createDebugNameObject(options.debugName, 'stream') : undefined);
309
+ }
310
+ catch (err) {
311
+ return signal({ error: encapsulateResourceError(err) }, isDevMode() ? createDebugNameObject(options.debugName, 'stream') : undefined);
312
+ }
313
+ };
314
+ }
315
+ function isStreamingResourceOptions(options) {
316
+ return !!options.stream;
317
+ }
318
+ /**
319
+ * Project from a state with `ResourceInternalStatus` to the user-facing `ResourceStatus`
320
+ */
321
+ function projectStatusOfState(state) {
322
+ switch (state.status) {
323
+ case 'loading':
324
+ return state.extRequest.reload === 0 ? 'loading' : 'reloading';
325
+ case 'resolved':
326
+ return isResolved(state.stream()) ? 'resolved' : 'error';
327
+ default:
328
+ return state.status;
329
+ }
330
+ }
331
+ function isResolved(state) {
332
+ return state.error === undefined;
333
+ }
334
+ /**
335
+ * Creates a debug name object for an internal signal.
336
+ */
337
+ function createDebugNameObject(resourceDebugName, internalSignalDebugName) {
338
+ return {
339
+ debugName: `Resource${resourceDebugName ? '#' + resourceDebugName : ''}.${internalSignalDebugName}`,
340
+ };
341
+ }
342
+ export function encapsulateResourceError(error) {
343
+ if (isErrorLike(error)) {
344
+ return error;
345
+ }
346
+ return new ResourceWrappedError(error);
347
+ }
348
+ export function isErrorLike(error) {
349
+ return (error instanceof Error ||
350
+ (typeof error === 'object' &&
351
+ typeof error.name === 'string' &&
352
+ typeof error.message === 'string'));
353
+ }
354
+ export class ResourceValueError extends Error {
355
+ constructor(error) {
356
+ super(isDevMode()
357
+ ? `Resource is currently in an error state (see Error.cause for details): ${error.message}`
358
+ : error.message, { cause: error });
359
+ }
360
+ }
361
+ class ResourceWrappedError extends Error {
362
+ constructor(error) {
363
+ super(isDevMode()
364
+ ? `Resource returned an error that's not an Error instance: ${String(error)}. Check this error's .cause for the actual error.`
365
+ : String(error), { cause: error });
366
+ }
367
+ }
368
+ /**
369
+ * Chains the value of another resource into the params of the current resource, returning the value
370
+ * of the other resource if it is available, or propagating the status to the current resource if it
371
+ * is not.
372
+ */
373
+ export const paramsContext = {
374
+ chain(resource) {
375
+ switch (resource.status()) {
376
+ case 'idle':
377
+ throw ResourceParamsStatus.IDLE;
378
+ case 'error':
379
+ throw new ResourceDependencyError(resource);
380
+ case 'loading':
381
+ case 'reloading':
382
+ throw ResourceParamsStatus.LOADING;
383
+ }
384
+ return resource.value();
385
+ },
386
+ };
387
+ let inParamsFunction = false;
388
+ export function isInParamsFunction() {
389
+ return inParamsFunction;
390
+ }
391
+ export function setInParamsFunction(value) {
392
+ inParamsFunction = value;
393
+ }
394
+ export function invalidResourceCreationInParams() {
395
+ return new Error(`Cannot create a resource inside the \`params\` of another resource`);
396
+ }
397
+ export function rethrowFatalErrors(error) {
398
+ if (error instanceof Error &&
399
+ error.message === `Cannot create a resource inside the \`params\` of another resource`) {
400
+ throw error;
401
+ }
402
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * @license
3
+ * Copyright Google LLC All Rights Reserved.
4
+ *
5
+ * Use of this source code is governed by an MIT-style license that can be
6
+ * found in the LICENSE file at https://angular.dev/license
7
+ */
8
+ /** biome-ignore-all lint/nursery/noExcessiveClassesPerFile: <explanation> */
9
+ /**
10
+ * Abstraction that encompasses any kind of effect that can be scheduled.
11
+ */
12
+ export interface SchedulableEffect {
13
+ run(): void;
14
+ dirty: boolean;
15
+ }
16
+ /**
17
+ * A scheduler which manages the execution of effects.
18
+ */
19
+ export declare abstract class EffectScheduler {
20
+ abstract add(e: SchedulableEffect): void;
21
+ /**
22
+ * Schedule the given effect to be executed at a later time.
23
+ *
24
+ * It is an error to attempt to execute any effects synchronously during a scheduling operation.
25
+ */
26
+ abstract schedule(e: SchedulableEffect): void;
27
+ /**
28
+ * Run any scheduled effects.
29
+ */
30
+ abstract flush(): void;
31
+ /** Remove a scheduled effect */
32
+ abstract remove(e: SchedulableEffect): void;
33
+ }
34
+ export declare class MicrotaskEffectScheduler implements EffectScheduler {
35
+ private readonly queue;
36
+ private dirtyEffectCount;
37
+ private hasPendingFlush;
38
+ add(handle: SchedulableEffect): void;
39
+ schedule(handle: SchedulableEffect): void;
40
+ remove(handle: SchedulableEffect): void;
41
+ private enqueue;
42
+ /**
43
+ * Run all scheduled effects.
44
+ *
45
+ * Execution order of effects within the same zone is guaranteed to be FIFO, but there is no
46
+ * ordering guarantee between effects scheduled in different zones.
47
+ */
48
+ flush(): void;
49
+ }
50
+ export declare const microtaskEffectScheduler: MicrotaskEffectScheduler;
@@ -0,0 +1,66 @@
1
+ /**
2
+ * @license
3
+ * Copyright Google LLC All Rights Reserved.
4
+ *
5
+ * Use of this source code is governed by an MIT-style license that can be
6
+ * found in the LICENSE file at https://angular.dev/license
7
+ */
8
+ /**
9
+ * A scheduler which manages the execution of effects.
10
+ */
11
+ export class EffectScheduler {
12
+ }
13
+ export class MicrotaskEffectScheduler {
14
+ queue = new Set();
15
+ dirtyEffectCount = 0;
16
+ hasPendingFlush = false;
17
+ add(handle) {
18
+ this.enqueue(handle);
19
+ this.schedule(handle);
20
+ }
21
+ schedule(handle) {
22
+ if (!handle.dirty) {
23
+ return;
24
+ }
25
+ this.dirtyEffectCount++;
26
+ if (!this.hasPendingFlush) {
27
+ this.hasPendingFlush = true;
28
+ queueMicrotask(() => {
29
+ this.hasPendingFlush = false;
30
+ this.flush();
31
+ });
32
+ }
33
+ }
34
+ remove(handle) {
35
+ this.queue.delete(handle);
36
+ if (handle.dirty) {
37
+ this.dirtyEffectCount--;
38
+ }
39
+ }
40
+ enqueue(handle) {
41
+ if (this.queue.has(handle)) {
42
+ return;
43
+ }
44
+ this.queue.add(handle);
45
+ }
46
+ /**
47
+ * Run all scheduled effects.
48
+ *
49
+ * Execution order of effects within the same zone is guaranteed to be FIFO, but there is no
50
+ * ordering guarantee between effects scheduled in different zones.
51
+ */
52
+ flush() {
53
+ while (this.dirtyEffectCount > 0) {
54
+ for (const handle of this.queue) {
55
+ if (!handle.dirty) {
56
+ continue;
57
+ }
58
+ this.dirtyEffectCount--;
59
+ // TODO: what happens if this throws an error?
60
+ handle.run();
61
+ }
62
+ }
63
+ this.dirtyEffectCount = 0;
64
+ }
65
+ }
66
+ export const microtaskEffectScheduler = new MicrotaskEffectScheduler();
@@ -3,27 +3,51 @@
3
3
  * Copyright Google LLC All Rights Reserved.
4
4
  *
5
5
  * Use of this source code is governed by an MIT-style license that can be
6
- * found in the LICENSE file at https://angular.io/license
6
+ * found in the LICENSE file at https://angular.dev/license
7
7
  */
8
- import type { ValueEqualityFn } from './equality.js';
9
- import type { ReactiveNode } from './graph.js';
10
- import { SIGNAL } from './graph.js';
11
- export interface SignalNode<T> extends ReactiveNode {
12
- value: T;
13
- equal: ValueEqualityFn<T>;
8
+ import type { Signal, ValueEqualityFn } from './api.js';
9
+ import { type SignalGetter } from './primitive/signal.js';
10
+ /** Symbol used distinguish `WritableSignal` from other non-writable signals and functions. */
11
+ export declare const ɵWRITABLE_SIGNAL: unique symbol;
12
+ /**
13
+ * A `Signal` with a value that can be mutated via a setter interface.
14
+ *
15
+ * @publicApi 17.0
16
+ */
17
+ export interface WritableSignal<T> extends Signal<T> {
18
+ [ɵWRITABLE_SIGNAL]: T;
19
+ /**
20
+ * Directly set the signal to a new value, and notify any dependents.
21
+ */
22
+ set(value: T): void;
23
+ /**
24
+ * Update the value of the signal based on its current value, and
25
+ * notify any dependents.
26
+ */
27
+ update(updateFn: (value: T) => T): void;
28
+ /**
29
+ * Returns a readonly version of this signal. Readonly signals can be accessed to read their value
30
+ * but can't be changed using set or update methods. The readonly signals do _not_ have
31
+ * any built-in mechanism that would prevent deep-mutation of their value.
32
+ */
33
+ asReadonly(): Signal<T>;
14
34
  }
15
- export type SignalBaseGetter<T> = (() => T) & {
16
- readonly [SIGNAL]: unknown;
17
- };
18
- export interface SignalGetter<T> extends SignalBaseGetter<T> {
19
- readonly [SIGNAL]: SignalNode<T>;
35
+ /**
36
+ * Options passed to the `signal` creation function.
37
+ */
38
+ export interface CreateSignalOptions<T> {
39
+ /**
40
+ * A comparison function which defines equality for signal values.
41
+ */
42
+ equal?: ValueEqualityFn<T>;
43
+ /**
44
+ * A debug name for the signal. Used in Angular DevTools to identify the signal.
45
+ */
46
+ debugName?: string;
20
47
  }
21
48
  /**
22
49
  * Create a `Signal` that can be set or updated directly.
50
+ * @see [Angular Signals](guide/signals)
23
51
  */
24
- export declare function createSignal<T>(initialValue: T): SignalGetter<T>;
25
- export declare function setPostSignalSetFn(fn: (() => void) | null): (() => void) | null;
26
- export declare function signalGetFn<T>(this: SignalNode<T>): T;
27
- export declare function signalSetFn<T>(node: SignalNode<T>, newValue: T): void;
28
- export declare function signalUpdateFn<T>(node: SignalNode<T>, updater: (value: T) => T): void;
29
- export declare const SIGNAL_NODE: SignalNode<unknown>;
52
+ export declare function signal<T>(initialValue: T, options?: CreateSignalOptions<T>): WritableSignal<T>;
53
+ export declare function signalAsReadonlyFn<T>(this: SignalGetter<T>): Signal<T>;
@@ -1,59 +1,39 @@
1
- /* eslint-disable */
2
- import { defaultEquals } from './equality.js';
3
- import { throwInvalidWriteToSignalError } from './errors.js';
4
- import { producerAccessed, producerIncrementEpoch, producerNotifyConsumers, producerUpdatesAllowed, REACTIVE_NODE, SIGNAL } from './graph.js';
5
1
  /**
6
- * If set, called after `WritableSignal`s are updated.
2
+ * @license
3
+ * Copyright Google LLC All Rights Reserved.
7
4
  *
8
- * This hook can be used to achieve various effects, such as running effects synchronously as part
9
- * of setting a signal.
5
+ * Use of this source code is governed by an MIT-style license that can be
6
+ * found in the LICENSE file at https://angular.dev/license
10
7
  */
11
- let postSignalSetFn = null;
8
+ import { isDevMode } from '../../core.js';
9
+ import { SIGNAL } from '../symbol.js';
10
+ import { createSignal } from './primitive/signal.js';
11
+ /** Symbol used distinguish `WritableSignal` from other non-writable signals and functions. */
12
+ export const ɵWRITABLE_SIGNAL = /* @__PURE__ */ Symbol('WRITABLE_SIGNAL');
12
13
  /**
13
14
  * Create a `Signal` that can be set or updated directly.
15
+ * @see [Angular Signals](guide/signals)
14
16
  */
15
- export function createSignal(initialValue) {
16
- const node = Object.create(SIGNAL_NODE);
17
- node.value = initialValue;
18
- const getter = (() => {
19
- producerAccessed(node);
20
- return node.value;
21
- });
22
- getter[SIGNAL] = node;
23
- return getter;
24
- }
25
- export function setPostSignalSetFn(fn) {
26
- const prev = postSignalSetFn;
27
- postSignalSetFn = fn;
28
- return prev;
29
- }
30
- export function signalGetFn() {
31
- producerAccessed(this);
32
- return this.value;
33
- }
34
- export function signalSetFn(node, newValue) {
35
- if (!producerUpdatesAllowed()) {
36
- throwInvalidWriteToSignalError();
37
- }
38
- if (!node.equal(node.value, newValue)) {
39
- node.value = newValue;
40
- signalValueChanged(node);
17
+ export function signal(initialValue, options) {
18
+ const [get, set, update] = createSignal(initialValue, options?.equal);
19
+ const signalFn = get;
20
+ const node = signalFn[SIGNAL];
21
+ signalFn.set = set;
22
+ signalFn.update = update;
23
+ signalFn.asReadonly = signalAsReadonlyFn.bind(signalFn);
24
+ if (isDevMode()) {
25
+ const debugName = options?.debugName;
26
+ node.debugName = debugName;
27
+ signalFn.toString = () => `[Signal${debugName ? ' (' + debugName + ')' : ''}: ${signalFn()}]`;
41
28
  }
29
+ return signalFn;
42
30
  }
43
- export function signalUpdateFn(node, updater) {
44
- if (!producerUpdatesAllowed()) {
45
- throwInvalidWriteToSignalError();
31
+ export function signalAsReadonlyFn() {
32
+ const node = this[SIGNAL];
33
+ if (node.readonlyFn === undefined) {
34
+ const readonlyFn = () => this();
35
+ readonlyFn[SIGNAL] = node;
36
+ node.readonlyFn = readonlyFn;
46
37
  }
47
- signalSetFn(node, updater(node.value));
48
- }
49
- export const SIGNAL_NODE = {
50
- ...REACTIVE_NODE,
51
- equal: defaultEquals,
52
- value: undefined,
53
- };
54
- function signalValueChanged(node) {
55
- node.version++;
56
- producerIncrementEpoch();
57
- producerNotifyConsumers(node);
58
- postSignalSetFn?.();
38
+ return node.readonlyFn;
59
39
  }