@ghuri/socialauth 0.0.0-stage → 0.1.0-alpha.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ghuri contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,189 @@
1
- # Temporary Holding Version
1
+ # @ghuri/socialauth
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ "Log in with GitHub / Google / Facebook…" for [Ghuri](https://github.com/ghurijs/ghuri), like **django-allauth**'s
4
+ `socialaccount`: configure providers in settings and include the URLs. Accounts are linked to users with the same
5
+ tables as allauth, new users sign up automatically, existing users connect more providers, and SPAs and mobile apps get
6
+ JSON endpoints. Built on [`@ghuri/oauth`](https://github.com/ghurijs/oauth); runs on Cloudflare Workers and Node.
7
+
8
+ > Status: alpha (ARCHITECTURE.md §18). Needs `@ghuri/auth` 0.1.0-alpha.2 and `@ghuri/oauth`.
9
+
10
+ ```sh
11
+ npm install @ghuri/socialauth @ghuri/oauth
12
+ ```
13
+
14
+ ## Setup
15
+
16
+ ```ts
17
+ // src/settings.ts
18
+ import { AuthConfig, ContentTypesConfig, SessionsConfig } from '@ghuri/auth'
19
+ import { SocialAuthConfig } from '@ghuri/socialauth'
20
+
21
+ INSTALLED_APPS: [ContentTypesConfig, AuthConfig, SessionsConfig, SocialAuthConfig, /* your apps */],
22
+ SOCIALACCOUNT: {
23
+ PROVIDERS: {
24
+ github: { APP: { clientId: env.GITHUB_CLIENT_ID, secret: env.GITHUB_SECRET } },
25
+ google: { APP: { clientId: env.GOOGLE_CLIENT_ID, secret: env.GOOGLE_SECRET } },
26
+ },
27
+ },
28
+ ```
29
+
30
+ ```ts
31
+ // src/urls.ts
32
+ import { authUrls } from '@ghuri/auth'
33
+ import { socialUrls } from '@ghuri/socialauth'
34
+
35
+ export const urlpatterns = [
36
+ path('accounts/', include(authUrls)),
37
+ path('accounts/', include(socialUrls)),
38
+ ]
39
+ ```
40
+
41
+ ```sh
42
+ npx ghuri migrate
43
+ ```
44
+
45
+ Register `https://<your host>/accounts/<provider>/login/callback/` as the redirect URI in each provider's console.
46
+
47
+ A login button is a POST form (CSRF-protected, so other sites can't log your visitors in to their own account):
48
+
49
+ ```html
50
+ <form method="post" action="/accounts/github/login/?next=/dashboard/">
51
+ <input type="hidden" name="csrfmiddlewaretoken" value="{csrfToken}">
52
+ <button>Continue with GitHub</button>
53
+ </form>
54
+ ```
55
+
56
+ A GET to the same URL shows a one-button confirmation page instead (or starts right away with `LOGIN_ON_GET: true`).
57
+
58
+ ## Providers
59
+
60
+ | id | Notes |
61
+ |---|---|
62
+ | `github` | Profile from `/user`; the email is the primary **verified** one from `/user/emails`. `settings.webUrl` / `apiUrl` for GitHub Enterprise. |
63
+ | `google` | OpenID Connect. |
64
+ | `facebook` | Graph API (`VERSION`, default `v21.0`). Emails are treated as unverified unless `VERIFIED_EMAIL: true`. |
65
+ | `microsoft` | Entra ID, OpenID Connect. `settings.tenant` (default `common`). Emails are never trusted by default (tenants can claim any address). |
66
+ | `discord` | `verified` flag from `/users/@me`. |
67
+ | `gitlab` | OpenID Connect; `settings.url` for self-hosted GitLab. |
68
+ | `openid_connect` | Any OIDC issuer (Auth0, Okta, Keycloak, Cognito, Zitadel…), several apps at once: |
69
+
70
+ ```ts
71
+ openid_connect: {
72
+ APPS: [
73
+ { providerId: 'okta', name: 'Okta', clientId: env.OKTA_ID, secret: env.OKTA_SECRET, settings: { serverUrl: 'https://acme.okta.com' } },
74
+ ],
75
+ },
76
+ // → /accounts/okta/login/
77
+ ```
78
+
79
+ Per provider: `SCOPE` (replaces the defaults), `AUTH_PARAMS` (extra authorization parameters), `VERIFIED_EMAIL`.
80
+ Credentials can also live in the database as `SocialApp` rows (managed in the admin); settings win.
81
+
82
+ Your own provider: subclass `Provider`, return an `OAuth2Strategy` / `OIDCStrategy` from `createStrategy()`, and call
83
+ `registerProvider(new MyProvider())`.
84
+
85
+ ## What happens on the callback
86
+
87
+ 1. **A linked account** (`SocialAccount` with this provider and uid) → its user logs in.
88
+ 2. **Connecting** (`?process=connect`, user logged in) → the account is linked to them. An account linked to someone
89
+ else is refused.
90
+ 3. **`EMAIL_AUTHENTICATION`** (off by default) and the provider says the email is **verified** and exactly one user has
91
+ it → link and log in. Unverified emails never link to existing users.
92
+ 4. **Sign up**: with `AUTO_SIGNUP` (default) the user is created from the profile (a free username, the email unless
93
+ another user has it, first/last name) with an unusable password. When something is missing or taken, the visitor
94
+ goes to `signup/` to fill it in.
95
+
96
+ Then: redirect to a safe `next` or `LOGIN_REDIRECT_URL`. Errors redirect to `LOGIN_ERROR_URL` (default `LOGIN_URL`)
97
+ with `?error=`.
98
+
99
+ ## URLs
100
+
101
+ | | |
102
+ |---|---|
103
+ | `providers/` | JSON list of configured providers with their login URLs. |
104
+ | `<provider>/login/` | POST starts the login (`?next=`, `?process=connect`). |
105
+ | `<provider>/login/callback/` | The OAuth callback. |
106
+ | `<provider>/token/` | Native apps: POST JSON `{ id_token }` (OIDC providers) or `{ access_token }` (GitHub, Facebook). The token is checked against your client id (`settings.audiences` adds iOS/Android client ids). |
107
+ | `token/` | SPAs: POST JSON `{ code }` → `{ access, refresh, user }`. |
108
+ | `signup/` | Finish a signup (HTML form or JSON). |
109
+ | `connections/` | The user's linked accounts (GET); POST `{ account }` disconnects one. The last login method of a user without a password can't be removed. |
110
+
111
+ ## SPAs and mobile apps
112
+
113
+ With `LOGIN_RESPONSE: 'jwt'` and `FRONTEND_URL`, the callback redirects to `FRONTEND_URL#code=<one-time code>`; the SPA
114
+ posts the code to `token/` for a JWT pair. Tokens never appear in URLs; codes expire after 60 seconds and are refused on
115
+ reuse while the cache remembers them. Native apps that sign in with the provider's SDK post the token to
116
+ `<provider>/token/` instead and get a session (or the JWT pair with `LOGIN_RESPONSE: 'jwt'`).
117
+
118
+ ## Adapter and signals
119
+
120
+ ```ts
121
+ import { ImmediateResponse, SocialAccountAdapter } from '@ghuri/socialauth'
122
+
123
+ class Adapter extends SocialAccountAdapter {
124
+ isOpenForSignup(c, login) {
125
+ return login.profile.email?.endsWith('@acme.com') ?? false
126
+ }
127
+ async preSocialLogin(c, login) {
128
+ if (login.provider.id === 'facebook') throw new ImmediateResponse(c.text('Not here', 403))
129
+ }
130
+ }
131
+
132
+ SOCIALACCOUNT: { ADAPTER: Adapter }
133
+ ```
134
+
135
+ Also: `isAutoSignupAllowed`, `newUser`, `populateUser`, `saveUser`, `generateUsername`, `getConnectRedirectUrl`,
136
+ `authenticationError`. Signals: `preSocialLogin`, `socialAccountAdded`, `socialAccountUpdated`, `socialAccountRemoved`.
137
+
138
+ ## Provider tokens
139
+
140
+ With `STORE_TOKENS: true`, access and refresh tokens are kept in `SocialToken`, encrypted with a key derived from
141
+ `SECRET_KEY`. `await getAccessToken(account)` returns a usable token, refreshing it when it expired.
142
+
143
+ ## Admin
144
+
145
+ ```ts
146
+ // src/admin.ts
147
+ import '@ghuri/socialauth/admin' // SocialApp, SocialAccount, SocialToken (tokens are never shown)
148
+ ```
149
+
150
+ ## Settings
151
+
152
+ ```ts
153
+ SOCIALACCOUNT: {
154
+ PROVIDERS: {},
155
+ ADAPTER: SocialAccountAdapter,
156
+ AUTO_SIGNUP: true,
157
+ EMAIL_AUTHENTICATION: false,
158
+ EMAIL_REQUIRED: false,
159
+ LOGIN_ON_GET: false,
160
+ STORE_TOKENS: false,
161
+ LOGIN_RESPONSE: 'session', // or 'jwt' (needs FRONTEND_URL)
162
+ FRONTEND_URL: undefined,
163
+ LOGIN_ERROR_URL: undefined, // default LOGIN_URL
164
+ }
165
+ ```
166
+
167
+ ## Testing
168
+
169
+ ```ts
170
+ import { socialLogin } from '@ghuri/socialauth/testing'
171
+
172
+ const res = await socialLogin(client, 'github', { id: '1', username: 'ann', email: 'ann@example.com', emailVerified: true })
173
+ // the client is now logged in (or res redirects to signup/)
174
+ ```
175
+
176
+ `socialLogin` runs the real views with a stand-in for the provider. To test a provider's own requests, use
177
+ `mockOAuthProvider` from `@ghuri/oauth/testing`.
178
+
179
+ ## For django-allauth users
180
+
181
+ | allauth | Ghuri |
182
+ |---|---|
183
+ | `INSTALLED_APPS += ['allauth.socialaccount', 'allauth.socialaccount.providers.github']` | `SocialAuthConfig` (all providers built in) |
184
+ | `SOCIALACCOUNT_PROVIDERS = {'github': {'APP': {...}}}` | `SOCIALACCOUNT: { PROVIDERS: { github: { APP: { clientId, secret } } } }` |
185
+ | `{% provider_login_url 'github' %}` | `reverse('socialaccount_login', { provider: 'github' })` |
186
+ | `SOCIALACCOUNT_AUTO_SIGNUP`, `SOCIALACCOUNT_EMAIL_AUTHENTICATION`, `SOCIALACCOUNT_LOGIN_ON_GET`, `SOCIALACCOUNT_STORE_TOKENS` | `AUTO_SIGNUP`, `EMAIL_AUTHENTICATION`, `LOGIN_ON_GET`, `STORE_TOKENS` |
187
+ | `DefaultSocialAccountAdapter` | `SocialAccountAdapter` |
188
+ | `SocialAccount`, `SocialApp`, `SocialToken` (same tables) | same |
189
+ | allauth headless `provider/token` | `<provider>/token/` |
@@ -0,0 +1,22 @@
1
+ import { ModelAdmin } from '@ghuri/admin';
2
+ import { S as SocialAccount, a as SocialApp, b as SocialToken } from './models-Cepu1xG8.js';
3
+ import '@ghuri/orm';
4
+
5
+ declare class SocialAppAdmin extends ModelAdmin<SocialApp> {
6
+ listDisplay: string[];
7
+ listFilter: string[];
8
+ searchFields: string[];
9
+ }
10
+ declare class SocialAccountAdmin extends ModelAdmin<SocialAccount> {
11
+ listDisplay: string[];
12
+ listFilter: string[];
13
+ searchFields: string[];
14
+ readonlyFields: string[];
15
+ }
16
+ declare class SocialTokenAdmin extends ModelAdmin<SocialToken> {
17
+ listDisplay: string[];
18
+ exclude: string[];
19
+ readonlyFields: string[];
20
+ }
21
+
22
+ export { SocialAccountAdmin, SocialAppAdmin, SocialTokenAdmin };
package/dist/admin.js ADDED
@@ -0,0 +1,35 @@
1
+ import {
2
+ SocialAccount,
3
+ SocialApp,
4
+ SocialToken
5
+ } from "./chunk-ZNZG4OU3.js";
6
+ import "./chunk-PZ5AY32C.js";
7
+
8
+ // src/admin.ts
9
+ import { ModelAdmin, site } from "@ghuri/admin";
10
+ var SocialAppAdmin = class extends ModelAdmin {
11
+ listDisplay = ["name", "provider", "providerId", "clientId"];
12
+ listFilter = ["provider"];
13
+ searchFields = ["name", "clientId", "providerId"];
14
+ };
15
+ var SocialAccountAdmin = class extends ModelAdmin {
16
+ listDisplay = ["user", "provider", "uid", "lastLogin", "dateJoined"];
17
+ listFilter = ["provider"];
18
+ searchFields = ["uid", "provider"];
19
+ readonlyFields = ["extraData", "lastLogin", "dateJoined"];
20
+ };
21
+ var SocialTokenAdmin = class extends ModelAdmin {
22
+ listDisplay = ["account", "app", "expiresAt"];
23
+ // Tokens are encrypted; never show or edit them in the admin.
24
+ exclude = ["token", "tokenSecret"];
25
+ readonlyFields = ["account", "app", "expiresAt"];
26
+ };
27
+ site.register(SocialApp, SocialAppAdmin);
28
+ site.register(SocialAccount, SocialAccountAdmin);
29
+ site.register(SocialToken, SocialTokenAdmin);
30
+ export {
31
+ SocialAccountAdmin,
32
+ SocialAppAdmin,
33
+ SocialTokenAdmin
34
+ };
35
+ //# sourceMappingURL=admin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/admin.ts"],"sourcesContent":["// @ghuri/socialauth/admin — import from your project's admin module to manage social apps and accounts:\n// import '@ghuri/socialauth/admin'\nimport { ModelAdmin, site } from '@ghuri/admin'\nimport { SocialAccount, SocialApp, SocialToken } from './models'\n\nexport class SocialAppAdmin extends ModelAdmin<SocialApp> {\n override listDisplay = ['name', 'provider', 'providerId', 'clientId']\n override listFilter = ['provider']\n override searchFields = ['name', 'clientId', 'providerId']\n}\n\nexport class SocialAccountAdmin extends ModelAdmin<SocialAccount> {\n override listDisplay = ['user', 'provider', 'uid', 'lastLogin', 'dateJoined']\n override listFilter = ['provider']\n override searchFields = ['uid', 'provider']\n override readonlyFields = ['extraData', 'lastLogin', 'dateJoined']\n}\n\nexport class SocialTokenAdmin extends ModelAdmin<SocialToken> {\n override listDisplay = ['account', 'app', 'expiresAt']\n // Tokens are encrypted; never show or edit them in the admin.\n override exclude = ['token', 'tokenSecret']\n override readonlyFields = ['account', 'app', 'expiresAt']\n}\n\nsite.register(SocialApp, SocialAppAdmin)\nsite.register(SocialAccount, SocialAccountAdmin)\nsite.register(SocialToken, SocialTokenAdmin)\n"],"mappings":";;;;;;;;AAEA,SAAS,YAAY,YAAY;AAG1B,IAAM,iBAAN,cAA6B,WAAsB;AAAA,EAC/C,cAAc,CAAC,QAAQ,YAAY,cAAc,UAAU;AAAA,EAC3D,aAAa,CAAC,UAAU;AAAA,EACxB,eAAe,CAAC,QAAQ,YAAY,YAAY;AAC3D;AAEO,IAAM,qBAAN,cAAiC,WAA0B;AAAA,EACvD,cAAc,CAAC,QAAQ,YAAY,OAAO,aAAa,YAAY;AAAA,EACnE,aAAa,CAAC,UAAU;AAAA,EACxB,eAAe,CAAC,OAAO,UAAU;AAAA,EACjC,iBAAiB,CAAC,aAAa,aAAa,YAAY;AACnE;AAEO,IAAM,mBAAN,cAA+B,WAAwB;AAAA,EACnD,cAAc,CAAC,WAAW,OAAO,WAAW;AAAA;AAAA,EAE5C,UAAU,CAAC,SAAS,aAAa;AAAA,EACjC,iBAAiB,CAAC,WAAW,OAAO,WAAW;AAC1D;AAEA,KAAK,SAAS,WAAW,cAAc;AACvC,KAAK,SAAS,eAAe,kBAAkB;AAC/C,KAAK,SAAS,aAAa,gBAAgB;","names":[]}
@@ -0,0 +1,10 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
6
+
7
+ export {
8
+ __export
9
+ };
10
+ //# sourceMappingURL=chunk-PZ5AY32C.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,77 @@
1
+ // src/models.ts
2
+ import { getUserModel } from "@ghuri/auth";
3
+ import {
4
+ CASCADE,
5
+ CharField,
6
+ DateTimeField,
7
+ ForeignKey,
8
+ JSONField,
9
+ Model,
10
+ TextField
11
+ } from "@ghuri/orm";
12
+ var userModel = () => getUserModel();
13
+ function emptyDict() {
14
+ return {};
15
+ }
16
+ var SocialApp = class extends Model({
17
+ provider: new CharField({ maxLength: 30, verboseName: "provider" }),
18
+ /** For providers with several apps (`openid_connect`): the id used in URLs. */
19
+ providerId: new CharField({ maxLength: 200, blank: true, verboseName: "provider ID" }),
20
+ name: new CharField({ maxLength: 40, verboseName: "name" }),
21
+ clientId: new CharField({ maxLength: 191, verboseName: "client id" }),
22
+ secret: new CharField({ maxLength: 191, blank: true, verboseName: "secret key" }),
23
+ key: new CharField({ maxLength: 191, blank: true, verboseName: "key" }),
24
+ settings: new JSONField({ default: emptyDict, blank: true, verboseName: "settings" })
25
+ }) {
26
+ static Meta = {
27
+ dbTable: "socialaccount_socialapp",
28
+ verboseName: "social application",
29
+ verboseNamePlural: "social applications"
30
+ };
31
+ toString() {
32
+ return this.name;
33
+ }
34
+ };
35
+ var SocialAccount = class extends Model({
36
+ user: new ForeignKey(userModel, { onDelete: CASCADE, relatedName: "socialAccounts", verboseName: "user" }),
37
+ /** The provider id (`github`, or the `providerId` of an OpenID Connect app). */
38
+ provider: new CharField({ maxLength: 200, verboseName: "provider" }),
39
+ uid: new CharField({ maxLength: 191, verboseName: "uid" }),
40
+ lastLogin: new DateTimeField({ autoNow: true, verboseName: "last login" }),
41
+ dateJoined: new DateTimeField({ autoNowAdd: true, verboseName: "date joined" }),
42
+ /** The provider's raw profile. */
43
+ extraData: new JSONField({ default: emptyDict, verboseName: "extra data" })
44
+ }) {
45
+ static Meta = {
46
+ dbTable: "socialaccount_socialaccount",
47
+ uniqueTogether: [["provider", "uid"]],
48
+ verboseName: "social account",
49
+ verboseNamePlural: "social accounts"
50
+ };
51
+ toString() {
52
+ return `${this.provider}:${this.uid}`;
53
+ }
54
+ };
55
+ var SocialToken = class extends Model({
56
+ app: new ForeignKey(() => SocialApp, { onDelete: CASCADE, null: true, blank: true }),
57
+ account: new ForeignKey(() => SocialAccount, { onDelete: CASCADE, relatedName: "tokens" }),
58
+ token: new TextField({ verboseName: "token" }),
59
+ /** The refresh token (allauth's name). */
60
+ tokenSecret: new TextField({ blank: true, verboseName: "token secret" }),
61
+ expiresAt: new DateTimeField({ null: true, blank: true, verboseName: "expires at" })
62
+ }) {
63
+ static Meta = {
64
+ dbTable: "socialaccount_socialtoken",
65
+ uniqueTogether: [["app", "account"]],
66
+ verboseName: "social application token",
67
+ verboseNamePlural: "social application tokens"
68
+ };
69
+ };
70
+
71
+ export {
72
+ emptyDict,
73
+ SocialApp,
74
+ SocialAccount,
75
+ SocialToken
76
+ };
77
+ //# sourceMappingURL=chunk-ZNZG4OU3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/models.ts"],"sourcesContent":["// django-allauth's socialaccount models (same table names): apps, linked accounts, provider tokens.\nimport { getUserModel } from '@ghuri/auth'\nimport {\n CASCADE,\n CharField,\n DateTimeField,\n ForeignKey,\n JSONField,\n type Manager,\n Model,\n type ModelClass,\n TextField,\n} from '@ghuri/orm'\n\nconst userModel = () => getUserModel() as unknown as ModelClass\n\n/** Default of the JSON fields (a named function, so migrations can reference it). */\nexport function emptyDict(): Record<string, unknown> {\n return {}\n}\n\n/** Provider credentials kept in the database (alternative to `SOCIALACCOUNT.PROVIDERS.<id>.APP`). */\nexport class SocialApp extends Model({\n provider: new CharField({ maxLength: 30, verboseName: 'provider' }),\n /** For providers with several apps (`openid_connect`): the id used in URLs. */\n providerId: new CharField({ maxLength: 200, blank: true, verboseName: 'provider ID' }),\n name: new CharField({ maxLength: 40, verboseName: 'name' }),\n clientId: new CharField({ maxLength: 191, verboseName: 'client id' }),\n secret: new CharField({ maxLength: 191, blank: true, verboseName: 'secret key' }),\n key: new CharField({ maxLength: 191, blank: true, verboseName: 'key' }),\n settings: new JSONField({ default: emptyDict, blank: true, verboseName: 'settings' }),\n}) {\n static Meta = {\n dbTable: 'socialaccount_socialapp',\n verboseName: 'social application',\n verboseNamePlural: 'social applications',\n }\n declare static objects: Manager<SocialApp>\n\n override toString(): string {\n return this.name\n }\n}\n\n/** A provider account linked to a user. */\nexport class SocialAccount extends Model({\n user: new ForeignKey(userModel, { onDelete: CASCADE, relatedName: 'socialAccounts', verboseName: 'user' }),\n /** The provider id (`github`, or the `providerId` of an OpenID Connect app). */\n provider: new CharField({ maxLength: 200, verboseName: 'provider' }),\n uid: new CharField({ maxLength: 191, verboseName: 'uid' }),\n lastLogin: new DateTimeField({ autoNow: true, verboseName: 'last login' }),\n dateJoined: new DateTimeField({ autoNowAdd: true, verboseName: 'date joined' }),\n /** The provider's raw profile. */\n extraData: new JSONField({ default: emptyDict, verboseName: 'extra data' }),\n}) {\n static Meta = {\n dbTable: 'socialaccount_socialaccount',\n uniqueTogether: [['provider', 'uid']],\n verboseName: 'social account',\n verboseNamePlural: 'social accounts',\n }\n declare static objects: Manager<SocialAccount>\n\n override toString(): string {\n return `${this.provider}:${this.uid}`\n }\n}\n\n/** Provider tokens (only with `STORE_TOKENS`), encrypted at rest. Read them with `getAccessToken()`. */\nexport class SocialToken extends Model({\n app: new ForeignKey(() => SocialApp, { onDelete: CASCADE, null: true, blank: true }),\n account: new ForeignKey(() => SocialAccount, { onDelete: CASCADE, relatedName: 'tokens' }),\n token: new TextField({ verboseName: 'token' }),\n /** The refresh token (allauth's name). */\n tokenSecret: new TextField({ blank: true, verboseName: 'token secret' }),\n expiresAt: new DateTimeField({ null: true, blank: true, verboseName: 'expires at' }),\n}) {\n static Meta = {\n dbTable: 'socialaccount_socialtoken',\n uniqueTogether: [['app', 'account']],\n verboseName: 'social application token',\n verboseNamePlural: 'social application tokens',\n }\n declare static objects: Manager<SocialToken>\n}\n"],"mappings":";AACA,SAAS,oBAAoB;AAC7B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EAEA;AAAA,OACK;AAEP,IAAM,YAAY,MAAM,aAAa;AAG9B,SAAS,YAAqC;AACnD,SAAO,CAAC;AACV;AAGO,IAAM,YAAN,cAAwB,MAAM;AAAA,EACnC,UAAU,IAAI,UAAU,EAAE,WAAW,IAAI,aAAa,WAAW,CAAC;AAAA;AAAA,EAElE,YAAY,IAAI,UAAU,EAAE,WAAW,KAAK,OAAO,MAAM,aAAa,cAAc,CAAC;AAAA,EACrF,MAAM,IAAI,UAAU,EAAE,WAAW,IAAI,aAAa,OAAO,CAAC;AAAA,EAC1D,UAAU,IAAI,UAAU,EAAE,WAAW,KAAK,aAAa,YAAY,CAAC;AAAA,EACpE,QAAQ,IAAI,UAAU,EAAE,WAAW,KAAK,OAAO,MAAM,aAAa,aAAa,CAAC;AAAA,EAChF,KAAK,IAAI,UAAU,EAAE,WAAW,KAAK,OAAO,MAAM,aAAa,MAAM,CAAC;AAAA,EACtE,UAAU,IAAI,UAAU,EAAE,SAAS,WAAW,OAAO,MAAM,aAAa,WAAW,CAAC;AACtF,CAAC,EAAE;AAAA,EACD,OAAO,OAAO;AAAA,IACZ,SAAS;AAAA,IACT,aAAa;AAAA,IACb,mBAAmB;AAAA,EACrB;AAAA,EAGS,WAAmB;AAC1B,WAAO,KAAK;AAAA,EACd;AACF;AAGO,IAAM,gBAAN,cAA4B,MAAM;AAAA,EACvC,MAAM,IAAI,WAAW,WAAW,EAAE,UAAU,SAAS,aAAa,kBAAkB,aAAa,OAAO,CAAC;AAAA;AAAA,EAEzG,UAAU,IAAI,UAAU,EAAE,WAAW,KAAK,aAAa,WAAW,CAAC;AAAA,EACnE,KAAK,IAAI,UAAU,EAAE,WAAW,KAAK,aAAa,MAAM,CAAC;AAAA,EACzD,WAAW,IAAI,cAAc,EAAE,SAAS,MAAM,aAAa,aAAa,CAAC;AAAA,EACzE,YAAY,IAAI,cAAc,EAAE,YAAY,MAAM,aAAa,cAAc,CAAC;AAAA;AAAA,EAE9E,WAAW,IAAI,UAAU,EAAE,SAAS,WAAW,aAAa,aAAa,CAAC;AAC5E,CAAC,EAAE;AAAA,EACD,OAAO,OAAO;AAAA,IACZ,SAAS;AAAA,IACT,gBAAgB,CAAC,CAAC,YAAY,KAAK,CAAC;AAAA,IACpC,aAAa;AAAA,IACb,mBAAmB;AAAA,EACrB;AAAA,EAGS,WAAmB;AAC1B,WAAO,GAAG,KAAK,QAAQ,IAAI,KAAK,GAAG;AAAA,EACrC;AACF;AAGO,IAAM,cAAN,cAA0B,MAAM;AAAA,EACrC,KAAK,IAAI,WAAW,MAAM,WAAW,EAAE,UAAU,SAAS,MAAM,MAAM,OAAO,KAAK,CAAC;AAAA,EACnF,SAAS,IAAI,WAAW,MAAM,eAAe,EAAE,UAAU,SAAS,aAAa,SAAS,CAAC;AAAA,EACzF,OAAO,IAAI,UAAU,EAAE,aAAa,QAAQ,CAAC;AAAA;AAAA,EAE7C,aAAa,IAAI,UAAU,EAAE,OAAO,MAAM,aAAa,eAAe,CAAC;AAAA,EACvE,WAAW,IAAI,cAAc,EAAE,MAAM,MAAM,OAAO,MAAM,aAAa,aAAa,CAAC;AACrF,CAAC,EAAE;AAAA,EACD,OAAO,OAAO;AAAA,IACZ,SAAS;AAAA,IACT,gBAAgB,CAAC,CAAC,OAAO,SAAS,CAAC;AAAA,IACnC,aAAa;AAAA,IACb,mBAAmB;AAAA,EACrB;AAEF;","names":[]}