@bitbaum/accountkit 0.0.0-stage → 0.6.3
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/LICENSE +21 -0
- package/README.md +203 -2
- package/dist/AccountMenu.d.ts +76 -0
- package/dist/AccountMenu.d.ts.map +1 -0
- package/dist/AccountMenu.js +156 -0
- package/dist/AccountMenu.js.map +1 -0
- package/dist/SignInError.d.ts +50 -0
- package/dist/SignInError.d.ts.map +1 -0
- package/dist/SignInError.js +34 -0
- package/dist/SignInError.js.map +1 -0
- package/dist/auth/client.d.ts +19 -0
- package/dist/auth/client.d.ts.map +1 -0
- package/dist/auth/client.js +17 -0
- package/dist/auth/client.js.map +1 -0
- package/dist/auth/factor.d.ts +9 -0
- package/dist/auth/factor.d.ts.map +1 -0
- package/dist/auth/factor.js +107 -0
- package/dist/auth/factor.js.map +1 -0
- package/dist/auth/index.d.ts +6 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +6 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/labels.d.ts +114 -0
- package/dist/auth/labels.d.ts.map +1 -0
- package/dist/auth/labels.js +132 -0
- package/dist/auth/labels.js.map +1 -0
- package/dist/auth/limits.d.ts +28 -0
- package/dist/auth/limits.d.ts.map +1 -0
- package/dist/auth/limits.js +90 -0
- package/dist/auth/limits.js.map +1 -0
- package/dist/auth/mail.d.ts +10 -0
- package/dist/auth/mail.d.ts.map +1 -0
- package/dist/auth/mail.js +45 -0
- package/dist/auth/mail.js.map +1 -0
- package/dist/auth/methods.d.ts +71 -0
- package/dist/auth/methods.d.ts.map +1 -0
- package/dist/auth/methods.js +92 -0
- package/dist/auth/methods.js.map +1 -0
- package/dist/auth/next.d.ts +73 -0
- package/dist/auth/next.d.ts.map +1 -0
- package/dist/auth/next.js +131 -0
- package/dist/auth/next.js.map +1 -0
- package/dist/auth/react.d.ts +174 -0
- package/dist/auth/react.d.ts.map +1 -0
- package/dist/auth/react.js +396 -0
- package/dist/auth/react.js.map +1 -0
- package/dist/auth/recovery.d.ts +17 -0
- package/dist/auth/recovery.d.ts.map +1 -0
- package/dist/auth/recovery.js +85 -0
- package/dist/auth/recovery.js.map +1 -0
- package/dist/auth/roles.d.ts +19 -0
- package/dist/auth/roles.d.ts.map +1 -0
- package/dist/auth/roles.js +29 -0
- package/dist/auth/roles.js.map +1 -0
- package/dist/auth/schema.d.ts +1923 -0
- package/dist/auth/schema.d.ts.map +1 -0
- package/dist/auth/schema.js +120 -0
- package/dist/auth/schema.js.map +1 -0
- package/dist/auth/server.d.ts +56 -0
- package/dist/auth/server.d.ts.map +1 -0
- package/dist/auth/server.js +229 -0
- package/dist/auth/server.js.map +1 -0
- package/dist/auth/translations.d.ts +9 -0
- package/dist/auth/translations.d.ts.map +1 -0
- package/dist/auth/translations.js +513 -0
- package/dist/auth/translations.js.map +1 -0
- package/dist/identity.d.ts +50 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +76 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/orangecat.d.ts +333 -0
- package/dist/orangecat.d.ts.map +1 -0
- package/dist/orangecat.js +508 -0
- package/dist/orangecat.js.map +1 -0
- package/dist/paths.d.ts +3 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +11 -0
- package/dist/paths.js.map +1 -0
- package/package.json +145 -4
- package/styles.css +383 -0
package/dist/identity.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Who is signed in, as the menu shows it — pure, so every rule is testable
|
|
3
|
+
* without a browser.
|
|
4
|
+
*
|
|
5
|
+
* Two apps had already learned two different halves of this, and each was
|
|
6
|
+
* missing the other's half:
|
|
7
|
+
*
|
|
8
|
+
* - Loki: initials come from the NAME only. Built from an email local-part,
|
|
9
|
+
* "butaeff" becomes "B" and tells the person nothing they didn't know.
|
|
10
|
+
* - OrangeCat: a display name is NEVER reconstructed from the email address.
|
|
11
|
+
* Its old chain ended in the local-part titlecased, so
|
|
12
|
+
* `firstname.lastname@…` came out as "Firstname Lastname" — a real name
|
|
13
|
+
* nobody typed, rebuilt from an address the person never chose to display,
|
|
14
|
+
* on an account that may have chosen a pseudonym on purpose.
|
|
15
|
+
*
|
|
16
|
+
* Loki itself still fell back to the email local-part for its name. This
|
|
17
|
+
* module takes OrangeCat's rule, so adopting it fixes that too.
|
|
18
|
+
*/
|
|
19
|
+
/** Shown when the person has no name and no handle. Not their email. */
|
|
20
|
+
export const PLACEHOLDER_NAME = "Account";
|
|
21
|
+
/**
|
|
22
|
+
* The name the menu shows: name, else @handle, else a placeholder.
|
|
23
|
+
* Never the email, never anything derived from it.
|
|
24
|
+
*/
|
|
25
|
+
export function displayNameFor(user) {
|
|
26
|
+
const name = user.name?.trim();
|
|
27
|
+
if (name)
|
|
28
|
+
return name;
|
|
29
|
+
const handle = user.handle?.trim().replace(/^@/, "");
|
|
30
|
+
if (handle)
|
|
31
|
+
return `@${handle}`;
|
|
32
|
+
return PLACEHOLDER_NAME;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Up to two initials from the person's NAME, or null — in which case the
|
|
36
|
+
* trigger draws a person glyph rather than a letter that means nothing.
|
|
37
|
+
*/
|
|
38
|
+
export function initialsFor(user) {
|
|
39
|
+
const name = user.name?.trim();
|
|
40
|
+
if (!name)
|
|
41
|
+
return null;
|
|
42
|
+
const letters = name
|
|
43
|
+
.split(/\s+/)
|
|
44
|
+
.slice(0, 2)
|
|
45
|
+
.map((part) => Array.from(part)[0]?.toUpperCase() ?? "")
|
|
46
|
+
.join("");
|
|
47
|
+
return letters || null;
|
|
48
|
+
}
|
|
49
|
+
/** The identity line under the name: @handle when the name is shown, else the email. */
|
|
50
|
+
export function secondaryLineFor(user) {
|
|
51
|
+
const name = user.name?.trim();
|
|
52
|
+
const handle = user.handle?.trim().replace(/^@/, "");
|
|
53
|
+
if (name && handle)
|
|
54
|
+
return `@${handle}`;
|
|
55
|
+
return user.email?.trim() || null;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Where keyboard focus goes next among `count` menu items. Arrows wrap;
|
|
59
|
+
* Home and End jump. Pure so the wrap-around is pinned by a test — an
|
|
60
|
+
* off-by-one here strands the keyboard on the last row.
|
|
61
|
+
*/
|
|
62
|
+
export function nextMenuIndex(current, key, count) {
|
|
63
|
+
if (count <= 0)
|
|
64
|
+
return -1;
|
|
65
|
+
switch (key) {
|
|
66
|
+
case "Home":
|
|
67
|
+
return 0;
|
|
68
|
+
case "End":
|
|
69
|
+
return count - 1;
|
|
70
|
+
case "ArrowDown":
|
|
71
|
+
return current < 0 ? 0 : (current + 1) % count;
|
|
72
|
+
case "ArrowUp":
|
|
73
|
+
return current < 0 ? count - 1 : (current - 1 + count) % count;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAcH,wEAAwE;AACxE,MAAM,CAAC,MAAM,gBAAgB,GAAG,SAAS,CAAC;AAE1C;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,IAAiB;IAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;IAC/B,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IACtB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACrD,IAAI,MAAM;QAAE,OAAO,IAAI,MAAM,EAAE,CAAC;IAChC,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,IAAiB;IAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;IAC/B,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,MAAM,OAAO,GAAG,IAAI;SACjB,KAAK,CAAC,KAAK,CAAC;SACZ,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;SACvD,IAAI,CAAC,EAAE,CAAC,CAAC;IACZ,OAAO,OAAO,IAAI,IAAI,CAAC;AACzB,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,gBAAgB,CAAC,IAAiB;IAChD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;IAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACrD,IAAI,IAAI,IAAI,MAAM;QAAE,OAAO,IAAI,MAAM,EAAE,CAAC;IACxC,OAAO,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC;AACpC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAC3B,OAAe,EACf,GAA6C,EAC7C,KAAa;IAEb,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC,CAAC;IAC1B,QAAQ,GAAG,EAAE,CAAC;QACZ,KAAK,MAAM;YACT,OAAO,CAAC,CAAC;QACX,KAAK,KAAK;YACR,OAAO,KAAK,GAAG,CAAC,CAAC;QACnB,KAAK,WAAW;YACd,OAAO,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;QACjD,KAAK,SAAS;YACZ,OAAO,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC;IACnE,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { displayNameFor, initialsFor, nextMenuIndex, secondaryLineFor, PLACEHOLDER_NAME, type AccountUser, } from "./identity.js";
|
|
2
|
+
export { AccountMenu, type AccountActionItem, type AccountGroup, type AccountItem, type AccountLinkItem, type AccountMenuLabels, type AccountMenuProps, type RenderLinkProps, } from "./AccountMenu.js";
|
|
3
|
+
export { SignInError, signInErrorKind, type SignInErrorKind, type SignInErrorLabels, type SignInErrorProps, } from "./SignInError.js";
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EAChB,KAAK,WAAW,GACjB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,WAAW,EACX,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,eAAe,GACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,WAAW,EACX,eAAe,EACf,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,GACtB,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,gBAAgB,GAEjB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,WAAW,GAQZ,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,WAAW,EACX,eAAe,GAIhB,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
export declare const ORANGECAT_PROVIDER_ID = "orangecat";
|
|
2
|
+
export declare const ORANGECAT_DEFAULT_ISSUER = "https://orangecat.ch";
|
|
3
|
+
/** Identity only. An app that acts on OrangeCat's behalf passes its own. */
|
|
4
|
+
export declare const ORANGECAT_IDENTITY_SCOPES = "openid profile email";
|
|
5
|
+
type Env = Record<string, string | undefined>;
|
|
6
|
+
/**
|
|
7
|
+
* The issuer every OrangeCat token's `iss` carries. Not normalised: OIDC
|
|
8
|
+
* compares `iss` byte for byte, so a trailing slash in the env is a
|
|
9
|
+
* different issuer, exactly as discovery would treat it.
|
|
10
|
+
*/
|
|
11
|
+
export declare function orangecatIssuer(env?: Env): string;
|
|
12
|
+
export interface OrangecatClient {
|
|
13
|
+
clientId: string;
|
|
14
|
+
clientSecret: string;
|
|
15
|
+
issuer: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The client pair from the env names every app already uses, or null. Null
|
|
19
|
+
* means the provider is ABSENT — an app hides the button rather than mount a
|
|
20
|
+
* half-configured provider that fails opaquely at the code exchange.
|
|
21
|
+
*/
|
|
22
|
+
export declare function orangecatClient(env?: Env): OrangecatClient | null;
|
|
23
|
+
/** The id_token / userinfo claims OrangeCat sends. `sub` is the actor id. */
|
|
24
|
+
export interface OrangecatClaims {
|
|
25
|
+
sub?: string | null;
|
|
26
|
+
name?: string | null;
|
|
27
|
+
preferred_username?: string | null;
|
|
28
|
+
email?: string | null;
|
|
29
|
+
picture?: string | null;
|
|
30
|
+
[claim: string]: unknown;
|
|
31
|
+
}
|
|
32
|
+
/** What the provider hands Auth.js as "the user". */
|
|
33
|
+
export interface OrangecatProfileUser {
|
|
34
|
+
id: string;
|
|
35
|
+
name: string | null;
|
|
36
|
+
image: string | null;
|
|
37
|
+
/** The actor id again, under a name an adapter can key on. */
|
|
38
|
+
orangecatSub: string;
|
|
39
|
+
/** OrangeCat handle, without the @. */
|
|
40
|
+
username: string | null;
|
|
41
|
+
/** The OrangeCat address as CONTACT data, lower-cased. Never an identity. */
|
|
42
|
+
contactEmail: string | null;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Deliberately has NO `email` key. For an account it has not seen, Auth.js
|
|
46
|
+
* calls `getUserByEmail(user.email)` and then either links the two (account
|
|
47
|
+
* takeover, since the address is unverified) or refuses the sign-in
|
|
48
|
+
* (OAuthAccountNotLinked). Without the key that lookup never runs, so a new
|
|
49
|
+
* `sub` always becomes a new person. The address rides along as
|
|
50
|
+
* `contactEmail`, for an app that wants to store it — see `contactEmailFor`.
|
|
51
|
+
*/
|
|
52
|
+
export declare function orangecatProfile(claims: OrangecatClaims): OrangecatProfileUser;
|
|
53
|
+
export interface OrangecatProviderOptions {
|
|
54
|
+
clientId: string;
|
|
55
|
+
clientSecret: string;
|
|
56
|
+
issuer?: string;
|
|
57
|
+
/** Space-separated. Defaults to identity only; must not exceed what
|
|
58
|
+
* OrangeCat registered for the client, or the consent screen refuses. */
|
|
59
|
+
scopes?: string;
|
|
60
|
+
}
|
|
61
|
+
/** Auth.js v5 (`next-auth@5`). Spread into `providers: [...]`. */
|
|
62
|
+
export declare function orangecatProvider(options: OrangecatProviderOptions): {
|
|
63
|
+
id: string;
|
|
64
|
+
name: string;
|
|
65
|
+
type: "oidc";
|
|
66
|
+
issuer: string;
|
|
67
|
+
clientId: string;
|
|
68
|
+
clientSecret: string;
|
|
69
|
+
client: {
|
|
70
|
+
token_endpoint_auth_method: "client_secret_post";
|
|
71
|
+
};
|
|
72
|
+
checks: ("pkce" | "state")[];
|
|
73
|
+
authorization: {
|
|
74
|
+
params: {
|
|
75
|
+
scope: string;
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
profile: typeof orangecatProfile;
|
|
79
|
+
allowDangerousEmailAccountLinking: boolean;
|
|
80
|
+
};
|
|
81
|
+
/** next-auth v4 (`next-auth@4`): an "oauth" provider with OIDC discovery. */
|
|
82
|
+
export declare function orangecatProviderV4(options: OrangecatProviderOptions): {
|
|
83
|
+
id: string;
|
|
84
|
+
name: string;
|
|
85
|
+
type: "oauth";
|
|
86
|
+
wellKnown: string;
|
|
87
|
+
issuer: string;
|
|
88
|
+
idToken: boolean;
|
|
89
|
+
clientId: string;
|
|
90
|
+
clientSecret: string;
|
|
91
|
+
client: {
|
|
92
|
+
token_endpoint_auth_method: "client_secret_post";
|
|
93
|
+
};
|
|
94
|
+
checks: ("pkce" | "state")[];
|
|
95
|
+
authorization: {
|
|
96
|
+
params: {
|
|
97
|
+
scope: string;
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
profile: typeof orangecatProfile;
|
|
101
|
+
allowDangerousEmailAccountLinking: boolean;
|
|
102
|
+
};
|
|
103
|
+
export type EntryMode = "sign-in" | "sign-up";
|
|
104
|
+
/** The providers OrangeCat has switched on that an app may offer a button for. */
|
|
105
|
+
export declare const SOCIAL_PROVIDERS: readonly ["google", "github"];
|
|
106
|
+
export type SocialProvider = (typeof SOCIAL_PROVIDERS)[number];
|
|
107
|
+
export declare function isSocialProvider(value: unknown): value is SocialProvider;
|
|
108
|
+
/**
|
|
109
|
+
* The third argument to `signIn("orangecat", options, params)`. OrangeCat's
|
|
110
|
+
* screen opens already in the state the person chose:
|
|
111
|
+
*
|
|
112
|
+
* prompt=create on "Create account" (OIDC Prompt Create 1.0)
|
|
113
|
+
* login_hint the email they typed, pre-filled
|
|
114
|
+
* idp_hint straight to Google or GitHub
|
|
115
|
+
*
|
|
116
|
+
* Auth.js merges these into the authorization URL verbatim, including over
|
|
117
|
+
* its own parameters, so only these three keys are ever produced and every
|
|
118
|
+
* value is checked first.
|
|
119
|
+
*/
|
|
120
|
+
export declare function authorizationParams(input: {
|
|
121
|
+
mode?: EntryMode;
|
|
122
|
+
email?: string | null;
|
|
123
|
+
provider?: string | null;
|
|
124
|
+
}): Record<string, string>;
|
|
125
|
+
/**
|
|
126
|
+
* Where to land after signing in: `from`, if it is a path on this site.
|
|
127
|
+
* `from` arrives in a URL anyone can write, so `//evil.example` and
|
|
128
|
+
* `/\evil.example` (which browsers read as protocol-relative) are refused.
|
|
129
|
+
*/
|
|
130
|
+
export { returnPath } from "./paths.js";
|
|
131
|
+
export interface OcSessionClaims extends Record<string, unknown> {
|
|
132
|
+
/** OrangeCat actor id (id_token.sub). Absent = not signed in. */
|
|
133
|
+
actorId?: string;
|
|
134
|
+
ocRefreshToken?: string;
|
|
135
|
+
/** Access-token expiry, seconds since the epoch. */
|
|
136
|
+
ocExpiresAt?: number;
|
|
137
|
+
/** Earliest time (seconds) to retry after a transient refresh failure. */
|
|
138
|
+
ocRetryAt?: number;
|
|
139
|
+
}
|
|
140
|
+
export interface OcTokenGrant {
|
|
141
|
+
refresh_token?: string | null;
|
|
142
|
+
expires_at?: number | null;
|
|
143
|
+
}
|
|
144
|
+
/** On sign-in: remember what OrangeCat handed over. */
|
|
145
|
+
export declare function bindOcTokens<T extends OcSessionClaims>(token: T, account: OcTokenGrant): T;
|
|
146
|
+
/** True when the access token has (nearly) expired and a retry is not on hold. */
|
|
147
|
+
export declare function ocRefreshDue(token: OcSessionClaims, nowSeconds: number): boolean;
|
|
148
|
+
export type OcRefreshResult = {
|
|
149
|
+
ok: true;
|
|
150
|
+
refreshToken: string;
|
|
151
|
+
expiresAt: number;
|
|
152
|
+
} | {
|
|
153
|
+
ok: false;
|
|
154
|
+
revoked: true;
|
|
155
|
+
} | {
|
|
156
|
+
ok: false;
|
|
157
|
+
revoked: false;
|
|
158
|
+
reason: string;
|
|
159
|
+
};
|
|
160
|
+
export interface OcRefreshDeps {
|
|
161
|
+
issuer: string;
|
|
162
|
+
clientId: string;
|
|
163
|
+
clientSecret: string;
|
|
164
|
+
fetch: typeof fetch;
|
|
165
|
+
nowSeconds: number;
|
|
166
|
+
}
|
|
167
|
+
/** One refresh_token grant against OrangeCat's token endpoint. */
|
|
168
|
+
export declare function refreshOcTokens(refreshToken: string, deps: OcRefreshDeps): Promise<OcRefreshResult>;
|
|
169
|
+
/**
|
|
170
|
+
* Apply a refresh outcome. Revoked → the identity is dropped, which is how
|
|
171
|
+
* an app reads "signed out" (read `token.actorId`, never `token.sub`).
|
|
172
|
+
* Transient → hold the retry for a minute.
|
|
173
|
+
*/
|
|
174
|
+
export declare function applyOcRefresh<T extends OcSessionClaims>(token: T, result: OcRefreshResult, nowSeconds: number): T;
|
|
175
|
+
/**
|
|
176
|
+
* The whole of an app's `jwt()` callback for OrangeCat, in one call:
|
|
177
|
+
*
|
|
178
|
+
* async jwt({ token, account, profile }) {
|
|
179
|
+
* return syncOcSession({ token, account, profile }, orangecat);
|
|
180
|
+
* }
|
|
181
|
+
*
|
|
182
|
+
* Sign-in: records the actor id and the tokens. Afterwards: refreshes when
|
|
183
|
+
* due, and drops `actorId` when OrangeCat revoked the grant.
|
|
184
|
+
*/
|
|
185
|
+
export declare function syncOcSession<T extends OcSessionClaims>(input: {
|
|
186
|
+
token: T;
|
|
187
|
+
account?: (OcTokenGrant & {
|
|
188
|
+
provider?: string;
|
|
189
|
+
}) | null;
|
|
190
|
+
profile?: {
|
|
191
|
+
sub?: string | null;
|
|
192
|
+
} | null;
|
|
193
|
+
}, client: OrangecatClient | null, deps?: {
|
|
194
|
+
fetch?: typeof fetch;
|
|
195
|
+
nowSeconds?: number;
|
|
196
|
+
}): Promise<T>;
|
|
197
|
+
/**
|
|
198
|
+
* The address stored when the OrangeCat email already belongs to another
|
|
199
|
+
* local user (or there is none). `.invalid` is reserved (RFC 2606): it can
|
|
200
|
+
* never be delivered to, registered, or sent a reset link.
|
|
201
|
+
*/
|
|
202
|
+
export declare function placeholderEmail(sub: string): string;
|
|
203
|
+
export declare function isPlaceholderEmail(email: string | null | undefined): boolean;
|
|
204
|
+
/** The contact address to store for a new OrangeCat user: theirs when free. */
|
|
205
|
+
export declare function contactEmailFor(sub: string, wanted: string | null | undefined, taken: boolean): string;
|
|
206
|
+
/**
|
|
207
|
+
* Whether a sign-in's email may earn ADMIN_EMAILS (or any email-list)
|
|
208
|
+
* promotion. Never for OrangeCat: promoting on an unverified address makes
|
|
209
|
+
* admin a matter of typing one into OrangeCat.
|
|
210
|
+
*/
|
|
211
|
+
export declare function emailEarnsPromotion(provider: string | null | undefined): boolean;
|
|
212
|
+
/**
|
|
213
|
+
* Whether "forgot password" may email this account a reset link.
|
|
214
|
+
*
|
|
215
|
+
* A user OrangeCat created has no local password, and its address came from
|
|
216
|
+
* OrangeCat unverified: a reset link would hand whoever really owns that
|
|
217
|
+
* address a password on the OrangeCat person's account. A placeholder can
|
|
218
|
+
* never receive mail. Anyone with a password of their own may reset it.
|
|
219
|
+
*/
|
|
220
|
+
export declare function mayReceivePasswordReset(user: {
|
|
221
|
+
email: string | null | undefined;
|
|
222
|
+
hasPassword: boolean;
|
|
223
|
+
orangecatLinked: boolean;
|
|
224
|
+
}): boolean;
|
|
225
|
+
export type OrangecatRefusal = "already-linked" | "no-email" | "email-taken";
|
|
226
|
+
export type OrangecatDecision = {
|
|
227
|
+
kind: "existing";
|
|
228
|
+
userId: string;
|
|
229
|
+
} | {
|
|
230
|
+
kind: "link";
|
|
231
|
+
userId: string;
|
|
232
|
+
} | {
|
|
233
|
+
kind: "create";
|
|
234
|
+
email: string;
|
|
235
|
+
} | {
|
|
236
|
+
kind: "refuse";
|
|
237
|
+
reason: OrangecatRefusal;
|
|
238
|
+
};
|
|
239
|
+
export interface OrangecatPolicy {
|
|
240
|
+
/** Another local account has this address. Default: a placeholder. evig
|
|
241
|
+
* refuses instead and sends the person to connect from their profile. */
|
|
242
|
+
whenEmailTaken?: "placeholder" | "refuse";
|
|
243
|
+
/** OrangeCat sent no address (an anonymous account). Default: placeholder. */
|
|
244
|
+
whenNoEmail?: "placeholder" | "refuse";
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* What an OrangeCat sign-in means for a local account. Pure; the adapter
|
|
248
|
+
* wrapper and the JWT-only apps (evig) both decide through it.
|
|
249
|
+
*
|
|
250
|
+
* - An explicit connect from a signed-in account wins: the person's own
|
|
251
|
+
* decision, made from inside their session.
|
|
252
|
+
* - A known `sub` signs in as its user.
|
|
253
|
+
* - Anything else creates a new user — never a match on email.
|
|
254
|
+
*/
|
|
255
|
+
export declare function decideOrangecatSignIn(input: {
|
|
256
|
+
sub: string;
|
|
257
|
+
contactEmail: string | null | undefined;
|
|
258
|
+
/** The local user already carrying this sub. */
|
|
259
|
+
byActor: {
|
|
260
|
+
id: string;
|
|
261
|
+
} | null;
|
|
262
|
+
/** The signed-in user who asked to connect (link token / session). */
|
|
263
|
+
linkFor: {
|
|
264
|
+
id: string;
|
|
265
|
+
orangecatSub: string | null;
|
|
266
|
+
} | null;
|
|
267
|
+
/** Whether another local user holds `contactEmail` (case-insensitive). */
|
|
268
|
+
emailTaken: boolean;
|
|
269
|
+
}, policy?: OrangecatPolicy): OrangecatDecision;
|
|
270
|
+
/** The few database operations the OrangeCat identity rule needs. */
|
|
271
|
+
export interface OrangecatUserStore<U> {
|
|
272
|
+
findBySub(sub: string): Promise<U | null>;
|
|
273
|
+
/** Case-insensitive. */
|
|
274
|
+
emailTaken(email: string): Promise<boolean>;
|
|
275
|
+
insert(user: {
|
|
276
|
+
orangecatSub: string;
|
|
277
|
+
email: string;
|
|
278
|
+
name: string | null;
|
|
279
|
+
image: string | null;
|
|
280
|
+
}): Promise<U>;
|
|
281
|
+
/** Attach a sub to an existing user. False when they already hold a different one. */
|
|
282
|
+
attachSub(userId: string, sub: string): Promise<boolean>;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Find or create the local user for an OrangeCat identity — for apps that
|
|
286
|
+
* resolve in a callback rather than through an adapter (datacat). Survives
|
|
287
|
+
* the insert race datacat found: a concurrent sign-in of the same sub returns
|
|
288
|
+
* that row; an address claimed between check and insert falls back to the
|
|
289
|
+
* placeholder.
|
|
290
|
+
*/
|
|
291
|
+
export declare function resolveOrangecatUser<U>(store: OrangecatUserStore<U>, identity: {
|
|
292
|
+
sub: string;
|
|
293
|
+
contactEmail?: string | null;
|
|
294
|
+
name?: string | null;
|
|
295
|
+
image?: string | null;
|
|
296
|
+
}): Promise<U>;
|
|
297
|
+
export interface AdapterSlice {
|
|
298
|
+
getUserByAccount?(ref: never): unknown;
|
|
299
|
+
createUser?(user: never): unknown;
|
|
300
|
+
linkAccount?(account: never): unknown;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Wrap an Auth.js adapter so an OrangeCat sign-in resolves its user by
|
|
304
|
+
* `sub` alone. Every other provider passes straight through.
|
|
305
|
+
*
|
|
306
|
+
* `keepTokens: false` (default) stores no OrangeCat tokens — identity only,
|
|
307
|
+
* and the sub column is the single source of truth for the link. An app that
|
|
308
|
+
* calls OrangeCat on the person's behalf (loki) passes `true`, and the base
|
|
309
|
+
* adapter also writes the accounts row.
|
|
310
|
+
*
|
|
311
|
+
* Linking an existing account is Auth.js's own path: sign in to the app,
|
|
312
|
+
* then sign in with OrangeCat — `linkAccount` runs for the signed-in user,
|
|
313
|
+
* never on the strength of an email match.
|
|
314
|
+
*/
|
|
315
|
+
export declare function withOrangecatIdentity<A extends AdapterSlice, U>(base: A, store: OrangecatUserStore<U>, options?: {
|
|
316
|
+
keepTokens?: boolean;
|
|
317
|
+
}): A;
|
|
318
|
+
/**
|
|
319
|
+
* For an app without an adapter, proof that THIS signed-in user asked to
|
|
320
|
+
* connect OrangeCat: a cookie set by a POST from inside their session,
|
|
321
|
+
* read back by the sign-in callback, good for ten minutes. The OrangeCat
|
|
322
|
+
* identity that comes back attaches to that account and no other.
|
|
323
|
+
*
|
|
324
|
+
* POST /api/user/orangecat → set cookie mintLinkToken(user.id, AUTH_SECRET)
|
|
325
|
+
* signIn("orangecat") → OrangeCat → callback
|
|
326
|
+
* signIn/jwt callback → readLinkToken(cookie) → decideOrangecatSignIn({ linkFor })
|
|
327
|
+
*/
|
|
328
|
+
export declare const ORANGECAT_LINK_TTL_SECONDS: number;
|
|
329
|
+
/** `userId.expiresAt.signature`, minted for one signed-in user. */
|
|
330
|
+
export declare function mintLinkToken(userId: string, secret: string, nowMs?: number): string;
|
|
331
|
+
/** The user id the token was minted for, or null if forged, altered or expired. */
|
|
332
|
+
export declare function readLinkToken(token: string | null | undefined, secret: string, nowMs?: number): string | null;
|
|
333
|
+
//# sourceMappingURL=orangecat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orangecat.d.ts","sourceRoot":"","sources":["../src/orangecat.ts"],"names":[],"mappings":"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"}
|