@flow-industries/id 0.26.3 → 0.26.4
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 +38 -0
- package/contracts/v1/sdk-exports.json +30 -0
- package/dist/sdk/caller.d.ts +29 -0
- package/dist/sdk/caller.js +37 -0
- package/dist/sdk/client/atproto-resolver.d.ts +8 -0
- package/dist/sdk/client/atproto-resolver.js +87 -0
- package/dist/sdk/client/atproto.js +9 -1
- package/dist/sdk/client/create-flow.js +10 -0
- package/dist/sdk/client/index.d.ts +2 -1
- package/dist/sdk/client/index.js +1 -0
- package/dist/sdk/client/static-flow.js +2 -0
- package/dist/sdk/db/invitations.d.ts +310 -0
- package/dist/sdk/db/invitations.js +42 -0
- package/dist/sdk/db/schema.d.ts +248 -0
- package/dist/sdk/db/schema.js +25 -0
- package/dist/sdk/session-view.d.ts +15 -0
- package/dist/sdk/session-view.js +32 -0
- package/dist/sdk/types/atproto-resolver.d.ts +46 -0
- package/dist/sdk/types/atproto-resolver.js +0 -0
- package/dist/sdk/types/atproto.d.ts +22 -0
- package/dist/sdk/types/auth.d.ts +4 -0
- package/dist/sdk/types/dialog.d.ts +3 -0
- package/dist/sdk/types/hosted-oauth.d.ts +23 -0
- package/dist/sdk/types/hosted-oauth.js +0 -0
- package/dist/sdk/types/hosting-quota.d.ts +28 -0
- package/dist/sdk/types/hosting-quota.js +0 -0
- package/dist/sdk/types/index.d.ts +5 -1
- package/dist/sdk/types/managed-provisioning.d.ts +51 -0
- package/dist/sdk/types/managed-provisioning.js +0 -0
- package/dist/sdk/types/sdk.d.ts +2 -0
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -23,6 +23,33 @@ partially migrated schema.
|
|
|
23
23
|
|
|
24
24
|
### AT Protocol identity
|
|
25
25
|
|
|
26
|
+
Consumers discover the signed-in user's current PDS through
|
|
27
|
+
`await flow.atproto.resolve({ freshness: "cached" })`. Use `"refresh"` after an
|
|
28
|
+
endpoint or authorization failure, and call `flow.atproto.invalidate()` after
|
|
29
|
+
identity or migration events. Flow account switches, logout and the first-party
|
|
30
|
+
linking helpers invalidate automatically. Invalidation forces the next request
|
|
31
|
+
to refresh. Discovery uses the configured Auth host, cookie or Flow bearer
|
|
32
|
+
session, and canonical user ID; it never provisions an account.
|
|
33
|
+
|
|
34
|
+
The result includes the DID, verified display handle (or null), current PDS
|
|
35
|
+
origin, hosting ownership, lifecycle and authorization status. DID documents
|
|
36
|
+
are authoritative for the endpoint. No OAuth tokens or private keys are
|
|
37
|
+
returned. `connected` indicates an unexpired stored grant whose audience and
|
|
38
|
+
issuer match public resource metadata; it does not prove that a remote grant
|
|
39
|
+
has not since been revoked. Writes must obtain fresh AT OAuth authorization,
|
|
40
|
+
and must not forward old credentials to a migrated host or replay mutations
|
|
41
|
+
with unknown outcomes. `AtprotoRequestError.code` distinguishes sign-in,
|
|
42
|
+
missing identity, pending or failed provisioning, account changes, unsupported
|
|
43
|
+
DID methods, invalid identity and unavailable resolution.
|
|
44
|
+
|
|
45
|
+
`ATPROTO_MANAGED_PDS_ORIGINS` is an optional comma-separated list of public
|
|
46
|
+
HTTPS PDS origins owned by Flow, used only to classify current hosting.
|
|
47
|
+
`ATPROTO_RESOLUTION_TTL_MS` enables a server metadata cache keyed by DID and
|
|
48
|
+
mapping version, bounded to five minutes; unset or invalid values disable
|
|
49
|
+
caching. Authorization status is checked separately on each request. A cached
|
|
50
|
+
authorization failure forces one fresh DID resolution. Public discovery works
|
|
51
|
+
without OAuth credential configuration and reports `reconnect_required`.
|
|
52
|
+
|
|
26
53
|
Bluesky and other AT Protocol accounts can sign in to Flow ID or connect to an
|
|
27
54
|
existing account. Flow user IDs remain stable; the provider DID identifies the
|
|
28
55
|
connection. New accounts do not need an email, passkey, or wallet to enroll.
|
|
@@ -223,3 +250,14 @@ still need complete request/response descriptions and generated client coverage
|
|
|
223
250
|
before the full HTTP contract work is complete.
|
|
224
251
|
|
|
225
252
|
Server deployments may set `FLOW_ID_API_URL` to a trusted internal HTTP(S) origin for API and JWKS requests, or pass `apiUrl` to server session/verification helpers. `issuerUrl` remains the public JWT issuer and browser navigation origin. The transport URL must contain no credentials, path, query, or fragment.
|
|
253
|
+
|
|
254
|
+
PDS discovery requires explicit nonnegative integer budgets in
|
|
255
|
+
`ATPROTO_RESOLUTION_USER_HOURLY_CAP` and
|
|
256
|
+
`ATPROTO_RESOLUTION_GLOBAL_HOURLY_CAP`. Unset, invalid or zero budgets refuse
|
|
257
|
+
outbound discovery with HTTP 429 and retryable `RESOLUTION_UNAVAILABLE`. Every discovery
|
|
258
|
+
request, including cached reads and forced refreshes, consumes durable
|
|
259
|
+
per-user and fleet-wide hourly admission before any provider request. Failed
|
|
260
|
+
outbound attempts retain admission consumption; counters use the existing
|
|
261
|
+
bounded verification retention and canonical account erasure mechanism.
|
|
262
|
+
These caps bound request admission across replicas; operators must choose
|
|
263
|
+
budgets appropriate to replica count, outbound latency and capacity.
|
|
@@ -92,6 +92,31 @@
|
|
|
92
92
|
"type": false,
|
|
93
93
|
"value": true
|
|
94
94
|
},
|
|
95
|
+
{
|
|
96
|
+
"name": "AtprotoApi",
|
|
97
|
+
"type": true,
|
|
98
|
+
"value": false
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"name": "AtprotoRequestError",
|
|
102
|
+
"type": true,
|
|
103
|
+
"value": true
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"name": "AtprotoResolution",
|
|
107
|
+
"type": true,
|
|
108
|
+
"value": false
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"name": "AtprotoResolutionFailure",
|
|
112
|
+
"type": true,
|
|
113
|
+
"value": false
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"name": "AtprotoResolveOptions",
|
|
117
|
+
"type": true,
|
|
118
|
+
"value": false
|
|
119
|
+
},
|
|
95
120
|
{
|
|
96
121
|
"name": "BrowserAccount",
|
|
97
122
|
"type": true,
|
|
@@ -142,6 +167,11 @@
|
|
|
142
167
|
"type": false,
|
|
143
168
|
"value": true
|
|
144
169
|
},
|
|
170
|
+
{
|
|
171
|
+
"name": "createAtprotoApi",
|
|
172
|
+
"type": false,
|
|
173
|
+
"value": true
|
|
174
|
+
},
|
|
145
175
|
{
|
|
146
176
|
"name": "createDialogHost",
|
|
147
177
|
"type": false,
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { AppDb } from "./db/handle";
|
|
2
|
+
import type { SessionUser } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* Caller-identity core, shared by the dialog-facing routes and the tests. Takes
|
|
5
|
+
* the drizzle handle as a parameter (postgres-js in the server, PGlite in
|
|
6
|
+
* tests) instead of importing the singleton, which requires DATABASE_URL at
|
|
7
|
+
* import time. The singleton-bound entry point is `resolveCaller` in
|
|
8
|
+
* `routes/caller.ts`.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* The user behind a dialog request, and the better-auth session row that
|
|
12
|
+
* authenticated it — null when the caller presented an access JWT instead,
|
|
13
|
+
* since a bearer holds no session row.
|
|
14
|
+
*/
|
|
15
|
+
/** The session row as callers read it: opaque beyond the fields session-view names. */
|
|
16
|
+
export type CallerSession = {
|
|
17
|
+
id: string;
|
|
18
|
+
audience?: string | null;
|
|
19
|
+
};
|
|
20
|
+
export type Caller = {
|
|
21
|
+
user: SessionUser;
|
|
22
|
+
session: CallerSession | null;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Reads the user a verified bearer's `sub` names, in the shape better-auth puts
|
|
26
|
+
* on `session.user`. Null when the subject no longer exists — a token for a
|
|
27
|
+
* deleted account is unauthorized, not a caller with an empty profile.
|
|
28
|
+
*/
|
|
29
|
+
export declare function loadCallerUser(dbi: AppDb, userId: string): Promise<SessionUser | null>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { eq } from "drizzle-orm";
|
|
2
|
+
import * as schema from "./db/schema";
|
|
3
|
+
import { sessionUserOf } from "./session-view";
|
|
4
|
+
/**
|
|
5
|
+
* The columns better-auth puts on `session.user` (base fields plus the
|
|
6
|
+
* configured `additionalFields`), so a bearer-authenticated caller reads back
|
|
7
|
+
* the same user shape a cookie-authenticated one does. `sessionEpoch` is
|
|
8
|
+
* deliberately absent: it is an internal revocation lever, not profile data.
|
|
9
|
+
*/
|
|
10
|
+
const USER_COLUMNS = {
|
|
11
|
+
id: schema.user.id,
|
|
12
|
+
name: schema.user.name,
|
|
13
|
+
username: schema.user.username,
|
|
14
|
+
email: schema.user.email,
|
|
15
|
+
emailVerified: schema.user.emailVerified,
|
|
16
|
+
image: schema.user.image,
|
|
17
|
+
bio: schema.user.bio,
|
|
18
|
+
isGuest: schema.user.isGuest,
|
|
19
|
+
role: schema.user.role,
|
|
20
|
+
walletAddress: schema.user.walletAddress,
|
|
21
|
+
subscribedToNews: schema.user.subscribedToNews,
|
|
22
|
+
createdAt: schema.user.createdAt,
|
|
23
|
+
updatedAt: schema.user.updatedAt,
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Reads the user a verified bearer's `sub` names, in the shape better-auth puts
|
|
27
|
+
* on `session.user`. Null when the subject no longer exists — a token for a
|
|
28
|
+
* deleted account is unauthorized, not a caller with an empty profile.
|
|
29
|
+
*/
|
|
30
|
+
export async function loadCallerUser(dbi, userId) {
|
|
31
|
+
const [user] = await dbi
|
|
32
|
+
.select(USER_COLUMNS)
|
|
33
|
+
.from(schema.user)
|
|
34
|
+
.where(eq(schema.user.id, userId))
|
|
35
|
+
.limit(1);
|
|
36
|
+
return user ? sessionUserOf(user) : null;
|
|
37
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AtprotoApi, AtprotoResolutionFailure } from "../types/atproto";
|
|
2
|
+
export declare class AtprotoRequestError extends Error {
|
|
3
|
+
readonly code: AtprotoResolutionFailure;
|
|
4
|
+
readonly retryable: boolean;
|
|
5
|
+
constructor(code: AtprotoResolutionFailure, retryable?: boolean);
|
|
6
|
+
}
|
|
7
|
+
/** Identity changes and migration completion should invalidate before another discovery. */
|
|
8
|
+
export declare function createAtprotoApi(host: string, getToken: () => Promise<string | null>, getUserId: () => string | null): AtprotoApi;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const failureSchema = z.enum([
|
|
3
|
+
"SIGN_IN_REQUIRED",
|
|
4
|
+
"NO_AT_IDENTITY",
|
|
5
|
+
"PROVISIONING_PENDING",
|
|
6
|
+
"PROVISIONING_FAILED",
|
|
7
|
+
"ACCOUNT_CHANGED",
|
|
8
|
+
"UNSUPPORTED_DID_METHOD",
|
|
9
|
+
"IDENTITY_INVALID",
|
|
10
|
+
"RESOLUTION_UNAVAILABLE",
|
|
11
|
+
]);
|
|
12
|
+
const resolutionSchema = z.object({
|
|
13
|
+
flowUserId: z.string(),
|
|
14
|
+
did: z.string(),
|
|
15
|
+
handle: z.string().nullable(),
|
|
16
|
+
pdsUrl: z.url(),
|
|
17
|
+
hosting: z.enum(["flow", "external"]),
|
|
18
|
+
lifecycle: z.enum(["active", "suspended", "migrated", "deletion_pending"]),
|
|
19
|
+
authorization: z.enum(["connected", "reconnect_required"]),
|
|
20
|
+
resolvedAt: z.iso.datetime(),
|
|
21
|
+
expiresAt: z.iso.datetime(),
|
|
22
|
+
identityVersion: z.string(),
|
|
23
|
+
});
|
|
24
|
+
export class AtprotoRequestError extends Error {
|
|
25
|
+
code;
|
|
26
|
+
retryable;
|
|
27
|
+
constructor(code, retryable = false) {
|
|
28
|
+
super(code);
|
|
29
|
+
this.code = code;
|
|
30
|
+
this.retryable = retryable;
|
|
31
|
+
this.name = "AtprotoRequestError";
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/** Identity changes and migration completion should invalidate before another discovery. */
|
|
35
|
+
export function createAtprotoApi(host, getToken, getUserId) {
|
|
36
|
+
let generation = 0;
|
|
37
|
+
let dirty = false;
|
|
38
|
+
return {
|
|
39
|
+
invalidate() {
|
|
40
|
+
generation++;
|
|
41
|
+
dirty = true;
|
|
42
|
+
},
|
|
43
|
+
async resolve(options = {}) {
|
|
44
|
+
options.signal?.throwIfAborted();
|
|
45
|
+
const userId = getUserId();
|
|
46
|
+
if (!userId)
|
|
47
|
+
throw new AtprotoRequestError("SIGN_IN_REQUIRED");
|
|
48
|
+
const requestGeneration = generation;
|
|
49
|
+
const unchanged = () => {
|
|
50
|
+
if (generation !== requestGeneration || getUserId() !== userId)
|
|
51
|
+
throw new AtprotoRequestError("ACCOUNT_CHANGED");
|
|
52
|
+
};
|
|
53
|
+
const token = await getToken();
|
|
54
|
+
unchanged();
|
|
55
|
+
const headers = new Headers({ "X-Flow-User-Id": userId });
|
|
56
|
+
if (token)
|
|
57
|
+
headers.set("Authorization", `Bearer ${token}`);
|
|
58
|
+
let response;
|
|
59
|
+
try {
|
|
60
|
+
response = await fetch(`${host}/api/atproto/resolve?freshness=${dirty ? "refresh" : (options.freshness ?? "cached")}`, { headers, credentials: "include", signal: options.signal });
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
options.signal?.throwIfAborted();
|
|
64
|
+
unchanged();
|
|
65
|
+
throw new AtprotoRequestError("RESOLUTION_UNAVAILABLE", true);
|
|
66
|
+
}
|
|
67
|
+
unchanged();
|
|
68
|
+
const body = await response.json().catch(() => null);
|
|
69
|
+
options.signal?.throwIfAborted();
|
|
70
|
+
unchanged();
|
|
71
|
+
if (!response.ok) {
|
|
72
|
+
const parsed = z.object({ code: failureSchema }).safeParse(body);
|
|
73
|
+
const code = parsed.success
|
|
74
|
+
? parsed.data.code
|
|
75
|
+
: "RESOLUTION_UNAVAILABLE";
|
|
76
|
+
throw new AtprotoRequestError(code, ["RESOLUTION_UNAVAILABLE", "PROVISIONING_PENDING"].includes(code));
|
|
77
|
+
}
|
|
78
|
+
const parsed = resolutionSchema.safeParse(body);
|
|
79
|
+
if (!parsed.success)
|
|
80
|
+
throw new AtprotoRequestError("IDENTITY_INVALID");
|
|
81
|
+
if (parsed.data.flowUserId !== userId)
|
|
82
|
+
throw new AtprotoRequestError("ACCOUNT_CHANGED");
|
|
83
|
+
dirty = false;
|
|
84
|
+
return parsed.data;
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getFlow } from "./create-flow";
|
|
1
2
|
async function readResponse(response) {
|
|
2
3
|
const body = await response.json();
|
|
3
4
|
if (!response.ok)
|
|
@@ -17,6 +18,7 @@ export async function unlinkAtproto(expectedUserId) {
|
|
|
17
18
|
headers: { "Content-Type": "application/json" },
|
|
18
19
|
body: JSON.stringify({ expectedUserId }),
|
|
19
20
|
}));
|
|
21
|
+
getFlow()?.atproto.invalidate();
|
|
20
22
|
}
|
|
21
23
|
const completionKey = "flow.atproto.completion";
|
|
22
24
|
export async function connectAtproto(request, signal) {
|
|
@@ -30,6 +32,7 @@ export async function connectAtproto(request, signal) {
|
|
|
30
32
|
}));
|
|
31
33
|
signal.throwIfAborted();
|
|
32
34
|
sessionStorage.setItem(completionKey, result.completionToken);
|
|
35
|
+
getFlow()?.atproto.invalidate();
|
|
33
36
|
window.location.assign(result.url);
|
|
34
37
|
}
|
|
35
38
|
let completion = null;
|
|
@@ -44,6 +47,11 @@ export function completeAtproto() {
|
|
|
44
47
|
credentials: "include",
|
|
45
48
|
headers: { "Content-Type": "application/json" },
|
|
46
49
|
body: JSON.stringify({ completionToken }),
|
|
47
|
-
})
|
|
50
|
+
})
|
|
51
|
+
.then((readResponse))
|
|
52
|
+
.then((result) => {
|
|
53
|
+
getFlow()?.atproto.invalidate();
|
|
54
|
+
return result;
|
|
55
|
+
});
|
|
48
56
|
return completion;
|
|
49
57
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { BROWSER_FLOW_TTL_MS } from "../browser-contract";
|
|
2
2
|
import { DEFAULT_SESSION_PATH, isLocalHostname, resolveIdHost, } from "../id-host";
|
|
3
3
|
import { isExpiring } from "../token-expiry";
|
|
4
|
+
import { createAtprotoApi } from "./atproto-resolver";
|
|
4
5
|
import { createDialogHost } from "./dialog-host";
|
|
5
6
|
import { idb } from "./idb";
|
|
6
7
|
import { createRoomsApi } from "./rooms";
|
|
@@ -510,6 +511,14 @@ export function createFlow(options = {}) {
|
|
|
510
511
|
};
|
|
511
512
|
window.addEventListener("focus", refreshOnFocus);
|
|
512
513
|
document.addEventListener("visibilitychange", refreshOnFocus);
|
|
514
|
+
const atproto = createAtprotoApi(host, getToken, () => store.getSnapshot().user?.id ?? null);
|
|
515
|
+
let resolverUserId = store.getSnapshot().user?.id ?? null;
|
|
516
|
+
store.subscribe((state) => {
|
|
517
|
+
const userId = state.user?.id ?? null;
|
|
518
|
+
if (userId !== resolverUserId)
|
|
519
|
+
atproto.invalidate();
|
|
520
|
+
resolverUserId = userId;
|
|
521
|
+
});
|
|
513
522
|
const flow = {
|
|
514
523
|
get user() {
|
|
515
524
|
return store.getSnapshot().user;
|
|
@@ -541,6 +550,7 @@ export function createFlow(options = {}) {
|
|
|
541
550
|
getToken,
|
|
542
551
|
mintAudience,
|
|
543
552
|
rooms: createRoomsApi(host, getToken),
|
|
553
|
+
atproto,
|
|
544
554
|
signMessage: async (args) => {
|
|
545
555
|
const mod = await import("./signing");
|
|
546
556
|
return mod.signMessage(buildSigningContext(), args);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export { defaultIdHost, isLocalHostname } from "../id-host";
|
|
2
|
-
export type { AccessKeyOptions, ActionCatalogEntry, ActionCatalogResponse, ActionCurve, ActionEventRequest, ActionEventResponse, ActionSubjectRef, ActionSurface, ActionsApi, ActionTransitionKind, ActiveAction, ActiveActionResponse, ActiveSessionConflict, AdditionalSession, Address, BrowserAccount, BrowserAccounts, CatalogFieldRef, ClockAnchor, ConnectCapabilities, ConnectResponse, CreateFlowOptions, CreateStudySubjectInput, CurrentAction, DialogHost, FinishActionRequest, FinishActionResponse, FinishedSummary, Flow, FlowCredential, FlowSessionState, FlowState, FlowUser, FlowWidgetHandle, FlowWidgetName, FocusApi, FocusPhase, FocusSessionEvent, FocusSessionState, ListStudySessionsOptions, ListStudySubjectsOptions, LoginOptions, MarkNotificationsReadInput, MethodName, MountFlowWidgetOptions, MountProfileOptions, NotificationCounts, NotificationEntry, NotificationPage, NotificationReadResult, NotificationRefusal, OpenProfileOptions, ProfileButtonHandle, ProfilePosition, RoomMemberEntry, Session, StartActionInput, StartActionResponse, StartActionResult, StartFocusRequest, StudyApi, StudyCatalog, StudyCategory, StudyCategoryTotals, StudyField, StudyRange, StudySearchHit, StudySessionEntry, StudySessionPage, StudySubject, StudySubjectList, StudySubjectRefusal, StudySubjectRemovalResponse, StudySubjectResponse, StudySubjectTotals, StudySummary, SwitchAccountOptions, UpdateStudySubjectInput, UserActionSurface, XpEstimateContext, XpMode, } from "../types";
|
|
2
|
+
export type { AccessKeyOptions, ActionCatalogEntry, ActionCatalogResponse, ActionCurve, ActionEventRequest, ActionEventResponse, ActionSubjectRef, ActionSurface, ActionsApi, ActionTransitionKind, ActiveAction, ActiveActionResponse, ActiveSessionConflict, AdditionalSession, Address, AtprotoApi, AtprotoResolution, AtprotoResolutionFailure, AtprotoResolveOptions, BrowserAccount, BrowserAccounts, CatalogFieldRef, ClockAnchor, ConnectCapabilities, ConnectResponse, CreateFlowOptions, CreateStudySubjectInput, CurrentAction, DialogHost, FinishActionRequest, FinishActionResponse, FinishedSummary, Flow, FlowCredential, FlowSessionState, FlowState, FlowUser, FlowWidgetHandle, FlowWidgetName, FocusApi, FocusPhase, FocusSessionEvent, FocusSessionState, ListStudySessionsOptions, ListStudySubjectsOptions, LoginOptions, MarkNotificationsReadInput, MethodName, MountFlowWidgetOptions, MountProfileOptions, NotificationCounts, NotificationEntry, NotificationPage, NotificationReadResult, NotificationRefusal, OpenProfileOptions, ProfileButtonHandle, ProfilePosition, RoomMemberEntry, Session, StartActionInput, StartActionResponse, StartActionResult, StartFocusRequest, StudyApi, StudyCatalog, StudyCategory, StudyCategoryTotals, StudyField, StudyRange, StudySearchHit, StudySessionEntry, StudySessionPage, StudySubject, StudySubjectList, StudySubjectRefusal, StudySubjectRemovalResponse, StudySubjectResponse, StudySubjectTotals, StudySummary, SwitchAccountOptions, UpdateStudySubjectInput, UserActionSurface, XpEstimateContext, XpMode, } from "../types";
|
|
3
3
|
export { consistencyCurve, estimateActionXp, FLOW_SCORE_MAX, flowMultiplier, } from "../xp/curve";
|
|
4
4
|
export { ActionsRequestError, createActionsApi, isActiveSessionConflict, } from "./actions";
|
|
5
|
+
export { AtprotoRequestError, createAtprotoApi } from "./atproto-resolver";
|
|
5
6
|
export { createFlow, getFlow, requireFlow, resetFlow } from "./create-flow";
|
|
6
7
|
export { createDialogHost } from "./dialog-host";
|
|
7
8
|
export { createFlowWidget } from "./flow-widget";
|
package/dist/sdk/client/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { defaultIdHost, isLocalHostname } from "../id-host";
|
|
2
2
|
export { consistencyCurve, estimateActionXp, FLOW_SCORE_MAX, flowMultiplier, } from "../xp/curve";
|
|
3
3
|
export { ActionsRequestError, createActionsApi, isActiveSessionConflict, } from "./actions";
|
|
4
|
+
export { AtprotoRequestError, createAtprotoApi } from "./atproto-resolver";
|
|
4
5
|
export { createFlow, getFlow, requireFlow, resetFlow } from "./create-flow";
|
|
5
6
|
export { createDialogHost } from "./dialog-host";
|
|
6
7
|
export { createFlowWidget } from "./flow-widget";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { resolveIdHost } from "../id-host";
|
|
2
|
+
import { createAtprotoApi } from "./atproto-resolver";
|
|
2
3
|
import { createRoomsApi } from "./rooms";
|
|
3
4
|
function unavailable(method) {
|
|
4
5
|
throw new Error(`flow.${method} is not available on a static Flow — it renders ` +
|
|
@@ -55,6 +56,7 @@ export function createStaticFlow(state, options = {}) {
|
|
|
55
56
|
getToken,
|
|
56
57
|
mintAudience: async () => null,
|
|
57
58
|
rooms: createRoomsApi(host, getToken),
|
|
59
|
+
atproto: createAtprotoApi(host, getToken, () => snapshot.user?.id ?? null),
|
|
58
60
|
signMessage: () => unavailable("signMessage"),
|
|
59
61
|
signTypedData: () => unavailable("signTypedData"),
|
|
60
62
|
sendTransaction: () => unavailable("sendTransaction"),
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
export declare const signupPolicy: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
2
|
+
name: "signup_policy";
|
|
3
|
+
schema: undefined;
|
|
4
|
+
columns: {
|
|
5
|
+
id: import("drizzle-orm/pg-core").PgColumn<{
|
|
6
|
+
name: "id";
|
|
7
|
+
tableName: "signup_policy";
|
|
8
|
+
dataType: "number";
|
|
9
|
+
columnType: "PgInteger";
|
|
10
|
+
data: number;
|
|
11
|
+
driverParam: string | number;
|
|
12
|
+
notNull: true;
|
|
13
|
+
hasDefault: false;
|
|
14
|
+
isPrimaryKey: true;
|
|
15
|
+
isAutoincrement: false;
|
|
16
|
+
hasRuntimeDefault: false;
|
|
17
|
+
enumValues: undefined;
|
|
18
|
+
baseColumn: never;
|
|
19
|
+
identity: undefined;
|
|
20
|
+
generated: undefined;
|
|
21
|
+
}, {}, {}>;
|
|
22
|
+
invitationOnly: import("drizzle-orm/pg-core").PgColumn<{
|
|
23
|
+
name: "invitation_only";
|
|
24
|
+
tableName: "signup_policy";
|
|
25
|
+
dataType: "boolean";
|
|
26
|
+
columnType: "PgBoolean";
|
|
27
|
+
data: boolean;
|
|
28
|
+
driverParam: boolean;
|
|
29
|
+
notNull: true;
|
|
30
|
+
hasDefault: true;
|
|
31
|
+
isPrimaryKey: false;
|
|
32
|
+
isAutoincrement: false;
|
|
33
|
+
hasRuntimeDefault: false;
|
|
34
|
+
enumValues: undefined;
|
|
35
|
+
baseColumn: never;
|
|
36
|
+
identity: undefined;
|
|
37
|
+
generated: undefined;
|
|
38
|
+
}, {}, {}>;
|
|
39
|
+
updatedBy: import("drizzle-orm/pg-core").PgColumn<{
|
|
40
|
+
name: "updated_by";
|
|
41
|
+
tableName: "signup_policy";
|
|
42
|
+
dataType: "string";
|
|
43
|
+
columnType: "PgText";
|
|
44
|
+
data: string;
|
|
45
|
+
driverParam: string;
|
|
46
|
+
notNull: false;
|
|
47
|
+
hasDefault: false;
|
|
48
|
+
isPrimaryKey: false;
|
|
49
|
+
isAutoincrement: false;
|
|
50
|
+
hasRuntimeDefault: false;
|
|
51
|
+
enumValues: [string, ...string[]];
|
|
52
|
+
baseColumn: never;
|
|
53
|
+
identity: undefined;
|
|
54
|
+
generated: undefined;
|
|
55
|
+
}, {}, {}>;
|
|
56
|
+
updatedAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
57
|
+
name: "updated_at";
|
|
58
|
+
tableName: "signup_policy";
|
|
59
|
+
dataType: "date";
|
|
60
|
+
columnType: "PgTimestamp";
|
|
61
|
+
data: Date;
|
|
62
|
+
driverParam: string;
|
|
63
|
+
notNull: true;
|
|
64
|
+
hasDefault: true;
|
|
65
|
+
isPrimaryKey: false;
|
|
66
|
+
isAutoincrement: false;
|
|
67
|
+
hasRuntimeDefault: false;
|
|
68
|
+
enumValues: undefined;
|
|
69
|
+
baseColumn: never;
|
|
70
|
+
identity: undefined;
|
|
71
|
+
generated: undefined;
|
|
72
|
+
}, {}, {}>;
|
|
73
|
+
};
|
|
74
|
+
dialect: "pg";
|
|
75
|
+
}>;
|
|
76
|
+
export declare const invitation: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
77
|
+
name: "invitation";
|
|
78
|
+
schema: undefined;
|
|
79
|
+
columns: {
|
|
80
|
+
id: import("drizzle-orm/pg-core").PgColumn<{
|
|
81
|
+
name: "id";
|
|
82
|
+
tableName: "invitation";
|
|
83
|
+
dataType: "string";
|
|
84
|
+
columnType: "PgText";
|
|
85
|
+
data: string;
|
|
86
|
+
driverParam: string;
|
|
87
|
+
notNull: true;
|
|
88
|
+
hasDefault: false;
|
|
89
|
+
isPrimaryKey: true;
|
|
90
|
+
isAutoincrement: false;
|
|
91
|
+
hasRuntimeDefault: false;
|
|
92
|
+
enumValues: [string, ...string[]];
|
|
93
|
+
baseColumn: never;
|
|
94
|
+
identity: undefined;
|
|
95
|
+
generated: undefined;
|
|
96
|
+
}, {}, {}>;
|
|
97
|
+
codeHash: import("drizzle-orm/pg-core").PgColumn<{
|
|
98
|
+
name: "code_hash";
|
|
99
|
+
tableName: "invitation";
|
|
100
|
+
dataType: "string";
|
|
101
|
+
columnType: "PgText";
|
|
102
|
+
data: string;
|
|
103
|
+
driverParam: string;
|
|
104
|
+
notNull: true;
|
|
105
|
+
hasDefault: false;
|
|
106
|
+
isPrimaryKey: false;
|
|
107
|
+
isAutoincrement: false;
|
|
108
|
+
hasRuntimeDefault: false;
|
|
109
|
+
enumValues: [string, ...string[]];
|
|
110
|
+
baseColumn: never;
|
|
111
|
+
identity: undefined;
|
|
112
|
+
generated: undefined;
|
|
113
|
+
}, {}, {}>;
|
|
114
|
+
inviterId: import("drizzle-orm/pg-core").PgColumn<{
|
|
115
|
+
name: "inviter_id";
|
|
116
|
+
tableName: "invitation";
|
|
117
|
+
dataType: "string";
|
|
118
|
+
columnType: "PgText";
|
|
119
|
+
data: string;
|
|
120
|
+
driverParam: string;
|
|
121
|
+
notNull: false;
|
|
122
|
+
hasDefault: false;
|
|
123
|
+
isPrimaryKey: false;
|
|
124
|
+
isAutoincrement: false;
|
|
125
|
+
hasRuntimeDefault: false;
|
|
126
|
+
enumValues: [string, ...string[]];
|
|
127
|
+
baseColumn: never;
|
|
128
|
+
identity: undefined;
|
|
129
|
+
generated: undefined;
|
|
130
|
+
}, {}, {}>;
|
|
131
|
+
createdBy: import("drizzle-orm/pg-core").PgColumn<{
|
|
132
|
+
name: "created_by";
|
|
133
|
+
tableName: "invitation";
|
|
134
|
+
dataType: "string";
|
|
135
|
+
columnType: "PgText";
|
|
136
|
+
data: string;
|
|
137
|
+
driverParam: string;
|
|
138
|
+
notNull: false;
|
|
139
|
+
hasDefault: false;
|
|
140
|
+
isPrimaryKey: false;
|
|
141
|
+
isAutoincrement: false;
|
|
142
|
+
hasRuntimeDefault: false;
|
|
143
|
+
enumValues: [string, ...string[]];
|
|
144
|
+
baseColumn: never;
|
|
145
|
+
identity: undefined;
|
|
146
|
+
generated: undefined;
|
|
147
|
+
}, {}, {}>;
|
|
148
|
+
maxUses: import("drizzle-orm/pg-core").PgColumn<{
|
|
149
|
+
name: "max_uses";
|
|
150
|
+
tableName: "invitation";
|
|
151
|
+
dataType: "number";
|
|
152
|
+
columnType: "PgInteger";
|
|
153
|
+
data: number;
|
|
154
|
+
driverParam: string | number;
|
|
155
|
+
notNull: true;
|
|
156
|
+
hasDefault: true;
|
|
157
|
+
isPrimaryKey: false;
|
|
158
|
+
isAutoincrement: false;
|
|
159
|
+
hasRuntimeDefault: false;
|
|
160
|
+
enumValues: undefined;
|
|
161
|
+
baseColumn: never;
|
|
162
|
+
identity: undefined;
|
|
163
|
+
generated: undefined;
|
|
164
|
+
}, {}, {}>;
|
|
165
|
+
usedCount: import("drizzle-orm/pg-core").PgColumn<{
|
|
166
|
+
name: "used_count";
|
|
167
|
+
tableName: "invitation";
|
|
168
|
+
dataType: "number";
|
|
169
|
+
columnType: "PgInteger";
|
|
170
|
+
data: number;
|
|
171
|
+
driverParam: string | number;
|
|
172
|
+
notNull: true;
|
|
173
|
+
hasDefault: true;
|
|
174
|
+
isPrimaryKey: false;
|
|
175
|
+
isAutoincrement: false;
|
|
176
|
+
hasRuntimeDefault: false;
|
|
177
|
+
enumValues: undefined;
|
|
178
|
+
baseColumn: never;
|
|
179
|
+
identity: undefined;
|
|
180
|
+
generated: undefined;
|
|
181
|
+
}, {}, {}>;
|
|
182
|
+
createdAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
183
|
+
name: "created_at";
|
|
184
|
+
tableName: "invitation";
|
|
185
|
+
dataType: "date";
|
|
186
|
+
columnType: "PgTimestamp";
|
|
187
|
+
data: Date;
|
|
188
|
+
driverParam: string;
|
|
189
|
+
notNull: true;
|
|
190
|
+
hasDefault: true;
|
|
191
|
+
isPrimaryKey: false;
|
|
192
|
+
isAutoincrement: false;
|
|
193
|
+
hasRuntimeDefault: false;
|
|
194
|
+
enumValues: undefined;
|
|
195
|
+
baseColumn: never;
|
|
196
|
+
identity: undefined;
|
|
197
|
+
generated: undefined;
|
|
198
|
+
}, {}, {}>;
|
|
199
|
+
expiresAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
200
|
+
name: "expires_at";
|
|
201
|
+
tableName: "invitation";
|
|
202
|
+
dataType: "date";
|
|
203
|
+
columnType: "PgTimestamp";
|
|
204
|
+
data: Date;
|
|
205
|
+
driverParam: string;
|
|
206
|
+
notNull: true;
|
|
207
|
+
hasDefault: false;
|
|
208
|
+
isPrimaryKey: false;
|
|
209
|
+
isAutoincrement: false;
|
|
210
|
+
hasRuntimeDefault: false;
|
|
211
|
+
enumValues: undefined;
|
|
212
|
+
baseColumn: never;
|
|
213
|
+
identity: undefined;
|
|
214
|
+
generated: undefined;
|
|
215
|
+
}, {}, {}>;
|
|
216
|
+
revokedAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
217
|
+
name: "revoked_at";
|
|
218
|
+
tableName: "invitation";
|
|
219
|
+
dataType: "date";
|
|
220
|
+
columnType: "PgTimestamp";
|
|
221
|
+
data: Date;
|
|
222
|
+
driverParam: string;
|
|
223
|
+
notNull: false;
|
|
224
|
+
hasDefault: false;
|
|
225
|
+
isPrimaryKey: false;
|
|
226
|
+
isAutoincrement: false;
|
|
227
|
+
hasRuntimeDefault: false;
|
|
228
|
+
enumValues: undefined;
|
|
229
|
+
baseColumn: never;
|
|
230
|
+
identity: undefined;
|
|
231
|
+
generated: undefined;
|
|
232
|
+
}, {}, {}>;
|
|
233
|
+
};
|
|
234
|
+
dialect: "pg";
|
|
235
|
+
}>;
|
|
236
|
+
export declare const invitationRedemption: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
237
|
+
name: "invitation_redemption";
|
|
238
|
+
schema: undefined;
|
|
239
|
+
columns: {
|
|
240
|
+
userId: import("drizzle-orm/pg-core").PgColumn<{
|
|
241
|
+
name: "user_id";
|
|
242
|
+
tableName: "invitation_redemption";
|
|
243
|
+
dataType: "string";
|
|
244
|
+
columnType: "PgText";
|
|
245
|
+
data: string;
|
|
246
|
+
driverParam: string;
|
|
247
|
+
notNull: true;
|
|
248
|
+
hasDefault: false;
|
|
249
|
+
isPrimaryKey: true;
|
|
250
|
+
isAutoincrement: false;
|
|
251
|
+
hasRuntimeDefault: false;
|
|
252
|
+
enumValues: [string, ...string[]];
|
|
253
|
+
baseColumn: never;
|
|
254
|
+
identity: undefined;
|
|
255
|
+
generated: undefined;
|
|
256
|
+
}, {}, {}>;
|
|
257
|
+
invitationId: import("drizzle-orm/pg-core").PgColumn<{
|
|
258
|
+
name: "invitation_id";
|
|
259
|
+
tableName: "invitation_redemption";
|
|
260
|
+
dataType: "string";
|
|
261
|
+
columnType: "PgText";
|
|
262
|
+
data: string;
|
|
263
|
+
driverParam: string;
|
|
264
|
+
notNull: true;
|
|
265
|
+
hasDefault: false;
|
|
266
|
+
isPrimaryKey: false;
|
|
267
|
+
isAutoincrement: false;
|
|
268
|
+
hasRuntimeDefault: false;
|
|
269
|
+
enumValues: [string, ...string[]];
|
|
270
|
+
baseColumn: never;
|
|
271
|
+
identity: undefined;
|
|
272
|
+
generated: undefined;
|
|
273
|
+
}, {}, {}>;
|
|
274
|
+
inviterId: import("drizzle-orm/pg-core").PgColumn<{
|
|
275
|
+
name: "inviter_id";
|
|
276
|
+
tableName: "invitation_redemption";
|
|
277
|
+
dataType: "string";
|
|
278
|
+
columnType: "PgText";
|
|
279
|
+
data: string;
|
|
280
|
+
driverParam: string;
|
|
281
|
+
notNull: false;
|
|
282
|
+
hasDefault: false;
|
|
283
|
+
isPrimaryKey: false;
|
|
284
|
+
isAutoincrement: false;
|
|
285
|
+
hasRuntimeDefault: false;
|
|
286
|
+
enumValues: [string, ...string[]];
|
|
287
|
+
baseColumn: never;
|
|
288
|
+
identity: undefined;
|
|
289
|
+
generated: undefined;
|
|
290
|
+
}, {}, {}>;
|
|
291
|
+
redeemedAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
292
|
+
name: "redeemed_at";
|
|
293
|
+
tableName: "invitation_redemption";
|
|
294
|
+
dataType: "date";
|
|
295
|
+
columnType: "PgTimestamp";
|
|
296
|
+
data: Date;
|
|
297
|
+
driverParam: string;
|
|
298
|
+
notNull: true;
|
|
299
|
+
hasDefault: true;
|
|
300
|
+
isPrimaryKey: false;
|
|
301
|
+
isAutoincrement: false;
|
|
302
|
+
hasRuntimeDefault: false;
|
|
303
|
+
enumValues: undefined;
|
|
304
|
+
baseColumn: never;
|
|
305
|
+
identity: undefined;
|
|
306
|
+
generated: undefined;
|
|
307
|
+
}, {}, {}>;
|
|
308
|
+
};
|
|
309
|
+
dialect: "pg";
|
|
310
|
+
}>;
|