MCPcopy Create free account
hub / github.com/UsefulSoftwareCo/executor / removeClient

Function removeClient

packages/core/sdk/src/oauth-service.ts:1129–1205  ·  view source on GitHub ↗
(
    owner: Owner,
    slug: OAuthClientSlug,
  )

Source from the content-addressed store, hash-verified

1127 // op never cascades into connections).
1128 // -----------------------------------------------------------------------
1129 const removeClient = (
1130 owner: Owner,
1131 slug: OAuthClientSlug,
1132 ): Effect.Effect<void, OrgWriteDeniedError | StorageFailure> =>
1133 Effect.gen(function* () {
1134 // Config-declared apps have no row to remove; removing one is an env
1135 // change on the host, not a storage operation. Fail loudly rather than
1136 // returning a success that changed nothing.
1137 if (isFirstPartyOAuthClientSlug(String(slug))) {
1138 return yield* new StorageError({
1139 message: `OAuth client "${String(slug)}" is a first-party app declared in host config; it cannot be removed through this surface.`,
1140 cause: undefined,
1141 });
1142 }
1143 yield* deps.guardOrgWrite(owner);
1144 // "Is there an app at (owner, slug) right now?" — asked twice, for two
1145 // different reasons. Before the delete it says whether this call removes
1146 // anything at all; after the commit it says whether the secret key still
1147 // belongs to the app this call removed.
1148 const findClientRow = deps.fuma.use("oauth_client.findFirst", (db) =>
1149 looseDb(db).findFirst("oauth_client", {
1150 where: (b: any) => b.and(b("owner", "=", owner), b("slug", "=", String(slug))),
1151 }),
1152 );
1153
1154 const removedRow = yield* deps.fuma.transaction(
1155 Effect.gen(function* () {
1156 const existing = yield* findClientRow;
1157 yield* deps.fuma
1158 .use("oauth_client.delete", (db) =>
1159 looseDb(db).deleteMany("oauth_client", {
1160 where: (b: any) => b.and(b("owner", "=", owner), b("slug", "=", String(slug))),
1161 }),
1162 )
1163 .pipe(Effect.asVoid);
1164 return existing;
1165 }),
1166 );
1167 // Nothing matched, so this call removed nothing and owns no secret. The
1168 // idempotent no-op and the cross-subject miss both land here, and both
1169 // used to queue a delete of a key they never had a claim on.
1170 if (!removedRow) return;
1171 // Best-effort: drop the secret from the provider so it isn't orphaned.
1172 //
1173 // Deferred to the outermost commit. This function opens no transaction of
1174 // its own, but a caller can wrap it in one — and `provider.delete` reaches
1175 // a store that does not roll back with it. An abort would then restore the
1176 // client row while its secret stayed destroyed, leaving a client that
1177 // looks configured and can never authenticate again. Orphaning a secret is
1178 // recoverable; deleting one that is still referenced is not, so the
1179 // deletion waits until the row's removal is durable. With no transaction
1180 // active `afterCommit` runs it immediately, which is the behaviour this
1181 // path already had.
1182 const provider = deps.defaultWritableProvider();
1183 const dropSecret = provider?.delete;
1184 if (provider && dropSecret) {
1185 yield* afterCommit(
1186 Effect.gen(function* () {

Callers

nothing calls this directly

Calls 5

afterCommitFunction · 0.90
looseDbFunction · 0.85
callMethod · 0.80
transactionMethod · 0.65

Tested by

no test coverage detected