If your Lambda function has **timeouts**, please read this section.
@@ -53,7 +99,7 @@ When possible, an alternative to NAT Gateways is to split the work done by a lam
Finally, another free alternative to NAT Gateway is to access AWS services by creating "*private VPC endpoints*": this is possible for S3, API Gateway, [and more](https://docs.aws.amazon.com/en_pv/vpc/latest/userguide/vpc-endpoints-access.html).
-## Creating a database
+### Creating a database
In the [RDS console](https://console.aws.amazon.com/rds/home):
@@ -67,7 +113,7 @@ Tips to better control costs:
- switch storage to "General Purpose (SSD)" for lower costs
- you can disable "enhanced monitoring" to avoid the associated costs
-## Accessing the database from PHP
+### Accessing the database from PHP
To retrieve the information needed to let AWS Lambda access the database go into [the RDS dashboard](https://console.aws.amazon.com/rds/home#databases:) (or the [Bref Dashboard](https://dashboard.bref.sh/?ref=bref)) and open the database you created.
@@ -122,11 +168,11 @@ To learn how to properly store this connection string in your configuration head
Also refer to the [Extensions](/docs/environment/php.mdx#extensions) section to see if you need to enable any database-specific extensions.
-### Learn more
+#### Learn more
You can learn more about limitations and guidelines from the AWS documentation about [Configuring a lambda to access resources in a VPC](https://docs.aws.amazon.com/lambda/latest/dg/vpc.html).
-## Accessing the database from your machine
+### Accessing the database from your machine
A database in a VPC cannot be accessed from the outside, i.e. the internet. You cannot connect to it via tools like MySQL Workbench.
diff --git a/docs/environment/database/cloud-db-create.png b/docs/environment/database/cloud-db-create.png
new file mode 100644
index 000000000..116927aaa
Binary files /dev/null and b/docs/environment/database/cloud-db-create.png differ
diff --git a/docs/environment/logs.mdx b/docs/environment/logs.mdx
index 148024464..4a8d6c096 100644
--- a/docs/environment/logs.mdx
+++ b/docs/environment/logs.mdx
@@ -3,7 +3,6 @@ import { Tab, Tabs } from 'nextra/components';
import { Callout } from 'nextra/components';
import Image from 'next/image';
import brefCloudLogs from '../cloud/logs.png';
-import Link from 'next/link';
diff --git a/docs/environment/php.mdx b/docs/environment/php.mdx
index fabb6b2ad..3c2295656 100644
--- a/docs/environment/php.mdx
+++ b/docs/environment/php.mdx
@@ -73,6 +73,7 @@ The following extensions are installed and enabled by default in Bref runtimes:
PDO
pdo_sqlite
pdo_mysql
+ pdo_pgsql
Phar
posix
readline
@@ -98,14 +99,16 @@ The following extensions are installed in Bref runtimes, but disabled by default
- **[intl](https://www.php.net/manual/en/intro.intl.php)** - Internationalization extension (referred as Intl) is a wrapper for ICU library, enabling PHP programmers to perform various locale-aware operations.
- **[APCu](https://www.php.net/manual/en/intro.apcu.php)** - APCu is APC stripped of opcode caching.
-- **[PostgreSQL PDO Driver](https://www.php.net/manual/en/ref.pdo-pgsql.php)** - PDO_PGSQL is a driver that implements the PHP Data Objects (PDO) interface to enable access from PHP to PostgreSQL databases.
+- **[Redis](https://github.com/phpredis/phpredis)** - A PHP extension for interfacing with Redis.
+- **[soap](https://www.php.net/manual/en/book.soap.php)** - SOAP client and server for PHP
You can enable these extensions by loading them in `php/conf.d/php.ini` (as mentioned in [the section above](#phpini)), for example:
```ini filename="php/conf.d/php.ini"
extension=intl
extension=apcu
-extension=pdo_pgsql
+extension=redis
+extension=soap
```
### Extra extensions
@@ -133,7 +136,7 @@ To create your custom layer, you will need to:
To compile the extension, Bref provides the `bref/build-php-*` Docker images. Here is an example with Blackfire:
```dockerfile
-FROM bref/build-php-80:2
+FROM bref/build-php-84:2
RUN curl -A "Docker" -o /tmp/blackfire.so -L -s "https://packages.blackfire.io/binaries/blackfire-php/1.42.0/blackfire-php-linux_amd64-php-74.so"
diff --git a/docs/environment/serverless-yml.mdx b/docs/environment/serverless-yml.mdx
index 18815399c..35934e5df 100644
--- a/docs/environment/serverless-yml.mdx
+++ b/docs/environment/serverless-yml.mdx
@@ -22,7 +22,7 @@ plugins:
functions:
foo:
handler: index.php
- runtime: php-81
+ runtime: php-84
resources:
Resources:
@@ -65,7 +65,7 @@ The `provider` section also lets us configure global options on all functions:
```yaml
provider:
name: aws
- runtime: php-81
+ runtime: php-84
timeout: 10
functions:
@@ -86,11 +86,11 @@ provider:
functions:
foo:
handler: foo.php
- runtime: php-81
+ runtime: php-84
timeout: 10
bar:
handler: bar.php
- runtime: php-81
+ runtime: php-84
timeout: 10
# ...
@@ -136,10 +136,10 @@ Read more about the `package` configuration [in the serverless.yml documentation
functions:
foo:
handler: foo.php
- runtime: php-81
+ runtime: php-84
bar:
handler: bar.php
- runtime: php-81
+ runtime: php-84
```
Functions are AWS Lambda functions. You can find all options available [in this Serverless documentation page](https://serverless.com/framework/docs/providers/aws/guide/functions/).
diff --git a/docs/environment/variables-create-secret.png b/docs/environment/variables-create-secret.png
index 45406f962..c3430bdf9 100644
Binary files a/docs/environment/variables-create-secret.png and b/docs/environment/variables-create-secret.png differ
diff --git a/docs/environment/variables.mdx b/docs/environment/variables.mdx
index 4c634bd53..898779f36 100644
--- a/docs/environment/variables.mdx
+++ b/docs/environment/variables.mdx
@@ -1,4 +1,4 @@
-import { Callout } from 'nextra/components';
+import { Callout, Tab, Tabs } from 'nextra/components';
import { NextSeo } from 'next-seo';
@@ -42,25 +42,42 @@ Instead, you can use the [SSM parameter store](https://docs.aws.amazon.com/syste
### Creating secrets
-To create a parameter, you can do it via the [AWS SSM console](https://console.aws.amazon.com/systems-manager/parameters) or the [Bref Dashboard](https://dashboard.bref.sh/):
+
+
+ Create secrets via [Bref Cloud](https://bref.cloud).
-
+ If you have **not** deployed the application yet, go to the root "Secrets" section in Bref Cloud and create a new secret there ([bref.cloud/secrets/create](https://bref.cloud/secrets/create)). Provide the target application and environment name when creating the secret.
-You can also do it in the CLI via the following command:
+ If you have already deployed the application, open the application in Bref Cloud, go to a specific environment, and create a new secret under the "Secrets" tab:
-```bash
-aws ssm put-parameter --region us-east-1 --name '/my-app/my-parameter' --type String --value 'mysecretvalue'
-```
+ 
-On Windows, the first part of the path needs to be double slashes and all subsequent forward slashes changed to backslashes:
+ You can also run the `bref secret:create` command in your terminal:
-```bash
-aws ssm put-parameter --region us-east-1 --name '//my-app\my-parameter' --type String --value 'mysecretvalue'
-```
+ ```bash
+ bref secret:create
+ ```
+
+ You can also run the command outside of a project: `bref secret:create --app=app-name --env=env-name --team=team-slug`.
+
+
+ Create a parameter via the [AWS SSM console](https://console.aws.amazon.com/systems-manager/parameters) or the `aws` CLI:
+
+ ```bash
+ aws ssm put-parameter --region us-east-1 --name '/my-app/my-parameter' --type String --value 'mysecretvalue'
+ ```
+
+ On Windows, the first part of the path needs to be double slashes and all subsequent forward slashes changed to backslashes:
+
+ ```bash
+ aws ssm put-parameter --region us-east-1 --name '//my-app\my-parameter' --type String --value 'mysecretvalue'
+ ```
-It is recommended to prefix the parameter name with your application name, for example: `/my-app/my-parameter`.
+ It is recommended to prefix the parameter name with your application name, for example: `/my-app/my-parameter`.
-SSM also allows to store a SecureString parameter, which is encrypted with AWS KMS. To use a SecureString, simply change the `--type` argument to `--type SecureString`. Bref takes care of decrypting the value.
+ SSM also allows to store a SecureString parameter, which is encrypted with AWS KMS. To use a SecureString, simply change the `--type` argument to `--type SecureString`. Bref takes care of decrypting the value.
+
+
### Retrieving secrets
diff --git a/docs/index.mdx b/docs/index.mdx
index 6ea54835c..df96eaca5 100644
--- a/docs/index.mdx
+++ b/docs/index.mdx
@@ -10,7 +10,7 @@ Serverless means using cloud services that manage the servers for us.
When running PHP on a server, we must:
-- setup, configure and maintain that server,
+- set up, configure, and maintain that server,
- pay a fixed price for the server,
- scale the server(s) if we get more traffic.
@@ -20,48 +20,40 @@ When running PHP serverless:
- We pay only for what we use (per request).
- Our application scales automatically.
-**Serverless provides more scalable, affordable and reliable architectures for less effort.**
+**Serverless provides more scalable, affordable, and reliable architectures with less effort.**
Serverless includes services like storage as a service, database as a service, message queue as a service, etc. One service in particular is interesting for us developers: *Function as a Service* (FaaS).
-FaaS is a way to run code where the hosting provider takes care of setting up everything, keeping the application available 24/7, scaling it up and down and we are only charged *while the code is actually executing*.
+FaaS is a way to run code where the hosting provider takes care of setting up everything, keeping the application available 24/7, scaling it up and down, and we are only charged *while the code is actually executing*.
## Why Bref?
Bref aims to make running PHP applications simple.
-To reach that goal, Bref takes advantage of serverless technologies. However, while serverless is promising, there are many choices to make, tools to build and best practices to figure out.
+To reach that goal, Bref takes advantage of serverless technologies. However, while serverless is promising, there are many choices to make, tools to build, and best practices to figure out.
-Bref's approach is to:
-
-- **simplify problems by removing choices**
-
- *instead of trying to address every need*
-- **provide simple and familiar solutions**
-
- *instead of aiming for powerful custom solutions*
-- **empower by sharing knowledge**
-
- *instead of hiding too much behind leaky abstractions*
+Bref provides extensive documentation and an entire toolkit to make serverless approachable and easy to use.
### What is Bref
-Bref (which means "brief" in french) comes as an open source Composer package and helps you deploy PHP applications to [AWS](https://aws.amazon.com) and run them on [AWS Lambda](https://aws.amazon.com/lambda/).
+Bref (which means "brief" in French) comes as an open source Composer package and helps you deploy PHP applications to [AWS](https://aws.amazon.com) and run them on [AWS Lambda](https://aws.amazon.com/lambda/). It also makes it easy to use other AWS services (like S3, RDS, SQS…) for file storage, databases, etc.
Bref provides:
- documentation
- PHP runtimes for AWS Lambda
- deployment tooling
-- PHP frameworks integration
+- integrations for Laravel and Symfony
+
+The choice of AWS is deliberate: at the moment, AWS is the leading hosting provider, it is ahead in the serverless space in terms of features, performance, and reliability. AWS combines the advantages of being an extremely safe choice for hosting while providing the most advanced serverless solution.
-The choice of AWS as serverless provider is deliberate: at the moment AWS is the leading hosting provider, it is ahead in the serverless space in terms of features, performance and reliability.
+Bref configures and deploys applications to AWS using [the `serverless` CLI](https://github.com/oss-serverless/serverless). Being the most popular tool, `serverless` comes with a huge community, a lot of examples online, and a simple configuration format.
-Bref uses [the Serverless framework](https://serverless.com/) to configure and deploy serverless applications. Being the most popular tool, Serverless comes with a huge community, a lot of examples online and a simple configuration format.
+If you want to learn [how AWS Lambda and Bref work, read more here](/docs/how-it-works).
## Use cases
-Bref and AWS Lambda can be used to run many kind of PHP application, for example:
+Bref and AWS Lambda can be used to run many kinds of PHP applications, for example:
- APIs
- websites
@@ -71,7 +63,48 @@ Bref and AWS Lambda can be used to run many kind of PHP application, for example
Bref aims to support any PHP framework. It comes with deep integrations with Laravel and Symfony.
-If you are interested in real-world examples as well as cost analyses head over to the [**Case Studies** page](/docs/case-studies.md).
+If you are interested in real-world examples as well as cost analyses, head over to the [**Case Studies** page](/docs/case-studies.md).
+
+## Adapting to serverless
+
+> Do PHP applications need to be adapted to run serverless?
+
+In general no, but it depends on where you're coming from.
+
+Running PHP applications serverless comes with roughly the same constraints as running an application in auto-scaled containers.
+
+- The application code is mounted as read-only on disk.
+- Since the application scales horizontally to run in multiple "instances" (like containers), all these instances have independent and ephemeral filesystems.
+- Logs must not be written to disk, instead they must be sent to a centralized system (on AWS Lambda, logs written to `stderr` are automatically centralized in AWS CloudWatch, so this is usually a one-line config change).
+- Sessions must not be written to disk, instead they must be stored in a centralized system (e.g. the database or Redis).
+- Database and cache services (e.g. MySQL and Redis) must not run on the same server/container as PHP; instead, they must run in separate servers or containers (e.g. run databases in AWS RDS, Redis in AWS ElastiCache…).
+- Uploaded files and generated files (e.g. CSV exports, PDF files…) must be stored in a centralized system (e.g. AWS S3).
+- You can use the filesystem as a cache, but each instance of the application will then have a separate cache since the filesystem is not shared.
+
+If these sound familiar to you, good news: your application is ready for serverless.
+
+If your application is currently not set up like this, good news: preparing for serverless means you are actually preparing for a horizontally scalable application. These points are not "serverless-specific".
+
+### Serverless-specific constraints
+
+There are still a few serverless-specific constraints to be aware of:
+
+- About 0.3% of all requests in production are ["cold starts"](/docs/environment/performances.mdx#cold-starts), i.e. slower requests (AWS Lambda scaling up) that can add 200 ms to 500 ms (or even more on very large applications) to the HTTP response time.
+
+ If your application cannot tolerate that occasional latency at the p99 metric, then serverless might not be the best fit.
+- AWS Lambda has a limit of ~4 MB for HTTP requests/uploaded files.
+
+ If your application needs to support uploading larger files, a better option is to update your JavaScript frontend to upload files directly to AWS S3 via S3 pre-signed URLs (Laravel has helpers to generate these URLs for example).
+
+- We do not run long-running processes on AWS Lambda, like queue workers or websocket servers.
+
+ For queue workers, this is actually great: SQS and Lambda integrate natively so that we don't have to run workers (or even think about them). Bref does the rest of the job to integrate natively with Laravel Queues or Symfony Messenger. More on this in the rest of the Bref documentation.
+
+ For websocket servers, this means we cannot run servers like Ratchet or Laravel Reverb on Lambda. It is possible to run this on the side in an AWS EC2 server, or in a container in ECS, but this is extra setup. An alternative is to use the native API Gateway WebSocket feature; however, this is not well documented in Bref at the moment.
+
+- AWS Lambda has a maximum execution time limit of 15 minutes *per invocation*.
+
+ Note that this limit applies "per invocation", i.e. per HTTP request, per SQS job, per CLI command, per cron task, etc. That does mean you cannot have one job or a PHP script running for more than 15 minutes. If you do, you can either try to split these tasks into smaller jobs, or run longer tasks in EC2 or ECS separately.
## Maturity matrix
@@ -106,7 +139,7 @@ This matrix will be updated as Bref and AWS services evolve over time.
- API
+ APIs
@@ -118,7 +151,7 @@ This matrix will be updated as Bref and AWS services evolve over time.
- Website
+ Websites
@@ -130,7 +163,7 @@ This matrix will be updated as Bref and AWS services evolve over time.
- Legacy application
+ Legacy applications
@@ -153,6 +186,18 @@ This matrix will be updated as Bref and AWS services evolve over time.
+
+ WebSockets
+
+
+
+
+
+
+
+
+
+
Real-time applications
@@ -182,14 +227,14 @@ This matrix will be updated as Bref and AWS services evolve over time.
Legend:
- Good use case
+ Good use case
Some drawbacks
Strong limitations
- **Jobs, Cron**
- Jobs, cron tasks and batch processes are very good candidates for FaaS. The scaling model of AWS Lambda can lead to very high throughput in queue processing, and the pay-per-use billing model can sometimes result in drastic costs reduction.
+ Jobs, cron tasks, and batch processes are very good candidates for FaaS. The scaling model of AWS Lambda can lead to very high throughput in queue processing, and the pay-per-use billing model can sometimes result in drastic cost reductions.
Using Bref, it is possible to implement cron jobs and queue workers using PHP. Bref also provides integration with popular queue libraries, like Laravel Queues and Symfony Messenger.
@@ -199,24 +244,36 @@ This matrix will be updated as Bref and AWS services evolve over time.
APIs run on AWS Lambda without problems. Performance is now similar to what you could expect on a traditional VPS.
- The main difference to account for is that about 0.5% of HTTP requests are cold starts. If your use case requires that _all_ requests are handled below 10ms, serverless might not be a good fit.
+ The main difference to account for is that about 0.5% of HTTP requests are cold starts. If your use case requires that _all_ requests are handled in under 10 ms, serverless might not be a good fit.
- **Website**
- Websites run well on AWS Lambda. Assets can be stored in S3 and served via Cloudfront. This is documented in the ["Websites" documentation](/docs/use-cases/websites.mdx). Performance is as good as any server.
+ Websites run well on AWS Lambda. Assets can be stored in S3 and served via CloudFront. This is documented in the ["Websites" guide](/docs/use-cases/websites.mdx). Performance is as good as any server.
- **Legacy application**
- Migrating a legacy PHP application to Bref and Lambda can be a challenge. One could expect to rewrite some parts of the code to make the application fit for Lambda (or running in containers in general). For example, file uploads and sessions often need to be adapted to work with the read-only filesystem. Cron tasks, scripts or asynchronous jobs must be made compatible with Lambda and SQS.
+ Migrating a legacy PHP application to Bref and Lambda can be a challenge. You can expect to rewrite some parts of the code to make the application fit for Lambda (or running in containers in general). For example, file uploads and sessions often need to be adapted to work with the read-only file system. Cron tasks, scripts, or asynchronous jobs must be made compatible with Lambda and SQS.
+
+ Not impossible, but definitely not the easiest place to start. As a first step, you can follow the guidelines of [The Twelve-Factor App](https://12factor.net). Note that if your application already runs redundantly on multiple servers, it is much closer to being ready for AWS Lambda and the migration could be simple.
+
+- **Event-driven microservices**
+
+ Serverless is excellent for running event-driven microservice architectures. First of all, being able to standardize and orchestrate the deployment of multiple PHP microservices via a simple `serverless.yml` file and AWS CloudFormation simplifies deployments a lot. Every microservice can deploy in under a minute and easily reference other services or AWS resources. Each microservice then scales independently and in real time without thinking about provisioning or allocating resources, and while keeping costs aligned with usage (not paying for dozens or hundreds of idle containers).
+
+ On top of that, `serverless.yml` and CloudFormation offer the ability to deeply integrate with other AWS services like SQS, EventBridge, SNS, DynamoDB, and more.
+
+ Some teams also prefer to deploy everything with Terraform, which is less documented in Bref but doable for those experienced with Terraform.
+
+- **Websockets**
- Not impossible, but definitely not the easiest place to start. As a first step, you can follow the guidelines of [The Twelve-Factor App](https://12factor.net). Note that if your application already runs redundantly on multiple servers, it is much more ready for AWS Lambda and the migration could be simple.
+ It is possible to integrate PHP applications with API Gateway WebSocket. This has been done by several Bref users; however, this is currently not documented in Bref directly. On top of that, there is currently no native integration with Laravel Echo.
- **Real-time applications**
- Warm Lambda invocations are very fast (can be as low as 1ms), but cold starts can take 230ms or more. Cold starts are rare on most applications (less than 0.5% of invocations) and can be further mitigated with [provisioned concurrency](https://docs.aws.amazon.com/lambda/latest/dg/provisioned-concurrency.html), but it's unlikely to ensure they will _never_ happen. This makes Lambda a poor choice for real-time applications where latency must be below 100ms for 100% of requests.
+ Warm Lambda invocations are very fast (can be as low as 1 ms), but cold starts can take 200 ms or more. Cold starts are rare on most applications (less than 0.5% of invocations) and can be further mitigated with [provisioned concurrency](https://docs.aws.amazon.com/lambda/latest/dg/provisioned-concurrency.html), but it's unlikely you can ensure they will _never_ happen. This makes Lambda a poor choice for real-time applications where latency **must** be below 100 ms for 100% of requests.
## Getting started
Get started with Bref by reading the [installation documentation](/docs/setup.mdx).
-Want to know if Bref is a good fit for you? [Let's talk on Zoom](https://calendly.com/bref-enterprise/intro) (30 minutes, yes it's free, I'll answer any questions I can) or find me on [Slack](https://bref.sh/slack).
+Want to know if Bref is a good fit for you? Ask on [Slack](https://bref.sh/slack) in the `#help` channel.
diff --git a/docs/laravel/caching.mdx b/docs/laravel/caching.mdx
index 245a387c6..a2540325a 100644
--- a/docs/laravel/caching.mdx
+++ b/docs/laravel/caching.mdx
@@ -4,9 +4,9 @@ By default, the Bref bridge will move Laravel's storage and cache directories to
However, the `/tmp` directory isn't shared across Lambda instances. If you Lambda function scales up or is redeployed, the cache will be empty in new instances.
-If you want the cache to be shared across all Lambda instances, for example if your application caches a lot of data or if you use it for locking mechanisms (like API rate limiting), you can instead use Redis or DynamoDB.
+If you want the cache to be shared across all Lambda instances, for example if your application caches a lot of data or if you use it for locking mechanisms (like API rate limiting), you can instead use the database, Redis, or DynamoDB.
-DynamoDB is the easiest to set up and is "pay per use". Redis is a bit more complex as it requires a VPC and managing instances, but offers slightly faster response times.
+If you are using a database already, using it as the cache driver is the simplest option. DynamoDB is a good alternative: fairly easy to set up, and "pay per use". Redis is a bit more complex as it requires a VPC and managing instances, but offers slightly faster response times.
## DynamoDB Cache
diff --git a/docs/laravel/file-storage.mdx b/docs/laravel/file-storage.mdx
index c83de075b..9e33587ed 100644
--- a/docs/laravel/file-storage.mdx
+++ b/docs/laravel/file-storage.mdx
@@ -6,34 +6,153 @@ Laravel has a [filesystem abstraction](https://laravel.com/docs/filesystem) that
When running on Lambda, you will need to use the **`s3` adapter** to store files on AWS S3.
-To do this, set `FILESYSTEM_DISK: s3` either in `serverless.yml` or your production `.env` file. We can also create an S3 bucket via `serverless.yml` directly:
+## Quick setup with Lift
+
+The easiest way to set up S3 storage is using [Serverless Lift](https://github.com/getlift/lift):
+
+First install the Lift plugin:
+
+```bash
+serverless plugin install -n serverless-lift
+```
+
+Then use [the `storage` construct](https://github.com/getlift/lift/blob/master/docs/storage.md) in `serverless.yml`:
```yaml filename="serverless.yml"
-# ...
provider:
# ...
environment:
# environment variable for Laravel
FILESYSTEM_DISK: s3
- AWS_BUCKET: !Ref Storage
- iam:
- role:
- statements:
- # Allow Lambda to read and write files in the S3 buckets
- - Effect: Allow
- Action: s3:*
- Resource:
- - !Sub '${Storage.Arn}' # the storage bucket
- - !Sub '${Storage.Arn}/*' # and everything inside
-
-resources:
- Resources:
- # Create our S3 storage bucket using CloudFormation
- Storage:
- Type: AWS::S3::Bucket
+ AWS_BUCKET: ${construct:storage.bucketName}
+
+constructs:
+ storage:
+ type: storage
+```
+
+That's it! Lift automatically:
+
+- Creates the S3 bucket
+- Grants IAM permissions to your Lambda functions
+- Exposes the bucket name via `${construct:storage.bucketName}`
+
+The AWS credentials (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_SESSION_TOKEN) are set automatically in AWS Lambda, you don't have to define them.
+
+## Uploading files
+
+### Small files (< 6 MB)
+
+For files under 6 MB, you can upload directly through your Laravel application as usual:
+
+```php
+$request->file('document')->store('documents');
+```
+
+### Large files
+
+AWS Lambda has a **6MB request payload limit**. For larger files, you must upload directly to S3 from the browser using **presigned URLs**.
+
+How it works:
+
+1. Your frontend requests a presigned upload URL from your backend
+1. Your backend generates a temporary presigned URL using Laravel's Storage
+1. The frontend uploads the file directly to S3
+1. The frontend sends the S3 key back to your backend to save in the database
+
+Backend - Generate presigned URL:
+
+```php
+use Illuminate\Support\Facades\Storage;
+use Illuminate\Support\Str;
+
+public function presignedUploadUrl(): JsonResponse
+{
+ $key = 'tmp/' . Str::uuid() . '.pdf';
+
+ // Generate a presigned PUT URL valid for 15 minutes
+ $url = Storage::temporaryUploadUrl($key, now()->addMinutes(15));
+
+ return response()->json([
+ 'url' => $url,
+ 'key' => $key,
+ ]);
+}
+```
+
+Frontend - Upload to S3:
+
+```js
+// 1. Get presigned URL from your backend
+const { url, key } = await fetch('/api/presigned-upload-url', {
+ method: 'POST',
+ headers: { 'X-CSRF-TOKEN': csrfToken },
+}).then(r => r.json());
+
+// 2. Upload directly to S3
+await fetch(url, {
+ method: 'PUT',
+ body: file,
+ headers: { 'Content-Type': file.type },
+});
+
+// 3. Put the key in your form or send the key to your backend to save
+await fetch('/api/documents', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'X-CSRF-TOKEN': csrfToken,
+ },
+ body: JSON.stringify({ file_key: key }),
+});
+```
+
+Backend - Move file to final location:
+
+```php
+public function store(Request $request)
+{
+ $validated = $request->validate([
+ 'file_key' => 'required|string',
+ ]);
+
+ // Move from temporary location to final location
+ $finalPath = "documents/{$document->id}.pdf";
+ Storage::move($validated['file_key'], $finalPath);
+
+ // Save the final path in the database
+ $document->update(['file_path' => $finalPath]);
+}
+```
+
+
+ **Cleanup temporary files**: Files uploaded to `tmp/` but never moved (e.g., user abandons the form) will accumulate. Add an S3 lifecycle rule to auto-delete them:
+
+ ```yaml filename="serverless.yml"
+ constructs:
+ storage:
+ type: storage
+ lifecycleRules:
+ # Files in the `tmp/` folder are will be cleaned after 1 day
+ - prefix: tmp/
+ expirationInDays: 1
+ ```
+
+
+## Downloading files
+
+For private files, generate temporary presigned URLs:
+
+```php
+// Generate a presigned download URL valid for 15 minutes
+$url = Storage::temporaryUrl($document->file_path, now()->addMinutes(15));
+
+return response()->json(['download_url' => $url]);
```
-That's it! The AWS credentials (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_SESSION_TOKEN) are set automatically in AWS Lambda, you don't have to define them.
+The URL can be used directly in the browser or in an `` tag.
+
+For local development, Laravel's filesystem abstraction lets you use the same code locally and in production. Laravel [supports temporary URLs for local files](https://laravel.com/docs/filesystem#temporary-urls) since version 9.
## Public files
diff --git a/docs/laravel/getting-started.mdx b/docs/laravel/getting-started.mdx
index cc0b3e395..e2170001c 100644
--- a/docs/laravel/getting-started.mdx
+++ b/docs/laravel/getting-started.mdx
@@ -76,6 +76,10 @@ At the moment, we deployed our local codebase to Lambda. When deploying for prod
Follow [the deployment guide](/docs/deploy.md#deploying-for-production) for more details about deploying in general.
+
+ Most Laravel applications use `aws/aws-sdk-php` (pulled in by packages like SQS queues, S3 storage, etc.). This package is **very large** (100MB+) and can push your deployment over Lambda's 250MB size limit. Make sure to [remove unused AWS services](/docs/deploy.md#reducing-package-size) to reduce the deployment size.
+
+
Specifically for Laravel, Bref will automatically cache the configuration on "cold starts". This means that you don't need to run `php artisan config:cache` before deploying.
diff --git a/docs/laravel/octane.mdx b/docs/laravel/octane.mdx
index 5c83008c5..89e71368d 100644
--- a/docs/laravel/octane.mdx
+++ b/docs/laravel/octane.mdx
@@ -11,7 +11,7 @@ To run the HTTP application with [Laravel Octane](https://laravel.com/docs/10.x/
functions:
web:
handler: Bref\LaravelBridge\Http\OctaneHandler
- runtime: php-81
+ runtime: php-84
environment:
BREF_LOOP_MAX: 250
# ...
@@ -40,7 +40,7 @@ You can keep database connections persistent across requests to make your applic
functions:
web:
handler: Bref\LaravelBridge\Http\OctaneHandler
- runtime: php-81
+ runtime: php-84
environment:
BREF_LOOP_MAX: 250
OCTANE_PERSIST_DATABASE_SESSIONS: 1
diff --git a/docs/laravel/queues.mdx b/docs/laravel/queues.mdx
index 098882689..480fc41fb 100644
--- a/docs/laravel/queues.mdx
+++ b/docs/laravel/queues.mdx
@@ -39,7 +39,7 @@ constructs:
type: queue
worker:
handler: Bref\LaravelBridge\Queue\QueueHandler
- runtime: php-81
+ runtime: php-84
timeout: 60 # seconds
```
diff --git a/docs/local-development.mdx b/docs/local-development.mdx
index ceacbf6a0..aee7bc96a 100644
--- a/docs/local-development.mdx
+++ b/docs/local-development.mdx
@@ -42,7 +42,7 @@ version: "3.5"
services:
app:
- image: bref/php-81-fpm-dev:2
+ image: bref/php-84-dev:3
ports: [ '8000:8000' ]
volumes:
- .:/var/task
@@ -62,7 +62,7 @@ The application will be available at [http://localhost:8000/](http://localhost:8
The `HANDLER` environment variable lets you define which PHP file will be handling all HTTP requests. This should be the same handler that you have defined in `serverless.yml` for your HTTP function.
-> Currently, the Docker image support only one PHP handler. If you have multiple HTTP functions in `serverless.yml`, you can duplicate the service in `docker-compose.yml` to have one container per lambda function.
+> Currently, the Docker image supports only one PHP handler. If you have multiple HTTP functions in `serverless.yml`, you can duplicate the service in `docker-compose.yml` to have one container per lambda function.
### Read-only filesystem
diff --git a/docs/local-development/event-driven-functions.mdx b/docs/local-development/event-driven-functions.mdx
index d7464c3ef..58e4249b1 100644
--- a/docs/local-development/event-driven-functions.mdx
+++ b/docs/local-development/event-driven-functions.mdx
@@ -30,7 +30,7 @@ return function (array $event) {
functions:
hello:
handler: my-function.php
- runtime: php-81
+ runtime: php-84
```
You can invoke it with or without event data:
@@ -86,10 +86,10 @@ Hello Alex
If you want to run your function in Docker:
```bash
-$ docker run --rm -it --entrypoint= -v $(PWD):/var/task:ro bref/php-81:2 vendor/bin/bref-local my-function.php
+$ docker run --rm -it --entrypoint= -v $(PWD):/var/task:ro bref/php-84:3 vendor/bin/bref-local my-function.php
-# You can also use the `dev` images for a simpler command (and Xdebug and Blackfire in the image):
-$ docker run --rm -it -v $(PWD):/var/task:ro bref/php-81-fpm-dev:2 vendor/bin/bref-local my-function.php
+# You can also use the `dev` images for a simpler command (and Xdebug in the image):
+$ docker run --rm -it -v $(PWD):/var/task:ro bref/php-84-dev:3 vendor/bin/bref-local my-function.php
```
You can also use Docker Compose, like described in [Local development for HTTP applications](../local-development.mdx):
@@ -98,7 +98,7 @@ You can also use Docker Compose, like described in [Local development for HTTP a
version: "3.5"
services:
app:
- image: bref/php-81-fpm-dev:2
+ image: bref/php-84-dev:3
volumes:
- .:/var/task
```
diff --git a/docs/monitoring.mdx b/docs/monitoring.mdx
new file mode 100644
index 000000000..8fb935d82
--- /dev/null
+++ b/docs/monitoring.mdx
@@ -0,0 +1,74 @@
+import Image from 'next/image';
+import cloudXrayTrace from './monitoring/cloud-xray-trace.png';
+import cloudXrayFiltersGeneral from './monitoring/cloud-xray-filters-general.png';
+import cloudXrayFiltersAnnotations from './monitoring/cloud-xray-filters-annotations.png';
+import cloudOverview from './monitoring/cloud-overview.png';
+import cloudLogs from './monitoring/cloud-logs.png';
+
+# Monitoring
+
+By default, AWS Lambda publishes PHP logs and metrics to [AWS CloudWatch](https://aws.amazon.com/cloudwatch/). These include HTTP response times, code execution duration, error rates, and more.
+
+Here is a summary of recommended tools for monitoring Bref applications:
+
+- **Logs and metrics**: CloudWatch (built-in), [Bref Cloud](/cloud)
+- **Error tracking**: [Sentry](https://sentry.io) and similar services
+- **Performance tracing**: [Bref Cloud](/cloud) with [X-Ray](/xray)
+
+Let's dive into the details of each of them.
+
+## Sentry
+
+[Sentry](https://sentry.io) is a popular error tracking service. It works well out of the box with Bref for HTTP applications: install the [Sentry SDK for PHP](https://docs.sentry.io/platforms/php/) (or the [Laravel](https://docs.sentry.io/platforms/php/guides/laravel/) or [Symfony](https://docs.sentry.io/platforms/php/guides/symfony/) integrations) and errors will be tracked automatically.
+
+For more advanced use cases, such as tracking Lambda errors outside of PHP-FPM (timeouts, oversized responses…), monitoring event-driven handlers (SQS, EventBridge, S3…), or tracking cold starts and AWS SDK calls, the [Bref Sentry package](/sentry) extends Sentry's capabilities for AWS Lambda. It is available as a [separate license](/sentry).
+
+## Bref Cloud
+
+[Bref Cloud](/cloud) provides an all-in-one monitoring experience for serverless PHP applications:
+
+
+
+- **Logs**: view and search CloudWatch logs in a simplified UI.
+
+
+
+- **Metrics**: monitor Lambda invocations, duration, errors, and more.
+- **Traces**: visualize X-Ray traces to understand the performance of your application, including database queries, HTTP calls, and AWS SDK calls.
+
+
+
+With the [Bref X-Ray](/xray) package, traces are enriched with annotations that you can use to filter and search. For example, you can filter traces by specific controller, route, CLI command, or job class:
+
+
+
+
+
+
+Bref Cloud users get a **free [Bref X-Ray](/xray) license** included in their plan to enable performance tracing. To activate it, contact support via [bref.cloud/support](https://bref.cloud/support) or [Slack](https://bref.sh/slack).
+
+[Learn more about Bref Cloud](/cloud).
+
+## X-Ray
+
+[AWS X-Ray](https://aws.amazon.com/xray/) provides distributed tracing for Lambda applications. The [Bref X-Ray package](/xray) integrates X-Ray with PHP, tracking cold starts, database queries, HTTP calls, AWS SDK calls, and more. It supports both Laravel and Symfony.
+
+The package can be used with or without Bref Cloud. Bref Cloud users get a free license (see above), while others can [purchase a standalone license](/xray).
+
+## Sentry Lambda package
+
+As mentioned above, the standard Sentry SDK works great for HTTP applications. The [Bref Sentry package](/sentry) goes further by adding Lambda-specific capabilities: tracking errors outside of PHP-FPM, monitoring event-driven handlers, and tracking cold starts.
+
+The package can be used with or without Bref Cloud. It is available as a [standalone license](/sentry).
+
+## Bref Dashboard
+
+The [Bref Dashboard](https://dashboard.bref.sh/?ref=bref) is an alternative for projects that do not use Bref Cloud. It fetches data from AWS CloudWatch and provides a simple UI for logs and metrics. It requires no setup in AWS and can be used straight away.
+
+[](https://dashboard.bref.sh/?ref=bref)
+
+## Tideways
+
+[Tideways](https://tideways.com/?ref=bref) is a PHP-specific monitoring and profiling tool that can be used with Bref. It requires setting up a daemon on an EC2 instance in a VPC.
+
+[Learn more about using Tideways with Bref](./monitoring/tideways.md).
diff --git a/docs/monitoring/_meta.json b/docs/monitoring/_meta.json
new file mode 100644
index 000000000..2c53c986a
--- /dev/null
+++ b/docs/monitoring/_meta.json
@@ -0,0 +1,5 @@
+{
+ "tideways": {
+ "display": "hidden"
+ }
+}
\ No newline at end of file
diff --git a/docs/monitoring/cloud-logs.png b/docs/monitoring/cloud-logs.png
new file mode 100644
index 000000000..3c5c317aa
Binary files /dev/null and b/docs/monitoring/cloud-logs.png differ
diff --git a/docs/monitoring/cloud-overview.png b/docs/monitoring/cloud-overview.png
new file mode 100644
index 000000000..0082f1c75
Binary files /dev/null and b/docs/monitoring/cloud-overview.png differ
diff --git a/docs/monitoring/cloud-xray-filters-annotations.png b/docs/monitoring/cloud-xray-filters-annotations.png
new file mode 100644
index 000000000..ccc095b81
Binary files /dev/null and b/docs/monitoring/cloud-xray-filters-annotations.png differ
diff --git a/docs/monitoring/cloud-xray-filters-general.png b/docs/monitoring/cloud-xray-filters-general.png
new file mode 100644
index 000000000..d21431a79
Binary files /dev/null and b/docs/monitoring/cloud-xray-filters-general.png differ
diff --git a/docs/monitoring/cloud-xray-trace.png b/docs/monitoring/cloud-xray-trace.png
new file mode 100644
index 000000000..0d718d2c9
Binary files /dev/null and b/docs/monitoring/cloud-xray-trace.png differ
diff --git a/docs/monitoring.md b/docs/monitoring/tideways.md
similarity index 70%
rename from docs/monitoring.md
rename to docs/monitoring/tideways.md
index 1c4614b83..db9f3b8e0 100644
--- a/docs/monitoring.md
+++ b/docs/monitoring/tideways.md
@@ -1,33 +1,4 @@
-# Monitoring
-
-By default, AWS Lambda publishes all logs and general metrics (HTTP response time, code execution duration, etc.) to AWS CloudWatch.
-
-It is possible to view these logs and metrics directly in the [AWS console](https://us-east-1.console.aws.amazon.com/cloudwatch/home?region=us-east-1). However, the CloudWatch UI can be complex and overwhelming.
-
-As an alternative, we can use [Bref Cloud](/cloud) or the [Bref Dashboard](https://dashboard.bref.sh/?ref=bref) to view these logs and metrics. It provides a simpler UI designed for serverless PHP applications.
-
-For advanced metrics and profiling, we can use [Tideways](https://tideways.com/?ref=bref), or [Sentry's performance monitoring](/sentry). Note that [Serverless.com's Dashboard](https://www.serverless.com/) is not compatible with PHP.
-
-To summarize:
-
-- **General monitoring**: [Bref Cloud](/cloud), CloudWatch, or [Bref Dashboard](https://dashboard.bref.sh/?ref=bref)
-- **Advanced monitoring and profiling**: [Tideways](https://tideways.com/?ref=bref), [Sentry](/sentry)
-
-## Bref Cloud
-
-[Bref Cloud](/cloud) is an all-in-one platform for serverless PHP applications. It provides a simple UI to view logs, metrics, and errors, and it is designed specifically for PHP applications running on AWS Lambda.
-
-[Learn more about Bref Cloud](/cloud).
-
-## Bref Dashboard
-
-As mentioned above, the [Bref Dashboard](https://dashboard.bref.sh/?ref=bref) fetches data from AWS CloudWatch (which is published by default by all serverless applications). As such, it requires no setup in AWS and can be used straight away.
-
-[](https://dashboard.bref.sh/?ref=bref)
-
-## Tideways
-
-> Disclaimer: Tideways is a Bref sponsor ❤️
+# Monitoring with Tideways
To use [Tideways](https://tideways.com/?ref=bref) with Bref, we first need to [create a Tideways account](https://app.tideways.io/register/).
@@ -38,17 +9,17 @@ Next, we will need to set up two pieces:
Indeed, the PHP extension runs in the same process as the PHP application and collects traces and advanced metrics. It then sends this data to a Tideways daemon, that will collect it and forward it to tideways.com. That ensures the PHP extension does not add latency to the PHP application.
-
+
The connexion between the PHP extension and the daemon needs to be secured. This is why the PHP lambda and the EC2 instance need to run in a VPC (virtual private network), and the EC2 instance should only be reachable from inside the VPC.
-### Complete example
+## Complete example
The sections below describe how to set up the daemon and PHP extension manually.
Alernatively, you can have a look at a complete and deployable example: [github.com/tideways/bref-tideways-example](https://github.com/tideways/bref-tideways-example). In this example, we deploy the PHP application, the VPC and the daemon in one command via `serverless.yml`.
-### Setting up the daemon
+## Setting up the daemon
Assuming we already have a VPC set up (the [serverless-vpc-plugin](https://github.com/smoketurner/serverless-vpc-plugin) is a good solution to create one), the daemon must be started in the VPC.
@@ -73,7 +44,7 @@ Assuming we already have a VPC set up (the [serverless-vpc-plugin](https://githu
Once the daemon has started, copy its "Private IP DNS name", we will use it to configure the PHP application.
-### Setting up the PHP application
+## Setting up the PHP application
First, let's install the Tideways PHP extension (it is distributed via the Bref extra extensions):
@@ -97,9 +68,9 @@ functions:
my-function:
handler: index.php
layers:
- - ${bref:layer.php-81-fpm}
+ - ${bref:layer.php-84-fpm}
# Add this line:
- - ${bref-extra:tideways-php-81}
+ - ${bref-extra:tideways-php-84}
```
> Make sure to use the same PHP version as the one for the PHP layer.
@@ -125,7 +96,7 @@ provider:
```
> **Note**:
->
+>
> The `TIDEWAYS_CONNECTION` variable should contain the "Private IP DNS name" of the Tideways daemon (for example `tcp://ip-172-31-4-74.eu-west-1.compute.internal:9135`). This is the value you retrieved in the previous section.
Don't forget to redeploy the application:
diff --git a/docs/runtimes.mdx b/docs/runtimes.mdx
index 095b2ea3c..59fdae1c8 100644
--- a/docs/runtimes.mdx
+++ b/docs/runtimes.mdx
@@ -23,7 +23,7 @@ The runtimes are available as AWS Lambda layers that you can use (explained belo
### PHP-FPM runtime for web apps
-Name: `php-84-fpm`, `php-83-fpm`, `php-82-fpm`, `php-81-fpm`, and `php-80-fpm`.
+Name: `php-85-fpm`, `php-84-fpm`, `php-83-fpm`, and `php-82-fpm`.
This runtime uses PHP-FPM to run **web applications** on AWS Lambda, like on a traditional server.
@@ -33,7 +33,7 @@ It's **the easiest to start with**: it works like traditional PHP hosting and is
### Event-driven functions
-Name: `php-84`, `php-83`, `php-82`, `php-81`, and `php-80`.
+Name: `php-85`, `php-84`, `php-83`, and `php-82`.
AWS Lambda was initially created to run _functions_ (yes, functions of code) in the cloud.
@@ -49,7 +49,7 @@ This runtime works great to create **event-driven micro-services**.
### Console
-Name: `php-84-console`, `php-83-console`, `php-82-console`, `php-81-console`, and `php-80-console`.
+Name: `php-85-console`, `php-84-console`, `php-83-console`, and `php-82-console`.
This runtime lets you run CLI console commands on Lambda.
@@ -70,33 +70,30 @@ plugins:
functions:
hello:
# ...
- runtime: php-81
+ runtime: php-84
# or:
- runtime: php-81-fpm
+ runtime: php-84-fpm
# or:
- runtime: php-81-console
+ runtime: php-84-console
```
-Bref currently provides runtimes for PHP 8.0, 8.1, 8.2, 8.3 and 8.4:
+Bref currently provides runtimes for PHP 8.2, 8.3, 8.4, and 8.5:
+- `php-85`
- `php-84`
- `php-83`
- `php-82`
-- `php-81`
-- `php-80`
+- `php-85-fpm`
- `php-84-fpm`
- `php-83-fpm`
- `php-82-fpm`
-- `php-81-fpm`
-- `php-80-fpm`
+- `php-85-console`
- `php-84-console`
- `php-83-console`
- `php-82-console`
-- `php-81-console`
-- `php-80-console`
- `php-80` means PHP 8.0.\*. It is not possible to require a specific "patch" version. The latest Bref versions always aim to support the latest PHP versions, so upgrade via Composer frequently to keep PHP up to date.
+ `php-84` means PHP 8.4.\*. It is not possible to require a specific "patch" version. The latest Bref versions always aim to support the latest PHP versions, so upgrade via Composer frequently to keep PHP up to date.
### The Bref plugin for serverless.yml
@@ -108,7 +105,7 @@ plugins:
- ./vendor/bref/bref
```
-This plugin is what makes `runtime: php-81` work (as well as other utilities). It is explained in more details in the section below.
+This plugin is what makes `runtime: php-84` work (as well as other utilities). It is explained in more details in the section below.
### ARM runtimes
@@ -120,7 +117,7 @@ You can deploy to ARM by using the `arm64` architecture:
functions:
api:
handler: public/index.php
- runtime: php-81-fpm
+ runtime: php-84-fpm
+ architecture: arm64
```
@@ -140,7 +137,7 @@ What the Bref plugin for `serverless.yml` (the one we include with `./vendor/bre
functions:
hello:
# ...
- runtime: php-81
+ runtime: php-84
```
into this:
@@ -149,45 +146,43 @@ into this:
functions:
hello:
# ...
- runtime: provided.al2
+ runtime: provided.al2023
layers:
- - 'arn:aws:lambda:us-east-1:534081306603:layer:php-81:21'
+ - 'arn:aws:lambda:us-east-1:873528684822:layer:php-84:21'
```
-☝️ `provided.al2` [is the generic Linux environment for custom runtimes](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-custom.html#runtimes-custom-use), and the `layers` config points to Bref's AWS Lambda layers.
+☝️ `provided.al2023` [is the generic Linux environment for custom runtimes](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-custom.html#runtimes-custom-use), and the `layers` config points to Bref's AWS Lambda layers.
Thanks to the Bref plugin, our `serverless.yml` is simpler. It also automatically adapts to the AWS region in use, and automatically points to the correct layer version. You can learn more about "layers" [in this page](./runtimes/runtimes-details.mdx).
-If you want to reference AWS Lambda layers directly (instead of using the simpler `runtime: php-81` syntax), the Bref plugin also provides simple `serverless.yml` variables. These were the default in Bref v1.x, so you may find this older syntax on tutorials and blog posts:
+If you want to reference AWS Lambda layers directly (instead of using the simpler `runtime: php-84` syntax), the Bref plugin also provides simple `serverless.yml` variables. These were the default in Bref v1.x, so you may find this older syntax on tutorials and blog posts:
```yaml
service: app
provider:
name: aws
- runtime: provided.al2
+ runtime: provided.al2023
plugins:
- ./vendor/bref/bref
functions:
hello:
# ...
layers:
- - ${bref:layer.php-81}
+ - ${bref:layer.php-84}
# or:
- - ${bref:layer.php-81-fpm}
+ - ${bref:layer.php-84-fpm}
```
The `${...}` notation is the [syntax to use variables](https://serverless.com/framework/docs/providers/aws/guide/variables/) in `serverless.yml`. The Bref plugin provides the following variables:
+- `${bref:layer.php-85}`
- `${bref:layer.php-84}`
- `${bref:layer.php-83}`
- `${bref:layer.php-82}`
-- `${bref:layer.php-81}`
-- `${bref:layer.php-80}`
+- `${bref:layer.php-85-fpm}`
- `${bref:layer.php-84-fpm}`
- `${bref:layer.php-83-fpm}`
- `${bref:layer.php-82-fpm}`
-- `${bref:layer.php-81-fpm}`
-- `${bref:layer.php-80-fpm}`
- `${bref:layer.console}`
Bref ARM layers are the same as the x86 layers, but with the `arm-` prefix in their name, for example `${bref:layer.arm-php-82}`. The only exception is `${bref:layer.console}` (this is the same layer for both x86 and ARM).
diff --git a/docs/runtimes/console.mdx b/docs/runtimes/console.mdx
index 26cafb7a6..4b6f4240e 100644
--- a/docs/runtimes/console.mdx
+++ b/docs/runtimes/console.mdx
@@ -35,10 +35,10 @@ plugins:
functions:
hello:
handler: the-php-script-to-run.php
- runtime: php-81-console
+ runtime: php-84-console
```
-Behind the scenes, the `php-xx-console` runtime will deploy a Lambda function configured to use Bref's `php-81` AWS Lambda layer plus Bref's `console` layer (read more about these in the [runtimes documentation](../runtimes.mdx)).
+Behind the scenes, the `php-xx-console` runtime will deploy a Lambda function configured to use Bref's `php-84` AWS Lambda layer plus Bref's `console` layer (read more about these in the [runtimes documentation](../runtimes.mdx)).
## Running commands
@@ -48,7 +48,7 @@ When invoked, the "Console" runtime executes the `handler` script in a sub-proce
functions:
hello:
handler: the-php-script-to-run.php
- runtime: php-81-console
+ runtime: php-84-console
```
Then the following command would run in Lambda every time the function is invoked:
diff --git a/docs/runtimes/fpm-runtime.mdx b/docs/runtimes/fpm-runtime.mdx
index 9765f30b7..c17a7a039 100644
--- a/docs/runtimes/fpm-runtime.mdx
+++ b/docs/runtimes/fpm-runtime.mdx
@@ -38,7 +38,7 @@ plugins:
functions:
app:
handler: index.php
- runtime: php-81-fpm
+ runtime: php-84-fpm
events:
- httpApi: '*'
```
diff --git a/docs/runtimes/function.mdx b/docs/runtimes/function.mdx
index 087c306c8..a2dcf4592 100644
--- a/docs/runtimes/function.mdx
+++ b/docs/runtimes/function.mdx
@@ -49,7 +49,7 @@ plugins:
functions:
hello:
handler: my-function.php
- runtime: php-81
+ runtime: php-84
```
## PHP functions
@@ -248,6 +248,10 @@ You first need to install the AWS PHP SDK by running
$ composer require aws/aws-sdk-php
```
+
+ The `aws/aws-sdk-php` package is very large (100MB+). To avoid hitting Lambda's 250MB size limit, [remove unused AWS services from the package](/docs/deploy.md#reducing-package-size).
+
+
```php
$lambda = new \Aws\Lambda\LambdaClient([
'version' => 'latest',
diff --git a/docs/runtimes/runtimes-details.mdx b/docs/runtimes/runtimes-details.mdx
index 3aef0a18f..76a01a14d 100644
--- a/docs/runtimes/runtimes-details.mdx
+++ b/docs/runtimes/runtimes-details.mdx
@@ -15,12 +15,12 @@ Bref runtimes are distributed as [AWS Lambda layers](https://docs.aws.amazon.com
The layer names (aka "[ARN](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference-arns.html)") follow this pattern:
```
-arn:aws:lambda::534081306603:layer::
+arn:aws:lambda::873528684822:layer::
```
For example:
```
-arn:aws:lambda:us-east-1:534081306603:layer:php-80:21
+arn:aws:lambda:us-east-1:873528684822:layer:php-84:21
```
You can use layers via their full ARN, for example in `serverless.yml`:
@@ -32,9 +32,9 @@ provider:
functions:
hello:
# ...
- runtime: provided.al2
+ runtime: provided.al2023
layers:
- - 'arn:aws:lambda:us-east-1:534081306603:layer:php-80:21'
+ - 'arn:aws:lambda:us-east-1:873528684822:layer:php-84:21'
```
Or if you are using [SAM's `template.yaml`](https://aws.amazon.com/serverless/sam/):
@@ -47,9 +47,9 @@ Resources:
Type: AWS::Serverless::Function
Properties:
# ...
- Runtime: provided.al2
+ Runtime: provided.al2023
Layers:
- - 'arn:aws:lambda:us-east-1:534081306603:layer:php-80:21'
+ - 'arn:aws:lambda:us-east-1:873528684822:layer:php-84:21'
```
Bref layers work with AWS Lambda regardless of the tool you use to deploy your application: Serverless, SAM, CloudFormation, Terraform, AWS CDK, etc.
@@ -80,6 +80,15 @@ serverless bref:layers
You can use [the `@bref.sh/layers.js` NPM package](https://github.com/brefphp/layers.js) to get up-to-date layer ARNs in Node applications, for example with the AWS CDK.
+## Environment variables
+
+Bref exposes the following environment variables on every Lambda invocation:
+
+- **`LAMBDA_REQUEST_ID`**: the current AWS Lambda request ID. This is useful for logging and tracing purposes, for example to group all logs of the same invocation.
+- **`_X_AMZN_TRACE_ID`**: the [AWS X-Ray](https://docs.aws.amazon.com/lambda/latest/dg/services-xray.html) trace ID. This is a standard AWS Lambda variable that is normally set by native runtimes.
+
+These variables are refreshed on every invocation.
+
## Telemetry ping
Bref layers send an anonymous ping to estimate the total number of Lambda invocations powered by Bref. That statistic is useful in two ways:
diff --git a/docs/setup.mdx b/docs/setup.mdx
index 6ff9b38f3..dc2ead96f 100644
--- a/docs/setup.mdx
+++ b/docs/setup.mdx
@@ -125,3 +125,8 @@ That's it, you're ready to use Bref with the Serverless CLI!
} title="Get started with Symfony" arrow="true" href="/docs/symfony/getting-started" />
+
+
+ Bref is compatible with PHP 8.2 or greater.
+ If you are using PHP 8.0 or 8.1, Bref v2 (previous major version) will be installed instead.
+
diff --git a/docs/setup/minimal-aws-policy.mdx b/docs/setup/minimal-aws-policy.mdx
index 51e2d9510..46134f369 100644
--- a/docs/setup/minimal-aws-policy.mdx
+++ b/docs/setup/minimal-aws-policy.mdx
@@ -66,6 +66,7 @@ Feel free to submit a PR if you have any suggestions for improvements.
"iam:DeleteRolePolicy",
"iam:DetachRolePolicy",
"iam:GetRole",
+ "iam:TagRole",
"iam:PassRole",
"iam:PutRolePolicy",
"iot:CreateTopicRule",
diff --git a/docs/symfony/getting-started.mdx b/docs/symfony/getting-started.mdx
index e47ecb0c4..8dd8e15d8 100644
--- a/docs/symfony/getting-started.mdx
+++ b/docs/symfony/getting-started.mdx
@@ -21,13 +21,54 @@ Next, in an existing Symfony project, install Bref and the [Symfony Bridge packa
composer require bref/bref bref/symfony-bridge --update-with-dependencies
```
-Next, create a `serverless.yml` configuration file at the root of your project by running:
-
-```bash
-vendor/bin/bref init symfony
+Next, create a `serverless.yml` configuration file at the root of your project:
+
+```yml filename="serverless.yml"
+service: app # your application name (lowercase without spaces)
+
+bref:
+ # Uncomment and set your team ID if you are using Bref Cloud
+ #team: bref-team-id
+
+provider:
+ name: aws
+ region: us-east-1 # AWS region to deploy to
+ environment: # Environment variables
+ APP_ENV: prod
+
+functions:
+ # This function runs the Symfony website/API
+ web:
+ handler: public/index.php
+ runtime: php-84-fpm
+ timeout: 28 # in seconds (API Gateway has a max timeout of 29 seconds)
+ events:
+ - httpApi: '*'
+ # This function let us run console commands in Lambda
+ console:
+ handler: bin/console
+ runtime: php-84-console
+ timeout: 120 # in seconds
+
+package:
+ patterns:
+ # Excluded files and folders for deployment
+ - '!assets/**'
+ - '!node_modules/**'
+ - '!public/build/**'
+ - '!tests/**'
+ - '!var/**'
+ # If you want to include files and folders that are part of excluded folders,
+ # add them at the end
+ - 'var/cache/prod/**'
+ - 'public/build/entrypoints.json'
+ - 'public/build/manifest.json'
+
+plugins:
+ - ./vendor/bref/bref
```
-(you can preview that file [here](https://github.com/brefphp/bref/blob/master/template/http/serverless.yml))
+You will also want to add `.serverless` to your `.gitignore`.
You still have a few modifications to do on the application to make it compatible with AWS Lambda.
diff --git a/docs/symfony/keep-alive.mdx b/docs/symfony/keep-alive.mdx
index 0de6636b2..9e2fed588 100644
--- a/docs/symfony/keep-alive.mdx
+++ b/docs/symfony/keep-alive.mdx
@@ -19,8 +19,8 @@ functions:
+ handler: App\Kernel
layers:
# Switch from PHP-FPM to the "function" runtime:
-- - ${bref:layer.php-81-fpm}
-+ - ${bref:layer.php-81}
+- - ${bref:layer.php-84-fpm}
++ - ${bref:layer.php-84}
environment:
+ # The Symfony process will restart every 100 requests
+ BREF_LOOP_MAX: 100
diff --git a/docs/symfony/messenger.mdx b/docs/symfony/messenger.mdx
index dbbf87972..11675f9f6 100644
--- a/docs/symfony/messenger.mdx
+++ b/docs/symfony/messenger.mdx
@@ -84,7 +84,7 @@ constructs:
type: queue
worker:
handler: bin/consumer.php
- runtime: php-81
+ runtime: php-84
timeout: 60 # in seconds
```
@@ -193,7 +193,7 @@ functions:
worker:
handler: bin/consumer.php
timeout: 20 # in seconds
- runtime: php-81
+ runtime: php-84
events:
# Read more at https://www.serverless.com/framework/docs/providers/aws/events/sns/
- sns:
@@ -269,7 +269,7 @@ functions:
worker:
handler: bin/consumer.php
timeout: 20 # in seconds
- runtime: php-81
+ runtime: php-84
events:
# Read more at https://www.serverless.com/framework/docs/providers/aws/events/event-bridge/
- eventBridge:
diff --git a/docs/upgrading/_meta.json b/docs/upgrading/_meta.json
index 1a03b074b..94f4120a7 100644
--- a/docs/upgrading/_meta.json
+++ b/docs/upgrading/_meta.json
@@ -1,3 +1,4 @@
{
- "v2": "From 1.x to 2.0"
+ "v2": "From 1.x to 2.0",
+ "v3": "From 2.x to 3.0"
}
\ No newline at end of file
diff --git a/docs/upgrading/v2.md b/docs/upgrading/v2.md
index 042394853..34acf9c7f 100644
--- a/docs/upgrading/v2.md
+++ b/docs/upgrading/v2.md
@@ -43,15 +43,15 @@ There is a new (simpler) syntax to use Bref's PHP runtimes in `serverless.yml`:
functions:
hello:
# ...
- runtime: php-81
+ runtime: php-84
# instead of:
runtime: provided.al2
layers:
- - ${bref:layer.php-81}
+ - ${bref:layer.php-84}
```
-The [bref.sh](https://bref.sh) documentation now uses the simpler `runtime: php-81` syntax, but `${bref:layer.php-xxx}` variables still work! These variables are not deprecated. There are no breaking changes here.
+The [bref.sh](https://bref.sh) documentation now uses the simpler `runtime: php-84` syntax, but `${bref:layer.php-xxx}` variables still work! These variables are not deprecated. There are no breaking changes here.
## Bref CLI
diff --git a/docs/upgrading/v3.mdx b/docs/upgrading/v3.mdx
new file mode 100644
index 000000000..9de76b589
--- /dev/null
+++ b/docs/upgrading/v3.mdx
@@ -0,0 +1,409 @@
+---
+introduction: Upgrading guide to go from Bref 2.x to Bref 3.0.
+---
+
+import { Callout } from 'nextra/components';
+
+# Upgrading to Bref 3.0
+
+Read the [Bref 3.0 release announcement](/news/03-bref-3.0) to learn about all the new features and improvements.
+
+## Updating dependencies
+
+### PHP 8.2 required
+
+Bref 3.0 now requires PHP 8.2 or greater.
+
+### Composer Dependencies
+
+Update all Bref packages in your `composer.json` file from `^2` to `^3`, for example:
+
+```json filename="composer.json"
+"require": {
+ "bref/bref": "^3",
+ "bref/laravel-bridge": "^3", // if you use Laravel
+ "bref/symfony-bridge": "^3", // if you use Symfony
+ "bref/extra-php-extensions": "^3" // if you use extra extensions
+}
+```
+
+
+ Only update the versions for the packages you actually have in your project.
+
+
+
+ If you use [`bref/extra-php-extensions`](https://github.com/brefphp/extra-php-extensions), note that it jumps from v1 to v3 (there is no v2). The v1 version was used with Bref v2, and v3 is aligned with Bref v3.
+
+
+Then run:
+
+```bash
+composer update --with-all-dependencies
+```
+
+## PHP extension changes
+
+The following improvements in Bref 3.0 let you clean up old configurations.
+
+### PostgreSQL extension is enabled by default
+
+The PostgreSQL PDO extension (`pdo_pgsql`) is now enabled by default in Bref layers.
+
+If you had enabled it manually via a `php.ini` file, you can remove that line:
+
+```diff filename="php/conf.d/php.ini"
+-extension=pdo_pgsql
+```
+
+### Redis extension is now built-in
+
+The Redis PHP extension is now included in Bref layers by default.
+
+If you were using the Redis extension from [bref/extra-php-extensions](https://github.com/brefphp/extra-php-extensions), remove the layer from your `serverless.yml`:
+
+```diff filename="serverless.yml"
+functions:
+ api:
+ # ...
+ layers:
+- - ${bref-extra:redis-php-84}
+```
+
+And enable the extension via a `php.ini` file in your project (`php/conf.d/php.ini`):
+
+```diff filename="php/conf.d/php.ini"
+extension=redis
+```
+
+If Redis was the only `bref/extra-php-extensions` extension you were using, you can uninstall the package:
+
+```bash
+composer remove bref/extra-php-extensions
+```
+
+## Container image changes
+
+If you deploy using [container images](../deploy/docker.mdx), you must update your `Dockerfile`.
+
+**If you don't have a `Dockerfile` in your project, you can skip this section.**
+
+Since Bref container images have been merged into a single `bref/php-xx` image, the following images don't exist anymore: `bref/php-xx-fpm` and `bref/php-xx-console`.
+
+### Option 1: Set BREF_RUNTIME in the Dockerfile
+
+The simplest upgrade path is to update your Dockerfile to use the unified image and set the runtime:
+
+```diff filename="Dockerfile"
+- FROM bref/php-84-fpm:2
++ FROM bref/php-84:3
++ ENV BREF_RUNTIME=fpm
+
+# ...
+```
+
+Replace `fpm` with `function` or `console` depending on your use case.
+
+### Option 2: Use one image for all function types (recommended)
+
+A major benefit of v3 is that you can now use **a single Docker image** for all your functions (web, console, queues, etc.) and set `BREF_RUNTIME` per function in `serverless.yml`.
+
+**Dockerfile** (single image for everything):
+
+```dockerfile filename="Dockerfile"
+FROM bref/php-84:3
+
+# Your application code
+COPY . /var/task
+
+# No BREF_RUNTIME set here!
+```
+
+**serverless.yml** (set runtime per function):
+
+```yml filename="serverless.yml"
+functions:
+ web:
+ image:
+ name: my-app-image
+ environment:
+ BREF_RUNTIME: fpm # Web/HTTP function
+ events:
+ - httpApi: '*'
+
+ console:
+ image:
+ name: my-app-image
+ environment:
+ BREF_RUNTIME: console # Console commands
+
+ worker:
+ image:
+ name: my-app-image
+ environment:
+ BREF_RUNTIME: function # Queue worker
+ events:
+ - sqs:
+ arn: !GetAtt MyQueue.Arn
+```
+
+This approach lets you build and deploy a single Docker image for all function types, simplifying your deployment pipeline.
+
+### Local development images
+
+If you use the `bref/php-84-fpm-dev` image for local development, update it to:
+
+```diff filename="docker-compose.yml"
+- FROM bref/php-84-fpm-dev:2
++ FROM bref/php-84-dev:3
+```
+
+You can then set `BREF_RUNTIME` environment variable in your `docker-compose.yml` file or in the `Dockerfile` directly.
+
+## Smaller breaking changes that might impact you
+
+The changes below should not impact the majority of users. However, if you are using any of these features, you might need to update your code.
+
+### Changed the AWS account ID for AWS Lambda layers
+
+The AWS account ID where Bref layers are published is different for v3. That lets us keep releasing Bref v2 layers without mixing up layer numbers. If you reference the layers via their full ARN, you must update the Bref AWS account number to `873528684822` (instead of `534081306603`).
+
+```bash
+# Bref v2 layer
+arn:aws:lambda:us-east-1:534081306603:layer:php-84:xxx
+
+# Bref v3 layer
+arn:aws:lambda:us-east-1:873528684822:layer:php-84:xxx
+```
+
+**If you don't know what that means**, you're likely not concerned by this change.
+
+If you're not sure, search for `534081306603` in your codebase and replace it with the new account ID.
+
+### AWS Lambda layers have been merged into a single layer
+
+If you configure the `runtime` in your functions using the following syntax:
+
+```yml filename="serverless.yml"
+functions:
+ web:
+ # ...
+ runtime: php-84-fpm # or `php-xx` or `php-xx-console`
+```
+
+✅ **you have nothing to do**, your configuration is valid for Bref v3.
+
+However, if you specify AWS Lambda layers explicitly in `serverless.yml` (or through any other deployment method), for example:
+
+```yml filename="serverless.yml"
+functions:
+ web:
+ # ...
+ runtime: provided.al2
+ layers:
+ - ${bref:layer.php-84}
+ # or:
+ - ${bref:layer.php-84-fpm}
+ # or:
+ layers:
+ - 'arn:aws:lambda:us-east-1:534081306603:layer:php-84:21'
+```
+
+Then you must update your configuration.
+
+Under the hood, **all layers have been merged into one**, i.e. `php-xx-fpm` and `php-xx-console` have been merged into `php-xx` to make Bref layers simpler. The runtime is now defined via an environment variable that is automatically injected by Bref when using the `runtime:` syntax.
+
+- **Option 1**: switch to using the simpler `runtime:` syntax.
+
+ Before:
+
+ ```yml filename="serverless.yml"
+ functions:
+ web:
+ # ...
+ runtime: provided.al2
+ layers:
+ - ${bref:layer.php-84}
+ # or:
+ - ${bref:layer.php-84-fpm}
+ # or:
+ - ${bref:layer.php-84-console}
+ ```
+
+ After:
+
+ ```yml filename="serverless.yml"
+ functions:
+ web:
+ # ...
+ runtime: php-84
+ # or:
+ runtime: php-84-fpm
+ # or:
+ runtime: php-84-console
+ ```
+
+ The examples above assume you are using PHP 8.4 (`php-84`) but you can replace `84` with another PHP version.
+
+ If you include additional layers, you can keep them without issues, for example:
+
+ ```yml filename="serverless.yml"
+ functions:
+ web:
+ # ...
+ runtime: php-84-fpm
+ layers:
+ - ${bref-extra:imagick-php-84}
+ ```
+
+- **Option 2**: change the layer names and define the `BREF_RUNTIME` environment variable.
+
+ Before:
+
+ ```yml filename="serverless.yml"
+ functions:
+ web:
+ # ...
+ runtime: provided.al2
+ layers:
+ - ${bref:layer.php-84}
+ # or:
+ - ${bref:layer.php-84-fpm}
+ # or:
+ - ${bref:layer.php-84-console}
+ ```
+
+ After:
+
+ ```yml filename="serverless.yml"
+ functions:
+ web:
+ # ...
+ runtime: provided.al2
+ layers:
+ - ${bref:layer.php-84}
+ environment:
+ # ...
+ BREF_RUNTIME: function # for ${bref:layer.php-xx}
+ # or
+ BREF_RUNTIME: fpm # for ${bref:layer.php-xx-fpm}
+ # or
+ BREF_RUNTIME: console # ${bref:layer.php-xx-console}
+ ```
+
+ The examples above assume you are using PHP 8.4 (`php-84`) but you can replace `84` with another PHP version.
+
+### The `vendor/bin/bref` CLI has been removed
+
+The `vendor/bin/bref` CLI has been completely removed in Bref 3.0. This is a minor change since the CLI was already 90% removed in Bref 2.0 - only the `bref init` command remained for bootstrapping new projects.
+
+We now have better onboarding with improved documentation. Here are the alternatives:
+
+- **Scaffolding new projects**: Follow the [getting started guide](/docs/setup) to create your `serverless.yml` manually.
+- **Layer versions**: Visit [runtimes.bref.sh](https://runtimes.bref.sh/) or run `serverless bref:layers`.
+- **Running console commands**: Use `serverless bref:cli` (unchanged from v2).
+- **Local development**: Use [Docker-based local development](/docs/local-development).
+
+### The hooks system has been removed
+
+The deprecated hooks system has been removed. This change affects very few users (less than 1%) as it was a low-level API used primarily by framework integrations.
+
+If you were using `Bref::beforeStartup()` or `Bref::beforeInvoke()`, you must migrate to the `BrefEventSubscriber` pattern:
+
+Before:
+
+```php
+use Bref\Bref;
+
+Bref::beforeStartup(function () {
+ // Setup code
+});
+```
+
+After:
+
+```php
+use Bref\Bref;
+use Bref\Listener\BrefEventSubscriber;
+
+class MyEventSubscriber extends BrefEventSubscriber
+{
+ public function beforeStartup(): void
+ {
+ // Setup code
+ }
+}
+
+Bref::events()->subscribe(new MyEventSubscriber());
+```
+
+The `BrefEventSubscriber` class provides additional hooks: `afterStartup()`, `beforeInvoke()`, and `afterInvoke()`. This refactor powers better integrations like the [Laravel bridge](https://github.com/brefphp/laravel-bridge), [X-Ray integration](https://bref.sh/xray), and [Sentry integration](https://bref.sh/sentry).
+
+### SOAP extension is now disabled by default
+
+The SOAP PHP extension is now disabled by default. It had very little usage, and disabling it helped reduce layer sizes to make room for more commonly used extensions.
+
+If you need the SOAP extension, you can enable it by creating a `php.ini` file in your project:
+
+```ini filename="php/conf.d/soap.ini"
+extension=soap
+```
+
+And reference it in your `serverless.yml`:
+
+```yml filename="serverless.yml"
+provider:
+ environment:
+ BREF_AUTOLOAD_PATH: php/conf.d
+```
+
+### Laravel version compatibility
+
+If you are using Laravel with Bref, note that:
+
+- **Laravel 10, 11, or 12 is required** (Laravel 8 and 9 are no longer supported).
+- Update `bref/laravel-bridge` to the latest version.
+
+The Laravel bridge has been updated to use the new `BrefEventSubscriber` pattern internally, but this change is transparent to users.
+
+### CloudWatch log formatter enabled by default
+
+The [Bref Monolog formatter](https://github.com/brefphp/monolog-bridge) is now enabled by default in the Laravel and Symfony bridges.
+
+**This changes how your logs will look.** Logs now use a hybrid format that combines human-readable text with structured JSON:
+
+Before (plain text):
+```
+[2025-12-05 10:30:45] production.ERROR: Database connection failed
+```
+
+After (structured format):
+```
+ERROR Database connection failed {"message":"Database connection failed","level":"ERROR","context":{...}}
+```
+
+This format makes logs easier to read in CloudWatch and enables powerful filtering with CloudWatch Logs Insights (e.g., filter by log level or exception class).
+
+**Exception handling is greatly improved:** Previously, exception stack traces were split across multiple CloudWatch log records (one per line), making them difficult to read and browse. Now, the entire exception (including stack trace) is grouped in a single JSON object, making debugging much easier.
+
+If you prefer the old format, you can disable the formatter in your Laravel or Symfony configuration. See the [Bref Monolog documentation](https://github.com/brefphp/monolog-bridge) for details.
+
+### Locale files from glibc langpacks are no longer included
+
+If you are using [`intl` / ICU](https://www.php.net/manual/en/intro.intl.php) for locale-aware formatting (dates, numbers, currencies) or translations, you don't need to do anything as ICU is fully supported in Bref v3. **Modern frameworks (Laravel, Symfony…) use ICU, not `gettext`**. That means most users are not affected.
+
+If you are using PHP's native [`gettext`](https://www.php.net/manual/en/book.gettext.php) functions or rely on `setlocale()` with specific locales (e.g. for
+`strftime()`), glibc locale files are no longer included in Amazon Linux 2023 (AL2023). These will no longer work in Bref v3. You may either:
+
+- Switch to using `intl` / ICU, which is the modern standard for translations in PHP and is fully supported in Bref v3.
+- Or, if you want to keep using `gettext` or `setlocale()`, switch to [container deployments](../deploy/docker.mdx) and use a custom Docker image that includes the necessary locale files:
+
+```dockerfile filename="Dockerfile"
+# Install the locale packages you need (e.g. English and French)
+RUN microdnf update -y && \
+ microdnf install -y glibc-langpack-en glibc-langpack-fr && \
+ microdnf clean all
+```
+
+---
+
+That's it! Read the [Bref 3.0 release announcement](/news/03-bref-3.0) to learn more about all the new features and improvements in this release.
diff --git a/docs/use-cases/cron.mdx b/docs/use-cases/cron.mdx
index 4eda71636..44750bebd 100644
--- a/docs/use-cases/cron.mdx
+++ b/docs/use-cases/cron.mdx
@@ -22,7 +22,7 @@ functions:
Cron events can be used to run CLI commands with the [Console runtime](../runtimes/console.md).
-In that case, use the `php-xx-console` runtime (for example `php-81-console`).
+In that case, use the `php-xx-console` runtime (for example `php-84-console`).
This is usually best when coupled with a framework like Laravel or Symfony, or when porting an existing cron task to AWS Lambda.
@@ -33,7 +33,7 @@ This is usually best when coupled with a framework like Laravel or Symfony, or w
# ...
cron:
handler: artisan
- runtime: php-81-console
+ runtime: php-84-console
events:
- schedule:
rate: rate(1 hour)
@@ -51,7 +51,7 @@ This is usually best when coupled with a framework like Laravel or Symfony, or w
# ...
artisan:
handler: artisan
- runtime: php-81-console
+ runtime: php-84-console
events:
- schedule:
rate: rate(1 minute)
@@ -64,7 +64,7 @@ This is usually best when coupled with a framework like Laravel or Symfony, or w
# ...
cron:
handler: bin/console
- runtime: php-81-console
+ runtime: php-84-console
events:
- schedule:
rate: rate(1 hour)
@@ -81,7 +81,7 @@ This is usually best when coupled with a framework like Laravel or Symfony, or w
# ...
cron:
handler: my-script.php
- runtime: php-81-console
+ runtime: php-84-console
events:
- schedule:
rate: rate(1 hour)
@@ -96,7 +96,7 @@ This is usually best when coupled with a framework like Laravel or Symfony, or w
# ...
cron:
handler: my-script.php
- runtime: php-81-console
+ runtime: php-84-console
events:
- schedule:
rate: rate(1 hour)
@@ -122,7 +122,7 @@ On top of running CLI cron tasks with the `php-xx-console` runtime, we can also
# ...
cron:
handler: App\MyCronHandler
- runtime: php-81
+ runtime: php-84
events:
- schedule:
rate: rate(1 hour)
@@ -165,7 +165,7 @@ On top of running CLI cron tasks with the `php-xx-console` runtime, we can also
# ...
cron:
handler: App\MyCronHandler
- runtime: php-81
+ runtime: php-84
events:
- schedule:
rate: rate(1 hour)
@@ -208,7 +208,7 @@ On top of running CLI cron tasks with the `php-xx-console` runtime, we can also
# ...
cron:
handler: function.php
- runtime: php-81-console
+ runtime: php-84-console
events:
- schedule:
rate: rate(1 hour)
diff --git a/docs/use-cases/http.mdx b/docs/use-cases/http.mdx
index 152285db3..27edf4d92 100644
--- a/docs/use-cases/http.mdx
+++ b/docs/use-cases/http.mdx
@@ -37,14 +37,14 @@ Bref sets up API Gateway with AWS Lambda and the [PHP-FPM runtime](../runtimes/f
functions:
web:
handler: public/index.php
- runtime: php-81-fpm
+ runtime: php-84-fpm
events:
- httpApi: '*'
```
This configuration deploys an API Gateway that forwards all routes (`*` is a wildcard) to AWS Lambda.
-On Lambda, the `php-81-fpm` runtime starts PHP-FPM and forwards all requests to it. PHP-FPM then runs the PHP code.
+On Lambda, the `php-84-fpm` runtime starts PHP-FPM and forwards all requests to it. PHP-FPM then runs the PHP code.
This is perfect for most use-cases: **PHP works like on any server** with PHP-FPM. HTTP routing based on the URL is done by the application/the framework.
diff --git a/docs/use-cases/http/advanced-use-cases.mdx b/docs/use-cases/http/advanced-use-cases.mdx
index cc7333931..f567620fe 100644
--- a/docs/use-cases/http/advanced-use-cases.mdx
+++ b/docs/use-cases/http/advanced-use-cases.mdx
@@ -189,7 +189,7 @@ Then, create a Lambda function that listens to HTTP events with the handler you
functions:
# ...
handler: App\MyHttpHandler
- runtime: php-81
+ runtime: php-84
# Lambda Function URL
url: true
# Or API Gateway
@@ -207,7 +207,7 @@ Then, create a Lambda function that listens to HTTP events with the handler you
functions:
# ...
handler: App\MyHttpHandler
- runtime: php-81
+ runtime: php-84
# Lambda Function URL
url: true
# Or API Gateway
@@ -225,7 +225,7 @@ Then, create a Lambda function that listens to HTTP events with the handler you
functions:
# ...
handler: handler.php
- runtime: php-81
+ runtime: php-84
# Lambda Function URL
url: true
# Or API Gateway
@@ -254,12 +254,12 @@ Since a handler is a controller for a specific route, we can use the API Gateway
functions:
create-article:
handler: App\CreateArticleController
- runtime: php-81
+ runtime: php-84
events:
- httpApi: 'POST /articles'
get-article:
handler: App\GetArticleController
- runtime: php-81
+ runtime: php-84
events:
- httpApi: 'GET /articles/{id}'
```
diff --git a/docs/use-cases/websites.mdx b/docs/use-cases/websites.mdx
index fda17dd28..7bba1d0d5 100644
--- a/docs/use-cases/websites.mdx
+++ b/docs/use-cases/websites.mdx
@@ -211,3 +211,40 @@ The last step will be to point your domain name DNS records to the CloudFront do
- if you use another registrar and you want to point your root domain (without `www.`) to CloudFront, you will need to use a registrar that supports this (for example [CloudFlare allows this with a technique called CNAME flattening](https://support.cloudflare.com/hc/en-us/articles/200169056-Understand-and-configure-CNAME-Flattening))
Lift supports more advanced use cases like multiple domains, root domain to `www` redirects, and more. Check out [the Lift documentation](https://github.com/getlift/lift/blob/master/docs/server-side-website.md).
+
+## Compressing HTTP responses
+
+By default, Lift enables gzip and brotli compression for static assets served from S3. That means that if a client supports compressed responses (via the `Accept-Encoding` header), [CloudFront will cache and serve a compressed version of the asset](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/ServingCompressedFiles.html#compressed-content-cloudfront-how-it-works), which is usually smaller and faster to transfer.
+
+However, dynamic responses generated by PHP (for example HTML pages) are not compressed. The reason is that CloudFront's cache is disabled for requests to PHP (Lift sets up the [`CachingDisabled` policy](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-managed-cache-policies.html#managed-cache-policy-caching-disabled)), and therefore CloudFront does not compress non-cached responses.
+
+You can compress PHP responses by using an HTTP middleware that compresses the response body and sets the `Content-Encoding` header. Here is an example for Laravel:
+
+```php filename="app/Http/Middleware/CompressResponse.php"
+class CompressResponse
+{
+ public function handle(Request $request, Closure $next)
+ {
+ /** @var \Illuminate\Http\JsonResponse $response */
+ $response = $next($request);
+
+ if (! in_array('gzip', $request->getEncodings())) {
+ return $response;
+ }
+ if ($response->headers->has('Content-Encoding')) {
+ return $response;
+ }
+
+ $content = $response->getContent();
+ if (! $content) {
+ return $response;
+ }
+
+ $response->setContent(gzencode($content, 9));
+ $response->headers->set('Content-Encoding', 'gzip');
+ $response->headers->set('Content-Length', (string) strlen($content));
+
+ return $response;
+ }
+}
+```
diff --git a/index.js b/index.js
index c8bd15f39..61fe23994 100644
--- a/index.js
+++ b/index.js
@@ -43,15 +43,22 @@ class ServerlessPlugin {
/** @type {Record>} */
this.layers = JSON.parse(fs.readFileSync(filename).toString());
- this.runtimes = Object.keys(this.layers)
- .filter(name => !name.startsWith('arm-'));
- // Console runtimes must have a PHP version provided
- this.runtimes = this.runtimes.filter(name => name !== 'console');
- this.runtimes.push('php-80-console', 'php-81-console', 'php-82-console', 'php-83-console', 'php-84-console');
-
this.checkCompatibleRuntime();
- serverless.configSchemaHandler.schema.definitions.awsLambdaRuntime.enum.push(...this.runtimes);
+ serverless.configSchemaHandler.schema.definitions.awsLambdaRuntime.enum.push(...[
+ 'php-82',
+ 'php-83',
+ 'php-84',
+ 'php-85',
+ 'php-82-fpm',
+ 'php-83-fpm',
+ 'php-84-fpm',
+ 'php-85-fpm',
+ 'php-82-console',
+ 'php-83-console',
+ 'php-84-console',
+ 'php-85-console',
+ ]);
serverless.configSchemaHandler.defineTopLevelProperty('bref', {
type: 'object',
});
@@ -170,77 +177,104 @@ class ServerlessPlugin {
}
/**
- * Process the `php-xx` runtimes to turn them into `provided.al2` runtimes + Bref layers.
+ * Process the `php-xx` runtimes to turn them into `provided.al2023` runtimes + Bref layers.
*/
processPhpRuntimes() {
- const includeBrefLayers = (runtime, existingLayers, isArm) => {
- let layerName = runtime;
+ const includeBrefLayers = (existingLayers, phpVersion, isArm) => {
+ let layerName = 'php-' + phpVersion;
// Automatically use ARM layers if the function is deployed to an ARM architecture
if (isArm) {
layerName = 'arm-' + layerName;
}
- if (layerName.endsWith('-console')) {
- layerName = layerName.substring(0, layerName.length - '-console'.length);
- existingLayers.unshift(this.getLayerArn('console', this.provider.getRegion()));
- existingLayers.unshift(this.getLayerArn(layerName, this.provider.getRegion()));
- } else {
- existingLayers.unshift(this.getLayerArn(layerName, this.provider.getRegion()));
- }
+ existingLayers.unshift(this.getLayerArn(layerName, this.provider.getRegion()));
return existingLayers;
}
+ /**
+ * @param {string} runtime
+ * @return {string|undefined}
+ */
+ const runtimeStringToRuntimeClass = (runtime) => {
+ if (! runtime.startsWith('php-')) {
+ return undefined;
+ }
+ if (runtime.endsWith('-console')) {
+ return 'Bref\\ConsoleRuntime\\Main';
+ }
+ if (runtime.endsWith('-fpm')) {
+ return 'Bref\\FpmRuntime\\Main';
+ }
+ return 'Bref\\FunctionRuntime\\Main';
+ };
+ const configureFunctionRuntime = (f) => {
+ // `php-\d\d(-fpm|console)?`
+ const fullRuntimeString = f.runtime || config.provider.runtime;
+ if (! fullRuntimeString || ! fullRuntimeString.startsWith('php-')) {
+ return;
+ }
+ const phpVersion = fullRuntimeString.substring('php-'.length).split('-')[0];
+ const runtimeClass = runtimeStringToRuntimeClass(fullRuntimeString);
+ if (! runtimeClass) return;
+
+ // The logic here is a bit custom:
+ // If there are layers on the function, we preserve them
+ let existingLayers = f.layers || []; // make sure it's an array
+ // Else, we merge with the layers defined at the root.
+ // Indeed, SF overrides the layers defined at the root with the ones defined on the function.
+ if (existingLayers.length === 0) {
+ // for some reason it's not always an array
+ existingLayers = Array.from(config.provider.layers || []);
+ }
+
+ f.layers = includeBrefLayers(
+ existingLayers,
+ phpVersion,
+ f.architecture === 'arm64' || (isArmGlobally && !f.architecture),
+ );
+ f.runtime = 'provided.al2023';
+ // Add the `BREF_RUNTIME` environment variable
+ // to let the function know which runtime it is using
+ // (this is used by the Bref runtime)
+ if (!f.environment) {
+ f.environment = {};
+ }
+ if (!f.environment.BREF_RUNTIME) {
+ f.environment.BREF_RUNTIME = runtimeClass;
+ }
+ }
const config = this.serverless.service;
const isArmGlobally = config.provider.architecture === 'arm64';
- const isBrefRuntimeGlobally = this.runtimes.includes(config.provider.runtime || '');
// Check functions config
for (const f of Object.values(config.functions || {})) {
- if (
- (f.runtime && this.runtimes.includes(f.runtime)) ||
- (!f.runtime && isBrefRuntimeGlobally)
- ) {
- // The logic here is a bit custom:
- // If there are layers on the function, we preserve them
- let existingLayers = f.layers || []; // make sure it's an array
- // Else, we merge with the layers defined at the root.
- // Indeed, SF overrides the layers defined at the root with the ones defined on the function.
- if (existingLayers.length === 0) {
- // for some reason it's not always an array
- existingLayers = Array.from(config.provider.layers || []);
- }
-
- f.layers = includeBrefLayers(
- f.runtime || config.provider.runtime,
- existingLayers,
- f.architecture === 'arm64' || (isArmGlobally && !f.architecture),
- );
- f.runtime = 'provided.al2';
- }
+ configureFunctionRuntime(f);
}
// Check Lift constructs config
for (const construct of Object.values(this.serverless.configurationInput.constructs || {})) {
if (construct.type !== 'queue' && construct.type !== 'webhook') continue;
const f = construct.type === 'queue' ? construct.worker : construct.authorizer;
- if (f && (f.runtime && this.runtimes.includes(f.runtime) || !f.runtime && isBrefRuntimeGlobally) ) {
- f.layers = includeBrefLayers(
- f.runtime || config.provider.runtime,
- f.layers || [], // make sure it's an array
- f.architecture === 'arm64' || (isArmGlobally && !f.architecture),
- );
- f.runtime = 'provided.al2';
+ if (f) {
+ configureFunctionRuntime(f);
}
}
}
checkCompatibleRuntime() {
- const errorMessage = 'Bref layers are not compatible with the "provided" runtime.\nYou have to use the "provided.al2" runtime instead in serverless.yml.\nMore details here: https://bref.sh/docs/news/01-bref-1.0.html#amazon-linux-2';
+ const providedErrorMessage = 'Bref layers are not compatible with the "provided" runtime.\nYou have to use the "provided.al2023" runtime instead in serverless.yml.\nMore details here: https://bref.sh/docs/news/01-bref-1.0.html#amazon-linux-2';
+ const providdeAl2ErrorMessage = 'Bref layers are not compatible with the "provided" runtime.\nYou have to use the "provided.al2023" runtime instead in serverless.yml.\nMore details here: https://bref.sh/docs/news/01-bref-1.0.html#amazon-linux-2';
if (this.serverless.service.provider.runtime === 'provided') {
- throw new this.serverless.classes.Error(errorMessage);
+ throw new this.serverless.classes.Error(providedErrorMessage);
+ }
+ if (this.serverless.service.provider.runtime === 'provided.al2') {
+ throw new this.serverless.classes.Error(providdeAl2ErrorMessage);
}
for (const [, f] of Object.entries(this.serverless.service.functions || {})) {
if (f.runtime === 'provided') {
- throw new this.serverless.classes.Error(errorMessage);
+ throw new this.serverless.classes.Error(providedErrorMessage);
+ }
+ if (f.runtime === 'provided.al2') {
+ throw new this.serverless.classes.Error(providdeAl2ErrorMessage);
}
}
}
@@ -258,7 +292,7 @@ class ServerlessPlugin {
throw new this.serverless.classes.Error(`There is no Bref layer named "${layerName}" in region "${region}".\nThat region may not be supported yet. Check out https://runtimes.bref.sh to see the list of supported regions.\nOpen an issue to ask for that region to be supported: https://github.com/brefphp/bref/issues`);
}
const version = this.layers[layerName][region];
- return `arn:aws:lambda:${region}:534081306603:layer:${layerName}:${version}`;
+ return `arn:aws:lambda:${region}:873528684822:layer:${layerName}:${version}`;
}
/**
@@ -299,7 +333,7 @@ class ServerlessPlugin {
const payload = {
cli: 'sls',
- v: 2, // Bref version
+ v: 3, // Bref version
c: command,
ci: ci.isCI,
install: userConfig.get('meta.created_at'),
diff --git a/layers.json b/layers.json
index c89532a02..3d97137e1 100644
--- a/layers.json
+++ b/layers.json
@@ -1,506 +1,210 @@
{
- "php-84": {
- "ca-central-1": "34",
- "eu-central-1": "34",
- "eu-north-1": "34",
- "eu-west-1": "34",
- "eu-west-2": "34",
- "eu-west-3": "34",
- "sa-east-1": "34",
- "us-east-1": "34",
- "us-east-2": "34",
- "us-west-1": "34",
- "us-west-2": "34",
- "ap-east-1": "34",
- "ap-south-1": "34",
- "ap-northeast-1": "34",
- "ap-northeast-2": "34",
- "ap-northeast-3": "34",
- "ap-southeast-1": "34",
- "ap-southeast-2": "34",
- "eu-south-1": "34",
- "eu-south-2": "34",
- "af-south-1": "34",
- "me-south-1": "34"
+ "php-85": {
+ "ca-central-1": 12,
+ "eu-central-1": 12,
+ "eu-north-1": 12,
+ "eu-west-1": 12,
+ "eu-west-2": 12,
+ "eu-west-3": 12,
+ "sa-east-1": 12,
+ "us-east-1": 12,
+ "us-east-2": 12,
+ "us-west-1": 12,
+ "us-west-2": 12,
+ "ap-east-1": 12,
+ "ap-south-1": 12,
+ "ap-northeast-1": 12,
+ "ap-northeast-2": 12,
+ "ap-northeast-3": 12,
+ "ap-southeast-1": 12,
+ "ap-southeast-2": 12,
+ "ap-southeast-3": 12,
+ "eu-south-1": 12,
+ "eu-south-2": 12,
+ "af-south-1": 12,
+ "me-south-1": 12,
+ "me-central-1": 12
},
- "php-84-fpm": {
- "ca-central-1": "34",
- "eu-central-1": "34",
- "eu-north-1": "34",
- "eu-west-1": "34",
- "eu-west-2": "34",
- "eu-west-3": "34",
- "sa-east-1": "34",
- "us-east-1": "34",
- "us-east-2": "34",
- "us-west-1": "34",
- "us-west-2": "34",
- "ap-east-1": "34",
- "ap-south-1": "34",
- "ap-northeast-1": "34",
- "ap-northeast-2": "34",
- "ap-northeast-3": "34",
- "ap-southeast-1": "34",
- "ap-southeast-2": "34",
- "eu-south-1": "34",
- "eu-south-2": "34",
- "af-south-1": "34",
- "me-south-1": "34"
+ "php-84": {
+ "ca-central-1": 15,
+ "eu-central-1": 15,
+ "eu-north-1": 15,
+ "eu-west-1": 15,
+ "eu-west-2": 15,
+ "eu-west-3": 15,
+ "sa-east-1": 15,
+ "us-east-1": 15,
+ "us-east-2": 15,
+ "us-west-1": 15,
+ "us-west-2": 15,
+ "ap-east-1": 15,
+ "ap-south-1": 15,
+ "ap-northeast-1": 15,
+ "ap-northeast-2": 15,
+ "ap-northeast-3": 15,
+ "ap-southeast-1": 15,
+ "ap-southeast-2": 15,
+ "ap-southeast-3": 15,
+ "eu-south-1": 15,
+ "eu-south-2": 15,
+ "af-south-1": 15,
+ "me-south-1": 15,
+ "me-central-1": 15
},
"php-83": {
- "ca-central-1": "62",
- "eu-central-1": "62",
- "eu-north-1": "62",
- "eu-west-1": "62",
- "eu-west-2": "62",
- "eu-west-3": "62",
- "sa-east-1": "62",
- "us-east-1": "62",
- "us-east-2": "62",
- "us-west-1": "62",
- "us-west-2": "62",
- "ap-east-1": "62",
- "ap-south-1": "62",
- "ap-northeast-1": "62",
- "ap-northeast-2": "62",
- "ap-northeast-3": "62",
- "ap-southeast-1": "62",
- "ap-southeast-2": "62",
- "eu-south-1": "62",
- "eu-south-2": "62",
- "af-south-1": "62",
- "me-south-1": "62"
- },
- "php-83-fpm": {
- "ca-central-1": "62",
- "eu-central-1": "62",
- "eu-north-1": "62",
- "eu-west-1": "62",
- "eu-west-2": "62",
- "eu-west-3": "62",
- "sa-east-1": "62",
- "us-east-1": "62",
- "us-east-2": "62",
- "us-west-1": "62",
- "us-west-2": "62",
- "ap-east-1": "62",
- "ap-south-1": "62",
- "ap-northeast-1": "62",
- "ap-northeast-2": "62",
- "ap-northeast-3": "62",
- "ap-southeast-1": "62",
- "ap-southeast-2": "62",
- "eu-south-1": "62",
- "eu-south-2": "62",
- "af-south-1": "62",
- "me-south-1": "62"
+ "ca-central-1": 15,
+ "eu-central-1": 15,
+ "eu-north-1": 15,
+ "eu-west-1": 15,
+ "eu-west-2": 15,
+ "eu-west-3": 15,
+ "sa-east-1": 15,
+ "us-east-1": 15,
+ "us-east-2": 15,
+ "us-west-1": 15,
+ "us-west-2": 15,
+ "ap-east-1": 15,
+ "ap-south-1": 15,
+ "ap-northeast-1": 15,
+ "ap-northeast-2": 15,
+ "ap-northeast-3": 15,
+ "ap-southeast-1": 15,
+ "ap-southeast-2": 15,
+ "ap-southeast-3": 15,
+ "eu-south-1": 15,
+ "eu-south-2": 15,
+ "af-south-1": 15,
+ "me-south-1": 15,
+ "me-central-1": 15
},
"php-82": {
- "ca-central-1": "106",
- "eu-central-1": "106",
- "eu-north-1": "106",
- "eu-west-1": "106",
- "eu-west-2": "106",
- "eu-west-3": "106",
- "sa-east-1": "106",
- "us-east-1": "106",
- "us-east-2": "106",
- "us-west-1": "106",
- "us-west-2": "106",
- "ap-east-1": "106",
- "ap-south-1": "106",
- "ap-northeast-1": "106",
- "ap-northeast-2": "106",
- "ap-northeast-3": "106",
- "ap-southeast-1": "106",
- "ap-southeast-2": "106",
- "eu-south-1": "106",
- "eu-south-2": "105",
- "af-south-1": "106",
- "me-south-1": "106"
- },
- "php-82-fpm": {
- "ca-central-1": "106",
- "eu-central-1": "106",
- "eu-north-1": "106",
- "eu-west-1": "106",
- "eu-west-2": "106",
- "eu-west-3": "106",
- "sa-east-1": "106",
- "us-east-1": "106",
- "us-east-2": "106",
- "us-west-1": "106",
- "us-west-2": "106",
- "ap-east-1": "106",
- "ap-south-1": "106",
- "ap-northeast-1": "106",
- "ap-northeast-2": "106",
- "ap-northeast-3": "106",
- "ap-southeast-1": "106",
- "ap-southeast-2": "106",
- "eu-south-1": "106",
- "eu-south-2": "105",
- "af-south-1": "106",
- "me-south-1": "106"
- },
- "php-81": {
- "ca-central-1": "117",
- "eu-central-1": "117",
- "eu-north-1": "117",
- "eu-west-1": "117",
- "eu-west-2": "117",
- "eu-west-3": "117",
- "sa-east-1": "117",
- "us-east-1": "117",
- "us-east-2": "117",
- "us-west-1": "117",
- "us-west-2": "117",
- "ap-east-1": "109",
- "ap-south-1": "116",
- "ap-northeast-1": "116",
- "ap-northeast-2": "116",
- "ap-northeast-3": "116",
- "ap-southeast-1": "116",
- "ap-southeast-2": "116",
- "eu-south-1": "109",
- "eu-south-2": "106",
- "af-south-1": "109",
- "me-south-1": "109"
- },
- "php-81-fpm": {
- "ca-central-1": "116",
- "eu-central-1": "116",
- "eu-north-1": "117",
- "eu-west-1": "117",
- "eu-west-2": "116",
- "eu-west-3": "116",
- "sa-east-1": "116",
- "us-east-1": "117",
- "us-east-2": "116",
- "us-west-1": "116",
- "us-west-2": "117",
- "ap-east-1": "109",
- "ap-south-1": "115",
- "ap-northeast-1": "116",
- "ap-northeast-2": "115",
- "ap-northeast-3": "115",
- "ap-southeast-1": "115",
- "ap-southeast-2": "115",
- "eu-south-1": "108",
- "eu-south-2": "105",
- "af-south-1": "108",
- "me-south-1": "108"
- },
- "php-80": {
- "ca-central-1": "120",
- "eu-central-1": "119",
- "eu-north-1": "120",
- "eu-west-1": "120",
- "eu-west-2": "120",
- "eu-west-3": "120",
- "sa-east-1": "120",
- "us-east-1": "120",
- "us-east-2": "120",
- "us-west-1": "120",
- "us-west-2": "120",
- "ap-east-1": "110",
- "ap-south-1": "119",
- "ap-northeast-1": "117",
- "ap-northeast-2": "116",
- "ap-northeast-3": "117",
- "ap-southeast-1": "116",
- "ap-southeast-2": "118",
- "eu-south-1": "110",
- "eu-south-2": "106",
- "af-south-1": "110",
- "me-south-1": "110"
- },
- "php-80-fpm": {
- "ca-central-1": "117",
- "eu-central-1": "117",
- "eu-north-1": "117",
- "eu-west-1": "117",
- "eu-west-2": "117",
- "eu-west-3": "117",
- "sa-east-1": "117",
- "us-east-1": "117",
- "us-east-2": "117",
- "us-west-1": "117",
- "us-west-2": "117",
- "ap-east-1": "109",
- "ap-south-1": "116",
- "ap-northeast-1": "116",
- "ap-northeast-2": "116",
- "ap-northeast-3": "116",
- "ap-southeast-1": "116",
- "ap-southeast-2": "116",
- "eu-south-1": "109",
- "eu-south-2": "106",
- "af-south-1": "109",
- "me-south-1": "109"
+ "ca-central-1": 15,
+ "eu-central-1": 15,
+ "eu-north-1": 15,
+ "eu-west-1": 15,
+ "eu-west-2": 15,
+ "eu-west-3": 15,
+ "sa-east-1": 15,
+ "us-east-1": 15,
+ "us-east-2": 15,
+ "us-west-1": 15,
+ "us-west-2": 15,
+ "ap-east-1": 15,
+ "ap-south-1": 15,
+ "ap-northeast-1": 15,
+ "ap-northeast-2": 15,
+ "ap-northeast-3": 15,
+ "ap-southeast-1": 15,
+ "ap-southeast-2": 15,
+ "ap-southeast-3": 15,
+ "eu-south-1": 15,
+ "eu-south-2": 15,
+ "af-south-1": 15,
+ "me-south-1": 15,
+ "me-central-1": 15
+ },
+ "arm-php-85": {
+ "ca-central-1": 12,
+ "eu-central-1": 12,
+ "eu-north-1": 12,
+ "eu-west-1": 12,
+ "eu-west-2": 12,
+ "eu-west-3": 12,
+ "sa-east-1": 12,
+ "us-east-1": 12,
+ "us-east-2": 12,
+ "us-west-1": 12,
+ "us-west-2": 12,
+ "ap-east-1": 12,
+ "ap-south-1": 12,
+ "ap-northeast-1": 12,
+ "ap-northeast-2": 12,
+ "ap-northeast-3": 12,
+ "ap-southeast-1": 12,
+ "ap-southeast-2": 12,
+ "ap-southeast-3": 12,
+ "eu-south-1": 12,
+ "eu-south-2": 12,
+ "af-south-1": 12,
+ "me-south-1": 12,
+ "me-central-1": 12
},
"arm-php-84": {
- "ca-central-1": "34",
- "eu-central-1": "34",
- "eu-north-1": "34",
- "eu-west-1": "34",
- "eu-west-2": "34",
- "eu-west-3": "34",
- "sa-east-1": "34",
- "us-east-1": "34",
- "us-east-2": "34",
- "us-west-1": "34",
- "us-west-2": "34",
- "ap-east-1": "34",
- "ap-south-1": "34",
- "ap-northeast-1": "34",
- "ap-northeast-2": "34",
- "ap-northeast-3": "34",
- "ap-southeast-1": "34",
- "ap-southeast-2": "34",
- "eu-south-1": "34",
- "eu-south-2": "34",
- "af-south-1": "34",
- "me-south-1": "34"
- },
- "arm-php-84-fpm": {
- "ca-central-1": "34",
- "eu-central-1": "34",
- "eu-north-1": "34",
- "eu-west-1": "34",
- "eu-west-2": "34",
- "eu-west-3": "34",
- "sa-east-1": "34",
- "us-east-1": "34",
- "us-east-2": "34",
- "us-west-1": "34",
- "us-west-2": "34",
- "ap-east-1": "34",
- "ap-south-1": "34",
- "ap-northeast-1": "34",
- "ap-northeast-2": "34",
- "ap-northeast-3": "34",
- "ap-southeast-1": "34",
- "ap-southeast-2": "34",
- "eu-south-1": "34",
- "eu-south-2": "34",
- "af-south-1": "34",
- "me-south-1": "34"
+ "ca-central-1": 15,
+ "eu-central-1": 15,
+ "eu-north-1": 15,
+ "eu-west-1": 15,
+ "eu-west-2": 15,
+ "eu-west-3": 15,
+ "sa-east-1": 15,
+ "us-east-1": 15,
+ "us-east-2": 15,
+ "us-west-1": 15,
+ "us-west-2": 15,
+ "ap-east-1": 15,
+ "ap-south-1": 15,
+ "ap-northeast-1": 15,
+ "ap-northeast-2": 15,
+ "ap-northeast-3": 15,
+ "ap-southeast-1": 15,
+ "ap-southeast-2": 15,
+ "ap-southeast-3": 15,
+ "eu-south-1": 15,
+ "eu-south-2": 15,
+ "af-south-1": 15,
+ "me-south-1": 15,
+ "me-central-1": 15
},
"arm-php-83": {
- "ca-central-1": "62",
- "eu-central-1": "62",
- "eu-north-1": "62",
- "eu-west-1": "62",
- "eu-west-2": "62",
- "eu-west-3": "62",
- "sa-east-1": "62",
- "us-east-1": "62",
- "us-east-2": "62",
- "us-west-1": "62",
- "us-west-2": "62",
- "ap-east-1": "62",
- "ap-south-1": "62",
- "ap-northeast-1": "62",
- "ap-northeast-2": "62",
- "ap-northeast-3": "62",
- "ap-southeast-1": "62",
- "ap-southeast-2": "62",
- "eu-south-1": "62",
- "eu-south-2": "62",
- "af-south-1": "62",
- "me-south-1": "62"
- },
- "arm-php-83-fpm": {
- "ca-central-1": "61",
- "eu-central-1": "61",
- "eu-north-1": "61",
- "eu-west-1": "61",
- "eu-west-2": "61",
- "eu-west-3": "61",
- "sa-east-1": "61",
- "us-east-1": "62",
- "us-east-2": "61",
- "us-west-1": "61",
- "us-west-2": "61",
- "ap-east-1": "61",
- "ap-south-1": "61",
- "ap-northeast-1": "61",
- "ap-northeast-2": "61",
- "ap-northeast-3": "61",
- "ap-southeast-1": "61",
- "ap-southeast-2": "61",
- "eu-south-1": "61",
- "eu-south-2": "61",
- "af-south-1": "61",
- "me-south-1": "61"
+ "ca-central-1": 15,
+ "eu-central-1": 15,
+ "eu-north-1": 15,
+ "eu-west-1": 15,
+ "eu-west-2": 15,
+ "eu-west-3": 15,
+ "sa-east-1": 15,
+ "us-east-1": 15,
+ "us-east-2": 15,
+ "us-west-1": 15,
+ "us-west-2": 15,
+ "ap-east-1": 15,
+ "ap-south-1": 15,
+ "ap-northeast-1": 15,
+ "ap-northeast-2": 15,
+ "ap-northeast-3": 15,
+ "ap-southeast-1": 15,
+ "ap-southeast-2": 15,
+ "ap-southeast-3": 15,
+ "eu-south-1": 15,
+ "eu-south-2": 15,
+ "af-south-1": 15,
+ "me-south-1": 15,
+ "me-central-1": 15
},
"arm-php-82": {
- "ca-central-1": "94",
- "eu-central-1": "94",
- "eu-north-1": "94",
- "eu-west-1": "94",
- "eu-west-2": "94",
- "eu-west-3": "94",
- "sa-east-1": "94",
- "us-east-1": "94",
- "us-east-2": "94",
- "us-west-1": "94",
- "us-west-2": "94",
- "ap-east-1": "94",
- "ap-south-1": "94",
- "ap-northeast-1": "94",
- "ap-northeast-2": "94",
- "ap-northeast-3": "94",
- "ap-southeast-1": "94",
- "ap-southeast-2": "94",
- "eu-south-1": "94",
- "eu-south-2": "94",
- "af-south-1": "94",
- "me-south-1": "94"
- },
- "arm-php-82-fpm": {
- "ca-central-1": "94",
- "eu-central-1": "94",
- "eu-north-1": "94",
- "eu-west-1": "94",
- "eu-west-2": "94",
- "eu-west-3": "94",
- "sa-east-1": "94",
- "us-east-1": "94",
- "us-east-2": "94",
- "us-west-1": "94",
- "us-west-2": "94",
- "ap-east-1": "94",
- "ap-south-1": "94",
- "ap-northeast-1": "94",
- "ap-northeast-2": "94",
- "ap-northeast-3": "94",
- "ap-southeast-1": "94",
- "ap-southeast-2": "94",
- "eu-south-1": "94",
- "eu-south-2": "94",
- "af-south-1": "94",
- "me-south-1": "94"
- },
- "arm-php-81": {
- "ca-central-1": "97",
- "eu-central-1": "97",
- "eu-north-1": "97",
- "eu-west-1": "97",
- "eu-west-2": "97",
- "eu-west-3": "97",
- "sa-east-1": "97",
- "us-east-1": "97",
- "us-east-2": "97",
- "us-west-1": "97",
- "us-west-2": "97",
- "ap-east-1": "97",
- "ap-south-1": "97",
- "ap-northeast-1": "97",
- "ap-northeast-2": "97",
- "ap-northeast-3": "97",
- "ap-southeast-1": "97",
- "ap-southeast-2": "97",
- "eu-south-1": "97",
- "eu-south-2": "97",
- "af-south-1": "97",
- "me-south-1": "97"
- },
- "arm-php-81-fpm": {
- "ca-central-1": "97",
- "eu-central-1": "97",
- "eu-north-1": "97",
- "eu-west-1": "97",
- "eu-west-2": "97",
- "eu-west-3": "97",
- "sa-east-1": "97",
- "us-east-1": "97",
- "us-east-2": "97",
- "us-west-1": "97",
- "us-west-2": "97",
- "ap-east-1": "97",
- "ap-south-1": "97",
- "ap-northeast-1": "97",
- "ap-northeast-2": "97",
- "ap-northeast-3": "97",
- "ap-southeast-1": "97",
- "ap-southeast-2": "97",
- "eu-south-1": "97",
- "eu-south-2": "97",
- "af-south-1": "97",
- "me-south-1": "97"
- },
- "arm-php-80": {
- "ca-central-1": "119",
- "eu-central-1": "118",
- "eu-north-1": "119",
- "eu-west-1": "119",
- "eu-west-2": "119",
- "eu-west-3": "119",
- "sa-east-1": "119",
- "us-east-1": "119",
- "us-east-2": "119",
- "us-west-1": "119",
- "us-west-2": "119",
- "ap-east-1": "111",
- "ap-south-1": "118",
- "ap-northeast-1": "118",
- "ap-northeast-2": "118",
- "ap-northeast-3": "118",
- "ap-southeast-1": "118",
- "ap-southeast-2": "118",
- "eu-south-1": "111",
- "eu-south-2": "107",
- "af-south-1": "111",
- "me-south-1": "111"
- },
- "arm-php-80-fpm": {
- "ca-central-1": "118",
- "eu-central-1": "117",
- "eu-north-1": "118",
- "eu-west-1": "118",
- "eu-west-2": "117",
- "eu-west-3": "117",
- "sa-east-1": "117",
- "us-east-1": "118",
- "us-east-2": "118",
- "us-west-1": "117",
- "us-west-2": "118",
- "ap-east-1": "110",
- "ap-south-1": "116",
- "ap-northeast-1": "117",
- "ap-northeast-2": "116",
- "ap-northeast-3": "116",
- "ap-southeast-1": "116",
- "ap-southeast-2": "116",
- "eu-south-1": "109",
- "eu-south-2": "106",
- "af-south-1": "110",
- "me-south-1": "109"
- },
- "console": {
- "ca-central-1": "115",
- "eu-central-1": "115",
- "eu-north-1": "115",
- "eu-west-1": "115",
- "eu-west-2": "115",
- "eu-west-3": "115",
- "sa-east-1": "115",
- "us-east-1": "115",
- "us-east-2": "115",
- "us-west-1": "115",
- "us-west-2": "115",
- "ap-east-1": "107",
- "ap-south-1": "114",
- "ap-northeast-1": "114",
- "ap-northeast-2": "114",
- "ap-northeast-3": "114",
- "ap-southeast-1": "114",
- "ap-southeast-2": "114",
- "eu-south-1": "107",
- "eu-south-2": "104",
- "af-south-1": "107",
- "me-south-1": "107"
+ "ca-central-1": 15,
+ "eu-central-1": 15,
+ "eu-north-1": 15,
+ "eu-west-1": 15,
+ "eu-west-2": 15,
+ "eu-west-3": 15,
+ "sa-east-1": 15,
+ "us-east-1": 15,
+ "us-east-2": 15,
+ "us-west-1": 15,
+ "us-west-2": 15,
+ "ap-east-1": 15,
+ "ap-south-1": 15,
+ "ap-northeast-1": 15,
+ "ap-northeast-2": 15,
+ "ap-northeast-3": 15,
+ "ap-southeast-1": 15,
+ "ap-southeast-2": 15,
+ "ap-southeast-3": 15,
+ "eu-south-1": 15,
+ "eu-south-2": 15,
+ "af-south-1": 15,
+ "me-south-1": 15,
+ "me-central-1": 15
}
}
\ No newline at end of file
diff --git a/phpstan.neon b/phpstan.neon
index bcea319ff..337d37e45 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -1,7 +1,6 @@
parameters:
level: 5
paths:
- - bref
- src
- tests
excludePaths:
diff --git a/phpunit.xml b/phpunit.xml
index f8a3f2026..e8e4f4094 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -1,21 +1,23 @@
-
-
-
- src
-
-
+
./tests/
./tests/Sam
./tests/Fixtures
+ ./tests/HttpRequestProxyTest.php
+ ./tests/Event/Http/CommonHttpTest.php
./tests/Sam
-
+
+
+
+ src
+
+
diff --git a/plugin/layers.js b/plugin/layers.js
index fd1307476..f0d9c45c8 100644
--- a/plugin/layers.js
+++ b/plugin/layers.js
@@ -17,7 +17,7 @@ function listLayers(serverless, log) {
log('----------------------------------------------------------------------------------');
for (const [layer, versions] of Object.entries(layers)) {
const version = versions[region];
- const arn = `arn:aws:lambda:${region}:534081306603:layer:${layer}:${version}`;
+ const arn = `arn:aws:lambda:${region}:873528684822:layer:${layer}:${version}`;
log(`${padString(layer, 12)} ${padString(version, 9)} ${arn}`);
}
}
diff --git a/plugin/run-console.js b/plugin/run-console.js
index 1e8775689..009af4fc9 100644
--- a/plugin/run-console.js
+++ b/plugin/run-console.js
@@ -1,14 +1,10 @@
-const fs = require('fs');
-const path = require('path');
-
/**
* @param {import('./serverless').Serverless} serverless
* @param {import('./serverless').CliOptions} options
*/
async function runConsole(serverless, options) {
- const region = serverless.getProvider('aws').getRegion();
// Override CLI options for `sls invoke`
- options.function = options.function || getConsoleFunction(serverless, region);
+ options.function = options.function || getConsoleFunction(serverless);
options.type = 'RequestResponse';
options.data = options.args;
options.log = true;
@@ -18,36 +14,24 @@ async function runConsole(serverless, options) {
/**
* @param {import('./serverless').Serverless} serverless
- * @param {string} region
*/
-function getConsoleFunction(serverless, region) {
- const consoleLayerArn = getConsoleLayerArn(region);
-
+function getConsoleFunction(serverless) {
const functions = serverless.service.functions;
const consoleFunctions = [];
for (const [functionName, functionDetails] of Object.entries(functions || {})) {
- if (functionDetails.layers && functionDetails.layers.includes(consoleLayerArn)) {
+ // Check for BREF_RUNTIME environment variable (set by Bref plugin for php-XX-console runtimes)
+ const brefRuntime = functionDetails.environment && functionDetails.environment.BREF_RUNTIME;
+ if (brefRuntime === 'Bref\\ConsoleRuntime\\Main' || brefRuntime === 'console') {
consoleFunctions.push(functionName);
}
}
if (consoleFunctions.length === 0) {
- throw new serverless.classes.Error('This command invokes the Lambda "console" function, but no function was found with the "console" layer');
+ throw new serverless.classes.Error('This command invokes a Lambda console function, but no function was found using the console runtime (e.g. php-84-console)');
}
if (consoleFunctions.length > 1) {
- throw new serverless.classes.Error('More than one function contains the console layer: cannot automatically run it. Please provide a function name using the --function option.');
+ throw new serverless.classes.Error('More than one function uses the console runtime: cannot automatically run it. Please provide a function name using the --function option.');
}
return consoleFunctions[0];
}
-/**
- * @param {string} region
- * @returns {string}
- */
-function getConsoleLayerArn(region) {
- const json = fs.readFileSync(path.join(__dirname, '../layers.json'));
- const layers = JSON.parse(json.toString());
- const version = layers.console[region];
- return `arn:aws:lambda:${region}:534081306603:layer:console:${version}`;
-}
-
module.exports = {runConsole};
diff --git a/src/Bref.php b/src/Bref.php
index d5d6c5fe7..38b705c52 100644
--- a/src/Bref.php
+++ b/src/Bref.php
@@ -12,11 +12,6 @@ class Bref
{
private static ?Closure $containerProvider = null;
private static ?ContainerInterface $container = null;
- /** @deprecated Use Bref::events()->subscribe() instead */
- private static array $hooks = [
- 'beforeStartup' => [],
- 'beforeInvoke' => [],
- ];
private static EventDispatcher $eventDispatcher;
/**
@@ -37,46 +32,6 @@ public static function events(): EventDispatcher
return self::$eventDispatcher;
}
- /**
- * Register a hook to be executed before the runtime starts.
- *
- * Warning: hooks are low-level extension points to be used by framework
- * integrations. For user code, it is not recommended to use them. Use your
- * framework's extension points instead.
- *
- * @deprecated Use Bref::events()->subscribe() instead.
- */
- public static function beforeStartup(Closure $hook): void
- {
- self::$hooks['beforeStartup'][] = $hook;
- }
-
- /**
- * Register a hook to be executed before any Lambda invocation.
- *
- * Warning: hooks are low-level extension points to be used by framework
- * integrations. For user code, it is not recommended to use them. Use your
- * framework's extension points instead.
- *
- * @deprecated Use Bref::events()->subscribe() instead.
- */
- public static function beforeInvoke(Closure $hook): void
- {
- self::$hooks['beforeInvoke'][] = $hook;
- }
-
- /**
- * @param 'beforeStartup'|'beforeInvoke' $hookName
- *
- * @internal Used by the Bref runtime
- */
- public static function triggerHooks(string $hookName): void
- {
- foreach (self::$hooks[$hookName] as $hook) {
- $hook();
- }
- }
-
/**
* @internal Used by the Bref runtime
*/
@@ -103,10 +58,6 @@ public static function reset(): void
{
self::$containerProvider = null;
self::$container = null;
- self::$hooks = [
- 'beforeStartup' => [],
- 'beforeInvoke' => [],
- ];
self::$eventDispatcher = new EventDispatcher;
}
}
diff --git a/src/Cli/init.php b/src/Cli/init.php
deleted file mode 100644
index b91fc53f9..000000000
--- a/src/Cli/init.php
+++ /dev/null
@@ -1,100 +0,0 @@
-find('serverless')) {
- warning(
- 'The `serverless` command is not installed.' . PHP_EOL .
- 'You will not be able to deploy your application unless it is installed' . PHP_EOL .
- 'Please follow the instructions at https://bref.sh/docs/installation.html' . PHP_EOL .
- 'If you have the `serverless` command available elsewhere (eg in a Docker container) you can ignore this warning.' . PHP_EOL
- );
- }
-
- if (! $template) {
- $intro = green('What kind of application are you building?');
- echo << ') ?: '0';
- echo PHP_EOL;
- if (! in_array($choice, ['0', '1', '2'], true)) {
- error('Invalid response (must be "0", "1" or "2"), aborting');
- }
-
- $template = [
- '0' => 'http',
- '1' => 'function',
- '2' => 'symfony',
- ][$choice];
- }
-
- $rootPath = dirname(__DIR__, 2) . "/template/$template";
-
- if (file_exists($rootPath . '/index.php')) {
- createFile($rootPath, 'index.php');
- }
- createFile($rootPath, 'serverless.yml');
-
- // If these is a `.gitignore` file in the current directory, let's add `.serverless` to it
- if (file_exists('.gitignore')) {
- $gitignore = file_get_contents('.gitignore');
- if (! str_contains($gitignore, '.serverless')) {
- file_put_contents('.gitignore', PHP_EOL . '.serverless' . PHP_EOL, FILE_APPEND);
- success('Added `.serverless` to your `.gitignore` file.');
- }
- }
-
- success('Project initialized and ready to test or deploy.');
-}
-
-/**
- * Creates files from the template directory and automatically adds them to git
- */
-function createFile(string $templatePath, string $file): void
-{
- echo "Creating $file\n";
-
- if (file_exists($file)) {
- $overwrite = false;
- echo "A file named $file already exists, do you want to overwrite it? [y/N]\n";
- $choice = strtolower(readline('> ') ?: 'n');
- echo PHP_EOL;
- if ($choice === 'y') {
- $overwrite = true;
- } elseif (! in_array($choice, ['y', 'n'], true)) {
- error('Invalid response (must be "y" or "n"), aborting');
- }
- if (! $overwrite) {
- echo "Skipping $file\n";
- return;
- }
- }
-
- $template = file_get_contents("$templatePath/$file");
- if (! $template) {
- error("Could not read file $templatePath/$file");
- }
- $template = str_replace('PHP_VERSION', PHP_MAJOR_VERSION . PHP_MINOR_VERSION, $template);
- file_put_contents($file, $template);
-
- /*
- * We check if this is a git repository to automatically add file to git.
- */
- $message = "$file successfully created";
- if ((new Process(['git', 'rev-parse', '--is-inside-work-tree']))->run() === 0) {
- (new Process(['git', 'add', $file]))->run();
- $message .= ' and added to git automatically';
- }
-
- echo PHP_EOL;
- success("$message.");
-}
diff --git a/src/ConsoleRuntime/Main.php b/src/ConsoleRuntime/Main.php
index 5e51639e3..9e9a31c1f 100755
--- a/src/ConsoleRuntime/Main.php
+++ b/src/ConsoleRuntime/Main.php
@@ -20,7 +20,6 @@ public static function run(): void
LazySecretsLoader::loadSecretEnvironmentVariables();
- Bref::triggerHooks('beforeStartup');
Bref::events()->beforeStartup();
$lambdaRuntime = LambdaRuntime::fromEnvironmentVariable('console');
diff --git a/src/Event/Http/HttpHandler.php b/src/Event/Http/HttpHandler.php
index ebd7092d5..6e61793c1 100644
--- a/src/Event/Http/HttpHandler.php
+++ b/src/Event/Http/HttpHandler.php
@@ -25,9 +25,9 @@ public function handle($event, Context $context): array
$response = $this->handleRequest($httpEvent, $context);
if ($httpEvent->isFormatV2()) {
- return $response->toApiGatewayFormatV2();
+ return $response->toApiGatewayFormatV2($context->getAwsRequestId());
}
- return $response->toApiGatewayFormat($httpEvent->hasMultiHeader());
+ return $response->toApiGatewayFormat($httpEvent->hasMultiHeader(), $context->getAwsRequestId());
}
}
diff --git a/src/Event/Http/HttpResponse.php b/src/Event/Http/HttpResponse.php
index 80a679bc2..76c24d5d7 100644
--- a/src/Event/Http/HttpResponse.php
+++ b/src/Event/Http/HttpResponse.php
@@ -21,7 +21,7 @@ public function __construct(string $body, array $headers = [], int $statusCode =
$this->statusCode = $statusCode;
}
- public function toApiGatewayFormat(bool $multiHeaders = false): array
+ public function toApiGatewayFormat(bool $multiHeaders = false, ?string $awsRequestId = null): array
{
$base64Encoding = (bool) getenv('BREF_BINARY_RESPONSES');
@@ -38,6 +38,8 @@ public function toApiGatewayFormat(bool $multiHeaders = false): array
}
}
+ $this->checkHeadersSize($headers, $awsRequestId);
+
// The headers must be a JSON object. If the PHP array is empty it is
// serialized to `[]` (we want `{}`) so we force it to an empty object.
$headers = empty($headers) ? new \stdClass : $headers;
@@ -58,7 +60,7 @@ public function toApiGatewayFormat(bool $multiHeaders = false): array
/**
* See https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html#http-api-develop-integrations-lambda.response
*/
- public function toApiGatewayFormatV2(): array
+ public function toApiGatewayFormatV2(?string $awsRequestId = null): array
{
$base64Encoding = (bool) getenv('BREF_BINARY_RESPONSES');
@@ -76,6 +78,11 @@ public function toApiGatewayFormatV2(): array
}
}
+ $this->checkHeadersSize(array_merge(
+ $headers,
+ ['Set-Cookie' => $cookies], // include cookies in the size check
+ ), $awsRequestId);
+
// The headers must be a JSON object. If the PHP array is empty it is
// serialized to `[]` (we want `{}`) so we force it to an empty object.
$headers = empty($headers) ? new \stdClass : $headers;
@@ -98,4 +105,31 @@ private function capitalizeHeaderName(string $name): string
$name = ucwords($name);
return str_replace(' ', '-', $name);
}
+
+ /**
+ * API Gateway v1 and v2 have a headers total max size of 10 KB.
+ * ALB has a max size of 32 KB.
+ * It's hard to calculate the exact size of headers here, so we just
+ * estimate it roughly: if above 9.5 KB we log a warning.
+ *
+ * @param array $headers
+ */
+ private function checkHeadersSize(array $headers, ?string $awsRequestId): void
+ {
+ $estimatedHeadersSize = 0;
+ foreach ($headers as $name => $values) {
+ $estimatedHeadersSize += strlen($name);
+ if (is_array($values)) {
+ foreach ($values as $value) {
+ $estimatedHeadersSize += strlen($value);
+ }
+ } else {
+ $estimatedHeadersSize += strlen($values);
+ }
+ }
+
+ if ($estimatedHeadersSize > 9_500) {
+ echo "$awsRequestId\tWARNING\tThe total size of HTTP response headers is estimated to be above 10 KB, which is the API Gateway limit. If the limit is reached, the HTTP response will be a 500 error.\n";
+ }
+ }
}
diff --git a/src/FpmRuntime/FpmHandler.php b/src/FpmRuntime/FpmHandler.php
index caa1ef145..6931b9caa 100644
--- a/src/FpmRuntime/FpmHandler.php
+++ b/src/FpmRuntime/FpmHandler.php
@@ -43,7 +43,7 @@ final class FpmHandler extends HttpHandler
*/
private const SIGTERM = 15;
- private ?Client $client;
+ private ?Client $client = null;
private UnixDomainSocket $connection;
private string $handler;
private string $configFile;
@@ -76,8 +76,20 @@ public function start(): void
/**
* --nodaemonize: we want to keep control of the process
* --force-stderr: force logs to be sent to stderr, which will allow us to send them to CloudWatch
+ * TODO set `max_execution_time` to the timeout of the Lambda function?
*/
- $resource = @proc_open(['php-fpm', '--nodaemonize', '--force-stderr', '--fpm-config', $this->configFile], [], $pipes);
+ $resource = @proc_open([
+ 'php-fpm',
+ '--nodaemonize',
+ '--force-stderr',
+ '--fpm-config',
+ $this->configFile,
+ // This setting is enabled by default for CLI invocations because it
+ // improves performance. We disable if it for PHP-FPM manually
+ // because it tanks performance by essentially disabling opcache
+ '-d',
+ 'opcache.file_cache_only=0',
+ ], [], $pipes);
if (! is_resource($resource)) {
throw new RuntimeException('PHP-FPM failed to start');
diff --git a/src/FpmRuntime/Main.php b/src/FpmRuntime/Main.php
index 2eb7c6a0c..8ec401ea3 100755
--- a/src/FpmRuntime/Main.php
+++ b/src/FpmRuntime/Main.php
@@ -16,15 +16,10 @@ class Main
{
public static function run(): void
{
- // In the FPM runtime process (our process) we want to log all errors and warnings
- ini_set('display_errors', '1');
- error_reporting(E_ALL);
-
ColdStartTracker::init();
LazySecretsLoader::loadSecretEnvironmentVariables();
- Bref::triggerHooks('beforeStartup');
Bref::events()->beforeStartup();
$lambdaRuntime = LambdaRuntime::fromEnvironmentVariable('fpm');
diff --git a/src/FunctionRuntime/Main.php b/src/FunctionRuntime/Main.php
index 7a4dda0de..823293f03 100644
--- a/src/FunctionRuntime/Main.php
+++ b/src/FunctionRuntime/Main.php
@@ -19,7 +19,6 @@ public static function run(): void
LazySecretsLoader::loadSecretEnvironmentVariables();
- Bref::triggerHooks('beforeStartup');
Bref::events()->beforeStartup();
$lambdaRuntime = LambdaRuntime::fromEnvironmentVariable('function');
diff --git a/src/Runtime/LambdaRuntime.php b/src/Runtime/LambdaRuntime.php
index 17fa52e65..4c7796c73 100755
--- a/src/Runtime/LambdaRuntime.php
+++ b/src/Runtime/LambdaRuntime.php
@@ -35,10 +35,8 @@
*/
final class LambdaRuntime
{
- /** @var resource|CurlHandle|null */
- private $curlHandleNext;
- /** @var resource|CurlHandle|null */
- private $curlHandleResult;
+ private ?CurlHandle $curlHandleNext = null;
+ private ?CurlHandle $curlHandleResult = null;
private string $apiUrl;
private Invoker $invoker;
private string $layer;
@@ -84,11 +82,13 @@ public function processNextEvent(Handler | RequestHandlerInterface | callable $h
// Expose the context in an environment variable
$this->setEnv('LAMBDA_INVOCATION_CONTEXT', json_encode($context, JSON_THROW_ON_ERROR));
+ // These are used for logging/tracing purposes
+ $this->setEnv('LAMBDA_REQUEST_ID', $context->getAwsRequestId());
+ $this->setEnv('_X_AMZN_TRACE_ID', $context->getTraceId());
try {
ColdStartTracker::invocationStarted();
- Bref::triggerHooks('beforeInvoke');
Bref::events()->beforeInvoke($handler, $event, $context);
$this->ping();
@@ -337,7 +337,6 @@ private function postJson(string $url, mixed $data, array $headers = []): void
private function closeCurlHandleNext(): void
{
if ($this->curlHandleNext !== null) {
- curl_close($this->curlHandleNext);
$this->curlHandleNext = null;
}
}
@@ -345,7 +344,6 @@ private function closeCurlHandleNext(): void
private function closeCurlHandleResult(): void
{
if ($this->curlHandleResult !== null) {
- curl_close($this->curlHandleResult);
$this->curlHandleResult = null;
}
}
diff --git a/src/bref-local b/src/bref-local
index 63e77d5ac..b66882e3b 100755
--- a/src/bref-local
+++ b/src/bref-local
@@ -22,13 +22,19 @@ $opts = getopt('', ['path:']);
if (isset($opts['path'])) {
if (! file_exists($opts['path'])) {
- throw new Exception('The file ' . $opts['path'] . ' could not be found.');
+ error_log('The file ' . $opts['path'] . ' could not be found.');
+ exit(1);
}
$handler = $argv[array_key_last($argv)];
$data = file_get_contents($opts['path']);
}
+if (!$handler) {
+ error_log('You must provide the handler to invoke as the first argument.');
+ exit(1);
+}
+
try {
$handler = Bref::getContainer()->get($handler);
} catch (NotFoundExceptionInterface $e) {
@@ -38,7 +44,8 @@ try {
try {
$event = $data ? json_decode($data, true, 512, JSON_THROW_ON_ERROR) : null;
} catch (JsonException $e) {
- throw new Exception('The JSON provided for the event data is invalid JSON.');
+ error_log('The JSON provided for the event data is invalid JSON.');
+ exit(1);
}
// Same configuration as the Bref runtime on Lambda
diff --git a/template/function/index.php b/template/function/index.php
deleted file mode 100644
index 346496cb7..000000000
--- a/template/function/index.php
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
- Welcome!
-
-
-
-
-
-
-
diff --git a/template/http/serverless.yml b/template/http/serverless.yml
deleted file mode 100644
index 65f86f77e..000000000
--- a/template/http/serverless.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-service: app
-
-# Set your team ID if you are using Bref Cloud
-#bref:
-# team: my-team-id
-
-provider:
- name: aws
- region: us-east-1
-
-plugins:
- - ./vendor/bref/bref
-
-functions:
- api:
- handler: index.php
- description: ''
- runtime: php-PHP_VERSION-fpm
- timeout: 28 # in seconds (API Gateway has a timeout of 29 seconds)
- events:
- - httpApi: '*'
-
-# Exclude files from deployment
-package:
- patterns:
- - '!node_modules/**'
- - '!tests/**'
diff --git a/template/symfony/serverless.yml b/template/symfony/serverless.yml
deleted file mode 100644
index 48c49adb6..000000000
--- a/template/symfony/serverless.yml
+++ /dev/null
@@ -1,47 +0,0 @@
-# Read the documentation at https://bref.sh/docs/symfony/getting-started
-service: symfony
-
-# Set your team ID if you are using Bref Cloud
-#bref:
-# team: my-team-id
-
-provider:
- name: aws
- # The AWS region in which to deploy (us-east-1 is the default)
- region: us-east-1
- environment:
- # Symfony environment variables
- APP_ENV: prod
-
-plugins:
- - ./vendor/bref/bref
-
-functions:
-
- # This function runs the Symfony website/API
- web:
- handler: public/index.php
- runtime: php-82-fpm
- timeout: 28 # in seconds (API Gateway has a timeout of 29 seconds)
- events:
- - httpApi: '*'
-
- # This function let us run console commands in Lambda
- console:
- handler: bin/console
- runtime: php-82-console
- timeout: 120 # in seconds
-
-package:
- patterns:
- # Excluded files and folders for deployment
- - '!assets/**'
- - '!node_modules/**'
- - '!public/build/**'
- - '!tests/**'
- - '!var/**'
- # If you want to include files and folders that are part of excluded folders,
- # add them at the end
- - 'var/cache/prod/**'
- - 'public/build/entrypoints.json'
- - 'public/build/manifest.json'
diff --git a/tests/BrefTest.php b/tests/BrefTest.php
index 4ebbd05cd..8be54f30a 100644
--- a/tests/BrefTest.php
+++ b/tests/BrefTest.php
@@ -30,34 +30,4 @@ public function test override the container(): void
$this->assertSame($container, Bref::getContainer());
}
-
- public function test hooks(): void
- {
- $beforeStartup1 = false;
- $beforeStartup2 = false;
- $beforeInvoke = false;
-
- // Check that we can set multiple handlers
- Bref::beforeStartup(function () use (&$beforeStartup1) {
- return $beforeStartup1 = true;
- });
- Bref::beforeStartup(function () use (&$beforeStartup2) {
- return $beforeStartup2 = true;
- });
- Bref::beforeInvoke(function () use (&$beforeInvoke) {
- return $beforeInvoke = true;
- });
-
- $this->assertFalse($beforeStartup1);
- $this->assertFalse($beforeStartup2);
- $this->assertFalse($beforeInvoke);
-
- Bref::triggerHooks('beforeStartup');
- $this->assertTrue($beforeStartup1);
- $this->assertTrue($beforeStartup2);
- $this->assertFalse($beforeInvoke);
-
- Bref::triggerHooks('beforeInvoke');
- $this->assertTrue($beforeInvoke);
- }
}
diff --git a/tests/CliTest.php b/tests/CliTest.php
deleted file mode 100644
index 09b03afc0..000000000
--- a/tests/CliTest.php
+++ /dev/null
@@ -1,16 +0,0 @@
-mustRun();
- self::assertNotEmpty($process->getOutput());
- }
-}
diff --git a/tests/ConsoleRuntime/MainTest.php b/tests/ConsoleRuntime/MainTest.php
index 37785ae50..0b3f1946a 100644
--- a/tests/ConsoleRuntime/MainTest.php
+++ b/tests/ConsoleRuntime/MainTest.php
@@ -2,12 +2,10 @@
namespace Bref\Test\ConsoleRuntime;
-use Bref\Bref;
use Bref\ConsoleRuntime\CommandFailed;
use Bref\ConsoleRuntime\Main;
use Bref\Test\RuntimeTestCase;
use Bref\Test\Server;
-use Exception;
class MainTest extends RuntimeTestCase
{
@@ -19,16 +17,6 @@ public function setUp(): void
putenv('_HANDLER=console.php');
}
- public function test startup hook is called()
- {
- Bref::beforeStartup(function () {
- throw new Exception('This should be called');
- });
-
- $this->expectExceptionMessage('This should be called');
- Main::run();
- }
-
public function test happy path()
{
$this->givenAnEvent('');
diff --git a/tests/Event/Http/CommonHttpTest.php b/tests/Event/Http/CommonHttpTest.php
index 1c4805901..c3940b5fa 100644
--- a/tests/Event/Http/CommonHttpTest.php
+++ b/tests/Event/Http/CommonHttpTest.php
@@ -7,7 +7,7 @@
abstract class CommonHttpTest extends TestCase implements HttpRequestProxyTest
{
- public function provide API Gateway versions(): array
+ public static function provide API Gateway versions(): array
{
return [
'v1' => [1],
@@ -232,7 +232,7 @@ public function test POST request with form data and content type(int $v
]);
}
- public function provideHttpMethodsWithRequestBodySupport(): array
+ public static function provideHttpMethodsWithRequestBodySupport(): array
{
return [
'POST v1' => [
diff --git a/tests/Event/Http/HttpRequestEventTest.php b/tests/Event/Http/HttpRequestEventTest.php
index 925a324f9..bf9868450 100644
--- a/tests/Event/Http/HttpRequestEventTest.php
+++ b/tests/Event/Http/HttpRequestEventTest.php
@@ -168,7 +168,7 @@ public function test query string to array(string $query, array $expectedOut
$this->assertEquals($expectedOutput, $result);
}
- public function provide query strings(): iterable
+ public static function provide query strings(): iterable
{
yield ['', []];
@@ -248,7 +248,7 @@ public function test query string will be parsed correctly(array $expected
self::assertSame($normalizedQs, $event->getQueryString());
}
- public function provide query strings for event(): array
+ public static function provide query strings for event(): array
{
return [
[['foo' => 'bar'], 'foo=bar', 'foo=bar'],
diff --git a/tests/FpmRuntime/FpmHandlerTest.php b/tests/FpmRuntime/FpmHandlerTest.php
index 9ae4e7ce0..ae79a40a5 100644
--- a/tests/FpmRuntime/FpmHandlerTest.php
+++ b/tests/FpmRuntime/FpmHandlerTest.php
@@ -30,7 +30,7 @@ public function tearDown(): void
ob_end_clean();
}
- public function provide API Gateway versions(): array
+ public static function provide API Gateway versions(): array
{
return [
'v1' => [1],
@@ -480,7 +480,7 @@ public function test POST request with form data and content type(int $v
]);
}
- public function provideHttpMethodsWithRequestBodySupport(): array
+ public static function provideHttpMethodsWithRequestBodySupport(): array
{
return [
'POST v1' => [
@@ -883,12 +883,6 @@ public function test POST request with multipart file uploads(int $version
'HTTP_RAW_BODY' => '',
];
- if (\PHP_VERSION_ID < 80100) {
- // full_path was introduced in PHP 8.1, remove it for lower versions
- unset($expectedGlobalVariables['$_FILES']['foo']['full_path']);
- unset($expectedGlobalVariables['$_FILES']['bar']['full_path']);
- }
-
$this->assertGlobalVariables($event, $expectedGlobalVariables);
}
@@ -1139,7 +1133,7 @@ public function test response with status code(int $expectedStatusCode)
self::assertEquals($expectedStatusCode, $statusCode);
}
- public function provideStatusCodes(): array
+ public static function provideStatusCodes(): array
{
return [[200], [301], [302], [400], [401], [403], [404], [500], [504]];
}
diff --git a/tests/FpmRuntime/Functional/serverless.yml b/tests/FpmRuntime/Functional/serverless.yml
index 07c108f43..66bf3ea41 100644
--- a/tests/FpmRuntime/Functional/serverless.yml
+++ b/tests/FpmRuntime/Functional/serverless.yml
@@ -2,7 +2,7 @@ service: bref-tests
provider:
name: aws
- runtime: provided.al2
+ runtime: provided.al2023
region: eu-west-1
profile: bref-tests
apiGateway:
diff --git a/tests/FpmRuntime/MainTest.php b/tests/FpmRuntime/MainTest.php
deleted file mode 100644
index 7c0aa5c16..000000000
--- a/tests/FpmRuntime/MainTest.php
+++ /dev/null
@@ -1,21 +0,0 @@
-expectExceptionMessage('This should be called');
- Main::run();
- }
-}
diff --git a/tests/FunctionRuntime/MainTest.php b/tests/FunctionRuntime/MainTest.php
deleted file mode 100644
index 97fe60eaf..000000000
--- a/tests/FunctionRuntime/MainTest.php
+++ /dev/null
@@ -1,21 +0,0 @@
-expectExceptionMessage('This should be called');
- Main::run();
- }
-}
diff --git a/tests/PluginTest.php b/tests/PluginTest.php
index afc00d6d6..22684ff5d 100644
--- a/tests/PluginTest.php
+++ b/tests/PluginTest.php
@@ -2,6 +2,9 @@
namespace Bref\Test;
+use Bref\ConsoleRuntime\Main as ConsoleMain;
+use Bref\FpmRuntime\Main as FpmMain;
+use Bref\FunctionRuntime\Main as FunctionMain;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Process\Process;
use Symfony\Component\Yaml\Yaml;
@@ -12,26 +15,24 @@ public function test the plugin adds the layers(): void
{
$output = $this->slsPrint('serverless.yml');
- self::assertFunction($output['functions']['function'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:php-83:',
+ self::assertFunction($output['functions']['function'], FunctionMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:php-83:',
]);
- self::assertFunction($output['functions']['fpm'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:php-83-fpm:',
+ self::assertFunction($output['functions']['fpm'], FpmMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:php-83:',
]);
- self::assertFunction($output['functions']['console'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:php-83:',
- 'arn:aws:lambda:us-east-1:534081306603:layer:console:',
+ self::assertFunction($output['functions']['console'], ConsoleMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:php-83:',
]);
- self::assertFunction($output['functions']['function-arm'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:arm-php-83:',
+ self::assertFunction($output['functions']['function-arm'], FunctionMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:arm-php-83:',
]);
- self::assertFunction($output['functions']['fpm-arm'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:arm-php-83-fpm:',
+ self::assertFunction($output['functions']['fpm-arm'], FpmMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:arm-php-83:',
]);
- self::assertFunction($output['functions']['console-arm'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:arm-php-83:',
- 'arn:aws:lambda:us-east-1:534081306603:layer:console:',
+ self::assertFunction($output['functions']['console-arm'], ConsoleMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:arm-php-83:',
]);
}
@@ -39,11 +40,11 @@ public function test the plugin adds the layers when the runtime is se
{
$output = $this->slsPrint('serverless-runtime-root.yml');
- self::assertFunction($output['functions']['function'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:php-83:',
+ self::assertFunction($output['functions']['function'], FunctionMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:php-83:',
]);
- self::assertFunction($output['functions']['function-arm'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:arm-php-83:',
+ self::assertFunction($output['functions']['function-arm'], FunctionMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:arm-php-83:',
]);
}
@@ -51,22 +52,22 @@ public function test the plugin doesnt break layers added separately(): v
{
$output = $this->slsPrint('serverless-with-layers.yml');
- self::assertFunction($output['functions']['function'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:php-83:',
+ self::assertFunction($output['functions']['function'], FunctionMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:php-83:',
'arn:aws:lambda:us-east-1:1234567890:layer:foo:1',
]);
- self::assertFunction($output['functions']['function-arm'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:arm-php-83:',
+ self::assertFunction($output['functions']['function-arm'], FunctionMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:arm-php-83:',
'arn:aws:lambda:us-east-1:1234567890:layer:foo:1',
]);
- self::assertFunction($output['functions']['function-with-layers'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:php-83:',
+ self::assertFunction($output['functions']['function-with-layers'], FunctionMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:php-83:',
// This function doesn't have the `foo` layer because that's how SF works:
// layers in the function completely override the layers in the root
'arn:aws:lambda:us-east-1:1234567890:layer:bar:1',
]);
- self::assertFunction($output['functions']['function-arm-with-layers'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:arm-php-83:',
+ self::assertFunction($output['functions']['function-arm-with-layers'], FunctionMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:arm-php-83:',
// This function doesn't have the `foo` layer because that's how SF works:
// layers in the function completely override the layers in the root
'arn:aws:lambda:us-east-1:1234567890:layer:bar:1',
@@ -77,22 +78,22 @@ public function test the plugin doesnt break layers added separately wit
{
$output = $this->slsPrint('serverless-runtime-root-with-layers.yml');
- self::assertFunction($output['functions']['function'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:php-83:',
+ self::assertFunction($output['functions']['function'], FunctionMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:php-83:',
'arn:aws:lambda:us-east-1:1234567890:layer:foo:1',
]);
- self::assertFunction($output['functions']['function-arm'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:arm-php-83:',
+ self::assertFunction($output['functions']['function-arm'], FunctionMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:arm-php-83:',
'arn:aws:lambda:us-east-1:1234567890:layer:foo:1',
]);
- self::assertFunction($output['functions']['function-with-layers'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:php-83:',
+ self::assertFunction($output['functions']['function-with-layers'], FunctionMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:php-83:',
// This function doesn't have the `foo` layer because that's how SF works:
// layers in the function completely override the layers in the root
'arn:aws:lambda:us-east-1:1234567890:layer:bar:1',
]);
- self::assertFunction($output['functions']['function-arm-with-layers'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:arm-php-83:',
+ self::assertFunction($output['functions']['function-arm-with-layers'], FunctionMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:arm-php-83:',
// This function doesn't have the `foo` layer because that's how SF works:
// layers in the function completely override the layers in the root
'arn:aws:lambda:us-east-1:1234567890:layer:bar:1',
@@ -111,9 +112,10 @@ private function slsPrint(string $configFile): array
return Yaml::parse($process->getOutput());
}
- private static function assertFunction(array $config, array $layers): void
+ private static function assertFunction(array $config, string $brefRuntime, array $layers): void
{
- self::assertEquals('provided.al2', $config['runtime']);
+ self::assertEquals('provided.al2023', $config['runtime']);
+ self::assertEquals($brefRuntime, $config['environment']['BREF_RUNTIME']);
self::assertCount(count($layers), $config['layers'], sprintf('Expected %d layers, got %d: %s', count($layers), count($config['layers']), json_encode($config['layers'], JSON_THROW_ON_ERROR)));
foreach ($layers as $index => $layer) {
self::assertStringStartsWith($layer, $config['layers'][$index]);
diff --git a/tests/Runtime/LambdaRuntimeTest.php b/tests/Runtime/LambdaRuntimeTest.php
index aecc7d89a..1f468d533 100644
--- a/tests/Runtime/LambdaRuntimeTest.php
+++ b/tests/Runtime/LambdaRuntimeTest.php
@@ -428,7 +428,21 @@ public function afterInvoke(mixed ...$params): void
// The error response was already sent, it contains the handler error
$this->assertInvocationErrorResult('Exception', 'Invocation error');
// The logs should contain both the handler error and the afterInvoke error
- $this->assertStringContainsString('Invoke Error {"errorType":"Exception","errorMessage":"Invocation error","stack":', $this->getActualOutput());
- $this->assertStringContainsString('Invoke Error {"errorType":"Exception","errorMessage":"This is an exception in afterInvoke","stack":', $this->getActualOutput());
+ $this->assertStringContainsString('Invoke Error {"errorType":"Exception","errorMessage":"Invocation error","stack":', $this->output());
+ $this->assertStringContainsString('Invoke Error {"errorType":"Exception","errorMessage":"This is an exception in afterInvoke","stack":', $this->output());
+ }
+
+ public function test request id env variables()
+ {
+ $this->givenAnEvent([]);
+
+ $this->runtime->processNextEvent(function () use (&$requestId, &$traceId) {
+ $requestId = getenv('LAMBDA_REQUEST_ID');
+ $traceId = getenv('_X_AMZN_TRACE_ID');
+ return ['hello' => 'world'];
+ });
+
+ $this->assertSame('1', $requestId);
+ $this->assertSame('Root=1-67891233-abcdef012345678912345678', $traceId);
}
}
diff --git a/tests/RuntimeTestCase.php b/tests/RuntimeTestCase.php
index 9cf2602b0..74bd44e76 100644
--- a/tests/RuntimeTestCase.php
+++ b/tests/RuntimeTestCase.php
@@ -34,6 +34,7 @@ protected function givenAnEvent(mixed $event): void
[
'lambda-runtime-aws-request-id' => '1',
'lambda-runtime-invoked-function-arn' => 'test-function-name',
+ 'lambda-runtime-trace-id' => 'Root=1-67891233-abcdef012345678912345678',
],
json_encode($event, JSON_THROW_ON_ERROR)
),
@@ -80,7 +81,7 @@ protected function assertInvocationErrorResult(string $errorClass, string $error
protected function assertErrorInLogs(string $errorClass, string $errorMessage): void
{
// Decode the logs from stdout
- $stdout = $this->getActualOutput();
+ $stdout = $this->output();
[$requestId, $message, $json] = explode("\t", $stdout);
@@ -108,7 +109,7 @@ protected function assertErrorInLogs(string $errorClass, string $errorMessage):
protected function assertPreviousErrorsInLogs(array $previousErrors): void
{
// Decode the logs from stdout
- $stdout = $this->getActualOutput();
+ $stdout = $this->output();
[, , $json] = explode("\t", $stdout);
diff --git a/tests/Sam/template.yaml b/tests/Sam/template.yaml
index 7e262270f..05ca94f6b 100644
--- a/tests/Sam/template.yaml
+++ b/tests/Sam/template.yaml
@@ -8,9 +8,9 @@ Resources:
FunctionName: 'bref-tests-function'
CodeUri: ../..
Handler: tests/Sam/Php/function.php
- Runtime: provided.al2
+ Runtime: provided.al2023
Layers:
- - 'arn:aws:lambda:us-east-1:534081306603:layer:php-74:18'
+ - 'arn:aws:lambda:us-east-1:873528684822:layer:php-74:18'
Environment:
Variables:
FOO: bar
@@ -21,9 +21,9 @@ Resources:
FunctionName: 'bref-tests-http'
CodeUri: ../..
Handler: tests/Sam/PhpFpm/index.php
- Runtime: provided.al2
+ Runtime: provided.al2023
Layers:
- - 'arn:aws:lambda:us-east-1:534081306603:layer:php-74-fpm:18'
+ - 'arn:aws:lambda:us-east-1:873528684822:layer:php-74-fpm:18'
Events:
HttpRoot:
Type: Api
@@ -40,9 +40,9 @@ Resources:
FunctionName: 'bref-tests-http-missing-handler'
CodeUri: ../..
Handler: tests/Sam/PhpFpm/UNKNOWN.php
- Runtime: provided.al2
+ Runtime: provided.al2023
Layers:
- - 'arn:aws:lambda:us-east-1:534081306603:layer:php-74-fpm:18'
+ - 'arn:aws:lambda:us-east-1:873528684822:layer:php-74-fpm:18'
Events:
HttpRoot:
Type: Api
@@ -56,9 +56,9 @@ Resources:
FunctionName: 'bref-tests-psr7'
CodeUri: ../..
Handler: tests/Sam/Php/psr7.php
- Runtime: provided.al2
+ Runtime: provided.al2023
Layers:
- - 'arn:aws:lambda:us-east-1:534081306603:layer:php-74:18'
+ - 'arn:aws:lambda:us-east-1:873528684822:layer:php-74:18'
Events:
HttpRoot:
Type: Api
diff --git a/utils/layers.json/regions.json b/utils/layers.json/regions.json
index 5940d586c..0d0d125b3 100644
--- a/utils/layers.json/regions.json
+++ b/utils/layers.json/regions.json
@@ -17,8 +17,10 @@
"ap-northeast-3",
"ap-southeast-1",
"ap-southeast-2",
+ "ap-southeast-3",
"eu-south-1",
"eu-south-2",
"af-south-1",
- "me-south-1"
+ "me-south-1",
+ "me-central-1"
]
diff --git a/utils/layers.json/update.php b/utils/layers.json/update.php
index 3d2412119..0897e8abf 100644
--- a/utils/layers.json/update.php
+++ b/utils/layers.json/update.php
@@ -13,27 +13,14 @@
require_once __DIR__ . '/../../vendor/autoload.php';
const LAYER_NAMES = [
+ 'php-85',
'php-84',
- 'php-84-fpm',
'php-83',
- 'php-83-fpm',
'php-82',
- 'php-82-fpm',
- 'php-81',
- 'php-81-fpm',
- 'php-80',
- 'php-80-fpm',
+ 'arm-php-85',
'arm-php-84',
- 'arm-php-84-fpm',
'arm-php-83',
- 'arm-php-83-fpm',
'arm-php-82',
- 'arm-php-82-fpm',
- 'arm-php-81',
- 'arm-php-81-fpm',
- 'arm-php-80',
- 'arm-php-80-fpm',
- 'console',
];
$regions = json_decode(file_get_contents(__DIR__ . '/regions.json'), true);
@@ -66,7 +53,7 @@ function lambdaClient(string $region): LambdaClient
]);
$credentials = $stsClient->AssumeRole([
- 'RoleArn' => 'arn:aws:iam::534081306603:role/bref-layer-publisher',
+ 'RoleArn' => 'arn:aws:iam::873528684822:role/bref-layer-publisher',
'RoleSessionName' => 'bref-layer-builder',
]);
@@ -90,7 +77,7 @@ function listLayers(LambdaClient $lambda, string $selectedRegion): array
foreach (LAYER_NAMES as $layerName) {
$results[$layerName] = $lambda->listLayerVersions([
- 'LayerName' => sprintf('arn:aws:lambda:%s:534081306603:layer:%s', $selectedRegion, $layerName),
+ 'LayerName' => sprintf('arn:aws:lambda:%s:873528684822:layer:%s', $selectedRegion, $layerName),
'MaxItems' => 1,
]);
}
diff --git a/website/next.config.js b/website/next.config.js
index f57debbbd..307e842ae 100644
--- a/website/next.config.js
+++ b/website/next.config.js
@@ -27,6 +27,15 @@ module.exports = withNextra(withPlausibleProxy()({
...redirectList,
]
},
+ // Serve Markdown versions of docs for AI crawlers
+ async rewrites() {
+ return [
+ {
+ source: '/docs/:path*.md',
+ destination: '/api/md/:path*',
+ },
+ ]
+ },
}));
// If you have other Next.js configurations, you can pass them as the parameter:
diff --git a/website/package-lock.json b/website/package-lock.json
index 0f8e5a6a2..f04dee50d 100644
--- a/website/package-lock.json
+++ b/website/package-lock.json
@@ -11,7 +11,7 @@
"@headlessui/react": "^2.2.0",
"@heroicons/react": "^2.0.18",
"@octokit/graphql": "^7.0.1",
- "next": "^14.2.32",
+ "next": "^14.2.35",
"next-plausible": "^3.11.1",
"next-seo": "^6.1.0",
"next-sitemap": "^4.2.3",
@@ -1299,15 +1299,15 @@
}
},
"node_modules/@next/env": {
- "version": "14.2.32",
- "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.32.tgz",
- "integrity": "sha512-n9mQdigI6iZ/DF6pCTwMKeWgF2e8lg7qgt5M7HXMLtyhZYMnf/u905M18sSpPmHL9MKp9JHo56C6jrD2EvWxng==",
+ "version": "14.2.35",
+ "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.35.tgz",
+ "integrity": "sha512-DuhvCtj4t9Gwrx80dmz2F4t/zKQ4ktN8WrMwOuVzkJfBilwAwGr6v16M5eI8yCuZ63H9TTuEU09Iu2HqkzFPVQ==",
"license": "MIT"
},
"node_modules/@next/swc-darwin-arm64": {
- "version": "14.2.32",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.32.tgz",
- "integrity": "sha512-osHXveM70zC+ilfuFa/2W6a1XQxJTvEhzEycnjUaVE8kpUS09lDpiDDX2YLdyFCzoUbvbo5r0X1Kp4MllIOShw==",
+ "version": "14.2.33",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.33.tgz",
+ "integrity": "sha512-HqYnb6pxlsshoSTubdXKu15g3iivcbsMXg4bYpjL2iS/V6aQot+iyF4BUc2qA/J/n55YtvE4PHMKWBKGCF/+wA==",
"cpu": [
"arm64"
],
@@ -1321,9 +1321,9 @@
}
},
"node_modules/@next/swc-darwin-x64": {
- "version": "14.2.32",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.32.tgz",
- "integrity": "sha512-P9NpCAJuOiaHHpqtrCNncjqtSBi1f6QUdHK/+dNabBIXB2RUFWL19TY1Hkhu74OvyNQEYEzzMJCMQk5agjw1Qg==",
+ "version": "14.2.33",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.33.tgz",
+ "integrity": "sha512-8HGBeAE5rX3jzKvF593XTTFg3gxeU4f+UWnswa6JPhzaR6+zblO5+fjltJWIZc4aUalqTclvN2QtTC37LxvZAA==",
"cpu": [
"x64"
],
@@ -1337,9 +1337,9 @@
}
},
"node_modules/@next/swc-linux-arm64-gnu": {
- "version": "14.2.32",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.32.tgz",
- "integrity": "sha512-v7JaO0oXXt6d+cFjrrKqYnR2ubrD+JYP7nQVRZgeo5uNE5hkCpWnHmXm9vy3g6foMO8SPwL0P3MPw1c+BjbAzA==",
+ "version": "14.2.33",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.33.tgz",
+ "integrity": "sha512-JXMBka6lNNmqbkvcTtaX8Gu5by9547bukHQvPoLe9VRBx1gHwzf5tdt4AaezW85HAB3pikcvyqBToRTDA4DeLw==",
"cpu": [
"arm64"
],
@@ -1353,9 +1353,9 @@
}
},
"node_modules/@next/swc-linux-arm64-musl": {
- "version": "14.2.32",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.32.tgz",
- "integrity": "sha512-tA6sIKShXtSJBTH88i0DRd6I9n3ZTirmwpwAqH5zdJoQF7/wlJXR8DkPmKwYl5mFWhEKr5IIa3LfpMW9RRwKmQ==",
+ "version": "14.2.33",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.33.tgz",
+ "integrity": "sha512-Bm+QulsAItD/x6Ih8wGIMfRJy4G73tu1HJsrccPW6AfqdZd0Sfm5Imhgkgq2+kly065rYMnCOxTBvmvFY1BKfg==",
"cpu": [
"arm64"
],
@@ -1369,9 +1369,9 @@
}
},
"node_modules/@next/swc-linux-x64-gnu": {
- "version": "14.2.32",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.32.tgz",
- "integrity": "sha512-7S1GY4TdnlGVIdeXXKQdDkfDysoIVFMD0lJuVVMeb3eoVjrknQ0JNN7wFlhCvea0hEk0Sd4D1hedVChDKfV2jw==",
+ "version": "14.2.33",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.33.tgz",
+ "integrity": "sha512-FnFn+ZBgsVMbGDsTqo8zsnRzydvsGV8vfiWwUo1LD8FTmPTdV+otGSWKc4LJec0oSexFnCYVO4hX8P8qQKaSlg==",
"cpu": [
"x64"
],
@@ -1385,9 +1385,9 @@
}
},
"node_modules/@next/swc-linux-x64-musl": {
- "version": "14.2.32",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.32.tgz",
- "integrity": "sha512-OHHC81P4tirVa6Awk6eCQ6RBfWl8HpFsZtfEkMpJ5GjPsJ3nhPe6wKAJUZ/piC8sszUkAgv3fLflgzPStIwfWg==",
+ "version": "14.2.33",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.33.tgz",
+ "integrity": "sha512-345tsIWMzoXaQndUTDv1qypDRiebFxGYx9pYkhwY4hBRaOLt8UGfiWKr9FSSHs25dFIf8ZqIFaPdy5MljdoawA==",
"cpu": [
"x64"
],
@@ -1401,9 +1401,9 @@
}
},
"node_modules/@next/swc-win32-arm64-msvc": {
- "version": "14.2.32",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.32.tgz",
- "integrity": "sha512-rORQjXsAFeX6TLYJrCG5yoIDj+NKq31Rqwn8Wpn/bkPNy5rTHvOXkW8mLFonItS7QC6M+1JIIcLe+vOCTOYpvg==",
+ "version": "14.2.33",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.33.tgz",
+ "integrity": "sha512-nscpt0G6UCTkrT2ppnJnFsYbPDQwmum4GNXYTeoTIdsmMydSKFz9Iny2jpaRupTb+Wl298+Rh82WKzt9LCcqSQ==",
"cpu": [
"arm64"
],
@@ -1417,9 +1417,9 @@
}
},
"node_modules/@next/swc-win32-ia32-msvc": {
- "version": "14.2.32",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.32.tgz",
- "integrity": "sha512-jHUeDPVHrgFltqoAqDB6g6OStNnFxnc7Aks3p0KE0FbwAvRg6qWKYF5mSTdCTxA3axoSAUwxYdILzXJfUwlHhA==",
+ "version": "14.2.33",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.33.tgz",
+ "integrity": "sha512-pc9LpGNKhJ0dXQhZ5QMmYxtARwwmWLpeocFmVG5Z0DzWq5Uf0izcI8tLc+qOpqxO1PWqZ5A7J1blrUIKrIFc7Q==",
"cpu": [
"ia32"
],
@@ -1433,9 +1433,9 @@
}
},
"node_modules/@next/swc-win32-x64-msvc": {
- "version": "14.2.32",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.32.tgz",
- "integrity": "sha512-2N0lSoU4GjfLSO50wvKpMQgKd4HdI2UHEhQPPPnlgfBJlOgJxkjpkYBqzk08f1gItBB6xF/n+ykso2hgxuydsA==",
+ "version": "14.2.33",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.33.tgz",
+ "integrity": "sha512-nOjfZMy8B94MdisuzZo9/57xuFVLHJaDj5e/xrduJp9CV2/HrfxTRH2fbyLe+K9QT41WBLUd4iXX3R7jBp0EUg==",
"cpu": [
"x64"
],
@@ -2370,6 +2370,13 @@
"csstype": "^3.0.2"
}
},
+ "node_modules/@types/trusted-types": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
+ "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
+ "license": "MIT",
+ "optional": true
+ },
"node_modules/@types/unist": {
"version": "2.0.10",
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz",
@@ -3059,6 +3066,7 @@
"version": "7.9.0",
"resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz",
"integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==",
+ "license": "ISC",
"dependencies": {
"d3-array": "3",
"d3-axis": "3",
@@ -3099,6 +3107,7 @@
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz",
"integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==",
+ "license": "ISC",
"dependencies": {
"internmap": "1 - 2"
},
@@ -3110,6 +3119,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz",
"integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==",
+ "license": "ISC",
"engines": {
"node": ">=12"
}
@@ -3118,6 +3128,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz",
"integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==",
+ "license": "ISC",
"dependencies": {
"d3-dispatch": "1 - 3",
"d3-drag": "2 - 3",
@@ -3133,6 +3144,7 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz",
"integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==",
+ "license": "ISC",
"dependencies": {
"d3-path": "1 - 3"
},
@@ -3144,6 +3156,7 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
"integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
+ "license": "ISC",
"engines": {
"node": ">=12"
}
@@ -3152,6 +3165,7 @@
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz",
"integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==",
+ "license": "ISC",
"dependencies": {
"d3-array": "^3.2.0"
},
@@ -3163,6 +3177,7 @@
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz",
"integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==",
+ "license": "ISC",
"dependencies": {
"delaunator": "5"
},
@@ -3174,6 +3189,7 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz",
"integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==",
+ "license": "ISC",
"engines": {
"node": ">=12"
}
@@ -3182,6 +3198,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz",
"integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==",
+ "license": "ISC",
"dependencies": {
"d3-dispatch": "1 - 3",
"d3-selection": "3"
@@ -3194,6 +3211,7 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz",
"integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==",
+ "license": "ISC",
"dependencies": {
"commander": "7",
"iconv-lite": "0.6",
@@ -3218,6 +3236,7 @@
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
"integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
+ "license": "MIT",
"engines": {
"node": ">= 10"
}
@@ -3226,6 +3245,7 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
"integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
+ "license": "BSD-3-Clause",
"engines": {
"node": ">=12"
}
@@ -3234,6 +3254,7 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz",
"integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==",
+ "license": "ISC",
"dependencies": {
"d3-dsv": "1 - 3"
},
@@ -3245,6 +3266,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz",
"integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==",
+ "license": "ISC",
"dependencies": {
"d3-dispatch": "1 - 3",
"d3-quadtree": "1 - 3",
@@ -3258,6 +3280,7 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
"integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==",
+ "license": "ISC",
"engines": {
"node": ">=12"
}
@@ -3266,6 +3289,7 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz",
"integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==",
+ "license": "ISC",
"dependencies": {
"d3-array": "2.5.0 - 3"
},
@@ -3277,6 +3301,7 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz",
"integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==",
+ "license": "ISC",
"engines": {
"node": ">=12"
}
@@ -3285,6 +3310,7 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
"integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
+ "license": "ISC",
"dependencies": {
"d3-color": "1 - 3"
},
@@ -3296,6 +3322,7 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz",
"integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==",
+ "license": "ISC",
"engines": {
"node": ">=12"
}
@@ -3304,6 +3331,7 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz",
"integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==",
+ "license": "ISC",
"engines": {
"node": ">=12"
}
@@ -3312,6 +3340,7 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz",
"integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==",
+ "license": "ISC",
"engines": {
"node": ">=12"
}
@@ -3320,6 +3349,7 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz",
"integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==",
+ "license": "ISC",
"engines": {
"node": ">=12"
}
@@ -3363,6 +3393,7 @@
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
"integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
+ "license": "ISC",
"dependencies": {
"d3-array": "2.10.0 - 3",
"d3-format": "1 - 3",
@@ -3378,6 +3409,7 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz",
"integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==",
+ "license": "ISC",
"dependencies": {
"d3-color": "1 - 3",
"d3-interpolate": "1 - 3"
@@ -3390,6 +3422,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
+ "license": "ISC",
"engines": {
"node": ">=12"
}
@@ -3398,6 +3431,7 @@
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz",
"integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==",
+ "license": "ISC",
"dependencies": {
"d3-path": "^3.1.0"
},
@@ -3409,6 +3443,7 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz",
"integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==",
+ "license": "ISC",
"dependencies": {
"d3-array": "2 - 3"
},
@@ -3420,6 +3455,7 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
"integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
+ "license": "ISC",
"dependencies": {
"d3-time": "1 - 3"
},
@@ -3431,6 +3467,7 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
"integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
+ "license": "ISC",
"engines": {
"node": ">=12"
}
@@ -3439,6 +3476,7 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz",
"integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==",
+ "license": "ISC",
"dependencies": {
"d3-color": "1 - 3",
"d3-dispatch": "1 - 3",
@@ -3457,6 +3495,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz",
"integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==",
+ "license": "ISC",
"dependencies": {
"d3-dispatch": "1 - 3",
"d3-drag": "2 - 3",
@@ -3469,11 +3508,12 @@
}
},
"node_modules/dagre-d3-es": {
- "version": "7.0.10",
- "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.10.tgz",
- "integrity": "sha512-qTCQmEhcynucuaZgY5/+ti3X/rnszKZhEQH/ZdWdtP1tA/y3VoHJzcVrO9pjjJCNpigfscAtoUB5ONcd2wNn0A==",
+ "version": "7.0.13",
+ "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.13.tgz",
+ "integrity": "sha512-efEhnxpSuwpYOKRm/L5KbqoZmNNukHa/Flty4Wp62JRvgH2ojwVgPgdYyr4twpieZnyRDdIH7PY2mopX26+j2Q==",
+ "license": "MIT",
"dependencies": {
- "d3": "^7.8.2",
+ "d3": "^7.9.0",
"lodash-es": "^4.17.21"
}
},
@@ -3536,6 +3576,7 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz",
"integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==",
+ "license": "ISC",
"dependencies": {
"robust-predicates": "^3.0.2"
}
@@ -3581,9 +3622,10 @@
"dev": true
},
"node_modules/diff": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz",
- "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==",
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.2.tgz",
+ "integrity": "sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A==",
+ "license": "BSD-3-Clause",
"engines": {
"node": ">=0.3.1"
}
@@ -3595,9 +3637,13 @@
"dev": true
},
"node_modules/dompurify": {
- "version": "3.1.5",
- "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.5.tgz",
- "integrity": "sha512-lwG+n5h8QNpxtyrJW/gJWckL+1/DQiYMX8f7t8Z2AZTPw1esVrqjI63i7Zc2Gz0aKzLVMYC1V1PL/ky+aY/NgA=="
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.0.tgz",
+ "integrity": "sha512-r+f6MYR1gGN1eJv0TVQbhA7if/U7P87cdPl3HN5rikqaBSBxLiCb/b9O+2eG0cxz0ghyU+mU1QkbsOwERMYlWQ==",
+ "license": "(MPL-2.0 OR Apache-2.0)",
+ "optionalDependencies": {
+ "@types/trusted-types": "^2.0.7"
+ }
},
"node_modules/eastasianwidth": {
"version": "0.2.0",
@@ -4038,23 +4084,22 @@
"integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="
},
"node_modules/glob": {
- "version": "10.4.1",
- "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz",
- "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==",
+ "version": "10.5.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
+ "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"foreground-child": "^3.1.0",
"jackspeak": "^3.1.2",
"minimatch": "^9.0.4",
"minipass": "^7.1.2",
+ "package-json-from-dist": "^1.0.0",
"path-scurry": "^1.11.1"
},
"bin": {
"glob": "dist/esm/bin.mjs"
},
- "engines": {
- "node": ">=16 || 14 >=14.18"
- },
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
@@ -4531,6 +4576,7 @@
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
},
@@ -4576,6 +4622,7 @@
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
"integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
+ "license": "ISC",
"engines": {
"node": ">=12"
}
@@ -4839,9 +4886,10 @@
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
},
"node_modules/js-yaml": {
- "version": "3.14.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
- "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+ "version": "3.14.2",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
+ "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
+ "license": "MIT",
"dependencies": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
@@ -4921,9 +4969,10 @@
"dev": true
},
"node_modules/lodash-es": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
- "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
+ "version": "4.17.23",
+ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz",
+ "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==",
+ "license": "MIT"
},
"node_modules/lodash.get": {
"version": "4.4.2",
@@ -5317,9 +5366,10 @@
}
},
"node_modules/mdast-util-to-hast": {
- "version": "13.2.0",
- "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz",
- "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==",
+ "version": "13.2.1",
+ "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz",
+ "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==",
+ "license": "MIT",
"dependencies": {
"@types/hast": "^3.0.0",
"@types/mdast": "^4.0.0",
@@ -5546,9 +5596,9 @@
}
},
"node_modules/mermaid": {
- "version": "10.9.4",
- "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-10.9.4.tgz",
- "integrity": "sha512-VIG2B0R9ydvkS+wShA8sXqkzfpYglM2Qwj7VyUeqzNVqSGPoP/tcaUr3ub4ESykv8eqQJn3p99bHNvYdg3gCHQ==",
+ "version": "10.9.5",
+ "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-10.9.5.tgz",
+ "integrity": "sha512-eRlKEjzak4z1rcXeCd1OAlyawhrptClQDo8OuI8n6bSVqJ9oMfd5Lrf3Q+TdJHewi/9AIOc3UmEo8Fz+kNzzuQ==",
"license": "MIT",
"dependencies": {
"@braintree/sanitize-url": "^6.0.1",
@@ -5558,9 +5608,9 @@
"cytoscape-cose-bilkent": "^4.1.0",
"d3": "^7.4.0",
"d3-sankey": "^0.12.3",
- "dagre-d3-es": "7.0.10",
+ "dagre-d3-es": "7.0.13",
"dayjs": "^1.11.7",
- "dompurify": "^3.0.5 <3.1.7",
+ "dompurify": "^3.2.4",
"elkjs": "^0.9.0",
"katex": "^0.16.9",
"khroma": "^2.0.0",
@@ -6441,12 +6491,12 @@
"integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg=="
},
"node_modules/next": {
- "version": "14.2.32",
- "resolved": "https://registry.npmjs.org/next/-/next-14.2.32.tgz",
- "integrity": "sha512-fg5g0GZ7/nFc09X8wLe6pNSU8cLWbLRG3TZzPJ1BJvi2s9m7eF991se67wliM9kR5yLHRkyGKU49MMx58s3LJg==",
+ "version": "14.2.35",
+ "resolved": "https://registry.npmjs.org/next/-/next-14.2.35.tgz",
+ "integrity": "sha512-KhYd2Hjt/O1/1aZVX3dCwGXM1QmOV4eNM2UTacK5gipDdPN/oHHK/4oVGy7X8GMfPMsUTUEmGlsy0EY1YGAkig==",
"license": "MIT",
"dependencies": {
- "@next/env": "14.2.32",
+ "@next/env": "14.2.35",
"@swc/helpers": "0.5.5",
"busboy": "1.6.0",
"caniuse-lite": "^1.0.30001579",
@@ -6461,15 +6511,15 @@
"node": ">=18.17.0"
},
"optionalDependencies": {
- "@next/swc-darwin-arm64": "14.2.32",
- "@next/swc-darwin-x64": "14.2.32",
- "@next/swc-linux-arm64-gnu": "14.2.32",
- "@next/swc-linux-arm64-musl": "14.2.32",
- "@next/swc-linux-x64-gnu": "14.2.32",
- "@next/swc-linux-x64-musl": "14.2.32",
- "@next/swc-win32-arm64-msvc": "14.2.32",
- "@next/swc-win32-ia32-msvc": "14.2.32",
- "@next/swc-win32-x64-msvc": "14.2.32"
+ "@next/swc-darwin-arm64": "14.2.33",
+ "@next/swc-darwin-x64": "14.2.33",
+ "@next/swc-linux-arm64-gnu": "14.2.33",
+ "@next/swc-linux-arm64-musl": "14.2.33",
+ "@next/swc-linux-x64-gnu": "14.2.33",
+ "@next/swc-linux-x64-musl": "14.2.33",
+ "@next/swc-win32-arm64-msvc": "14.2.33",
+ "@next/swc-win32-ia32-msvc": "14.2.33",
+ "@next/swc-win32-x64-msvc": "14.2.33"
},
"peerDependencies": {
"@opentelemetry/api": "^1.1.0",
@@ -6824,6 +6874,13 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/package-json-from-dist": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
+ "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
+ "dev": true,
+ "license": "BlueOak-1.0.0"
+ },
"node_modules/parse-entities": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.1.tgz",
@@ -7605,7 +7662,8 @@
"node_modules/robust-predicates": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz",
- "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg=="
+ "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==",
+ "license": "Unlicense"
},
"node_modules/run-parallel": {
"version": "1.2.0",
@@ -7632,7 +7690,8 @@
"node_modules/rw": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz",
- "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ=="
+ "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==",
+ "license": "BSD-3-Clause"
},
"node_modules/sade": {
"version": "1.8.1",
@@ -7667,7 +7726,8 @@
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "license": "MIT"
},
"node_modules/scheduler": {
"version": "0.23.2",
@@ -8772,9 +8832,10 @@
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
},
"node_modules/vfile-matter/node_modules/js-yaml": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
- "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
+ "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
+ "license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
},
diff --git a/website/package.json b/website/package.json
index c39b447c9..344a4fa2a 100644
--- a/website/package.json
+++ b/website/package.json
@@ -13,7 +13,7 @@
"@headlessui/react": "^2.2.0",
"@heroicons/react": "^2.0.18",
"@octokit/graphql": "^7.0.1",
- "next": "^14.2.32",
+ "next": "^14.2.35",
"next-plausible": "^3.11.1",
"next-seo": "^6.1.0",
"next-sitemap": "^4.2.3",
diff --git a/website/public/news/03-social-card.png b/website/public/news/03-social-card.png
new file mode 100644
index 000000000..9783628db
Binary files /dev/null and b/website/public/news/03-social-card.png differ
diff --git a/website/src/middleware.js b/website/src/middleware.js
new file mode 100644
index 000000000..70c30a763
--- /dev/null
+++ b/website/src/middleware.js
@@ -0,0 +1,17 @@
+import { NextResponse } from 'next/server';
+
+export function middleware(request) {
+ const accept = request.headers.get('accept') || '';
+
+ // Content negotiation: serve Markdown for AI crawlers requesting it
+ if (accept.includes('text/markdown') && request.nextUrl.pathname.startsWith('/docs/')) {
+ const mdPath = request.nextUrl.pathname.replace('/docs/', '/api/md/');
+ return NextResponse.rewrite(new URL(mdPath, request.url));
+ }
+
+ return NextResponse.next();
+}
+
+export const config = {
+ matcher: '/docs/:path*',
+};
diff --git a/website/src/pages/api/md/[...slug].js b/website/src/pages/api/md/[...slug].js
new file mode 100644
index 000000000..d291a678a
--- /dev/null
+++ b/website/src/pages/api/md/[...slug].js
@@ -0,0 +1,34 @@
+import fs from 'fs';
+import path from 'path';
+
+export default function handler(req, res) {
+ const { slug } = req.query;
+ const slugPath = Array.isArray(slug) ? slug.join('/') : slug;
+
+ // Try to find the MDX file
+ const docsDir = path.join(process.cwd(), 'src/pages/docs');
+ let filePath = path.join(docsDir, `${slugPath}.mdx`);
+
+ // If not found, try index.mdx in directory
+ if (!fs.existsSync(filePath)) {
+ filePath = path.join(docsDir, slugPath, 'index.mdx');
+ }
+
+ if (!fs.existsSync(filePath)) {
+ return res.status(404).json({ error: 'Page not found' });
+ }
+
+ let content = fs.readFileSync(filePath, 'utf8');
+
+ // Strip import statements at the top of the file
+ content = content.replace(/^import\s+.*?(?:from\s+['"].*?['"])?;?\s*$/gm, '');
+
+ // Strip tags
+ content = content.replace(/ /g, '');
+
+ // Clean up excessive blank lines at the start
+ content = content.replace(/^\s*\n+/, '');
+
+ res.setHeader('Content-Type', 'text/markdown; charset=utf-8');
+ res.status(200).send(content);
+}
diff --git a/website/src/pages/cloud/features.jsx b/website/src/pages/cloud/features.jsx
index ba14db298..0be4d7599 100644
--- a/website/src/pages/cloud/features.jsx
+++ b/website/src/pages/cloud/features.jsx
@@ -37,7 +37,7 @@ const sections = [
{ name: 'Deploy multiple environments (prod, staging…)', tiers: { bref: true, cloud: true } },
{ name: 'Simple deployments from GitHub Actions', tiers: { bref: false, cloud: true }, description: 'Documentation ' },
{ name: 'Simplified creation and management of databases', tiers: { bref: false, cloud: true } },
- { name: 'Simplified creation of private networks', tiers: { bref: false, cloud: 'Coming soon' } },
+ { name: 'Simplified creation of private networks', tiers: { bref: false, cloud: true } },
{ name: 'AWS deployment security', tiers: {
bref: {
title: 'Your responsibility',
@@ -84,6 +84,17 @@ const sections = [
cloud: true,
}
},
+ { name: 'X-Ray tracing', tiers: {
+ bref: {
+ title: false,
+ description: 'AWS CloudWatch (advanced) + extra Bref X-Ray license',
+ },
+ cloud: {
+ title: true,
+ description: 'Trace explorer optimized for PHP apps. No extra license needed.',
+ },
+ }
+ },
{ name: 'Queue jobs management', tiers: { bref: false, cloud: true } },
{ name: 'Secrets management', tiers: {
bref: {
diff --git a/website/src/pages/news.mdx b/website/src/pages/news.mdx
index 471b4ecb0..a0ca257c5 100644
--- a/website/src/pages/news.mdx
+++ b/website/src/pages/news.mdx
@@ -9,6 +9,14 @@ import { NextSeo } from 'next-seo';
+## [Bref 3.0 is released 🎉](./news/03-bref-3.0.mdx)
+
+Bref 3.0 is here! Since Bref 2.0, we've grown from 10 billion to **40 billion Lambda executions** every month. The package has been installed more than **8 million times**, and we've crossed **4,000 commits** across all Bref repositories.
+
+Today, we celebrate these achievements and **the release of Bref 3.0** 🎉
+
+[▶ Read more](./news/03-bref-3.0.mdx)
+
## [Bref 2.0 is released 🎉](./news/02-bref-2.0.md)
The work on what would be Bref 2.0 started in October 2021, about 1.5 year ago. We went through many different strategies, experiments, rewrites, over **700 commits** to finally land with the stable release.
diff --git a/website/src/pages/news/02-bref-2.0.mdx b/website/src/pages/news/02-bref-2.0.mdx
index 1f2d919f1..f624319ff 100644
--- a/website/src/pages/news/02-bref-2.0.mdx
+++ b/website/src/pages/news/02-bref-2.0.mdx
@@ -70,7 +70,7 @@ functions:
handler: public/index.php
# ...
layers:
- - ${bref:layer.php-81-fpm}
+ - ${bref:layer.php-84-fpm}
```
After (Bref v2 syntax):
@@ -82,10 +82,10 @@ functions:
api:
handler: public/index.php
# ...
- runtime: php-81-fpm
+ runtime: php-84-fpm
```
-As you can see, we no longer have to set `runtime: provided.al2` and add the Bref layers. We can now directly set a PHP runtime (`php-81`, `php-81-fpm`, `php-81-console`) and Bref will transform this into the proper runtime + layers configuration.
+As you can see, we no longer have to set `runtime: provided.al2` and add the Bref layers. We can now directly set a PHP runtime (`php-84`, `php-84-fpm`, `php-84-console`) and Bref will transform this into the proper runtime + layers configuration.
This works for all the Bref runtimes ([FPM](https://bref.sh/docs/runtimes/http.html), [function](https://bref.sh/docs/runtimes/function.html) and [console](https://bref.sh/docs/runtimes/console.html)) and all supported PHP versions (`80`, `81`, and `82` at the moment). Here's a recap:
@@ -93,24 +93,24 @@ This works for all the Bref runtimes ([FPM](https://bref.sh/docs/runtimes/http.h
# PHP-FPM runtime (web apps)
runtime: provided.al2
layers:
- - ${bref:layer.php-81-fpm}
+ - ${bref:layer.php-84-fpm}
# becomes:
-runtime: php-81-fpm
+runtime: php-84-fpm
# Function runtime
runtime: provided.al2
layers:
- - ${bref:layer.php-81}
+ - ${bref:layer.php-84}
# becomes:
-runtime: php-81
+runtime: php-84
# Console runtime
runtime: provided.al2
layers:
- - ${bref:layer.php-81}
+ - ${bref:layer.php-84}
- ${bref:layer.console}
# becomes:
-runtime: php-81-console
+runtime: php-84-console
```
The Bref documentation has been updated to reflect these changes.
@@ -174,7 +174,7 @@ functions:
# ...
layers:
# Add the `-arm` prefix in layers 👇
- - ${bref:layer.arm-php-81-fpm}
+ - ${bref:layer.arm-php-84-fpm}
```
## Faster deployments
diff --git a/website/src/pages/news/03-bref-3.0.mdx b/website/src/pages/news/03-bref-3.0.mdx
new file mode 100644
index 000000000..431f3cf9a
--- /dev/null
+++ b/website/src/pages/news/03-bref-3.0.mdx
@@ -0,0 +1,317 @@
+import ArticleHeader from '../../components/news/ArticleHeader';
+import { NextSeo } from 'next-seo';
+import Image from 'next/image';
+import cloudOverview from '../docs/monitoring/cloud-overview.png';
+import cloudXrayTrace from '../docs/monitoring/cloud-xray-trace.png';
+import cloudNetworkCreate from './03/cloud-vpc.png';
+import cloudXrayFiltersGeneral from '../docs/monitoring/cloud-xray-filters-general.png';
+import cloudXrayFiltersAnnotations from '../docs/monitoring/cloud-xray-filters-annotations.png';
+
+
+
+# Bref 3.0 is released 🎉
+
+
+
+Bref 3.0 is here! Since Bref 2.0, we've grown from 10 billion to **40 billion Lambda executions** (aka requests) every month. The package has been installed more than **9 million times**, and we've reached **4,000 commits** across all Bref repositories.
+
+Today, we celebrate these achievements and **the release of Bref 3.0** 🎉
+
+Let's check out what's new in v3.
+
+## Bref 3.0
+
+Here's a summary, we'll dive into the details below:
+
+- **24% smaller layers** for faster cold starts.
+- **Runtimes rebuilt on Amazon Linux 2023**: upgraded from Amazon Linux 2.
+- **PHP 8.5 support**
+- **PostgreSQL extension** is now enabled by default.
+- **Redis extension** is now built-in.
+- **Unified PHP runtime**: one layer and one container image instead of three.
+- **New regions**: `ap-southeast-3` and `me-central-1`.
+- **Better CloudWatch logs** with the new Monolog formatter enabled by default.
+- **Lambda request ID and trace ID** exposed as environment variables for easier logging.
+- **[Bref Cloud](https://bref.sh/cloud)**: a simpler way to deploy Bref applications.
+
+What did we break? **Almost nothing**, the upgrade should be smooth. Here's an overview:
+
+- PHP 8.2+ is now required (PHP 8.0 and 8.1 support is dropped).
+- The `vendor/bin/bref` CLI is removed (it was already 90% removed in v2).
+- The SOAP extension is now opt-in (it had very little usage).
+- If you deploy using container images, you'll need to update your Dockerfile.
+- If you use [`bref/extra-php-extensions`](https://github.com/brefphp/extra-php-extensions), update it from v1 to v3 (there's no v2, versions are aligned with Bref now).
+
+For a complete list of changes and instructions, check out the [**v3 upgrade guide**](../docs/upgrading/v3.mdx).
+
+## Faster Lambda cold starts
+
+The Bref layers for AWS Lambda have been optimized and their size reduced. This leaves more room for your code and should improve cold start times.
+
+- PHP 8.4: 69MB → 53MB
+- PHP 8.3: 65MB → 46MB
+
+This was achieved through plenty of tests leading to these optimizations:
+
+- Stripping debug symbols from all libraries and PHP extensions.
+- Compiling PHP with size-optimization flags.
+- Disabling the rarely-used SOAP extension by default.
+- Bundling some PHP extensions directly into the PHP binary.
+
+## Amazon Linux 2023
+
+Bref 3.0 is built on **[Amazon Linux 2023](https://docs.aws.amazon.com/linux/al2023/ug/what-is-amazon-linux.html)** (AL2023), the latest version of Amazon's Linux distribution for AWS.
+
+The previous Bref versions were built on **Amazon Linux 2** (AL2), which is reaching end of life soon. AWS Lambda will continue to support AL2 for some time, but it's recommended to migrate to AL2023 as soon as possible.
+
+This upgrade brings several benefits:
+
+- **Performance**: AL2023 is leaner than AL2, with more recent kernel and system libraries.
+- **Modern packages**: AL2023 ships with more recent package versions, simplifying the Bref build process.
+- **Long-term support**: AL2 will be deprecated in June 2026, while AL2023 will be supported at least until 2029.
+
+The migration happens automatically when you upgrade to Bref 3.0, no changes are needed on your end.
+
+## PHP 8.5 support
+
+Bref 3.0 adds support for **PHP 8.5** (which depended on an AL2023 system upgrade). You can start using it by setting the runtime in your `serverless.yml`:
+
+```yaml
+functions:
+ api:
+ handler: public/index.php
+ runtime: php-85-fpm
+```
+
+## Redis extension built-in
+
+The **Redis extension** is now included in Bref layers by default. Redis is one of the most used extensions by Bref users for caching and session storage.
+
+If you were using the Redis extension from [`bref/extra-php-extensions`](https://github.com/brefphp/extra-php-extensions), remove the layer from your `serverless.yml`:
+
+```diff filename="serverless.yml"
+functions:
+ api:
+ # ...
+ layers:
+- - ${bref-extra:redis-php-84}
+```
+
+And enable the extension via a `php.ini` file in your project (`php/conf.d/php.ini`):
+
+```diff filename="php/conf.d/php.ini"
+extension=redis
+```
+
+If Redis was the only `bref/extra-php-extensions` extension you were using, you can uninstall the package:
+
+```bash
+composer remove bref/extra-php-extensions
+```
+
+## PostgreSQL enabled by default
+
+The **PostgreSQL PDO extension** is now enabled by default. If you're using PostgreSQL, you no longer need any additional configuration.
+
+If you had enabled it manually via a `php.ini` file, you can remove that line:
+
+```diff filename="php/conf.d/php.ini"
+-extension=pdo_pgsql
+```
+
+## Unified PHP runtime
+
+Bref 3.0 consolidates the three separate layer types (function, FPM, console) into a **single unified layer** per PHP version. This simplification makes maintenance easier and provides a simpler mental model for users.
+
+**Do you need to change anything?**
+
+- **If you use `runtime: php-xxx` in `serverless.yml`** (for example `runtime: php-84-fpm`): no changes are needed!
+- **If you deploy using container images**: you need to update your `Dockerfile`, ⚠️ read the [upgrade guide](../docs/upgrading/v3.mdx#updating-your-dockerfile-for-bref-30).
+- **If you specify layers explicitly**: ⚠️ read the [upgrade guide](../docs/upgrading/v3.mdx#aws-lambda-layers-have-been-merged-into-a-single-layer).
+
+A single layer/image is how it should have been from the start, and I'm really glad we're getting there now!
+
+## Better CloudWatch logs
+
+The [Bref Monolog formatter](https://github.com/brefphp/monolog-bridge) is now **enabled by default** in the Laravel and Symfony bridges. This formatter outputs logs in a format optimized for CloudWatch, making them easier to read and filter.
+
+Before (plain text):
+```
+[2025-12-05 10:30:45] production.ERROR: Database connection failed
+```
+
+After (structured format):
+```json
+ERROR Database connection failed {"message":"Database connection failed","level":"ERROR","context":{...}}
+```
+
+This format makes logs easier to read in CloudWatch and enables powerful filtering with CloudWatch Logs Insights (e.g., filter by log level or exception class).
+
+**Exception handling is also greatly improved:** Previously, exception stack traces were split across multiple CloudWatch log records (one per line), making them difficult to read and browse. Now, the entire exception (including stack trace) is grouped in a single JSON object, making debugging much easier.
+
+That new logging approach also lets you read all the logs of a single request, by filtering via the AWS request ID.
+
+## Lambda request ID and trace ID
+
+Bref now exposes the **Lambda request ID** and **X-Ray trace ID** as environment variables on every invocation:
+
+- `LAMBDA_REQUEST_ID`: the current AWS Lambda request ID.
+- `_X_AMZN_TRACE_ID`: the [AWS X-Ray](/xray) trace ID.
+
+These are useful for logging and tracing purposes, for example to group all logs of the same invocation in CloudWatch.
+
+## New regions
+
+Bref layers are now available in two additional regions:
+
+- `ap-southeast-3` (Asia Pacific - Jakarta)
+- `me-central-1` (Middle East - UAE)
+
+## The `vendor/bin/bref` CLI is removed
+
+The `vendor/bin/bref` CLI has been completely removed in Bref 3.0. This is a minor change since the CLI was already 90% removed in Bref 2.0 - only the `bref init` command remained for bootstrapping new projects.
+
+We now have better onboarding with improved documentation and the `serverless` CLI commands. Here are the alternatives:
+
+- **Scaffolding new projects**: Follow the [getting started guide](https://bref.sh/docs/setup) to create your `serverless.yml` manually.
+- **Layer versions**: Visit [runtimes.bref.sh](https://runtimes.bref.sh/) or run `serverless bref:layers`.
+- **Running console commands**: Use `serverless bref:cli` (this existed in v2).
+- **Local development**: Use [Docker-based local development](https://bref.sh/docs/local-development).
+
+
+## Upgrading
+
+Check out the [**v3 Upgrade Guide**](../docs/upgrading/v3.mdx) for a complete list of changes and instructions to upgrade your projects.
+
+
+## Bref Cloud
+
+Launched in 2025, **[Bref Cloud](https://bref.sh/cloud)** is the simplest way to deploy and monitor PHP applications on AWS Lambda. It replaces the AWS console with an intuitive dashboard to manage everything.
+
+Here's an overview of the Bref Cloud features that launched recently:
+
+**Application diagrams with live metrics**
+
+Bref Cloud now shows a **diagram of your application's architecture**: CloudFront CDN, API Gateway, Lambda functions, SQS queues, S3 buckets. All that with live metrics: number of requests, response times, queue depth, storage usage, and errors across every component.
+
+
+
+**Private networks and databases**
+
+You can now create private networks (VPC) from Bref Cloud. No AWS networking expertise required: Bref Cloud handles the VPC configuration, subnets, security groups, and connectivity (like NAT Gateway) so your databases are only accessible from your Lambda functions.
+
+
+
+### X-Ray performance tracing
+
+With the release of Bref v3, I am super happy to release **tracing support in Bref Cloud via X-Ray**.
+
+Bref already provided an [X-Ray integration](/xray) via an extra package. This integration is now available for free to all Bref Cloud users: [set it up](/docs/monitoring#bref-cloud) and start tracing your PHP code.
+
+Once set up, Bref Cloud lets you explore X-Ray traces with a simple UI. Unlike AWS's native X-Ray console, which is generic and complex, Bref Cloud's UI is designed specifically for PHP: you can filter traces by controller, route, CLI command, or job class, and quickly drill down into individual requests to find bottlenecks.
+
+
+
+
+
+
+Traces are enriched by Bref with annotations to understand where time is spent in your application: cold starts, database queries, HTTP calls, AWS SDK calls, and more:
+
+
+
+Combined with the [improved CloudWatch logs](#better-cloudwatch-logs) and the [Lambda request ID](#lambda-request-id-and-trace-id) exposed in Bref v3, Bref Cloud gives you **complete observability** for your serverless PHP applications out of the box.
+
+
+ Learn more about Bref Cloud →
+
+
+
+## Community Serverless Framework
+
+While not directly related to Bref v3, this is worth mentioning: the original [Serverless Framework](https://www.serverless.com/) is no longer fully open-source with its v4 and requires a paid license. Since most of the Bref community relies on the `serverless` CLI to deploy their applications, this was a problem for many.
+
+That's why we now maintain [**a community fork of Serverless Framework v3**](https://github.com/oss-serverless/serverless), which is fully open-source (MIT) and free to use without any limitations. The fork is stable, mature, and actively maintained by Bref maintainers and the community. It includes security fixes, dependency updates, and up-to-date support for new AWS Lambda runtimes.
+
+On top of that, the CLI has been made lighter and faster by removing obsolete features like the Serverless Dashboard integration and Tencent Cloud support.
+
+Migration is straightforward since it's a drop-in replacement:
+
+```bash
+npm remove serverless
+npm install -g osls
+```
+
+No changes to your `serverless.yml` or project configuration are needed. The CLI command remains `serverless` (or `osls` if you want to have both the old and new CLI).
+
+**We recommend all Bref users to migrate to this fork.**
+
+
+## New observability packages
+
+Also not part of Bref v3, but worth mentioning: two new packages were released in 2025 to help monitor PHP applications on AWS Lambda:
+
+- [**Bref X-Ray**](https://bref.sh/xray): integrates AWS X-Ray with Bref for performance monitoring and distributed tracing. It tracks cold starts, database queries, HTTP calls, AWS SDK calls, and more. It supports both Laravel and Symfony.
+- [**Bref Sentry**](https://bref.sh/sentry): extends Sentry's capabilities for AWS Lambda, capturing errors outside of PHP-FPM (such as timeouts or oversized responses), adding exception tracking to event-driven handlers (SQS, EventBridge, S3…), and tracking cold starts and AWS SDK calls.
+
+These are commercial packages (not part of the open-source project) that help fill the observability gap for serverless PHP.
+
+
+
+
+## Thanks
+
+A huge thanks to the [Bref contributors](https://github.com/brefphp/bref/graphs/contributors), to the community for supporting the project, and to the open-source sponsors:
+
+**Premium sponsors:**
+
+- [Craft CMS](https://craftcms.com/?ref=bref.sh)
+- [Voxie](https://voxie.com/?ref=bref)
+- [MyBuilder](https://www.mybuilder.com/?ref=bref.sh)
+
+**Gold sponsors:**
+
+- [Depot](https://depot.dev/?ref=bref.sh)
+- [SecuMailer](https://secumailer.com/?ref=bref.sh)
+- [Ecomail](https://ecomail.cz/?ref=bref.sh)
+- [Spreaker](https://www.spreaker.com/?ref=bref)
+- [Runs On](https://runs-on.com/?ref=bref)
+- [Playable](https://playable.com/?ref=bref)
+
+And [many other personal sponsors](https://github.com/sponsors/mnapoli#sponsors)!
+
+Thank you all!
+
+
+## That's it!
+
+I hope you enjoy Bref v3!
+
+If you want to support the project, consider [sponsoring on GitHub](https://github.com/sponsors/mnapoli), subscribing to [Bref Pro support](/support), or trying out [Bref Cloud](/cloud). Bref has been thriving for 8 years thanks to the support of the community, and I hope it will continue to thrive for many more years to come ❤️
+
+There is a complete [**v3 Upgrade Guide**](../docs/upgrading/v3.mdx) that you can follow.
+
+Head to the docs to [**get started with Bref**](../), or check out the documentation for [Laravel](../docs/laravel/getting-started.mdx) or [Symfony](../docs/symfony/getting-started.mdx).
+
+You can also join the community [in Slack](/docs/community.md), post details about your project in [Built with Bref](https://github.com/brefphp/bref/issues/267), or share your experience online and mention [@brefphp](https://twitter.com/brefphp) on Twitter.
+
+
diff --git a/website/src/pages/news/03/cloud-vpc.png b/website/src/pages/news/03/cloud-vpc.png
new file mode 100644
index 000000000..2b47e5d7a
Binary files /dev/null and b/website/src/pages/news/03/cloud-vpc.png differ
diff --git a/website/src/pages/xray/docs.mdx b/website/src/pages/xray/docs.mdx
index ecf122a2f..a76006a4f 100644
--- a/website/src/pages/xray/docs.mdx
+++ b/website/src/pages/xray/docs.mdx
@@ -12,6 +12,10 @@ This package provides an advanced integration between Bref applications and [AWS
Check out the documentation below for screenshots and more details. View the [changelog](/xray/changelog) for the latest updates and releases.
+
+ **Bref Cloud users** get a free X-Ray license included in their plan. You can view traces directly in the [Bref Cloud dashboard](/docs/monitoring#bref-cloud). To activate your free license, contact support via [bref.cloud/support](https://bref.cloud/support) or [Slack](https://bref.sh/slack).
+
+
## Installation
### 1. Enable Packagist.com
diff --git a/website/theme.config.jsx b/website/theme.config.jsx
index ca65d9c25..0b11a0ea7 100644
--- a/website/theme.config.jsx
+++ b/website/theme.config.jsx
@@ -8,7 +8,15 @@ export default {
logo: ,
docsRepositoryBase: 'https://github.com/brefphp/bref/blob/main',
project: {
- link: 'https://github.com/brefphp/bref'
+ link: 'https://github.com/brefphp/bref',
+ },
+ banner: {
+ key: 'v3',
+ text: (
+
+ 🎉 Bref 3.0 is released. Read more →
+
+ ),
},
useNextSeoProps() {
const { asPath } = useRouter();
@@ -19,10 +27,10 @@ export default {
openGraph: {
images: [
{
- url: 'https://bref.sh/social-card.png'
- }
- ]
- }
+ url: 'https://bref.sh/social-card.png',
+ },
+ ],
+ },
};
} else {
return {
@@ -30,23 +38,30 @@ export default {
openGraph: {
images: [
{
- url: 'https://bref.sh/social-card.png'
- }
- ]
- }
+ url: 'https://bref.sh/social-card.png',
+ },
+ ],
+ },
};
}
},
chat: {
link: 'https://bref.sh/slack',
icon: (
- Slack
+
+ Slack
+ d="M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52zM6.313 15.165a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313zM8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834zM8.834 6.313a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312zM18.956 8.834a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V8.834zM17.688 8.834a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312zM15.165 18.956a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52zM15.165 17.688a2.527 2.527 0 0 1-2.52-2.523 2.526 2.526 0 0 1 2.52-2.52h6.313A2.527 2.527 0 0 1 24 15.165a2.528 2.528 0 0 1-2.522 2.523h-6.313z"
+ />
- )
+ ),
},
darkMode: false,
nextThemes: {
@@ -57,44 +72,69 @@ export default {
sidebar: {
defaultMenuCollapseLevel: 1,
},
- head: (
- <>
-
-
-
-
-
-
-
-
-
-
- >
- ),
+ head: function Head() {
+ const { asPath } = useRouter();
+ const isDocsPage = asPath.startsWith('/docs/');
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+ {isDocsPage && (
+
+ )}
+ >
+ );
+ },
footer: {
component: Footer,
text: (
- MIT {new Date().getFullYear()} ©{' '}
-
- Matthieu Napoli
-
- .
+ MIT {new Date().getFullYear()} © Matthieu Napoli .
- )
+ ),
},
search: {
- component: ,
+ component: (
+
+ ),
},
components: {
// https://github.com/shuding/nextra/blob/main/packages/nextra-theme-docs/src/mdx-components.tsx
- h1: props => (
+ h1: (props) => (
),
- }
-}
+ },
+};