@flow-industries/id 0.22.1 → 0.23.1
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 +19 -8
- package/dist/sdk/browser-contract.d.ts +30 -0
- package/dist/sdk/browser-contract.js +19 -0
- package/dist/sdk/browser-session-route.d.ts +8 -0
- package/dist/sdk/browser-session-route.js +201 -0
- package/dist/sdk/client/create-flow.js +176 -166
- package/dist/sdk/client/flow-widget.js +1 -1
- package/dist/sdk/client/idb.d.ts +1 -0
- package/dist/sdk/client/idb.js +24 -0
- package/dist/sdk/client/open-profile.js +9 -1
- package/dist/sdk/client/profile-button.d.ts +1 -13
- package/dist/sdk/client/profile-button.js +114 -177
- package/dist/sdk/client/session.d.ts +1 -10
- package/dist/sdk/client/session.js +0 -37
- package/dist/sdk/client/static-flow.js +1 -0
- package/dist/sdk/issuer-api.d.ts +3 -0
- package/dist/sdk/issuer-api.js +28 -0
- package/dist/sdk/react/hooks.d.ts +1 -1
- package/dist/sdk/react/profile-button.d.ts +1 -12
- package/dist/sdk/react/profile-button.js +1 -12
- package/dist/sdk/server.js +6 -4
- package/dist/sdk/session-core.d.ts +2 -2
- package/dist/sdk/session-core.js +12 -11
- package/dist/sdk/session-route.js +114 -7
- package/dist/sdk/types/auth.d.ts +2 -0
- package/dist/sdk/types/dialog.d.ts +0 -3
- package/dist/sdk/types/index.d.ts +1 -1
- package/dist/sdk/types/landing.d.ts +1 -0
- package/dist/sdk/types/sdk.d.ts +7 -21
- package/dist/sdk/types/server.d.ts +10 -0
- package/dist/sdk/verify.js +9 -4
- package/dist/sdk/wagmi/index.js +0 -3
- package/package.json +4 -3
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { browserCompletionSchema } from "./browser-contract";
|
|
3
|
+
import { finishBrowserSession, startBrowserSession, } from "./browser-session-route";
|
|
4
|
+
import { clearCookieString } from "./cookies";
|
|
5
|
+
import { fetchIssuerApi, resolveIssuerApiUrl } from "./issuer-api";
|
|
2
6
|
/**
|
|
3
7
|
* The first-party session route every consumer app serves from its own
|
|
4
8
|
* origin — the only path between a browser and the refresh token. The
|
|
@@ -21,13 +25,20 @@ import { z } from "zod";
|
|
|
21
25
|
*/
|
|
22
26
|
import { cookieNamesFor, parseCookieHeader } from "./cookies";
|
|
23
27
|
import { DEFAULT_SESSION_PATH, defaultAudience, resolveIdHost, } from "./id-host";
|
|
24
|
-
import { claimsToUser, clearingCookies, isJwtVerificationFailure, resolveSessionCore, sessionCookies, } from "./session-core";
|
|
28
|
+
import { claimsToUser, clearingCookies, isJwtVerificationFailure, refreshSessionCore, resolveSessionCore, sessionCookies, } from "./session-core";
|
|
25
29
|
import { verifyFlowJWT } from "./verify";
|
|
26
30
|
/** The body the browser SDK posts to its own app's session route. */
|
|
27
31
|
const installBodySchema = z.object({
|
|
28
32
|
refreshToken: z.string().min(1).optional(),
|
|
29
33
|
jwt: z.string().min(1).optional(),
|
|
30
34
|
mint: z.array(z.string()).optional(),
|
|
35
|
+
action: z.enum(["login", "account", "guest"]).optional(),
|
|
36
|
+
returnTo: z.string().optional(),
|
|
37
|
+
signUp: z.boolean().optional(),
|
|
38
|
+
accessKeyHash: z
|
|
39
|
+
.string()
|
|
40
|
+
.regex(/^0x[a-fA-F0-9]{64}$/)
|
|
41
|
+
.optional(),
|
|
31
42
|
});
|
|
32
43
|
const additionalBodySchema = z.object({
|
|
33
44
|
additionalSessions: z
|
|
@@ -72,17 +83,105 @@ function isCrossSite(request, audience) {
|
|
|
72
83
|
export async function handleSessionRequest(request, opts = {}) {
|
|
73
84
|
const audience = opts.audience ?? defaultAudience(new URL(request.url).origin);
|
|
74
85
|
const issuerUrl = resolveIdHost(opts.issuerUrl, audience);
|
|
86
|
+
const apiUrl = resolveIssuerApiUrl(issuerUrl, opts.apiUrl);
|
|
87
|
+
const callback = new URL(request.url);
|
|
88
|
+
if (request.method === "GET" && callback.searchParams.has("flow_state")) {
|
|
89
|
+
return finishBrowserSession(request, audience, issuerUrl, apiUrl);
|
|
90
|
+
}
|
|
75
91
|
if (isCrossSite(request, audience)) {
|
|
76
92
|
return json({ state: null }, 403);
|
|
77
93
|
}
|
|
78
94
|
switch (request.method) {
|
|
79
95
|
case "GET": {
|
|
80
|
-
|
|
81
|
-
|
|
96
|
+
if (new URL(request.url).searchParams.get("refresh") === "1") {
|
|
97
|
+
const token = parseCookieHeader(request.headers.get("Cookie"))[cookieNamesFor(audience).refresh];
|
|
98
|
+
if (!token)
|
|
99
|
+
return json({ state: null }, 200);
|
|
100
|
+
const result = await refreshSessionCore(issuerUrl, audience, token, apiUrl);
|
|
101
|
+
if (result === "dead")
|
|
102
|
+
return json({ state: null }, 200, clearingCookies(audience));
|
|
103
|
+
if (!result)
|
|
104
|
+
return json({ state: null }, 502);
|
|
105
|
+
return json({ state: result.session }, 200, result.setCookies);
|
|
106
|
+
}
|
|
107
|
+
const { session, setCookies } = await resolveSessionCore(request.headers.get("Cookie"), audience, issuerUrl, apiUrl);
|
|
108
|
+
const completionName = `${cookieNamesFor(audience).refresh}.completion`;
|
|
109
|
+
const raw = parseCookieHeader(request.headers.get("Cookie"))[completionName];
|
|
110
|
+
let loginCompletion;
|
|
111
|
+
if (raw) {
|
|
112
|
+
setCookies.push(clearCookieString(completionName, {
|
|
113
|
+
secure: audience.startsWith("https:"),
|
|
114
|
+
}));
|
|
115
|
+
try {
|
|
116
|
+
const parsed = browserCompletionSchema.safeParse(JSON.parse(decodeURIComponent(atob(raw))));
|
|
117
|
+
if (parsed.success &&
|
|
118
|
+
parsed.data.expires > Date.now() &&
|
|
119
|
+
parsed.data.userId === session?.user.id)
|
|
120
|
+
loginCompletion = parsed.data;
|
|
121
|
+
}
|
|
122
|
+
catch { }
|
|
123
|
+
}
|
|
124
|
+
return json({ state: session, loginCompletion }, 200, setCookies);
|
|
82
125
|
}
|
|
83
126
|
case "POST": {
|
|
84
127
|
const parsed = installBodySchema.safeParse(await request.json().catch(() => null));
|
|
85
128
|
const body = parsed.success ? parsed.data : null;
|
|
129
|
+
if (body?.action === "login" || body?.action === "account") {
|
|
130
|
+
try {
|
|
131
|
+
return await startBrowserSession(request, audience, issuerUrl, {
|
|
132
|
+
...body,
|
|
133
|
+
action: body.action,
|
|
134
|
+
}, apiUrl);
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
return json({ state: null }, 502);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (body?.action === "guest") {
|
|
141
|
+
const existing = await resolveSessionCore(request.headers.get("Cookie"), audience, issuerUrl, apiUrl);
|
|
142
|
+
if (existing.session)
|
|
143
|
+
return json({ state: existing.session }, 200, existing.setCookies);
|
|
144
|
+
const previousRefresh = parseCookieHeader(request.headers.get("Cookie"))[cookieNamesFor(audience).refresh];
|
|
145
|
+
if (previousRefresh && existing.setCookies.length === 0)
|
|
146
|
+
return json({ state: null }, 502);
|
|
147
|
+
try {
|
|
148
|
+
const headers = new Headers({ "Content-Type": "application/json" });
|
|
149
|
+
for (const name of [
|
|
150
|
+
"cf-connecting-ip",
|
|
151
|
+
"x-forwarded-for",
|
|
152
|
+
"user-agent",
|
|
153
|
+
]) {
|
|
154
|
+
const value = request.headers.get(name);
|
|
155
|
+
if (value)
|
|
156
|
+
headers.set(name, value);
|
|
157
|
+
}
|
|
158
|
+
const result = await fetchIssuerApi(`${apiUrl}/api/auth/passkey/guest`, {
|
|
159
|
+
method: "POST",
|
|
160
|
+
headers,
|
|
161
|
+
body: JSON.stringify({ audience }),
|
|
162
|
+
});
|
|
163
|
+
if (!result.ok)
|
|
164
|
+
return json({ state: null }, result.status);
|
|
165
|
+
// SAFETY: the configured issuer returns this session token pair, verified below.
|
|
166
|
+
const data = (await result.json());
|
|
167
|
+
const claims = await verifyFlowJWT(data.jwt, {
|
|
168
|
+
audience,
|
|
169
|
+
issuerUrl,
|
|
170
|
+
apiUrl,
|
|
171
|
+
});
|
|
172
|
+
return json({
|
|
173
|
+
state: {
|
|
174
|
+
user: claimsToUser(claims),
|
|
175
|
+
jwt: data.jwt,
|
|
176
|
+
credential: null,
|
|
177
|
+
address: null,
|
|
178
|
+
},
|
|
179
|
+
}, 200, sessionCookies(audience, data.jwt, data.refreshToken));
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
return json({ state: null }, 502);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
86
185
|
// Reconcile mint: the browser asks its own server to obtain additional-
|
|
87
186
|
// audience sessions (e.g. talk.flow.game) authorized by the PRIMARY
|
|
88
187
|
// refresh cookie, for an embed that booted with no session of its own.
|
|
@@ -95,7 +194,7 @@ export async function handleSessionRequest(request, opts = {}) {
|
|
|
95
194
|
let additionalSessions = [];
|
|
96
195
|
if (token && audiences.length > 0) {
|
|
97
196
|
try {
|
|
98
|
-
const res = await
|
|
197
|
+
const res = await fetchIssuerApi(`${apiUrl}/api/session/additional`, {
|
|
99
198
|
method: "POST",
|
|
100
199
|
headers: {
|
|
101
200
|
"Content-Type": "application/json",
|
|
@@ -123,7 +222,11 @@ export async function handleSessionRequest(request, opts = {}) {
|
|
|
123
222
|
// for another app from being installed here; a failed install must not
|
|
124
223
|
// clear cookies that may hold a live session.
|
|
125
224
|
try {
|
|
126
|
-
const claims = await verifyFlowJWT(jwt, {
|
|
225
|
+
const claims = await verifyFlowJWT(jwt, {
|
|
226
|
+
audience,
|
|
227
|
+
issuerUrl,
|
|
228
|
+
apiUrl,
|
|
229
|
+
});
|
|
127
230
|
return json({ state: { user: claimsToUser(claims), jwt } }, 200, sessionCookies(audience, jwt, refreshToken));
|
|
128
231
|
}
|
|
129
232
|
catch (err) {
|
|
@@ -137,12 +240,16 @@ export async function handleSessionRequest(request, opts = {}) {
|
|
|
137
240
|
// an unreachable issuer just leaves the lineage to expire on its own.
|
|
138
241
|
if (token) {
|
|
139
242
|
try {
|
|
140
|
-
await
|
|
243
|
+
const response = await fetchIssuerApi(`${apiUrl}/api/session/revoke`, {
|
|
141
244
|
method: "POST",
|
|
142
245
|
headers: { Authorization: `Bearer ${token}` },
|
|
143
246
|
});
|
|
247
|
+
if (!response.ok)
|
|
248
|
+
return json({ state: null }, 502);
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
return json({ state: null }, 502);
|
|
144
252
|
}
|
|
145
|
-
catch { }
|
|
146
253
|
}
|
|
147
254
|
const headers = new Headers({ "Cache-Control": "no-store" });
|
|
148
255
|
for (const cookie of clearingCookies(audience)) {
|
package/dist/sdk/types/auth.d.ts
CHANGED
|
@@ -99,6 +99,8 @@ export type PasskeyPluginOptions = {
|
|
|
99
99
|
export type VerifyOptions = {
|
|
100
100
|
audience: string;
|
|
101
101
|
issuerUrl?: string;
|
|
102
|
+
/** Trusted server API origin; defaults to FLOW_ID_API_URL, then the public issuer. */
|
|
103
|
+
apiUrl?: string;
|
|
102
104
|
};
|
|
103
105
|
/**
|
|
104
106
|
* One entry in the signed-in user's session list (`GET /api/account/sessions`).
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { RpcRequest } from "./protocol";
|
|
2
1
|
/**
|
|
3
2
|
* Async view state for a dialog panel — the three states every fetched
|
|
4
3
|
* section renders (spinner / retry row / content), so "empty" stays
|
|
@@ -91,7 +90,6 @@ export type DialogState = {
|
|
|
91
90
|
customLabels?: DialogCustomLabels;
|
|
92
91
|
};
|
|
93
92
|
export type SignUpProps = {
|
|
94
|
-
request: RpcRequest;
|
|
95
93
|
rpId: string;
|
|
96
94
|
accessKeyHash?: string | undefined;
|
|
97
95
|
guestToken?: string | undefined;
|
|
@@ -99,7 +97,6 @@ export type SignUpProps = {
|
|
|
99
97
|
onSignIn: () => void;
|
|
100
98
|
};
|
|
101
99
|
export type SignInWithEmailProps = {
|
|
102
|
-
request: RpcRequest;
|
|
103
100
|
onBack: () => void;
|
|
104
101
|
onHome: () => void;
|
|
105
102
|
};
|
|
@@ -16,7 +16,7 @@ export { getConnectCapabilities, isPersonalSignParams, isSendCallsParams, isSend
|
|
|
16
16
|
export type { ReportOperation, ReportRequest, ReportResponse, ReportsApi, ReportTransport, } from "./reports";
|
|
17
17
|
export type { CreateRoomEventInput, RoomEventArchive, RoomEventAttendance, RoomEventFrequency, RoomEventInstance, RoomEventInterest, RoomEventInterestState, RoomEventList, RoomEventOccurrence, RoomEventRecurrence, RoomEventRoomRef, RoomEventRun, RoomEventSeries, RoomEventStatus, SetInterestInput, UpdateRoomEventInput, } from "./room-events";
|
|
18
18
|
export type { CreateRoomInput, GlobalRole, ModerationSubject, MyRooms, PlayerPositionReport, RoleChangeVerdict, RoomCapabilities, RoomCapability, RoomChannel, RoomDetail, RoomList, RoomMemberEntry, RoomMembers, RoomOccupancy, RoomOwner, RoomPlayerPosition, RoomPresenceEntry, RoomPresenceSnapshot, RoomRestrictionKind, RoomRole, RoomSummary, RoomSurfaceSettings, RoomsApi, RoomVisibility, StaffEntry, UpdateRoomInput, VerifyRoomContext, Viewer, VoiceDecisionReason, VoiceDecisionSubject, VoiceRoomDecision, } from "./rooms";
|
|
19
|
-
export type { AccessKeyOptions, AccessKeyPreparation, Address, ColorScheme, CreateDialogHostOptions, CreateFlowOptions, DialogHost, DialogOpenOptions, FinalizeAccessKeyParams, Flow, FlowConnectorParameters, FlowCookieNames, FlowIdProviderProps, FlowSessionState, FlowState, FlowWidgetHandle, FlowWidgetName, FlowWidgetProps, Listener, LoginOptions, MountFlowWidgetOptions, MountProfileOptions, OpenProfileOptions, PrepareArgsWithAuth, PrepareTransactionRequestPhase, ProfileButtonHandle, ProfileButtonProps, ProfilePosition, ResolveAccountParams, ResolvedAccessKeyOptions, RootCredential,
|
|
19
|
+
export type { AccessKeyOptions, AccessKeyPreparation, Address, ColorScheme, CreateDialogHostOptions, CreateFlowOptions, DialogHost, DialogOpenOptions, FinalizeAccessKeyParams, Flow, FlowConnectorParameters, FlowCookieNames, FlowIdProviderProps, FlowSessionState, FlowState, FlowWidgetHandle, FlowWidgetName, FlowWidgetProps, Listener, LoginOptions, MountFlowWidgetOptions, MountProfileOptions, OpenProfileOptions, PrepareArgsWithAuth, PrepareTransactionRequestPhase, ProfileButtonHandle, ProfileButtonProps, ProfilePosition, ResolveAccountParams, ResolvedAccessKeyOptions, RootCredential, SendCallsArgs, SendTransactionArgs, Session, SigningContext, SignMessageArgs, SignTypedDataArgs, Store, StoredAccessKey, UseOpenProfileOptions, WagmiConnectCapabilities, WagmiConnectParams, } from "./sdk";
|
|
20
20
|
export type { GracefulShutdownCleanup, GracefulShutdownOptions, GracefulShutdownServer, GracefulShutdownSignal, ResolvedFlowSession, ResolveSessionOptions, SessionRouteOptions, SessionRouteResponse, SessionRouteSession, } from "./server";
|
|
21
21
|
export type { CosmeticOffer, PaintDescriptor, SettingDescriptor, Settings, SettingsMigration, StoredSettings, SurfaceRegistry, } from "./settings";
|
|
22
22
|
export type { CreateStudySubjectInput, ListStudySessionsInput, StudyCatalog, StudyCategory, StudyCategoryTotals, StudyField, StudyRange, StudySessionEntry, StudySessionPage, StudySessionsResult, StudySubject, StudySubjectCreation, StudySubjectList, StudySubjectRefusal, StudySubjectRemoval, StudySubjectRemovalResponse, StudySubjectTotals, StudySubjectUpdate, StudySummary, UpdateStudySubjectInput, } from "./study";
|
package/dist/sdk/types/sdk.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { Chain, Hex, PrepareTransactionRequestParameters, SendTransactionPa
|
|
|
3
3
|
import type { SendCallsParameters } from "viem/actions";
|
|
4
4
|
import type { RawValue } from "../json";
|
|
5
5
|
import type { AdditionalSession, FlowCredential, FlowUser, WebAuthnSignature } from "./auth";
|
|
6
|
-
import type { ConnectCapabilities
|
|
6
|
+
import type { ConnectCapabilities } from "./protocol";
|
|
7
7
|
import type { RoomsApi } from "./rooms";
|
|
8
8
|
export type Address = `0x${string}`;
|
|
9
9
|
/**
|
|
@@ -133,10 +133,9 @@ export type FlowCookieNames = {
|
|
|
133
133
|
refresh: string;
|
|
134
134
|
};
|
|
135
135
|
export type LoginOptions = {
|
|
136
|
-
|
|
136
|
+
returnTo?: string;
|
|
137
137
|
signUp?: boolean;
|
|
138
138
|
signIn?: boolean;
|
|
139
|
-
signInHeadless?: boolean;
|
|
140
139
|
};
|
|
141
140
|
export type Session = {
|
|
142
141
|
user: FlowUser;
|
|
@@ -197,7 +196,7 @@ export type ColorScheme = "light" | "dark" | "light dark";
|
|
|
197
196
|
export type ProfilePosition = "top-right" | "top-left" | "bottom-right" | "bottom-left";
|
|
198
197
|
export type MountProfileOptions = {
|
|
199
198
|
/**
|
|
200
|
-
* Element to mount the
|
|
199
|
+
* Element to mount the native account button into. When omitted, a fixed-position
|
|
201
200
|
* container is created and anchored via `position` — the path of least
|
|
202
201
|
* resistance for non-DOM hosts (the Godot canvas overlay).
|
|
203
202
|
*/
|
|
@@ -221,12 +220,10 @@ export type MountProfileOptions = {
|
|
|
221
220
|
};
|
|
222
221
|
export type ProfileButtonHandle = {
|
|
223
222
|
/**
|
|
224
|
-
* Recolors the mounted
|
|
225
|
-
* theme toggle calls this instead of remounting: rebuilding the iframe would
|
|
226
|
-
* reload the widget and flash the pill out of the layout on every toggle.
|
|
223
|
+
* Recolors the mounted account button without remounting it.
|
|
227
224
|
*/
|
|
228
225
|
setTheme: (theme: ColorScheme) => void;
|
|
229
|
-
/** Tears down the
|
|
226
|
+
/** Tears down the button, listeners, and any auto-created container. */
|
|
230
227
|
destroy: () => void;
|
|
231
228
|
};
|
|
232
229
|
export type OpenProfileOptions = {
|
|
@@ -332,7 +329,8 @@ export type Flow = {
|
|
|
332
329
|
* actions on `!isGuest`, not on `isAuthenticated`.
|
|
333
330
|
*/
|
|
334
331
|
readonly isGuest: boolean;
|
|
335
|
-
login(options?: LoginOptions): Promise<
|
|
332
|
+
login(options?: LoginOptions): Promise<never>;
|
|
333
|
+
openAccount(): boolean;
|
|
336
334
|
logout(): Promise<void>;
|
|
337
335
|
restore(): Promise<boolean>;
|
|
338
336
|
/**
|
|
@@ -413,18 +411,6 @@ export type ProfileButtonProps = {
|
|
|
413
411
|
/** Color scheme for the widget chrome; defaults to "light dark" (the OS). */
|
|
414
412
|
theme?: ColorScheme;
|
|
415
413
|
};
|
|
416
|
-
export type RunLoginParams = {
|
|
417
|
-
dialog: DialogHost;
|
|
418
|
-
store: Store<FlowState>;
|
|
419
|
-
options?: LoginOptions;
|
|
420
|
-
extraCapabilities?: ConnectCapabilities;
|
|
421
|
-
};
|
|
422
|
-
export type RunLoginResult = {
|
|
423
|
-
session: Session;
|
|
424
|
-
refreshToken: string;
|
|
425
|
-
webauthn: ConnectResponse["webauthn"];
|
|
426
|
-
additionalSessions?: AdditionalSession[];
|
|
427
|
-
};
|
|
428
414
|
export type FinalizeAccessKeyParams = {
|
|
429
415
|
address: Address;
|
|
430
416
|
credential: FlowCredential;
|
|
@@ -6,6 +6,8 @@ export type ResolveSessionOptions = {
|
|
|
6
6
|
audience: string;
|
|
7
7
|
/** Flow ID origin; defaults to `https://id.flow.industries`. */
|
|
8
8
|
issuerUrl?: string;
|
|
9
|
+
/** Trusted server API origin; defaults to FLOW_ID_API_URL, then the public issuer. */
|
|
10
|
+
apiUrl?: string;
|
|
9
11
|
/**
|
|
10
12
|
* Also fetch the public profile (avatar, tier, level) for a resolved
|
|
11
13
|
* session via `/api/session/verify` — one extra round-trip; off by default.
|
|
@@ -36,6 +38,8 @@ export type SessionRouteOptions = {
|
|
|
36
38
|
audience?: string;
|
|
37
39
|
/** Flow ID origin; defaults per `defaultIdHost` (`FLOW_ID_HOST` on servers). */
|
|
38
40
|
issuerUrl?: string;
|
|
41
|
+
/** Trusted server API origin; defaults to FLOW_ID_API_URL, then the public issuer. */
|
|
42
|
+
apiUrl?: string;
|
|
39
43
|
/** Route path for `createSessionHandler`'s own path check. */
|
|
40
44
|
path?: string;
|
|
41
45
|
};
|
|
@@ -53,6 +57,12 @@ export type SessionRouteSession = {
|
|
|
53
57
|
};
|
|
54
58
|
export type SessionRouteResponse = {
|
|
55
59
|
state: SessionRouteSession | null;
|
|
60
|
+
loginCompletion?: {
|
|
61
|
+
loginId: string;
|
|
62
|
+
userId: string;
|
|
63
|
+
expires: number;
|
|
64
|
+
webauthn?: import("./auth").WebAuthnSignature;
|
|
65
|
+
};
|
|
56
66
|
/**
|
|
57
67
|
* Additional-audience sessions minted by a reconcile request (POST `{ mint }`)
|
|
58
68
|
* — one per allowed audience the caller asked to provision. The consumer
|
package/dist/sdk/verify.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { createRemoteJWKSet, jwtVerify } from "jose";
|
|
1
|
+
import { createRemoteJWKSet, customFetch, jwtVerify } from "jose";
|
|
2
|
+
import { fetchIssuerApi, resolveIssuerApiUrl } from "./issuer-api";
|
|
2
3
|
const jwksCache = new Map();
|
|
3
4
|
const DEFAULT_ISSUER_URL = "https://id.flow.industries";
|
|
4
5
|
/**
|
|
@@ -22,10 +23,14 @@ const DEFAULT_ISSUER_URL = "https://id.flow.industries";
|
|
|
22
23
|
*/
|
|
23
24
|
export async function verifyFlowJWT(token, opts) {
|
|
24
25
|
const issuerUrl = opts.issuerUrl ?? DEFAULT_ISSUER_URL;
|
|
25
|
-
|
|
26
|
+
const apiUrl = resolveIssuerApiUrl(issuerUrl, opts.apiUrl);
|
|
27
|
+
const cacheKey = `${issuerUrl}\n${apiUrl}`;
|
|
28
|
+
let jwks = jwksCache.get(cacheKey);
|
|
26
29
|
if (!jwks) {
|
|
27
|
-
jwks = createRemoteJWKSet(new URL(`${
|
|
28
|
-
|
|
30
|
+
jwks = createRemoteJWKSet(new URL(`${apiUrl}/api/auth/jwks`), {
|
|
31
|
+
[customFetch]: fetchIssuerApi,
|
|
32
|
+
});
|
|
33
|
+
jwksCache.set(cacheKey, jwks);
|
|
29
34
|
}
|
|
30
35
|
const { payload } = await jwtVerify(token, jwks, {
|
|
31
36
|
issuer: issuerUrl,
|
package/dist/sdk/wagmi/index.js
CHANGED
|
@@ -5,12 +5,9 @@ flowConnector.type = "flow";
|
|
|
5
5
|
function loginOptionsFromCapabilities(capabilities) {
|
|
6
6
|
const signUp = capabilities?.type === "sign-up" || capabilities?.createAccount;
|
|
7
7
|
const signIn = capabilities?.type === "sign-in" || capabilities?.signIn;
|
|
8
|
-
const headless = !signUp &&
|
|
9
|
-
(capabilities?.signInHeadless || capabilities?.type === "sign-in");
|
|
10
8
|
return {
|
|
11
9
|
signUp: signUp ? true : undefined,
|
|
12
10
|
signIn: !signUp && signIn ? true : undefined,
|
|
13
|
-
signInHeadless: headless ? true : undefined,
|
|
14
11
|
};
|
|
15
12
|
}
|
|
16
13
|
export function flowConnector(parameters = {}) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flow-industries/id",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -66,9 +66,10 @@
|
|
|
66
66
|
"scripts": {
|
|
67
67
|
"dev": "./dev.sh",
|
|
68
68
|
"build:dialog": "bunx vite build",
|
|
69
|
+
"build:legacy-dialog": "bunx vite build --config vite.legacy.config.ts",
|
|
69
70
|
"build:playground": "bunx vite build --config vite.playground.config.ts",
|
|
70
71
|
"build:landing": "bunx vite build --config vite.landing.config.ts",
|
|
71
|
-
"build": "bunx vite build && bunx vite build --config vite.playground.config.ts && bunx vite build --config vite.landing.config.ts",
|
|
72
|
+
"build": "bun run build:legacy-dialog && bunx vite build && bunx vite build --config vite.playground.config.ts && bunx vite build --config vite.landing.config.ts",
|
|
72
73
|
"build:sdk": "tsc --project tsconfig.sdk.json",
|
|
73
74
|
"prepublishOnly": "bun run build:sdk",
|
|
74
75
|
"start": "bun run src/index.ts",
|
|
@@ -84,7 +85,7 @@
|
|
|
84
85
|
"test:sdk-package": "bash scripts/test-sdk-package.sh",
|
|
85
86
|
"format": "biome format --write",
|
|
86
87
|
"check": "biome check --write",
|
|
87
|
-
"typecheck": "tsr generate && tsc --noEmit",
|
|
88
|
+
"typecheck": "tsr generate && (cd src/legacy-dialog && bunx tsr generate) && tsc --noEmit && tsc -p tsconfig.legacy.json --noEmit",
|
|
88
89
|
"contracts:generate": "bun scripts/generate-contracts.ts",
|
|
89
90
|
"contracts:check": "bun scripts/generate-contracts.ts --check && bun scripts/check-contract-compatibility.ts",
|
|
90
91
|
"db:check": "bun scripts/db-check.ts",
|