@almadar/integrations 2.38.0 → 2.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { e as IntegrationLogger, c as IntegrationErrorCode, a as IntegrationConfig, B as BaseIntegration, d as IntegrationFactory, g as IntegrationParams, h as IntegrationResult, I as IntegrationCallContext } from './BaseIntegration-CWdas-N_.js';
2
2
  export { b as IntegrationError, f as IntegrationParamValue, U as UnknownActionError, V as ValidationError, i as ValidationResult, j as getIntegrationFactory, r as resetIntegrationFactory, v as validateParams } from './BaseIntegration-CWdas-N_.js';
3
- import { e as CredentialStore, d as CredentialPersistence, H as HookDeclaration } from './store-RNvxZO-q.js';
4
- export { A as ArxivActions, C as CLIActions, a as CREDENTIAL_ENTITY_TYPE, b as CREDENTIAL_MASTER_KEY_ENV, c as CredentialEntry, D as DatabaseActions, f as DatabaseDriver, g as DatabaseQueryParamValue, h as DatabaseQueryParams, i as DatabaseQueryResult, j as DatabaseRow, k as DeepAgentActions, l as DockerActions, E as EmailActions, G as GitHubActions, I as IconifyActions, m as IntegrationActionName, n as IntegrationContracts, o as IntegrationName, L as LLMIntegrationActions, M as MLActions, O as OAuthActions, p as OtelActions, Q as QueueActions, R as RedisActions, S as StorageActions, q as StripeActions, T as TwilioActions, W as WebhookActions, r as WikimediaActions, Y as YouTubeActions, s as allCredentialEnvVars, t as declaredCredentialEnvVars, u as serviceHooks } from './store-RNvxZO-q.js';
3
+ import { e as CredentialStore, d as CredentialPersistence, H as HookDeclaration } from './store-DG5OGiuQ.js';
4
+ export { A as ArxivActions, C as CLIActions, a as CREDENTIAL_ENTITY_TYPE, b as CREDENTIAL_MASTER_KEY_ENV, c as CredentialEntry, D as DatabaseActions, f as DatabaseDriver, g as DatabaseQueryParamValue, h as DatabaseQueryParams, i as DatabaseQueryResult, j as DatabaseRow, k as DeepAgentActions, l as DockerActions, E as EmailActions, G as GitHubActions, I as IconifyActions, m as IntegrationActionName, n as IntegrationContracts, o as IntegrationName, L as LLMIntegrationActions, M as MLActions, O as OAuthActions, p as OtelActions, Q as QueueActions, R as RedisActions, S as StorageActions, q as StripeActions, T as TwilioActions, W as WebhookActions, r as WikimediaActions, Y as YouTubeActions, s as allCredentialEnvVars, t as declaredCredentialEnvVars, u as serviceHooks } from './store-DG5OGiuQ.js';
5
5
  import { LogMeta, EntityRow, EventPayload } from '@almadar/core';
6
6
  export { GitHubIntegration } from './integrations/github/index.js';
7
7
 
@@ -61,6 +61,11 @@ declare function isKnownIntegration(name: string): boolean;
61
61
  */
62
62
  declare function getRegisteredIntegrations(): string[];
63
63
 
64
+ /**
65
+ * Run `fn` as one tenant of a multi-tenant host: every credential reference resolved inside it
66
+ * (across awaits) comes from `store` alone, never from the host's env or installed store.
67
+ */
68
+ declare function runWithCredentialScope<T>(store: CredentialStore, fn: () => T): T;
64
69
  /**
65
70
  * The factory the host's `RuntimeIntegrationManager` configures — installed
66
71
  * by its constructor so the `credentials.test` probe executes through the
@@ -79,7 +84,8 @@ declare function getInstalledCredentialStore(): CredentialStore | null;
79
84
  /** Testing/reset hook. */
80
85
  declare function uninstallCredentialStore(): void;
81
86
  /**
82
- * The one credential-reference resolver: store → env → undefined.
87
+ * The one credential-reference resolver: store → env → undefined; inside a tenant's
88
+ * credential scope, that tenant's store only.
83
89
  * `ref` is an env-var name — the same name `serviceCredentials` declares and
84
90
  * `connectionRef` params carry. Every place that used to read
85
91
  * `process.env[ref]` for a credential routes through here.
@@ -766,11 +772,44 @@ declare class OtelIntegration extends BaseIntegration {
766
772
 
767
773
  /** Supported OAuth providers */
768
774
  type OAuthProvider = 'google' | 'github' | 'auth0';
775
+ /** `token` result: the grant's tokens plus the scopes granted and the subject bound at `authorize`. */
776
+ interface OAuthTokenResult {
777
+ accessToken: string;
778
+ refreshToken: string;
779
+ expiresIn: number;
780
+ tokenType: 'bearer';
781
+ scope: string[];
782
+ subject?: string;
783
+ }
784
+ /** `authorize` input: `subject` is the opaque id of whoever starts the flow, handed back by `token`. */
785
+ interface OAuthAuthorizeInput {
786
+ provider: OAuthProvider;
787
+ scopes: string[];
788
+ redirectUri: string;
789
+ subject?: string;
790
+ }
791
+ /** `token` input: the provider's code, the `state` returned by `authorize`, and who is completing. */
792
+ interface OAuthTokenInput {
793
+ code: string;
794
+ state: string;
795
+ /** Must equal the grant's bound subject; checked before any code exchange. */
796
+ subject?: string;
797
+ }
798
+ /** No pending grant for this `state`: never issued, already used, or expired. */
799
+ declare class OAuthGrantNotFoundError extends Error {
800
+ constructor(state: string);
801
+ }
802
+ /** The completing subject is not the one bound at `authorize`; the grant is consumed, nothing exchanged. */
803
+ declare class OAuthSubjectMismatchError extends Error {
804
+ constructor();
805
+ }
769
806
  /** Server-held per-authorization state (never leaves the process). */
770
807
  interface PendingAuthorization {
771
808
  provider: OAuthProvider;
772
809
  redirectUri: string;
773
810
  pkceVerifier: string;
811
+ /** Opaque id the host bound at `authorize` (the verified user who started); `token` returns it. */
812
+ subject?: string;
774
813
  }
775
814
  /**
776
815
  * Where pending OIDC authorizations (PKCE verifier, redirect URI) live
@@ -814,7 +853,7 @@ declare function installPendingGrantStore(store: PendingGrantStore | null): void
814
853
  * and single-use.
815
854
  */
816
855
  declare class OAuthIntegration extends BaseIntegration {
817
- /** Maps state token -> provider for pending MOCK authorization flows */
856
+ /** Maps state token -> pending MOCK authorization */
818
857
  private states;
819
858
  /** Maps access token -> token set (mock backend) */
820
859
  private tokens;
@@ -832,6 +871,13 @@ declare class OAuthIntegration extends BaseIntegration {
832
871
  private readonly real;
833
872
  constructor(config: IntegrationConfig);
834
873
  execute(action: string, params: IntegrationParams): Promise<IntegrationResult>;
874
+ /** Build the provider authorization URL and hold the pending grant (PKCE verifier, subject) under `state`. */
875
+ startAuthorization(input: OAuthAuthorizeInput): Promise<{
876
+ authUrl: string;
877
+ state: string;
878
+ }>;
879
+ /** Consume the pending grant once and exchange the code; throws on an unknown, replayed or expired `state`. */
880
+ completeAuthorization(input: OAuthTokenInput): Promise<OAuthTokenResult>;
835
881
  private issuerFor;
836
882
  private configurationFor;
837
883
  private oidcAuthorize;
@@ -1039,4 +1085,4 @@ declare class RiggerIntegration extends BaseIntegration {
1039
1085
  private generate;
1040
1086
  }
1041
1087
 
1042
- export { AccountingIntegration, type AlmadarCheckoutSession, type AlmadarCustomer, type AlmadarInvoiceFailure, type AlmadarInvoicePayment, type AlmadarPortalSession, type AlmadarStripeEvent, type AlmadarStripeEventOk, type AlmadarSubscription, type AlmadarSubscriptionStatus, type AlmadarTier, ArxivIntegration, type ArxivResult, BankingIntegration, BaseIntegration, CLIIntegration, CREDENTIALS_FILE_ENV, CalendarIntegration, type CancelSubscriptionInput, ConsoleLogger, type CreateCheckoutInput, type CreateCustomerInput, type CreatePortalInput, CredentialPersistence, CredentialStore, CredentialsIntegration, DatabaseIntegration, DeepAgentIntegration, DockerIntegration, DriveIntegration, EmailIntegration, EsignIntegration, FileCredentialPersistence, HookDeclaration, type HookProviderInput, type HookProviderResult, IconifyIntegration, InMemoryPendingGrantStore, IntegrationCallContext, IntegrationConfig, type IntegrationConstructor, IntegrationErrorCode, IntegrationFactory, IntegrationLogger, IntegrationParams, IntegrationResult, LLMIntegration, MLIntegration, MetaAdsIntegration, OAuthIntegration, OtelIntegration, type PendingGrantStore, PushIntegration, QueueIntegration, RedisIntegration, type RegisteredHookProvider, type RetryConfig, RiggerIntegration, type SqlGuardResult, StorageIntegration, StripeIntegration, type StripePriceMap, TwilioIntegration, type UpdateSubscriptionInput, type VerifyAndParseInput, WebhookIntegration, WikimediaIntegration, YouTubeIntegration, allHookDeclarations, assertReadOnlySelect, getActiveFactory, getInstalledCredentialStore, getIntegration, getRegisteredIntegrations, googleCalendarHookProvider, installActiveFactory, installCredentialStore, installPendingGrantStore, isKnownIntegration, parseCalendarPushNotification, registerIntegration, registeredHookProviders, resolveCredentialRef, uninstallCredentialStore, verifyAndParseStripeEvent, withRetry };
1088
+ export { AccountingIntegration, type AlmadarCheckoutSession, type AlmadarCustomer, type AlmadarInvoiceFailure, type AlmadarInvoicePayment, type AlmadarPortalSession, type AlmadarStripeEvent, type AlmadarStripeEventOk, type AlmadarSubscription, type AlmadarSubscriptionStatus, type AlmadarTier, ArxivIntegration, type ArxivResult, BankingIntegration, BaseIntegration, CLIIntegration, CREDENTIALS_FILE_ENV, CalendarIntegration, type CancelSubscriptionInput, ConsoleLogger, type CreateCheckoutInput, type CreateCustomerInput, type CreatePortalInput, CredentialPersistence, CredentialStore, CredentialsIntegration, DatabaseIntegration, DeepAgentIntegration, DockerIntegration, DriveIntegration, EmailIntegration, EsignIntegration, FileCredentialPersistence, HookDeclaration, type HookProviderInput, type HookProviderResult, IconifyIntegration, InMemoryPendingGrantStore, IntegrationCallContext, IntegrationConfig, type IntegrationConstructor, IntegrationErrorCode, IntegrationFactory, IntegrationLogger, IntegrationParams, IntegrationResult, LLMIntegration, MLIntegration, MetaAdsIntegration, type OAuthAuthorizeInput, OAuthGrantNotFoundError, OAuthIntegration, type OAuthProvider, OAuthSubjectMismatchError, type OAuthTokenInput, type OAuthTokenResult, OtelIntegration, type PendingAuthorization, type PendingGrantStore, PushIntegration, QueueIntegration, RedisIntegration, type RegisteredHookProvider, type RetryConfig, RiggerIntegration, type SqlGuardResult, StorageIntegration, StripeIntegration, type StripePriceMap, TwilioIntegration, type UpdateSubscriptionInput, type VerifyAndParseInput, WebhookIntegration, WikimediaIntegration, YouTubeIntegration, allHookDeclarations, assertReadOnlySelect, getActiveFactory, getInstalledCredentialStore, getIntegration, getRegisteredIntegrations, googleCalendarHookProvider, installActiveFactory, installCredentialStore, installPendingGrantStore, isKnownIntegration, parseCalendarPushNotification, registerIntegration, registeredHookProviders, resolveCredentialRef, runWithCredentialScope, uninstallCredentialStore, verifyAndParseStripeEvent, withRetry };
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { createLogger } from '@almadar/logger';
2
2
  import { integratorsRegistry } from '@almadar/core/patterns';
3
3
  import { randomBytes, createCipheriv, createDecipheriv, createHmac, createHash } from 'crypto';
4
+ import { AsyncLocalStorage } from 'async_hooks';
4
5
  import { readFileSync, mkdirSync, writeFileSync, renameSync, mkdtempSync, rmSync, promises } from 'fs';
5
6
  import { join, dirname } from 'path';
6
7
  import Stripe from 'stripe';
@@ -132,8 +133,8 @@ var serviceCredentials = {
132
133
  { envVar: "REDIS_URL", required: true, description: "Redis connection URL" }
133
134
  ],
134
135
  oauth: [
135
- { envVar: "OAUTH_CLIENT_ID", required: true, description: "OIDC client ID" },
136
- { envVar: "OAUTH_CLIENT_SECRET", required: true, description: "OIDC client secret" },
136
+ { envVar: "OAUTH_CLIENT_ID", required: true, description: "OAuth/OIDC client ID" },
137
+ { envVar: "OAUTH_CLIENT_SECRET", required: true, description: "OAuth/OIDC client secret" },
137
138
  { envVar: "OAUTH_REDIRECT_URI", required: false, description: "OIDC redirect URI (default per-call param)" },
138
139
  { envVar: "OIDC_ISSUER_URL", required: false, description: "OIDC issuer URL (default https://accounts.google.com)" }
139
140
  ],
@@ -412,8 +413,7 @@ function isKnownIntegration(name) {
412
413
  function getRegisteredIntegrations() {
413
414
  return Object.keys(INTEGRATION_REGISTRY);
414
415
  }
415
-
416
- // src/factory.ts
416
+ var callLog = createLogger("almadar:integrations:calls");
417
417
  function instanceKey(name, principal) {
418
418
  return principal ? `${name}\0${principal}` : name;
419
419
  }
@@ -458,8 +458,16 @@ var IntegrationFactory = class {
458
458
  * Execute an action on an integration
459
459
  */
460
460
  async execute(integration, action, params, context) {
461
- const instance = this.get(integration, context?.principal);
462
- return await instance.execute(action, params, context);
461
+ const start = performance.now();
462
+ const record = (ok, error) => callLog.call({ kind: "external", service: integration, op: action, durationMs: performance.now() - start, ok, ...error !== void 0 ? { error } : {} });
463
+ try {
464
+ const result = await this.get(integration, context?.principal).execute(action, params, context);
465
+ record(result.success, result.success ? void 0 : result.error?.message);
466
+ return result;
467
+ } catch (err) {
468
+ record(false, err instanceof Error ? err.message : String(err));
469
+ throw err;
470
+ }
463
471
  }
464
472
  /**
465
473
  * Check if integration is configured
@@ -736,9 +744,11 @@ var CredentialStore = class {
736
744
  return true;
737
745
  }
738
746
  };
739
-
740
- // src/credentials/resolver.ts
741
747
  var installedStore = null;
748
+ var tenantScope = new AsyncLocalStorage();
749
+ function runWithCredentialScope(store, fn) {
750
+ return tenantScope.run(store, fn);
751
+ }
742
752
  var activeFactory = null;
743
753
  function installActiveFactory(factory) {
744
754
  activeFactory = factory;
@@ -756,6 +766,8 @@ function uninstallCredentialStore() {
756
766
  installedStore = null;
757
767
  }
758
768
  function resolveCredentialRef(ref, env = process.env) {
769
+ const tenant = tenantScope.getStore();
770
+ if (tenant) return tenant.resolve(ref);
759
771
  return installedStore?.resolve(ref) ?? env[ref];
760
772
  }
761
773
  var CREDENTIALS_FILE_ENV = "ALMADAR_CREDENTIALS_FILE";
@@ -4029,6 +4041,31 @@ var PROVIDER_AUTH_URLS = {
4029
4041
  var PROVIDER_ISSUERS = {
4030
4042
  google: "https://accounts.google.com"
4031
4043
  };
4044
+ var PROVIDER_SERVER_METADATA = {
4045
+ github: {
4046
+ issuer: "https://github.com",
4047
+ authorization_endpoint: "https://github.com/login/oauth/authorize",
4048
+ token_endpoint: "https://github.com/login/oauth/access_token"
4049
+ }
4050
+ };
4051
+ var OAuthGrantNotFoundError = class extends Error {
4052
+ constructor(state) {
4053
+ super(`Invalid or expired state token: ${state}`);
4054
+ this.name = "OAuthGrantNotFoundError";
4055
+ }
4056
+ };
4057
+ var OAuthSubjectMismatchError = class extends Error {
4058
+ constructor() {
4059
+ super("OAuth completion refused: the completing subject is not the one that started the authorization");
4060
+ this.name = "OAuthSubjectMismatchError";
4061
+ }
4062
+ };
4063
+ function assertSubject(bound, completer) {
4064
+ if (bound !== completer) throw new OAuthSubjectMismatchError();
4065
+ }
4066
+ function grantedScopes(scope) {
4067
+ return (scope ?? "").split(/[\s,]+/).filter((s) => s.length > 0);
4068
+ }
4032
4069
  var PENDING_GRANT_TTL_MS = 10 * 60 * 1e3;
4033
4070
  var InMemoryPendingGrantStore = class {
4034
4071
  constructor() {
@@ -4057,7 +4094,7 @@ function installPendingGrantStore(store) {
4057
4094
  var OAuthIntegration = class extends BaseIntegration {
4058
4095
  constructor(config) {
4059
4096
  super(config);
4060
- /** Maps state token -> provider for pending MOCK authorization flows */
4097
+ /** Maps state token -> pending MOCK authorization */
4061
4098
  this.states = /* @__PURE__ */ new Map();
4062
4099
  /** Maps access token -> token set (mock backend) */
4063
4100
  this.tokens = /* @__PURE__ */ new Map();
@@ -4086,12 +4123,25 @@ var OAuthIntegration = class extends BaseIntegration {
4086
4123
  try {
4087
4124
  let data;
4088
4125
  switch (action) {
4089
- case "authorize":
4090
- data = await this.executeWithRetry(() => this.real ? this.oidcAuthorize(params) : this.authorize(params));
4126
+ case "authorize": {
4127
+ const input = {
4128
+ provider: params.provider,
4129
+ scopes: params.scopes,
4130
+ redirectUri: params.redirectUri,
4131
+ ...params.subject === void 0 ? {} : { subject: params.subject }
4132
+ };
4133
+ data = await this.executeWithRetry(() => this.startAuthorization(input));
4091
4134
  break;
4092
- case "token":
4093
- data = await this.executeWithRetry(() => this.real ? this.oidcToken(params) : this.token(params));
4135
+ }
4136
+ case "token": {
4137
+ const input = {
4138
+ code: params.code,
4139
+ state: params.state,
4140
+ ...params.subject === void 0 ? {} : { subject: params.subject }
4141
+ };
4142
+ data = await this.executeWithRetry(() => this.completeAuthorization(input));
4094
4143
  break;
4144
+ }
4095
4145
  case "refresh":
4096
4146
  data = await this.executeWithRetry(() => this.real ? this.oidcRefresh(params) : this.refresh(params));
4097
4147
  break;
@@ -4113,6 +4163,14 @@ var OAuthIntegration = class extends BaseIntegration {
4113
4163
  return this.handleError(action, error);
4114
4164
  }
4115
4165
  }
4166
+ /** Build the provider authorization URL and hold the pending grant (PKCE verifier, subject) under `state`. */
4167
+ async startAuthorization(input) {
4168
+ return this.real ? this.oidcAuthorize(input) : this.authorize(input);
4169
+ }
4170
+ /** Consume the pending grant once and exchange the code; throws on an unknown, replayed or expired `state`. */
4171
+ async completeAuthorization(input) {
4172
+ return this.real ? this.oidcToken(input) : this.token(input);
4173
+ }
4116
4174
  // ---------------------------------------------------------------------------
4117
4175
  // OIDC backend (openid-client)
4118
4176
  // ---------------------------------------------------------------------------
@@ -4128,6 +4186,19 @@ var OAuthIntegration = class extends BaseIntegration {
4128
4186
  return issuer;
4129
4187
  }
4130
4188
  async configurationFor(provider) {
4189
+ const metadata = PROVIDER_SERVER_METADATA[provider];
4190
+ if (metadata && !this.config.env.OIDC_ISSUER_URL) {
4191
+ const cached2 = this.discovered.get(metadata.issuer);
4192
+ if (cached2) return cached2;
4193
+ const configuration2 = new oidc.Configuration(
4194
+ metadata,
4195
+ this.config.env.OAUTH_CLIENT_ID,
4196
+ this.config.env.OAUTH_CLIENT_SECRET,
4197
+ oidc.ClientSecretPost(this.config.env.OAUTH_CLIENT_SECRET)
4198
+ );
4199
+ this.discovered.set(metadata.issuer, configuration2);
4200
+ return configuration2;
4201
+ }
4131
4202
  const issuer = this.issuerFor(provider);
4132
4203
  const cached = this.discovered.get(issuer);
4133
4204
  if (cached) return cached;
@@ -4139,10 +4210,9 @@ var OAuthIntegration = class extends BaseIntegration {
4139
4210
  this.discovered.set(issuer, configuration);
4140
4211
  return configuration;
4141
4212
  }
4142
- async oidcAuthorize(params) {
4143
- const provider = params.provider;
4144
- const scopes = params.scopes;
4145
- const redirectUri = params.redirectUri || this.config.env.OAUTH_REDIRECT_URI;
4213
+ async oidcAuthorize(input) {
4214
+ const { provider, scopes, subject } = input;
4215
+ const redirectUri = input.redirectUri || this.config.env.OAUTH_REDIRECT_URI;
4146
4216
  const configuration = await this.configurationFor(provider);
4147
4217
  const state = oidc.randomState();
4148
4218
  const pkceVerifier = oidc.randomPKCECodeVerifier();
@@ -4159,17 +4229,21 @@ var OAuthIntegration = class extends BaseIntegration {
4159
4229
  parameters.prompt = "consent";
4160
4230
  }
4161
4231
  const authUrl = oidc.buildAuthorizationUrl(configuration, parameters);
4162
- await this.pendingStore().put(state, { provider, redirectUri, pkceVerifier }, PENDING_GRANT_TTL_MS);
4232
+ await this.pendingStore().put(
4233
+ state,
4234
+ { provider, redirectUri, pkceVerifier, ...subject === void 0 ? {} : { subject } },
4235
+ PENDING_GRANT_TTL_MS
4236
+ );
4163
4237
  void this.pendingStore().sweep();
4164
4238
  return { authUrl: authUrl.toString(), state };
4165
4239
  }
4166
- async oidcToken(params) {
4167
- const code = params.code;
4168
- const state = params.state;
4240
+ async oidcToken(input) {
4241
+ const { code, state } = input;
4169
4242
  const pendingAuth = await this.pendingStore().take(state);
4170
4243
  if (!pendingAuth) {
4171
- throw new Error(`Invalid or expired state token: ${state}`);
4244
+ throw new OAuthGrantNotFoundError(state);
4172
4245
  }
4246
+ assertSubject(pendingAuth.subject, input.subject);
4173
4247
  const configuration = await this.configurationFor(pendingAuth.provider);
4174
4248
  const callbackUrl = new URL(pendingAuth.redirectUri);
4175
4249
  callbackUrl.searchParams.set("code", code);
@@ -4186,7 +4260,9 @@ var OAuthIntegration = class extends BaseIntegration {
4186
4260
  accessToken: tokens.access_token,
4187
4261
  refreshToken: tokens.refresh_token ?? "",
4188
4262
  expiresIn: tokens.expires_in ?? 3600,
4189
- tokenType: "bearer"
4263
+ tokenType: "bearer",
4264
+ scope: grantedScopes(tokens.scope),
4265
+ ...pendingAuth.subject === void 0 ? {} : { subject: pendingAuth.subject }
4190
4266
  };
4191
4267
  }
4192
4268
  async oidcRefresh(params) {
@@ -4249,13 +4325,11 @@ var OAuthIntegration = class extends BaseIntegration {
4249
4325
  // ---------------------------------------------------------------------------
4250
4326
  // Mock backend actions
4251
4327
  // ---------------------------------------------------------------------------
4252
- async authorize(params) {
4253
- const provider = params.provider;
4254
- const scopes = params.scopes;
4255
- const redirectUri = params.redirectUri;
4328
+ async authorize(input) {
4329
+ const { provider, scopes, redirectUri, subject } = input;
4256
4330
  this.logger.debug("OAuth AUTHORIZE", { provider, scopes: scopes.join(", "), redirectUri });
4257
4331
  const state = this.generateToken(16);
4258
- this.states.set(state, provider);
4332
+ this.states.set(state, { provider, scopes, ...subject === void 0 ? {} : { subject } });
4259
4333
  const baseUrl = PROVIDER_AUTH_URLS[provider];
4260
4334
  const queryParams = new URLSearchParams({
4261
4335
  response_type: "code",
@@ -4267,17 +4341,15 @@ var OAuthIntegration = class extends BaseIntegration {
4267
4341
  const authUrl = `${baseUrl}?${queryParams.toString()}`;
4268
4342
  return { authUrl, state };
4269
4343
  }
4270
- async token(params) {
4271
- const code = params.code;
4272
- const state = params.state;
4344
+ async token(input) {
4345
+ const { code, state } = input;
4273
4346
  this.logger.debug("OAuth TOKEN", { code, state });
4274
- const provider = this.states.get(state);
4275
- if (!provider) {
4276
- throw new Error(
4277
- `Invalid or expired state token: ${state}`
4278
- );
4347
+ const pending = this.states.get(state);
4348
+ if (!pending) {
4349
+ throw new OAuthGrantNotFoundError(state);
4279
4350
  }
4280
4351
  this.states.delete(state);
4352
+ assertSubject(pending.subject, input.subject);
4281
4353
  const accessToken = this.generateToken(32);
4282
4354
  const refreshToken = this.generateToken(32);
4283
4355
  const expiresIn = 3600;
@@ -4289,8 +4361,15 @@ var OAuthIntegration = class extends BaseIntegration {
4289
4361
  this.tokens.set(accessToken, tokenSet);
4290
4362
  this.refreshIndex.set(refreshToken, accessToken);
4291
4363
  const sub = this.generateToken(8);
4292
- this.sessions.set(accessToken, this.generateMockUser(provider, sub));
4293
- return { accessToken, refreshToken, expiresIn, tokenType: "bearer" };
4364
+ this.sessions.set(accessToken, this.generateMockUser(pending.provider, sub));
4365
+ return {
4366
+ accessToken,
4367
+ refreshToken,
4368
+ expiresIn,
4369
+ tokenType: "bearer",
4370
+ scope: pending.scopes,
4371
+ ...pending.subject === void 0 ? {} : { subject: pending.subject }
4372
+ };
4294
4373
  }
4295
4374
  async refresh(params) {
4296
4375
  const refreshToken = params.refreshToken;
@@ -5758,6 +5837,6 @@ var RiggerIntegration = class extends BaseIntegration {
5758
5837
  };
5759
5838
  registerIntegration("rigger", RiggerIntegration);
5760
5839
 
5761
- export { AccountingIntegration, ArxivIntegration, BankingIntegration, BaseIntegration, CLIIntegration, CREDENTIALS_FILE_ENV, CREDENTIAL_ENTITY_TYPE, CREDENTIAL_MASTER_KEY_ENV, CalendarIntegration, ConsoleLogger, CredentialStore, CredentialsIntegration, DatabaseIntegration, DeepAgentIntegration, DockerIntegration, DriveIntegration, EmailIntegration, EsignIntegration, FileCredentialPersistence, GitHubIntegration, IconifyIntegration, InMemoryPendingGrantStore, IntegrationError, IntegrationFactory, LLMIntegration, MLIntegration, MetaAdsIntegration, OAuthIntegration, OtelIntegration, PushIntegration, QueueIntegration, RedisIntegration, RiggerIntegration, StorageIntegration, StripeIntegration, TwilioIntegration, UnknownActionError, WebhookIntegration, WikimediaIntegration, YouTubeIntegration, allCredentialEnvVars, allHookDeclarations, assertReadOnlySelect, declaredCredentialEnvVars, getActiveFactory, getInstalledCredentialStore, getIntegration, getIntegrationFactory, getRegisteredIntegrations, googleCalendarHookProvider, installActiveFactory, installCredentialStore, installPendingGrantStore, isKnownIntegration, parseCalendarPushNotification, registerIntegration, registeredHookProviders, resetIntegrationFactory, resolveCredentialRef, serviceHooks, uninstallCredentialStore, validateParams, verifyAndParseStripeEvent, withRetry };
5840
+ export { AccountingIntegration, ArxivIntegration, BankingIntegration, BaseIntegration, CLIIntegration, CREDENTIALS_FILE_ENV, CREDENTIAL_ENTITY_TYPE, CREDENTIAL_MASTER_KEY_ENV, CalendarIntegration, ConsoleLogger, CredentialStore, CredentialsIntegration, DatabaseIntegration, DeepAgentIntegration, DockerIntegration, DriveIntegration, EmailIntegration, EsignIntegration, FileCredentialPersistence, GitHubIntegration, IconifyIntegration, InMemoryPendingGrantStore, IntegrationError, IntegrationFactory, LLMIntegration, MLIntegration, MetaAdsIntegration, OAuthGrantNotFoundError, OAuthIntegration, OAuthSubjectMismatchError, OtelIntegration, PushIntegration, QueueIntegration, RedisIntegration, RiggerIntegration, StorageIntegration, StripeIntegration, TwilioIntegration, UnknownActionError, WebhookIntegration, WikimediaIntegration, YouTubeIntegration, allCredentialEnvVars, allHookDeclarations, assertReadOnlySelect, declaredCredentialEnvVars, getActiveFactory, getInstalledCredentialStore, getIntegration, getIntegrationFactory, getRegisteredIntegrations, googleCalendarHookProvider, installActiveFactory, installCredentialStore, installPendingGrantStore, isKnownIntegration, parseCalendarPushNotification, registerIntegration, registeredHookProviders, resetIntegrationFactory, resolveCredentialRef, runWithCredentialScope, serviceHooks, uninstallCredentialStore, validateParams, verifyAndParseStripeEvent, withRetry };
5762
5841
  //# sourceMappingURL=index.js.map
5763
5842
  //# sourceMappingURL=index.js.map