| 56 | }); |
| 57 | |
| 58 | const observe = (address: string, owner: Owner, value: unknown): Effect.Effect<void> => |
| 59 | Effect.gen(function* () { |
| 60 | const key = cacheKey(owner, address); |
| 61 | const prior = yield* load(address, owner); |
| 62 | const now = yield* Clock.currentTimeMillis; |
| 63 | const next = observeShape(prior, value, now); |
| 64 | cache.set(key, next); |
| 65 | // Write only when the merged shape actually changed — observation |
| 66 | // counters alone are bookkeeping, not worth a row write per call. |
| 67 | const schemaJson = JSON.stringify(next.schema); |
| 68 | if (persisted.get(key) === schemaJson) return; |
| 69 | yield* storage |
| 70 | .put({ owner, collection: COLLECTION, key: address, data: next }) |
| 71 | .pipe(Effect.catch(() => Effect.succeed(null))); |
| 72 | persisted.set(key, schemaJson); |
| 73 | }).pipe(Effect.catchCause(() => Effect.void)); |
| 74 | |
| 75 | return { |
| 76 | observe, |