@instantdb/core 0.22.167 → 0.22.168
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/__tests__/src/auth-extra-fields.e2e.test.ts +134 -0
- package/__tests__/src/utils/e2e.ts +23 -11
- package/dist/commonjs/Reactor.d.ts +12 -9
- package/dist/commonjs/Reactor.d.ts.map +1 -1
- package/dist/commonjs/Reactor.js +48 -11
- package/dist/commonjs/Reactor.js.map +1 -1
- package/dist/commonjs/authAPI.d.ts +19 -2
- package/dist/commonjs/authAPI.d.ts.map +1 -1
- package/dist/commonjs/authAPI.js +23 -2
- package/dist/commonjs/authAPI.js.map +1 -1
- package/dist/commonjs/index.d.ts +6 -5
- package/dist/commonjs/index.d.ts.map +1 -1
- package/dist/commonjs/index.js.map +1 -1
- package/dist/esm/Reactor.d.ts +12 -9
- package/dist/esm/Reactor.d.ts.map +1 -1
- package/dist/esm/Reactor.js +48 -11
- package/dist/esm/Reactor.js.map +1 -1
- package/dist/esm/authAPI.d.ts +19 -2
- package/dist/esm/authAPI.d.ts.map +1 -1
- package/dist/esm/authAPI.js +22 -2
- package/dist/esm/authAPI.js.map +1 -1
- package/dist/esm/index.d.ts +6 -5
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/standalone/index.js +891 -864
- package/dist/standalone/index.umd.cjs +3 -3
- package/package.json +3 -2
- package/src/Reactor.js +49 -11
- package/src/authAPI.ts +45 -2
- package/src/index.ts +11 -4
- package/vitest.config.ts +6 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@instantdb/core",
|
|
3
|
-
"version": "0.22.
|
|
3
|
+
"version": "0.22.168",
|
|
4
4
|
"description": "Instant's core local abstraction",
|
|
5
5
|
"homepage": "https://github.com/instantdb/instant/tree/main/client/packages/core",
|
|
6
6
|
"repository": {
|
|
@@ -56,13 +56,14 @@
|
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"mutative": "^1.0.10",
|
|
58
58
|
"uuid": "^11.1.0",
|
|
59
|
-
"@instantdb/version": "0.22.
|
|
59
|
+
"@instantdb/version": "0.22.168"
|
|
60
60
|
},
|
|
61
61
|
"scripts": {
|
|
62
62
|
"test": "vitest",
|
|
63
63
|
"bench": "vitest bench",
|
|
64
64
|
"test:types": "tsc -p tsconfig.test.json --noEmit",
|
|
65
65
|
"test:ci": "vitest run && pnpm run test:types",
|
|
66
|
+
"test:e2e": "vitest run --project e2e",
|
|
66
67
|
"bench:ci": "vitest bench --run",
|
|
67
68
|
"check": "tsc --noEmit",
|
|
68
69
|
"check-exports": "attw --pack .",
|
package/src/Reactor.js
CHANGED
|
@@ -63,6 +63,9 @@ const defaultConfig = {
|
|
|
63
63
|
|
|
64
64
|
// Param that the backend adds if this is an oauth redirect
|
|
65
65
|
const OAUTH_REDIRECT_PARAM = '_instant_oauth_redirect';
|
|
66
|
+
const OAUTH_EXTRA_FIELDS_ID_PARAM = '_instant_extra_fields_id';
|
|
67
|
+
|
|
68
|
+
const oauthExtraFieldsKey = 'oauthExtraFields';
|
|
66
69
|
|
|
67
70
|
const currentUserKey = `currentUser`;
|
|
68
71
|
|
|
@@ -1877,6 +1880,7 @@ export default class Reactor {
|
|
|
1877
1880
|
if (url.searchParams.get(OAUTH_REDIRECT_PARAM)) {
|
|
1878
1881
|
const startUrl = url.toString();
|
|
1879
1882
|
url.searchParams.delete(OAUTH_REDIRECT_PARAM);
|
|
1883
|
+
url.searchParams.delete(OAUTH_EXTRA_FIELDS_ID_PARAM);
|
|
1880
1884
|
url.searchParams.delete('code');
|
|
1881
1885
|
url.searchParams.delete('error');
|
|
1882
1886
|
const newPath =
|
|
@@ -1949,8 +1953,20 @@ export default class Reactor {
|
|
|
1949
1953
|
if (!code) {
|
|
1950
1954
|
return null;
|
|
1951
1955
|
}
|
|
1956
|
+
const extraFieldsId = params.get(OAUTH_EXTRA_FIELDS_ID_PARAM);
|
|
1952
1957
|
this._replaceUrlAfterOAuth();
|
|
1953
1958
|
try {
|
|
1959
|
+
let extraFields;
|
|
1960
|
+
const stored = await this.kv.waitForKeyToLoad(oauthExtraFieldsKey);
|
|
1961
|
+
if (extraFieldsId && stored) {
|
|
1962
|
+
extraFields = stored[extraFieldsId];
|
|
1963
|
+
}
|
|
1964
|
+
// Clean up all stored extraFields after login
|
|
1965
|
+
if (stored) {
|
|
1966
|
+
this.kv.updateInPlace((prev) => {
|
|
1967
|
+
delete prev[oauthExtraFieldsKey];
|
|
1968
|
+
});
|
|
1969
|
+
}
|
|
1954
1970
|
const currentUser = await this._getCurrentUser();
|
|
1955
1971
|
const isGuest = currentUser?.type === 'guest';
|
|
1956
1972
|
const { user } = await authAPI.exchangeCodeForToken({
|
|
@@ -1958,6 +1974,7 @@ export default class Reactor {
|
|
|
1958
1974
|
appId: this.config.appId,
|
|
1959
1975
|
code,
|
|
1960
1976
|
refreshToken: isGuest ? currentUser.refresh_token : undefined,
|
|
1977
|
+
extraFields,
|
|
1961
1978
|
});
|
|
1962
1979
|
this.setCurrentUser(user);
|
|
1963
1980
|
return null;
|
|
@@ -2199,15 +2216,16 @@ export default class Reactor {
|
|
|
2199
2216
|
});
|
|
2200
2217
|
}
|
|
2201
2218
|
|
|
2202
|
-
async signInWithMagicCode(
|
|
2219
|
+
async signInWithMagicCode(params) {
|
|
2203
2220
|
const currentUser = await this.getCurrentUser();
|
|
2204
2221
|
const isGuest = currentUser?.user?.type === 'guest';
|
|
2205
|
-
const res = await authAPI.
|
|
2222
|
+
const res = await authAPI.checkMagicCode({
|
|
2206
2223
|
apiURI: this.config.apiURI,
|
|
2207
2224
|
appId: this.config.appId,
|
|
2208
|
-
email,
|
|
2209
|
-
code,
|
|
2225
|
+
email: params.email,
|
|
2226
|
+
code: params.code,
|
|
2210
2227
|
refreshToken: isGuest ? currentUser?.user?.refresh_token : undefined,
|
|
2228
|
+
extraFields: params.extraFields,
|
|
2211
2229
|
});
|
|
2212
2230
|
await this.changeCurrentUser(res.user);
|
|
2213
2231
|
return res;
|
|
@@ -2266,19 +2284,36 @@ export default class Reactor {
|
|
|
2266
2284
|
* @param {Object} params - The parameters to create the authorization URL.
|
|
2267
2285
|
* @param {string} params.clientName - The name of the client requesting authorization.
|
|
2268
2286
|
* @param {string} params.redirectURL - The URL to redirect users to after authorization.
|
|
2287
|
+
* @param {Record<string, any>} [params.extraFields] - Extra fields to write to $users on creation
|
|
2269
2288
|
* @returns {string} The created authorization URL.
|
|
2270
2289
|
*/
|
|
2271
|
-
createAuthorizationURL({ clientName, redirectURL }) {
|
|
2290
|
+
createAuthorizationURL({ clientName, redirectURL, extraFields }) {
|
|
2272
2291
|
const { apiURI, appId } = this.config;
|
|
2273
|
-
|
|
2292
|
+
let finalRedirectURL = redirectURL;
|
|
2293
|
+
if (extraFields) {
|
|
2294
|
+
// Store extraFields under a unique ID so multiple
|
|
2295
|
+
// createAuthorizationURL calls don't overwrite each other.
|
|
2296
|
+
// The ID is passed through the redirect URL and used
|
|
2297
|
+
// by _oauthLoginInit to retrieve the right extraFields.
|
|
2298
|
+
// All entries are cleaned up after login.
|
|
2299
|
+
const extraFieldsId = `${Math.random().toString(36).slice(2)}`;
|
|
2300
|
+
this.kv.updateInPlace((prev) => {
|
|
2301
|
+
const stored = prev[oauthExtraFieldsKey] || {};
|
|
2302
|
+
stored[extraFieldsId] = extraFields;
|
|
2303
|
+
prev[oauthExtraFieldsKey] = stored;
|
|
2304
|
+
});
|
|
2305
|
+
finalRedirectURL = `${redirectURL}${redirectURL.includes('?') ? '&' : '?'}${OAUTH_EXTRA_FIELDS_ID_PARAM}=${extraFieldsId}`;
|
|
2306
|
+
}
|
|
2307
|
+
return `${apiURI}/runtime/oauth/start?app_id=${appId}&client_name=${clientName}&redirect_uri=${encodeURIComponent(finalRedirectURL)}`;
|
|
2274
2308
|
}
|
|
2275
2309
|
|
|
2276
2310
|
/**
|
|
2277
2311
|
* @param {Object} params
|
|
2278
2312
|
* @param {string} params.code - The code received from the OAuth service.
|
|
2279
2313
|
* @param {string} [params.codeVerifier] - The code verifier used to generate the code challenge.
|
|
2314
|
+
* @param {Record<string, any>} [params.extraFields] - Extra fields to write to $users on creation
|
|
2280
2315
|
*/
|
|
2281
|
-
async exchangeCodeForToken({ code, codeVerifier }) {
|
|
2316
|
+
async exchangeCodeForToken({ code, codeVerifier, extraFields }) {
|
|
2282
2317
|
const currentUser = await this.getCurrentUser();
|
|
2283
2318
|
const isGuest = currentUser?.user?.type === 'guest';
|
|
2284
2319
|
const res = await authAPI.exchangeCodeForToken({
|
|
@@ -2287,6 +2322,7 @@ export default class Reactor {
|
|
|
2287
2322
|
code: code,
|
|
2288
2323
|
codeVerifier,
|
|
2289
2324
|
refreshToken: isGuest ? currentUser?.user?.refresh_token : undefined,
|
|
2325
|
+
extraFields,
|
|
2290
2326
|
});
|
|
2291
2327
|
await this.changeCurrentUser(res.user);
|
|
2292
2328
|
return res;
|
|
@@ -2302,18 +2338,20 @@ export default class Reactor {
|
|
|
2302
2338
|
* @param {string} params.clientName - The name of the client requesting authorization.
|
|
2303
2339
|
* @param {string} params.idToken - The id_token from the external service
|
|
2304
2340
|
* @param {string | null | undefined} [params.nonce] - The nonce used when requesting the id_token from the external service
|
|
2341
|
+
* @param {Record<string, any>} [params.extraFields] - Extra fields to write to $users on creation
|
|
2305
2342
|
*/
|
|
2306
|
-
async signInWithIdToken(
|
|
2343
|
+
async signInWithIdToken(params) {
|
|
2307
2344
|
const currentUser = await this.getCurrentUser();
|
|
2308
2345
|
const refreshToken = currentUser?.user?.refresh_token;
|
|
2309
2346
|
|
|
2310
2347
|
const res = await authAPI.signInWithIdToken({
|
|
2311
2348
|
apiURI: this.config.apiURI,
|
|
2312
2349
|
appId: this.config.appId,
|
|
2313
|
-
idToken,
|
|
2314
|
-
clientName,
|
|
2315
|
-
nonce,
|
|
2350
|
+
idToken: params.idToken,
|
|
2351
|
+
clientName: params.clientName,
|
|
2352
|
+
nonce: params.nonce,
|
|
2316
2353
|
refreshToken,
|
|
2354
|
+
extraFields: params.extraFields,
|
|
2317
2355
|
});
|
|
2318
2356
|
await this.changeCurrentUser(res.user);
|
|
2319
2357
|
return res;
|
package/src/authAPI.ts
CHANGED
|
@@ -31,6 +31,11 @@ export type VerifyMagicCodeParams = {
|
|
|
31
31
|
export type VerifyResponse = {
|
|
32
32
|
user: User;
|
|
33
33
|
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @deprecated Use {@link checkMagicCode} instead to get the `created` field
|
|
37
|
+
* and support `extraFields`.
|
|
38
|
+
*/
|
|
34
39
|
export async function verifyMagicCode({
|
|
35
40
|
apiURI,
|
|
36
41
|
appId,
|
|
@@ -51,6 +56,38 @@ export async function verifyMagicCode({
|
|
|
51
56
|
return res;
|
|
52
57
|
}
|
|
53
58
|
|
|
59
|
+
export type CheckMagicCodeParams = {
|
|
60
|
+
email: string;
|
|
61
|
+
code: string;
|
|
62
|
+
refreshToken?: string | undefined;
|
|
63
|
+
extraFields?: Record<string, any> | undefined;
|
|
64
|
+
};
|
|
65
|
+
export type CheckMagicCodeResponse = {
|
|
66
|
+
user: User;
|
|
67
|
+
created: boolean;
|
|
68
|
+
};
|
|
69
|
+
export async function checkMagicCode({
|
|
70
|
+
apiURI,
|
|
71
|
+
appId,
|
|
72
|
+
email,
|
|
73
|
+
code,
|
|
74
|
+
refreshToken,
|
|
75
|
+
extraFields,
|
|
76
|
+
}: SharedInput & CheckMagicCodeParams): Promise<CheckMagicCodeResponse> {
|
|
77
|
+
const res = await jsonFetch(`${apiURI}/runtime/auth/verify_magic_code`, {
|
|
78
|
+
method: 'POST',
|
|
79
|
+
headers: { 'content-type': 'application/json' },
|
|
80
|
+
body: JSON.stringify({
|
|
81
|
+
'app-id': appId,
|
|
82
|
+
email,
|
|
83
|
+
code,
|
|
84
|
+
...(refreshToken ? { 'refresh-token': refreshToken } : {}),
|
|
85
|
+
...(extraFields ? { 'extra-fields': extraFields } : {}),
|
|
86
|
+
}),
|
|
87
|
+
});
|
|
88
|
+
return res;
|
|
89
|
+
}
|
|
90
|
+
|
|
54
91
|
export type VerifyRefreshTokenParams = { refreshToken: string };
|
|
55
92
|
export async function verifyRefreshToken({
|
|
56
93
|
apiURI,
|
|
@@ -86,6 +123,7 @@ export type ExchangeCodeForTokenParams = {
|
|
|
86
123
|
code: string;
|
|
87
124
|
codeVerifier?: string;
|
|
88
125
|
refreshToken?: string | undefined;
|
|
126
|
+
extraFields?: Record<string, any> | undefined;
|
|
89
127
|
};
|
|
90
128
|
|
|
91
129
|
export async function exchangeCodeForToken({
|
|
@@ -94,7 +132,8 @@ export async function exchangeCodeForToken({
|
|
|
94
132
|
code,
|
|
95
133
|
codeVerifier,
|
|
96
134
|
refreshToken,
|
|
97
|
-
|
|
135
|
+
extraFields,
|
|
136
|
+
}: SharedInput & ExchangeCodeForTokenParams): Promise<CheckMagicCodeResponse> {
|
|
98
137
|
const res = await jsonFetch(`${apiURI}/runtime/oauth/token`, {
|
|
99
138
|
method: 'POST',
|
|
100
139
|
headers: { 'content-type': 'application/json' },
|
|
@@ -103,6 +142,7 @@ export async function exchangeCodeForToken({
|
|
|
103
142
|
code: code,
|
|
104
143
|
code_verifier: codeVerifier,
|
|
105
144
|
refresh_token: refreshToken,
|
|
145
|
+
...(extraFields ? { extra_fields: extraFields } : {}),
|
|
106
146
|
}),
|
|
107
147
|
});
|
|
108
148
|
return res;
|
|
@@ -113,6 +153,7 @@ export type SignInWithIdTokenParams = {
|
|
|
113
153
|
idToken: string;
|
|
114
154
|
clientName: string;
|
|
115
155
|
refreshToken?: string;
|
|
156
|
+
extraFields?: Record<string, any> | undefined;
|
|
116
157
|
};
|
|
117
158
|
|
|
118
159
|
export async function signInWithIdToken({
|
|
@@ -122,7 +163,8 @@ export async function signInWithIdToken({
|
|
|
122
163
|
idToken,
|
|
123
164
|
clientName,
|
|
124
165
|
refreshToken,
|
|
125
|
-
|
|
166
|
+
extraFields,
|
|
167
|
+
}: SharedInput & SignInWithIdTokenParams): Promise<CheckMagicCodeResponse> {
|
|
126
168
|
const res = await jsonFetch(`${apiURI}/runtime/oauth/id_token`, {
|
|
127
169
|
method: 'POST',
|
|
128
170
|
headers: { 'content-type': 'application/json' },
|
|
@@ -132,6 +174,7 @@ export async function signInWithIdToken({
|
|
|
132
174
|
id_token: idToken,
|
|
133
175
|
client_name: clientName,
|
|
134
176
|
refresh_token: refreshToken,
|
|
177
|
+
...(extraFields ? { extra_fields: extraFields } : {}),
|
|
135
178
|
}),
|
|
136
179
|
});
|
|
137
180
|
return res;
|
package/src/index.ts
CHANGED
|
@@ -114,6 +114,8 @@ import type { UploadFileResponse, DeleteFileResponse } from './StorageAPI.ts';
|
|
|
114
114
|
import { FrameworkClient, type FrameworkConfig } from './framework.ts';
|
|
115
115
|
|
|
116
116
|
import type {
|
|
117
|
+
CheckMagicCodeParams,
|
|
118
|
+
CheckMagicCodeResponse,
|
|
117
119
|
ExchangeCodeForTokenParams,
|
|
118
120
|
SendMagicCodeParams,
|
|
119
121
|
SendMagicCodeResponse,
|
|
@@ -347,8 +349,8 @@ class Auth {
|
|
|
347
349
|
* .catch((err) => console.error(err.body?.message))
|
|
348
350
|
*/
|
|
349
351
|
signInWithMagicCode = (
|
|
350
|
-
params:
|
|
351
|
-
): Promise<
|
|
352
|
+
params: CheckMagicCodeParams,
|
|
353
|
+
): Promise<CheckMagicCodeResponse> => {
|
|
352
354
|
return this.db.signInWithMagicCode(params);
|
|
353
355
|
};
|
|
354
356
|
|
|
@@ -397,6 +399,7 @@ class Auth {
|
|
|
397
399
|
createAuthorizationURL = (params: {
|
|
398
400
|
clientName: string;
|
|
399
401
|
redirectURL: string;
|
|
402
|
+
extraFields?: Record<string, any>;
|
|
400
403
|
}): string => {
|
|
401
404
|
return this.db.createAuthorizationURL(params);
|
|
402
405
|
};
|
|
@@ -421,7 +424,7 @@ class Auth {
|
|
|
421
424
|
*/
|
|
422
425
|
signInWithIdToken = (
|
|
423
426
|
params: SignInWithIdTokenParams,
|
|
424
|
-
): Promise<
|
|
427
|
+
): Promise<CheckMagicCodeResponse> => {
|
|
425
428
|
return this.db.signInWithIdToken(params);
|
|
426
429
|
};
|
|
427
430
|
|
|
@@ -441,7 +444,9 @@ class Auth {
|
|
|
441
444
|
* .catch((err) => console.error(err.body?.message));
|
|
442
445
|
*
|
|
443
446
|
*/
|
|
444
|
-
exchangeOAuthCode = (
|
|
447
|
+
exchangeOAuthCode = (
|
|
448
|
+
params: ExchangeCodeForTokenParams,
|
|
449
|
+
): Promise<CheckMagicCodeResponse> => {
|
|
445
450
|
return this.db.exchangeCodeForToken(params);
|
|
446
451
|
};
|
|
447
452
|
|
|
@@ -1155,6 +1160,8 @@ export {
|
|
|
1155
1160
|
type InstantDBInferredType,
|
|
1156
1161
|
|
|
1157
1162
|
// auth types
|
|
1163
|
+
type CheckMagicCodeParams,
|
|
1164
|
+
type CheckMagicCodeResponse,
|
|
1158
1165
|
type ExchangeCodeForTokenParams,
|
|
1159
1166
|
type SendMagicCodeParams,
|
|
1160
1167
|
type SendMagicCodeResponse,
|
package/vitest.config.ts
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import { playwright } from '@vitest/browser-playwright';
|
|
2
2
|
import { defineConfig } from 'vitest/config';
|
|
3
3
|
|
|
4
|
+
const devSlot = Number(process.env.DEV_SLOT ?? 0);
|
|
5
|
+
const localPort = process.env.CI ? 0 : 8888 + devSlot * 1000;
|
|
6
|
+
|
|
4
7
|
export default defineConfig({
|
|
5
8
|
test: {
|
|
6
9
|
projects: [
|
|
7
10
|
{
|
|
8
11
|
extends: true,
|
|
12
|
+
define: {
|
|
13
|
+
__DEV_LOCAL_PORT__: localPort,
|
|
14
|
+
},
|
|
9
15
|
test: {
|
|
10
16
|
name: 'e2e',
|
|
11
17
|
include: ['**/**.e2e.test.ts'],
|