(owner: Owner, slug: OAuthClientSlug)
| 895 | // op never cascades into connections). |
| 896 | // ----------------------------------------------------------------------- |
| 897 | const removeClient = (owner: Owner, slug: OAuthClientSlug): Effect.Effect<void, StorageFailure> => |
| 898 | Effect.gen(function* () { |
| 899 | // Config-declared apps have no row to remove; removing one is an env |
| 900 | // change on the host, not a storage operation. Fail loudly rather than |
| 901 | // returning a success that changed nothing. |
| 902 | if (isFirstPartyOAuthClientSlug(String(slug))) { |
| 903 | return yield* new StorageError({ |
| 904 | message: `OAuth client "${String(slug)}" is a first-party app declared in host config; it cannot be removed through this surface.`, |
| 905 | cause: undefined, |
| 906 | }); |
| 907 | } |
| 908 | yield* deps.fuma |
| 909 | .use("oauth_client.delete", (db) => |
| 910 | looseDb(db).deleteMany("oauth_client", { |
| 911 | where: (b: any) => b.and(b("owner", "=", owner), b("slug", "=", String(slug))), |
| 912 | }), |
| 913 | ) |
| 914 | .pipe(Effect.asVoid); |
| 915 | // Best-effort: drop the secret from the provider so it isn't orphaned. |
| 916 | const provider = deps.defaultWritableProvider(); |
| 917 | if (provider?.delete) { |
| 918 | yield* provider |
| 919 | .delete(ProviderItemId.make(clientSecretItemId(owner, slug))) |
| 920 | .pipe(Effect.catch(() => Effect.void)); |
| 921 | } |
| 922 | }); |
| 923 | |
| 924 | // ----------------------------------------------------------------------- |
| 925 | // registerDynamicClient — RFC 7591 Dynamic Client Registration. |
nothing calls this directly
no test coverage detected