sveltekit-adapter-middy 0.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +91 -0
- package/handler.js +11 -0
- package/index.js +98 -0
- package/package.json +66 -0
- package/sveltekitHandler.js +66 -0
- package/sveltekitMiddleware.js +46 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 will Farrell
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<h1>Middy SvelteKit Adapter</h1>
|
|
3
|
+
<img alt="Middy logo" src="https://raw.githubusercontent.com/middyjs/middy/main/docs/img/middy-logo.svg"/>
|
|
4
|
+
<p><strong>SvelteKit adapter for AWS Lambda using Middy</strong></p>
|
|
5
|
+
<p>
|
|
6
|
+
<a href="https://www.npmjs.com/package/@middy/http-router?activeTab=versions">
|
|
7
|
+
<img src="https://badge.fury.io/js/%40middy%2Fhttp-router.svg" alt="npm version" style="max-width:100%;">
|
|
8
|
+
</a>
|
|
9
|
+
<a href="https://packagephobia.com/result?p=@middy/http-router">
|
|
10
|
+
<img src="https://packagephobia.com/badge?p=@middy/http-router" alt="npm install size" style="max-width:100%;">
|
|
11
|
+
</a>
|
|
12
|
+
<a href="https://github.com/middyjs/middy/actions/workflows/tests.yml">
|
|
13
|
+
<img src="https://github.com/middyjs/middy/actions/workflows/tests.yml/badge.svg?branch=main&event=push" alt="GitHub Actions CI status badge" style="max-width:100%;">
|
|
14
|
+
</a>
|
|
15
|
+
<br/>
|
|
16
|
+
<a href="https://standardjs.com/">
|
|
17
|
+
<img src="https://img.shields.io/badge/code_style-standard-brightgreen.svg" alt="Standard Code Style" style="max-width:100%;">
|
|
18
|
+
</a>
|
|
19
|
+
<a href="https://snyk.io/test/github/middyjs/middy">
|
|
20
|
+
<img src="https://snyk.io/test/github/middyjs/middy/badge.svg" alt="Known Vulnerabilities" data-canonical-src="https://snyk.io/test/github/middyjs/middy" style="max-width:100%;">
|
|
21
|
+
</a>
|
|
22
|
+
<a href="https://github.com/middyjs/middy/actions/workflows/sast.yml">
|
|
23
|
+
<img src="https://github.com/middyjs/middy/actions/workflows/sast.yml/badge.svg
|
|
24
|
+
?branch=main&event=push" alt="CodeQL" style="max-width:100%;">
|
|
25
|
+
</a>
|
|
26
|
+
<a href="https://bestpractices.coreinfrastructure.org/projects/5280">
|
|
27
|
+
<img src="https://bestpractices.coreinfrastructure.org/projects/5280/badge" alt="Core Infrastructure Initiative (CII) Best Practices" style="max-width:100%;">
|
|
28
|
+
</a>
|
|
29
|
+
<br/>
|
|
30
|
+
<a href="https://gitter.im/middyjs/Lobby">
|
|
31
|
+
<img src="https://badges.gitter.im/gitterHQ/gitter.svg" alt="Chat on Gitter" style="max-width:100%;">
|
|
32
|
+
</a>
|
|
33
|
+
<a href="https://stackoverflow.com/questions/tagged/middy?sort=Newest&uqlId=35052">
|
|
34
|
+
<img src="https://img.shields.io/badge/StackOverflow-[middy]-yellow" alt="Ask questions on StackOverflow" style="max-width:100%;">
|
|
35
|
+
</a>
|
|
36
|
+
</p>
|
|
37
|
+
<!--<p>You can read the documentation at: <a href="https://middy.js.org/docs/ssr/sveltekit">https://middy.js.org/docs/ssr/sveltekit</a></p>-->
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
Creates a lambda that supports a Function URL with streaming responses.
|
|
41
|
+
|
|
42
|
+
## Features
|
|
43
|
+
|
|
44
|
+
- Response Stream
|
|
45
|
+
- Extendable with Middy middlewares:
|
|
46
|
+
- `http-content-encoding`
|
|
47
|
+
- `http-security-headers`
|
|
48
|
+
- `ssm`/`secrets-manger`
|
|
49
|
+
- Removes `x-sveltekit-page` headers
|
|
50
|
+
|
|
51
|
+
Note: Bring your own deployment.
|
|
52
|
+
|
|
53
|
+
## Getting started
|
|
54
|
+
|
|
55
|
+
```js
|
|
56
|
+
import adapter from 'sveltekit-adapter-middy'
|
|
57
|
+
|
|
58
|
+
export default {
|
|
59
|
+
kit: {
|
|
60
|
+
adapter: adapter({
|
|
61
|
+
// options
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Options
|
|
68
|
+
|
|
69
|
+
- `handlerPath` (string): Relative path to handler override file. Overriding allows you to add in Content-Encoding, Security Headers, and pass in secrets more securely. Defaults to build-in minimalist handler.
|
|
70
|
+
- `out` (string): Relative path to build dir. Defaults to `build`
|
|
71
|
+
- `esbuildOptions` (object): `esbuild` option overrides. See [code]() for defaults.
|
|
72
|
+
|
|
73
|
+
## Recommended Infrastructure
|
|
74
|
+
|
|
75
|
+
- CloudFront: Route to static assets / pages, with fallback to server side rendering
|
|
76
|
+
- S3: store static assets and pages
|
|
77
|
+
- Lambda Function URL: server side rendering
|
|
78
|
+
|
|
79
|
+
## Roadmap
|
|
80
|
+
|
|
81
|
+
- infra diagram
|
|
82
|
+
- cli to sync static assets to S3 w/ headers
|
|
83
|
+
- LLRT
|
|
84
|
+
|
|
85
|
+
## License
|
|
86
|
+
|
|
87
|
+
Licensed under [MIT License](LICENSE). Copyright (c) 2017-2024 [Luciano Mammino](https://github.com/lmammino), [will Farrell](https://github.com/willfarrell), and the [Middy team](https://github.com/middyjs/middy/graphs/contributors).
|
|
88
|
+
|
|
89
|
+
<a href="https://app.fossa.io/projects/git%2Bgithub.com%2Fmiddyjs%2Fmiddy?ref=badge_large">
|
|
90
|
+
<img src="https://app.fossa.io/api/projects/git%2Bgithub.com%2Fmiddyjs%2Fmiddy.svg?type=large" alt="FOSSA Status" style="max-width:100%;">
|
|
91
|
+
</a>
|
package/handler.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import middy from '@middy/core'
|
|
2
|
+
|
|
3
|
+
import sveltekitMiddleware from './sveltekitMiddleware.js'
|
|
4
|
+
import sveltekitHandler from './sveltekitHandler.js'
|
|
5
|
+
|
|
6
|
+
export const handler = middy({ streamifyResponse: true })
|
|
7
|
+
.use([
|
|
8
|
+
// other middleware here
|
|
9
|
+
sveltekitMiddleware()
|
|
10
|
+
])
|
|
11
|
+
.handler(sveltekitHandler)
|
package/index.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync } from 'node:fs'
|
|
2
|
+
import { fileURLToPath } from 'node:url'
|
|
3
|
+
import esbuild from 'esbuild'
|
|
4
|
+
|
|
5
|
+
const name = '@middy/sveltekit'
|
|
6
|
+
const files = fileURLToPath(new URL('./', import.meta.url).href)
|
|
7
|
+
|
|
8
|
+
const sveltekitAdapterMiddy = (opts = {}) => {
|
|
9
|
+
const {
|
|
10
|
+
out = 'build',
|
|
11
|
+
handlerPath = `${files}/handler.js`,
|
|
12
|
+
esbuildOptions = {}
|
|
13
|
+
} = opts
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
name,
|
|
17
|
+
async adapt(builder) {
|
|
18
|
+
const tmp = builder.getBuildDirectory('adapter-middy')
|
|
19
|
+
|
|
20
|
+
builder.rimraf(out)
|
|
21
|
+
builder.rimraf(tmp)
|
|
22
|
+
|
|
23
|
+
builder.log.minor('Copying static assets')
|
|
24
|
+
const clientFiles = await builder.writeClient(
|
|
25
|
+
`${out}/assets${builder.config.kit.paths.base}`
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
builder.log.minor('Building server')
|
|
29
|
+
await builder.writeServer(tmp)
|
|
30
|
+
writeFileSync(
|
|
31
|
+
`${tmp}/manifest.js`,
|
|
32
|
+
[
|
|
33
|
+
`export const manifest = ${builder.generateManifest({
|
|
34
|
+
relativePath: './'
|
|
35
|
+
})};`,
|
|
36
|
+
`export const prerendered = new Set(${JSON.stringify(
|
|
37
|
+
builder.prerendered.paths
|
|
38
|
+
)});`,
|
|
39
|
+
`export const base = ${JSON.stringify(
|
|
40
|
+
builder.config.kit.paths.base
|
|
41
|
+
)};`
|
|
42
|
+
].join('\n\n')
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
builder.copy(
|
|
46
|
+
`${files}/sveltekitMiddleware.js`,
|
|
47
|
+
`${tmp}/sveltekitMiddleware.js`
|
|
48
|
+
)
|
|
49
|
+
builder.copy(`${files}/sveltekitHandler.js`, `${tmp}/sveltekitHandler.js`)
|
|
50
|
+
builder.copy(handlerPath, `${tmp}/handler.js`)
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
const result = await esbuild.build({
|
|
54
|
+
target: 'node20',
|
|
55
|
+
bundle: true,
|
|
56
|
+
platform: 'node',
|
|
57
|
+
format: 'esm',
|
|
58
|
+
treeShaking: true,
|
|
59
|
+
...esbuildOptions,
|
|
60
|
+
entryPoints: [`${tmp}/handler.js`],
|
|
61
|
+
outfile: `${out}/index.mjs`,
|
|
62
|
+
external: ['node:*', ...(esbuildOptions?.external ?? [])]
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
if (result.warnings.length > 0) {
|
|
66
|
+
const formatted = await esbuild.formatMessages(result.warnings, {
|
|
67
|
+
kind: 'warning',
|
|
68
|
+
color: true
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
console.error(formatted.join('\n'))
|
|
72
|
+
}
|
|
73
|
+
} catch (err) {
|
|
74
|
+
const formatted = await esbuild.formatMessages(err.errors, {
|
|
75
|
+
kind: 'error',
|
|
76
|
+
color: true
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
console.error(formatted.join('\n'))
|
|
80
|
+
|
|
81
|
+
throw new Error(
|
|
82
|
+
`Bundling with esbuild failed with ${err.errors.length} ${
|
|
83
|
+
err.errors.length === 1 ? 'error' : 'errors'
|
|
84
|
+
}`
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
builder.log.minor('Prerendering static pages')
|
|
89
|
+
const prerenderedFiles = await builder.writePrerendered(
|
|
90
|
+
`${out}/prerendered${builder.config.kit.paths.base}`
|
|
91
|
+
)
|
|
92
|
+
},
|
|
93
|
+
supports: {
|
|
94
|
+
read: () => true
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
export default sveltekitAdapterMiddy
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "sveltekit-adapter-middy",
|
|
3
|
+
"version": "0.0.0-alpha.0",
|
|
4
|
+
"description": "SvelteKit adapter for AWS Lambda with Middy",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=20"
|
|
8
|
+
},
|
|
9
|
+
"engineStrict": true,
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"access": "public"
|
|
12
|
+
},
|
|
13
|
+
"module": "./index.js",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"import": {
|
|
17
|
+
"default": "./index.js"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"index.js",
|
|
23
|
+
"handler.js",
|
|
24
|
+
"sveltekitMiddleware.js",
|
|
25
|
+
"sveltekitHandler.js"
|
|
26
|
+
],
|
|
27
|
+
"scripts": {
|
|
28
|
+
"test": "echo test"
|
|
29
|
+
},
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"keywords": [
|
|
32
|
+
"SvelteKit",
|
|
33
|
+
"Middy",
|
|
34
|
+
"Lambda",
|
|
35
|
+
"Middleware",
|
|
36
|
+
"Serverless",
|
|
37
|
+
"AWS",
|
|
38
|
+
"AWS Lambda",
|
|
39
|
+
"Middy",
|
|
40
|
+
"HTTP",
|
|
41
|
+
"SSR"
|
|
42
|
+
],
|
|
43
|
+
"author": {
|
|
44
|
+
"name": "contributors",
|
|
45
|
+
"url": "https://github.com/willfarrell/sveltekit-adapter-middy/graphs/contributors"
|
|
46
|
+
},
|
|
47
|
+
"repository": {
|
|
48
|
+
"type": "git",
|
|
49
|
+
"url": "github:willfarrell/sveltekit-adapter-middy",
|
|
50
|
+
"directory": ""
|
|
51
|
+
},
|
|
52
|
+
"bugs": {
|
|
53
|
+
"url": "https://github.com/willfarrell/sveltekit-adapter-middy/issues"
|
|
54
|
+
},
|
|
55
|
+
"homepage": "https://middy.js.org",
|
|
56
|
+
"funding": {
|
|
57
|
+
"type": "github",
|
|
58
|
+
"url": "https://github.com/sponsors/willfarrell"
|
|
59
|
+
},
|
|
60
|
+
"dependencies": {
|
|
61
|
+
"@datastream/string": "0.0.36",
|
|
62
|
+
"@middy/core": "5.4.0",
|
|
63
|
+
"esbuild": "^0.21.0",
|
|
64
|
+
"set-cookie-parser": "2.6.0"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { splitCookiesString } from 'set-cookie-parser'
|
|
2
|
+
|
|
3
|
+
const lambdaHandler = async (event, context, { signal }) => {
|
|
4
|
+
const { server, env } = context
|
|
5
|
+
const { headers, rawQueryString, body: rawBody, isBase64Encoded } = event
|
|
6
|
+
const { method, path } = event.requestContext.http
|
|
7
|
+
|
|
8
|
+
// Copy secrets from ssm into import.meta scope
|
|
9
|
+
Object.assign(import.meta.env, env)
|
|
10
|
+
|
|
11
|
+
// Override origin
|
|
12
|
+
headers.origin = process.env.ORIGIN ?? headers.origin
|
|
13
|
+
|
|
14
|
+
const queryString = rawQueryString ? `?${rawQueryString}` : ''
|
|
15
|
+
const url = `${headers.origin}${path}${queryString}`
|
|
16
|
+
|
|
17
|
+
const encoding = isBase64Encoded
|
|
18
|
+
? 'base64'
|
|
19
|
+
: headers['content-encoding'] ?? 'utf-8'
|
|
20
|
+
const body =
|
|
21
|
+
typeof rawBody === 'string' ? Buffer.from(rawBody, encoding) : rawBody
|
|
22
|
+
|
|
23
|
+
await init
|
|
24
|
+
|
|
25
|
+
const rendered = await server.respond(
|
|
26
|
+
new Request(url, {
|
|
27
|
+
method,
|
|
28
|
+
headers: new Headers(headers),
|
|
29
|
+
body
|
|
30
|
+
}),
|
|
31
|
+
{
|
|
32
|
+
getClientAddress() {
|
|
33
|
+
console.log('getClientAddress', headers['x-forwarded-for'])
|
|
34
|
+
return headers['x-forwarded-for']
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
if (rendered) {
|
|
40
|
+
const response = {
|
|
41
|
+
statusCode: rendered.status,
|
|
42
|
+
headers: {
|
|
43
|
+
'cache-control': 'no-cache'
|
|
44
|
+
},
|
|
45
|
+
multiValueHeaders: {},
|
|
46
|
+
body: rendered.body
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
for (const [key, value] of rendered.headers.entries()) {
|
|
50
|
+
if (key === 'set-cookie') {
|
|
51
|
+
response.multiValueHeaders[key] = setCookie.splitCookiesString(value)
|
|
52
|
+
} else if (key === 'x-sveltekit-page') {
|
|
53
|
+
// excluded, security
|
|
54
|
+
} else {
|
|
55
|
+
response.headers[key] = value
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return response
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
statusCode: 404
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export default lambdaHandler
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { createTransformStream } from '@datastream/core'
|
|
2
|
+
import { Server } from './index.js'
|
|
3
|
+
import { manifest } from './manifest.js'
|
|
4
|
+
|
|
5
|
+
const server = new Server(manifest)
|
|
6
|
+
const init = server.init({ env: process.env })
|
|
7
|
+
|
|
8
|
+
// TODO replace with @datastream/string
|
|
9
|
+
export const stringReplaceStream = (options, streamOptions) => {
|
|
10
|
+
const { pattern, replacement } = options
|
|
11
|
+
let previousChunk = ''
|
|
12
|
+
const transform = (chunk, enqueue) => {
|
|
13
|
+
const newChunk = (previousChunk + chunk).replace(pattern, replacement)
|
|
14
|
+
enqueue(newChunk.substring(0, previousChunk.length))
|
|
15
|
+
previousChunk = newChunk.substring(previousChunk.length)
|
|
16
|
+
}
|
|
17
|
+
const flush = (enqueue) => {
|
|
18
|
+
enqueue(previousChunk)
|
|
19
|
+
}
|
|
20
|
+
return createTransformStream(transform, flush, streamOptions)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const formActionPattern = /action="\?\//g
|
|
24
|
+
const formActionReplacement = 'action="?%2F'
|
|
25
|
+
const sveltekitMiddleware = () => {
|
|
26
|
+
const sveltekitMiddlewareBefore = async (request) => {
|
|
27
|
+
request.context.server = server
|
|
28
|
+
await init
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const sveltekitMiddlewareAfter = async (request) => {
|
|
32
|
+
// Workaround: AWS Function URLs doesn't support querystring keys that contain `/`
|
|
33
|
+
if (request.response['Content-Type'].inlcudes('text/html')) {
|
|
34
|
+
const stream = stringReplaceStream({
|
|
35
|
+
pattern: formActionPattern,
|
|
36
|
+
replacement: formActionReplacement
|
|
37
|
+
})
|
|
38
|
+
request.response.body.pipe(stream)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
before: sveltekitMiddlewareBefore,
|
|
43
|
+
after: sveltekitMiddlewareAfter
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export default sveltekitMiddleware
|