@feelflow/ffid-sdk 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-5XOQIUEZ.cjs → chunk-UBQEG3CS.cjs} +79 -1
- package/dist/{chunk-S2YL5Y4O.js → chunk-YJFOE2PP.js} +79 -1
- package/dist/components/index.cjs +7 -7
- 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/{index-DHmt43kQ.d.cts → index-DEtyiwFZ.d.cts} +37 -1
- package/dist/{index-DHmt43kQ.d.ts → index-DEtyiwFZ.d.ts} +37 -1
- package/dist/index.cjs +22 -22
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/package.json +4 -1
|
@@ -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(
|
|
@@ -336,6 +411,7 @@ function createFFIDClient(config) {
|
|
|
336
411
|
const authMode = config.authMode ?? "cookie";
|
|
337
412
|
const clientId = config.clientId ?? config.serviceCode;
|
|
338
413
|
const serviceApiKey = config.serviceApiKey?.trim();
|
|
414
|
+
const verifyStrategy = config.verifyStrategy ?? "jwt";
|
|
339
415
|
if (authMode === "service-key" && !serviceApiKey) {
|
|
340
416
|
throw new Error("FFID Client: service-key \u30E2\u30FC\u30C9\u3067\u306F serviceApiKey \u304C\u5FC5\u9808\u3067\u3059");
|
|
341
417
|
}
|
|
@@ -827,7 +903,9 @@ function createFFIDClient(config) {
|
|
|
827
903
|
const verifyAccessToken = createVerifyAccessToken({
|
|
828
904
|
authMode,
|
|
829
905
|
baseUrl,
|
|
906
|
+
serviceCode: config.serviceCode,
|
|
830
907
|
serviceApiKey,
|
|
908
|
+
verifyStrategy,
|
|
831
909
|
logger,
|
|
832
910
|
createError,
|
|
833
911
|
errorCodes: FFID_ERROR_CODES
|
|
@@ -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(
|
|
@@ -334,6 +409,7 @@ function createFFIDClient(config) {
|
|
|
334
409
|
const authMode = config.authMode ?? "cookie";
|
|
335
410
|
const clientId = config.clientId ?? config.serviceCode;
|
|
336
411
|
const serviceApiKey = config.serviceApiKey?.trim();
|
|
412
|
+
const verifyStrategy = config.verifyStrategy ?? "jwt";
|
|
337
413
|
if (authMode === "service-key" && !serviceApiKey) {
|
|
338
414
|
throw new Error("FFID Client: service-key \u30E2\u30FC\u30C9\u3067\u306F serviceApiKey \u304C\u5FC5\u9808\u3067\u3059");
|
|
339
415
|
}
|
|
@@ -825,7 +901,9 @@ function createFFIDClient(config) {
|
|
|
825
901
|
const verifyAccessToken = createVerifyAccessToken({
|
|
826
902
|
authMode,
|
|
827
903
|
baseUrl,
|
|
904
|
+
serviceCode: config.serviceCode,
|
|
828
905
|
serviceApiKey,
|
|
906
|
+
verifyStrategy,
|
|
829
907
|
logger,
|
|
830
908
|
createError,
|
|
831
909
|
errorCodes: FFID_ERROR_CODES
|
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkUBQEG3CS_cjs = require('../chunk-UBQEG3CS.cjs');
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
Object.defineProperty(exports, "FFIDAnnouncementBadge", {
|
|
8
8
|
enumerable: true,
|
|
9
|
-
get: function () { return
|
|
9
|
+
get: function () { return chunkUBQEG3CS_cjs.FFIDAnnouncementBadge; }
|
|
10
10
|
});
|
|
11
11
|
Object.defineProperty(exports, "FFIDAnnouncementList", {
|
|
12
12
|
enumerable: true,
|
|
13
|
-
get: function () { return
|
|
13
|
+
get: function () { return chunkUBQEG3CS_cjs.FFIDAnnouncementList; }
|
|
14
14
|
});
|
|
15
15
|
Object.defineProperty(exports, "FFIDLoginButton", {
|
|
16
16
|
enumerable: true,
|
|
17
|
-
get: function () { return
|
|
17
|
+
get: function () { return chunkUBQEG3CS_cjs.FFIDLoginButton; }
|
|
18
18
|
});
|
|
19
19
|
Object.defineProperty(exports, "FFIDOrganizationSwitcher", {
|
|
20
20
|
enumerable: true,
|
|
21
|
-
get: function () { return
|
|
21
|
+
get: function () { return chunkUBQEG3CS_cjs.FFIDOrganizationSwitcher; }
|
|
22
22
|
});
|
|
23
23
|
Object.defineProperty(exports, "FFIDSubscriptionBadge", {
|
|
24
24
|
enumerable: true,
|
|
25
|
-
get: function () { return
|
|
25
|
+
get: function () { return chunkUBQEG3CS_cjs.FFIDSubscriptionBadge; }
|
|
26
26
|
});
|
|
27
27
|
Object.defineProperty(exports, "FFIDUserMenu", {
|
|
28
28
|
enumerable: true,
|
|
29
|
-
get: function () { return
|
|
29
|
+
get: function () { return chunkUBQEG3CS_cjs.FFIDUserMenu; }
|
|
30
30
|
});
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { p as FFIDAnnouncementBadge,
|
|
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-DEtyiwFZ.cjs';
|
|
2
2
|
import 'react/jsx-runtime';
|
|
3
3
|
import 'react';
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { p as FFIDAnnouncementBadge,
|
|
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-DEtyiwFZ.js';
|
|
2
2
|
import 'react/jsx-runtime';
|
|
3
3
|
import 'react';
|
package/dist/components/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDSubscriptionBadge, FFIDUserMenu } from '../chunk-
|
|
1
|
+
export { FFIDAnnouncementBadge, FFIDAnnouncementList, FFIDLoginButton, FFIDOrganizationSwitcher, FFIDSubscriptionBadge, FFIDUserMenu } from '../chunk-YJFOE2PP.js';
|
|
@@ -139,6 +139,42 @@ interface FFIDConfig {
|
|
|
139
139
|
clientId?: string | undefined;
|
|
140
140
|
/** Service API key for service-key mode (X-Service-Api-Key header) */
|
|
141
141
|
serviceApiKey?: string | undefined;
|
|
142
|
+
/**
|
|
143
|
+
* Token verification strategy for service-key mode.
|
|
144
|
+
* - 'jwt': Local JWT verification via JWKS (default, lower latency)
|
|
145
|
+
* - 'introspect': Remote introspection via /api/v1/oauth/introspect
|
|
146
|
+
*
|
|
147
|
+
* JWT verification returns limited claims (no email/name/picture/subscription).
|
|
148
|
+
* Use 'introspect' if you need full user profile data.
|
|
149
|
+
*/
|
|
150
|
+
verifyStrategy?: 'jwt' | 'introspect' | undefined;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* FFID JWT claims structure (minimal payload).
|
|
154
|
+
*
|
|
155
|
+
* These are the claims available when using JWT local verification.
|
|
156
|
+
* email, name, picture, and subscription are NOT included in the JWT
|
|
157
|
+
* to minimize token size.
|
|
158
|
+
*/
|
|
159
|
+
interface FFIDJwtClaims {
|
|
160
|
+
/** Subject: user UUID */
|
|
161
|
+
sub: string;
|
|
162
|
+
/** Issuer */
|
|
163
|
+
iss: string;
|
|
164
|
+
/** Audience: service code */
|
|
165
|
+
aud: string;
|
|
166
|
+
/** Expiration time (Unix timestamp) */
|
|
167
|
+
exp: number;
|
|
168
|
+
/** Issued at (Unix timestamp) */
|
|
169
|
+
iat: number;
|
|
170
|
+
/** JWT ID: token row UUID */
|
|
171
|
+
jti: string;
|
|
172
|
+
/** OAuth scope */
|
|
173
|
+
scope: string;
|
|
174
|
+
/** Organization UUID */
|
|
175
|
+
org_id: string | null;
|
|
176
|
+
/** Service UUID */
|
|
177
|
+
svc_id: string;
|
|
142
178
|
}
|
|
143
179
|
/**
|
|
144
180
|
* FFID context value provided to consumers
|
|
@@ -647,4 +683,4 @@ interface FFIDAnnouncementListProps {
|
|
|
647
683
|
*/
|
|
648
684
|
declare function FFIDAnnouncementList({ announcements, isLoading, className, classNames, style, formatDate, emptyMessage, loadingRender, renderItem, maxContentLines, }: FFIDAnnouncementListProps): react_jsx_runtime.JSX.Element;
|
|
649
685
|
|
|
650
|
-
export { type AnnouncementListResponse as A,
|
|
686
|
+
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 };
|
|
@@ -139,6 +139,42 @@ interface FFIDConfig {
|
|
|
139
139
|
clientId?: string | undefined;
|
|
140
140
|
/** Service API key for service-key mode (X-Service-Api-Key header) */
|
|
141
141
|
serviceApiKey?: string | undefined;
|
|
142
|
+
/**
|
|
143
|
+
* Token verification strategy for service-key mode.
|
|
144
|
+
* - 'jwt': Local JWT verification via JWKS (default, lower latency)
|
|
145
|
+
* - 'introspect': Remote introspection via /api/v1/oauth/introspect
|
|
146
|
+
*
|
|
147
|
+
* JWT verification returns limited claims (no email/name/picture/subscription).
|
|
148
|
+
* Use 'introspect' if you need full user profile data.
|
|
149
|
+
*/
|
|
150
|
+
verifyStrategy?: 'jwt' | 'introspect' | undefined;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* FFID JWT claims structure (minimal payload).
|
|
154
|
+
*
|
|
155
|
+
* These are the claims available when using JWT local verification.
|
|
156
|
+
* email, name, picture, and subscription are NOT included in the JWT
|
|
157
|
+
* to minimize token size.
|
|
158
|
+
*/
|
|
159
|
+
interface FFIDJwtClaims {
|
|
160
|
+
/** Subject: user UUID */
|
|
161
|
+
sub: string;
|
|
162
|
+
/** Issuer */
|
|
163
|
+
iss: string;
|
|
164
|
+
/** Audience: service code */
|
|
165
|
+
aud: string;
|
|
166
|
+
/** Expiration time (Unix timestamp) */
|
|
167
|
+
exp: number;
|
|
168
|
+
/** Issued at (Unix timestamp) */
|
|
169
|
+
iat: number;
|
|
170
|
+
/** JWT ID: token row UUID */
|
|
171
|
+
jti: string;
|
|
172
|
+
/** OAuth scope */
|
|
173
|
+
scope: string;
|
|
174
|
+
/** Organization UUID */
|
|
175
|
+
org_id: string | null;
|
|
176
|
+
/** Service UUID */
|
|
177
|
+
svc_id: string;
|
|
142
178
|
}
|
|
143
179
|
/**
|
|
144
180
|
* FFID context value provided to consumers
|
|
@@ -647,4 +683,4 @@ interface FFIDAnnouncementListProps {
|
|
|
647
683
|
*/
|
|
648
684
|
declare function FFIDAnnouncementList({ announcements, isLoading, className, classNames, style, formatDate, emptyMessage, loadingRender, renderItem, maxContentLines, }: FFIDAnnouncementListProps): react_jsx_runtime.JSX.Element;
|
|
649
685
|
|
|
650
|
-
export { type AnnouncementListResponse as A,
|
|
686
|
+
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
|
|
3
|
+
var chunkUBQEG3CS_cjs = require('./chunk-UBQEG3CS.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 } =
|
|
9
|
+
const { isLoading, isAuthenticated, login } = chunkUBQEG3CS_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
|
|
34
|
+
get: function () { return chunkUBQEG3CS_cjs.DEFAULT_API_BASE_URL; }
|
|
35
35
|
});
|
|
36
36
|
Object.defineProperty(exports, "FFIDAnnouncementBadge", {
|
|
37
37
|
enumerable: true,
|
|
38
|
-
get: function () { return
|
|
38
|
+
get: function () { return chunkUBQEG3CS_cjs.FFIDAnnouncementBadge; }
|
|
39
39
|
});
|
|
40
40
|
Object.defineProperty(exports, "FFIDAnnouncementList", {
|
|
41
41
|
enumerable: true,
|
|
42
|
-
get: function () { return
|
|
42
|
+
get: function () { return chunkUBQEG3CS_cjs.FFIDAnnouncementList; }
|
|
43
43
|
});
|
|
44
44
|
Object.defineProperty(exports, "FFIDLoginButton", {
|
|
45
45
|
enumerable: true,
|
|
46
|
-
get: function () { return
|
|
46
|
+
get: function () { return chunkUBQEG3CS_cjs.FFIDLoginButton; }
|
|
47
47
|
});
|
|
48
48
|
Object.defineProperty(exports, "FFIDOrganizationSwitcher", {
|
|
49
49
|
enumerable: true,
|
|
50
|
-
get: function () { return
|
|
50
|
+
get: function () { return chunkUBQEG3CS_cjs.FFIDOrganizationSwitcher; }
|
|
51
51
|
});
|
|
52
52
|
Object.defineProperty(exports, "FFIDProvider", {
|
|
53
53
|
enumerable: true,
|
|
54
|
-
get: function () { return
|
|
54
|
+
get: function () { return chunkUBQEG3CS_cjs.FFIDProvider; }
|
|
55
55
|
});
|
|
56
56
|
Object.defineProperty(exports, "FFIDSubscriptionBadge", {
|
|
57
57
|
enumerable: true,
|
|
58
|
-
get: function () { return
|
|
58
|
+
get: function () { return chunkUBQEG3CS_cjs.FFIDSubscriptionBadge; }
|
|
59
59
|
});
|
|
60
60
|
Object.defineProperty(exports, "FFIDUserMenu", {
|
|
61
61
|
enumerable: true,
|
|
62
|
-
get: function () { return
|
|
62
|
+
get: function () { return chunkUBQEG3CS_cjs.FFIDUserMenu; }
|
|
63
63
|
});
|
|
64
64
|
Object.defineProperty(exports, "FFID_ANNOUNCEMENTS_ERROR_CODES", {
|
|
65
65
|
enumerable: true,
|
|
66
|
-
get: function () { return
|
|
66
|
+
get: function () { return chunkUBQEG3CS_cjs.FFID_ANNOUNCEMENTS_ERROR_CODES; }
|
|
67
67
|
});
|
|
68
68
|
Object.defineProperty(exports, "createFFIDAnnouncementsClient", {
|
|
69
69
|
enumerable: true,
|
|
70
|
-
get: function () { return
|
|
70
|
+
get: function () { return chunkUBQEG3CS_cjs.createFFIDAnnouncementsClient; }
|
|
71
71
|
});
|
|
72
72
|
Object.defineProperty(exports, "createFFIDClient", {
|
|
73
73
|
enumerable: true,
|
|
74
|
-
get: function () { return
|
|
74
|
+
get: function () { return chunkUBQEG3CS_cjs.createFFIDClient; }
|
|
75
75
|
});
|
|
76
76
|
Object.defineProperty(exports, "createTokenStore", {
|
|
77
77
|
enumerable: true,
|
|
78
|
-
get: function () { return
|
|
78
|
+
get: function () { return chunkUBQEG3CS_cjs.createTokenStore; }
|
|
79
79
|
});
|
|
80
80
|
Object.defineProperty(exports, "generateCodeChallenge", {
|
|
81
81
|
enumerable: true,
|
|
82
|
-
get: function () { return
|
|
82
|
+
get: function () { return chunkUBQEG3CS_cjs.generateCodeChallenge; }
|
|
83
83
|
});
|
|
84
84
|
Object.defineProperty(exports, "generateCodeVerifier", {
|
|
85
85
|
enumerable: true,
|
|
86
|
-
get: function () { return
|
|
86
|
+
get: function () { return chunkUBQEG3CS_cjs.generateCodeVerifier; }
|
|
87
87
|
});
|
|
88
88
|
Object.defineProperty(exports, "retrieveCodeVerifier", {
|
|
89
89
|
enumerable: true,
|
|
90
|
-
get: function () { return
|
|
90
|
+
get: function () { return chunkUBQEG3CS_cjs.retrieveCodeVerifier; }
|
|
91
91
|
});
|
|
92
92
|
Object.defineProperty(exports, "storeCodeVerifier", {
|
|
93
93
|
enumerable: true,
|
|
94
|
-
get: function () { return
|
|
94
|
+
get: function () { return chunkUBQEG3CS_cjs.storeCodeVerifier; }
|
|
95
95
|
});
|
|
96
96
|
Object.defineProperty(exports, "useFFID", {
|
|
97
97
|
enumerable: true,
|
|
98
|
-
get: function () { return
|
|
98
|
+
get: function () { return chunkUBQEG3CS_cjs.useFFID; }
|
|
99
99
|
});
|
|
100
100
|
Object.defineProperty(exports, "useFFIDAnnouncements", {
|
|
101
101
|
enumerable: true,
|
|
102
|
-
get: function () { return
|
|
102
|
+
get: function () { return chunkUBQEG3CS_cjs.useFFIDAnnouncements; }
|
|
103
103
|
});
|
|
104
104
|
Object.defineProperty(exports, "useSubscription", {
|
|
105
105
|
enumerable: true,
|
|
106
|
-
get: function () { return
|
|
106
|
+
get: function () { return chunkUBQEG3CS_cjs.useSubscription; }
|
|
107
107
|
});
|
|
108
108
|
Object.defineProperty(exports, "withSubscription", {
|
|
109
109
|
enumerable: true,
|
|
110
|
-
get: function () { return
|
|
110
|
+
get: function () { return chunkUBQEG3CS_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-
|
|
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
|
|
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-DEtyiwFZ.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-DEtyiwFZ.cjs';
|
|
3
3
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
4
|
import { ReactNode, ComponentType, FC } from 'react';
|
|
5
5
|
|
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-
|
|
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
|
|
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-DEtyiwFZ.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-DEtyiwFZ.js';
|
|
3
3
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
4
|
import { ReactNode, ComponentType, FC } from 'react';
|
|
5
5
|
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { useFFIDContext } from './chunk-
|
|
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-
|
|
1
|
+
import { useFFIDContext } from './chunk-YJFOE2PP.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-YJFOE2PP.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.
|
|
3
|
+
"version": "1.5.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"
|