@feelflow/ffid-sdk 11.0.0 → 12.1.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/README.md +33 -0
- package/dist/agency/index.d.cts +19 -0
- package/dist/agency/index.d.ts +19 -0
- package/dist/{chunk-QORWLPWG.js → chunk-3MYUVPLD.js} +6 -3
- package/dist/{chunk-VR3QR64A.cjs → chunk-62MINYOA.cjs} +6 -3
- package/dist/components/index.cjs +8 -8
- package/dist/components/index.d.cts +1 -1
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.js +1 -1
- package/dist/{ffid-client-By_vcKYu.d.ts → ffid-client-5dVFeHt8.d.ts} +11 -1
- package/dist/{ffid-client-C3A8L9uW.d.cts → ffid-client-aUNBn5SW.d.cts} +11 -1
- package/dist/{index-BknVfXhZ.d.cts → index-f9k9reXO.d.cts} +2 -1
- package/dist/{index-BknVfXhZ.d.ts → index-f9k9reXO.d.ts} +2 -1
- package/dist/index.cjs +91 -91
- package/dist/index.d.cts +16 -2
- package/dist/index.d.ts +16 -2
- package/dist/index.js +2 -2
- package/dist/server/index.cjs +232 -14
- package/dist/server/index.d.cts +166 -11
- package/dist/server/index.d.ts +166 -11
- package/dist/server/index.js +224 -16
- package/dist/server/test/index.d.cts +1 -1
- package/dist/server/test/index.d.ts +1 -1
- package/dist/webhooks/index.d.cts +13 -2
- package/dist/webhooks/index.d.ts +13 -2
- package/package.json +1 -1
package/dist/server/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { F as FFIDError, a as FFIDLogger, b as FFIDCacheAdapter, c as FFIDVerifyAccessTokenOptions, d as FFIDApiResponse, e as FFIDOAuthUserInfo, f as FFIDCatalogEnvironment, g as FFIDBillingInterval, h as FFIDTaxBehavior, i as FFIDPublishedCatalog } from '../ffid-client-
|
|
2
|
-
export { j as FFIDAddMemberParams, k as FFIDAddMemberRequest, l as FFIDAddMemberResponse, m as FFIDAllowedLogoMimeType, n as FFIDAssignableMemberRole, o as FFIDCacheConfig, p as FFIDCatalogPublication, q as FFIDCatalogPublicationStatus, r as FFIDClient, s as FFIDCompanySizeCode, t as FFIDConfig, u as FFIDIndustryCode, v as FFIDListMembersResponse, w as FFIDListingConsentInput, x as FFIDLogoWallEntry, y as FFIDLogoWallResponse, z as FFIDMemberRole, A as FFIDMemberSeatAssignmentResult, B as FFIDOrganization, C as FFIDOrganizationLogoUploadResponse, D as FFIDOrganizationMember, E as FFIDOrganizationProfile, G as FFIDOrganizationProfileErrorCode, H as FFIDOrganizationProfileResponse, I as FFIDOtpSendResponse, J as FFIDOtpVerifyResponse, K as FFIDPasswordResetConfirmResponse, L as FFIDPasswordResetResponse, M as FFIDPasswordResetVerifyResponse, N as FFIDProfileCallOptions, O as FFIDProvisionMemberPlan, P as FFIDProvisionMemberPlanStatus, Q as FFIDProvisionMemberResult, R as FFIDProvisionMemberStatus, S as FFIDProvisionOrganizationDryRun, T as FFIDProvisionOrganizationMemberInput, U as FFIDProvisionOrganizationOutcome, V as FFIDProvisionOrganizationParams, W as FFIDProvisionOrganizationResponse, X as FFIDProvisionUserDryRun, Y as FFIDProvisionUserOutcome, Z as FFIDProvisionUserParams, _ as FFIDProvisionUserProfileInput, $ as FFIDProvisionUserResponse, a0 as FFIDProvisionedOrganization, a1 as FFIDProvisionedUser, a2 as FFIDPublishedPlan, a3 as FFIDRemoveMemberResponse, a4 as FFIDResetSessionResponse, a5 as FFIDSubscription, a6 as FFIDUpdateMemberRoleResponse, a7 as FFIDUpdateUserProfileRequest, a8 as FFIDUploadOrganizationLogoParams, a9 as FFIDUpsertOrganizationProfileParams, aa as FFIDUpsertOrganizationProfileRequest, ab as FFIDUser, ac as FFIDUserProfile, ad as FFID_ALLOWED_ORGANIZATION_LOGO_MIME_TYPES, ae as FFID_CATALOG_ENVIRONMENTS, af as FFID_CATALOG_PUBLICATION_STATUSES, ag as FFID_COMPANY_SIZE_CODES, ah as FFID_INDUSTRY_CODES, ai as FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_BYTES, aj as FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_MB, ak as FFID_ORGANIZATION_PROFILE_ERROR_CODES, al as TokenData, am as TokenStore, an as createFFIDClient, ao as createTokenStore } from '../ffid-client-
|
|
1
|
+
import { F as FFIDError, a as FFIDLogger, b as FFIDCacheAdapter, c as FFIDVerifyAccessTokenOptions, d as FFIDApiResponse, e as FFIDOAuthUserInfo, f as FFIDCatalogEnvironment, g as FFIDBillingInterval, h as FFIDTaxBehavior, i as FFIDPublishedCatalog } from '../ffid-client-5dVFeHt8.js';
|
|
2
|
+
export { j as FFIDAddMemberParams, k as FFIDAddMemberRequest, l as FFIDAddMemberResponse, m as FFIDAllowedLogoMimeType, n as FFIDAssignableMemberRole, o as FFIDCacheConfig, p as FFIDCatalogPublication, q as FFIDCatalogPublicationStatus, r as FFIDClient, s as FFIDCompanySizeCode, t as FFIDConfig, u as FFIDIndustryCode, v as FFIDListMembersResponse, w as FFIDListingConsentInput, x as FFIDLogoWallEntry, y as FFIDLogoWallResponse, z as FFIDMemberRole, A as FFIDMemberSeatAssignmentResult, B as FFIDOrganization, C as FFIDOrganizationLogoUploadResponse, D as FFIDOrganizationMember, E as FFIDOrganizationProfile, G as FFIDOrganizationProfileErrorCode, H as FFIDOrganizationProfileResponse, I as FFIDOtpSendResponse, J as FFIDOtpVerifyResponse, K as FFIDPasswordResetConfirmResponse, L as FFIDPasswordResetResponse, M as FFIDPasswordResetVerifyResponse, N as FFIDProfileCallOptions, O as FFIDProvisionMemberPlan, P as FFIDProvisionMemberPlanStatus, Q as FFIDProvisionMemberResult, R as FFIDProvisionMemberStatus, S as FFIDProvisionOrganizationDryRun, T as FFIDProvisionOrganizationMemberInput, U as FFIDProvisionOrganizationOutcome, V as FFIDProvisionOrganizationParams, W as FFIDProvisionOrganizationResponse, X as FFIDProvisionUserDryRun, Y as FFIDProvisionUserOutcome, Z as FFIDProvisionUserParams, _ as FFIDProvisionUserProfileInput, $ as FFIDProvisionUserResponse, a0 as FFIDProvisionedOrganization, a1 as FFIDProvisionedUser, a2 as FFIDPublishedPlan, a3 as FFIDRemoveMemberResponse, a4 as FFIDResetSessionResponse, a5 as FFIDSubscription, a6 as FFIDUpdateMemberRoleResponse, a7 as FFIDUpdateUserProfileRequest, a8 as FFIDUploadOrganizationLogoParams, a9 as FFIDUpsertOrganizationProfileParams, aa as FFIDUpsertOrganizationProfileRequest, ab as FFIDUser, ac as FFIDUserProfile, ad as FFID_ALLOWED_ORGANIZATION_LOGO_MIME_TYPES, ae as FFID_CATALOG_ENVIRONMENTS, af as FFID_CATALOG_PUBLICATION_STATUSES, ag as FFID_COMPANY_SIZE_CODES, ah as FFID_INDUSTRY_CODES, ai as FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_BYTES, aj as FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_MB, ak as FFID_ORGANIZATION_PROFILE_ERROR_CODES, al as TokenData, am as TokenStore, an as createFFIDClient, ao as createTokenStore } from '../ffid-client-5dVFeHt8.js';
|
|
3
3
|
export { D as DEFAULT_API_BASE_URL, a as DEFAULT_OAUTH_SCOPES } from '../constants-Ce2eXQtB.js';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import '../types-Cjb9J0rL.js';
|
|
@@ -356,14 +356,22 @@ interface BuildAuthorizeUrlOptions {
|
|
|
356
356
|
interface BuildAuthorizeUrlResult {
|
|
357
357
|
/** Authorize URL to 302 the browser to. */
|
|
358
358
|
url: string;
|
|
359
|
-
/**
|
|
359
|
+
/**
|
|
360
|
+
* Opaque value to persist in an httpOnly cookie and pass back as
|
|
361
|
+
* `storedState`. Since 12.0.0 (#6611) it is `<state>.<code_verifier>`, not the
|
|
362
|
+
* raw OAuth `state` — do not compare it with the callback's `state` query
|
|
363
|
+
* yourself, and do not parse it; {@link ServerAuthClient.handleCallback} does.
|
|
364
|
+
*/
|
|
360
365
|
state: string;
|
|
361
366
|
}
|
|
362
367
|
/** Input to {@link ServerAuthClient.handleCallback}. */
|
|
363
368
|
interface HandleCallbackInput {
|
|
364
369
|
/** The callback request URL (absolute). `code` / `state` are read from its query. */
|
|
365
370
|
url: string | URL;
|
|
366
|
-
/**
|
|
371
|
+
/**
|
|
372
|
+
* The value previously stored in the httpOnly cookie — `result.state` from
|
|
373
|
+
* {@link ServerAuthClient.buildAuthorizeUrl}, verbatim (undefined if absent).
|
|
374
|
+
*/
|
|
367
375
|
storedState: string | undefined;
|
|
368
376
|
}
|
|
369
377
|
/**
|
|
@@ -380,14 +388,18 @@ type ServerTokenResult = {
|
|
|
380
388
|
/** Framework-agnostic confidential / BFF auth client. */
|
|
381
389
|
interface ServerAuthClient {
|
|
382
390
|
/**
|
|
383
|
-
* Build the authorize URL
|
|
384
|
-
*
|
|
385
|
-
* `
|
|
391
|
+
* Build the authorize URL with a fresh `state` and a PKCE S256
|
|
392
|
+
* `code_challenge` (#6611). The caller stores the returned `state` (which also
|
|
393
|
+
* carries the `code_verifier`) in an httpOnly cookie, then 302s to `url`.
|
|
394
|
+
* Async since 12.0.0 — the S256 challenge uses Web Crypto `subtle.digest`.
|
|
386
395
|
*/
|
|
387
|
-
buildAuthorizeUrl(opts?: BuildAuthorizeUrlOptions): BuildAuthorizeUrlResult
|
|
396
|
+
buildAuthorizeUrl(opts?: BuildAuthorizeUrlOptions): Promise<BuildAuthorizeUrlResult>;
|
|
388
397
|
/**
|
|
389
|
-
* Validate `state` (CSRF, fail-closed
|
|
390
|
-
*
|
|
398
|
+
* Validate `state` (CSRF, fail-closed; a stored value without the PKCE
|
|
399
|
+
* verifier is also a mismatch) then exchange `code` for tokens using the
|
|
400
|
+
* `client_secret` and `code_verifier` (server→server; browser JS never reads
|
|
401
|
+
* the secret, the verifier, or the tokens — the verifier and tokens travel only
|
|
402
|
+
* in httpOnly cookies, never in a URL).
|
|
391
403
|
*/
|
|
392
404
|
handleCallback(input: HandleCallbackInput): Promise<ServerTokenResult>;
|
|
393
405
|
/** Refresh tokens (`refresh_token` grant, `client_secret`-authenticated). */
|
|
@@ -637,4 +649,147 @@ declare function computeScopeHash(input: FFIDScopeHashInput): Promise<string>;
|
|
|
637
649
|
*/
|
|
638
650
|
declare function validatePublishedCatalog(catalog: unknown): asserts catalog is FFIDPublishedCatalog;
|
|
639
651
|
|
|
640
|
-
|
|
652
|
+
/**
|
|
653
|
+
* Constants for the product-side DB token minter (#6318).
|
|
654
|
+
*
|
|
655
|
+
* A product that reaches its own Supabase through supabase-js (PostgREST)
|
|
656
|
+
* mints a short-lived token for the FFID user on its server and sends it as
|
|
657
|
+
* the `Authorization: Bearer` header. Supabase validates it against the
|
|
658
|
+
* product's JWT Signing Keys and RLS reads the user from `auth.jwt()`.
|
|
659
|
+
*/
|
|
660
|
+
/** Only asymmetric signing is allowed; a shared secret (HS256) is rejected by policy. */
|
|
661
|
+
declare const FFID_DB_TOKEN_ALGORITHM: "ES256";
|
|
662
|
+
/** Supabase maps this claim to the Postgres role the request runs as. */
|
|
663
|
+
declare const FFID_DB_TOKEN_ROLE: "authenticated";
|
|
664
|
+
/** Same shape as the user tokens Supabase Auth issues (`aud` = `authenticated`). */
|
|
665
|
+
declare const FFID_DB_TOKEN_AUDIENCE: "authenticated";
|
|
666
|
+
/** Default lifetime: 5 minutes. The token is minted per request and never sent to the browser. */
|
|
667
|
+
declare const DEFAULT_DB_TOKEN_TTL_SECONDS = 300;
|
|
668
|
+
/** Hard ceiling: 15 minutes. Longer tokens defeat the "mint per request" model. */
|
|
669
|
+
declare const MAX_DB_TOKEN_TTL_SECONDS = 900;
|
|
670
|
+
/** Claim that carries the FFID organization id when the product scopes rows by organization. */
|
|
671
|
+
declare const FFID_DB_TOKEN_ORGANIZATION_CLAIM: "organization_id";
|
|
672
|
+
/**
|
|
673
|
+
* Claims the minter owns. Product-specific `claims` must not use these names,
|
|
674
|
+
* so a caller cannot forge a different user, role, or lifetime.
|
|
675
|
+
*/
|
|
676
|
+
declare const FFID_DB_TOKEN_RESERVED_CLAIMS: readonly ["sub", "role", "aud", "iss", "iat", "exp", "nbf", "jti", "organization_id"];
|
|
677
|
+
|
|
678
|
+
/**
|
|
679
|
+
* Types for the product-side DB token minter (#6318).
|
|
680
|
+
*/
|
|
681
|
+
|
|
682
|
+
/**
|
|
683
|
+
* Private P-256 JWK used to sign DB tokens. Generate it with
|
|
684
|
+
* `supabase gen signing-key --algorithm ES256`, import that private JWK into the
|
|
685
|
+
* product's Supabase JWT Signing Keys (Supabase keeps it non-extractable and
|
|
686
|
+
* publishes only the public half via JWKS), and keep the same JWK in a server
|
|
687
|
+
* environment variable. Nothing else may hold it.
|
|
688
|
+
*
|
|
689
|
+
* The CLI output also carries `use`, `key_ops` and `ext`; the minter strips
|
|
690
|
+
* those before import (WebCrypto rejects an ECDSA private key whose `key_ops`
|
|
691
|
+
* includes `verify`).
|
|
692
|
+
*/
|
|
693
|
+
interface FFIDDbTokenSigningJwk {
|
|
694
|
+
kty: 'EC';
|
|
695
|
+
crv: 'P-256';
|
|
696
|
+
/** Private scalar. Its presence is what makes this a signing key. */
|
|
697
|
+
d: string;
|
|
698
|
+
x: string;
|
|
699
|
+
y: string;
|
|
700
|
+
/** Key id. Supabase matches the token header `kid` against the imported key. */
|
|
701
|
+
kid?: string;
|
|
702
|
+
alg?: string;
|
|
703
|
+
use?: string;
|
|
704
|
+
[parameter: string]: unknown;
|
|
705
|
+
}
|
|
706
|
+
interface FFIDDbTokenMinterConfig {
|
|
707
|
+
/**
|
|
708
|
+
* The private JWK, either as an object or as the JSON string stored in an
|
|
709
|
+
* environment variable (for example `SUPABASE_JWT_SIGNING_KEY`).
|
|
710
|
+
*/
|
|
711
|
+
signingKey: string | FFIDDbTokenSigningJwk;
|
|
712
|
+
/** Overrides the JWK's `kid`. Required when the JWK has none. */
|
|
713
|
+
kid?: string;
|
|
714
|
+
/** Token lifetime. Default `DEFAULT_DB_TOKEN_TTL_SECONDS`, max `MAX_DB_TOKEN_TTL_SECONDS`. */
|
|
715
|
+
ttlSeconds?: number;
|
|
716
|
+
/** Optional `iss` claim. Supabase does not require it; set it when the product's policies read it. */
|
|
717
|
+
issuer?: string;
|
|
718
|
+
}
|
|
719
|
+
interface FFIDMintDbTokenInput {
|
|
720
|
+
/** FFID user id (UUID). Becomes `sub`, the value `private.current_ffid_user_id()` returns. */
|
|
721
|
+
userId: string;
|
|
722
|
+
/** FFID organization id (UUID). Becomes the `organization_id` claim. `null` means "none", like `FFIDUser.organizationId`. */
|
|
723
|
+
organizationId?: string | null;
|
|
724
|
+
/** Product-specific claims. Reserved names (`FFID_DB_TOKEN_RESERVED_CLAIMS`) are rejected. */
|
|
725
|
+
claims?: Record<string, unknown>;
|
|
726
|
+
/** Clock override for tests. Defaults to `new Date()`. An Invalid Date is rejected (`INVALID_CLOCK`). */
|
|
727
|
+
now?: Date;
|
|
728
|
+
}
|
|
729
|
+
interface FFIDDbTokenClaims {
|
|
730
|
+
sub: string;
|
|
731
|
+
role: typeof FFID_DB_TOKEN_ROLE;
|
|
732
|
+
aud: typeof FFID_DB_TOKEN_AUDIENCE;
|
|
733
|
+
iat: number;
|
|
734
|
+
exp: number;
|
|
735
|
+
iss?: string;
|
|
736
|
+
organization_id?: string;
|
|
737
|
+
[claim: string]: unknown;
|
|
738
|
+
}
|
|
739
|
+
interface FFIDDbToken {
|
|
740
|
+
/** Compact JWS to send as `Authorization: Bearer <token>` to the product's Supabase. */
|
|
741
|
+
token: string;
|
|
742
|
+
/** `exp` as a `Date`. For logging / diagnostics; the client is still created per request. */
|
|
743
|
+
expiresAt: Date;
|
|
744
|
+
/** The signed payload, for logging claim names (never log the token itself). */
|
|
745
|
+
claims: FFIDDbTokenClaims;
|
|
746
|
+
}
|
|
747
|
+
interface FFIDDbTokenMinter {
|
|
748
|
+
/** Key id written to every token header. */
|
|
749
|
+
readonly kid: string;
|
|
750
|
+
/** Effective lifetime in seconds. */
|
|
751
|
+
readonly ttlSeconds: number;
|
|
752
|
+
mint(input: FFIDMintDbTokenInput): Promise<FFIDDbToken>;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
/**
|
|
756
|
+
* Creates a minter bound to one signing key. Create it once per process and
|
|
757
|
+
* call `mint()` per request.
|
|
758
|
+
*
|
|
759
|
+
* The key shape is checked synchronously here. The key material is imported on
|
|
760
|
+
* the first `mint()`; a successful import is kept for the minter's lifetime,
|
|
761
|
+
* a failed one is retried on the next `mint()`.
|
|
762
|
+
*
|
|
763
|
+
* @throws FFIDDbTokenError when the key shape or TTL is invalid.
|
|
764
|
+
*/
|
|
765
|
+
declare function createDbTokenMinter(config: FFIDDbTokenMinterConfig): FFIDDbTokenMinter;
|
|
766
|
+
|
|
767
|
+
/**
|
|
768
|
+
* Errors thrown by the product-side DB token minter (#6318).
|
|
769
|
+
*
|
|
770
|
+
* These are programming / configuration errors on the product's server, never
|
|
771
|
+
* end-user input errors. Messages never include key material.
|
|
772
|
+
*/
|
|
773
|
+
declare const FFID_DB_TOKEN_ERROR_CODES: {
|
|
774
|
+
/** Signing key is not a private P-256 JWK with a `kid`, or cannot be imported. */
|
|
775
|
+
readonly INVALID_SIGNING_KEY: "INVALID_SIGNING_KEY";
|
|
776
|
+
/** `ttlSeconds` is not a positive integer within `MAX_DB_TOKEN_TTL_SECONDS`. */
|
|
777
|
+
readonly INVALID_TTL: "INVALID_TTL";
|
|
778
|
+
/** `userId` is not a UUID. */
|
|
779
|
+
readonly INVALID_USER_ID: "INVALID_USER_ID";
|
|
780
|
+
/** `organizationId` is not a UUID. */
|
|
781
|
+
readonly INVALID_ORGANIZATION_ID: "INVALID_ORGANIZATION_ID";
|
|
782
|
+
/** A product claim uses a name the minter reserves (`sub`, `role`, `exp`, ...). */
|
|
783
|
+
readonly RESERVED_CLAIM: "RESERVED_CLAIM";
|
|
784
|
+
/** `now` is not a valid `Date` (an Invalid Date would sign `iat` / `exp` as null). */
|
|
785
|
+
readonly INVALID_CLOCK: "INVALID_CLOCK";
|
|
786
|
+
};
|
|
787
|
+
type FFIDDbTokenErrorCode = (typeof FFID_DB_TOKEN_ERROR_CODES)[keyof typeof FFID_DB_TOKEN_ERROR_CODES];
|
|
788
|
+
declare class FFIDDbTokenError extends Error {
|
|
789
|
+
readonly code: FFIDDbTokenErrorCode;
|
|
790
|
+
constructor(code: FFIDDbTokenErrorCode, message: string, options?: {
|
|
791
|
+
cause?: unknown;
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
export { ALL_DENIED_EXCEPT_NECESSARY, type BuildAuthorizeUrlOptions, type BuildAuthorizeUrlResult, CATALOG_HASH_PATTERN, CONSENT_COOKIE_NAME, COOKIE_VERSION, type CookieOptions, DEFAULT_DB_TOKEN_TTL_SECONDS, type FFIDAuthorizationError, type FFIDAuthorizationErrorDetails, FFIDCacheAdapter, type FFIDCanonicalJsonValue, FFIDCatalogEnvironment, FFIDCatalogHashError, type FFIDConsentCategories, type FFIDConsentCategoryCode, type FFIDCookieStoreLike, type FFIDDbToken, type FFIDDbTokenClaims, FFIDDbTokenError, type FFIDDbTokenErrorCode, type FFIDDbTokenMinter, type FFIDDbTokenMinterConfig, type FFIDDbTokenSigningJwk, type FFIDErrorCode, type FFIDMintDbTokenInput, type FFIDOAuthDenialReason, FFIDOAuthUserInfo, type FFIDPaymentConfiguration, FFIDPublishedCatalog, type FFIDScopeHashInput, type FFIDScopeHashPlan, FFIDTaxBehavior, type FFIDTaxConfiguration, FFIDVerifyAccessTokenOptions, FFID_DB_TOKEN_ALGORITHM, FFID_DB_TOKEN_AUDIENCE, FFID_DB_TOKEN_ERROR_CODES, FFID_DB_TOKEN_ORGANIZATION_CLAIM, FFID_DB_TOKEN_RESERVED_CLAIMS, FFID_DB_TOKEN_ROLE, FFID_ERROR_CODES, FFID_OAUTH_DENIAL_REASONS, FFID_SESSION_COOKIE_NAME, type HandleCallbackInput, type KVNamespaceLike, MAX_DB_TOKEN_TTL_SECONDS, type ServerAuthClient, type ServerAuthConfig, type ServerSessionTokens, type ServerTokenResult, canonicalizeCatalogValue, computeFFIDCheckoutCopyHash, computeLegalDisclosureHash, computePaymentConfigurationHash, computePraxisCopyHash, computeScopeHash, computeTaxConfigurationHash, createDbTokenMinter, createKVCacheAdapter, createMemoryCacheAdapter, createServerAuthClient, createVerifyAccessToken, decodeConsentCookie, encodeConsentCookie, generateServerState, getFFIDAuthorizationError, getFFIDConsentFromCookieHeader, getFFIDConsentFromCookies, hashCanonicalJson, isFFIDOAuthDenialReason, sessionCookies, sha256Hex, validatePublishedCatalog };
|
package/dist/server/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DEFAULT_API_BASE_URL } from '../chunk-JEVK2XUM.js';
|
|
2
2
|
export { DEFAULT_API_BASE_URL, DEFAULT_OAUTH_SCOPES } from '../chunk-JEVK2XUM.js';
|
|
3
|
-
import {
|
|
3
|
+
import { SignJWT, importJWK, jwtVerify, createRemoteJWKSet, errors } from 'jose';
|
|
4
4
|
|
|
5
5
|
// src/auth/token-store.ts
|
|
6
6
|
var STORAGE_KEY = "ffid_tokens";
|
|
@@ -309,13 +309,13 @@ var HTTP_SERVER_ERROR_MIN = 500;
|
|
|
309
309
|
var HTTP_SERVER_ERROR_LIMIT = 600;
|
|
310
310
|
function createVerifyAccessToken(deps) {
|
|
311
311
|
const { authMode, baseUrl, serviceCode, serviceApiKey, verifyStrategy, logger, createError, errorCodes, cache, timeout } = deps;
|
|
312
|
-
let
|
|
312
|
+
let jwtVerify3 = null;
|
|
313
313
|
let cacheReadFailureEscalated = false;
|
|
314
314
|
let cacheWriteFailureEscalated = false;
|
|
315
315
|
let missingSubtleCryptoLogged = false;
|
|
316
316
|
function getJwtVerifier() {
|
|
317
|
-
if (!
|
|
318
|
-
|
|
317
|
+
if (!jwtVerify3) {
|
|
318
|
+
jwtVerify3 = createJwtVerifier({
|
|
319
319
|
baseUrl,
|
|
320
320
|
serviceCode,
|
|
321
321
|
logger,
|
|
@@ -325,7 +325,7 @@ function createVerifyAccessToken(deps) {
|
|
|
325
325
|
errorCodes
|
|
326
326
|
});
|
|
327
327
|
}
|
|
328
|
-
return
|
|
328
|
+
return jwtVerify3;
|
|
329
329
|
}
|
|
330
330
|
async function verifyAccessToken(accessToken, options) {
|
|
331
331
|
if (authMode !== "service-key") {
|
|
@@ -573,7 +573,8 @@ function createBillingMethods(deps) {
|
|
|
573
573
|
subscriptionId: params.subscriptionId,
|
|
574
574
|
successUrl: params.successUrl,
|
|
575
575
|
cancelUrl: params.cancelUrl,
|
|
576
|
-
...params.planId ? { planId: params.planId } : {}
|
|
576
|
+
...params.planId ? { planId: params.planId } : {},
|
|
577
|
+
...params.quantity !== void 0 ? { quantity: params.quantity } : {}
|
|
577
578
|
})
|
|
578
579
|
}
|
|
579
580
|
);
|
|
@@ -1386,7 +1387,7 @@ var FFID_ORGANIZATION_PROFILE_ERROR_CODES = {
|
|
|
1386
1387
|
};
|
|
1387
1388
|
|
|
1388
1389
|
// src/client/version-check.ts
|
|
1389
|
-
var SDK_VERSION = "
|
|
1390
|
+
var SDK_VERSION = "12.1.0";
|
|
1390
1391
|
var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
|
|
1391
1392
|
var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
|
|
1392
1393
|
function sdkHeaders() {
|
|
@@ -4594,6 +4595,19 @@ function generateServerState() {
|
|
|
4594
4595
|
globalThis.crypto.getRandomValues(bytes);
|
|
4595
4596
|
return Array.from(bytes, (b) => b.toString(HEX_RADIX2).padStart(2, "0")).join("");
|
|
4596
4597
|
}
|
|
4598
|
+
var STORED_STATE_SEPARATOR = ".";
|
|
4599
|
+
function packStoredLoginHandle(handle) {
|
|
4600
|
+
return `${handle.state}${STORED_STATE_SEPARATOR}${handle.codeVerifier}`;
|
|
4601
|
+
}
|
|
4602
|
+
function unpackStoredLoginHandle(stored) {
|
|
4603
|
+
if (!stored) return null;
|
|
4604
|
+
const sep = stored.indexOf(STORED_STATE_SEPARATOR);
|
|
4605
|
+
if (sep <= 0) return null;
|
|
4606
|
+
const state = stored.slice(0, sep);
|
|
4607
|
+
const codeVerifier = stored.slice(sep + STORED_STATE_SEPARATOR.length);
|
|
4608
|
+
if (!codeVerifier) return null;
|
|
4609
|
+
return { state, codeVerifier };
|
|
4610
|
+
}
|
|
4597
4611
|
|
|
4598
4612
|
// src/server/auth/server-oauth-token.ts
|
|
4599
4613
|
var OAUTH_TOKEN_ENDPOINT2 = "/api/v1/oauth/token";
|
|
@@ -4655,7 +4669,7 @@ async function postToken(deps, body, fallbackErrorCode) {
|
|
|
4655
4669
|
}
|
|
4656
4670
|
return { tokens: toTokens(validation.tokens) };
|
|
4657
4671
|
}
|
|
4658
|
-
function exchangeAuthorizationCodeServer(deps, code) {
|
|
4672
|
+
function exchangeAuthorizationCodeServer(deps, code, codeVerifier) {
|
|
4659
4673
|
return postToken(
|
|
4660
4674
|
deps,
|
|
4661
4675
|
{
|
|
@@ -4663,7 +4677,8 @@ function exchangeAuthorizationCodeServer(deps, code) {
|
|
|
4663
4677
|
code,
|
|
4664
4678
|
client_id: deps.clientId,
|
|
4665
4679
|
client_secret: deps.clientSecret,
|
|
4666
|
-
redirect_uri: deps.redirectUri
|
|
4680
|
+
redirect_uri: deps.redirectUri,
|
|
4681
|
+
code_verifier: codeVerifier
|
|
4667
4682
|
},
|
|
4668
4683
|
FFID_ERROR_CODES.TOKEN_EXCHANGE_ERROR
|
|
4669
4684
|
);
|
|
@@ -4684,6 +4699,7 @@ function refreshTokensServer(deps, refreshToken) {
|
|
|
4684
4699
|
// src/server/auth/server-auth-client.ts
|
|
4685
4700
|
var OAUTH_AUTHORIZE_ENDPOINT2 = "/api/v1/oauth/authorize";
|
|
4686
4701
|
var SCREEN_HINT_SIGNUP2 = "signup";
|
|
4702
|
+
var CODE_CHALLENGE_METHOD_S256 = "S256";
|
|
4687
4703
|
function createServerAuthClient(config) {
|
|
4688
4704
|
if (!config.serviceCode?.trim()) {
|
|
4689
4705
|
throw new Error("FFID Server Auth: serviceCode \u304C\u672A\u8A2D\u5B9A\u3067\u3059");
|
|
@@ -4708,20 +4724,29 @@ function createServerAuthClient(config) {
|
|
|
4708
4724
|
redirectUri: config.redirectUri,
|
|
4709
4725
|
timeout: config.timeout
|
|
4710
4726
|
};
|
|
4711
|
-
function buildAuthorizeUrl(opts) {
|
|
4727
|
+
async function buildAuthorizeUrl(opts) {
|
|
4712
4728
|
const state = generateServerState();
|
|
4729
|
+
const codeVerifier = generateCodeVerifier();
|
|
4730
|
+
const codeChallenge = await generateCodeChallenge(codeVerifier);
|
|
4713
4731
|
const params = new URLSearchParams({
|
|
4714
4732
|
response_type: "code",
|
|
4715
4733
|
client_id: clientId,
|
|
4716
4734
|
scope: config.scope,
|
|
4717
4735
|
redirect_uri: config.redirectUri,
|
|
4718
|
-
state
|
|
4736
|
+
state,
|
|
4737
|
+
code_challenge: codeChallenge,
|
|
4738
|
+
code_challenge_method: CODE_CHALLENGE_METHOD_S256
|
|
4719
4739
|
});
|
|
4720
4740
|
const organizationId = opts?.organizationId?.trim();
|
|
4721
4741
|
if (organizationId) params.set("organization_id", organizationId);
|
|
4722
4742
|
if (opts?.screenHint === SCREEN_HINT_SIGNUP2) params.set("screen_hint", SCREEN_HINT_SIGNUP2);
|
|
4723
4743
|
if (opts?.prompt) params.set("prompt", opts.prompt);
|
|
4724
|
-
return {
|
|
4744
|
+
return {
|
|
4745
|
+
url: `${apiBaseUrl}${OAUTH_AUTHORIZE_ENDPOINT2}?${params.toString()}`,
|
|
4746
|
+
// Opaque cookie value: state + verifier. Only `state` and the challenge
|
|
4747
|
+
// reach the URL; the verifier stays in the caller's httpOnly cookie.
|
|
4748
|
+
state: packStoredLoginHandle({ state, codeVerifier })
|
|
4749
|
+
};
|
|
4725
4750
|
}
|
|
4726
4751
|
async function handleCallback(input) {
|
|
4727
4752
|
let url;
|
|
@@ -4735,12 +4760,15 @@ function createServerAuthClient(config) {
|
|
|
4735
4760
|
}
|
|
4736
4761
|
};
|
|
4737
4762
|
}
|
|
4763
|
+
const stored = unpackStoredLoginHandle(input.storedState);
|
|
4738
4764
|
const returnedState = url.searchParams.get("state") ?? void 0;
|
|
4739
|
-
if (!
|
|
4765
|
+
if (!stored || !returnedState || stored.state !== returnedState) {
|
|
4740
4766
|
return {
|
|
4741
4767
|
error: {
|
|
4742
4768
|
code: FFID_ERROR_CODES.STATE_MISMATCH_ERROR,
|
|
4743
|
-
|
|
4769
|
+
// Not "CSRF suspected": a state-only cookie written before 12.0.0 also
|
|
4770
|
+
// lands here, once per in-flight login across the upgrade (#6611).
|
|
4771
|
+
message: "OAuth state \u304C\u4E00\u81F4\u3057\u306A\u3044\u304B\u3001\u30ED\u30B0\u30A4\u30F3\u306E\u958B\u59CB\u304B\u3089\u6642\u9593\u304C\u7D4C\u3063\u3066\u3044\u307E\u3059\u3002\u3082\u3046\u4E00\u5EA6\u30ED\u30B0\u30A4\u30F3\u3057\u3066\u304F\u3060\u3055\u3044"
|
|
4744
4772
|
}
|
|
4745
4773
|
};
|
|
4746
4774
|
}
|
|
@@ -4757,7 +4785,7 @@ function createServerAuthClient(config) {
|
|
|
4757
4785
|
}
|
|
4758
4786
|
};
|
|
4759
4787
|
}
|
|
4760
|
-
return exchangeAuthorizationCodeServer(deps, code);
|
|
4788
|
+
return exchangeAuthorizationCodeServer(deps, code, stored.codeVerifier);
|
|
4761
4789
|
}
|
|
4762
4790
|
function refresh(refreshToken) {
|
|
4763
4791
|
return refreshTokensServer(deps, refreshToken);
|
|
@@ -4837,4 +4865,184 @@ function clear(opts = {}) {
|
|
|
4837
4865
|
}
|
|
4838
4866
|
var sessionCookies = { serialize, read, clear };
|
|
4839
4867
|
|
|
4840
|
-
|
|
4868
|
+
// src/server/db-token/constants.ts
|
|
4869
|
+
var FFID_DB_TOKEN_ALGORITHM = "ES256";
|
|
4870
|
+
var FFID_DB_TOKEN_ROLE = "authenticated";
|
|
4871
|
+
var FFID_DB_TOKEN_AUDIENCE = "authenticated";
|
|
4872
|
+
var DEFAULT_DB_TOKEN_TTL_SECONDS = 300;
|
|
4873
|
+
var MAX_DB_TOKEN_TTL_SECONDS = 900;
|
|
4874
|
+
var FFID_DB_TOKEN_ORGANIZATION_CLAIM = "organization_id";
|
|
4875
|
+
var FFID_DB_TOKEN_RESERVED_CLAIMS = [
|
|
4876
|
+
"sub",
|
|
4877
|
+
"role",
|
|
4878
|
+
"aud",
|
|
4879
|
+
"iss",
|
|
4880
|
+
"iat",
|
|
4881
|
+
"exp",
|
|
4882
|
+
"nbf",
|
|
4883
|
+
"jti",
|
|
4884
|
+
FFID_DB_TOKEN_ORGANIZATION_CLAIM
|
|
4885
|
+
];
|
|
4886
|
+
var MILLISECONDS_PER_SECOND = 1e3;
|
|
4887
|
+
|
|
4888
|
+
// src/server/db-token/errors.ts
|
|
4889
|
+
var FFID_DB_TOKEN_ERROR_CODES = {
|
|
4890
|
+
/** Signing key is not a private P-256 JWK with a `kid`, or cannot be imported. */
|
|
4891
|
+
INVALID_SIGNING_KEY: "INVALID_SIGNING_KEY",
|
|
4892
|
+
/** `ttlSeconds` is not a positive integer within `MAX_DB_TOKEN_TTL_SECONDS`. */
|
|
4893
|
+
INVALID_TTL: "INVALID_TTL",
|
|
4894
|
+
/** `userId` is not a UUID. */
|
|
4895
|
+
INVALID_USER_ID: "INVALID_USER_ID",
|
|
4896
|
+
/** `organizationId` is not a UUID. */
|
|
4897
|
+
INVALID_ORGANIZATION_ID: "INVALID_ORGANIZATION_ID",
|
|
4898
|
+
/** A product claim uses a name the minter reserves (`sub`, `role`, `exp`, ...). */
|
|
4899
|
+
RESERVED_CLAIM: "RESERVED_CLAIM",
|
|
4900
|
+
/** `now` is not a valid `Date` (an Invalid Date would sign `iat` / `exp` as null). */
|
|
4901
|
+
INVALID_CLOCK: "INVALID_CLOCK"
|
|
4902
|
+
};
|
|
4903
|
+
var FFIDDbTokenError = class extends Error {
|
|
4904
|
+
code;
|
|
4905
|
+
constructor(code, message, options) {
|
|
4906
|
+
super(message, options);
|
|
4907
|
+
this.name = "FFIDDbTokenError";
|
|
4908
|
+
this.code = code;
|
|
4909
|
+
}
|
|
4910
|
+
};
|
|
4911
|
+
|
|
4912
|
+
// src/server/db-token/mint.ts
|
|
4913
|
+
var UUID_PATTERN2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
4914
|
+
var RESERVED_CLAIM_SET = new Set(FFID_DB_TOKEN_RESERVED_CLAIMS);
|
|
4915
|
+
var isNonEmptyString = (value) => typeof value === "string" && value.length > 0;
|
|
4916
|
+
var invalidKey = (reason, cause) => new FFIDDbTokenError(
|
|
4917
|
+
FFID_DB_TOKEN_ERROR_CODES.INVALID_SIGNING_KEY,
|
|
4918
|
+
`Invalid DB token signing key: ${reason}`,
|
|
4919
|
+
cause === void 0 ? void 0 : { cause }
|
|
4920
|
+
);
|
|
4921
|
+
var describeCause = (cause) => cause instanceof Error ? `${cause.name}: ${cause.message}` : String(cause);
|
|
4922
|
+
function parseSigningKey(signingKey, kidOverride) {
|
|
4923
|
+
let candidate = signingKey;
|
|
4924
|
+
if (typeof signingKey === "string") {
|
|
4925
|
+
if (signingKey.trim().length === 0) {
|
|
4926
|
+
throw invalidKey("signingKey is empty (is the environment variable set?)");
|
|
4927
|
+
}
|
|
4928
|
+
try {
|
|
4929
|
+
candidate = JSON.parse(signingKey);
|
|
4930
|
+
} catch {
|
|
4931
|
+
throw invalidKey("not valid JSON");
|
|
4932
|
+
}
|
|
4933
|
+
}
|
|
4934
|
+
if (typeof candidate !== "object" || candidate === null || Array.isArray(candidate)) {
|
|
4935
|
+
throw invalidKey("expected a JWK object");
|
|
4936
|
+
}
|
|
4937
|
+
const jwk = candidate;
|
|
4938
|
+
if (jwk.kty !== "EC" || jwk.crv !== "P-256") {
|
|
4939
|
+
throw invalidKey(`expected kty=EC crv=P-256 for ${FFID_DB_TOKEN_ALGORITHM}`);
|
|
4940
|
+
}
|
|
4941
|
+
if (!isNonEmptyString(jwk.d) || !isNonEmptyString(jwk.x) || !isNonEmptyString(jwk.y)) {
|
|
4942
|
+
throw invalidKey("expected a private key (d, x, y)");
|
|
4943
|
+
}
|
|
4944
|
+
const kid = kidOverride ?? jwk.kid;
|
|
4945
|
+
if (!isNonEmptyString(kid)) {
|
|
4946
|
+
throw invalidKey("kid is required (Supabase matches the header kid against the imported key)");
|
|
4947
|
+
}
|
|
4948
|
+
return { jwk, kid };
|
|
4949
|
+
}
|
|
4950
|
+
function resolveTtlSeconds(ttlSeconds) {
|
|
4951
|
+
const ttl = ttlSeconds ?? DEFAULT_DB_TOKEN_TTL_SECONDS;
|
|
4952
|
+
if (!Number.isInteger(ttl) || ttl < 1 || ttl > MAX_DB_TOKEN_TTL_SECONDS) {
|
|
4953
|
+
throw new FFIDDbTokenError(
|
|
4954
|
+
FFID_DB_TOKEN_ERROR_CODES.INVALID_TTL,
|
|
4955
|
+
`ttlSeconds must be an integer between 1 and ${MAX_DB_TOKEN_TTL_SECONDS}`
|
|
4956
|
+
);
|
|
4957
|
+
}
|
|
4958
|
+
return ttl;
|
|
4959
|
+
}
|
|
4960
|
+
function requireUuid(value, code, label) {
|
|
4961
|
+
if (typeof value !== "string" || !UUID_PATTERN2.test(value)) {
|
|
4962
|
+
throw new FFIDDbTokenError(FFID_DB_TOKEN_ERROR_CODES[code], `${label} must be a UUID`);
|
|
4963
|
+
}
|
|
4964
|
+
return value.toLowerCase();
|
|
4965
|
+
}
|
|
4966
|
+
function resolveNow(now) {
|
|
4967
|
+
if (now === void 0) return /* @__PURE__ */ new Date();
|
|
4968
|
+
if (!(now instanceof Date) || Number.isNaN(now.getTime())) {
|
|
4969
|
+
throw new FFIDDbTokenError(FFID_DB_TOKEN_ERROR_CODES.INVALID_CLOCK, "now must be a valid Date");
|
|
4970
|
+
}
|
|
4971
|
+
return now;
|
|
4972
|
+
}
|
|
4973
|
+
function assertNoReservedClaims(claims) {
|
|
4974
|
+
if (!claims) return;
|
|
4975
|
+
for (const name of Object.keys(claims)) {
|
|
4976
|
+
if (RESERVED_CLAIM_SET.has(name)) {
|
|
4977
|
+
throw new FFIDDbTokenError(
|
|
4978
|
+
FFID_DB_TOKEN_ERROR_CODES.RESERVED_CLAIM,
|
|
4979
|
+
`Claim "${name}" is reserved by the DB token minter`
|
|
4980
|
+
);
|
|
4981
|
+
}
|
|
4982
|
+
}
|
|
4983
|
+
}
|
|
4984
|
+
async function importSigningKey(jwk, kid) {
|
|
4985
|
+
const ecParameters = { kty: jwk.kty, crv: jwk.crv, x: jwk.x, y: jwk.y };
|
|
4986
|
+
let privateKey;
|
|
4987
|
+
let publicKey;
|
|
4988
|
+
try {
|
|
4989
|
+
const imported = await Promise.all([
|
|
4990
|
+
importJWK({ ...ecParameters, d: jwk.d, kid, alg: FFID_DB_TOKEN_ALGORITHM }, FFID_DB_TOKEN_ALGORITHM),
|
|
4991
|
+
importJWK({ ...ecParameters, kid, alg: FFID_DB_TOKEN_ALGORITHM }, FFID_DB_TOKEN_ALGORITHM)
|
|
4992
|
+
]);
|
|
4993
|
+
if (imported[0] instanceof Uint8Array || imported[1] instanceof Uint8Array) {
|
|
4994
|
+
throw new Error("expected an asymmetric key");
|
|
4995
|
+
}
|
|
4996
|
+
;
|
|
4997
|
+
[privateKey, publicKey] = imported;
|
|
4998
|
+
} catch (cause) {
|
|
4999
|
+
throw invalidKey(`key material could not be imported (${describeCause(cause)})`, cause);
|
|
5000
|
+
}
|
|
5001
|
+
try {
|
|
5002
|
+
const probe = await new SignJWT({}).setProtectedHeader({ alg: FFID_DB_TOKEN_ALGORITHM, kid }).sign(privateKey);
|
|
5003
|
+
await jwtVerify(probe, publicKey);
|
|
5004
|
+
} catch (cause) {
|
|
5005
|
+
throw invalidKey("private part (d) does not match the public part (x, y)", cause);
|
|
5006
|
+
}
|
|
5007
|
+
return privateKey;
|
|
5008
|
+
}
|
|
5009
|
+
function createDbTokenMinter(config) {
|
|
5010
|
+
const { jwk, kid } = parseSigningKey(config.signingKey, config.kid);
|
|
5011
|
+
const ttlSeconds = resolveTtlSeconds(config.ttlSeconds);
|
|
5012
|
+
const issuer = config.issuer;
|
|
5013
|
+
let keyPromise;
|
|
5014
|
+
const loadKey = () => {
|
|
5015
|
+
keyPromise ??= importSigningKey(jwk, kid).catch((error) => {
|
|
5016
|
+
keyPromise = void 0;
|
|
5017
|
+
throw error;
|
|
5018
|
+
});
|
|
5019
|
+
return keyPromise;
|
|
5020
|
+
};
|
|
5021
|
+
return {
|
|
5022
|
+
kid,
|
|
5023
|
+
ttlSeconds,
|
|
5024
|
+
async mint(input) {
|
|
5025
|
+
const sub = requireUuid(input.userId, "INVALID_USER_ID", "userId");
|
|
5026
|
+
const organizationId = input.organizationId === void 0 || input.organizationId === null ? void 0 : requireUuid(input.organizationId, "INVALID_ORGANIZATION_ID", "organizationId");
|
|
5027
|
+
assertNoReservedClaims(input.claims);
|
|
5028
|
+
const now = resolveNow(input.now);
|
|
5029
|
+
const iat = Math.floor(now.getTime() / MILLISECONDS_PER_SECOND);
|
|
5030
|
+
const exp = iat + ttlSeconds;
|
|
5031
|
+
const claims = {
|
|
5032
|
+
...input.claims,
|
|
5033
|
+
sub,
|
|
5034
|
+
role: FFID_DB_TOKEN_ROLE,
|
|
5035
|
+
aud: FFID_DB_TOKEN_AUDIENCE,
|
|
5036
|
+
iat,
|
|
5037
|
+
exp,
|
|
5038
|
+
...issuer === void 0 ? {} : { iss: issuer },
|
|
5039
|
+
...organizationId === void 0 ? {} : { [FFID_DB_TOKEN_ORGANIZATION_CLAIM]: organizationId }
|
|
5040
|
+
};
|
|
5041
|
+
const key = await loadKey();
|
|
5042
|
+
const token = await new SignJWT(claims).setProtectedHeader({ alg: FFID_DB_TOKEN_ALGORITHM, kid, typ: "JWT" }).sign(key);
|
|
5043
|
+
return { token, expiresAt: new Date(exp * MILLISECONDS_PER_SECOND), claims };
|
|
5044
|
+
}
|
|
5045
|
+
};
|
|
5046
|
+
}
|
|
5047
|
+
|
|
5048
|
+
export { ALL_DENIED_EXCEPT_NECESSARY, CATALOG_HASH_PATTERN, CONSENT_COOKIE_NAME, COOKIE_VERSION, DEFAULT_DB_TOKEN_TTL_SECONDS, FFIDCatalogHashError, FFIDDbTokenError, FFID_ALLOWED_ORGANIZATION_LOGO_MIME_TYPES, FFID_CATALOG_ENVIRONMENTS, FFID_CATALOG_PUBLICATION_STATUSES, FFID_COMPANY_SIZE_CODES, FFID_DB_TOKEN_ALGORITHM, FFID_DB_TOKEN_AUDIENCE, FFID_DB_TOKEN_ERROR_CODES, FFID_DB_TOKEN_ORGANIZATION_CLAIM, FFID_DB_TOKEN_RESERVED_CLAIMS, FFID_DB_TOKEN_ROLE, FFID_ERROR_CODES, FFID_INDUSTRY_CODES, FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_BYTES, FFID_MAX_ORGANIZATION_LOGO_FILE_SIZE_MB, FFID_OAUTH_DENIAL_REASONS, FFID_ORGANIZATION_PROFILE_ERROR_CODES, FFID_SESSION_COOKIE_NAME, MAX_DB_TOKEN_TTL_SECONDS, canonicalizeCatalogValue, computeFFIDCheckoutCopyHash, computeLegalDisclosureHash, computePaymentConfigurationHash, computePraxisCopyHash, computeScopeHash, computeTaxConfigurationHash, createDbTokenMinter, createFFIDClient, createKVCacheAdapter, createMemoryCacheAdapter, createServerAuthClient, createTokenStore, createVerifyAccessToken, decodeConsentCookie, encodeConsentCookie, generateServerState, getFFIDAuthorizationError, getFFIDConsentFromCookieHeader, getFFIDConsentFromCookies, hashCanonicalJson, isFFIDOAuthDenialReason, sessionCookies, sha256Hex, validatePublishedCatalog };
|
|
@@ -115,7 +115,17 @@ interface FFIDCreditsPackPurchasedPayload extends FFIDCreditsEventBase {
|
|
|
115
115
|
*/
|
|
116
116
|
|
|
117
117
|
/** All supported webhook event types */
|
|
118
|
-
type FFIDWebhookEventType = 'subscription.created' | 'subscription.reactivated' | 'subscription.updated' | 'subscription.canceled' | 'subscription.downgrade_scheduled' | 'subscription.downgrade_applied' | 'subscription.downgrade_canceled' | 'subscription.trial_ending' | 'subscription.payment_failed' | 'user.created' | 'user.updated' | 'user.deleted' | 'user.deletion_requested' | 'organization.created' | 'organization.updated' | 'organization.member.added' | 'organization.member.removed' | 'organization.member.role_changed' | 'legal.document.updated' | 'legal.agreement.required' | 'system.maintenance.scheduled' | 'system.maintenance.started' | 'system.maintenance.completed' | 'announcement.published' | 'credits.granted' | 'credits.low' | 'credits.exhausted' | 'credits.pack_purchased' | 'test.ping';
|
|
118
|
+
type FFIDWebhookEventType = 'subscription.created' | 'subscription.reactivated' | 'subscription.updated' | 'subscription.seats.changed' | 'subscription.canceled' | 'subscription.downgrade_scheduled' | 'subscription.downgrade_applied' | 'subscription.downgrade_canceled' | 'subscription.trial_ending' | 'subscription.payment_failed' | 'user.created' | 'user.updated' | 'user.deleted' | 'user.deletion_requested' | 'organization.created' | 'organization.updated' | 'organization.member.added' | 'organization.member.removed' | 'organization.member.role_changed' | 'legal.document.updated' | 'legal.agreement.required' | 'system.maintenance.scheduled' | 'system.maintenance.started' | 'system.maintenance.completed' | 'announcement.published' | 'credits.granted' | 'credits.low' | 'credits.exhausted' | 'credits.pack_purchased' | 'test.ping';
|
|
119
|
+
/**
|
|
120
|
+
* Seat-roster reconciliation hint. Fetch the current roster from FFID; delivery
|
|
121
|
+
* can be delayed, duplicated or reordered. This event grants no access by itself.
|
|
122
|
+
*/
|
|
123
|
+
interface FFIDSubscriptionSeatsChangedPayload {
|
|
124
|
+
subscriptionId: string;
|
|
125
|
+
organizationId: string;
|
|
126
|
+
/** Compare with the receiver's own service before reading/reconciling its roster. */
|
|
127
|
+
serviceCode?: string;
|
|
128
|
+
}
|
|
119
129
|
interface FFIDSubscriptionCreatedPayload {
|
|
120
130
|
subscriptionId: string;
|
|
121
131
|
organizationId?: string;
|
|
@@ -500,6 +510,7 @@ interface FFIDWebhookEventMap {
|
|
|
500
510
|
'subscription.created': FFIDSubscriptionCreatedPayload;
|
|
501
511
|
'subscription.reactivated': FFIDSubscriptionReactivatedPayload;
|
|
502
512
|
'subscription.updated': FFIDSubscriptionUpdatedPayload;
|
|
513
|
+
'subscription.seats.changed': FFIDSubscriptionSeatsChangedPayload;
|
|
503
514
|
'subscription.canceled': FFIDSubscriptionCanceledPayload;
|
|
504
515
|
'subscription.downgrade_scheduled': FFIDSubscriptionDowngradeScheduledPayload;
|
|
505
516
|
'subscription.downgrade_applied': FFIDSubscriptionDowngradeAppliedPayload;
|
|
@@ -650,4 +661,4 @@ declare function createFFIDWebhookHandler(config: FFIDWebhookHandlerConfig): {
|
|
|
650
661
|
/** Type of the FFID Webhook handler */
|
|
651
662
|
type FFIDWebhookHandler = ReturnType<typeof createFFIDWebhookHandler>;
|
|
652
663
|
|
|
653
|
-
export { DEFAULT_TOLERANCE_SECONDS, type FFIDAnnouncementPublishedPayload, type FFIDCreditsExhaustedPayload, type FFIDCreditsGrantedPayload, type FFIDCreditsLowPayload, type FFIDCreditsPackPurchasedPayload, type FFIDLegalAgreementRequiredPayload, type FFIDLegalDocumentUpdatedPayload, type FFIDOrganizationCreatedPayload, type FFIDOrganizationMemberAddedPayload, type FFIDOrganizationMemberRemovedPayload, type FFIDOrganizationMemberRoleChangedPayload, type FFIDOrganizationUpdatedPayload, type FFIDSubscriptionCanceledPayload, type FFIDSubscriptionCreatedPayload, type FFIDSubscriptionDowngradeAppliedPayload, type FFIDSubscriptionDowngradeCanceledPayload, type FFIDSubscriptionDowngradeScheduledPayload, type FFIDSubscriptionPaymentFailedPayload, type FFIDSubscriptionReactivatedPayload, type FFIDSubscriptionTrialEndingPayload, type FFIDSubscriptionUpdatedPayload, type FFIDSystemMaintenancePayload, type FFIDTestPingPayload, type FFIDUserCreatedPayload, type FFIDUserDeletedPayload, type FFIDUserDeletionRequestedPayload, type FFIDUserUpdatedPayload, FFIDWebhookError, type FFIDWebhookEvent, type FFIDWebhookEventHandler, type FFIDWebhookEventMap, type FFIDWebhookEventType, type FFIDWebhookHandler, type FFIDWebhookHandlerConfig, type FFIDWebhookLogger, FFIDWebhookPayloadError, FFIDWebhookSignatureError, FFIDWebhookTimestampError, FFID_WEBHOOK_EVENT_ID_HEADER, FFID_WEBHOOK_SIGNATURE_HEADER, FFID_WEBHOOK_SIGNATURE_VERSION, FFID_WEBHOOK_TIMESTAMP_HEADER, computeSignature, createFFIDWebhookHandler, parseSignatureHeader, verifyWebhookSignature };
|
|
664
|
+
export { DEFAULT_TOLERANCE_SECONDS, type FFIDAnnouncementPublishedPayload, type FFIDCreditsExhaustedPayload, type FFIDCreditsGrantedPayload, type FFIDCreditsLowPayload, type FFIDCreditsPackPurchasedPayload, type FFIDLegalAgreementRequiredPayload, type FFIDLegalDocumentUpdatedPayload, type FFIDOrganizationCreatedPayload, type FFIDOrganizationMemberAddedPayload, type FFIDOrganizationMemberRemovedPayload, type FFIDOrganizationMemberRoleChangedPayload, type FFIDOrganizationUpdatedPayload, type FFIDSubscriptionCanceledPayload, type FFIDSubscriptionCreatedPayload, type FFIDSubscriptionDowngradeAppliedPayload, type FFIDSubscriptionDowngradeCanceledPayload, type FFIDSubscriptionDowngradeScheduledPayload, type FFIDSubscriptionPaymentFailedPayload, type FFIDSubscriptionReactivatedPayload, type FFIDSubscriptionSeatsChangedPayload, type FFIDSubscriptionTrialEndingPayload, type FFIDSubscriptionUpdatedPayload, type FFIDSystemMaintenancePayload, type FFIDTestPingPayload, type FFIDUserCreatedPayload, type FFIDUserDeletedPayload, type FFIDUserDeletionRequestedPayload, type FFIDUserUpdatedPayload, FFIDWebhookError, type FFIDWebhookEvent, type FFIDWebhookEventHandler, type FFIDWebhookEventMap, type FFIDWebhookEventType, type FFIDWebhookHandler, type FFIDWebhookHandlerConfig, type FFIDWebhookLogger, FFIDWebhookPayloadError, FFIDWebhookSignatureError, FFIDWebhookTimestampError, FFID_WEBHOOK_EVENT_ID_HEADER, FFID_WEBHOOK_SIGNATURE_HEADER, FFID_WEBHOOK_SIGNATURE_VERSION, FFID_WEBHOOK_TIMESTAMP_HEADER, computeSignature, createFFIDWebhookHandler, parseSignatureHeader, verifyWebhookSignature };
|
package/dist/webhooks/index.d.ts
CHANGED
|
@@ -115,7 +115,17 @@ interface FFIDCreditsPackPurchasedPayload extends FFIDCreditsEventBase {
|
|
|
115
115
|
*/
|
|
116
116
|
|
|
117
117
|
/** All supported webhook event types */
|
|
118
|
-
type FFIDWebhookEventType = 'subscription.created' | 'subscription.reactivated' | 'subscription.updated' | 'subscription.canceled' | 'subscription.downgrade_scheduled' | 'subscription.downgrade_applied' | 'subscription.downgrade_canceled' | 'subscription.trial_ending' | 'subscription.payment_failed' | 'user.created' | 'user.updated' | 'user.deleted' | 'user.deletion_requested' | 'organization.created' | 'organization.updated' | 'organization.member.added' | 'organization.member.removed' | 'organization.member.role_changed' | 'legal.document.updated' | 'legal.agreement.required' | 'system.maintenance.scheduled' | 'system.maintenance.started' | 'system.maintenance.completed' | 'announcement.published' | 'credits.granted' | 'credits.low' | 'credits.exhausted' | 'credits.pack_purchased' | 'test.ping';
|
|
118
|
+
type FFIDWebhookEventType = 'subscription.created' | 'subscription.reactivated' | 'subscription.updated' | 'subscription.seats.changed' | 'subscription.canceled' | 'subscription.downgrade_scheduled' | 'subscription.downgrade_applied' | 'subscription.downgrade_canceled' | 'subscription.trial_ending' | 'subscription.payment_failed' | 'user.created' | 'user.updated' | 'user.deleted' | 'user.deletion_requested' | 'organization.created' | 'organization.updated' | 'organization.member.added' | 'organization.member.removed' | 'organization.member.role_changed' | 'legal.document.updated' | 'legal.agreement.required' | 'system.maintenance.scheduled' | 'system.maintenance.started' | 'system.maintenance.completed' | 'announcement.published' | 'credits.granted' | 'credits.low' | 'credits.exhausted' | 'credits.pack_purchased' | 'test.ping';
|
|
119
|
+
/**
|
|
120
|
+
* Seat-roster reconciliation hint. Fetch the current roster from FFID; delivery
|
|
121
|
+
* can be delayed, duplicated or reordered. This event grants no access by itself.
|
|
122
|
+
*/
|
|
123
|
+
interface FFIDSubscriptionSeatsChangedPayload {
|
|
124
|
+
subscriptionId: string;
|
|
125
|
+
organizationId: string;
|
|
126
|
+
/** Compare with the receiver's own service before reading/reconciling its roster. */
|
|
127
|
+
serviceCode?: string;
|
|
128
|
+
}
|
|
119
129
|
interface FFIDSubscriptionCreatedPayload {
|
|
120
130
|
subscriptionId: string;
|
|
121
131
|
organizationId?: string;
|
|
@@ -500,6 +510,7 @@ interface FFIDWebhookEventMap {
|
|
|
500
510
|
'subscription.created': FFIDSubscriptionCreatedPayload;
|
|
501
511
|
'subscription.reactivated': FFIDSubscriptionReactivatedPayload;
|
|
502
512
|
'subscription.updated': FFIDSubscriptionUpdatedPayload;
|
|
513
|
+
'subscription.seats.changed': FFIDSubscriptionSeatsChangedPayload;
|
|
503
514
|
'subscription.canceled': FFIDSubscriptionCanceledPayload;
|
|
504
515
|
'subscription.downgrade_scheduled': FFIDSubscriptionDowngradeScheduledPayload;
|
|
505
516
|
'subscription.downgrade_applied': FFIDSubscriptionDowngradeAppliedPayload;
|
|
@@ -650,4 +661,4 @@ declare function createFFIDWebhookHandler(config: FFIDWebhookHandlerConfig): {
|
|
|
650
661
|
/** Type of the FFID Webhook handler */
|
|
651
662
|
type FFIDWebhookHandler = ReturnType<typeof createFFIDWebhookHandler>;
|
|
652
663
|
|
|
653
|
-
export { DEFAULT_TOLERANCE_SECONDS, type FFIDAnnouncementPublishedPayload, type FFIDCreditsExhaustedPayload, type FFIDCreditsGrantedPayload, type FFIDCreditsLowPayload, type FFIDCreditsPackPurchasedPayload, type FFIDLegalAgreementRequiredPayload, type FFIDLegalDocumentUpdatedPayload, type FFIDOrganizationCreatedPayload, type FFIDOrganizationMemberAddedPayload, type FFIDOrganizationMemberRemovedPayload, type FFIDOrganizationMemberRoleChangedPayload, type FFIDOrganizationUpdatedPayload, type FFIDSubscriptionCanceledPayload, type FFIDSubscriptionCreatedPayload, type FFIDSubscriptionDowngradeAppliedPayload, type FFIDSubscriptionDowngradeCanceledPayload, type FFIDSubscriptionDowngradeScheduledPayload, type FFIDSubscriptionPaymentFailedPayload, type FFIDSubscriptionReactivatedPayload, type FFIDSubscriptionTrialEndingPayload, type FFIDSubscriptionUpdatedPayload, type FFIDSystemMaintenancePayload, type FFIDTestPingPayload, type FFIDUserCreatedPayload, type FFIDUserDeletedPayload, type FFIDUserDeletionRequestedPayload, type FFIDUserUpdatedPayload, FFIDWebhookError, type FFIDWebhookEvent, type FFIDWebhookEventHandler, type FFIDWebhookEventMap, type FFIDWebhookEventType, type FFIDWebhookHandler, type FFIDWebhookHandlerConfig, type FFIDWebhookLogger, FFIDWebhookPayloadError, FFIDWebhookSignatureError, FFIDWebhookTimestampError, FFID_WEBHOOK_EVENT_ID_HEADER, FFID_WEBHOOK_SIGNATURE_HEADER, FFID_WEBHOOK_SIGNATURE_VERSION, FFID_WEBHOOK_TIMESTAMP_HEADER, computeSignature, createFFIDWebhookHandler, parseSignatureHeader, verifyWebhookSignature };
|
|
664
|
+
export { DEFAULT_TOLERANCE_SECONDS, type FFIDAnnouncementPublishedPayload, type FFIDCreditsExhaustedPayload, type FFIDCreditsGrantedPayload, type FFIDCreditsLowPayload, type FFIDCreditsPackPurchasedPayload, type FFIDLegalAgreementRequiredPayload, type FFIDLegalDocumentUpdatedPayload, type FFIDOrganizationCreatedPayload, type FFIDOrganizationMemberAddedPayload, type FFIDOrganizationMemberRemovedPayload, type FFIDOrganizationMemberRoleChangedPayload, type FFIDOrganizationUpdatedPayload, type FFIDSubscriptionCanceledPayload, type FFIDSubscriptionCreatedPayload, type FFIDSubscriptionDowngradeAppliedPayload, type FFIDSubscriptionDowngradeCanceledPayload, type FFIDSubscriptionDowngradeScheduledPayload, type FFIDSubscriptionPaymentFailedPayload, type FFIDSubscriptionReactivatedPayload, type FFIDSubscriptionSeatsChangedPayload, type FFIDSubscriptionTrialEndingPayload, type FFIDSubscriptionUpdatedPayload, type FFIDSystemMaintenancePayload, type FFIDTestPingPayload, type FFIDUserCreatedPayload, type FFIDUserDeletedPayload, type FFIDUserDeletionRequestedPayload, type FFIDUserUpdatedPayload, FFIDWebhookError, type FFIDWebhookEvent, type FFIDWebhookEventHandler, type FFIDWebhookEventMap, type FFIDWebhookEventType, type FFIDWebhookHandler, type FFIDWebhookHandlerConfig, type FFIDWebhookLogger, FFIDWebhookPayloadError, FFIDWebhookSignatureError, FFIDWebhookTimestampError, FFID_WEBHOOK_EVENT_ID_HEADER, FFID_WEBHOOK_SIGNATURE_HEADER, FFID_WEBHOOK_SIGNATURE_VERSION, FFID_WEBHOOK_TIMESTAMP_HEADER, computeSignature, createFFIDWebhookHandler, parseSignatureHeader, verifyWebhookSignature };
|