(
pluginId: string,
input: RegisterIntegrationInput,
)
| 3211 | config.onIntegrationChange ? afterCommit(config.onIntegrationChange(event)) : Effect.void; |
| 3212 | |
| 3213 | const integrationsRegister = ( |
| 3214 | pluginId: string, |
| 3215 | input: RegisterIntegrationInput, |
| 3216 | ): Effect.Effect<void, OrgWriteDeniedError | StorageFailure> => |
| 3217 | transaction( |
| 3218 | Effect.gen(function* () { |
| 3219 | const now = new Date(); |
| 3220 | const existing = yield* findIntegrationRow(input.slug); |
| 3221 | const config = input.config === undefined ? null : input.config; |
| 3222 | if (existing) { |
| 3223 | // Extension methods also run for subjectless boot/system executors, |
| 3224 | // which must be able to converge existing catalog rows. A bound |
| 3225 | // subject is an end-user principal, so its replacement is the same |
| 3226 | // workspace mutation as creation and requires the live role guard. |
| 3227 | if (subject !== null) yield* guardOrgWrite(); |
| 3228 | yield* core.updateMany("integration", { |
| 3229 | where: (b: AnyCb) => b("slug", "=", String(input.slug)), |
| 3230 | set: { |
| 3231 | plugin_id: pluginId, |
| 3232 | name: input.name ?? existing.name ?? null, |
| 3233 | description: input.description, |
| 3234 | config, |
| 3235 | can_remove: input.canRemove ?? Boolean(existing.can_remove), |
| 3236 | can_refresh: input.canRefresh ?? Boolean(existing.can_refresh), |
| 3237 | updated_at: now, |
| 3238 | }, |
| 3239 | }); |
| 3240 | return false; |
| 3241 | } |
| 3242 | // A NEW catalog row is always user intent (the add-integration |
| 3243 | // flows), including from a subjectless executor. |
| 3244 | yield* guardOrgWrite(); |
| 3245 | yield* core.create("integration", { |
| 3246 | tenant, |
| 3247 | slug: String(input.slug), |
| 3248 | plugin_id: pluginId, |
| 3249 | name: input.name ?? null, |
| 3250 | description: input.description, |
| 3251 | config, |
| 3252 | can_remove: input.canRemove ?? true, |
| 3253 | can_refresh: input.canRefresh ?? false, |
| 3254 | created_at: now, |
| 3255 | updated_at: now, |
| 3256 | }); |
| 3257 | return true; |
| 3258 | }), |
| 3259 | ).pipe( |
| 3260 | Effect.tap((created) => |
| 3261 | created |
| 3262 | ? notifyIntegrationChange({ |
| 3263 | kind: "added", |
| 3264 | pluginKey: pluginId, |
| 3265 | slug: input.slug, |
| 3266 | }) |
| 3267 | : Effect.void, |
| 3268 | ), |
| 3269 | Effect.asVoid, |
| 3270 | ); |
no test coverage detected