@flow-industries/id 0.8.0 → 0.9.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 +12 -8
- package/dist/sdk/client/dialog-host.js +0 -1
- package/dist/sdk/client/index.d.ts +1 -0
- package/dist/sdk/client/index.js +1 -0
- package/dist/sdk/client/profile-button.js +0 -1
- package/dist/sdk/client/refresh-store.js +5 -0
- package/dist/sdk/client/rooms.d.ts +14 -0
- package/dist/sdk/client/rooms.js +86 -0
- package/dist/sdk/react/hooks.d.ts +26 -1
- package/dist/sdk/react/hooks.js +78 -1
- package/dist/sdk/react/index.d.ts +1 -1
- package/dist/sdk/react/index.js +1 -1
- package/dist/sdk/types/index.d.ts +2 -1
- package/dist/sdk/types/index.js +1 -1
- package/dist/sdk/types/protocol.d.ts +6 -0
- package/dist/sdk/types/protocol.js +8 -0
- package/dist/sdk/types/rooms.d.ts +129 -0
- package/dist/sdk/types/rooms.js +1 -0
- package/dist/sdk/types/sdk.d.ts +3 -0
- package/package.json +1 -1
|
@@ -2,6 +2,7 @@ import { createDialogHost } from "./dialog-host";
|
|
|
2
2
|
import { idb } from "./idb";
|
|
3
3
|
import { METHODS } from "./methods";
|
|
4
4
|
import { makeRefreshStore } from "./refresh-store";
|
|
5
|
+
import { createRoomsApi } from "./rooms";
|
|
5
6
|
import { credentialToAddress, restoreCredential, runLogin, runLogout, } from "./session";
|
|
6
7
|
import { createStore, initialFlowState } from "./store";
|
|
7
8
|
const DEFAULT_HOST = "https://id.flow.industries";
|
|
@@ -309,14 +310,16 @@ export function createFlow(options = {}) {
|
|
|
309
310
|
}
|
|
310
311
|
// When the current session is a guest, forward its access token so a
|
|
311
312
|
// sign-up upgrades that guest in place even where the guest cookie is
|
|
312
|
-
// unreadable (the iOS top-level sign-up popup).
|
|
313
|
-
//
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
313
|
+
// unreadable (the iOS top-level sign-up popup). Mint via getToken() rather
|
|
314
|
+
// than reading store.jwt directly: the cached JWT can be up to an hour stale
|
|
315
|
+
// on a long-idle tab, and an expired token fails server verification — the
|
|
316
|
+
// guest would then be registered as a fresh account instead of upgraded.
|
|
317
|
+
// An app that never becomes a guest forwards nothing.
|
|
318
|
+
if (store.getSnapshot().user?.isGuest) {
|
|
319
|
+
const guestToken = await getToken();
|
|
320
|
+
if (guestToken) {
|
|
321
|
+
extraCapabilities = { ...(extraCapabilities ?? {}), guestToken };
|
|
322
|
+
}
|
|
320
323
|
}
|
|
321
324
|
const { session, webauthn, refreshToken } = await runLogin({
|
|
322
325
|
dialog: dialogHost,
|
|
@@ -392,6 +395,7 @@ export function createFlow(options = {}) {
|
|
|
392
395
|
ensureGuest,
|
|
393
396
|
refreshJwt,
|
|
394
397
|
getToken,
|
|
398
|
+
rooms: createRoomsApi(host, getToken),
|
|
395
399
|
signMessage: async (args) => {
|
|
396
400
|
const mod = await import("./signing");
|
|
397
401
|
return mod.signMessage(buildSigningContext(), args);
|
|
@@ -3,3 +3,4 @@ export { createFlow, getFlow, requireFlow, resetFlow } from "./create-flow";
|
|
|
3
3
|
export { createDialogHost } from "./dialog-host";
|
|
4
4
|
export { METHODS } from "./methods";
|
|
5
5
|
export { createProfileButton } from "./profile-button";
|
|
6
|
+
export { createRoomsApi, RoomsRequestError } from "./rooms";
|
package/dist/sdk/client/index.js
CHANGED
|
@@ -2,3 +2,4 @@ export { createFlow, getFlow, requireFlow, resetFlow } from "./create-flow";
|
|
|
2
2
|
export { createDialogHost } from "./dialog-host";
|
|
3
3
|
export { METHODS } from "./methods";
|
|
4
4
|
export { createProfileButton } from "./profile-button";
|
|
5
|
+
export { createRoomsApi, RoomsRequestError } from "./rooms";
|
|
@@ -10,6 +10,11 @@ export function makeRefreshStore(host) {
|
|
|
10
10
|
}
|
|
11
11
|
},
|
|
12
12
|
set(token) {
|
|
13
|
+
// Never persist a missing token: localStorage.setItem coerces undefined
|
|
14
|
+
// to the literal "undefined", which later reads back as a bogus bearer
|
|
15
|
+
// and 401s as refresh_token_invalid. Fail safe by ignoring it instead.
|
|
16
|
+
if (!token)
|
|
17
|
+
return;
|
|
13
18
|
try {
|
|
14
19
|
localStorage.setItem(key, token);
|
|
15
20
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { RoomsApi } from "../types";
|
|
2
|
+
/** Thrown on any non-2xx rooms response; `reason` carries the machine-readable
|
|
3
|
+
* cause when the API provides one (e.g. "banned", "private"). */
|
|
4
|
+
export declare class RoomsRequestError extends Error {
|
|
5
|
+
readonly status: number;
|
|
6
|
+
readonly reason?: string | undefined;
|
|
7
|
+
constructor(status: number, message: string, reason?: string | undefined);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Thin typed client for the room registry, bound to a host and the Flow
|
|
11
|
+
* token supplier. Public reads work signed-out; mutations attach the caller's
|
|
12
|
+
* bearer and fail fast with a 401-shaped error when no session exists.
|
|
13
|
+
*/
|
|
14
|
+
export declare function createRoomsApi(host: string, getToken: () => Promise<string | null>): RoomsApi;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/** Thrown on any non-2xx rooms response; `reason` carries the machine-readable
|
|
2
|
+
* cause when the API provides one (e.g. "banned", "private"). */
|
|
3
|
+
export class RoomsRequestError extends Error {
|
|
4
|
+
status;
|
|
5
|
+
reason;
|
|
6
|
+
constructor(status, message, reason) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.status = status;
|
|
9
|
+
this.reason = reason;
|
|
10
|
+
this.name = "RoomsRequestError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Thin typed client for the room registry, bound to a host and the Flow
|
|
15
|
+
* token supplier. Public reads work signed-out; mutations attach the caller's
|
|
16
|
+
* bearer and fail fast with a 401-shaped error when no session exists.
|
|
17
|
+
*/
|
|
18
|
+
export function createRoomsApi(host, getToken) {
|
|
19
|
+
async function request(path, options = {}) {
|
|
20
|
+
const headers = {};
|
|
21
|
+
const token = await getToken();
|
|
22
|
+
if (token)
|
|
23
|
+
headers.Authorization = `Bearer ${token}`;
|
|
24
|
+
else if (options.authRequired) {
|
|
25
|
+
throw new RoomsRequestError(401, "Sign in first");
|
|
26
|
+
}
|
|
27
|
+
if (options.body !== undefined)
|
|
28
|
+
headers["Content-Type"] = "application/json";
|
|
29
|
+
const res = await fetch(`${host}/api/rooms${path}`, {
|
|
30
|
+
method: options.method ?? "GET",
|
|
31
|
+
headers,
|
|
32
|
+
body: options.body !== undefined ? JSON.stringify(options.body) : undefined,
|
|
33
|
+
});
|
|
34
|
+
const payload = (await res.json().catch(() => ({})));
|
|
35
|
+
if (!res.ok) {
|
|
36
|
+
throw new RoomsRequestError(res.status, typeof payload.error === "string"
|
|
37
|
+
? payload.error
|
|
38
|
+
: `Rooms request failed (${res.status})`, typeof payload.reason === "string" ? payload.reason : undefined);
|
|
39
|
+
}
|
|
40
|
+
return payload;
|
|
41
|
+
}
|
|
42
|
+
const slugPath = (slug) => `/${encodeURIComponent(slug)}`;
|
|
43
|
+
const act = (slug, action, body) => request(`${slugPath(slug)}/${action}`, {
|
|
44
|
+
method: "POST",
|
|
45
|
+
body,
|
|
46
|
+
authRequired: true,
|
|
47
|
+
}).then(() => undefined);
|
|
48
|
+
return {
|
|
49
|
+
list(options) {
|
|
50
|
+
const params = new URLSearchParams();
|
|
51
|
+
if (options?.cursor)
|
|
52
|
+
params.set("cursor", options.cursor);
|
|
53
|
+
if (options?.limit)
|
|
54
|
+
params.set("limit", String(options.limit));
|
|
55
|
+
const query = params.size ? `?${params}` : "";
|
|
56
|
+
return request(query);
|
|
57
|
+
},
|
|
58
|
+
get: (slug) => request(slugPath(slug)),
|
|
59
|
+
mine: () => request("/mine", { authRequired: true }),
|
|
60
|
+
create: (input) => request("", {
|
|
61
|
+
method: "POST",
|
|
62
|
+
body: input,
|
|
63
|
+
authRequired: true,
|
|
64
|
+
}),
|
|
65
|
+
update: (slug, patch) => request(`${slugPath(slug)}/update`, {
|
|
66
|
+
method: "POST",
|
|
67
|
+
body: patch,
|
|
68
|
+
authRequired: true,
|
|
69
|
+
}),
|
|
70
|
+
remove: (slug) => act(slug, "delete", {}),
|
|
71
|
+
join: (slug) => act(slug, "join", {}),
|
|
72
|
+
leave: (slug) => act(slug, "leave", {}),
|
|
73
|
+
members: (slug) => request(`${slugPath(slug)}/members`, { authRequired: true }),
|
|
74
|
+
presence: (slug) => request(`${slugPath(slug)}/presence`),
|
|
75
|
+
settings: (slug, surface) => request(`${slugPath(slug)}/settings/${encodeURIComponent(surface)}`),
|
|
76
|
+
saveSettings: (slug, surface, settings) => request(`${slugPath(slug)}/settings/${encodeURIComponent(surface)}`, { method: "POST", body: { settings }, authRequired: true }),
|
|
77
|
+
transfer: (slug, userId) => act(slug, "transfer", { userId }),
|
|
78
|
+
claim: (slug) => act(slug, "claim", {}),
|
|
79
|
+
setRole: (slug, userId, role) => act(slug, "role", { userId, role }),
|
|
80
|
+
kick: (slug, userId) => act(slug, "kick", { userId }),
|
|
81
|
+
ban: (slug, userId, options) => act(slug, "ban", { userId, ...options }),
|
|
82
|
+
unban: (slug, userId) => act(slug, "unban", { userId }),
|
|
83
|
+
mute: (slug, userId, options) => act(slug, "mute", { userId, ...options }),
|
|
84
|
+
unmute: (slug, userId) => act(slug, "unmute", { userId }),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Flow, FlowState } from "../types";
|
|
1
|
+
import type { Flow, FlowState, RoomDetail, RoomPresenceSnapshot, RoomSummary } from "../types";
|
|
2
2
|
/**
|
|
3
3
|
* Returns the Flow instance to use. Resolution order:
|
|
4
4
|
* 1. The instance from a `<FlowIdProvider>` ancestor (if any)
|
|
@@ -35,3 +35,28 @@ export declare function useFlowId(): {
|
|
|
35
35
|
refreshJwt: () => Promise<boolean>;
|
|
36
36
|
getToken: () => Promise<string | null>;
|
|
37
37
|
};
|
|
38
|
+
/**
|
|
39
|
+
* Fetches the public room list once (call `reload` to refresh). Pagination
|
|
40
|
+
* stays manual: pass the returned `nextCursor` back through `flow.rooms.list`.
|
|
41
|
+
*/
|
|
42
|
+
export declare function useRooms(): {
|
|
43
|
+
rooms: RoomSummary[];
|
|
44
|
+
nextCursor: string | null;
|
|
45
|
+
loading: boolean;
|
|
46
|
+
error: Error | null;
|
|
47
|
+
reload: () => void;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Fetches one room's detail, and optionally polls its live presence when
|
|
51
|
+
* `presencePollMs` is set (polling until the presence store grows a push
|
|
52
|
+
* channel). Re-fetches when the slug changes; call `reload` to refresh.
|
|
53
|
+
*/
|
|
54
|
+
export declare function useRoom(slug: string, options?: {
|
|
55
|
+
presencePollMs?: number;
|
|
56
|
+
}): {
|
|
57
|
+
room: RoomDetail | null;
|
|
58
|
+
presence: RoomPresenceSnapshot | null;
|
|
59
|
+
loading: boolean;
|
|
60
|
+
error: Error | null;
|
|
61
|
+
reload: () => void;
|
|
62
|
+
};
|
package/dist/sdk/react/hooks.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { useContext, useSyncExternalStore } from "react";
|
|
1
|
+
import { useCallback, useContext, useEffect, useState, useSyncExternalStore, } from "react";
|
|
2
2
|
import { getFlow as getSingletonFlow } from "../client/create-flow";
|
|
3
3
|
import { FlowContext } from "./provider";
|
|
4
|
+
const asError = (e) => e instanceof Error ? e : new Error(String(e));
|
|
4
5
|
/**
|
|
5
6
|
* Returns the Flow instance to use. Resolution order:
|
|
6
7
|
* 1. The instance from a `<FlowIdProvider>` ancestor (if any)
|
|
@@ -53,3 +54,79 @@ export function useFlowId() {
|
|
|
53
54
|
getToken: flow.getToken,
|
|
54
55
|
};
|
|
55
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Fetches the public room list once (call `reload` to refresh). Pagination
|
|
59
|
+
* stays manual: pass the returned `nextCursor` back through `flow.rooms.list`.
|
|
60
|
+
*/
|
|
61
|
+
export function useRooms() {
|
|
62
|
+
const flow = useFlow();
|
|
63
|
+
const [result, setResult] = useState(null);
|
|
64
|
+
const [error, setError] = useState(null);
|
|
65
|
+
const load = useCallback(() => {
|
|
66
|
+
flow.rooms
|
|
67
|
+
.list()
|
|
68
|
+
.then((list) => {
|
|
69
|
+
setResult(list);
|
|
70
|
+
setError(null);
|
|
71
|
+
})
|
|
72
|
+
.catch((err) => setError(asError(err)));
|
|
73
|
+
}, [flow]);
|
|
74
|
+
useEffect(load, [load]);
|
|
75
|
+
return {
|
|
76
|
+
rooms: result?.rooms ?? [],
|
|
77
|
+
nextCursor: result?.nextCursor ?? null,
|
|
78
|
+
loading: result === null && error === null,
|
|
79
|
+
error,
|
|
80
|
+
reload: load,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Fetches one room's detail, and optionally polls its live presence when
|
|
85
|
+
* `presencePollMs` is set (polling until the presence store grows a push
|
|
86
|
+
* channel). Re-fetches when the slug changes; call `reload` to refresh.
|
|
87
|
+
*/
|
|
88
|
+
export function useRoom(slug, options) {
|
|
89
|
+
const flow = useFlow();
|
|
90
|
+
const pollMs = options?.presencePollMs ?? 0;
|
|
91
|
+
const [room, setRoom] = useState(null);
|
|
92
|
+
const [presence, setPresence] = useState(null);
|
|
93
|
+
const [error, setError] = useState(null);
|
|
94
|
+
const loadRoom = useCallback(() => {
|
|
95
|
+
flow.rooms
|
|
96
|
+
.get(slug)
|
|
97
|
+
.then((detail) => {
|
|
98
|
+
setRoom(detail);
|
|
99
|
+
setError(null);
|
|
100
|
+
})
|
|
101
|
+
.catch((err) => setError(asError(err)));
|
|
102
|
+
}, [flow, slug]);
|
|
103
|
+
const loadPresence = useCallback(() => {
|
|
104
|
+
flow.rooms
|
|
105
|
+
.presence(slug)
|
|
106
|
+
.then(setPresence)
|
|
107
|
+
.catch(() => { });
|
|
108
|
+
}, [flow, slug]);
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
setRoom(null);
|
|
111
|
+
setError(null);
|
|
112
|
+
loadRoom();
|
|
113
|
+
}, [loadRoom]);
|
|
114
|
+
useEffect(() => {
|
|
115
|
+
loadPresence();
|
|
116
|
+
if (pollMs <= 0)
|
|
117
|
+
return;
|
|
118
|
+
const timer = setInterval(loadPresence, pollMs);
|
|
119
|
+
return () => clearInterval(timer);
|
|
120
|
+
}, [loadPresence, pollMs]);
|
|
121
|
+
const reload = useCallback(() => {
|
|
122
|
+
loadRoom();
|
|
123
|
+
loadPresence();
|
|
124
|
+
}, [loadRoom, loadPresence]);
|
|
125
|
+
return {
|
|
126
|
+
room,
|
|
127
|
+
presence,
|
|
128
|
+
loading: room === null && error === null,
|
|
129
|
+
error,
|
|
130
|
+
reload,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export type { FlowIdProviderProps, ProfileButtonProps } from "../types";
|
|
2
|
-
export { useFlow, useFlowId, useFlowState } from "./hooks";
|
|
2
|
+
export { useFlow, useFlowId, useFlowState, useRoom, useRooms } from "./hooks";
|
|
3
3
|
export { ProfileButton } from "./profile-button";
|
|
4
4
|
export { FlowIdProvider } from "./provider";
|
package/dist/sdk/react/index.js
CHANGED
|
@@ -3,7 +3,8 @@ export type { BoundaryError, DialogCustomFeatures, DialogCustomLabels, DialogErr
|
|
|
3
3
|
export type { AuthErrorCode, AuthEventName, AuthEventRecord, AuthMode, AuthOutcome, BeaconBody, FunnelStep, } from "./events";
|
|
4
4
|
export type { Bridge, BridgeParameters, FlowAccount, FlowRemote, FlowRemoteConfig, FromWindowOptions, MessageResponse, Messenger, OneOf, Payload, QueuedRequest, ReadyOptions, RemoteFlowState, RemoteState, Schema, Storage, Topic, WithReady, } from "./messenger";
|
|
5
5
|
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";
|
|
6
|
-
export { isPersonalSignParams, isSendCallsParams, isSendTransactionParams, } from "./protocol";
|
|
6
|
+
export { getConnectCapabilities, isPersonalSignParams, isSendCallsParams, isSendTransactionParams, } from "./protocol";
|
|
7
|
+
export type { CreateRoomInput, MyRooms, RoomChannel, RoomDetail, RoomList, RoomMemberEntry, RoomMembers, RoomOccupancy, RoomOwner, RoomPresenceEntry, RoomPresenceSnapshot, RoomRestrictionKind, RoomRole, RoomSummary, RoomSurfaceSettings, RoomsApi, RoomVisibility, UpdateRoomInput, VerifyRoomContext, } from "./rooms";
|
|
7
8
|
export type { AccessKeyOptions, AccessKeyPreparation, Address, CreateDialogHostOptions, CreateFlowOptions, DialogHost, DialogOpenOptions, FinalizeAccessKeyParams, Flow, FlowConnectorParameters, FlowIdProviderProps, FlowState, Listener, LoginOptions, MountProfileOptions, PrepareArgsWithAuth, PrepareTransactionRequestPhase, ProfileButtonHandle, ProfileButtonProps, ProfilePosition, ResolveAccountParams, ResolvedAccessKeyOptions, RootCredential, RunLoginParams, RunLoginResult, SendCallsArgs, SendTransactionArgs, Session, SigningContext, SignMessageArgs, SignTypedDataArgs, Store, StoredAccessKey, WagmiConnectCapabilities, WagmiConnectParams, } from "./sdk";
|
|
8
9
|
export type { CoinAsset, IdentifiedTx, TxApprove, TxConvert, TxSend, TxSwap, } from "./tx";
|
|
9
10
|
export type { ActionDayContext, ActionEventKind, ActionSessionState, ActiveActionResponse, LevelProgress, PublicProfile, XpGrantResult, XpRecentGrant, XpSummary, } from "./xp";
|
package/dist/sdk/types/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { isPersonalSignParams, isSendCallsParams, isSendTransactionParams, } from "./protocol";
|
|
1
|
+
export { getConnectCapabilities, isPersonalSignParams, isSendCallsParams, isSendTransactionParams, } from "./protocol";
|
|
@@ -131,6 +131,12 @@ export type SendCallsParams = {
|
|
|
131
131
|
chainId?: string;
|
|
132
132
|
capabilities?: Record<string, unknown>;
|
|
133
133
|
};
|
|
134
|
+
/**
|
|
135
|
+
* Unwraps the connect capabilities from a wallet_connect RPC request (they ride
|
|
136
|
+
* as the first param), or undefined. Several dialog surfaces read them (mode,
|
|
137
|
+
* accessKeyHash, guestToken), so the cast lives here rather than being repeated.
|
|
138
|
+
*/
|
|
139
|
+
export declare function getConnectCapabilities(request: RpcRequest | undefined): ConnectCapabilities | undefined;
|
|
134
140
|
export declare function isPersonalSignParams(params: readonly unknown[] | undefined): params is readonly [string, string];
|
|
135
141
|
export declare function isSendTransactionParams(params: readonly unknown[] | undefined): params is readonly [SendTransactionParams];
|
|
136
142
|
export declare function isSendCallsParams(params: readonly unknown[] | undefined): params is readonly [SendCallsParams];
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unwraps the connect capabilities from a wallet_connect RPC request (they ride
|
|
3
|
+
* as the first param), or undefined. Several dialog surfaces read them (mode,
|
|
4
|
+
* accessKeyHash, guestToken), so the cast lives here rather than being repeated.
|
|
5
|
+
*/
|
|
6
|
+
export function getConnectCapabilities(request) {
|
|
7
|
+
return request?.params?.[0]?.capabilities;
|
|
8
|
+
}
|
|
1
9
|
export function isPersonalSignParams(params) {
|
|
2
10
|
if (!params || params.length < 2)
|
|
3
11
|
return false;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/** Room registry types shared by the server routes and the client SDK. */
|
|
2
|
+
export type RoomVisibility = "public" | "unlisted" | "private";
|
|
3
|
+
/**
|
|
4
|
+
* Owner is not a member-row role: `room.ownerId` is the single authority.
|
|
5
|
+
* Member rows carry moderator|member.
|
|
6
|
+
*/
|
|
7
|
+
export type RoomRole = "owner" | "moderator" | "member";
|
|
8
|
+
export type RoomChannel = "game" | "voice" | "text";
|
|
9
|
+
export type RoomRestrictionKind = "ban" | "mute";
|
|
10
|
+
export interface RoomOwner {
|
|
11
|
+
id: string;
|
|
12
|
+
username: string;
|
|
13
|
+
}
|
|
14
|
+
/** Live occupant counts per channel, staleness-filtered at read time. */
|
|
15
|
+
export interface RoomOccupancy {
|
|
16
|
+
game: number;
|
|
17
|
+
voice: number;
|
|
18
|
+
text: number;
|
|
19
|
+
}
|
|
20
|
+
export interface RoomSummary {
|
|
21
|
+
id: string;
|
|
22
|
+
slug: string;
|
|
23
|
+
displayName: string;
|
|
24
|
+
description: string | null;
|
|
25
|
+
owner: RoomOwner | null;
|
|
26
|
+
visibility: RoomVisibility;
|
|
27
|
+
isSystem: boolean;
|
|
28
|
+
occupancy: RoomOccupancy;
|
|
29
|
+
createdAt: string;
|
|
30
|
+
}
|
|
31
|
+
export interface RoomDetail extends RoomSummary {
|
|
32
|
+
/** The caller's role in this room, when the request carried a valid bearer. */
|
|
33
|
+
viewerRole: RoomRole | null;
|
|
34
|
+
memberCount: number;
|
|
35
|
+
}
|
|
36
|
+
export interface RoomMemberEntry {
|
|
37
|
+
userId: string;
|
|
38
|
+
username: string;
|
|
39
|
+
role: RoomRole;
|
|
40
|
+
joinedAt: string;
|
|
41
|
+
}
|
|
42
|
+
export interface RoomMembers {
|
|
43
|
+
owner: RoomOwner | null;
|
|
44
|
+
members: RoomMemberEntry[];
|
|
45
|
+
}
|
|
46
|
+
export interface CreateRoomInput {
|
|
47
|
+
slug: string;
|
|
48
|
+
displayName?: string;
|
|
49
|
+
description?: string;
|
|
50
|
+
visibility?: RoomVisibility;
|
|
51
|
+
}
|
|
52
|
+
export interface UpdateRoomInput {
|
|
53
|
+
slug?: string;
|
|
54
|
+
displayName?: string;
|
|
55
|
+
description?: string;
|
|
56
|
+
visibility?: RoomVisibility;
|
|
57
|
+
}
|
|
58
|
+
export interface MyRooms {
|
|
59
|
+
owned: RoomSummary[];
|
|
60
|
+
member: RoomSummary[];
|
|
61
|
+
}
|
|
62
|
+
export interface RoomList {
|
|
63
|
+
rooms: RoomSummary[];
|
|
64
|
+
nextCursor: string | null;
|
|
65
|
+
}
|
|
66
|
+
export interface RoomPresenceEntry {
|
|
67
|
+
userId: string;
|
|
68
|
+
username: string;
|
|
69
|
+
joinedAt: string;
|
|
70
|
+
}
|
|
71
|
+
export interface RoomPresenceSnapshot {
|
|
72
|
+
roomId: string;
|
|
73
|
+
slug: string;
|
|
74
|
+
channels: Record<RoomChannel, RoomPresenceEntry[]>;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Room admission context returned by POST /api/session/verify when the caller
|
|
78
|
+
* passes a `room` slug: whether the verified subject may enter, and with which
|
|
79
|
+
* role and per-room game settings. `settings` is delivered only through this
|
|
80
|
+
* server-to-server path — surface blobs may hold secret-ish values.
|
|
81
|
+
*/
|
|
82
|
+
export interface VerifyRoomContext {
|
|
83
|
+
ok: boolean;
|
|
84
|
+
reason?: "not_found" | "banned" | "private_not_member";
|
|
85
|
+
id: string | null;
|
|
86
|
+
slug: string;
|
|
87
|
+
visibility: RoomVisibility | null;
|
|
88
|
+
role: RoomRole | null;
|
|
89
|
+
muted: boolean;
|
|
90
|
+
settings: Record<string, number | boolean | string>;
|
|
91
|
+
}
|
|
92
|
+
export interface RoomSurfaceSettings {
|
|
93
|
+
surface: string;
|
|
94
|
+
version: number;
|
|
95
|
+
settings: Record<string, number | boolean | string>;
|
|
96
|
+
}
|
|
97
|
+
/** The room-registry client exposed as `flow.rooms`. Public reads work
|
|
98
|
+
* signed-out; everything else attaches the caller's bearer token. */
|
|
99
|
+
export interface RoomsApi {
|
|
100
|
+
list(options?: {
|
|
101
|
+
cursor?: string;
|
|
102
|
+
limit?: number;
|
|
103
|
+
}): Promise<RoomList>;
|
|
104
|
+
get(slug: string): Promise<RoomDetail>;
|
|
105
|
+
mine(): Promise<MyRooms>;
|
|
106
|
+
create(input: CreateRoomInput): Promise<RoomDetail>;
|
|
107
|
+
update(slug: string, patch: UpdateRoomInput): Promise<RoomDetail>;
|
|
108
|
+
remove(slug: string): Promise<void>;
|
|
109
|
+
join(slug: string): Promise<void>;
|
|
110
|
+
leave(slug: string): Promise<void>;
|
|
111
|
+
members(slug: string): Promise<RoomMembers>;
|
|
112
|
+
presence(slug: string): Promise<RoomPresenceSnapshot>;
|
|
113
|
+
settings(slug: string, surface: string): Promise<RoomSurfaceSettings>;
|
|
114
|
+
saveSettings(slug: string, surface: string, settings: Record<string, unknown>): Promise<RoomSurfaceSettings>;
|
|
115
|
+
transfer(slug: string, userId: string): Promise<void>;
|
|
116
|
+
claim(slug: string): Promise<void>;
|
|
117
|
+
setRole(slug: string, userId: string, role: "moderator" | "member"): Promise<void>;
|
|
118
|
+
kick(slug: string, userId: string): Promise<void>;
|
|
119
|
+
ban(slug: string, userId: string, options?: {
|
|
120
|
+
reason?: string;
|
|
121
|
+
expiresInSeconds?: number;
|
|
122
|
+
}): Promise<void>;
|
|
123
|
+
unban(slug: string, userId: string): Promise<void>;
|
|
124
|
+
mute(slug: string, userId: string, options?: {
|
|
125
|
+
reason?: string;
|
|
126
|
+
expiresInSeconds?: number;
|
|
127
|
+
}): Promise<void>;
|
|
128
|
+
unmute(slug: string, userId: string): Promise<void>;
|
|
129
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/** Room registry types shared by the server routes and the client SDK. */
|
package/dist/sdk/types/sdk.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { Chain, Hex, PrepareTransactionRequestParameters, SendTransactionPa
|
|
|
3
3
|
import type { SendCallsParameters } from "viem/actions";
|
|
4
4
|
import type { FlowCredential, FlowUser, WebAuthnSignature } from "./auth";
|
|
5
5
|
import type { ConnectCapabilities, ConnectResponse } from "./protocol";
|
|
6
|
+
import type { RoomsApi } from "./rooms";
|
|
6
7
|
export type Address = `0x${string}`;
|
|
7
8
|
/**
|
|
8
9
|
* Phases viem invokes a chain's `prepareTransactionRequest` hook at. Inlined
|
|
@@ -205,6 +206,8 @@ export type Flow = {
|
|
|
205
206
|
walletClient(args?: {
|
|
206
207
|
chainId?: number;
|
|
207
208
|
}): Promise<WalletClient>;
|
|
209
|
+
/** Typed client for the room registry (browse, membership, settings, moderation). */
|
|
210
|
+
rooms: RoomsApi;
|
|
208
211
|
subscribe(listener: Listener<FlowState>): () => void;
|
|
209
212
|
getState(): FlowState;
|
|
210
213
|
dialog: DialogHost;
|