| 177 | * Implementation for `resource()` which uses a `linkedSignal` to manage the resource's state. |
| 178 | */ |
| 179 | export class ResourceImpl<T, R> extends BaseWritableResource<T> implements ResourceRef<T> { |
| 180 | private readonly pendingTasks: PendingTasks; |
| 181 | |
| 182 | /** |
| 183 | * The current state of the resource. Status, value, and error are derived from this. |
| 184 | */ |
| 185 | private readonly state: WritableSignal<ResourceState<T>>; |
| 186 | |
| 187 | /** |
| 188 | * Combines the current request with a reload counter which allows the resource to be reloaded on |
| 189 | * imperative command. |
| 190 | */ |
| 191 | protected readonly extRequest: WritableSignal<WrappedRequest>; |
| 192 | private readonly effectRef: EffectRef; |
| 193 | |
| 194 | private pendingController: AbortController | undefined; |
| 195 | private resolvePendingTask: (() => void) | undefined = undefined; |
| 196 | private destroyed = false; |
| 197 | private unregisterOnDestroy: () => void; |
| 198 | |
| 199 | override readonly status: Signal<ResourceStatus>; |
| 200 | override readonly error: Signal<Error | undefined>; |
| 201 | private readonly transferState: TransferState | undefined; |
| 202 | |
| 203 | constructor( |
| 204 | request: (ctx: ResourceParamsContext) => R, |
| 205 | private readonly loaderFn: ResourceStreamingLoader<T, R>, |
| 206 | defaultValue: T, |
| 207 | private readonly equal: ValueEqualityFn<T> | undefined, |
| 208 | private readonly debugName: string | undefined, |
| 209 | injector: Injector, |
| 210 | private transferCacheKey: StateKey<T> | undefined, |
| 211 | getInitialStream?: (request: R) => Signal<ResourceStreamItem<T>> | undefined, |
| 212 | ) { |
| 213 | if (isInParamsFunction()) { |
| 214 | throw invalidResourceCreationInParams(); |
| 215 | } |
| 216 | |
| 217 | super( |
| 218 | // Feed a computed signal for the value to `BaseWritableResource`, which will upgrade it to a |
| 219 | // `WritableSignal` that delegates to `ResourceImpl.set`. |
| 220 | computed( |
| 221 | () => { |
| 222 | const streamValue = this.state().stream?.(); |
| 223 | |
| 224 | if (!streamValue) { |
| 225 | return defaultValue; |
| 226 | } |
| 227 | |
| 228 | // Prevents `hasValue()` from throwing an error when a reload happened in the error state |
| 229 | if (this.state().status === 'loading' && this.error()) { |
| 230 | return defaultValue; |
| 231 | } |
| 232 | |
| 233 | if (!isResolved(streamValue)) { |
| 234 | throw new ResourceValueError(this.error()!); |
| 235 | } |
| 236 |
nothing calls this directly
no outgoing calls
no test coverage detected