@feelflow/ffid-sdk 1.9.1 → 1.11.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.
@@ -0,0 +1,431 @@
1
+ export { D as DEFAULT_API_BASE_URL } from '../constants-DvTGHPZn.cjs';
2
+
3
+ /** Cache adapter interface for FFID SDK token verification */
4
+ /**
5
+ * Pluggable cache adapter interface.
6
+ * Implement this to use custom cache backends (Redis, Memcached, etc.)
7
+ */
8
+ interface FFIDCacheAdapter {
9
+ /** Get a cached value by key. Returns null if not found or expired. */
10
+ get(key: string): Promise<unknown | null>;
11
+ /** Set a value with TTL in seconds. */
12
+ set(key: string, value: unknown, ttlSeconds: number): Promise<void>;
13
+ /** Delete a cached value. */
14
+ delete(key: string): Promise<void>;
15
+ }
16
+ /** Cache configuration for createFFIDClient */
17
+ interface FFIDCacheConfig {
18
+ /** Cache adapter instance */
19
+ adapter: FFIDCacheAdapter;
20
+ /** Cache TTL in seconds (how long to cache userinfo/introspect results) */
21
+ ttl: number;
22
+ }
23
+
24
+ /**
25
+ * FFID SDK Type Definitions
26
+ *
27
+ * Core types for the FeelFlow ID SDK
28
+ */
29
+
30
+ /** Authentication mode for FFID client */
31
+ type FFIDAuthMode = 'cookie' | 'token' | 'service-key';
32
+ /**
33
+ * User information from FFID
34
+ */
35
+ type FFIDSeatModel = 'organization';
36
+ /** Userinfo member role for OAuth responses */
37
+ type FFIDOAuthUserInfoMemberRole = 'owner' | 'admin' | 'member' | 'viewer';
38
+ interface FFIDUser {
39
+ /** User ID (UUID) */
40
+ id: string;
41
+ /** Email address */
42
+ email: string;
43
+ /** Display name */
44
+ displayName: string | null;
45
+ /** Avatar URL */
46
+ avatarUrl: string | null;
47
+ /** Locale setting (e.g., 'ja', 'en') */
48
+ locale: string | null;
49
+ /** Timezone (e.g., 'Asia/Tokyo') */
50
+ timezone: string | null;
51
+ /** Account creation timestamp */
52
+ createdAt: string;
53
+ }
54
+ /**
55
+ * Agency branding information for white-label support.
56
+ * Included in organization when it is linked to an agency.
57
+ */
58
+ interface FFIDAgencyBranding {
59
+ /** Agency ID (UUID) */
60
+ agencyId: string;
61
+ /** Agency display name */
62
+ agencyName: string;
63
+ /** Custom logo URL */
64
+ logoUrl?: string;
65
+ /** Custom favicon URL */
66
+ faviconUrl?: string;
67
+ /** Primary brand color (hex) */
68
+ primaryColor?: string;
69
+ /** Secondary brand color (hex) */
70
+ secondaryColor?: string;
71
+ /** White-label company name */
72
+ companyName?: string;
73
+ }
74
+ /**
75
+ * Organization membership information
76
+ */
77
+ interface FFIDOrganization {
78
+ /** Organization ID (UUID) */
79
+ id: string;
80
+ /** Organization name */
81
+ name: string;
82
+ /** URL-safe slug */
83
+ slug: string;
84
+ /** User's role in this organization */
85
+ role: 'owner' | 'admin' | 'member';
86
+ /** Membership status */
87
+ status: 'active' | 'invited' | 'suspended';
88
+ /** Agency branding (null if org is not linked to an agency) */
89
+ agencyBranding: FFIDAgencyBranding | null;
90
+ }
91
+ /**
92
+ * Subscription/contract information
93
+ */
94
+ interface FFIDSubscription {
95
+ /** Subscription ID (UUID) */
96
+ id: string;
97
+ /** Service code (e.g., 'chatbot') */
98
+ serviceCode: string;
99
+ /** Service display name */
100
+ serviceName: string;
101
+ /** Plan code (e.g., 'basic', 'pro') */
102
+ planCode: string;
103
+ /** Plan display name */
104
+ planName: string;
105
+ /** Subscription status */
106
+ status: 'trialing' | 'active' | 'past_due' | 'canceled' | 'paused';
107
+ /** Current billing period end date */
108
+ currentPeriodEnd: string | null;
109
+ /** Service seat model (available when sourced from OAuth userinfo) */
110
+ seatModel?: FFIDSeatModel | undefined;
111
+ /** Member role in the resolved organization context */
112
+ memberRole?: FFIDOAuthUserInfoMemberRole | undefined;
113
+ /** Organization ID used to resolve subscription access */
114
+ organizationId?: string | null | undefined;
115
+ }
116
+ /** OAuth userinfo subscription summary */
117
+ interface FFIDOAuthUserInfoSubscription {
118
+ subscriptionId: string | null;
119
+ status: 'trialing' | 'active' | 'past_due' | 'canceled' | 'paused' | null;
120
+ planCode: string | null;
121
+ seatModel: FFIDSeatModel | null;
122
+ memberRole: FFIDOAuthUserInfoMemberRole | null;
123
+ organizationId: string | null;
124
+ }
125
+ /** OAuth userinfo response exposed by FFID */
126
+ interface FFIDOAuthUserInfo {
127
+ sub: string;
128
+ email: string | null;
129
+ name: string | null;
130
+ picture: string | null;
131
+ organizationId?: string | null | undefined;
132
+ subscription?: FFIDOAuthUserInfoSubscription | undefined;
133
+ }
134
+ /** Options for verifyAccessToken */
135
+ interface FFIDVerifyAccessTokenOptions {
136
+ /**
137
+ * When true, fetches profile info (email, name, picture) via introspect API
138
+ * after local JWT verification. No effect when verifyStrategy is 'introspect'
139
+ * (profile is always included).
140
+ * Requires {@link FFIDConfig.serviceApiKey} to be configured when using jwt strategy.
141
+ * @default false
142
+ */
143
+ includeProfile?: boolean;
144
+ }
145
+ /**
146
+ * SDK configuration options
147
+ */
148
+ interface FFIDConfig {
149
+ /** Service code to identify your application */
150
+ serviceCode: string;
151
+ /** FFID API base URL (defaults to production) */
152
+ apiBaseUrl?: string | undefined;
153
+ /**
154
+ * Enable debug logging (deprecated: use logger instead)
155
+ * When true and no logger provided, uses console for logging
156
+ * @deprecated Use `logger` option for custom logging
157
+ */
158
+ debug?: boolean | undefined;
159
+ /**
160
+ * Custom logger for SDK debug output
161
+ * If not provided: uses no-op logger (silent)
162
+ * If debug=true and no logger: uses console
163
+ */
164
+ logger?: FFIDLogger | undefined;
165
+ /** Session refresh interval in milliseconds */
166
+ refreshInterval?: number | undefined;
167
+ /** Callback when authentication state changes */
168
+ onAuthStateChange?: ((user: FFIDUser | null) => void) | undefined;
169
+ /** Callback on authentication error */
170
+ onError?: ((error: FFIDError) => void) | undefined;
171
+ /** Authentication mode: 'cookie' (default), 'token' (OAuth Bearer), or 'service-key' (server-to-server) */
172
+ authMode?: FFIDAuthMode | undefined;
173
+ /** Client ID for token mode (defaults to serviceCode if not set) */
174
+ clientId?: string | undefined;
175
+ /** Custom redirect URI for OAuth flow (defaults to window.location.origin + window.location.pathname) */
176
+ redirectUri?: string | undefined;
177
+ /** Service API key for service-key mode (X-Service-Api-Key header) */
178
+ serviceApiKey?: string | undefined;
179
+ /**
180
+ * Token verification strategy for service-key mode.
181
+ * - 'jwt': Local JWT verification via JWKS (default, lower latency)
182
+ * - 'introspect': Remote introspection via /api/v1/oauth/introspect
183
+ *
184
+ * JWT verification returns limited claims (no email/name/picture/subscription) by default.
185
+ * Use 'introspect' if you always need full user profile data, or pass
186
+ * { includeProfile: true } to verifyAccessToken() for on-demand profile fetching.
187
+ */
188
+ verifyStrategy?: 'jwt' | 'introspect' | undefined;
189
+ /**
190
+ * Cache configuration for token verification results.
191
+ * When set, introspect/userinfo responses are cached to reduce API calls.
192
+ * Effective in service-key mode with verifyStrategy: 'introspect',
193
+ * or with verifyStrategy: 'jwt' when includeProfile: true is used.
194
+ */
195
+ cache?: FFIDCacheConfig | undefined;
196
+ /**
197
+ * Request timeout in milliseconds for FFID API calls.
198
+ * Applies to token verification and introspection requests.
199
+ * @default undefined (no timeout, uses fetch default)
200
+ */
201
+ timeout?: number | undefined;
202
+ }
203
+ /**
204
+ * Logger interface for SDK debug output
205
+ *
206
+ * Allows injection of custom loggers (e.g., winston, pino)
207
+ * or use of the built-in console logger when debug is enabled
208
+ */
209
+ interface FFIDLogger {
210
+ /** Debug level logging */
211
+ debug: (...args: unknown[]) => void;
212
+ /** Info level logging */
213
+ info: (...args: unknown[]) => void;
214
+ /** Warning level logging */
215
+ warn: (...args: unknown[]) => void;
216
+ /** Error level logging */
217
+ error: (...args: unknown[]) => void;
218
+ }
219
+ /**
220
+ * FFID error object
221
+ */
222
+ interface FFIDError {
223
+ /** Error code */
224
+ code: string;
225
+ /** Human-readable error message */
226
+ message: string;
227
+ /** Additional error details */
228
+ details?: Record<string, unknown>;
229
+ }
230
+ /**
231
+ * Session response from FFID API
232
+ */
233
+ interface FFIDSessionResponse {
234
+ user: FFIDUser;
235
+ organizations: FFIDOrganization[];
236
+ subscriptions: FFIDSubscription[];
237
+ }
238
+ /**
239
+ * API response wrapper (discriminated union for type safety)
240
+ *
241
+ * Either data is present (success) or error is present (failure), never both.
242
+ * This pattern ensures callers handle both cases explicitly.
243
+ */
244
+ type FFIDApiResponse<T> = {
245
+ data: T;
246
+ error?: undefined;
247
+ } | {
248
+ data?: undefined;
249
+ error: FFIDError;
250
+ };
251
+ /**
252
+ * Subscription check response from ext/check endpoint
253
+ */
254
+ /** Subscription status values matching the FFID platform's SubscriptionStatus type */
255
+ type FFIDSubscriptionStatus = 'trialing' | 'active' | 'past_due' | 'canceled' | 'pending_invoice' | 'paused' | 'incomplete' | 'incomplete_expired' | 'unpaid';
256
+ interface FFIDSubscriptionCheckResponse {
257
+ hasActiveSubscription: boolean;
258
+ organizationId: string | null;
259
+ subscriptionId: string | null;
260
+ status: FFIDSubscriptionStatus | null;
261
+ planCode: string | null;
262
+ currentPeriodEnd: string | null;
263
+ }
264
+ /**
265
+ * Checkout session response from billing checkout endpoint
266
+ */
267
+ interface FFIDCheckoutSessionResponse {
268
+ /** Stripe Checkout session ID */
269
+ sessionId: string;
270
+ /** Stripe Checkout session URL (null if session creation had issues) */
271
+ url: string | null;
272
+ }
273
+ /**
274
+ * Portal session response from billing portal endpoint
275
+ */
276
+ interface FFIDPortalSessionResponse {
277
+ /** Stripe Billing Portal URL */
278
+ url: string;
279
+ }
280
+ /**
281
+ * Parameters for creating a checkout session
282
+ */
283
+ interface FFIDCreateCheckoutParams {
284
+ /** Organization ID (UUID) */
285
+ organizationId: string;
286
+ /** Subscription ID (UUID) */
287
+ subscriptionId: string;
288
+ /** URL to redirect after successful checkout */
289
+ successUrl: string;
290
+ /** URL to redirect after cancelled checkout */
291
+ cancelUrl: string;
292
+ /** Optional plan ID for upgrade or resubscription */
293
+ planId?: string;
294
+ }
295
+ /**
296
+ * Parameters for creating a billing portal session
297
+ */
298
+ interface FFIDCreatePortalParams {
299
+ /** Organization ID (UUID) */
300
+ organizationId: string;
301
+ /** URL to redirect when user exits the portal */
302
+ returnUrl: string;
303
+ }
304
+
305
+ /**
306
+ * Token Store
307
+ *
308
+ * Manages OAuth 2.0 tokens (access + refresh) with dual-storage support.
309
+ * Falls back to in-memory storage when localStorage is unavailable
310
+ * (e.g., Safari private browsing mode).
311
+ */
312
+ /**
313
+ * Token data stored by the token store
314
+ */
315
+ interface TokenData {
316
+ /** OAuth 2.0 access token */
317
+ accessToken: string;
318
+ /** OAuth 2.0 refresh token */
319
+ refreshToken: string;
320
+ /** Expiration timestamp in milliseconds (Unix epoch) */
321
+ expiresAt: number;
322
+ }
323
+ /**
324
+ * Token store interface for managing OAuth tokens
325
+ */
326
+ interface TokenStore {
327
+ /** Get stored tokens (null if not stored) */
328
+ getTokens(): TokenData | null;
329
+ /** Store new tokens */
330
+ setTokens(tokens: TokenData): void;
331
+ /** Clear all stored tokens */
332
+ clearTokens(): void;
333
+ /** Check if access token is expired (with 30s buffer) */
334
+ isAccessTokenExpired(): boolean;
335
+ }
336
+ /**
337
+ * Create a token store with the specified storage type.
338
+ *
339
+ * When storageType is 'localStorage' (default in browser), falls back
340
+ * to memory if localStorage is not available (e.g., Safari private mode).
341
+ *
342
+ * @param storageType - 'localStorage' (default) or 'memory'
343
+ */
344
+ declare function createTokenStore(storageType?: 'localStorage' | 'memory'): TokenStore;
345
+
346
+ /** Creates an FFID API client instance */
347
+ declare function createFFIDClient(config: FFIDConfig): {
348
+ getSession: () => Promise<FFIDApiResponse<FFIDSessionResponse>>;
349
+ signOut: () => Promise<FFIDApiResponse<void>>;
350
+ redirectToLogin: () => Promise<boolean>;
351
+ getLoginUrl: (redirectUrl?: string) => string;
352
+ getSignupUrl: (redirectUrl?: string) => string;
353
+ createError: (code: string, message: string) => FFIDError;
354
+ exchangeCodeForTokens: (code: string, codeVerifier?: string) => Promise<FFIDApiResponse<void>>;
355
+ refreshAccessToken: () => Promise<FFIDApiResponse<void>>;
356
+ checkSubscription: (params: {
357
+ userId: string;
358
+ organizationId: string;
359
+ }) => Promise<FFIDApiResponse<FFIDSubscriptionCheckResponse>>;
360
+ createCheckoutSession: (params: FFIDCreateCheckoutParams) => Promise<FFIDApiResponse<FFIDCheckoutSessionResponse>>;
361
+ createPortalSession: (params: FFIDCreatePortalParams) => Promise<FFIDApiResponse<FFIDPortalSessionResponse>>;
362
+ verifyAccessToken: (accessToken: string, options?: FFIDVerifyAccessTokenOptions) => Promise<FFIDApiResponse<FFIDOAuthUserInfo>>;
363
+ /** Token store (token mode only) */
364
+ tokenStore: TokenStore;
365
+ /** Resolved auth mode */
366
+ authMode: FFIDAuthMode;
367
+ /** Resolved logger instance */
368
+ logger: FFIDLogger;
369
+ baseUrl: string;
370
+ serviceCode: string;
371
+ clientId: string;
372
+ redirectUri: string | null;
373
+ };
374
+ /** Type of the FFID client */
375
+ type FFIDClient = ReturnType<typeof createFFIDClient>;
376
+
377
+ /** Token verification - verifyAccessToken() implementation */
378
+
379
+ /** Dependencies required by verifyAccessToken */
380
+ interface VerifyAccessTokenDeps {
381
+ authMode: string;
382
+ baseUrl: string;
383
+ serviceCode: string;
384
+ serviceApiKey: string | undefined;
385
+ verifyStrategy: 'jwt' | 'introspect';
386
+ logger: FFIDLogger;
387
+ createError: (code: string, message: string) => FFIDError;
388
+ errorCodes: {
389
+ NETWORK_ERROR: string;
390
+ PARSE_ERROR: string;
391
+ TOKEN_VERIFICATION_ERROR: string;
392
+ };
393
+ cache?: {
394
+ adapter: FFIDCacheAdapter;
395
+ ttl: number;
396
+ } | undefined;
397
+ timeout?: number | undefined;
398
+ }
399
+ /**
400
+ * Creates a verifyAccessToken function bound to the given client dependencies.
401
+ *
402
+ * Supports two strategies:
403
+ * - 'jwt': Local JWT verification via JWKS (default, lower latency)
404
+ * - 'introspect': Remote token introspection (full user profile data)
405
+ */
406
+ declare function createVerifyAccessToken(deps: VerifyAccessTokenDeps): (accessToken: string, options?: FFIDVerifyAccessTokenOptions) => Promise<FFIDApiResponse<FFIDOAuthUserInfo>>;
407
+
408
+ /**
409
+ * Create an in-memory cache adapter using a Map.
410
+ * Suitable for single-process environments (e.g., development, testing).
411
+ */
412
+ declare function createMemoryCacheAdapter(): FFIDCacheAdapter;
413
+
414
+ /**
415
+ * Minimal KVNamespace-compatible interface.
416
+ * Matches Cloudflare Workers KV without requiring the CF Workers dependency.
417
+ */
418
+ interface KVNamespaceLike {
419
+ get(key: string, type: 'json'): Promise<unknown | null>;
420
+ put(key: string, value: string, options?: {
421
+ expirationTtl?: number;
422
+ }): Promise<void>;
423
+ delete(key: string): Promise<void>;
424
+ }
425
+ /**
426
+ * Create a cache adapter backed by a KVNamespace-compatible store.
427
+ * Suitable for Cloudflare Workers and other KV-based environments.
428
+ */
429
+ declare function createKVCacheAdapter(kv: KVNamespaceLike): FFIDCacheAdapter;
430
+
431
+ export { type FFIDCacheAdapter, type FFIDCacheConfig, type FFIDClient, type FFIDConfig, type FFIDOAuthUserInfo, type FFIDOrganization, type FFIDSubscription, type FFIDUser, type FFIDVerifyAccessTokenOptions, type KVNamespaceLike, type TokenData, type TokenStore, createFFIDClient, createKVCacheAdapter, createMemoryCacheAdapter, createTokenStore, createVerifyAccessToken };