(organizationId: string, seats: number)
| 181 | }).pipe(Effect.withSpan("autumn.trackExecution")); |
| 182 | |
| 183 | const setMemberSeats = (organizationId: string, seats: number) => |
| 184 | Effect.gen(function* () { |
| 185 | yield* Effect.annotateCurrentSpan({ |
| 186 | "autumn.customer.id": organizationId, |
| 187 | "autumn.members.seats": seats, |
| 188 | }); |
| 189 | // getOrCreate rather than get: reuses the provisioning repair, so an |
| 190 | // org Autumn has never seen gets its customer minted here instead of |
| 191 | // 404ing forever. |
| 192 | const customer = yield* use((c) => c.customers.getOrCreate({ customerId: organizationId })); |
| 193 | // Plans that predate seat pricing have no members balance to set. |
| 194 | // Existing subscribers stay on those versions deliberately, so this is |
| 195 | // a steady state, not an error. |
| 196 | if (customer.balances["members"] == null) { |
| 197 | yield* Effect.annotateCurrentSpan({ "autumn.members.skipped": true }); |
| 198 | return; |
| 199 | } |
| 200 | yield* use((c) => |
| 201 | c.balances.update({ customerId: organizationId, featureId: "members", usage: seats }), |
| 202 | ); |
| 203 | }).pipe( |
| 204 | Effect.catch((error) => |
| 205 | Effect.gen(function* () { |
| 206 | // Silent seat drift means wrong invoices, so failures page just |
| 207 | // like a lost execution track. |
| 208 | yield* Effect.sync(() => { |
| 209 | console.error("[billing] seat sync failed:", error); |
| 210 | }); |
| 211 | yield* captureCauseEffect(error); |
| 212 | yield* Effect.annotateCurrentSpan({ "autumn.members.failed": true }); |
| 213 | }), |
| 214 | ), |
| 215 | Effect.withSpan("autumn.setMemberSeats"), |
| 216 | ); |
| 217 | |
| 218 | const checkExecutionBalance = (organizationId: string) => |
| 219 | Effect.gen(function* () { |
nothing calls this directly
no test coverage detected