@flow-industries/id 0.21.1 → 0.22.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/sdk/client/create-flow.js +3 -5
- package/dist/sdk/client/dialog-host.js +13 -1
- package/dist/sdk/client/flow-widget.js +6 -1
- package/dist/sdk/client/focus-session.d.ts +18 -0
- package/dist/sdk/client/focus-session.js +140 -0
- package/dist/sdk/client/focus.d.ts +11 -0
- package/dist/sdk/client/focus.js +30 -0
- package/dist/sdk/client/iframe-host.d.ts +5 -3
- package/dist/sdk/client/iframe-host.js +6 -3
- package/dist/sdk/client/index.d.ts +2 -1
- package/dist/sdk/client/index.js +1 -0
- package/dist/sdk/client/json-api.d.ts +1 -1
- package/dist/sdk/client/json-api.js +3 -1
- package/dist/sdk/client/open-profile.js +7 -3
- package/dist/sdk/client/overlay-focus.d.ts +1 -0
- package/dist/sdk/client/overlay-focus.js +24 -0
- package/dist/sdk/client/profile-button.js +9 -4
- package/dist/sdk/client/rooms.js +7 -26
- package/dist/sdk/client/study-search.d.ts +20 -0
- package/dist/sdk/client/study-search.js +116 -0
- package/dist/sdk/react/use-cooldown.d.ts +1 -0
- package/dist/sdk/react/use-cooldown.js +12 -0
- package/dist/sdk/types/account-data.d.ts +269 -0
- package/dist/sdk/types/account-data.js +0 -0
- package/dist/sdk/types/auth.d.ts +12 -0
- package/dist/sdk/types/dialog.d.ts +25 -0
- package/dist/sdk/types/events.d.ts +5 -1
- package/dist/sdk/types/focus.d.ts +109 -0
- package/dist/sdk/types/focus.js +0 -0
- package/dist/sdk/types/index.d.ts +8 -3
- package/dist/sdk/types/landing.d.ts +9 -0
- package/dist/sdk/types/landing.js +0 -0
- package/dist/sdk/types/otp.d.ts +20 -0
- package/dist/sdk/types/otp.js +0 -0
- package/dist/sdk/types/sdk.d.ts +1 -0
- package/dist/sdk/types/settings.d.ts +162 -0
- package/dist/sdk/types/settings.js +0 -0
- package/dist/sdk/types/xp.d.ts +8 -0
- package/package.json +6 -2
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
export function normalizeSearchText(text) {
|
|
2
|
+
return text
|
|
3
|
+
.normalize("NFD")
|
|
4
|
+
.replace(/\p{M}+/gu, "")
|
|
5
|
+
.toLowerCase()
|
|
6
|
+
.replace(/\s+/g, " ")
|
|
7
|
+
.trim();
|
|
8
|
+
}
|
|
9
|
+
/** 4 exact, 3 prefix, 2 a later word's prefix, 1 substring, 0 no match.
|
|
10
|
+
* Both sides are normalized here so callers can pass raw labels. */
|
|
11
|
+
export function matchScore(query, candidate) {
|
|
12
|
+
const normalizedQuery = normalizeSearchText(query);
|
|
13
|
+
const normalizedCandidate = normalizeSearchText(candidate);
|
|
14
|
+
if (!normalizedQuery || !normalizedCandidate)
|
|
15
|
+
return 0;
|
|
16
|
+
if (normalizedCandidate === normalizedQuery)
|
|
17
|
+
return 4;
|
|
18
|
+
if (normalizedCandidate.startsWith(normalizedQuery))
|
|
19
|
+
return 3;
|
|
20
|
+
if (normalizedCandidate.includes(` ${normalizedQuery}`))
|
|
21
|
+
return 2;
|
|
22
|
+
if (normalizedCandidate.includes(normalizedQuery))
|
|
23
|
+
return 1;
|
|
24
|
+
return 0;
|
|
25
|
+
}
|
|
26
|
+
export function catalogFieldIndex(catalog) {
|
|
27
|
+
const index = new Map();
|
|
28
|
+
for (const category of catalog.categories) {
|
|
29
|
+
for (const field of category.fields) {
|
|
30
|
+
index.set(field.slug, { category, field });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return index;
|
|
34
|
+
}
|
|
35
|
+
/** Live subjects newest-used first; auth stamps `lastUsedAt` at creation, so
|
|
36
|
+
* a subject never studied sorts by when it was added. */
|
|
37
|
+
export function recentSubjects(subjects, limit = 5) {
|
|
38
|
+
return [...subjects]
|
|
39
|
+
.sort((a, b) => b.lastUsedAt.localeCompare(a.lastUsedAt))
|
|
40
|
+
.slice(0, limit);
|
|
41
|
+
}
|
|
42
|
+
/** Catalog fields the user already keeps under the field's own name are
|
|
43
|
+
* hidden from results — the subject hit covers them and picking the field
|
|
44
|
+
* again would only re-create the same subject. A renamed subject ("Math for
|
|
45
|
+
* my test" under Algebra) leaves the field visible for a second subject. */
|
|
46
|
+
export function fieldsCoveredBySubjects(subjects, index) {
|
|
47
|
+
const covered = new Set();
|
|
48
|
+
for (const subject of subjects) {
|
|
49
|
+
if (!subject.field)
|
|
50
|
+
continue;
|
|
51
|
+
const ref = index.get(subject.field);
|
|
52
|
+
if (!ref)
|
|
53
|
+
continue;
|
|
54
|
+
if (normalizeSearchText(subject.name) === normalizeSearchText(ref.field.label)) {
|
|
55
|
+
covered.add(subject.field);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return covered;
|
|
59
|
+
}
|
|
60
|
+
function bestAliasMatch(query, field) {
|
|
61
|
+
let best = null;
|
|
62
|
+
for (const alias of field.aliases ?? []) {
|
|
63
|
+
const score = matchScore(query, alias);
|
|
64
|
+
if (score > (best?.score ?? 0))
|
|
65
|
+
best = { alias, score };
|
|
66
|
+
}
|
|
67
|
+
return best;
|
|
68
|
+
}
|
|
69
|
+
export function searchStudy(query, options) {
|
|
70
|
+
const { catalog, subjects, limit = 12 } = options;
|
|
71
|
+
if (!normalizeSearchText(query))
|
|
72
|
+
return [];
|
|
73
|
+
const index = catalogFieldIndex(catalog);
|
|
74
|
+
const covered = fieldsCoveredBySubjects(subjects, index);
|
|
75
|
+
const hits = [];
|
|
76
|
+
for (const subject of subjects) {
|
|
77
|
+
const ref = subject.field ? (index.get(subject.field) ?? null) : null;
|
|
78
|
+
let score = matchScore(query, subject.name);
|
|
79
|
+
if (ref) {
|
|
80
|
+
score = Math.max(score, matchScore(query, ref.field.label));
|
|
81
|
+
const alias = bestAliasMatch(query, ref.field);
|
|
82
|
+
if (alias)
|
|
83
|
+
score = Math.max(score, alias.score);
|
|
84
|
+
}
|
|
85
|
+
if (score > 0) {
|
|
86
|
+
hits.push({ kind: "subject", id: subject.id, subject, ref, score });
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
for (const ref of index.values()) {
|
|
90
|
+
if (covered.has(ref.field.slug))
|
|
91
|
+
continue;
|
|
92
|
+
const labelScore = matchScore(query, ref.field.label);
|
|
93
|
+
const alias = bestAliasMatch(query, ref.field);
|
|
94
|
+
const score = Math.max(labelScore, alias?.score ?? 0);
|
|
95
|
+
if (score === 0)
|
|
96
|
+
continue;
|
|
97
|
+
hits.push({
|
|
98
|
+
kind: "field",
|
|
99
|
+
id: ref.field.slug,
|
|
100
|
+
ref,
|
|
101
|
+
alias: alias && alias.score > labelScore ? alias.alias : null,
|
|
102
|
+
score,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
hits.sort((a, b) => {
|
|
106
|
+
if (b.score !== a.score)
|
|
107
|
+
return b.score - a.score;
|
|
108
|
+
if (a.kind !== b.kind)
|
|
109
|
+
return a.kind === "subject" ? -1 : 1;
|
|
110
|
+
return hitLabel(a).localeCompare(hitLabel(b));
|
|
111
|
+
});
|
|
112
|
+
return hits.slice(0, limit);
|
|
113
|
+
}
|
|
114
|
+
export function hitLabel(hit) {
|
|
115
|
+
return hit.kind === "subject" ? hit.subject.name : hit.ref.field.label;
|
|
116
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function useCooldown(initial: number): [number, (next: number) => void];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
export function useCooldown(initial) {
|
|
3
|
+
const [cooldown, setCooldown] = useState(initial);
|
|
4
|
+
const cooldownActive = cooldown > 0;
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
if (!cooldownActive)
|
|
7
|
+
return;
|
|
8
|
+
const timer = setInterval(() => setCooldown((c) => (c <= 1 ? 0 : c - 1)), 1000);
|
|
9
|
+
return () => clearInterval(timer);
|
|
10
|
+
}, [cooldownActive]);
|
|
11
|
+
return [cooldown, setCooldown];
|
|
12
|
+
}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import type { RawRecord, RawValue } from "../json";
|
|
2
|
+
import type { AccountSession, SecurityActivityEntry } from "./auth";
|
|
3
|
+
import type { RoomEventRecurrence } from "./room-events";
|
|
4
|
+
/**
|
|
5
|
+
* Self-serve account deletion (AUTH-246), the personal-data export (AUTH-247)
|
|
6
|
+
* and the erasure ledger downstream services replay (AUTH-119).
|
|
7
|
+
*/
|
|
8
|
+
/** Body of `POST /api/account/delete`: the caller's current username, typed
|
|
9
|
+
* back as the confirmation. */
|
|
10
|
+
export type AccountDeleteRequest = {
|
|
11
|
+
confirm: string;
|
|
12
|
+
};
|
|
13
|
+
export type AccountDeleteResponse = {
|
|
14
|
+
ok: true;
|
|
15
|
+
};
|
|
16
|
+
/** What one account deletion removed, beyond the user row's own cascade. */
|
|
17
|
+
export type AccountErasureCounts = {
|
|
18
|
+
/** Non-system rooms the account owned, deleted with everything inside them. */
|
|
19
|
+
ownedRoomsDeleted: number;
|
|
20
|
+
/** Cookie sessions the cascade took down. */
|
|
21
|
+
sessionsDeleted: number;
|
|
22
|
+
/** Passkeys the cascade took down. */
|
|
23
|
+
passkeysDeleted: number;
|
|
24
|
+
/** OTP / quota rows keyed on the account's email or id. */
|
|
25
|
+
verificationsDeleted: number;
|
|
26
|
+
/** Per-user rate-limit rows (never the ip-keyed ones). */
|
|
27
|
+
rateLimitsDeleted: number;
|
|
28
|
+
};
|
|
29
|
+
/** Result of `deleteAccount`: `missing` is the idempotent second call. */
|
|
30
|
+
export type AccountErasureResult = {
|
|
31
|
+
outcome: "missing";
|
|
32
|
+
} | {
|
|
33
|
+
outcome: "deleted";
|
|
34
|
+
userId: string;
|
|
35
|
+
isGuest: boolean;
|
|
36
|
+
/** The stored avatar URL, for the post-commit object delete. */
|
|
37
|
+
image: string | null;
|
|
38
|
+
counts: AccountErasureCounts;
|
|
39
|
+
};
|
|
40
|
+
/** One row of the erasure ledger as `GET /api/account/erasures` serves it. */
|
|
41
|
+
export type AccountErasureEntry = {
|
|
42
|
+
seq: number;
|
|
43
|
+
/** The deleted account's Flow `user.id` — the JWT `sub` consumers keyed on. */
|
|
44
|
+
sub: string;
|
|
45
|
+
deletedRoomIds: string[];
|
|
46
|
+
erasedAt: string;
|
|
47
|
+
};
|
|
48
|
+
export type AccountErasureFeed = {
|
|
49
|
+
/** Ascending by `seq`. */
|
|
50
|
+
erasures: AccountErasureEntry[];
|
|
51
|
+
/** Feed this back as `after` for the next page; equals the request's
|
|
52
|
+
* `after` when the page was empty. */
|
|
53
|
+
nextAfter: number;
|
|
54
|
+
};
|
|
55
|
+
export type AccountExportAccount = {
|
|
56
|
+
id: string;
|
|
57
|
+
username: string;
|
|
58
|
+
name: string | null;
|
|
59
|
+
email: string | null;
|
|
60
|
+
emailVerified: boolean;
|
|
61
|
+
isGuest: boolean;
|
|
62
|
+
role: string;
|
|
63
|
+
image: string | null;
|
|
64
|
+
bio: string | null;
|
|
65
|
+
walletAddress: string | null;
|
|
66
|
+
subscribedToNews: boolean;
|
|
67
|
+
createdAt: string;
|
|
68
|
+
};
|
|
69
|
+
/** A passkey as the owner sees it: metadata only, never the public key,
|
|
70
|
+
* credential id or signature counter. */
|
|
71
|
+
export type AccountExportPasskey = {
|
|
72
|
+
id: string;
|
|
73
|
+
name: string | null;
|
|
74
|
+
deviceType: string | null;
|
|
75
|
+
backedUp: boolean | null;
|
|
76
|
+
transports: string | null;
|
|
77
|
+
aaguid: string | null;
|
|
78
|
+
createdAt: string;
|
|
79
|
+
};
|
|
80
|
+
export type AccountExportSettingsSurface = {
|
|
81
|
+
version: number;
|
|
82
|
+
settings: Record<string, RawValue>;
|
|
83
|
+
};
|
|
84
|
+
export type AccountExportXpSummary = {
|
|
85
|
+
totalXp: number;
|
|
86
|
+
flowScore: number;
|
|
87
|
+
lastVisitDate: string | null;
|
|
88
|
+
updatedAt: string;
|
|
89
|
+
};
|
|
90
|
+
export type AccountExportXpGrant = {
|
|
91
|
+
id: string;
|
|
92
|
+
source: string;
|
|
93
|
+
baseAmount: number;
|
|
94
|
+
flowScore: number;
|
|
95
|
+
amount: number;
|
|
96
|
+
metadata: RawRecord | null;
|
|
97
|
+
createdAt: string;
|
|
98
|
+
};
|
|
99
|
+
export type AccountExportActionEvent = {
|
|
100
|
+
id: string;
|
|
101
|
+
sessionId: string;
|
|
102
|
+
kind: string;
|
|
103
|
+
accruedSeconds: number;
|
|
104
|
+
at: string;
|
|
105
|
+
};
|
|
106
|
+
export type AccountExportRoomSettings = {
|
|
107
|
+
roomId: string;
|
|
108
|
+
surface: string;
|
|
109
|
+
settings: RawRecord;
|
|
110
|
+
version: number;
|
|
111
|
+
};
|
|
112
|
+
export type AccountExportActionSession = {
|
|
113
|
+
id: string;
|
|
114
|
+
source: string;
|
|
115
|
+
state: string;
|
|
116
|
+
subjectId: string | null;
|
|
117
|
+
accruedSeconds: number;
|
|
118
|
+
focusedSeconds: number;
|
|
119
|
+
xpGranted: number | null;
|
|
120
|
+
metadata: RawRecord | null;
|
|
121
|
+
startedAt: string;
|
|
122
|
+
updatedAt: string;
|
|
123
|
+
finishedAt: string | null;
|
|
124
|
+
};
|
|
125
|
+
export type AccountExportStudySubject = {
|
|
126
|
+
id: string;
|
|
127
|
+
field: string | null;
|
|
128
|
+
name: string;
|
|
129
|
+
archivedAt: string | null;
|
|
130
|
+
createdAt: string;
|
|
131
|
+
lastUsedAt: string;
|
|
132
|
+
};
|
|
133
|
+
export type AccountExportCharacterStateTime = {
|
|
134
|
+
day: string;
|
|
135
|
+
state: string;
|
|
136
|
+
seconds: number;
|
|
137
|
+
updatedAt: string;
|
|
138
|
+
};
|
|
139
|
+
export type AccountExportOwnedRoom = {
|
|
140
|
+
id: string;
|
|
141
|
+
slug: string;
|
|
142
|
+
displayName: string;
|
|
143
|
+
description: string | null;
|
|
144
|
+
visibility: string;
|
|
145
|
+
isSystem: boolean;
|
|
146
|
+
createdAt: string;
|
|
147
|
+
updatedAt: string;
|
|
148
|
+
};
|
|
149
|
+
export type AccountExportRoomMembership = {
|
|
150
|
+
roomId: string;
|
|
151
|
+
roomSlug: string;
|
|
152
|
+
role: string;
|
|
153
|
+
joinedAt: string;
|
|
154
|
+
};
|
|
155
|
+
/** A restriction placed on the caller. The issuing moderator is deliberately
|
|
156
|
+
* absent — the export carries only the caller's own identity. */
|
|
157
|
+
export type AccountExportRoomRestriction = {
|
|
158
|
+
id: string;
|
|
159
|
+
roomId: string;
|
|
160
|
+
kind: string;
|
|
161
|
+
reason: string | null;
|
|
162
|
+
expiresAt: string | null;
|
|
163
|
+
createdAt: string;
|
|
164
|
+
};
|
|
165
|
+
export type AccountExportRoomPresence = {
|
|
166
|
+
roomId: string;
|
|
167
|
+
channel: string;
|
|
168
|
+
joinedAt: string;
|
|
169
|
+
updatedAt: string;
|
|
170
|
+
};
|
|
171
|
+
export type AccountExportRoomPlayerState = {
|
|
172
|
+
roomId: string;
|
|
173
|
+
x: number;
|
|
174
|
+
y: number;
|
|
175
|
+
z: number;
|
|
176
|
+
yaw: number;
|
|
177
|
+
worldId: string;
|
|
178
|
+
updatedAt: string;
|
|
179
|
+
};
|
|
180
|
+
export type AccountExportRooms = {
|
|
181
|
+
settings: AccountExportRoomSettings[];
|
|
182
|
+
owned: AccountExportOwnedRoom[];
|
|
183
|
+
memberships: AccountExportRoomMembership[];
|
|
184
|
+
restrictions: AccountExportRoomRestriction[];
|
|
185
|
+
presence: AccountExportRoomPresence[];
|
|
186
|
+
playerState: AccountExportRoomPlayerState[];
|
|
187
|
+
};
|
|
188
|
+
export type AccountExportAuthoredEvent = {
|
|
189
|
+
id: string;
|
|
190
|
+
roomId: string;
|
|
191
|
+
title: string;
|
|
192
|
+
description: string | null;
|
|
193
|
+
coverUrl: string | null;
|
|
194
|
+
startsAt: string;
|
|
195
|
+
endsAt: string | null;
|
|
196
|
+
timezone: string;
|
|
197
|
+
recurrence: RoomEventRecurrence | null;
|
|
198
|
+
reminderOffsets: number[] | null;
|
|
199
|
+
status: string;
|
|
200
|
+
createdAt: string;
|
|
201
|
+
updatedAt: string;
|
|
202
|
+
};
|
|
203
|
+
export type AccountExportRsvp = {
|
|
204
|
+
occurrenceId: string;
|
|
205
|
+
createdAt: string;
|
|
206
|
+
};
|
|
207
|
+
export type AccountExportFollow = {
|
|
208
|
+
eventId: string;
|
|
209
|
+
createdAt: string;
|
|
210
|
+
};
|
|
211
|
+
export type AccountExportAttendance = {
|
|
212
|
+
occurrenceId: string;
|
|
213
|
+
firstSeenAt: string;
|
|
214
|
+
lastSeenAt: string;
|
|
215
|
+
};
|
|
216
|
+
export type AccountExportRoomEvents = {
|
|
217
|
+
authored: AccountExportAuthoredEvent[];
|
|
218
|
+
rsvps: AccountExportRsvp[];
|
|
219
|
+
follows: AccountExportFollow[];
|
|
220
|
+
attendance: AccountExportAttendance[];
|
|
221
|
+
};
|
|
222
|
+
export type AccountExportGameEvent = {
|
|
223
|
+
id: string;
|
|
224
|
+
event: string;
|
|
225
|
+
occurredAt: string;
|
|
226
|
+
recordedAt: string;
|
|
227
|
+
serverId: string;
|
|
228
|
+
sessionId: string | null;
|
|
229
|
+
roomId: string | null;
|
|
230
|
+
roomSlug: string | null;
|
|
231
|
+
reason: string | null;
|
|
232
|
+
detail: RawRecord | null;
|
|
233
|
+
};
|
|
234
|
+
/** Where the rest of a person's Flow data lives, so one export names every
|
|
235
|
+
* service that has to be asked. */
|
|
236
|
+
export type AccountExportOtherService = {
|
|
237
|
+
service: string;
|
|
238
|
+
export: string;
|
|
239
|
+
holds: string;
|
|
240
|
+
};
|
|
241
|
+
/** The whole personal-data export (`GET /api/account/export`), version 1. */
|
|
242
|
+
export type AccountExport = {
|
|
243
|
+
format: "flow-id-export";
|
|
244
|
+
version: 1;
|
|
245
|
+
exportedAt: string;
|
|
246
|
+
account: AccountExportAccount;
|
|
247
|
+
passkeys: AccountExportPasskey[];
|
|
248
|
+
sessions: AccountSession[];
|
|
249
|
+
settings: Record<string, AccountExportSettingsSurface>;
|
|
250
|
+
xp: {
|
|
251
|
+
summary: AccountExportXpSummary | null;
|
|
252
|
+
ledger: AccountExportXpGrant[];
|
|
253
|
+
};
|
|
254
|
+
actions: {
|
|
255
|
+
events: AccountExportActionEvent[];
|
|
256
|
+
sessions: AccountExportActionSession[];
|
|
257
|
+
};
|
|
258
|
+
study: {
|
|
259
|
+
subjects: AccountExportStudySubject[];
|
|
260
|
+
};
|
|
261
|
+
characterStateTime: AccountExportCharacterStateTime[];
|
|
262
|
+
rooms: AccountExportRooms;
|
|
263
|
+
roomEvents: AccountExportRoomEvents;
|
|
264
|
+
gameEvents: AccountExportGameEvent[];
|
|
265
|
+
securityActivity: SecurityActivityEntry[];
|
|
266
|
+
otherServices: AccountExportOtherService[];
|
|
267
|
+
/** Dotted names of every collection that hit the row cap (newest rows kept). */
|
|
268
|
+
truncated: string[];
|
|
269
|
+
};
|
|
File without changes
|
package/dist/sdk/types/auth.d.ts
CHANGED
|
@@ -160,3 +160,15 @@ export type VerifiedFlowJWT = JWTPayload & {
|
|
|
160
160
|
*/
|
|
161
161
|
guest?: boolean;
|
|
162
162
|
};
|
|
163
|
+
export type PasskeyEnrollment = {
|
|
164
|
+
userId: string;
|
|
165
|
+
username: string;
|
|
166
|
+
credential: FlowCredential;
|
|
167
|
+
};
|
|
168
|
+
export type AccountRegistration = {
|
|
169
|
+
username: string;
|
|
170
|
+
email: string;
|
|
171
|
+
subscribedToNews: boolean;
|
|
172
|
+
walletAddress: string | null;
|
|
173
|
+
credential: FlowCredential | null;
|
|
174
|
+
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { RpcRequest } from "./protocol";
|
|
1
2
|
/**
|
|
2
3
|
* Async view state for a dialog panel — the three states every fetched
|
|
3
4
|
* section renders (spinner / retry row / content), so "empty" stays
|
|
@@ -89,3 +90,27 @@ export type DialogState = {
|
|
|
89
90
|
customFeatures?: DialogCustomFeatures;
|
|
90
91
|
customLabels?: DialogCustomLabels;
|
|
91
92
|
};
|
|
93
|
+
export type SignUpProps = {
|
|
94
|
+
request: RpcRequest;
|
|
95
|
+
rpId: string;
|
|
96
|
+
accessKeyHash?: string | undefined;
|
|
97
|
+
guestToken?: string | undefined;
|
|
98
|
+
onHome: () => void;
|
|
99
|
+
onSignIn: () => void;
|
|
100
|
+
};
|
|
101
|
+
export type SignInWithEmailProps = {
|
|
102
|
+
request: RpcRequest;
|
|
103
|
+
onBack: () => void;
|
|
104
|
+
onHome: () => void;
|
|
105
|
+
};
|
|
106
|
+
/** Cookie-authoritative identity for account data operations. */
|
|
107
|
+
export type AccountDataIdentity = {
|
|
108
|
+
id: string;
|
|
109
|
+
username: string;
|
|
110
|
+
isGuest: boolean;
|
|
111
|
+
};
|
|
112
|
+
/** Validated export file and any collections capped by the server. */
|
|
113
|
+
export type AccountDataDownload = {
|
|
114
|
+
blob: Blob;
|
|
115
|
+
truncated: string[];
|
|
116
|
+
};
|
|
@@ -9,7 +9,7 @@ export type AuthOutcome = "success" | "failure" | "info";
|
|
|
9
9
|
export type AuthMode = "sign-up" | "sign-in";
|
|
10
10
|
/** Client-only funnel steps reported via the `/api/events` beacon. */
|
|
11
11
|
export type FunnelStep = "mode_selected" | "email_entered" | "ceremony_started" | "ceremony_failed" | "done_shown";
|
|
12
|
-
export type AuthEventName = "auth.username.checked" | "auth.signup.succeeded" | "auth.signup.failed" | "auth.otp.sent" | "auth.otp.verified" | "auth.otp.failed" | "auth.email.verify.sent" | "auth.email.verify.succeeded" | "auth.email.verify.failed" | "auth.email.changed" | "auth.avatar.upload.succeeded" | "auth.avatar.upload.failed" | "auth.bio.update.succeeded" | "auth.bio.update.failed" | "auth.profile.view.failed" | "auth.profile.view.uncapped" | "auth.challenge.issued" | "auth.signin.succeeded" | "auth.signin.failed" | "auth.passkey.added" | "auth.passkey.add_failed" | "auth.restore.succeeded" | "auth.restore.failed" | "auth.restore.no_session" | "auth.refresh.succeeded" | "auth.refresh.failed" | "auth.refresh.reuse" | "auth.refresh.grace" | "auth.jwt.verified" | "auth.jwt.rejected" | "auth.signout" | "auth.session.revoked" | "auth.session.revoked_all" | "auth.audience.rejected" | "auth.audience.minted" | "auth.guest.created" | "auth.guest.restored" | "auth.guest.upgraded" | "auth.guest.failed" | "auth.role.granted" | "auth.role.revoked" | "room.restriction.issued" | "room.restriction.lifted" | "auth.funnel.mode_selected" | "auth.funnel.email_entered" | "auth.funnel.ceremony_started" | "auth.funnel.ceremony_failed" | "auth.funnel.done_shown" | "room_event.activated" | "room_event.completed" | "room_event.reminder_dispatched" | "room_event.reminder_failed";
|
|
12
|
+
export type AuthEventName = "auth.username.checked" | "auth.signup.succeeded" | "auth.signup.failed" | "auth.otp.sent" | "auth.otp.verified" | "auth.otp.failed" | "auth.email.verify.sent" | "auth.email.verify.succeeded" | "auth.email.verify.failed" | "auth.email.changed" | "auth.avatar.upload.succeeded" | "auth.avatar.upload.failed" | "auth.bio.update.succeeded" | "auth.bio.update.failed" | "auth.profile.view.failed" | "auth.profile.view.uncapped" | "auth.challenge.issued" | "auth.signin.succeeded" | "auth.signin.failed" | "auth.passkey.added" | "auth.passkey.add_failed" | "auth.restore.succeeded" | "auth.restore.failed" | "auth.restore.no_session" | "auth.refresh.succeeded" | "auth.refresh.failed" | "auth.refresh.reuse" | "auth.refresh.grace" | "auth.jwt.verified" | "auth.jwt.rejected" | "auth.signout" | "auth.session.revoked" | "auth.session.revoked_all" | "auth.audience.rejected" | "auth.audience.minted" | "auth.guest.created" | "auth.guest.restored" | "auth.guest.upgraded" | "auth.guest.failed" | "auth.role.granted" | "auth.role.revoked" | "auth.account.deleted" | "auth.account.exported" | "room.restriction.issued" | "room.restriction.lifted" | "auth.funnel.mode_selected" | "auth.funnel.email_entered" | "auth.funnel.ceremony_started" | "auth.funnel.ceremony_failed" | "auth.funnel.done_shown" | "room_event.activated" | "room_event.completed" | "room_event.reminder_dispatched" | "room_event.reminder_failed";
|
|
13
13
|
export type AuthErrorCode = "username_taken" | "credential_taken" | "email_taken" | "email_not_verified" | "no_email" | "image_upload_forbidden" | "image_upload_rate_limited" | "invalid_image_type" | "image_too_large" | "image_upload_failed" | "bio_forbidden" | "bio_invalid" | "bio_too_long" | "profile_rate_limited" | "profile_ip_missing" | "otp_invalid" | "otp_expired" | "otp_attempts_exceeded" | "otp_resend_cooldown" | "otp_resend_limit" | "otp_global_limit" | "otp_send_failed" | "challenge_expired" | "unknown_credential" | "invalid_assertion_type" | "invalid_assertion_origin" | "user_verification_required" | "invalid_signature" | "user_not_found" | "missing_audience" | "audience_not_allowed" | "audience_mismatch" | "no_session" | "no_passkey" | "refresh_token_invalid" | "refresh_token_expired" | "refresh_epoch_stale" | "refresh_user_epoch_stale" | "refresh_reuse_detected" | "guest_rate_limited" | "guest_global_limit" | "guest_username_exhausted" | "guest_session" | "passkey_exists" | "already_upgraded" | "malformed_token" | "unknown_key" | "verification_failed" | "webauthn_not_allowed" | "webauthn_security" | "webauthn_invalid_state" | "webauthn_not_supported" | "webauthn_constraint" | "webauthn_aborted" | "webauthn_unknown" | "internal_error";
|
|
14
14
|
/** One flat record per event = one row in the `auth_events` stream. */
|
|
15
15
|
export interface AuthEventRecord {
|
|
@@ -47,6 +47,10 @@ export interface AuthEventRecord {
|
|
|
47
47
|
occurrenceId: string | null;
|
|
48
48
|
dispatchKind: string | null;
|
|
49
49
|
recipients: number | null;
|
|
50
|
+
/** Account-lifecycle fields: whether the account was a guest, and what an
|
|
51
|
+
* erasure or export touched, as per-section row counts. */
|
|
52
|
+
guest: boolean | null;
|
|
53
|
+
counts: Record<string, number> | null;
|
|
50
54
|
}
|
|
51
55
|
/** Body accepted by `POST /api/events` from the dialog. */
|
|
52
56
|
export interface BeaconBody {
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type { ActionCatalogResponse, ActionEventRequest, ActionEventResponse, ActionSubjectRef, ActiveActionResponse, CreateStudySubjectInput, FinishActionRequest, FinishActionResponse, ListStudySessionsOptions, ListStudySubjectsOptions, StartActionInput, StartActionResult, StudyCatalog, StudyCategory, StudyField, StudyRange, StudySessionPage, StudySubject, StudySubjectList, StudySubjectRemovalResponse, StudySubjectResponse, StudySummary, UpdateStudySubjectInput } from "./index";
|
|
2
|
+
/** The running session as the header pill and the panel see it: the shape of
|
|
3
|
+
* `GET /api/actions/me`, of a start's `session` and of a 409's `active`. */
|
|
4
|
+
export type ActiveAction = ActiveActionResponse;
|
|
5
|
+
/** A start as the UI requests it. The surface is not the caller's to choose:
|
|
6
|
+
* `createFocusApi` stamps every start with the injected host surface. `sessionId` may be
|
|
7
|
+
* omitted; the SDK mints the idempotency key. */
|
|
8
|
+
export type StartFocusRequest = Omit<StartActionInput, "surface">;
|
|
9
|
+
export interface FocusApi {
|
|
10
|
+
catalog(): Promise<ActionCatalogResponse>;
|
|
11
|
+
/** The caller's running session, or null when idle. */
|
|
12
|
+
active(): Promise<ActiveAction | null>;
|
|
13
|
+
/** Resolves to the 409 conflict as a value; every other refusal throws. */
|
|
14
|
+
start(request: StartFocusRequest): Promise<StartActionResult>;
|
|
15
|
+
event(request: ActionEventRequest): Promise<ActionEventResponse>;
|
|
16
|
+
finish(request: FinishActionRequest): Promise<FinishActionResponse>;
|
|
17
|
+
studyCatalog(): Promise<StudyCatalog>;
|
|
18
|
+
subjects(options?: ListStudySubjectsOptions): Promise<StudySubjectList>;
|
|
19
|
+
createSubject(request: CreateStudySubjectInput): Promise<StudySubjectResponse>;
|
|
20
|
+
/** Rename (`{ name }`), re-anchor (`{ field }`), archive or restore
|
|
21
|
+
* (`{ archived }`) a subject. Archiving is what the picker means by
|
|
22
|
+
* "remove"; the host subject-management surface also offers deletion. */
|
|
23
|
+
updateSubject(id: string, patch: UpdateStudySubjectInput): Promise<StudySubjectResponse>;
|
|
24
|
+
/** Removes a subject outright when nothing references it; auth archives it
|
|
25
|
+
* instead when sessions do, which the `outcome` reports. */
|
|
26
|
+
deleteSubject(id: string): Promise<StudySubjectRemovalResponse>;
|
|
27
|
+
/** Finished study time per subject and per category; the running session
|
|
28
|
+
* is not in it and is folded in live from the provider. */
|
|
29
|
+
summary(range: StudyRange): Promise<StudySummary>;
|
|
30
|
+
/** One subject's finished sessions, newest first, keyset-paged on
|
|
31
|
+
* `nextBefore`. */
|
|
32
|
+
sessions(options: ListStudySessionsOptions): Promise<StudySessionPage>;
|
|
33
|
+
}
|
|
34
|
+
export interface CatalogFieldRef {
|
|
35
|
+
category: StudyCategory;
|
|
36
|
+
field: StudyField;
|
|
37
|
+
}
|
|
38
|
+
export type StudySearchHit = {
|
|
39
|
+
kind: "subject";
|
|
40
|
+
id: string;
|
|
41
|
+
subject: StudySubject;
|
|
42
|
+
ref: CatalogFieldRef | null;
|
|
43
|
+
score: number;
|
|
44
|
+
} | {
|
|
45
|
+
kind: "field";
|
|
46
|
+
id: string;
|
|
47
|
+
ref: CatalogFieldRef;
|
|
48
|
+
/** The alias that matched when the label itself did not. */
|
|
49
|
+
alias: string | null;
|
|
50
|
+
score: number;
|
|
51
|
+
};
|
|
52
|
+
export interface ClockAnchor {
|
|
53
|
+
accruedSeconds: number;
|
|
54
|
+
paused: boolean;
|
|
55
|
+
readAt: number;
|
|
56
|
+
}
|
|
57
|
+
export type FocusPhase = "unknown" | "idle" | "active";
|
|
58
|
+
/** What Stop leaves behind, shown exactly once before it is dismissed. */
|
|
59
|
+
export interface FinishedSummary {
|
|
60
|
+
source: string;
|
|
61
|
+
label: string | null;
|
|
62
|
+
subject: ActionSubjectRef | null;
|
|
63
|
+
xpGranted: number;
|
|
64
|
+
durationSeconds: number;
|
|
65
|
+
}
|
|
66
|
+
export interface FocusSessionState {
|
|
67
|
+
phase: FocusPhase;
|
|
68
|
+
active: ActiveAction | null;
|
|
69
|
+
anchor: ClockAnchor | null;
|
|
70
|
+
finished: FinishedSummary | null;
|
|
71
|
+
/** The other session a plain start ran into, awaiting "switch?". */
|
|
72
|
+
conflict: ActiveAction | null;
|
|
73
|
+
busy: boolean;
|
|
74
|
+
failed: boolean;
|
|
75
|
+
}
|
|
76
|
+
export type FocusSessionEvent = {
|
|
77
|
+
type: "read";
|
|
78
|
+
active: ActiveAction | null;
|
|
79
|
+
at: number;
|
|
80
|
+
} | {
|
|
81
|
+
type: "read-failed";
|
|
82
|
+
} | {
|
|
83
|
+
type: "request";
|
|
84
|
+
} | {
|
|
85
|
+
type: "request-failed";
|
|
86
|
+
} | {
|
|
87
|
+
type: "started";
|
|
88
|
+
session: ActiveAction;
|
|
89
|
+
at: number;
|
|
90
|
+
} | {
|
|
91
|
+
type: "conflict";
|
|
92
|
+
active: ActiveAction;
|
|
93
|
+
} | {
|
|
94
|
+
type: "paused";
|
|
95
|
+
at: number;
|
|
96
|
+
} | {
|
|
97
|
+
type: "resumed";
|
|
98
|
+
at: number;
|
|
99
|
+
} | {
|
|
100
|
+
type: "finished";
|
|
101
|
+
result: FinishActionResponse;
|
|
102
|
+
at: number;
|
|
103
|
+
} | {
|
|
104
|
+
type: "dismiss-finished";
|
|
105
|
+
} | {
|
|
106
|
+
type: "dismiss-conflict";
|
|
107
|
+
} | {
|
|
108
|
+
type: "reset";
|
|
109
|
+
};
|
|
File without changes
|
|
@@ -1,18 +1,23 @@
|
|
|
1
|
+
export type { AccountDeleteRequest, AccountDeleteResponse, AccountErasureCounts, AccountErasureEntry, AccountErasureFeed, AccountErasureResult, AccountExport, AccountExportAccount, AccountExportActionEvent, AccountExportActionSession, AccountExportAttendance, AccountExportAuthoredEvent, AccountExportCharacterStateTime, AccountExportFollow, AccountExportGameEvent, AccountExportOtherService, AccountExportOwnedRoom, AccountExportPasskey, AccountExportRoomEvents, AccountExportRoomMembership, AccountExportRoomPlayerState, AccountExportRoomPresence, AccountExportRoomRestriction, AccountExportRoomSettings, AccountExportRooms, AccountExportRsvp, AccountExportSettingsSurface, AccountExportStudySubject, AccountExportXpGrant, AccountExportXpSummary, } from "./account-data";
|
|
1
2
|
export type { ActionCurve, ActionEventRequest, ActionEventResponse, ActionsApi, ActiveActionState, FinishActionRequest, ListStudySessionsOptions, ListStudySubjectsOptions, StartActionInput, StartActionResult, StudyApi, StudySubjectResponse, UseActiveActionOptions, XpEstimateContext, } from "./actions";
|
|
2
|
-
export type { AccountSession, AccountSessionsResponse, AdditionalSession, AuthConfig, AuthResponse, AuthResponseWithWebAuthn, BioNormalization, BioRejection, BioWriteRefusal, BioWriteResult, FlowCredential, FlowUser, PasskeyPluginOptions, RevokeAllSessionsResponse, RevokeSessionResponse, SecurityActivityEntry, SecurityActivityResponse, SessionUser, VerifiedFlowJWT, VerifyOptions, WebAuthnSignature, } from "./auth";
|
|
3
|
+
export type { AccountRegistration, AccountSession, AccountSessionsResponse, AdditionalSession, AuthConfig, AuthResponse, AuthResponseWithWebAuthn, BioNormalization, BioRejection, BioWriteRefusal, BioWriteResult, FlowCredential, FlowUser, PasskeyEnrollment, PasskeyPluginOptions, RevokeAllSessionsResponse, RevokeSessionResponse, SecurityActivityEntry, SecurityActivityResponse, SessionUser, VerifiedFlowJWT, VerifyOptions, WebAuthnSignature, } from "./auth";
|
|
3
4
|
export type { BodyRegion, CosmeticItem, CosmeticMaterial, CosmeticPaint, CosmeticSlot, EquipConflict, EquippedCosmetic, EquippedCosmetics, EquipRegion, PaintSlot, SettingsConflict, } from "./cosmetics";
|
|
4
5
|
export { BODY_REGIONS, COSMETIC_MATERIALS } from "./cosmetics";
|
|
5
|
-
export type { BoundaryError, DialogCustomFeatures, DialogCustomLabels, DialogError, DialogReferrer, DialogState, Loadable, ProfileData, ProfileIdentity, } from "./dialog";
|
|
6
|
+
export type { AccountDataDownload, AccountDataIdentity, BoundaryError, DialogCustomFeatures, DialogCustomLabels, DialogError, DialogReferrer, DialogState, Loadable, ProfileData, ProfileIdentity, SignInWithEmailProps, SignUpProps, } from "./dialog";
|
|
6
7
|
export type { AuthErrorCode, AuthEventName, AuthEventRecord, AuthMode, AuthOutcome, BeaconBody, FunnelStep, } from "./events";
|
|
8
|
+
export type { ActiveAction, CatalogFieldRef, ClockAnchor, FinishedSummary, FocusApi, FocusPhase, FocusSessionEvent, FocusSessionState, StartFocusRequest, StudySearchHit, } from "./focus";
|
|
7
9
|
export type { GameEventReport, GameLifecycleEventName, GameLifecycleFeedEvent, GameLifecycleFeedPage, GamePlayerSession, } from "./game";
|
|
8
10
|
export { GAME_LIFECYCLE_EVENT_NAMES } from "./game";
|
|
11
|
+
export type { AccountProfileData } from "./landing";
|
|
9
12
|
export type { Bridge, BridgeParameters, FlowAccount, FlowRemote, FlowRemoteConfig, FromWindowOptions, MessageResponse, Messenger, OneOf, Payload, QueuedRequest, ReadyOptions, RemoteFlowState, RemoteState, Schema, Storage, Topic, WithReady, } from "./messenger";
|
|
13
|
+
export type { OtpVerificationFailure, OtpVerificationResult, VerificationAdapter, } from "./otp";
|
|
10
14
|
export type { Call, ConnectCapabilities, ConnectRequest, ConnectResponse, GuestRequest, GuestResponse, MethodName, MethodParams, MethodResult, RestoreResponse, RpcRequest, SendCallsParams, SendCallsRequest, SendCallsResponse, SendTransactionParams, SendTransactionRequest, SendTransactionResponse, SignMessageRequest, SignMessageResponse, SignOutRequest, SignOutResponse, SignTypedDataRequest, SignTypedDataResponse, TransactionArgs, TypedData, TypedDataDomain, TypedDataField, } from "./protocol";
|
|
11
15
|
export { getConnectCapabilities, isPersonalSignParams, isSendCallsParams, isSendTransactionParams, } from "./protocol";
|
|
12
16
|
export type { CreateRoomEventInput, RoomEventArchive, RoomEventAttendance, RoomEventFrequency, RoomEventInstance, RoomEventInterest, RoomEventInterestState, RoomEventList, RoomEventOccurrence, RoomEventRecurrence, RoomEventRoomRef, RoomEventRun, RoomEventSeries, RoomEventStatus, SetInterestInput, UpdateRoomEventInput, } from "./room-events";
|
|
13
17
|
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";
|
|
14
18
|
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, RunLoginParams, RunLoginResult, SendCallsArgs, SendTransactionArgs, Session, SigningContext, SignMessageArgs, SignTypedDataArgs, Store, StoredAccessKey, UseOpenProfileOptions, WagmiConnectCapabilities, WagmiConnectParams, } from "./sdk";
|
|
15
19
|
export type { GracefulShutdownCleanup, GracefulShutdownOptions, GracefulShutdownServer, GracefulShutdownSignal, ResolvedFlowSession, ResolveSessionOptions, SessionRouteOptions, SessionRouteResponse, SessionRouteSession, } from "./server";
|
|
20
|
+
export type { CosmeticOffer, PaintDescriptor, SettingDescriptor, Settings, SettingsMigration, StoredSettings, SurfaceRegistry, } from "./settings";
|
|
16
21
|
export type { CreateStudySubjectInput, ListStudySessionsInput, StudyCatalog, StudyCategory, StudyCategoryTotals, StudyField, StudyRange, StudySessionEntry, StudySessionPage, StudySessionsResult, StudySubject, StudySubjectCreation, StudySubjectList, StudySubjectRefusal, StudySubjectRemoval, StudySubjectRemovalResponse, StudySubjectTotals, StudySubjectUpdate, StudySummary, UpdateStudySubjectInput, } from "./study";
|
|
17
22
|
export type { CoinAsset, IdentifiedTx, TxApprove, TxConvert, TxSend, TxSwap, } from "./tx";
|
|
18
|
-
export type { ActionCatalogEntry, ActionCatalogResponse, ActionDayContext, ActionEventKind, ActionSessionState, ActionSubjectRef, ActionSurface, ActionTransitionKind, ActiveActionResponse, ActiveSessionConflict, CurrentAction, FinishActionResponse, LevelProgress, PublicProfile, PublicProfileRefusal, PublicProfileResult, PublicProfileSignal, PublicUserProfile, StartActionResponse, StartUserSessionResult, UserActionSurface, XpGrantResult, XpMode, XpRecentGrant, XpSummary, } from "./xp";
|
|
23
|
+
export type { ActionCatalogEntry, ActionCatalogResponse, ActionDayContext, ActionDurations, ActionEventKind, ActionSessionState, ActionSubjectRef, ActionSurface, ActionTimelineEvent, ActionTransitionKind, ActiveActionResponse, ActiveSessionConflict, CurrentAction, FinishActionResponse, LevelProgress, PublicProfile, PublicProfileRefusal, PublicProfileResult, PublicProfileSignal, PublicUserProfile, StartActionResponse, StartUserSessionResult, UserActionSurface, XpGrantResult, XpMode, XpRecentGrant, XpSummary, } from "./xp";
|
|
File without changes
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AuthErrorCode } from "./events";
|
|
2
|
+
export type OtpVerificationFailure = {
|
|
3
|
+
ok: false;
|
|
4
|
+
errorCode: AuthErrorCode;
|
|
5
|
+
apiCode: "INVALID_OTP" | "OTP_EXPIRED" | "TOO_MANY_ATTEMPTS";
|
|
6
|
+
status: 400 | 403;
|
|
7
|
+
message: string;
|
|
8
|
+
attemptsRemaining?: number;
|
|
9
|
+
};
|
|
10
|
+
export type OtpVerificationResult = {
|
|
11
|
+
ok: true;
|
|
12
|
+
} | OtpVerificationFailure;
|
|
13
|
+
export interface VerificationAdapter {
|
|
14
|
+
findVerificationValue(identifier: string): Promise<{
|
|
15
|
+
id: string;
|
|
16
|
+
value: string;
|
|
17
|
+
expiresAt: Date;
|
|
18
|
+
} | null | undefined>;
|
|
19
|
+
deleteVerificationValue(id: string): Promise<void>;
|
|
20
|
+
}
|
|
File without changes
|
package/dist/sdk/types/sdk.d.ts
CHANGED