GitHub repository: FoalTS/foal

Issues:
issue_1246: state: open
title: [Proposal] Give full control of express response object for user
body: Although it is possible to add premiddleware to intercept the request before it is processed by foal's core. 
It is better to simply pass the raw express response object to Context as well. 
So developers can interact with the raw response object in advanced use case while hooks for checking incoming request can still be reusable when implementing features like SSE(server-sent event) or streaming. 
A simple check of the response type in sendResponse function to determine whether or not to execute the default behaviours would be fine.

@LoicPoullain What do you think? I can submit a PR for this feature.
user: kingdun3284
issue_1245: state: open
title: added whitelist to cors docs
body: <!--
Please read the contribution guidelines first. A PR without (robust) tests will not be approved.
-->
# Issue
we should use a origin whitelist in case of allowing credentials in cors

# Solution and steps
use a whitelist in the cors hook
updated docs

# Checklist

- [ x] Add/update/check docs (code comments and docs/ folder).
- [ ] Add/update/check tests.
- [ ] Update/check the cli generators.

user: sebstec
issue_1244: state: open
title: v4.3.0
body: - [x] [Internal] Use fs native API with promises (PR: #1243)
user: LoicPoullain
issue_1211: state: open
title: SSR with built-in templates not working
body: Version of FoalTS: 3.2

Getting Error
```
Error: ENOENT: no such file or directory, open '/Users/wgallagher/dev/aq/aq-touchpoint-demo/build/app/templates/aq-touchpoint.html'
```

The src files are in: ```aq-touchpoint-demo/src/app/templates```

Getting an error whereby the template file cannot be found. It looks like the build is not copying the templates into the build directory. I've tried moving the directory under the controllers directory and adding the __dirname as well.

It would appear the template directory and its contents are not being copied into the build hierarchy.

```typescript
@Get('/aq-touchpoint-verify')
 async aqTouchpointVerify(ctx: Context) {
    const httpResponse = await render('./templates/aq-touchpoint.html', {
      touchpointId: 'cd544334-dd07-4010-9285-3b78461b7dae',
      title: 'Verify - &lt;aq-touchpoint/&gt;'
    }, __dirname);
    httpResponse.setHeader('Access-Control-Allow-Origin', '*');
    httpResponse.setHeader('Content-Type', 'text/html');
    return httpResponse;
 }
```

user: warren-gallagher
issue_1210: state: open
title: Task Scheduling In App
body: Hi,

I wanted to know if it was planned to provide a recurring task management system directly in the app instance instead of being executed via the CLI? 

In order to be able to trigger different elements in the code directly (Typically, sending a message to websockets clients?).

This would also allow to set up a "multi servers" system for the crons so that the load is distributed.

Thanks and thank for your work on FoalTS, my opinion is that it is probably the best framework ts (not chauvin at all..)
user: jonathanroze
issue_1205: state: open
title: JWT support for SocketIO
body: Is there a way we can integrate JWT into the SocketIO controller. One recommendation is to add a middleware like so:

```
io.use(function(socket, next){
  if (socket.handshake.query && socket.handshake.query.token){
    jwt.verify(socket.handshake.query.token, 'SECRET_KEY', function(err, decoded) {
      if (err) return next(new Error('Authentication error'));
      socket.decoded = decoded;
      next();
    });
  }
  else {
    next(new Error('Authentication error'));
  }    
})
```

How can we access the `io` object to connect such a middleware?


user: everythingspirals
issue_1175: state: open
title: [QOL Change] Use ts-node to directly execute foal script
body: As the title's said

user: kingdun3284
issue_1160: state: open
title: Generate upload/download pre-signed urls with the Disk util 
body: <!--
If you wish to share code, please use indentation and syntax highlighting.
The easier an issue is to read, the faster you will get an answer.

DON'T DO:
```
function test() {
for (const i of [1, 2, 3]) {
console.log(i);
}
}
```

DO:
```typescript
function test() {
  for (const i of [1, 2, 3]) {
    console.log(i);
  }
}
```
-->

We don't always want to server to handle file uploads, and it's easy enough to use the AWS SDK, but the Disk util is just too convenient. Would it be possible to add this feature to it? 

Something like: 

```typescript
 const { downloadUrl } = await this.disk.createPresignedDownloadUrl('docs/xxx.pdf', 'buffer', {
              expiresIn: 3600
          });
```


```typescript
 const { uploadUrl } = await this.disk.createPresignedUploadUrl('docs', content, {
              expiresIn: 3600
          });
```

Thought this does present a problem, to how to handle local file upload/downloads in this case, I don't have good idea for that one.
user: k0rn4l
issue_1136: state: open
title: Typed config.get based on default.json
body: Hi, I'm opening a new issue as you asked it in [#880](https://github.com/FoalTS/foal/issues/880#issuecomment-1218311630)
I took a deep dive into the Typescript type system and was able to come up with a type (lot of ideas came from the [type-challanges](https://github.com/type-challenges/type-challenges)) for the Config.get function:
- based on the default.json the key parameter is typed, it only accepts strings that are defined in the config file in the same format as the Config.get method accept keys (e.g.: 'port', 'setting.debug')
- based on the default.json the return type is automatically typed, you don't have to provide any type information to the function

As you might notice, the solution heavily relies on the default.json, if we want to read a value which is missing from that file, typescript will throw an error. In my opinion this is more of a positive outcome than a negative, as it forces to define a default value for every key that the application will try to read, also making the defaultValue parameter obsolete (defaults should be defined in default.json).
Another limitation is in a json file we can only have string, boolean, number, array and object types, the type the function returns with can only be these. So if we want to have a more restricted type (e.g. Stripe API has an Interval type which is a subset of string ("weekly" | "daily" | "manual" | "monthly") and we want to use the value straight from the config) we either need to cast the type, be able to specify the return type of the function similar to the current solution, or have some utility to rewrite the type of the config (which I included in the solution).
But in my opinion with these limitations we would get a type-safe, easy-to-use Config functionality.
I'm really interested in your opinion (and I don't have a clear idea, how to include this in the framework)

Some screenshots to show how it works:
![intellisense can show you all the available keys](https://user-images.githubusercontent.com/3876282/179979369-1889964a-d0ed-4f27-978a-6d61fe71d1b3.png)
intellisense can show you all the available keys

![typescript error if key doesn't exists, value automatically typed correctly](https://user-images.githubusercontent.com/3876282/179979661-5eaeb955-7b1b-486d-bc4e-862b2b4fe83e.png)
typescript error if key doesn't exists, value automatically typed correctly

![works with deep keys with dot notation, correctly returns with complex object types](https://user-images.githubusercontent.com/3876282/179980061-9cbe721a-14bc-4c42-bba5-53dede1fadeb.png)
works with deep keys with dot notation, correctly returns with complex object types

I tried to add as many comments as possible, as it is not an easy read :). (it also uses some of the newest features of typescript, I used version 4.7.3)
```typescript
import { Config } from '@foal/core';
import Stripe from 'stripe';

import config from 'config/default.json';

type BaseConfigType = typeof config;

/**
 * SetType<T, K, V>: object
 *   T: object type to modify
 *   K: string key to modify, can be in dot notation format to modify deep key
 *   V: type that key to have
 *   modifies T, overrides the key that K refers to to have the type V
 *   if K is not in T, then T is returned
 */
// first check if K has a dot in it. if yes H should be the part before the first dot R should be the part after
type SetType<T extends object, K extends string, V> = K extends `${infer H}.${infer R}`
  ? // we create a new object type
    {
      // the keys should be the same as in T, the type should be the same
      // expect for H: if T[H] is an object then recursively call SetType with that object and the rest of K (R)
      [Key in keyof T]: H extends Key ? (T[H] extends object ? SetType<T[H], R, V> : T[H]) : T[Key];
    }
  : // if K doesn't hava a dot in it then we still create a new object type
    {
      // the keys should be the same as in T, the type should be the same, expect for K: it should be V
      [Key in keyof T]: K extends Key ? V : T[Key];
    };

/**
 * SetTypes<T, KV>: object
 *   T: object to modify
 *   KV: array of key-value doubles, keys are strings can be in dot notation format, values can be any type
 *   modifies T, overrides each key in KV to have the corresponding type in KV
 */
// let's check if KV is an empty array. if not H should be the first item in the array and R should be the rest (could be an empty array as well)
type SetTypes<T extends object, KV extends [string, unknown][]> = KV extends [
  infer H extends [string, unknown],
  ...infer R extends [string, unknown][],
]
  ? // for each H item in the array we update T with the help of the SetType type (H[0] is the key, H[1] is the value)
    // then we recursively call SetTypes with the updated object and the rest of the array (R)
    SetTypes<SetType<T, H[0], H[1]>, R>
  : // if KV is empty just return with T, the input object
    T;

// examples of rewriting types in the config
export type ConfigType = SetTypes<
  BaseConfigType,
  [
    ['stripe.interval', Stripe.AccountCreateParams.Settings.Payouts.Schedule.Interval],
    ['stripe.weeklyanchor', Stripe.AccountCreateParams.Settings.Payouts.Schedule.WeeklyAnchor],
  ]
>;

/**
 * WithPrefix<Pre, Key>: string
 *   Pre: string to prefix Key with
 *   Key: string or number
 */
// first lets check if Pre is never (we use never instead of empty string when we don't want to add any prefix)
type WithPrefix<Pre extends string, Key extends string | number> = [Pre] extends [never]
  ? // if there is no prefix just convert Key to a string (needed if it is a number)
    `${Key}`
  : // if Pre isn't empty check if Key is a number
  Key extends number
  ? // if Key is a number, instead of dot notation use square brackets (this will handle arrays)
    `${Pre}[${Key}]`
  : // if Key is a string use dot notation
    `${Pre}.${Key}`;

/**
 * ObjectKeyPaths<T, Pre>: string (union)
 *   T: object to generate key paths from
 *   Pre: string to prefix key paths with, we use never instead of empty string to begin with
 *   generates all the possible keys in T, with dot notation to deep keys, all the keys prefixed with Pre
 */
type ObjectKeyPaths<T extends object, Pre extends string = never> =
  // Pre is always a key in object if used correctly
  // never | A = A that's why we start with never instead of empty string
  // A | A = A so unioning the same keys multiple times won't cause an issue
  | Pre
  // the idea is to create an object where keys are the same as in T, but values(types) are strings: the keys prefixed with Pre
  // when we created the correct object we can create a union of the values with indexing the object with all the possible keys
  // e.g: this works with tuples(arrays) ['a', 'b', 'c'][number] = 'a' | 'b' | 'c'
  | {
      // we use the same keys as in T, except:
      //  if T is an object we only use string and number keys (filtering symbols)
      //  if T is an array we only use number keys (filtering symbols and functions that are on every array like map, forEach etc.)
      //  this can cause that if we create an object based on an array, then we add some non number keys to it those keys wont be in the end result
      //  but for our use case, this can't happen, because we will read types from a json file
      [Key in T extends unknown[] ? keyof T & number : keyof T & (string | number)]: T[Key] extends object
        ? // if the type of the current key is an object, then we should recursively call ObjectKeyPaths with that object
          // adding the current key prefixed with Pre as the new prefix
          ObjectKeyPaths<T[Key], WithPrefix<Pre, Key>>
        : // if the type isn't an object then just prefix key with Pre
          WithPrefix<Pre, Key>;
      // we use the same logic to index the object when we created the keys for the object
    }[T extends unknown[] ? keyof T & number : keyof T & (string | number)];

type ConfigKeys = ObjectKeyPaths<ConfigType>;

/**
 * Get<T, K>: ?
 *   T: object to get the type from
 *   K: key to read, can be in dot notation to read deep key
 *   gets the type of K from T
 */
// first check if K has a dot in it, if yes then H should be the part before the first dot R should be the rest
type Get<T extends object, K extends string> = K extends `${infer H}.${infer R}`
  ? // check if H is a key in T and that key refers to an object
    T[H & keyof T] extends object
    ? // if yes recursively go a level deeper with that object and the rest of K (R)
      Get<T[H & keyof T], R>
    : // else K is not a proper key of T so there is no type to get
      never
  : // if K has no dot in it, then it must be at the root level, we return it with that type
    T[K & keyof T];

export const get = <K extends ConfigKeys>(key: K): Get<ConfigType, K> => {
  return Config.getOrThrow(key);
};
```
user: enepeti
issue_1051: state: open
title: Improve performance using output catching
body: Hi FoalTS team, I hope you are doing well! 

I was looking for a server-side cache implementation in FoalTS but I couldn't find it. I bring you the following `feature request`:

You can dramatically improve the performance of your web applications by taking advantage of output caching. The output cache enables you to cache the content returned by a controller action. That way, the same content does not need to be generated each and every time the same controller action is invoked.

Imagine, for example, that your application displays a list of database records in a view named Index. Normally, each and every time that a user invokes the controller action that returns the Index view, the set of database records must be retrieved from the database by executing a database query.

If, on the other hand, you take advantage of the output cache then you can avoid executing a database query every time any user invokes the same controller action. The view can be retrieved from the cache instead of being regenerated from the controller action. Caching enables you to avoid performing redundant work on the server.

Source:
[Improving Performance with Output Catching - MSDN Article](https://docs.microsoft.com/en-us/aspnet/mvc/overview/older-versions-1/controllers-and-routing/improving-performance-with-output-caching-cs)

Usage (example, in foal.ts):
```typescript
import { Context, Delete, dependency, Get, HttpResponseOK, OutputCache } from '@foal/core';
import { Project } from '../services/project.service';
import { System } from '../services/system.service';

export class ApiController {
  @dependency
  private projects: Project;
  @dependency
  private system: System;

  @OutputCache({ duration: 15 }) // 15 minutes
  @Get('/status')
  async getSystemInformation(ctx: Context) {
    const result = await this.system.doSomeHeavyTask();

    return new HttpResponseOK(result);
  }

  @OutputCache({ varyByParam: 'projectId' }) // Default duration (5 minutes?) - Cache key: projectId (param)
  @Get('/project/:projectId')
  async getResources(ctx: Context) {
    const resources = await this.projects.getResources(ctx.request.params.projectId);

    return new HttpResponseOK(resources);
  }
}

```

user: lcnvdl
issue_1038: state: open
title: Allow session stores to access information from the current request
body: I'm implementing a multi-tenant app where each tenant has its own database, and sessions should also be split between each database. I've written a custom session store, but as I am passing the tenant ID as a path parameter, the session store has no way to determine which database to use. For now, I have to basically re-implement sessions.
user: luxaritas
issue_917: state: open
title: [Social auth] Easy refresh token management
body: ## Issue

Currently, Foal allows users to be authenticated through social providers. Through social services, the application can authenticate users with Google, for example, and in return get user information as well as access and refresh tokens to communicate with the Google API.

**Issue 1**
However, there is no "easy" way to store securely the refresh token for later communication with the API. We can store the refresh token in the session using `ctx.session.set('refreshToken', tokens.refresh_token)` but then the token is saved in plain text in the database. This can cause security problems if the database is corrupted. For this reason, Foal should provide an easy way to encrypt and decrypt refresh tokens.

**Issue 2**
Once the refresh token is retrieved, in a later request for example, we still need to take a look at the Google API (or other providers API) to see how to get a new access token. This task could simply be handled by the framework.

## Possible solution

Add three new methods `encryptRefreshToken`, `decryptRefreshToken` and `refreshAndGetAccessToken` to each social service.

```typescript
export class AuthController {
  @dependency
  google: GoogleProvider;

  @dependency
  store: Store;

  @Get('/signin/google')
  redirectToGoogle() {
    return this.google.redirect({
      scopes: [
        'email', 'openid', 'profile',
        // Request access to view the user's YouTube account.
        'https://www.googleapis.com/auth/youtube.readonly'
      ]
    });
  }

  @Get('/signin/google/callback')
  @UseSessions({
    cookie: true,
    csrf: false,
  })
  async handleGoogleRedirection(ctx: Context) {
    const { userInfo } = await this.google.getUserInfo(ctx);

    if (!userInfo.email) {
      throw new Error('Google should have returned an email address.');
    }

    let user = await User.findOne({ email: userInfo.email });

    if (!user) {
      // If the user has not already signed up, then add them to the database.
      user = new User();
      user.email = userInfo.email;
      await user.save();
    }

    ctx.session.setUser(user);
    ctx.session.set('refreshToken', this.google.encryptRefreshToken(tokens.refresh_token))

    return new HttpResponseRedirect('/');
  }

}
```

```typescript
export class ApiController {
  @dependency
  google: GoogleProvider;

  @Get('/youtube-activities')
  @UseSessions({ cookie: true })
  async getYouTubeActivities(ctx: Context) {
    const encryptedRefreshToken = ctx.session.get<string|undefined>('refreshToken');
    if (!encryptedRefreshToken) {
      throw new Error('Refresh token not found');
    }

    const refreshToken = this.google.decryptRefreshToken(encryptedRefreshToken);

    const accessToken = await this.google.refreshAndGetAccessToken(refreshToken);

    const response = await fetch('https://www.googleapis.com/youtube/v3/activities', {
      headers: { 'Authorization': `Bearer ${accessToken}` }
    })

    const body = await response.json();

    if (!response.ok) {
      throw new Error(body);
    }

    return new HttpResponseOK(body);
  }

}
```

user: LoicPoullain
issue_655: state: open
title: Email & password reset
body: # Issue

Resetting passwords is something common. Maybe Foal should provide components to be able to do it with an email sending.

# Resources

https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Forgot_Password_Cheat_Sheet.md
user: LoicPoullain
issue_525: state: open
title: Remembering users?
body: Although the framework provides authenticating and fetching user from database, it seems to miss `remember me` functionality. Would be great if there was a built-in way to do this.

Laravel provides a layer called `Auth` for authenticating user and dealing with its state even permission gates. Again, I am not forcing anybody to follow laravel in every step, but there are proven benefits on their abstraction. Checkout these:
https://github.com/laravel/framework/blob/5.8/src/Illuminate/Auth/
https://laravel.com/docs/5.8/authentication#remembering-users
https://laravel.com/docs/4.2/upgrade#upgrade-4.1.26
user: OrkhanAlikhanov
issue_490: state: open
title: What do you like in FoalTS?
body: Hello, everyone!

Version 1 is finally out and so I will be able to **do more communication** on the framework!

To do this, I'd like to know what *you* like/love about FoalTS. Are there any key features, design or concepts that are important to you? Did you try other frameworks before using Foal and why did you choose this one over another? And finally, how did you hear about FoalTS? 

It will really help me to talk about the framework in the future and make it better known. Any feedback, whether long or short, is appreciated! 👍 
user: LoicPoullain