@feelflow/ffid-sdk 1.4.0 → 1.6.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 CHANGED
@@ -3,7 +3,7 @@
3
3
  [![npm version](https://img.shields.io/npm/v/@feelflow/ffid-sdk.svg)](https://www.npmjs.com/package/@feelflow/ffid-sdk)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
5
 
6
- FeelFlow ID Platform SDK for React/Next.js applications.
6
+ FeelFlow ID Platform SDK React/Next.js 向け + サーバーサイドモジュールはフレームワーク非依存。
7
7
 
8
8
  **5行のコードでFFID認証を導入!**
9
9
 
@@ -273,6 +273,92 @@ interface FFIDOAuthUserInfoSubscription {
273
273
 
274
274
  `seatModel` はシートモデル識別用であり、organization と role は userinfo の解決済み組織文脈として扱います。
275
275
 
276
+ ## React 以外の環境で使う
277
+
278
+ 本 SDK は React/Next.js 向けに設計されていますが、一部のモジュールはフレームワーク非依存で利用できます。
279
+
280
+ ### サーバーサイドモジュール(React 依存なし)
281
+
282
+ 以下の subpath exports は React に一切依存しません。Node.js、Deno、Bun 等で即座に利用できます。
283
+
284
+ ```typescript
285
+ // 利用規約・法的文書
286
+ import { createFFIDLegalClient } from '@feelflow/ffid-sdk/legal'
287
+
288
+ // Agency(代理店)管理
289
+ import { createFFIDAgencyClient } from '@feelflow/ffid-sdk/agency'
290
+
291
+ // お知らせ取得
292
+ import { createFFIDAnnouncementsClient } from '@feelflow/ffid-sdk/announcements'
293
+
294
+ // Webhook 署名検証・ハンドラー(※ Node.js crypto が必要)
295
+ import { createFFIDWebhookHandler, verifyWebhookSignature } from '@feelflow/ffid-sdk/webhooks'
296
+ ```
297
+
298
+ > **Note**: `webhooks` モジュールは Node.js の `crypto` モジュールと `Buffer` を使用します。Cloudflare Workers で利用する場合は [`nodejs_compat` 互換フラグ](https://developers.cloudflare.com/workers/runtime-apis/nodejs/)を有効にしてください。
299
+
300
+ これらのモジュールは独立した subpath export として公開されているため、メインエントリ (`@feelflow/ffid-sdk`) を経由せず、React の依存が伝播しません。
301
+
302
+ ### `createFFIDClient` を非 React 環境で使う
303
+
304
+ 非 React 環境では、可能な限り上記の subpath exports(`/legal`、`/webhooks` 等)の個別クライアントを使用してください。メインエントリの `createFFIDClient` を使う必要がある場合、`createFFIDClient` 自体は React を使用しませんが、メインエントリに含まれるため **bundler 環境では React を external に指定する**必要があります。
305
+
306
+ #### Cloudflare Workers
307
+
308
+ ビルドコマンドで `--external` を指定するか、カスタム esbuild 設定で `external` を設定してください。
309
+
310
+ ```bash
311
+ # wrangler のビルドコマンド例
312
+ esbuild src/index.ts --bundle --format=esm --external:react --external:react-dom
313
+ ```
314
+
315
+ #### Vue / Nuxt(Vite)
316
+
317
+ ```typescript
318
+ // vite.config.ts
319
+ export default defineConfig({
320
+ build: {
321
+ rollupOptions: {
322
+ external: ['react', 'react-dom'],
323
+ },
324
+ },
325
+ })
326
+ ```
327
+
328
+ #### esbuild
329
+
330
+ ```bash
331
+ esbuild src/index.ts --bundle --external:react --external:react-dom
332
+ ```
333
+
334
+ #### webpack
335
+
336
+ ```javascript
337
+ // webpack.config.js
338
+ module.exports = {
339
+ externals: {
340
+ react: 'react',
341
+ 'react-dom': 'react-dom',
342
+ },
343
+ }
344
+ ```
345
+
346
+ > **Note**: サーバーサイドで bundler を使わずに実行する場合、**subpath exports(`@feelflow/ffid-sdk/legal` 等)を使用すれば** external 設定なしで React がインストールされていなくても動作します。メインエントリ(`@feelflow/ffid-sdk`)を ESM で import する場合は、モジュールグラフが静的に解決されるため React が必要です。
347
+
348
+ ### `peerDependencies` は optional です
349
+
350
+ SDK の `package.json` で `react` / `react-dom` は `optional: true` に設定済みです(利用者側での設定は不要)。React をインストールしなくても `npm install` 時に warning は発生しません。
351
+
352
+ ```json
353
+ // SDK の package.json に設定済み(参考)
354
+ {
355
+ "peerDependenciesMeta": {
356
+ "react": { "optional": true },
357
+ "react-dom": { "optional": true }
358
+ }
359
+ }
360
+ ```
361
+
276
362
  ## 環境変数
277
363
 
278
364
  オプションで環境変数を使用してデフォルト設定を上書きできます:
@@ -1,4 +1,5 @@
1
1
  import { createContext, useState, useRef, useEffect, useMemo, useCallback, useContext } from 'react';
2
+ import { createRemoteJWKSet, jwtVerify } from 'jose';
2
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
4
 
4
5
  // src/constants.ts
@@ -176,11 +177,79 @@ function mapUserinfoSubscriptionToSession(userinfo, serviceCode) {
176
177
  }
177
178
  ];
178
179
  }
180
+ var JWKS_ENDPOINT = "/.well-known/jwks.json";
181
+ var JWT_ISSUER = "https://id.feelflow.co.jp";
182
+ var JWT_ALGORITHM = "ES256";
183
+ var JWT_CLOCK_TOLERANCE_SECONDS = 30;
184
+ function createJwtVerifier(deps) {
185
+ const { baseUrl, serviceCode, logger, createError, errorCodes } = deps;
186
+ const jwksUrl = new URL(JWKS_ENDPOINT, baseUrl);
187
+ const jwks = createRemoteJWKSet(jwksUrl);
188
+ async function verifyJwt(accessToken) {
189
+ if (!accessToken || !accessToken.trim()) {
190
+ return {
191
+ error: createError(
192
+ errorCodes.TOKEN_VERIFICATION_ERROR,
193
+ "\u30A2\u30AF\u30BB\u30B9\u30C8\u30FC\u30AF\u30F3\u304C\u6307\u5B9A\u3055\u308C\u3066\u3044\u307E\u305B\u3093"
194
+ )
195
+ };
196
+ }
197
+ try {
198
+ const { payload } = await jwtVerify(accessToken, jwks, {
199
+ algorithms: [JWT_ALGORITHM],
200
+ issuer: JWT_ISSUER,
201
+ audience: serviceCode,
202
+ clockTolerance: JWT_CLOCK_TOLERANCE_SECONDS
203
+ });
204
+ if (!payload.sub) {
205
+ logger.error("JWT payload missing sub claim");
206
+ return {
207
+ error: createError(
208
+ errorCodes.TOKEN_VERIFICATION_ERROR,
209
+ "JWT\u30DA\u30A4\u30ED\u30FC\u30C9\u306B\u30E6\u30FC\u30B6\u30FCID\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u305B\u3093"
210
+ )
211
+ };
212
+ }
213
+ const userInfo = {
214
+ sub: payload.sub,
215
+ email: null,
216
+ name: null,
217
+ picture: null,
218
+ organizationId: payload.org_id ?? null
219
+ // subscription is not available from JWT
220
+ };
221
+ return { data: userInfo };
222
+ } catch (error) {
223
+ const message = error instanceof Error ? error.message : "JWT\u691C\u8A3C\u306B\u5931\u6557\u3057\u307E\u3057\u305F";
224
+ logger.error("JWT verification failed:", message);
225
+ return {
226
+ error: createError(
227
+ errorCodes.TOKEN_VERIFICATION_ERROR,
228
+ `JWT\u691C\u8A3C\u306B\u5931\u6557\u3057\u307E\u3057\u305F: ${message}`
229
+ )
230
+ };
231
+ }
232
+ }
233
+ return verifyJwt;
234
+ }
179
235
 
180
236
  // src/client/verify-access-token.ts
181
237
  var OAUTH_INTROSPECT_ENDPOINT = "/api/v1/oauth/introspect";
182
238
  function createVerifyAccessToken(deps) {
183
- const { authMode, baseUrl, serviceApiKey, logger, createError, errorCodes } = deps;
239
+ const { authMode, baseUrl, serviceCode, serviceApiKey, verifyStrategy, logger, createError, errorCodes } = deps;
240
+ let jwtVerify2 = null;
241
+ function getJwtVerifier() {
242
+ if (!jwtVerify2) {
243
+ jwtVerify2 = createJwtVerifier({
244
+ baseUrl,
245
+ serviceCode,
246
+ logger,
247
+ createError,
248
+ errorCodes: { TOKEN_VERIFICATION_ERROR: errorCodes.TOKEN_VERIFICATION_ERROR }
249
+ });
250
+ }
251
+ return jwtVerify2;
252
+ }
184
253
  async function verifyAccessToken(accessToken) {
185
254
  if (authMode !== "service-key") {
186
255
  return {
@@ -198,6 +267,12 @@ function createVerifyAccessToken(deps) {
198
267
  )
199
268
  };
200
269
  }
270
+ if (verifyStrategy === "jwt") {
271
+ return getJwtVerifier()(accessToken);
272
+ }
273
+ return verifyViaIntrospect(accessToken);
274
+ }
275
+ async function verifyViaIntrospect(accessToken) {
201
276
  if (!serviceApiKey) {
202
277
  return {
203
278
  error: createError(
@@ -333,7 +408,9 @@ function createFFIDClient(config) {
333
408
  const baseUrl = config.apiBaseUrl ?? DEFAULT_API_BASE_URL;
334
409
  const authMode = config.authMode ?? "cookie";
335
410
  const clientId = config.clientId ?? config.serviceCode;
411
+ const resolvedRedirectUri = config.redirectUri ?? null;
336
412
  const serviceApiKey = config.serviceApiKey?.trim();
413
+ const verifyStrategy = config.verifyStrategy ?? "jwt";
337
414
  if (authMode === "service-key" && !serviceApiKey) {
338
415
  throw new Error("FFID Client: service-key \u30E2\u30FC\u30C9\u3067\u306F serviceApiKey \u304C\u5FC5\u9808\u3067\u3059");
339
416
  }
@@ -637,11 +714,21 @@ function createFFIDClient(config) {
637
714
  async function exchangeCodeForTokens(code, codeVerifier) {
638
715
  const url = `${baseUrl}${OAUTH_TOKEN_ENDPOINT}`;
639
716
  logger.debug("Exchanging code for tokens:", url);
717
+ const effectiveRedirectUri = resolvedRedirectUri ?? (typeof window !== "undefined" ? window.location.origin + window.location.pathname : null);
718
+ if (!effectiveRedirectUri) {
719
+ logger.error("redirectUri is required for token exchange in SSR environments. Set config.redirectUri explicitly.");
720
+ return {
721
+ error: {
722
+ code: FFID_ERROR_CODES.TOKEN_EXCHANGE_ERROR,
723
+ message: "redirectUri \u304C\u672A\u8A2D\u5B9A\u3067\u3059\u3002SSR\u74B0\u5883\u3067\u306F config.redirectUri \u3092\u660E\u793A\u7684\u306B\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044"
724
+ }
725
+ };
726
+ }
640
727
  const body = {
641
728
  grant_type: "authorization_code",
642
729
  code,
643
730
  client_id: clientId,
644
- redirect_uri: typeof window !== "undefined" ? window.location.origin + window.location.pathname : ""
731
+ redirect_uri: effectiveRedirectUri
645
732
  };
646
733
  if (codeVerifier) {
647
734
  body.code_verifier = codeVerifier;
@@ -779,11 +866,11 @@ function createFFIDClient(config) {
779
866
  storeCodeVerifier(verifier);
780
867
  generateCodeChallenge(verifier).then((challenge) => {
781
868
  const state = generateRandomState();
782
- const currentUrl = window.location.origin + window.location.pathname;
869
+ const redirectUri = resolvedRedirectUri ?? window.location.origin + window.location.pathname;
783
870
  const params = new URLSearchParams({
784
871
  response_type: "code",
785
872
  client_id: clientId,
786
- redirect_uri: currentUrl,
873
+ redirect_uri: redirectUri,
787
874
  state,
788
875
  code_challenge: challenge,
789
876
  code_challenge_method: "S256"
@@ -825,7 +912,9 @@ function createFFIDClient(config) {
825
912
  const verifyAccessToken = createVerifyAccessToken({
826
913
  authMode,
827
914
  baseUrl,
915
+ serviceCode: config.serviceCode,
828
916
  serviceApiKey,
917
+ verifyStrategy,
829
918
  logger,
830
919
  createError,
831
920
  errorCodes: FFID_ERROR_CODES
@@ -849,7 +938,8 @@ function createFFIDClient(config) {
849
938
  logger,
850
939
  baseUrl,
851
940
  serviceCode: config.serviceCode,
852
- clientId
941
+ clientId,
942
+ redirectUri: resolvedRedirectUri
853
943
  };
854
944
  }
855
945
  function generateRandomState() {
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var react = require('react');
4
+ var jose = require('jose');
4
5
  var jsxRuntime = require('react/jsx-runtime');
5
6
 
6
7
  // src/constants.ts
@@ -178,11 +179,79 @@ function mapUserinfoSubscriptionToSession(userinfo, serviceCode) {
178
179
  }
179
180
  ];
180
181
  }
182
+ var JWKS_ENDPOINT = "/.well-known/jwks.json";
183
+ var JWT_ISSUER = "https://id.feelflow.co.jp";
184
+ var JWT_ALGORITHM = "ES256";
185
+ var JWT_CLOCK_TOLERANCE_SECONDS = 30;
186
+ function createJwtVerifier(deps) {
187
+ const { baseUrl, serviceCode, logger, createError, errorCodes } = deps;
188
+ const jwksUrl = new URL(JWKS_ENDPOINT, baseUrl);
189
+ const jwks = jose.createRemoteJWKSet(jwksUrl);
190
+ async function verifyJwt(accessToken) {
191
+ if (!accessToken || !accessToken.trim()) {
192
+ return {
193
+ error: createError(
194
+ errorCodes.TOKEN_VERIFICATION_ERROR,
195
+ "\u30A2\u30AF\u30BB\u30B9\u30C8\u30FC\u30AF\u30F3\u304C\u6307\u5B9A\u3055\u308C\u3066\u3044\u307E\u305B\u3093"
196
+ )
197
+ };
198
+ }
199
+ try {
200
+ const { payload } = await jose.jwtVerify(accessToken, jwks, {
201
+ algorithms: [JWT_ALGORITHM],
202
+ issuer: JWT_ISSUER,
203
+ audience: serviceCode,
204
+ clockTolerance: JWT_CLOCK_TOLERANCE_SECONDS
205
+ });
206
+ if (!payload.sub) {
207
+ logger.error("JWT payload missing sub claim");
208
+ return {
209
+ error: createError(
210
+ errorCodes.TOKEN_VERIFICATION_ERROR,
211
+ "JWT\u30DA\u30A4\u30ED\u30FC\u30C9\u306B\u30E6\u30FC\u30B6\u30FCID\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u305B\u3093"
212
+ )
213
+ };
214
+ }
215
+ const userInfo = {
216
+ sub: payload.sub,
217
+ email: null,
218
+ name: null,
219
+ picture: null,
220
+ organizationId: payload.org_id ?? null
221
+ // subscription is not available from JWT
222
+ };
223
+ return { data: userInfo };
224
+ } catch (error) {
225
+ const message = error instanceof Error ? error.message : "JWT\u691C\u8A3C\u306B\u5931\u6557\u3057\u307E\u3057\u305F";
226
+ logger.error("JWT verification failed:", message);
227
+ return {
228
+ error: createError(
229
+ errorCodes.TOKEN_VERIFICATION_ERROR,
230
+ `JWT\u691C\u8A3C\u306B\u5931\u6557\u3057\u307E\u3057\u305F: ${message}`
231
+ )
232
+ };
233
+ }
234
+ }
235
+ return verifyJwt;
236
+ }
181
237
 
182
238
  // src/client/verify-access-token.ts
183
239
  var OAUTH_INTROSPECT_ENDPOINT = "/api/v1/oauth/introspect";
184
240
  function createVerifyAccessToken(deps) {
185
- const { authMode, baseUrl, serviceApiKey, logger, createError, errorCodes } = deps;
241
+ const { authMode, baseUrl, serviceCode, serviceApiKey, verifyStrategy, logger, createError, errorCodes } = deps;
242
+ let jwtVerify2 = null;
243
+ function getJwtVerifier() {
244
+ if (!jwtVerify2) {
245
+ jwtVerify2 = createJwtVerifier({
246
+ baseUrl,
247
+ serviceCode,
248
+ logger,
249
+ createError,
250
+ errorCodes: { TOKEN_VERIFICATION_ERROR: errorCodes.TOKEN_VERIFICATION_ERROR }
251
+ });
252
+ }
253
+ return jwtVerify2;
254
+ }
186
255
  async function verifyAccessToken(accessToken) {
187
256
  if (authMode !== "service-key") {
188
257
  return {
@@ -200,6 +269,12 @@ function createVerifyAccessToken(deps) {
200
269
  )
201
270
  };
202
271
  }
272
+ if (verifyStrategy === "jwt") {
273
+ return getJwtVerifier()(accessToken);
274
+ }
275
+ return verifyViaIntrospect(accessToken);
276
+ }
277
+ async function verifyViaIntrospect(accessToken) {
203
278
  if (!serviceApiKey) {
204
279
  return {
205
280
  error: createError(
@@ -335,7 +410,9 @@ function createFFIDClient(config) {
335
410
  const baseUrl = config.apiBaseUrl ?? DEFAULT_API_BASE_URL;
336
411
  const authMode = config.authMode ?? "cookie";
337
412
  const clientId = config.clientId ?? config.serviceCode;
413
+ const resolvedRedirectUri = config.redirectUri ?? null;
338
414
  const serviceApiKey = config.serviceApiKey?.trim();
415
+ const verifyStrategy = config.verifyStrategy ?? "jwt";
339
416
  if (authMode === "service-key" && !serviceApiKey) {
340
417
  throw new Error("FFID Client: service-key \u30E2\u30FC\u30C9\u3067\u306F serviceApiKey \u304C\u5FC5\u9808\u3067\u3059");
341
418
  }
@@ -639,11 +716,21 @@ function createFFIDClient(config) {
639
716
  async function exchangeCodeForTokens(code, codeVerifier) {
640
717
  const url = `${baseUrl}${OAUTH_TOKEN_ENDPOINT}`;
641
718
  logger.debug("Exchanging code for tokens:", url);
719
+ const effectiveRedirectUri = resolvedRedirectUri ?? (typeof window !== "undefined" ? window.location.origin + window.location.pathname : null);
720
+ if (!effectiveRedirectUri) {
721
+ logger.error("redirectUri is required for token exchange in SSR environments. Set config.redirectUri explicitly.");
722
+ return {
723
+ error: {
724
+ code: FFID_ERROR_CODES.TOKEN_EXCHANGE_ERROR,
725
+ message: "redirectUri \u304C\u672A\u8A2D\u5B9A\u3067\u3059\u3002SSR\u74B0\u5883\u3067\u306F config.redirectUri \u3092\u660E\u793A\u7684\u306B\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044"
726
+ }
727
+ };
728
+ }
642
729
  const body = {
643
730
  grant_type: "authorization_code",
644
731
  code,
645
732
  client_id: clientId,
646
- redirect_uri: typeof window !== "undefined" ? window.location.origin + window.location.pathname : ""
733
+ redirect_uri: effectiveRedirectUri
647
734
  };
648
735
  if (codeVerifier) {
649
736
  body.code_verifier = codeVerifier;
@@ -781,11 +868,11 @@ function createFFIDClient(config) {
781
868
  storeCodeVerifier(verifier);
782
869
  generateCodeChallenge(verifier).then((challenge) => {
783
870
  const state = generateRandomState();
784
- const currentUrl = window.location.origin + window.location.pathname;
871
+ const redirectUri = resolvedRedirectUri ?? window.location.origin + window.location.pathname;
785
872
  const params = new URLSearchParams({
786
873
  response_type: "code",
787
874
  client_id: clientId,
788
- redirect_uri: currentUrl,
875
+ redirect_uri: redirectUri,
789
876
  state,
790
877
  code_challenge: challenge,
791
878
  code_challenge_method: "S256"
@@ -827,7 +914,9 @@ function createFFIDClient(config) {
827
914
  const verifyAccessToken = createVerifyAccessToken({
828
915
  authMode,
829
916
  baseUrl,
917
+ serviceCode: config.serviceCode,
830
918
  serviceApiKey,
919
+ verifyStrategy,
831
920
  logger,
832
921
  createError,
833
922
  errorCodes: FFID_ERROR_CODES
@@ -851,7 +940,8 @@ function createFFIDClient(config) {
851
940
  logger,
852
941
  baseUrl,
853
942
  serviceCode: config.serviceCode,
854
- clientId
943
+ clientId,
944
+ redirectUri: resolvedRedirectUri
855
945
  };
856
946
  }
857
947
  function generateRandomState() {
@@ -1,30 +1,30 @@
1
1
  'use strict';
2
2
 
3
- var chunk5XOQIUEZ_cjs = require('../chunk-5XOQIUEZ.cjs');
3
+ var chunkLILTOMJP_cjs = require('../chunk-LILTOMJP.cjs');
4
4
 
5
5
 
6
6
 
7
7
  Object.defineProperty(exports, "FFIDAnnouncementBadge", {
8
8
  enumerable: true,
9
- get: function () { return chunk5XOQIUEZ_cjs.FFIDAnnouncementBadge; }
9
+ get: function () { return chunkLILTOMJP_cjs.FFIDAnnouncementBadge; }
10
10
  });
11
11
  Object.defineProperty(exports, "FFIDAnnouncementList", {
12
12
  enumerable: true,
13
- get: function () { return chunk5XOQIUEZ_cjs.FFIDAnnouncementList; }
13
+ get: function () { return chunkLILTOMJP_cjs.FFIDAnnouncementList; }
14
14
  });
15
15
  Object.defineProperty(exports, "FFIDLoginButton", {
16
16
  enumerable: true,
17
- get: function () { return chunk5XOQIUEZ_cjs.FFIDLoginButton; }
17
+ get: function () { return chunkLILTOMJP_cjs.FFIDLoginButton; }
18
18
  });
19
19
  Object.defineProperty(exports, "FFIDOrganizationSwitcher", {
20
20
  enumerable: true,
21
- get: function () { return chunk5XOQIUEZ_cjs.FFIDOrganizationSwitcher; }
21
+ get: function () { return chunkLILTOMJP_cjs.FFIDOrganizationSwitcher; }
22
22
  });
23
23
  Object.defineProperty(exports, "FFIDSubscriptionBadge", {
24
24
  enumerable: true,
25
- get: function () { return chunk5XOQIUEZ_cjs.FFIDSubscriptionBadge; }
25
+ get: function () { return chunkLILTOMJP_cjs.FFIDSubscriptionBadge; }
26
26
  });
27
27
  Object.defineProperty(exports, "FFIDUserMenu", {
28
28
  enumerable: true,
29
- get: function () { return chunk5XOQIUEZ_cjs.FFIDUserMenu; }
29
+ get: function () { return chunkLILTOMJP_cjs.FFIDUserMenu; }
30
30
  });
@@ -1,3 +1,3 @@
1
- export { p as FFIDAnnouncementBadge, K as FFIDAnnouncementBadgeClassNames, M as FFIDAnnouncementBadgeProps, q as FFIDAnnouncementList, N as FFIDAnnouncementListClassNames, O as FFIDAnnouncementListProps, v as FFIDLoginButton, P as FFIDLoginButtonProps, z as FFIDOrganizationSwitcher, Q as FFIDOrganizationSwitcherClassNames, R as FFIDOrganizationSwitcherProps, D as FFIDSubscriptionBadge, S as FFIDSubscriptionBadgeClassNames, T as FFIDSubscriptionBadgeProps, H as FFIDUserMenu, V as FFIDUserMenuClassNames, W as FFIDUserMenuProps } from '../index-DHmt43kQ.cjs';
1
+ export { p as FFIDAnnouncementBadge, M as FFIDAnnouncementBadgeClassNames, N as FFIDAnnouncementBadgeProps, q as FFIDAnnouncementList, O as FFIDAnnouncementListClassNames, P as FFIDAnnouncementListProps, w as FFIDLoginButton, Q as FFIDLoginButtonProps, B as FFIDOrganizationSwitcher, R as FFIDOrganizationSwitcherClassNames, S as FFIDOrganizationSwitcherProps, E as FFIDSubscriptionBadge, T as FFIDSubscriptionBadgeClassNames, V as FFIDSubscriptionBadgeProps, I as FFIDUserMenu, W as FFIDUserMenuClassNames, X as FFIDUserMenuProps } from '../index-oF_MAO2T.cjs';
2
2
  import 'react/jsx-runtime';
3
3
  import 'react';
@@ -1,3 +1,3 @@
1
- export { p as FFIDAnnouncementBadge, K as FFIDAnnouncementBadgeClassNames, M as FFIDAnnouncementBadgeProps, q as FFIDAnnouncementList, N as FFIDAnnouncementListClassNames, O as FFIDAnnouncementListProps, v as FFIDLoginButton, P as FFIDLoginButtonProps, z as FFIDOrganizationSwitcher, Q as FFIDOrganizationSwitcherClassNames, R as FFIDOrganizationSwitcherProps, D as FFIDSubscriptionBadge, S as FFIDSubscriptionBadgeClassNames, T as FFIDSubscriptionBadgeProps, H as FFIDUserMenu, V as FFIDUserMenuClassNames, W as FFIDUserMenuProps } from '../index-DHmt43kQ.js';
1
+ export { p as FFIDAnnouncementBadge, M as FFIDAnnouncementBadgeClassNames, N as FFIDAnnouncementBadgeProps, q as FFIDAnnouncementList, O as FFIDAnnouncementListClassNames, P as FFIDAnnouncementListProps, w as FFIDLoginButton, Q as FFIDLoginButtonProps, B as FFIDOrganizationSwitcher, R as FFIDOrganizationSwitcherClassNames, S as FFIDOrganizationSwitcherProps, E as FFIDSubscriptionBadge, T as FFIDSubscriptionBadgeClassNames, V as FFIDSubscriptionBadgeProps, I as FFIDUserMenu, W as FFIDUserMenuClassNames, X as FFIDUserMenuProps } from '../index-oF_MAO2T.js';
2
2
  import 'react/jsx-runtime';
3
3
  import 'react';
@@ -1 +1 @@
1
- export { FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDSubscriptionBadge, FFIDUserMenu } from '../chunk-S2YL5Y4O.js';
1
+ export { FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDSubscriptionBadge, FFIDUserMenu } from '../chunk-4LSSBFZG.js';
@@ -137,8 +137,46 @@ interface FFIDConfig {
137
137
  authMode?: 'cookie' | 'token' | 'service-key' | undefined;
138
138
  /** Client ID for token mode (defaults to serviceCode if not set) */
139
139
  clientId?: string | undefined;
140
+ /** Custom redirect URI for OAuth flow (defaults to window.location.origin + window.location.pathname) */
141
+ redirectUri?: string | undefined;
140
142
  /** Service API key for service-key mode (X-Service-Api-Key header) */
141
143
  serviceApiKey?: string | undefined;
144
+ /**
145
+ * Token verification strategy for service-key mode.
146
+ * - 'jwt': Local JWT verification via JWKS (default, lower latency)
147
+ * - 'introspect': Remote introspection via /api/v1/oauth/introspect
148
+ *
149
+ * JWT verification returns limited claims (no email/name/picture/subscription).
150
+ * Use 'introspect' if you need full user profile data.
151
+ */
152
+ verifyStrategy?: 'jwt' | 'introspect' | undefined;
153
+ }
154
+ /**
155
+ * FFID JWT claims structure (minimal payload).
156
+ *
157
+ * These are the claims available when using JWT local verification.
158
+ * email, name, picture, and subscription are NOT included in the JWT
159
+ * to minimize token size.
160
+ */
161
+ interface FFIDJwtClaims {
162
+ /** Subject: user UUID */
163
+ sub: string;
164
+ /** Issuer */
165
+ iss: string;
166
+ /** Audience: service code */
167
+ aud: string;
168
+ /** Expiration time (Unix timestamp) */
169
+ exp: number;
170
+ /** Issued at (Unix timestamp) */
171
+ iat: number;
172
+ /** JWT ID: token row UUID */
173
+ jti: string;
174
+ /** OAuth scope */
175
+ scope: string;
176
+ /** Organization UUID */
177
+ org_id: string | null;
178
+ /** Service UUID */
179
+ svc_id: string;
142
180
  }
143
181
  /**
144
182
  * FFID context value provided to consumers
@@ -647,4 +685,4 @@ interface FFIDAnnouncementListProps {
647
685
  */
648
686
  declare function FFIDAnnouncementList({ announcements, isLoading, className, classNames, style, formatDate, emptyMessage, loadingRender, renderItem, maxContentLines, }: FFIDAnnouncementListProps): react_jsx_runtime.JSX.Element;
649
687
 
650
- export { type AnnouncementListResponse as A, type FFIDSeatModel as B, type FFIDSubscription as C, FFIDSubscriptionBadge as D, type FFIDSubscriptionStatus as E, type FFIDConfig as F, type FFIDTokenIntrospectionResponse as G, FFIDUserMenu as H, type UseFFIDAnnouncementsReturn as I, useFFIDAnnouncements as J, type FFIDAnnouncementBadgeClassNames as K, type ListAnnouncementsOptions as L, type FFIDAnnouncementBadgeProps as M, type FFIDAnnouncementListClassNames as N, type FFIDAnnouncementListProps as O, type FFIDLoginButtonProps as P, type FFIDOrganizationSwitcherClassNames as Q, type FFIDOrganizationSwitcherProps as R, type FFIDSubscriptionBadgeClassNames as S, type FFIDSubscriptionBadgeProps as T, type UseFFIDAnnouncementsOptions as U, type FFIDUserMenuClassNames as V, type FFIDUserMenuProps as W, type FFIDApiResponse as a, type FFIDSessionResponse as b, type FFIDError as c, type FFIDSubscriptionCheckResponse as d, type FFIDOAuthUserInfo as e, type FFIDLogger as f, type FFIDUser as g, type FFIDOrganization as h, type FFIDSubscriptionContextValue as i, type FFIDAnnouncementsClientConfig as j, type FFIDAnnouncementsApiResponse as k, type FFIDAnnouncementsLogger as l, type Announcement as m, type AnnouncementStatus as n, type AnnouncementType as o, FFIDAnnouncementBadge as p, FFIDAnnouncementList as q, type FFIDAnnouncementsError as r, type FFIDAnnouncementsErrorCode as s, type FFIDAnnouncementsServerResponse as t, type FFIDContextValue as u, FFIDLoginButton as v, type FFIDOAuthTokenResponse as w, type FFIDOAuthUserInfoMemberRole as x, type FFIDOAuthUserInfoSubscription as y, FFIDOrganizationSwitcher as z };
688
+ export { type AnnouncementListResponse as A, FFIDOrganizationSwitcher as B, type FFIDSeatModel as C, type FFIDSubscription as D, FFIDSubscriptionBadge as E, type FFIDConfig as F, type FFIDSubscriptionStatus as G, type FFIDTokenIntrospectionResponse as H, FFIDUserMenu as I, type UseFFIDAnnouncementsReturn as J, useFFIDAnnouncements as K, type ListAnnouncementsOptions as L, type FFIDAnnouncementBadgeClassNames as M, type FFIDAnnouncementBadgeProps as N, type FFIDAnnouncementListClassNames as O, type FFIDAnnouncementListProps as P, type FFIDLoginButtonProps as Q, type FFIDOrganizationSwitcherClassNames as R, type FFIDOrganizationSwitcherProps as S, type FFIDSubscriptionBadgeClassNames as T, type UseFFIDAnnouncementsOptions as U, type FFIDSubscriptionBadgeProps as V, type FFIDUserMenuClassNames as W, type FFIDUserMenuProps as X, type FFIDApiResponse as a, type FFIDSessionResponse as b, type FFIDError as c, type FFIDSubscriptionCheckResponse as d, type FFIDOAuthUserInfo as e, type FFIDLogger as f, type FFIDUser as g, type FFIDOrganization as h, type FFIDSubscriptionContextValue as i, type FFIDAnnouncementsClientConfig as j, type FFIDAnnouncementsApiResponse as k, type FFIDAnnouncementsLogger as l, type Announcement as m, type AnnouncementStatus as n, type AnnouncementType as o, FFIDAnnouncementBadge as p, FFIDAnnouncementList as q, type FFIDAnnouncementsError as r, type FFIDAnnouncementsErrorCode as s, type FFIDAnnouncementsServerResponse as t, type FFIDContextValue as u, type FFIDJwtClaims as v, FFIDLoginButton as w, type FFIDOAuthTokenResponse as x, type FFIDOAuthUserInfoMemberRole as y, type FFIDOAuthUserInfoSubscription as z };
@@ -137,8 +137,46 @@ interface FFIDConfig {
137
137
  authMode?: 'cookie' | 'token' | 'service-key' | undefined;
138
138
  /** Client ID for token mode (defaults to serviceCode if not set) */
139
139
  clientId?: string | undefined;
140
+ /** Custom redirect URI for OAuth flow (defaults to window.location.origin + window.location.pathname) */
141
+ redirectUri?: string | undefined;
140
142
  /** Service API key for service-key mode (X-Service-Api-Key header) */
141
143
  serviceApiKey?: string | undefined;
144
+ /**
145
+ * Token verification strategy for service-key mode.
146
+ * - 'jwt': Local JWT verification via JWKS (default, lower latency)
147
+ * - 'introspect': Remote introspection via /api/v1/oauth/introspect
148
+ *
149
+ * JWT verification returns limited claims (no email/name/picture/subscription).
150
+ * Use 'introspect' if you need full user profile data.
151
+ */
152
+ verifyStrategy?: 'jwt' | 'introspect' | undefined;
153
+ }
154
+ /**
155
+ * FFID JWT claims structure (minimal payload).
156
+ *
157
+ * These are the claims available when using JWT local verification.
158
+ * email, name, picture, and subscription are NOT included in the JWT
159
+ * to minimize token size.
160
+ */
161
+ interface FFIDJwtClaims {
162
+ /** Subject: user UUID */
163
+ sub: string;
164
+ /** Issuer */
165
+ iss: string;
166
+ /** Audience: service code */
167
+ aud: string;
168
+ /** Expiration time (Unix timestamp) */
169
+ exp: number;
170
+ /** Issued at (Unix timestamp) */
171
+ iat: number;
172
+ /** JWT ID: token row UUID */
173
+ jti: string;
174
+ /** OAuth scope */
175
+ scope: string;
176
+ /** Organization UUID */
177
+ org_id: string | null;
178
+ /** Service UUID */
179
+ svc_id: string;
142
180
  }
143
181
  /**
144
182
  * FFID context value provided to consumers
@@ -647,4 +685,4 @@ interface FFIDAnnouncementListProps {
647
685
  */
648
686
  declare function FFIDAnnouncementList({ announcements, isLoading, className, classNames, style, formatDate, emptyMessage, loadingRender, renderItem, maxContentLines, }: FFIDAnnouncementListProps): react_jsx_runtime.JSX.Element;
649
687
 
650
- export { type AnnouncementListResponse as A, type FFIDSeatModel as B, type FFIDSubscription as C, FFIDSubscriptionBadge as D, type FFIDSubscriptionStatus as E, type FFIDConfig as F, type FFIDTokenIntrospectionResponse as G, FFIDUserMenu as H, type UseFFIDAnnouncementsReturn as I, useFFIDAnnouncements as J, type FFIDAnnouncementBadgeClassNames as K, type ListAnnouncementsOptions as L, type FFIDAnnouncementBadgeProps as M, type FFIDAnnouncementListClassNames as N, type FFIDAnnouncementListProps as O, type FFIDLoginButtonProps as P, type FFIDOrganizationSwitcherClassNames as Q, type FFIDOrganizationSwitcherProps as R, type FFIDSubscriptionBadgeClassNames as S, type FFIDSubscriptionBadgeProps as T, type UseFFIDAnnouncementsOptions as U, type FFIDUserMenuClassNames as V, type FFIDUserMenuProps as W, type FFIDApiResponse as a, type FFIDSessionResponse as b, type FFIDError as c, type FFIDSubscriptionCheckResponse as d, type FFIDOAuthUserInfo as e, type FFIDLogger as f, type FFIDUser as g, type FFIDOrganization as h, type FFIDSubscriptionContextValue as i, type FFIDAnnouncementsClientConfig as j, type FFIDAnnouncementsApiResponse as k, type FFIDAnnouncementsLogger as l, type Announcement as m, type AnnouncementStatus as n, type AnnouncementType as o, FFIDAnnouncementBadge as p, FFIDAnnouncementList as q, type FFIDAnnouncementsError as r, type FFIDAnnouncementsErrorCode as s, type FFIDAnnouncementsServerResponse as t, type FFIDContextValue as u, FFIDLoginButton as v, type FFIDOAuthTokenResponse as w, type FFIDOAuthUserInfoMemberRole as x, type FFIDOAuthUserInfoSubscription as y, FFIDOrganizationSwitcher as z };
688
+ export { type AnnouncementListResponse as A, FFIDOrganizationSwitcher as B, type FFIDSeatModel as C, type FFIDSubscription as D, FFIDSubscriptionBadge as E, type FFIDConfig as F, type FFIDSubscriptionStatus as G, type FFIDTokenIntrospectionResponse as H, FFIDUserMenu as I, type UseFFIDAnnouncementsReturn as J, useFFIDAnnouncements as K, type ListAnnouncementsOptions as L, type FFIDAnnouncementBadgeClassNames as M, type FFIDAnnouncementBadgeProps as N, type FFIDAnnouncementListClassNames as O, type FFIDAnnouncementListProps as P, type FFIDLoginButtonProps as Q, type FFIDOrganizationSwitcherClassNames as R, type FFIDOrganizationSwitcherProps as S, type FFIDSubscriptionBadgeClassNames as T, type UseFFIDAnnouncementsOptions as U, type FFIDSubscriptionBadgeProps as V, type FFIDUserMenuClassNames as W, type FFIDUserMenuProps as X, type FFIDApiResponse as a, type FFIDSessionResponse as b, type FFIDError as c, type FFIDSubscriptionCheckResponse as d, type FFIDOAuthUserInfo as e, type FFIDLogger as f, type FFIDUser as g, type FFIDOrganization as h, type FFIDSubscriptionContextValue as i, type FFIDAnnouncementsClientConfig as j, type FFIDAnnouncementsApiResponse as k, type FFIDAnnouncementsLogger as l, type Announcement as m, type AnnouncementStatus as n, type AnnouncementType as o, FFIDAnnouncementBadge as p, FFIDAnnouncementList as q, type FFIDAnnouncementsError as r, type FFIDAnnouncementsErrorCode as s, type FFIDAnnouncementsServerResponse as t, type FFIDContextValue as u, type FFIDJwtClaims as v, FFIDLoginButton as w, type FFIDOAuthTokenResponse as x, type FFIDOAuthUserInfoMemberRole as y, type FFIDOAuthUserInfoSubscription as z };
package/dist/index.cjs CHANGED
@@ -1,12 +1,12 @@
1
1
  'use strict';
2
2
 
3
- var chunk5XOQIUEZ_cjs = require('./chunk-5XOQIUEZ.cjs');
3
+ var chunkLILTOMJP_cjs = require('./chunk-LILTOMJP.cjs');
4
4
  var react = require('react');
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
6
 
7
7
  function withFFIDAuth(Component, options = {}) {
8
8
  const WrappedComponent = (props) => {
9
- const { isLoading, isAuthenticated, login } = chunk5XOQIUEZ_cjs.useFFIDContext();
9
+ const { isLoading, isAuthenticated, login } = chunkLILTOMJP_cjs.useFFIDContext();
10
10
  const hasRedirected = react.useRef(false);
11
11
  react.useEffect(() => {
12
12
  if (!isLoading && !isAuthenticated && options.redirectToLogin && !hasRedirected.current) {
@@ -31,82 +31,82 @@ function withFFIDAuth(Component, options = {}) {
31
31
 
32
32
  Object.defineProperty(exports, "DEFAULT_API_BASE_URL", {
33
33
  enumerable: true,
34
- get: function () { return chunk5XOQIUEZ_cjs.DEFAULT_API_BASE_URL; }
34
+ get: function () { return chunkLILTOMJP_cjs.DEFAULT_API_BASE_URL; }
35
35
  });
36
36
  Object.defineProperty(exports, "FFIDAnnouncementBadge", {
37
37
  enumerable: true,
38
- get: function () { return chunk5XOQIUEZ_cjs.FFIDAnnouncementBadge; }
38
+ get: function () { return chunkLILTOMJP_cjs.FFIDAnnouncementBadge; }
39
39
  });
40
40
  Object.defineProperty(exports, "FFIDAnnouncementList", {
41
41
  enumerable: true,
42
- get: function () { return chunk5XOQIUEZ_cjs.FFIDAnnouncementList; }
42
+ get: function () { return chunkLILTOMJP_cjs.FFIDAnnouncementList; }
43
43
  });
44
44
  Object.defineProperty(exports, "FFIDLoginButton", {
45
45
  enumerable: true,
46
- get: function () { return chunk5XOQIUEZ_cjs.FFIDLoginButton; }
46
+ get: function () { return chunkLILTOMJP_cjs.FFIDLoginButton; }
47
47
  });
48
48
  Object.defineProperty(exports, "FFIDOrganizationSwitcher", {
49
49
  enumerable: true,
50
- get: function () { return chunk5XOQIUEZ_cjs.FFIDOrganizationSwitcher; }
50
+ get: function () { return chunkLILTOMJP_cjs.FFIDOrganizationSwitcher; }
51
51
  });
52
52
  Object.defineProperty(exports, "FFIDProvider", {
53
53
  enumerable: true,
54
- get: function () { return chunk5XOQIUEZ_cjs.FFIDProvider; }
54
+ get: function () { return chunkLILTOMJP_cjs.FFIDProvider; }
55
55
  });
56
56
  Object.defineProperty(exports, "FFIDSubscriptionBadge", {
57
57
  enumerable: true,
58
- get: function () { return chunk5XOQIUEZ_cjs.FFIDSubscriptionBadge; }
58
+ get: function () { return chunkLILTOMJP_cjs.FFIDSubscriptionBadge; }
59
59
  });
60
60
  Object.defineProperty(exports, "FFIDUserMenu", {
61
61
  enumerable: true,
62
- get: function () { return chunk5XOQIUEZ_cjs.FFIDUserMenu; }
62
+ get: function () { return chunkLILTOMJP_cjs.FFIDUserMenu; }
63
63
  });
64
64
  Object.defineProperty(exports, "FFID_ANNOUNCEMENTS_ERROR_CODES", {
65
65
  enumerable: true,
66
- get: function () { return chunk5XOQIUEZ_cjs.FFID_ANNOUNCEMENTS_ERROR_CODES; }
66
+ get: function () { return chunkLILTOMJP_cjs.FFID_ANNOUNCEMENTS_ERROR_CODES; }
67
67
  });
68
68
  Object.defineProperty(exports, "createFFIDAnnouncementsClient", {
69
69
  enumerable: true,
70
- get: function () { return chunk5XOQIUEZ_cjs.createFFIDAnnouncementsClient; }
70
+ get: function () { return chunkLILTOMJP_cjs.createFFIDAnnouncementsClient; }
71
71
  });
72
72
  Object.defineProperty(exports, "createFFIDClient", {
73
73
  enumerable: true,
74
- get: function () { return chunk5XOQIUEZ_cjs.createFFIDClient; }
74
+ get: function () { return chunkLILTOMJP_cjs.createFFIDClient; }
75
75
  });
76
76
  Object.defineProperty(exports, "createTokenStore", {
77
77
  enumerable: true,
78
- get: function () { return chunk5XOQIUEZ_cjs.createTokenStore; }
78
+ get: function () { return chunkLILTOMJP_cjs.createTokenStore; }
79
79
  });
80
80
  Object.defineProperty(exports, "generateCodeChallenge", {
81
81
  enumerable: true,
82
- get: function () { return chunk5XOQIUEZ_cjs.generateCodeChallenge; }
82
+ get: function () { return chunkLILTOMJP_cjs.generateCodeChallenge; }
83
83
  });
84
84
  Object.defineProperty(exports, "generateCodeVerifier", {
85
85
  enumerable: true,
86
- get: function () { return chunk5XOQIUEZ_cjs.generateCodeVerifier; }
86
+ get: function () { return chunkLILTOMJP_cjs.generateCodeVerifier; }
87
87
  });
88
88
  Object.defineProperty(exports, "retrieveCodeVerifier", {
89
89
  enumerable: true,
90
- get: function () { return chunk5XOQIUEZ_cjs.retrieveCodeVerifier; }
90
+ get: function () { return chunkLILTOMJP_cjs.retrieveCodeVerifier; }
91
91
  });
92
92
  Object.defineProperty(exports, "storeCodeVerifier", {
93
93
  enumerable: true,
94
- get: function () { return chunk5XOQIUEZ_cjs.storeCodeVerifier; }
94
+ get: function () { return chunkLILTOMJP_cjs.storeCodeVerifier; }
95
95
  });
96
96
  Object.defineProperty(exports, "useFFID", {
97
97
  enumerable: true,
98
- get: function () { return chunk5XOQIUEZ_cjs.useFFID; }
98
+ get: function () { return chunkLILTOMJP_cjs.useFFID; }
99
99
  });
100
100
  Object.defineProperty(exports, "useFFIDAnnouncements", {
101
101
  enumerable: true,
102
- get: function () { return chunk5XOQIUEZ_cjs.useFFIDAnnouncements; }
102
+ get: function () { return chunkLILTOMJP_cjs.useFFIDAnnouncements; }
103
103
  });
104
104
  Object.defineProperty(exports, "useSubscription", {
105
105
  enumerable: true,
106
- get: function () { return chunk5XOQIUEZ_cjs.useSubscription; }
106
+ get: function () { return chunkLILTOMJP_cjs.useSubscription; }
107
107
  });
108
108
  Object.defineProperty(exports, "withSubscription", {
109
109
  enumerable: true,
110
- get: function () { return chunk5XOQIUEZ_cjs.withSubscription; }
110
+ get: function () { return chunkLILTOMJP_cjs.withSubscription; }
111
111
  });
112
112
  exports.withFFIDAuth = withFFIDAuth;
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { F as FFIDConfig, a as FFIDApiResponse, b as FFIDSessionResponse, c as FFIDError, d as FFIDSubscriptionCheckResponse, e as FFIDOAuthUserInfo, f as FFIDLogger, g as FFIDUser, h as FFIDOrganization, i as FFIDSubscriptionContextValue, j as FFIDAnnouncementsClientConfig, L as ListAnnouncementsOptions, k as FFIDAnnouncementsApiResponse, A as AnnouncementListResponse, l as FFIDAnnouncementsLogger } from './index-DHmt43kQ.cjs';
2
- export { m as Announcement, n as AnnouncementStatus, o as AnnouncementType, p as FFIDAnnouncementBadge, q as FFIDAnnouncementList, r as FFIDAnnouncementsError, s as FFIDAnnouncementsErrorCode, t as FFIDAnnouncementsServerResponse, u as FFIDContextValue, v as FFIDLoginButton, w as FFIDOAuthTokenResponse, x as FFIDOAuthUserInfoMemberRole, y as FFIDOAuthUserInfoSubscription, z as FFIDOrganizationSwitcher, B as FFIDSeatModel, C as FFIDSubscription, D as FFIDSubscriptionBadge, E as FFIDSubscriptionStatus, G as FFIDTokenIntrospectionResponse, H as FFIDUserMenu, U as UseFFIDAnnouncementsOptions, I as UseFFIDAnnouncementsReturn, J as useFFIDAnnouncements } from './index-DHmt43kQ.cjs';
1
+ import { F as FFIDConfig, a as FFIDApiResponse, b as FFIDSessionResponse, c as FFIDError, d as FFIDSubscriptionCheckResponse, e as FFIDOAuthUserInfo, f as FFIDLogger, g as FFIDUser, h as FFIDOrganization, i as FFIDSubscriptionContextValue, j as FFIDAnnouncementsClientConfig, L as ListAnnouncementsOptions, k as FFIDAnnouncementsApiResponse, A as AnnouncementListResponse, l as FFIDAnnouncementsLogger } from './index-oF_MAO2T.cjs';
2
+ export { m as Announcement, n as AnnouncementStatus, o as AnnouncementType, p as FFIDAnnouncementBadge, q as FFIDAnnouncementList, r as FFIDAnnouncementsError, s as FFIDAnnouncementsErrorCode, t as FFIDAnnouncementsServerResponse, u as FFIDContextValue, v as FFIDJwtClaims, w as FFIDLoginButton, x as FFIDOAuthTokenResponse, y as FFIDOAuthUserInfoMemberRole, z as FFIDOAuthUserInfoSubscription, B as FFIDOrganizationSwitcher, C as FFIDSeatModel, D as FFIDSubscription, E as FFIDSubscriptionBadge, G as FFIDSubscriptionStatus, H as FFIDTokenIntrospectionResponse, I as FFIDUserMenu, U as UseFFIDAnnouncementsOptions, J as UseFFIDAnnouncementsReturn, K as useFFIDAnnouncements } from './index-oF_MAO2T.cjs';
3
3
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
4
  import { ReactNode, ComponentType, FC } from 'react';
5
5
 
@@ -108,6 +108,7 @@ declare function createFFIDClient(config: FFIDConfig): {
108
108
  baseUrl: string;
109
109
  serviceCode: string;
110
110
  clientId: string;
111
+ redirectUri: string | null;
111
112
  };
112
113
  /** Type of the FFID client */
113
114
  type FFIDClient = ReturnType<typeof createFFIDClient>;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { F as FFIDConfig, a as FFIDApiResponse, b as FFIDSessionResponse, c as FFIDError, d as FFIDSubscriptionCheckResponse, e as FFIDOAuthUserInfo, f as FFIDLogger, g as FFIDUser, h as FFIDOrganization, i as FFIDSubscriptionContextValue, j as FFIDAnnouncementsClientConfig, L as ListAnnouncementsOptions, k as FFIDAnnouncementsApiResponse, A as AnnouncementListResponse, l as FFIDAnnouncementsLogger } from './index-DHmt43kQ.js';
2
- export { m as Announcement, n as AnnouncementStatus, o as AnnouncementType, p as FFIDAnnouncementBadge, q as FFIDAnnouncementList, r as FFIDAnnouncementsError, s as FFIDAnnouncementsErrorCode, t as FFIDAnnouncementsServerResponse, u as FFIDContextValue, v as FFIDLoginButton, w as FFIDOAuthTokenResponse, x as FFIDOAuthUserInfoMemberRole, y as FFIDOAuthUserInfoSubscription, z as FFIDOrganizationSwitcher, B as FFIDSeatModel, C as FFIDSubscription, D as FFIDSubscriptionBadge, E as FFIDSubscriptionStatus, G as FFIDTokenIntrospectionResponse, H as FFIDUserMenu, U as UseFFIDAnnouncementsOptions, I as UseFFIDAnnouncementsReturn, J as useFFIDAnnouncements } from './index-DHmt43kQ.js';
1
+ import { F as FFIDConfig, a as FFIDApiResponse, b as FFIDSessionResponse, c as FFIDError, d as FFIDSubscriptionCheckResponse, e as FFIDOAuthUserInfo, f as FFIDLogger, g as FFIDUser, h as FFIDOrganization, i as FFIDSubscriptionContextValue, j as FFIDAnnouncementsClientConfig, L as ListAnnouncementsOptions, k as FFIDAnnouncementsApiResponse, A as AnnouncementListResponse, l as FFIDAnnouncementsLogger } from './index-oF_MAO2T.js';
2
+ export { m as Announcement, n as AnnouncementStatus, o as AnnouncementType, p as FFIDAnnouncementBadge, q as FFIDAnnouncementList, r as FFIDAnnouncementsError, s as FFIDAnnouncementsErrorCode, t as FFIDAnnouncementsServerResponse, u as FFIDContextValue, v as FFIDJwtClaims, w as FFIDLoginButton, x as FFIDOAuthTokenResponse, y as FFIDOAuthUserInfoMemberRole, z as FFIDOAuthUserInfoSubscription, B as FFIDOrganizationSwitcher, C as FFIDSeatModel, D as FFIDSubscription, E as FFIDSubscriptionBadge, G as FFIDSubscriptionStatus, H as FFIDTokenIntrospectionResponse, I as FFIDUserMenu, U as UseFFIDAnnouncementsOptions, J as UseFFIDAnnouncementsReturn, K as useFFIDAnnouncements } from './index-oF_MAO2T.js';
3
3
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
4
  import { ReactNode, ComponentType, FC } from 'react';
5
5
 
@@ -108,6 +108,7 @@ declare function createFFIDClient(config: FFIDConfig): {
108
108
  baseUrl: string;
109
109
  serviceCode: string;
110
110
  clientId: string;
111
+ redirectUri: string | null;
111
112
  };
112
113
  /** Type of the FFID client */
113
114
  type FFIDClient = ReturnType<typeof createFFIDClient>;
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { useFFIDContext } from './chunk-S2YL5Y4O.js';
2
- export { DEFAULT_API_BASE_URL, FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDProvider, FFIDSubscriptionBadge, FFIDUserMenu, FFID_ANNOUNCEMENTS_ERROR_CODES, createFFIDAnnouncementsClient, createFFIDClient, createTokenStore, generateCodeChallenge, generateCodeVerifier, retrieveCodeVerifier, storeCodeVerifier, useFFID, useFFIDAnnouncements, useSubscription, withSubscription } from './chunk-S2YL5Y4O.js';
1
+ import { useFFIDContext } from './chunk-4LSSBFZG.js';
2
+ export { DEFAULT_API_BASE_URL, FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDProvider, FFIDSubscriptionBadge, FFIDUserMenu, FFID_ANNOUNCEMENTS_ERROR_CODES, createFFIDAnnouncementsClient, createFFIDClient, createTokenStore, generateCodeChallenge, generateCodeVerifier, retrieveCodeVerifier, storeCodeVerifier, useFFID, useFFIDAnnouncements, useSubscription, withSubscription } from './chunk-4LSSBFZG.js';
3
3
  import { useRef, useEffect } from 'react';
4
4
  import { jsx, Fragment } from 'react/jsx-runtime';
5
5
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feelflow/ffid-sdk",
3
- "version": "1.4.0",
3
+ "version": "1.6.0",
4
4
  "description": "FeelFlow ID Platform SDK for React/Next.js applications",
5
5
  "keywords": [
6
6
  "feelflow",
@@ -73,6 +73,9 @@
73
73
  "test:coverage": "vitest run --coverage",
74
74
  "prepublishOnly": "npm run build"
75
75
  },
76
+ "dependencies": {
77
+ "jose": "^6.0.0"
78
+ },
76
79
  "peerDependencies": {
77
80
  "react": "^18.0.0 || ^19.0.0",
78
81
  "react-dom": "^18.0.0 || ^19.0.0"