better-auth-studio 1.0.61-beta.1 → 1.0.61-beta.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/dist/routes.js CHANGED
@@ -1809,597 +1809,7 @@ export function createRoutes(authConfig, configPath, geoDbPath) {
1809
1809
  }
1810
1810
  });
1811
1811
  // Database Schema Visualization endpoint
1812
- // Schema definitions for different Better Auth plugins
1813
- const BASE_SCHEMA = {
1814
- user: {
1815
- name: 'user',
1816
- displayName: 'User',
1817
- fields: [
1818
- {
1819
- name: 'id',
1820
- type: 'string',
1821
- required: true,
1822
- primaryKey: true,
1823
- description: 'Unique user identifier',
1824
- },
1825
- { name: 'name', type: 'string', required: true, description: 'User display name' },
1826
- {
1827
- name: 'email',
1828
- type: 'string',
1829
- required: true,
1830
- unique: true,
1831
- description: 'User email address',
1832
- },
1833
- {
1834
- name: 'emailVerified',
1835
- type: 'boolean',
1836
- required: true,
1837
- defaultValue: false,
1838
- description: 'Email verification status',
1839
- },
1840
- { name: 'image', type: 'string', required: false, description: 'User profile image URL' },
1841
- {
1842
- name: 'createdAt',
1843
- type: 'date',
1844
- required: true,
1845
- description: 'Account creation timestamp',
1846
- },
1847
- { name: 'updatedAt', type: 'date', required: true, description: 'Last update timestamp' },
1848
- ],
1849
- relationships: [
1850
- { type: 'one-to-many', target: 'session', field: 'userId' },
1851
- { type: 'one-to-many', target: 'account', field: 'userId' },
1852
- ],
1853
- },
1854
- session: {
1855
- name: 'session',
1856
- displayName: 'Session',
1857
- fields: [
1858
- {
1859
- name: 'id',
1860
- type: 'string',
1861
- required: true,
1862
- primaryKey: true,
1863
- description: 'Unique session identifier',
1864
- },
1865
- {
1866
- name: 'expiresAt',
1867
- type: 'date',
1868
- required: true,
1869
- description: 'Session expiration timestamp',
1870
- },
1871
- {
1872
- name: 'token',
1873
- type: 'string',
1874
- required: true,
1875
- unique: true,
1876
- description: 'Session token',
1877
- },
1878
- {
1879
- name: 'createdAt',
1880
- type: 'date',
1881
- required: true,
1882
- description: 'Session creation timestamp',
1883
- },
1884
- { name: 'updatedAt', type: 'date', required: true, description: 'Last update timestamp' },
1885
- { name: 'ipAddress', type: 'string', required: false, description: 'Client IP address' },
1886
- { name: 'userAgent', type: 'string', required: false, description: 'Client user agent' },
1887
- { name: 'userId', type: 'string', required: true, description: 'Associated user ID' },
1888
- ],
1889
- relationships: [{ type: 'many-to-one', target: 'user', field: 'userId' }],
1890
- },
1891
- account: {
1892
- name: 'account',
1893
- displayName: 'Account',
1894
- fields: [
1895
- {
1896
- name: 'id',
1897
- type: 'string',
1898
- required: true,
1899
- primaryKey: true,
1900
- description: 'Unique account identifier',
1901
- },
1902
- { name: 'accountId', type: 'string', required: true, description: 'Provider account ID' },
1903
- {
1904
- name: 'providerId',
1905
- type: 'string',
1906
- required: true,
1907
- description: 'Authentication provider',
1908
- },
1909
- { name: 'userId', type: 'string', required: true, description: 'Associated user ID' },
1910
- { name: 'accessToken', type: 'string', required: false, description: 'OAuth access token' },
1911
- {
1912
- name: 'refreshToken',
1913
- type: 'string',
1914
- required: false,
1915
- description: 'OAuth refresh token',
1916
- },
1917
- { name: 'idToken', type: 'string', required: false, description: 'OAuth ID token' },
1918
- {
1919
- name: 'accessTokenExpiresAt',
1920
- type: 'date',
1921
- required: false,
1922
- description: 'Access token expiration',
1923
- },
1924
- {
1925
- name: 'refreshTokenExpiresAt',
1926
- type: 'date',
1927
- required: false,
1928
- description: 'Refresh token expiration',
1929
- },
1930
- { name: 'scope', type: 'string', required: false, description: 'OAuth scope' },
1931
- {
1932
- name: 'password',
1933
- type: 'string',
1934
- required: false,
1935
- description: 'Hashed password (if applicable)',
1936
- },
1937
- {
1938
- name: 'createdAt',
1939
- type: 'date',
1940
- required: true,
1941
- description: 'Account creation timestamp',
1942
- },
1943
- { name: 'updatedAt', type: 'date', required: true, description: 'Last update timestamp' },
1944
- ],
1945
- relationships: [{ type: 'many-to-one', target: 'user', field: 'userId' }],
1946
- },
1947
- verification: {
1948
- name: 'verification',
1949
- displayName: 'Verification',
1950
- fields: [
1951
- {
1952
- name: 'id',
1953
- type: 'string',
1954
- required: true,
1955
- primaryKey: true,
1956
- description: 'Unique verification identifier',
1957
- },
1958
- {
1959
- name: 'identifier',
1960
- type: 'string',
1961
- required: true,
1962
- description: 'Email or phone being verified',
1963
- },
1964
- {
1965
- name: 'value',
1966
- type: 'string',
1967
- required: true,
1968
- description: 'Verification code or token',
1969
- },
1970
- {
1971
- name: 'expiresAt',
1972
- type: 'date',
1973
- required: true,
1974
- description: 'Verification expiration timestamp',
1975
- },
1976
- {
1977
- name: 'createdAt',
1978
- type: 'date',
1979
- required: true,
1980
- description: 'Verification creation timestamp',
1981
- },
1982
- { name: 'updatedAt', type: 'date', required: true, description: 'Last update timestamp' },
1983
- ],
1984
- relationships: [],
1985
- },
1986
- };
1987
- // Plugin schemas that extend the base schema
1988
- const PLUGIN_SCHEMAS = {
1989
- organization: {
1990
- tables: {
1991
- organization: {
1992
- name: 'organization',
1993
- displayName: 'Organization',
1994
- fields: [
1995
- {
1996
- name: 'id',
1997
- type: 'string',
1998
- required: true,
1999
- primaryKey: true,
2000
- description: 'Unique organization identifier',
2001
- },
2002
- { name: 'name', type: 'string', required: true, description: 'Organization name' },
2003
- {
2004
- name: 'slug',
2005
- type: 'string',
2006
- required: false,
2007
- unique: true,
2008
- description: 'Organization URL slug',
2009
- },
2010
- { name: 'logo', type: 'string', required: false, description: 'Organization logo URL' },
2011
- {
2012
- name: 'createdAt',
2013
- type: 'date',
2014
- required: true,
2015
- description: 'Organization creation timestamp',
2016
- },
2017
- {
2018
- name: 'metadata',
2019
- type: 'json',
2020
- required: false,
2021
- description: 'Additional organization metadata',
2022
- },
2023
- ],
2024
- relationships: [
2025
- { type: 'one-to-many', target: 'member', field: 'organizationId' },
2026
- { type: 'one-to-many', target: 'invitation', field: 'organizationId' },
2027
- ],
2028
- },
2029
- member: {
2030
- name: 'member',
2031
- displayName: 'Member',
2032
- fields: [
2033
- {
2034
- name: 'id',
2035
- type: 'string',
2036
- required: true,
2037
- primaryKey: true,
2038
- description: 'Unique member identifier',
2039
- },
2040
- {
2041
- name: 'organizationId',
2042
- type: 'string',
2043
- required: true,
2044
- description: 'Organization ID',
2045
- },
2046
- { name: 'userId', type: 'string', required: true, description: 'User ID' },
2047
- {
2048
- name: 'role',
2049
- type: 'string',
2050
- required: true,
2051
- defaultValue: 'member',
2052
- description: 'Member role in organization',
2053
- },
2054
- {
2055
- name: 'createdAt',
2056
- type: 'date',
2057
- required: true,
2058
- description: 'Membership creation timestamp',
2059
- },
2060
- ],
2061
- relationships: [
2062
- { type: 'many-to-one', target: 'organization', field: 'organizationId' },
2063
- { type: 'many-to-one', target: 'user', field: 'userId' },
2064
- ],
2065
- },
2066
- invitation: {
2067
- name: 'invitation',
2068
- displayName: 'Invitation',
2069
- fields: [
2070
- {
2071
- name: 'id',
2072
- type: 'string',
2073
- required: true,
2074
- primaryKey: true,
2075
- description: 'Unique invitation identifier',
2076
- },
2077
- {
2078
- name: 'organizationId',
2079
- type: 'string',
2080
- required: true,
2081
- description: 'Organization ID',
2082
- },
2083
- { name: 'email', type: 'string', required: true, description: 'Invited email address' },
2084
- { name: 'role', type: 'string', required: false, description: 'Invited role' },
2085
- {
2086
- name: 'status',
2087
- type: 'string',
2088
- required: true,
2089
- defaultValue: 'pending',
2090
- description: 'Invitation status',
2091
- },
2092
- {
2093
- name: 'expiresAt',
2094
- type: 'date',
2095
- required: true,
2096
- description: 'Invitation expiration timestamp',
2097
- },
2098
- {
2099
- name: 'inviterId',
2100
- type: 'string',
2101
- required: true,
2102
- description: 'User who sent the invitation',
2103
- },
2104
- ],
2105
- relationships: [
2106
- { type: 'many-to-one', target: 'organization', field: 'organizationId' },
2107
- { type: 'many-to-one', target: 'user', field: 'inviterId' },
2108
- ],
2109
- },
2110
- },
2111
- userExtensions: {
2112
- fields: [],
2113
- relationships: [
2114
- { type: 'one-to-many', target: 'member', field: 'userId' },
2115
- { type: 'one-to-many', target: 'invitation', field: 'inviterId' },
2116
- ],
2117
- },
2118
- sessionExtensions: {
2119
- fields: [
2120
- {
2121
- name: 'activeOrganizationId',
2122
- type: 'string',
2123
- required: false,
2124
- description: 'Active organization ID',
2125
- },
2126
- ],
2127
- relationships: [],
2128
- },
2129
- },
2130
- teams: {
2131
- tables: {
2132
- team: {
2133
- name: 'team',
2134
- displayName: 'Team',
2135
- fields: [
2136
- {
2137
- name: 'id',
2138
- type: 'string',
2139
- required: true,
2140
- primaryKey: true,
2141
- description: 'Unique team identifier',
2142
- },
2143
- { name: 'name', type: 'string', required: true, description: 'Team name' },
2144
- {
2145
- name: 'organizationId',
2146
- type: 'string',
2147
- required: true,
2148
- description: 'Organization ID',
2149
- },
2150
- {
2151
- name: 'createdAt',
2152
- type: 'date',
2153
- required: true,
2154
- description: 'Team creation timestamp',
2155
- },
2156
- {
2157
- name: 'updatedAt',
2158
- type: 'date',
2159
- required: false,
2160
- description: 'Last update timestamp',
2161
- },
2162
- ],
2163
- relationships: [
2164
- { type: 'many-to-one', target: 'organization', field: 'organizationId' },
2165
- { type: 'one-to-many', target: 'teamMember', field: 'teamId' },
2166
- ],
2167
- },
2168
- teamMember: {
2169
- name: 'teamMember',
2170
- displayName: 'Team Member',
2171
- fields: [
2172
- {
2173
- name: 'id',
2174
- type: 'string',
2175
- required: true,
2176
- primaryKey: true,
2177
- description: 'Unique team member identifier',
2178
- },
2179
- { name: 'teamId', type: 'string', required: true, description: 'Team ID' },
2180
- { name: 'userId', type: 'string', required: true, description: 'User ID' },
2181
- {
2182
- name: 'createdAt',
2183
- type: 'date',
2184
- required: false,
2185
- description: 'Team membership creation timestamp',
2186
- },
2187
- ],
2188
- relationships: [
2189
- { type: 'many-to-one', target: 'team', field: 'teamId' },
2190
- { type: 'many-to-one', target: 'user', field: 'userId' },
2191
- ],
2192
- },
2193
- },
2194
- organizationExtensions: {
2195
- relationships: [{ type: 'one-to-many', target: 'team', field: 'organizationId' }],
2196
- },
2197
- sessionExtensions: {
2198
- fields: [
2199
- { name: 'activeTeamId', type: 'string', required: false, description: 'Active team ID' },
2200
- ],
2201
- relationships: [],
2202
- },
2203
- },
2204
- twoFactor: {
2205
- tables: {
2206
- twoFactor: {
2207
- name: 'twoFactor',
2208
- displayName: 'Two Factor',
2209
- fields: [
2210
- {
2211
- name: 'id',
2212
- type: 'string',
2213
- required: true,
2214
- primaryKey: true,
2215
- description: 'Unique two-factor authentication identifier',
2216
- },
2217
- { name: 'userId', type: 'string', required: true, description: 'Associated user ID' },
2218
- {
2219
- name: 'secret',
2220
- type: 'string',
2221
- required: true,
2222
- description: 'Two-factor authentication secret',
2223
- },
2224
- {
2225
- name: 'backupCodes',
2226
- type: 'string',
2227
- required: true,
2228
- description: 'Backup codes for two-factor authentication',
2229
- },
2230
- ],
2231
- relationships: [{ type: 'many-to-one', target: 'user', field: 'userId' }],
2232
- },
2233
- },
2234
- userExtensions: {
2235
- fields: [
2236
- {
2237
- name: 'twoFactorEnabled',
2238
- type: 'boolean',
2239
- required: false,
2240
- description: 'Two-factor authentication enabled status',
2241
- },
2242
- ],
2243
- relationships: [{ type: 'one-to-one', target: 'twoFactor', field: 'userId' }],
2244
- },
2245
- },
2246
- apiKey: {
2247
- tables: {
2248
- apiKey: {
2249
- name: 'apiKey',
2250
- displayName: 'API Key',
2251
- fields: [
2252
- {
2253
- name: 'id',
2254
- type: 'string',
2255
- required: true,
2256
- primaryKey: true,
2257
- description: 'Unique API key identifier',
2258
- },
2259
- { name: 'userId', type: 'string', required: true, description: 'Associated user ID' },
2260
- { name: 'name', type: 'string', required: true, description: 'API key name' },
2261
- {
2262
- name: 'key',
2263
- type: 'string',
2264
- required: true,
2265
- unique: true,
2266
- description: 'API key value',
2267
- },
2268
- {
2269
- name: 'expiresAt',
2270
- type: 'date',
2271
- required: false,
2272
- description: 'API key expiration timestamp',
2273
- },
2274
- {
2275
- name: 'lastUsedAt',
2276
- type: 'date',
2277
- required: false,
2278
- description: 'Last usage timestamp',
2279
- },
2280
- {
2281
- name: 'createdAt',
2282
- type: 'date',
2283
- required: true,
2284
- description: 'API key creation timestamp',
2285
- },
2286
- ],
2287
- relationships: [{ type: 'many-to-one', target: 'user', field: 'userId' }],
2288
- },
2289
- },
2290
- userExtensions: {
2291
- relationships: [{ type: 'one-to-many', target: 'apiKey', field: 'userId' }],
2292
- },
2293
- },
2294
- passkey: {
2295
- tables: {
2296
- passkey: {
2297
- name: 'passkey',
2298
- displayName: 'Passkey',
2299
- fields: [
2300
- {
2301
- name: 'id',
2302
- type: 'string',
2303
- required: true,
2304
- primaryKey: true,
2305
- description: 'Unique passkey identifier',
2306
- },
2307
- { name: 'userId', type: 'string', required: true, description: 'Associated user ID' },
2308
- { name: 'name', type: 'string', required: true, description: 'Passkey name' },
2309
- {
2310
- name: 'credentialId',
2311
- type: 'string',
2312
- required: true,
2313
- unique: true,
2314
- description: 'WebAuthn credential ID',
2315
- },
2316
- { name: 'publicKey', type: 'string', required: true, description: 'Public key' },
2317
- { name: 'counter', type: 'number', required: true, description: 'Usage counter' },
2318
- {
2319
- name: 'createdAt',
2320
- type: 'date',
2321
- required: true,
2322
- description: 'Passkey creation timestamp',
2323
- },
2324
- {
2325
- name: 'lastUsedAt',
2326
- type: 'date',
2327
- required: false,
2328
- description: 'Last usage timestamp',
2329
- },
2330
- ],
2331
- relationships: [{ type: 'many-to-one', target: 'user', field: 'userId' }],
2332
- },
2333
- },
2334
- userExtensions: {
2335
- relationships: [{ type: 'one-to-many', target: 'passkey', field: 'userId' }],
2336
- },
2337
- },
2338
- };
2339
- function generateStaticSchema(selectedPlugins) {
2340
- const schema = { tables: [] };
2341
- const baseTables = Object.values(BASE_SCHEMA).map((table) => ({
2342
- ...table,
2343
- fields: [...table.fields],
2344
- relationships: [...table.relationships],
2345
- }));
2346
- schema.tables.push(...baseTables);
2347
- selectedPlugins.forEach((pluginName) => {
2348
- const plugin = PLUGIN_SCHEMAS[pluginName];
2349
- if (!plugin)
2350
- return;
2351
- if (plugin.tables) {
2352
- Object.values(plugin.tables).forEach((table) => {
2353
- schema.tables.push({
2354
- ...table,
2355
- fields: [...table.fields],
2356
- relationships: [...table.relationships],
2357
- });
2358
- });
2359
- }
2360
- if ('userExtensions' in plugin && plugin.userExtensions) {
2361
- const userTable = schema.tables.find((t) => t.name === 'user');
2362
- if (userTable && 'fields' in plugin.userExtensions) {
2363
- (plugin.userExtensions.fields || []).forEach((field) => {
2364
- if (!userTable.fields.some((f) => f.name === field.name)) {
2365
- userTable.fields.push(field);
2366
- }
2367
- });
2368
- (plugin.userExtensions.relationships || []).forEach((rel) => {
2369
- if (!userTable.relationships.some((r) => r.target === rel.target && r.field === rel.field && r.type === rel.type)) {
2370
- userTable.relationships.push(rel);
2371
- }
2372
- });
2373
- }
2374
- }
2375
- if ('sessionExtensions' in plugin && plugin.sessionExtensions) {
2376
- const sessionTable = schema.tables.find((t) => t.name === 'session');
2377
- if (sessionTable && 'fields' in plugin.sessionExtensions) {
2378
- (plugin.sessionExtensions.fields || []).forEach((field) => {
2379
- if (!sessionTable.fields.some((f) => f.name === field.name)) {
2380
- sessionTable.fields.push(field);
2381
- }
2382
- });
2383
- (plugin.sessionExtensions.relationships || []).forEach((rel) => {
2384
- if (!sessionTable.relationships.some((r) => r.target === rel.target && r.field === rel.field && r.type === rel.type)) {
2385
- sessionTable.relationships.push(rel);
2386
- }
2387
- });
2388
- }
2389
- }
2390
- if ('organizationExtensions' in plugin && plugin.organizationExtensions) {
2391
- const orgTable = schema.tables.find((t) => t.name === 'organization');
2392
- if (orgTable) {
2393
- (plugin.organizationExtensions.relationships || []).forEach((rel) => {
2394
- if (!orgTable.relationships.some((r) => r.target === rel.target && r.field === rel.field && r.type === rel.type)) {
2395
- orgTable.relationships.push(rel);
2396
- }
2397
- });
2398
- }
2399
- }
2400
- });
2401
- return schema;
2402
- }
1812
+ // Now uses loadContextTables to dynamically load schema from Better Auth context
2403
1813
  const CONTEXT_CORE_TABLES = new Set(['user', 'session', 'account', 'verification']);
2404
1814
  async function resolveSchemaConfigPath() {
2405
1815
  if (configPath) {
@@ -2532,7 +1942,7 @@ export function createRoutes(authConfig, configPath, geoDbPath) {
2532
1942
  tableEntries.sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
2533
1943
  return { tables: tableEntries };
2534
1944
  }
2535
- async function generateSchemaFromContext(selectedTables) {
1945
+ async function generateSchemaFromContext(selectedPlugins) {
2536
1946
  try {
2537
1947
  const tables = await loadContextTables();
2538
1948
  if (!tables) {
@@ -2542,8 +1952,16 @@ export function createRoutes(authConfig, configPath, geoDbPath) {
2542
1952
  if (!schema) {
2543
1953
  return null;
2544
1954
  }
2545
- if (selectedTables && selectedTables.length > 0) {
2546
- schema.tables = schema.tables.filter((table) => selectedTables.includes(table.name));
1955
+ // Filter by plugin origin if plugins are specified
1956
+ if (selectedPlugins && selectedPlugins.length > 0) {
1957
+ schema.tables = schema.tables.filter((table) => {
1958
+ // Include core tables
1959
+ if (CONTEXT_CORE_TABLES.has(table.name)) {
1960
+ return true;
1961
+ }
1962
+ // Include tables from selected plugins
1963
+ return selectedPlugins.includes(table.origin);
1964
+ });
2547
1965
  }
2548
1966
  return schema;
2549
1967
  }
@@ -2565,11 +1983,22 @@ export function createRoutes(authConfig, configPath, geoDbPath) {
2565
1983
  error: 'Auth adapter not available',
2566
1984
  });
2567
1985
  }
2568
- const schema = (await generateSchemaFromContext(selectedPlugins)) || generateStaticSchema(selectedPlugins);
1986
+ const schema = await generateSchemaFromContext(selectedPlugins);
1987
+ if (!schema) {
1988
+ return res.json({
1989
+ success: false,
1990
+ schema: null,
1991
+ error: 'Failed to load schema from Better Auth context. Please ensure your auth configuration is properly set up.',
1992
+ });
1993
+ }
1994
+ // Extract available plugins from schema
1995
+ const availablePlugins = Array.from(new Set(schema.tables
1996
+ .map((table) => table.origin)
1997
+ .filter((origin) => origin !== 'core' && origin !== 'extended')));
2569
1998
  res.json({
2570
1999
  success: true,
2571
2000
  schema: schema,
2572
- availablePlugins: Object.keys(PLUGIN_SCHEMAS),
2001
+ availablePlugins: availablePlugins,
2573
2002
  selectedPlugins: selectedPlugins,
2574
2003
  });
2575
2004
  }
@@ -5137,7 +4566,6 @@ export const authClient = createAuthClient({
5137
4566
  if (match) {
5138
4567
  const key = match[1].trim();
5139
4568
  let value = match[2].trim();
5140
- // Remove surrounding quotes if present (handles both single and double quotes)
5141
4569
  if (value.length >= 2) {
5142
4570
  if ((value.startsWith('"') && value.endsWith('"')) ||
5143
4571
  (value.startsWith("'") && value.endsWith("'"))) {
@@ -5149,7 +4577,6 @@ export const authClient = createAuthClient({
5149
4577
  }
5150
4578
  }
5151
4579
  });
5152
- // Only consider it as existing if the values are not empty (after stripping quotes)
5153
4580
  const isValueEmpty = (val) => {
5154
4581
  if (!val)
5155
4582
  return true;