Skip to content

Commit

Permalink
Merge branch 'main' into miho-update-ci
Browse files Browse the repository at this point in the history
  • Loading branch information
infomiho committed Aug 28, 2024
2 parents 5db0730 + ccc652e commit 6db73ba
Show file tree
Hide file tree
Showing 120 changed files with 3,623 additions and 743 deletions.
2 changes: 1 addition & 1 deletion mage/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Mage

This directory contains the source code of Mage (aka "GPT Web App Generator" aka "Wasp AI"): a Wasp app (so a full-stack web app) that allows you to create a new Wasp app (inception :)!) from just a short description. It uses ChatGPT in a smart way to accomplish this (so it would be clasified as an AI code agent).
This directory contains the source code of Mage (aka "GPT Web App Generator" aka "Wasp AI"): a Wasp app (so a full-stack web app) that allows you to create a new Wasp app (inception :)!) from just a short description. It uses ChatGPT in a smart way to accomplish this (so it would be classified as an AI code agent).

Mage is hosted at https://usemage.ai and you can use it there for free.

Expand Down
4 changes: 2 additions & 2 deletions mage/src/client/components/Faq.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const faqs = [
answer: <p>
Due to GPT being non-deterministic, it sometimes introduces (small) mistakes, especially for more complex apps, but altogether it works better than we expected!
The code it generates is often very reasonable, and for very simple apps, it can even produce a working app out of the box, while for a bit more complex apps
it currently serves more like a super-intelligent starter that needs a couple of tweeks to get it going.
it currently serves more like a super-intelligent starter that needs a couple of tweaks to get it going.

<br/><br/>

Expand Down Expand Up @@ -76,7 +76,7 @@ const faqs = [
<br/><br/>

We use GPT4 during the planning phase, since that is the most critical step, and then use GPT3.5 for the rest of the steps.
Although using GPT4 exclusively does give better results, we use a mix to keep the costs, generation time, and bandwith acceptable (due to pricing and rate limits of GPT4).
Although using GPT4 exclusively does give better results, we use a mix to keep the costs, generation time, and bandwidth acceptable (due to pricing and rate limits of GPT4).

<br/><br/>

Expand Down
22 changes: 22 additions & 0 deletions waspc/ChangeLog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
# Changelog

## 0.14.1 (2024-08-26)

### 🎉 New Features

- Wasp now supports `onBeforeLogin` and `onAfterLogin` auth hooks! You can use these hooks to run custom logic before and after a user logs in. For example, you can use the `onBeforeLogin` hook to check if the user is allowed to log in.
- OAuth refresh tokens are here. If the OAuth provider supports refresh tokens, you'll be able to use them to refresh the access token when it expires. This is useful for using OAuth provider APIs in the background e.g. accessing user's calendar events.

### ⚠️ Breaking Changes

- To make the API consistent across different auth hooks, we change how the `onBeforeOAuthRedirect` hook receives the `uniqueRequestId` value to `oauth.uniqueRequestId`.

### 🐞 Bug fixes

- Prisma file parser now allows using empty arrays as default values.

### 🔧 Small improvements

- Replace `oslo/password` with directly using `@node-rs/argon2`
- We now use `websocket` transport for the WebSocket client to avoid issues when deploying the server behind a load balancer.

Community contributions by @rubyisrust @santolucito @sezercik @LLxD!

## 0.14.0 (2024-07-17)

### 🎉 New Features
Expand Down
87 changes: 52 additions & 35 deletions waspc/data/Generator/templates/sdk/wasp/server/auth/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{{={= =}=}}
import type { Request as ExpressRequest } from 'express'
import { type ProviderId, createUser, findAuthWithUserBy } from '../../auth/utils.js'
import { prisma } from '../index.js'
Expand Down Expand Up @@ -35,7 +36,7 @@ export type OnAfterLoginHook = (
export type InternalAuthHookParams = {
/**
* Prisma instance that can be used to interact with the database.
*/
*/
prisma: typeof prisma
}

Expand All @@ -48,86 +49,102 @@ export type InternalAuthHookParams = {
type OnBeforeSignupHookParams = {
/**
* Provider ID object that contains the provider name and the provide user ID.
*/
*/
providerId: ProviderId
/**
* Request object that can be used to access the incoming request.
*/
*/
req: ExpressRequest
} & InternalAuthHookParams

type OnAfterSignupHookParams = {
/**
* Provider ID object that contains the provider name and the provide user ID.
*/
*/
providerId: ProviderId
/**
* User object that was created during the signup process.
*/
*/
user: Awaited<ReturnType<typeof createUser>>
oauth?: {
/**
* Access token that was received during the OAuth flow.
*/
accessToken: string
/**
* Unique request ID that was generated during the OAuth flow.
*/
uniqueRequestId: string
},
/**
* OAuth flow data that was generated during the OAuth flow. This is only
* available if the user signed up using OAuth.
*/
oauth?: OAuthData
/**
* Request object that can be used to access the incoming request.
*/
*/
req: ExpressRequest
} & InternalAuthHookParams

type OnBeforeOAuthRedirectHookParams = {
/**
* URL that the OAuth flow should redirect to.
*/
*/
url: URL
/**
* Unique request ID that was generated during the OAuth flow.
*/
uniqueRequestId: string
*/
oauth: Pick<OAuthData, 'uniqueRequestId'>
/**
* Request object that can be used to access the incoming request.
*/
*/
req: ExpressRequest
} & InternalAuthHookParams

type OnBeforeLoginHookParams = {
/**
* Provider ID object that contains the provider name and the provide user ID.
*/
*/
providerId: ProviderId
/**
* User that is trying to log in.
*/
user: Awaited<ReturnType<typeof findAuthWithUserBy>>['user']
/**
* Request object that can be used to access the incoming request.
*/
*/
req: ExpressRequest
} & InternalAuthHookParams

type OnAfterLoginHookParams = {
/**
* Provider ID object that contains the provider name and the provide user ID.
*/
*/
providerId: ProviderId
oauth?: {
/**
* Access token that was received during the OAuth flow.
*/
accessToken: string
/**
* Unique request ID that was generated during the OAuth flow.
*/
uniqueRequestId: string
},
/**
* User that is logged in.
*/
*/
user: Awaited<ReturnType<typeof findAuthWithUserBy>>['user']
/**
* OAuth flow data that was generated during the OAuth flow. This is only
* available if the user logged in using OAuth.
*/
oauth?: OAuthData
/**
* Request object that can be used to access the incoming request.
*/
*/
req: ExpressRequest
} & InternalAuthHookParams

// PUBLIC API
export type OAuthData = {
/**
* Unique request ID that was generated during the OAuth flow.
*/
uniqueRequestId: string
} & (
{=# enabledProviders.isGoogleAuthEnabled =}
| { providerName: 'google'; tokens: import('arctic').GoogleTokens }
{=/ enabledProviders.isGoogleAuthEnabled =}
{=# enabledProviders.isDiscordAuthEnabled =}
| { providerName: 'discord'; tokens: import('arctic').DiscordTokens }
{=/ enabledProviders.isDiscordAuthEnabled =}
{=# enabledProviders.isGitHubAuthEnabled =}
| { providerName: 'github'; tokens: import('arctic').GitHubTokens }
{=/ enabledProviders.isGitHubAuthEnabled =}
{=# enabledProviders.isKeycloakAuthEnabled =}
| { providerName: 'keycloak'; tokens: import('arctic').KeycloakTokens }
{=/ enabledProviders.isKeycloakAuthEnabled =}
| never
)
13 changes: 9 additions & 4 deletions waspc/data/Generator/templates/sdk/wasp/server/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,17 @@ export type {
OnBeforeLoginHook,
OnAfterLoginHook,
InternalAuthHookParams,
OAuthData,
} from './hooks.js'

{=# isEmailAuthEnabled =}
{=# isExternalAuthEnabled =}
export * from './oauth/index.js'
{=/ isExternalAuthEnabled =}

{=# enabledProviders.isEmailAuthEnabled =}
export * from './email/index.js'
{=/ isEmailAuthEnabled =}
{=/ enabledProviders.isEmailAuthEnabled =}

{=# isUsernameAndPasswordAuthEnabled =}
{=# enabledProviders.isUsernameAndPasswordAuthEnabled =}
export * from './username.js'
{=/ isUsernameAndPasswordAuthEnabled =}
{=/ enabledProviders.isUsernameAndPasswordAuthEnabled =}
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { type ProviderConfig } from "wasp/auth/providers/types";

// PRIVATE API (SDK)
export function ensureEnvVarsForProvider<EnvVarName extends string>(
envVarNames: EnvVarName[],
provider: ProviderConfig,
providerName: string,
): Record<EnvVarName, string> {
const result: Record<string, string> = {};
for (const envVarName of envVarNames) {
const value = process.env[envVarName];
if (!value) {
throw new Error(`${envVarName} env variable is required when using the ${provider.displayName} auth provider.`);
throw new Error(`${envVarName} env variable is required when using the ${providerName} auth provider.`);
}
result[envVarName] = value;
}
Expand Down
31 changes: 31 additions & 0 deletions waspc/data/Generator/templates/sdk/wasp/server/auth/oauth/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{{={= =}=}}
{=# enabledProviders.isGoogleAuthEnabled =}
// PUBLIC API
export { google } from './providers/google.js';
{=/ enabledProviders.isGoogleAuthEnabled =}
{=# enabledProviders.isDiscordAuthEnabled =}
// PUBLIC API
export { discord } from './providers/discord.js';
{=/ enabledProviders.isDiscordAuthEnabled =}
{=# enabledProviders.isGitHubAuthEnabled =}
// PUBLIC API
export { github } from './providers/github.js';
{=/ enabledProviders.isGitHubAuthEnabled =}
{=# enabledProviders.isKeycloakAuthEnabled =}
// PUBLIC API
export { keycloak } from './providers/keycloak.js';
{=/ enabledProviders.isKeycloakAuthEnabled =}

// PRIVATE API
export {
loginPath,
callbackPath,
exchangeCodeForTokenPath,
handleOAuthErrorAndGetRedirectUri,
getRedirectUriForOneTimeCode,
} from './redirect.js'

// PRIVATE API
export {
tokenStore,
} from './oneTimeCode.js'
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { createJWT, validateJWT, TimeSpan } from '../../../auth/jwt.js'

export const tokenStore = createTokenStore();

function createTokenStore() {
const usedTokens = new Map<string, number>();

const validFor = new TimeSpan(1, 'm') // 1 minute
const cleanupAfter = 1000 * 60 * 60; // 1 hour

function createToken(userId: string): Promise<string> {
return createJWT(
{
id: userId,
},
{
expiresIn: validFor,
}
);
}

function verifyToken(token: string): Promise<{ id: string }> {
return validateJWT(token);
}

function isUsed(token: string): boolean {
return usedTokens.has(token);
}

function markUsed(token: string): void {
usedTokens.set(token, Date.now());
cleanUp();
}

function cleanUp(): void {
const now = Date.now();
for (const [token, timestamp] of usedTokens.entries()) {
if (now - timestamp > cleanupAfter) {
usedTokens.delete(token);
}
}
}

return {
createToken,
verifyToken,
isUsed,
markUsed,
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { OAuth2Provider, OAuth2ProviderWithPKCE } from "arctic";

export function defineProvider<
OAuthClient extends OAuth2Provider | OAuth2ProviderWithPKCE,
Env extends Record<string, string>
>({
id,
displayName,
env,
oAuthClient,
}: {
id: string;
displayName: string;
env: Env;
oAuthClient: OAuthClient;
}) {
return {
id,
displayName,
env,
oAuthClient,
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{{={= =}=}}
import { Discord } from "arctic";

import { defineProvider } from "../provider.js";
import { ensureEnvVarsForProvider } from "../env.js";
import { getRedirectUriForCallback } from "../redirect.js";

const id = "{= providerId =}";
const displayName = "{= displayName =}";

const env = ensureEnvVarsForProvider(
["DISCORD_CLIENT_ID", "DISCORD_CLIENT_SECRET"],
displayName
);

const oAuthClient = new Discord(
env.DISCORD_CLIENT_ID,
env.DISCORD_CLIENT_SECRET,
getRedirectUriForCallback(id).toString(),
);

// PUBLIC API
export const discord = defineProvider({
id,
displayName,
env,
oAuthClient,
});
Loading

0 comments on commit 6db73ba

Please sign in to comment.