@lowdefy/plugin-next-auth 5.6.0 → 6.1.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.
@@ -13,10 +13,13 @@
13
13
  See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
15
  */ function OpenIDConnectProvider(properties) {
16
+ // Auth.js v5 models OpenID Connect as an explicit 'oidc' provider type —
17
+ // discovery via issuer/wellKnown and ID token handling are built in,
18
+ // so the v4 `idToken: true` flag is no longer needed.
16
19
  return {
17
20
  id: properties.id ?? 'OpenIDConnectProvider',
18
21
  name: properties.name ?? 'OpenIDConnectProvider',
19
- type: 'oauth',
22
+ type: 'oidc',
20
23
  authorization: {
21
24
  params: {
22
25
  scope: 'openid email profile'
@@ -26,7 +29,6 @@
26
29
  'pkce',
27
30
  'state'
28
31
  ],
29
- idToken: true,
30
32
  ...properties
31
33
  };
32
34
  }
@@ -12,129 +12,65 @@
12
12
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
13
  See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
- */ // This syntax does not work because next-auth is not an es module.
16
- // export { default as Auth0Provider } from 'next-auth/providers/auth0';
17
- import forty_two_school from 'next-auth/providers/42-school';
18
- import apple from 'next-auth/providers/apple';
19
- import atlassian from 'next-auth/providers/atlassian';
20
- import auth0 from 'next-auth/providers/auth0';
21
- import authentik from 'next-auth/providers/authentik';
22
- import azure_ad_b2c from 'next-auth/providers/azure-ad-b2c';
23
- import azure_ad from 'next-auth/providers/azure-ad';
24
- import battlenet from 'next-auth/providers/battlenet';
25
- import box from 'next-auth/providers/box';
26
- import boxyhq_saml from 'next-auth/providers/boxyhq-saml';
27
- import bungie from 'next-auth/providers/bungie';
28
- import cognito from 'next-auth/providers/cognito';
29
- import coinbase from 'next-auth/providers/coinbase';
30
- import discord from 'next-auth/providers/discord';
31
- import dropbox from 'next-auth/providers/dropbox';
32
- import eveonline from 'next-auth/providers/eveonline';
33
- import facebook from 'next-auth/providers/facebook';
34
- import faceit from 'next-auth/providers/faceit';
35
- import foursquare from 'next-auth/providers/foursquare';
36
- import freshbooks from 'next-auth/providers/freshbooks';
37
- import fusionauth from 'next-auth/providers/fusionauth';
38
- import github from 'next-auth/providers/github';
39
- import gitlab from 'next-auth/providers/gitlab';
40
- import google from 'next-auth/providers/google';
41
- import hubspot from 'next-auth/providers/hubspot';
42
- import instagram from 'next-auth/providers/instagram';
43
- import kakao from 'next-auth/providers/kakao';
44
- import keycloak from 'next-auth/providers/keycloak';
45
- import line from 'next-auth/providers/line';
46
- import linkedin from 'next-auth/providers/linkedin';
47
- import mailchimp from 'next-auth/providers/mailchimp';
48
- import mailru from 'next-auth/providers/mailru';
49
- import medium from 'next-auth/providers/medium';
50
- import naver from 'next-auth/providers/naver';
51
- import netlify from 'next-auth/providers/netlify';
52
- import okta from 'next-auth/providers/okta';
53
- import onelogin from 'next-auth/providers/onelogin';
54
- import osso from 'next-auth/providers/osso';
55
- import osu from 'next-auth/providers/osu';
56
- import passage from 'next-auth/providers/passage';
57
- import patreon from 'next-auth/providers/patreon';
58
- import pinterest from 'next-auth/providers/pinterest';
59
- import pipedrive from 'next-auth/providers/pipedrive';
60
- import reddit from 'next-auth/providers/reddit';
61
- import salesforce from 'next-auth/providers/salesforce';
62
- import slack from 'next-auth/providers/slack';
63
- import spotify from 'next-auth/providers/spotify';
64
- import strava from 'next-auth/providers/strava';
65
- import todoist from 'next-auth/providers/todoist';
66
- import trakt from 'next-auth/providers/trakt';
67
- import twitch from 'next-auth/providers/twitch';
68
- import twitter from 'next-auth/providers/twitter';
69
- import vk from 'next-auth/providers/vk';
70
- import united_effects from 'next-auth/providers/united-effects';
71
- import wikimedia from 'next-auth/providers/wikimedia';
72
- import wordpress from 'next-auth/providers/wordpress';
73
- import workos from 'next-auth/providers/workos';
74
- import yandex from 'next-auth/providers/yandex';
75
- import zitadel from 'next-auth/providers/zitadel';
76
- import zoho from 'next-auth/providers/zoho';
77
- import zoom from 'next-auth/providers/zoom';
78
- import OpenIDConnectProvider from './OpenIDConnectProvider.js';
79
- const FortyTwoProvider = forty_two_school.default;
80
- const AppleProvider = apple.default;
81
- const AtlassianProvider = atlassian.default;
82
- const Auth0Provider = auth0.default;
83
- const AuthentikProvider = authentik.default;
84
- const AzureADB2CProvider = azure_ad_b2c.default;
85
- const AzureADProvider = azure_ad.default;
86
- const BattleNetProvider = battlenet.default;
87
- const BoxProvider = box.default;
88
- const BoxyHQSAMLProvider = boxyhq_saml.default;
89
- const BungieProvider = bungie.default;
90
- const CognitoProvider = cognito.default;
91
- const CoinbaseProvider = coinbase.default;
92
- const DiscordProvider = discord.default;
93
- const DropboxProvider = dropbox.default;
94
- const EVEOnlineProvider = eveonline.default;
95
- const FacebookProvider = facebook.default;
96
- const FaceItProvider = faceit.default;
97
- const FourSquareProvider = foursquare.default;
98
- const FreshbooksProvider = freshbooks.default;
99
- const FusionAuthProvider = fusionauth.default;
100
- const GitHubProvider = github.default;
101
- const GitlabProvider = gitlab.default;
102
- const GoogleProvider = google.default;
103
- const HubspotProvider = hubspot.default;
104
- const InstagramProvider = instagram.default;
105
- const KakaoProvider = kakao.default;
106
- const KeycloakProvider = keycloak.default;
107
- const LineProvider = line.default;
108
- const LinkedInProvider = linkedin.default;
109
- const MailchimpProvider = mailchimp.default;
110
- const MailRuProvider = mailru.default;
111
- const MediumProvider = medium.default;
112
- const NaverProvider = naver.default;
113
- const NetlifyProvider = netlify.default;
114
- const OktaProvider = okta.default;
115
- const OneLoginProvider = onelogin.default;
116
- const OssoProvider = osso.default;
117
- const OsuProvider = osu.default;
118
- const PassageProvider = passage.default;
119
- const PatreonProvider = patreon.default;
120
- const PinterestProvider = pinterest.default;
121
- const PipedriveProvider = pipedrive.default;
122
- const RedditProvider = reddit.default;
123
- const SalesforceProvider = salesforce.default;
124
- const SlackProvider = slack.default;
125
- const SpotifyProvider = spotify.default;
126
- const StravaProvider = strava.default;
127
- const TodoistProvider = todoist.default;
128
- const TraktProvider = trakt.default;
129
- const TwitchProvider = twitch.default;
130
- const TwitterProvider = twitter.default;
131
- const UnitedEffects = united_effects.default;
132
- const VkProvider = vk.default;
133
- const WikimediaProvider = wikimedia.default;
134
- const WordpressProvider = wordpress.default;
135
- const WorkOSProvider = workos.default;
136
- const YandexProvider = yandex.default;
137
- const ZitadelProvider = zitadel.default;
138
- const ZohoProvider = zoho.default;
139
- const ZoomProvider = zoom.default;
140
- export { FortyTwoProvider, AppleProvider, AtlassianProvider, Auth0Provider, AuthentikProvider, AzureADB2CProvider, AzureADProvider, BattleNetProvider, BoxProvider, BoxyHQSAMLProvider, BungieProvider, CognitoProvider, CoinbaseProvider, DiscordProvider, DropboxProvider, EVEOnlineProvider, FacebookProvider, FaceItProvider, FourSquareProvider, FreshbooksProvider, FusionAuthProvider, GitHubProvider, GitlabProvider, GoogleProvider, HubspotProvider, InstagramProvider, KakaoProvider, KeycloakProvider, LineProvider, LinkedInProvider, MailchimpProvider, MailRuProvider, MediumProvider, NaverProvider, NetlifyProvider, OktaProvider, OneLoginProvider, OpenIDConnectProvider, OssoProvider, OsuProvider, PassageProvider, PatreonProvider, PinterestProvider, PipedriveProvider, RedditProvider, SalesforceProvider, SlackProvider, SpotifyProvider, StravaProvider, TodoistProvider, TraktProvider, TwitchProvider, TwitterProvider, UnitedEffects, VkProvider, WikimediaProvider, WordpressProvider, WorkOSProvider, YandexProvider, ZitadelProvider, ZohoProvider, ZoomProvider };
15
+ */ export { default as FortyTwoProvider } from '@auth/core/providers/42-school';
16
+ export { default as AppleProvider } from '@auth/core/providers/apple';
17
+ export { default as AtlassianProvider } from '@auth/core/providers/atlassian';
18
+ export { default as Auth0Provider } from '@auth/core/providers/auth0';
19
+ export { default as AuthentikProvider } from '@auth/core/providers/authentik';
20
+ export { default as AzureADB2CProvider } from '@auth/core/providers/azure-ad-b2c';
21
+ export { default as AzureADProvider } from '@auth/core/providers/azure-ad';
22
+ export { default as BattleNetProvider } from '@auth/core/providers/battlenet';
23
+ export { default as BoxProvider } from '@auth/core/providers/box';
24
+ export { default as BoxyHQSAMLProvider } from '@auth/core/providers/boxyhq-saml';
25
+ export { default as BungieProvider } from '@auth/core/providers/bungie';
26
+ export { default as CognitoProvider } from '@auth/core/providers/cognito';
27
+ export { default as CoinbaseProvider } from '@auth/core/providers/coinbase';
28
+ export { default as DiscordProvider } from '@auth/core/providers/discord';
29
+ export { default as DropboxProvider } from '@auth/core/providers/dropbox';
30
+ export { default as EVEOnlineProvider } from '@auth/core/providers/eveonline';
31
+ export { default as FacebookProvider } from '@auth/core/providers/facebook';
32
+ export { default as FaceItProvider } from '@auth/core/providers/faceit';
33
+ export { default as FourSquareProvider } from '@auth/core/providers/foursquare';
34
+ export { default as FreshbooksProvider } from '@auth/core/providers/freshbooks';
35
+ export { default as FusionAuthProvider } from '@auth/core/providers/fusionauth';
36
+ export { default as GitHubProvider } from '@auth/core/providers/github';
37
+ export { default as GitlabProvider } from '@auth/core/providers/gitlab';
38
+ export { default as GoogleProvider } from '@auth/core/providers/google';
39
+ export { default as HubspotProvider } from '@auth/core/providers/hubspot';
40
+ export { default as InstagramProvider } from '@auth/core/providers/instagram';
41
+ export { default as KakaoProvider } from '@auth/core/providers/kakao';
42
+ export { default as KeycloakProvider } from '@auth/core/providers/keycloak';
43
+ export { default as LineProvider } from '@auth/core/providers/line';
44
+ export { default as LinkedInProvider } from '@auth/core/providers/linkedin';
45
+ export { default as MailchimpProvider } from '@auth/core/providers/mailchimp';
46
+ export { default as MailRuProvider } from '@auth/core/providers/mailru';
47
+ export { default as MediumProvider } from '@auth/core/providers/medium';
48
+ export { default as NaverProvider } from '@auth/core/providers/naver';
49
+ export { default as NetlifyProvider } from '@auth/core/providers/netlify';
50
+ export { default as OktaProvider } from '@auth/core/providers/okta';
51
+ export { default as OneLoginProvider } from '@auth/core/providers/onelogin';
52
+ export { default as OssoProvider } from '@auth/core/providers/osso';
53
+ export { default as OsuProvider } from '@auth/core/providers/osu';
54
+ export { default as PassageProvider } from '@auth/core/providers/passage';
55
+ export { default as PatreonProvider } from '@auth/core/providers/patreon';
56
+ export { default as PinterestProvider } from '@auth/core/providers/pinterest';
57
+ export { default as PipedriveProvider } from '@auth/core/providers/pipedrive';
58
+ export { default as RedditProvider } from '@auth/core/providers/reddit';
59
+ export { default as SalesforceProvider } from '@auth/core/providers/salesforce';
60
+ export { default as SlackProvider } from '@auth/core/providers/slack';
61
+ export { default as SpotifyProvider } from '@auth/core/providers/spotify';
62
+ export { default as StravaProvider } from '@auth/core/providers/strava';
63
+ export { default as TodoistProvider } from '@auth/core/providers/todoist';
64
+ export { default as TraktProvider } from '@auth/core/providers/trakt';
65
+ export { default as TwitchProvider } from '@auth/core/providers/twitch';
66
+ export { default as TwitterProvider } from '@auth/core/providers/twitter';
67
+ export { default as UnitedEffects } from '@auth/core/providers/united-effects';
68
+ export { default as VkProvider } from '@auth/core/providers/vk';
69
+ export { default as WikimediaProvider } from '@auth/core/providers/wikimedia';
70
+ export { default as WordpressProvider } from '@auth/core/providers/wordpress';
71
+ export { default as WorkOSProvider } from '@auth/core/providers/workos';
72
+ export { default as YandexProvider } from '@auth/core/providers/yandex';
73
+ export { default as ZitadelProvider } from '@auth/core/providers/zitadel';
74
+ export { default as ZohoProvider } from '@auth/core/providers/zoho';
75
+ export { default as ZoomProvider } from '@auth/core/providers/zoom';
76
+ export { default as OpenIDConnectProvider } from './OpenIDConnectProvider.js';
@@ -0,0 +1,60 @@
1
+ /*
2
+ Copyright 2020-2026 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ import { createHash, timingSafeEqual } from 'node:crypto';
16
+ import { type } from '@lowdefy/helpers';
17
+ function sha256(value) {
18
+ return createHash('sha256').update(value).digest();
19
+ }
20
+ // Static API key strategy - reads a dedicated header (default X-API-Key, set
21
+ // by build) and compares against the configured keys. Both sides are hashed
22
+ // to SHA-256 before timingSafeEqual: the digests are a fixed 32 bytes, so the
23
+ // comparison runs in constant time without a length fast-path that would leak
24
+ // key length through timing.
25
+ function apiKey({ logger, properties, strategyId }) {
26
+ const headerName = properties.headerName;
27
+ const keys = properties.keys.map((key, index)=>{
28
+ const keyId = type.isNone(key.id) ? String(index) : key.id;
29
+ if (!type.isString(key.value)) {
30
+ throw new Error(`Auth strategy "${strategyId}" key "${keyId}" did not resolve to a string. Check the _secret operator reference and that the secret is set.`);
31
+ }
32
+ // Secrets are opaque at build time; strength checks are startup warnings.
33
+ if (key.value.length < 32) {
34
+ logger.warn(`Auth strategy "${strategyId}" key "${keyId}" is shorter than 32 characters. Use a long random value, e.g. \`openssl rand -hex 32\`.`);
35
+ }
36
+ return {
37
+ digest: sha256(key.value),
38
+ id: keyId
39
+ };
40
+ });
41
+ return async function verify({ headers }) {
42
+ const presented = headers.get(headerName);
43
+ if (!presented) {
44
+ return null;
45
+ }
46
+ const presentedDigest = sha256(presented);
47
+ const match = keys.find((key)=>timingSafeEqual(presentedDigest, key.digest));
48
+ if (type.isNone(match)) {
49
+ return null;
50
+ }
51
+ // Synthetic caller id with per-key audit identity - the key index stands
52
+ // in when the config sets no key id.
53
+ return {
54
+ user: {
55
+ id: `apiKey:${strategyId}:${match.id}`
56
+ }
57
+ };
58
+ };
59
+ }
60
+ export default apiKey;
@@ -0,0 +1,137 @@
1
+ /*
2
+ Copyright 2020-2026 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ import { createRemoteJWKSet, jwtVerify } from 'jose';
16
+ import { get, type } from '@lowdefy/helpers';
17
+ // Prototype-pollution vectors - build rejects reserved claimMapping fields,
18
+ // and reserved claim paths resolve to no claim here as defense in depth: the
19
+ // id claim then rejects the token, and any other mapping entry is skipped.
20
+ const reservedKeys = new Set([
21
+ '__proto__',
22
+ 'constructor',
23
+ 'prototype',
24
+ '__defineGetter__',
25
+ '__defineSetter__',
26
+ '__lookupGetter__',
27
+ '__lookupSetter__'
28
+ ]);
29
+ function readClaim({ claimPath, payload }) {
30
+ if (String(claimPath).split('.').some((segment)=>reservedKeys.has(segment))) {
31
+ return undefined;
32
+ }
33
+ return get(payload, claimPath);
34
+ }
35
+ function toRoles(value) {
36
+ if (type.isArray(value)) {
37
+ return value.filter((role)=>type.isString(role));
38
+ }
39
+ if (type.isString(value)) {
40
+ return [
41
+ value
42
+ ];
43
+ }
44
+ return [];
45
+ }
46
+ // JWT strategy - verifies third-party Bearer tokens locally with jose, HMAC
47
+ // (secret) or JWKS (jwksUri; createRemoteJWKSet caches keys and handles
48
+ // rotation). Build guarantees exactly one of secret/jwksUri and a non-empty
49
+ // algorithms allowlist - the allowlist is what stops an `alg: none` or
50
+ // downgraded-algorithm token from verifying.
51
+ function jwt({ logger, properties, strategyId }) {
52
+ const { algorithms, audience, issuer, jwksUri, secret } = properties;
53
+ const claimMapping = properties.claimMapping ?? {};
54
+ let key;
55
+ if (!type.isNone(secret)) {
56
+ if (!type.isString(secret)) {
57
+ throw new Error(`Auth strategy "${strategyId}" "secret" did not resolve to a string. Check the _secret operator reference and that the secret is set.`);
58
+ }
59
+ // Secrets are opaque at build time; strength checks are startup warnings.
60
+ if (secret.length < 32) {
61
+ logger.warn(`Auth strategy "${strategyId}" "secret" is shorter than 32 characters. Use a long random value, e.g. \`openssl rand -base64 32\`.`);
62
+ }
63
+ key = new TextEncoder().encode(secret);
64
+ } else {
65
+ key = createRemoteJWKSet(new URL(jwksUri));
66
+ }
67
+ return async function verify({ headers, logger: requestLogger }) {
68
+ const authorization = headers.get('authorization');
69
+ if (!authorization || !authorization.startsWith('Bearer ')) {
70
+ return null;
71
+ }
72
+ const token = authorization.slice('Bearer '.length).trim();
73
+ let payload;
74
+ try {
75
+ ({ payload } = await jwtVerify(token, key, {
76
+ algorithms,
77
+ audience,
78
+ issuer
79
+ }));
80
+ } catch (error) {
81
+ // An invalid token is not this strategy's caller - resolution moves on
82
+ // to the next strategy instead of failing the request.
83
+ (requestLogger ?? logger).debug({
84
+ event: 'auth_strategy_token_rejected',
85
+ strategyId,
86
+ err: error
87
+ }, `Auth strategy "${strategyId}" rejected a Bearer token: ${error.message}`);
88
+ return null;
89
+ }
90
+ const idClaim = claimMapping.id ?? 'sub';
91
+ const id = readClaim({
92
+ claimPath: idClaim,
93
+ payload
94
+ });
95
+ if (type.isNone(id)) {
96
+ // A caller without an identity cannot be authenticated - a signed token
97
+ // missing the id claim is rejected, not promoted to an id-less caller.
98
+ (requestLogger ?? logger).debug({
99
+ event: 'auth_strategy_token_rejected',
100
+ strategyId
101
+ }, `Auth strategy "${strategyId}" rejected a Bearer token: the "${idClaim}" id claim is missing.`);
102
+ return null;
103
+ }
104
+ const user = {
105
+ id
106
+ };
107
+ const attributes = {};
108
+ let roles = [];
109
+ Object.entries(claimMapping).forEach(([field, claimPath])=>{
110
+ if (field === 'id') {
111
+ return;
112
+ }
113
+ const value = readClaim({
114
+ claimPath,
115
+ payload
116
+ });
117
+ if (field === 'roles') {
118
+ roles = toRoles(value);
119
+ return;
120
+ }
121
+ if (type.isNone(value)) {
122
+ return;
123
+ }
124
+ if (field.startsWith('attributes.')) {
125
+ attributes[field.slice('attributes.'.length)] = value;
126
+ return;
127
+ }
128
+ user[field] = value;
129
+ });
130
+ return {
131
+ attributes,
132
+ roles,
133
+ user
134
+ };
135
+ };
136
+ }
137
+ export default jwt;
@@ -0,0 +1,20 @@
1
+ /*
2
+ Copyright 2020-2026 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ // API auth strategy verifier factories. Each factory receives a strategy's
16
+ // resolved properties at startup and returns an async verify({ headers,
17
+ // logger }) that resolves a match or null - strategy order and caller
18
+ // assembly live in @lowdefy/api's resolveStrategyCaller.
19
+ export { default as apiKey } from './strategies/apiKey.js';
20
+ export { default as jwt } from './strategies/jwt.js';
package/dist/types.js CHANGED
@@ -77,6 +77,10 @@
77
77
  'ZitadelProvider',
78
78
  'ZohoProvider',
79
79
  'ZoomProvider'
80
+ ],
81
+ strategies: [
82
+ 'apiKey',
83
+ 'jwt'
80
84
  ]
81
85
  }
82
86
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lowdefy/plugin-next-auth",
3
- "version": "5.6.0",
3
+ "version": "6.1.0",
4
4
  "license": "Apache-2.0",
5
5
  "description": "",
6
6
  "homepage": "https://lowdefy.com",
@@ -29,21 +29,28 @@
29
29
  "exports": {
30
30
  ".": "./dist/index.js",
31
31
  "./auth/providers": "./dist/auth/providers.js",
32
+ "./auth/strategies": "./dist/auth/strategies.js",
32
33
  "./types": "./dist/types.js"
33
34
  },
34
35
  "files": [
35
36
  "dist/*"
36
37
  ],
38
+ "dependencies": {
39
+ "@lowdefy/helpers": "6.1.0",
40
+ "jose": "^6.2.3"
41
+ },
37
42
  "peerDependencies": {
38
- "next": ">=16",
39
- "next-auth": ">=4.24"
43
+ "@auth/core": ">=0.41.3"
40
44
  },
41
45
  "devDependencies": {
42
- "@lowdefy/node-utils": "5.6.0",
43
- "@swc/cli": "0.8.0",
44
- "@swc/core": "1.15.18",
46
+ "@auth/core": "0.41.3",
47
+ "@jest/globals": "28.1.3",
48
+ "@lowdefy/node-utils": "6.1.0",
49
+ "@swc/cli": "0.8.1",
50
+ "@swc/core": "1.15.32",
45
51
  "@swc/jest": "0.2.39",
46
52
  "jest": "28.1.3",
53
+ "jest-environment-node": "28.1.3",
47
54
  "react": "18.2.0",
48
55
  "react-dom": "18.2.0"
49
56
  },
@@ -52,6 +59,7 @@
52
59
  },
53
60
  "scripts": {
54
61
  "build": "swc src --out-dir dist --config-file ../../../../.swcrc --cli-config-file ../../../../.swc-cli.json --copy-files",
55
- "clean": "rm -rf dist"
62
+ "clean": "rm -rf dist",
63
+ "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
56
64
  }
57
65
  }