Skip to content

feat: connect vercel edge middleware to astro#7523

Merged
ematipico merged 6 commits intofeat/vercel-edge-middlewarefrom
feat/vercel/update-code-and-test-plt-586
Jun 30, 2023
Merged

feat: connect vercel edge middleware to astro#7523
ematipico merged 6 commits intofeat/vercel-edge-middlewarefrom
feat/vercel/update-code-and-test-plt-586

Conversation

@ematipico
Copy link
Copy Markdown
Member

@ematipico ematipico commented Jun 29, 2023

Changes

This PR connects the Vercel Edge Middleware to the Astro middleware:

  • created a new API called trySerializeLocals to serialise the locals. This is important because these locals will travel via headers, and we need to keep them when they are transferred from the vercel middleware to the Astro middleware;
  • created a new API inside the @astrojs/vercel adapter, this API is called createLocals and allows users to initialize their locals with anything they want. The function accepts an object that contains request and context. You can check Vercel documentation; As per @bluwy suggestion, the new API is actually a new key file called vercel-edge-middleware, it receives an object with request and context and esbuild will bundle the file.
  • updated the adapter to pass locals to app.render. These locals are extracted from the headers of the request;

Testing

I plan to create a preview release, create a new project and deploy it on Vercel.

Also, I added a snapshot test for the generated middleware. The reason is that it's very difficult to see how's the code generated, especially for reviewers. Please let me know how do feel about it; I am happy to remove it.

Docs

N/A Later when I know the APIs are stable and settled among the team members.

@ematipico ematipico requested a review from a team as a code owner June 29, 2023 14:09
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Jun 29, 2023

🦋 Changeset detected

Latest commit: 06a5c8a

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions bot added pkg: integration Related to any renderer integration (scope) pkg: astro Related to the core `astro` package (scope) semver: minor Change triggers a `minor` release labels Jun 29, 2023
Copy link
Copy Markdown
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is blocked because it contains a minor changeset. A reviewer will merge this at the next release if approved.

* prototype is the root `Object.prototype`. This includes objects created
* using object literals, but not for instance for class instances.
*/
function isPlainObject(value: unknown): value is object {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have packages/internal-helpers now. I could see some of the things like this going there. Not blocking though, just an idea.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about it, and wasn't sure what to do. I will move the function there!

@bluwy
Copy link
Copy Markdown
Member

bluwy commented Jun 29, 2023

And I'm not sure why...

That's because after the SSR build step, dist/entry.mjs contains import 'esbuild'; causing Vercel's nft tool to think esbuild needs to be "bundled". But you can't really bundle esbuild.

So somewhere is accidentally importing esbuild in the compiled runtime code maybe. I'm not really sure and it's hard to debug these stuff.

@ematipico
Copy link
Copy Markdown
Member Author

!preview vercel-edge-middleware

@github-actions
Copy link
Copy Markdown
Contributor

 > root@0.0.0 release /home/runner/work/astro/astro > pnpm run build && changeset publish "--tag" "next--vercel-edge-middleware" > root@0.0.0 build /home/runner/work/astro/astro > turbo run build --filter=astro --filter=create-astro --filter="@astrojs/*" --filter="@benchmark/*" �[2m• Packages in scope: @astrojs/alpinejs, @astrojs/cloudflare, @astrojs/deno, @astrojs/image, @astrojs/internal-helpers, @astrojs/lit, @astrojs/markdoc, @astrojs/markdown-component, @astrojs/markdown-remark, @astrojs/mdx, @astrojs/netlify, @astrojs/node, @astrojs/partytown, @astrojs/preact, @astrojs/prefetch, @astrojs/prism, @astrojs/react, @astrojs/rss, @astrojs/sitemap, @astrojs/solid-js, @astrojs/svelte, @astrojs/tailwind, @astrojs/telemetry, @astrojs/turbolinks, @astrojs/underscore-redirects, @astrojs/vercel, @astrojs/vue, @astrojs/webapi, @benchmark/timer, astro, create-astro�[0m �[2m• Running�[0m �[2m�[1mbuild�[0m�[0m �[2min 31 packages�[0m �[2m• Remote caching enabled�[0m �[35m@astrojs/webapi:build: �[0mcache hit, suppressing logs �[2m22131898d4fb04cf�[0m �[33m@astrojs/prism:build: �[0mcache hit, suppressing logs �[2me3cea146b484afb4�[0m �[34mcreate-astro:build: �[0mcache hit, suppressing logs �[2m8923896110073887�[0m �[36m@astrojs/internal-helpers:build: �[0mcache hit, suppressing logs �[2md6861eb4a622af5f�[0m �[32m@astrojs/telemetry:build: �[0mcache hit, suppressing logs �[2md5b919ea2e9792d8�[0m �[35m@astrojs/markdown-remark:build: �[0mcache hit, suppressing logs �[2m7f2fac8775910a9f�[0m �[32mastro:build: �[0mcache miss, executing �[2m81996ce557498f65�[0m �[32mastro:build: �[0m �[32mastro:build: �[0m> astro@0.0.0-vercel-edge-middleware-20230629145510 build /home/runner/work/astro/astro/packages/astro �[32mastro:build: �[0m> pnpm run prebuild && astro-scripts build "src/**/*.{ts,js}" && tsc && pnpm run postbuild �[32mastro:build: �[0m �[32mastro:build: �[0m �[32mastro:build: �[0m> astro@0.0.0-vercel-edge-middleware-20230629145510 prebuild /home/runner/work/astro/astro/packages/astro �[32mastro:build: �[0m> astro-scripts prebuild --to-string "src/runtime/server/astro-island.ts" "src/runtime/client/{idle,load,media,only,visible}.ts" �[32mastro:build: �[0m �[32mastro:build: �[0m �[32mastro:build: �[0m> astro@0.0.0-vercel-edge-middleware-20230629145510 postbuild /home/runner/work/astro/astro/packages/astro �[32mastro:build: �[0m> astro-scripts copy "src/**/*.astro" && astro-scripts copy "src/**/*.wasm" �[32mastro:build: �[0m �[35m@astrojs/tailwind:build: �[0mcache miss, executing �[2madf797870d00537f�[0m �[34m@astrojs/image:build: �[0mcache miss, executing �[2mc167c81fa552fa1b�[0m �[36m@astrojs/svelte:build: �[0mcache miss, executing �[2mdeb3b881d2ff2e69�[0m �[33m@astrojs/deno:build: �[0mcache miss, executing �[2m0ebc6e38f261db2e�[0m �[36m@astrojs/vue:build: �[0mcache miss, executing �[2m678bec70a8bbfbf8�[0m �[32m@astrojs/partytown:build: �[0mcache miss, executing �[2m2208e7e73365af36�[0m �[33m@astrojs/alpinejs:build: �[0mcache miss, executing �[2mcff7003fb84d9e59�[0m �[35m@astrojs/node:build: �[0mcache miss, executing �[2m135c5694effa7e4c�[0m �[34m@astrojs/prefetch:build: �[0mcache miss, executing �[2m4b1ce885f1452208�[0m �[32m@astrojs/preact:build: �[0mcache miss, executing �[2mfc44283192251697�[0m �[35m@astrojs/tailwind:build: �[0m �[35m@astrojs/tailwind:build: �[0m> @astrojs/tailwind@4.0.0 build /home/runner/work/astro/astro/packages/integrations/tailwind �[35m@astrojs/tailwind:build: �[0m> astro-scripts build "src/**/*.ts" && tsc �[35m@astrojs/tailwind:build: �[0m �[34m@astrojs/image:build: �[0m �[34m@astrojs/image:build: �[0m> @astrojs/image@0.17.1 build /home/runner/work/astro/astro/packages/integrations/image �[34m@astrojs/image:build: �[0m> astro-scripts build "src/**/*.ts" && tsc �[34m@astrojs/image:build: �[0m �[36m@astrojs/svelte:build: �[0m �[36m@astrojs/svelte:build: �[0m> @astrojs/svelte@3.0.0 build /home/runner/work/astro/astro/packages/integrations/svelte �[36m@astrojs/svelte:build: �[0m> astro-scripts build "src/index.ts" && astro-scripts build "src/editor.cts" --force-cjs --no-clean-dist && tsc �[36m@astrojs/svelte:build: �[0m �[34m@astrojs/prefetch:build: �[0m �[34m@astrojs/prefetch:build: �[0m> @astrojs/prefetch@0.2.3 build /home/runner/work/astro/astro/packages/integrations/prefetch �[34m@astrojs/prefetch:build: �[0m> astro-scripts build "src/**/*.ts" && tsc �[34m@astrojs/prefetch:build: �[0m �[35m@astrojs/node:build: �[0m �[35m@astrojs/node:build: �[0m> @astrojs/node@5.3.0 build /home/runner/work/astro/astro/packages/integrations/node �[35m@astrojs/node:build: �[0m> astro-scripts build "src/**/*.ts" && tsc �[35m@astrojs/node:build: �[0m �[36m@astrojs/vue:build: �[0m �[36m@astrojs/vue:build: �[0m> @astrojs/vue@2.2.1 build /home/runner/work/astro/astro/packages/integrations/vue �[36m@astrojs/vue:build: �[0m> astro-scripts build "src/index.ts" && astro-scripts build "src/editor.cts" --force-cjs --no-clean-dist && tsc �[36m@astrojs/vue:build: �[0m �[32m@astrojs/partytown:build: �[0m �[32m@astrojs/partytown:build: �[0m> @astrojs/partytown@1.2.3 build /home/runner/work/astro/astro/packages/integrations/partytown �[32m@astrojs/partytown:build: �[0m> astro-scripts build "src/**/*.ts" && tsc �[32m@astrojs/partytown:build: �[0m �[32m@astrojs/preact:build: �[0m �[32m@astrojs/preact:build: �[0m> @astrojs/preact@2.2.1 build /home/runner/work/astro/astro/packages/integrations/preact �[32m@astrojs/preact:build: �[0m> astro-scripts build "src/**/*.ts" && tsc �[32m@astrojs/preact:build: �[0m �[33m@astrojs/deno:build: �[0m �[33m@astrojs/deno:build: �[0m> @astrojs/deno@4.2.0 build /home/runner/work/astro/astro/packages/integrations/deno �[33m@astrojs/deno:build: �[0m> astro-scripts build "src/**/*.ts" && tsc �[33m@astrojs/deno:build: �[0m �[33m@astrojs/alpinejs:build: �[0m �[33m@astrojs/alpinejs:build: �[0m> @astrojs/alpinejs@0.2.2 build /home/runner/work/astro/astro/packages/integrations/alpinejs �[33m@astrojs/alpinejs:build: �[0m> astro-scripts build "src/**/*.ts" && tsc �[33m@astrojs/alpinejs:build: �[0m �[33m@astrojs/react:build: �[0mcache miss, executing �[2me9e7d46ad431efe1�[0m �[34m@astrojs/solid-js:build: �[0mcache miss, executing �[2m3a1a94738b04c88b�[0m �[36m@astrojs/markdoc:build: �[0mcache miss, executing �[2m4f64008ae0289b87�[0m �[35m@astrojs/mdx:build: �[0mcache miss, executing �[2m00959f57cbcc4944�[0m �[32m@benchmark/timer:build: �[0mcache miss, executing �[2m86c5505029c78027�[0m �[34m@astrojs/underscore-redirects:build: �[0mcache miss, executing �[2mf8fcc039e1ce791d�[0m �[33m@astrojs/react:build: �[0m �[33m@astrojs/react:build: �[0m> @astrojs/react@2.2.1 build /home/runner/work/astro/astro/packages/integrations/react �[33m@astrojs/react:build: �[0m> astro-scripts build "src/**/*.ts" && tsc �[33m@astrojs/react:build: �[0m �[33m@astrojs/rss:build: �[0mcache miss, executing �[2mdcd9fb16e19c9c88�[0m �[36m@astrojs/turbolinks:build: �[0mcache miss, executing �[2m27ffd38638226635�[0m �[35m@astrojs/lit:build: �[0mcache miss, executing �[2ma40dd0469fa8236c�[0m �[34m@astrojs/solid-js:build: �[0m �[34m@astrojs/solid-js:build: �[0m> @astrojs/solid-js@2.2.0 build /home/runner/work/astro/astro/packages/integrations/solid �[34m@astrojs/solid-js:build: �[0m> astro-scripts build "src/**/*.ts" && tsc �[34m@astrojs/solid-js:build: �[0m �[36m@astrojs/markdoc:build: �[0m �[36m@astrojs/markdoc:build: �[0m> @astrojs/markdoc@0.3.3 build /home/runner/work/astro/astro/packages/integrations/markdoc �[36m@astrojs/markdoc:build: �[0m> astro-scripts build "src/**/*.ts" && tsc �[36m@astrojs/markdoc:build: �[0m �[35m@astrojs/mdx:build: �[0m �[35m@astrojs/mdx:build: �[0m> @astrojs/mdx@0.19.7 build /home/runner/work/astro/astro/packages/integrations/mdx �[35m@astrojs/mdx:build: �[0m> astro-scripts build "src/**/*.ts" && tsc �[35m@astrojs/mdx:build: �[0m �[32m@benchmark/timer:build: �[0m �[32m@benchmark/timer:build: �[0m> @benchmark/timer@0.0.0 build /home/runner/work/astro/astro/benchmark/packages/timer �[32m@benchmark/timer:build: �[0m> astro-scripts build "src/**/*.ts" && tsc �[32m@benchmark/timer:build: �[0m �[34m@astrojs/underscore-redirects:build: �[0m �[34m@astrojs/underscore-redirects:build: �[0m> @astrojs/underscore-redirects@0.1.0 build /home/runner/work/astro/astro/packages/underscore-redirects �[34m@astrojs/underscore-redirects:build: �[0m> astro-scripts build "src/**/*.ts" && tsc -p tsconfig.json �[34m@astrojs/underscore-redirects:build: �[0m �[33m@astrojs/rss:build: �[0m �[33m@astrojs/rss:build: �[0m> @astrojs/rss@2.4.3 build /home/runner/work/astro/astro/packages/astro-rss �[33m@astrojs/rss:build: �[0m> astro-scripts build "src/**/*.ts" && tsc �[33m@astrojs/rss:build: �[0m �[36m@astrojs/turbolinks:build: �[0m �[36m@astrojs/turbolinks:build: �[0m> @astrojs/turbolinks@0.2.2 build /home/runner/work/astro/astro/packages/integrations/turbolinks �[36m@astrojs/turbolinks:build: �[0m> astro-scripts build "src/**/*.ts" && tsc �[36m@astrojs/turbolinks:build: �[0m �[35m@astrojs/lit:build: �[0m �[35m@astrojs/lit:build: �[0m> @astrojs/lit@2.1.0 build /home/runner/work/astro/astro/packages/integrations/lit �[35m@astrojs/lit:build: �[0m> astro-scripts build "src/**/*.ts" && tsc �[35m@astrojs/lit:build: �[0m �[32m@astrojs/vercel:build: �[0mcache miss, executing �[2m96bcae608e3929fd�[0m �[33m@astrojs/sitemap:build: �[0mcache miss, executing �[2me31fd16d459eefd4�[0m �[32m@astrojs/vercel:build: �[0m �[32m@astrojs/vercel:build: �[0m> @astrojs/vercel@0.0.0-vercel-edge-middleware-20230629145510 build /home/runner/work/astro/astro/packages/integrations/vercel �[32m@astrojs/vercel:build: �[0m> astro-scripts build "src/**/*.ts" && tsc �[32m@astrojs/vercel:build: �[0m �[34m@astrojs/netlify:build: �[0mcache miss, executing �[2me6dbe04f4a067994�[0m �[36m@astrojs/cloudflare:build: �[0mcache miss, executing �[2m3f3199bb6dad254d�[0m �[33m@astrojs/sitemap:build: �[0m �[33m@astrojs/sitemap:build: �[0m> @astrojs/sitemap@1.3.3 build /home/runner/work/astro/astro/packages/integrations/sitemap �[33m@astrojs/sitemap:build: �[0m> astro-scripts build "src/**/*.ts" && tsc �[33m@astrojs/sitemap:build: �[0m �[36m@astrojs/cloudflare:build: �[0m �[36m@astrojs/cloudflare:build: �[0m> @astrojs/cloudflare@6.5.1 build /home/runner/work/astro/astro/packages/integrations/cloudflare �[36m@astrojs/cloudflare:build: �[0m> astro-scripts build "src/**/*.ts" && tsc �[36m@astrojs/cloudflare:build: �[0m �[34m@astrojs/netlify:build: �[0m �[34m@astrojs/netlify:build: �[0m> @astrojs/netlify@2.3.0 build /home/runner/work/astro/astro/packages/integrations/netlify �[34m@astrojs/netlify:build: �[0m> astro-scripts build "src/**/*.ts" && tsc �[34m@astrojs/netlify:build: �[0m Tasks: 30 successful, 30 total Cached: 6 cached, 30 total Time: 1m12.915s 🦋 �[33mwarn�[39m �[31m===============================IMPORTANT!===============================�[39m 🦋 �[33mwarn�[39m Packages will be released under the next--vercel-edge-middleware tag 🦋 �[33mwarn�[39m �[31m----------------------------------------------------------------------�[39m 🦋 �[36minfo�[39m npm info astro 🦋 �[36minfo�[39m npm info @astrojs/prism 🦋 �[36minfo�[39m npm info @astrojs/rss 🦋 �[36minfo�[39m npm info create-astro 🦋 �[36minfo�[39m npm info @astrojs/alpinejs 🦋 �[36minfo�[39m npm info @astrojs/cloudflare 🦋 �[36minfo�[39m npm info @astrojs/deno 🦋 �[36minfo�[39m npm info @astrojs/image 🦋 �[36minfo�[39m npm info @astrojs/lit 🦋 �[36minfo�[39m npm info @astrojs/markdoc 🦋 �[36minfo�[39m npm info @astrojs/mdx 🦋 �[36minfo�[39m npm info @astrojs/netlify 🦋 �[36minfo�[39m npm info @astrojs/node 🦋 �[36minfo�[39m npm info @astrojs/partytown 🦋 �[36minfo�[39m npm info @astrojs/preact 🦋 �[36minfo�[39m npm info @astrojs/prefetch 🦋 �[36minfo�[39m npm info @astrojs/react 🦋 �[36minfo�[39m npm info @astrojs/sitemap 🦋 �[36minfo�[39m npm info @astrojs/solid-js 🦋 �[36minfo�[39m npm info @astrojs/svelte 🦋 �[36minfo�[39m npm info @astrojs/tailwind 🦋 �[36minfo�[39m npm info @astrojs/turbolinks 🦋 �[36minfo�[39m npm info @astrojs/vercel 🦋 �[36minfo�[39m npm info @astrojs/vue 🦋 �[36minfo�[39m npm info @astrojs/internal-helpers 🦋 �[36minfo�[39m npm info @astrojs/markdown-component 🦋 �[36minfo�[39m npm info @astrojs/markdown-remark 🦋 �[36minfo�[39m npm info @astrojs/telemetry 🦋 �[36minfo�[39m npm info @astrojs/underscore-redirects 🦋 �[36minfo�[39m npm info @astrojs/webapi 🦋 �[36minfo�[39m astro is being published because our local version (0.0.0-vercel-edge-middleware-20230629145510) has not been published on npm 🦋 �[33mwarn�[39m @astrojs/prism is not being published because version 2.1.2 is already published on npm 🦋 �[33mwarn�[39m @astrojs/rss is not being published because version 2.4.3 is already published on npm 🦋 �[33mwarn�[39m create-astro is not being published because version 3.1.8 is already published on npm 🦋 �[33mwarn�[39m @astrojs/alpinejs is not being published because version 0.2.2 is already published on npm 🦋 �[33mwarn�[39m @astrojs/cloudflare is not being published because version 6.5.1 is already published on npm 🦋 �[33mwarn�[39m @astrojs/deno is not being published because version 4.2.0 is already published on npm 🦋 �[33mwarn�[39m @astrojs/image is not being published because version 0.17.1 is already published on npm 🦋 �[33mwarn�[39m @astrojs/lit is not being published because version 2.1.0 is already published on npm 🦋 �[33mwarn�[39m @astrojs/markdoc is not being published because version 0.3.3 is already published on npm 🦋 �[33mwarn�[39m @astrojs/mdx is not being published because version 0.19.7 is already published on npm 🦋 �[33mwarn�[39m @astrojs/netlify is not being published because version 2.3.0 is already published on npm 🦋 �[33mwarn�[39m @astrojs/node is not being published because version 5.3.0 is already published on npm 🦋 �[33mwarn�[39m @astrojs/partytown is not being published because version 1.2.3 is already published on npm 🦋 �[33mwarn�[39m @astrojs/preact is not being published because version 2.2.1 is already published on npm 🦋 �[33mwarn�[39m @astrojs/prefetch is not being published because version 0.2.3 is already published on npm 🦋 �[33mwarn�[39m @astrojs/react is not being published because version 2.2.1 is already published on npm 🦋 �[33mwarn�[39m @astrojs/sitemap is not being published because version 1.3.3 is already published on npm 🦋 �[33mwarn�[39m @astrojs/solid-js is not being published because version 2.2.0 is already published on npm 🦋 �[33mwarn�[39m @astrojs/svelte is not being published because version 3.0.0 is already published on npm 🦋 �[33mwarn�[39m @astrojs/tailwind is not being published because version 4.0.0 is already published on npm 🦋 �[33mwarn�[39m @astrojs/turbolinks is not being published because version 0.2.2 is already published on npm 🦋 �[36minfo�[39m @astrojs/vercel is being published because our local version (0.0.0-vercel-edge-middleware-20230629145510) has not been published on npm 🦋 �[33mwarn�[39m @astrojs/vue is not being published because version 2.2.1 is already published on npm 🦋 �[33mwarn�[39m @astrojs/internal-helpers is not being published because version 0.1.0 is already published on npm 🦋 �[33mwarn�[39m @astrojs/markdown-component is not being published because version 1.0.5 is already published on npm 🦋 �[33mwarn�[39m @astrojs/markdown-remark is not being published because version 2.2.1 is already published on npm 🦋 �[33mwarn�[39m @astrojs/telemetry is not being published because version 2.1.1 is already published on npm 🦋 �[33mwarn�[39m @astrojs/underscore-redirects is not being published because version 0.1.0 is already published on npm 🦋 �[33mwarn�[39m @astrojs/webapi is not being published because version 2.2.0 is already published on npm 🦋 �[36minfo�[39m Publishing �[36m"astro"�[39m at �[32m"0.0.0-vercel-edge-middleware-20230629145510"�[39m 🦋 �[36minfo�[39m Publishing �[36m"@astrojs/vercel"�[39m at �[32m"0.0.0-vercel-edge-middleware-20230629145510"�[39m 🦋 �[32msuccess�[39m packages published successfully: 🦋 astro@0.0.0-vercel-edge-middleware-20230629145510 🦋 @astrojs/vercel@0.0.0-vercel-edge-middleware-20230629145510 🦋 Creating git tags... 🦋 New tag: astro@0.0.0-vercel-edge-middleware-20230629145510 🦋 New tag: @astrojs/vercel@0.0.0-vercel-edge-middleware-20230629145510

@ematipico
Copy link
Copy Markdown
Member Author

I tested the feature and the middleware works! I could see my logs, and I could see the locals working and rendered in the Astro page, I could see the new vercel-edge-middleware file working.

Here's the plan: I will merge this PR once the CI passes. Then I will create a final PR that will merge all the new code to main, and we will involve the docs team to craft some decent changelogs and documentation.

@ematipico ematipico merged commit 5c20fc2 into feat/vercel-edge-middleware Jun 30, 2023
@ematipico ematipico deleted the feat/vercel/update-code-and-test-plt-586 branch June 30, 2023 10:00
analytics?: boolean;
imageService?: boolean;
imagesConfig?: VercelImageConfig;
createLocals?: CreateLocals;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to remove this option since we're using the file now?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pkg: astro Related to the core `astro` package (scope) pkg: integration Related to any renderer integration (scope) semver: minor Change triggers a `minor` release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants