netlify-cli 16.7.0 → 16.8.1
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/README.md +10 -0
- package/npm-shrinkwrap.json +16123 -10639
- package/package.json +6 -4
- package/src/commands/build/build.mjs +4 -2
- package/src/commands/deploy/deploy.mjs +11 -3
- package/src/commands/integration/deploy.mjs +397 -0
- package/src/commands/integration/index.mjs +25 -0
- package/src/commands/main.mjs +2 -0
- package/src/lib/build.mjs +3 -1
- package/src/lib/edge-functions/consts.mjs +1 -0
- package/src/lib/edge-functions/proxy.mjs +1 -2
- package/src/lib/edge-functions/registry.mjs +15 -19
- package/src/lib/functions/registry.mjs +31 -4
- package/src/lib/functions/server.mjs +15 -0
- package/src/functions-templates/javascript/apollo-graphql/.netlify-function-template.mjs +0 -5
- package/src/functions-templates/javascript/apollo-graphql/package.json +0 -21
- package/src/functions-templates/javascript/apollo-graphql/{{name}}.js +0 -42
- package/src/functions-templates/javascript/apollo-graphql-rest/.netlify-function-template.mjs +0 -5
- package/src/functions-templates/javascript/apollo-graphql-rest/package.json +0 -22
- package/src/functions-templates/javascript/apollo-graphql-rest/random-user.js +0 -23
- package/src/functions-templates/javascript/apollo-graphql-rest/{{name}}.js +0 -68
- package/src/functions-templates/javascript/auth-fetch/.netlify-function-template.mjs +0 -11
- package/src/functions-templates/javascript/auth-fetch/package-lock.json +0 -83
- package/src/functions-templates/javascript/auth-fetch/package.json +0 -21
- package/src/functions-templates/javascript/auth-fetch/{{name}}.js +0 -39
- package/src/functions-templates/javascript/create-user/.netlify-function-template.mjs +0 -11
- package/src/functions-templates/javascript/create-user/package.json +0 -21
- package/src/functions-templates/javascript/create-user/{{name}}.js +0 -36
- package/src/functions-templates/javascript/fauna-crud/.netlify-function-template.mjs +0 -17
- package/src/functions-templates/javascript/fauna-crud/create-schema.js +0 -36
- package/src/functions-templates/javascript/fauna-crud/create.js +0 -37
- package/src/functions-templates/javascript/fauna-crud/delete.js +0 -29
- package/src/functions-templates/javascript/fauna-crud/package.json +0 -20
- package/src/functions-templates/javascript/fauna-crud/read-all.js +0 -33
- package/src/functions-templates/javascript/fauna-crud/read.js +0 -30
- package/src/functions-templates/javascript/fauna-crud/update.js +0 -30
- package/src/functions-templates/javascript/fauna-crud/{{name}}.js +0 -62
- package/src/functions-templates/javascript/fauna-graphql/.netlify-function-template.mjs +0 -17
- package/src/functions-templates/javascript/fauna-graphql/package.json +0 -26
- package/src/functions-templates/javascript/fauna-graphql/schema.graphql +0 -8
- package/src/functions-templates/javascript/fauna-graphql/sync-schema.js +0 -38
- package/src/functions-templates/javascript/fauna-graphql/{{name}}.js +0 -46
- package/src/functions-templates/javascript/google-analytics/.netlify-function-template.mjs +0 -5
- package/src/functions-templates/javascript/google-analytics/package-lock.json +0 -100
- package/src/functions-templates/javascript/google-analytics/package.json +0 -25
- package/src/functions-templates/javascript/google-analytics/{{name}}.js +0 -114
- package/src/functions-templates/javascript/graphql-gateway/.netlify-function-template.mjs +0 -5
- package/src/functions-templates/javascript/graphql-gateway/example-sibling-function-graphql-1.js +0 -42
- package/src/functions-templates/javascript/graphql-gateway/example-sibling-function-graphql-2.js +0 -80
- package/src/functions-templates/javascript/graphql-gateway/package.json +0 -24
- package/src/functions-templates/javascript/graphql-gateway/{{name}}.js +0 -75
- package/src/functions-templates/javascript/hasura-event-triggered/.netlify-function-template.mjs +0 -5
- package/src/functions-templates/javascript/hasura-event-triggered/package.json +0 -21
- package/src/functions-templates/javascript/hasura-event-triggered/{{name}}.js +0 -40
- package/src/functions-templates/javascript/node-fetch/.netlify-function-template.mjs +0 -5
- package/src/functions-templates/javascript/node-fetch/package.json +0 -19
- package/src/functions-templates/javascript/node-fetch/{{name}}.js +0 -29
- package/src/functions-templates/javascript/oauth-passport/.netlify-function-template.mjs +0 -5
- package/src/functions-templates/javascript/oauth-passport/package.json +0 -25
- package/src/functions-templates/javascript/oauth-passport/utils/auth.js +0 -65
- package/src/functions-templates/javascript/oauth-passport/utils/config.js +0 -24
- package/src/functions-templates/javascript/oauth-passport/{{name}}.js +0 -37
- package/src/functions-templates/javascript/protected-function/.netlify-function-template.mjs +0 -5
- package/src/functions-templates/javascript/protected-function/{{name}}.js +0 -25
- package/src/functions-templates/javascript/send-email/.netlify-function-template.mjs +0 -5
- package/src/functions-templates/javascript/send-email/package.json +0 -21
- package/src/functions-templates/javascript/send-email/validations.js +0 -38
- package/src/functions-templates/javascript/send-email/{{name}}.js +0 -68
- package/src/functions-templates/javascript/serverless-ssr/.netlify-function-template.mjs +0 -5
- package/src/functions-templates/javascript/serverless-ssr/app/index.js +0 -116
- package/src/functions-templates/javascript/serverless-ssr/package.json +0 -24
- package/src/functions-templates/javascript/serverless-ssr/serverless-http.js +0 -15
- package/src/functions-templates/javascript/serverless-ssr/{{name}}.js +0 -15
- package/src/functions-templates/javascript/set-cookie/.netlify-function-template.mjs +0 -5
- package/src/functions-templates/javascript/set-cookie/package.json +0 -19
- package/src/functions-templates/javascript/set-cookie/{{name}}.js +0 -44
- package/src/functions-templates/javascript/slack-rate-limit/.netlify-function-template.mjs +0 -5
- package/src/functions-templates/javascript/slack-rate-limit/package.json +0 -20
- package/src/functions-templates/javascript/slack-rate-limit/{{name}}.js +0 -115
- package/src/functions-templates/javascript/stripe-charge/.netlify-function-template.mjs +0 -28
- package/src/functions-templates/javascript/stripe-charge/package-lock.json +0 -196
- package/src/functions-templates/javascript/stripe-charge/package.json +0 -21
- package/src/functions-templates/javascript/stripe-charge/{{name}}.js +0 -56
- package/src/functions-templates/javascript/stripe-subscription/.netlify-function-template.mjs +0 -28
- package/src/functions-templates/javascript/stripe-subscription/package-lock.json +0 -196
- package/src/functions-templates/javascript/stripe-subscription/package.json +0 -21
- package/src/functions-templates/javascript/stripe-subscription/{{name}}.js +0 -52
- package/src/functions-templates/javascript/token-hider/.netlify-function-template.mjs +0 -29
- package/src/functions-templates/javascript/token-hider/package-lock.json +0 -317
- package/src/functions-templates/javascript/token-hider/package.json +0 -21
- package/src/functions-templates/javascript/token-hider/{{name}}.js +0 -37
- package/src/functions-templates/javascript/url-shortener/.netlify-function-template.mjs +0 -29
- package/src/functions-templates/javascript/url-shortener/generate-route.js +0 -53
- package/src/functions-templates/javascript/url-shortener/get-route.js +0 -32
- package/src/functions-templates/javascript/url-shortener/package-lock.json +0 -126
- package/src/functions-templates/javascript/url-shortener/package.json +0 -22
- package/src/functions-templates/javascript/url-shortener/{{name}}.js +0 -30
- package/src/functions-templates/javascript/using-middleware/.netlify-function-template.mjs +0 -5
- package/src/functions-templates/javascript/using-middleware/package.json +0 -19
- package/src/functions-templates/javascript/using-middleware/{{name}}.js +0 -60
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "graphql-gateway",
|
|
3
|
-
"version": "1.0.0",
|
|
4
|
-
"description": "netlify functions:create - Apollo Server Lambda Gateway stitching schemas from other GraphQL Functions!",
|
|
5
|
-
"main": "graphql-gateway.js",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
|
-
},
|
|
9
|
-
"keywords": [
|
|
10
|
-
"netlify",
|
|
11
|
-
"serverless",
|
|
12
|
-
"js",
|
|
13
|
-
"apollo"
|
|
14
|
-
],
|
|
15
|
-
"author": "Netlify",
|
|
16
|
-
"license": "MIT",
|
|
17
|
-
"dependencies": {
|
|
18
|
-
"apollo-link-http": "^1.5.17",
|
|
19
|
-
"apollo-server-lambda": "^2.18.2",
|
|
20
|
-
"graphql": "^14.2.1",
|
|
21
|
-
"graphql-tools": "^4.0.8",
|
|
22
|
-
"node-fetch": "^2.6.1"
|
|
23
|
-
}
|
|
24
|
-
}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This code assumes you have other graphql Netlify functions
|
|
3
|
-
* and shows you how to stitch them together in a "gateway".
|
|
4
|
-
*
|
|
5
|
-
* Of course, feel free to modify this gateway to suit your needs.
|
|
6
|
-
*/
|
|
7
|
-
const process = require('process')
|
|
8
|
-
|
|
9
|
-
const { createHttpLink } = require('apollo-link-http')
|
|
10
|
-
const { ApolloServer } = require('apollo-server-lambda')
|
|
11
|
-
const { introspectSchema, makeRemoteExecutableSchema, mergeSchemas } = require('graphql-tools')
|
|
12
|
-
const fetch = require('node-fetch')
|
|
13
|
-
|
|
14
|
-
const handler = async function (event, context) {
|
|
15
|
-
// other Netlify functions which are graphql lambdas
|
|
16
|
-
const schema1 = await getSchema('graphql-1')
|
|
17
|
-
const schema2 = await getSchema('graphql-2')
|
|
18
|
-
const schemas = [schema1, schema2]
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* resolving -between- schemas
|
|
22
|
-
* https://www.apollographql.com/docs/graphql-tools/schema-stitching#adding-resolvers
|
|
23
|
-
*/
|
|
24
|
-
const linkTypeDefs = `
|
|
25
|
-
extend type Book {
|
|
26
|
-
author: Author
|
|
27
|
-
}
|
|
28
|
-
`
|
|
29
|
-
schemas.push(linkTypeDefs)
|
|
30
|
-
const resolvers = {
|
|
31
|
-
Book: {
|
|
32
|
-
author: {
|
|
33
|
-
fragment: `... on Book { authorName }`,
|
|
34
|
-
resolve(book, args, resolveContext, info) {
|
|
35
|
-
return info.mergeInfo.delegateToSchema({
|
|
36
|
-
schema: schema1,
|
|
37
|
-
operation: 'query',
|
|
38
|
-
// reuse what's implemented in schema1
|
|
39
|
-
fieldName: 'authorByName',
|
|
40
|
-
args: {
|
|
41
|
-
name: book.authorName,
|
|
42
|
-
},
|
|
43
|
-
context: resolveContext,
|
|
44
|
-
info,
|
|
45
|
-
})
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// more docs https://www.apollographql.com/docs/graphql-tools/schema-stitching#api
|
|
52
|
-
const schema = mergeSchemas({
|
|
53
|
-
schemas,
|
|
54
|
-
resolvers,
|
|
55
|
-
})
|
|
56
|
-
const server = new ApolloServer({ schema })
|
|
57
|
-
return new Promise((resolve, reject) => {
|
|
58
|
-
const cb = (err, args) => (err ? reject(err) : resolve(args))
|
|
59
|
-
server.createHandler()(event, context, cb)
|
|
60
|
-
})
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const getSchema = async function (endpoint) {
|
|
64
|
-
// you can't use relative URLs within Netlify Functions so need a base URL
|
|
65
|
-
// process.env.URL is one of many build env variables:
|
|
66
|
-
// https://docs.netlify.com/configure-builds/environment-variables/
|
|
67
|
-
// Netlify Dev only supports URL and DEPLOY URL for now
|
|
68
|
-
const uri = `${process.env.URL}/.netlify/functions/${endpoint}`
|
|
69
|
-
const link = createHttpLink({ uri, fetch })
|
|
70
|
-
const schema = await introspectSchema(link)
|
|
71
|
-
const executableSchema = makeRemoteExecutableSchema({ schema, link })
|
|
72
|
-
return executableSchema
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
module.exports = { handler }
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "hasura-event-triggered",
|
|
3
|
-
"version": "1.0.0",
|
|
4
|
-
"description": "netlify functions:create - Serverless function to process a Hasura event and fire off a GraphQL mutation with cleaned text data",
|
|
5
|
-
"main": "hasura-event-triggered.js",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
|
-
},
|
|
9
|
-
"keywords": [
|
|
10
|
-
"netlify",
|
|
11
|
-
"serverless",
|
|
12
|
-
"js",
|
|
13
|
-
"hasura"
|
|
14
|
-
],
|
|
15
|
-
"author": "Netlify",
|
|
16
|
-
"license": "MIT",
|
|
17
|
-
"dependencies": {
|
|
18
|
-
"axios": "^1.0.0",
|
|
19
|
-
"bad-words": "^3.0.3"
|
|
20
|
-
}
|
|
21
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
// with thanks to https://github.com/vnovick/netlify-function-example/blob/master/functions/bad-words.js
|
|
2
|
-
const axios = require('axios')
|
|
3
|
-
const Filter = require('bad-words')
|
|
4
|
-
|
|
5
|
-
const filter = new Filter()
|
|
6
|
-
const hgeEndpoint = 'https://live-coding-netlify.herokuapp.com'
|
|
7
|
-
|
|
8
|
-
const query = `
|
|
9
|
-
mutation verifiedp($id: uuid!, $title: String!, $content: String!) {
|
|
10
|
-
update_posts(_set: { verified: true, content: $content, title: $title },
|
|
11
|
-
where:{ id: { _eq: $id } }) {
|
|
12
|
-
returning {
|
|
13
|
-
id
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
`
|
|
18
|
-
|
|
19
|
-
const handler = async (event) => {
|
|
20
|
-
let request
|
|
21
|
-
try {
|
|
22
|
-
request = JSON.parse(event.body)
|
|
23
|
-
} catch {
|
|
24
|
-
return { statusCode: 400, body: 'c annot parse hasura event' }
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const variables = {
|
|
28
|
-
id: request.event.data.new.id,
|
|
29
|
-
title: filter.clean(request.event.data.new.title),
|
|
30
|
-
content: filter.clean(request.event.data.new.content),
|
|
31
|
-
}
|
|
32
|
-
try {
|
|
33
|
-
await axios.post(`${hgeEndpoint}/v1alpha1/graphql`, { query, variables })
|
|
34
|
-
return { statusCode: 200, body: 'success' }
|
|
35
|
-
} catch (error) {
|
|
36
|
-
return { statusCode: 500, body: error.toString() }
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
module.exports = { handler }
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "node-fetch",
|
|
3
|
-
"version": "1.0.0",
|
|
4
|
-
"description": "netlify functions:create - default template for node fetch function",
|
|
5
|
-
"main": "node-fetch.js",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
|
-
},
|
|
9
|
-
"keywords": [
|
|
10
|
-
"netlify",
|
|
11
|
-
"serverless",
|
|
12
|
-
"js"
|
|
13
|
-
],
|
|
14
|
-
"author": "Netlify",
|
|
15
|
-
"license": "MIT",
|
|
16
|
-
"dependencies": {
|
|
17
|
-
"node-fetch": "^2.6.1"
|
|
18
|
-
}
|
|
19
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
const fetch = require('node-fetch')
|
|
2
|
-
|
|
3
|
-
const handler = async function () {
|
|
4
|
-
try {
|
|
5
|
-
const response = await fetch('https://icanhazdadjoke.com', {
|
|
6
|
-
headers: { Accept: 'application/json' },
|
|
7
|
-
})
|
|
8
|
-
if (!response.ok) {
|
|
9
|
-
// NOT res.status >= 200 && res.status < 300
|
|
10
|
-
return { statusCode: response.status, body: response.statusText }
|
|
11
|
-
}
|
|
12
|
-
const data = await response.json()
|
|
13
|
-
|
|
14
|
-
return {
|
|
15
|
-
statusCode: 200,
|
|
16
|
-
body: JSON.stringify({ msg: data.joke }),
|
|
17
|
-
}
|
|
18
|
-
} catch (error) {
|
|
19
|
-
// output to netlify function log
|
|
20
|
-
console.log(error)
|
|
21
|
-
return {
|
|
22
|
-
statusCode: 500,
|
|
23
|
-
// Could be a custom message or object i.e. JSON.stringify(err)
|
|
24
|
-
body: JSON.stringify({ msg: error.message }),
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
module.exports = { handler }
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "oauth-passport",
|
|
3
|
-
"version": "1.0.0",
|
|
4
|
-
"description": "netlify functions:create - template for Oauth workflow using Passport + Express.js",
|
|
5
|
-
"main": "oauth-passport.js",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
|
-
},
|
|
9
|
-
"keywords": [
|
|
10
|
-
"netlify",
|
|
11
|
-
"serverless",
|
|
12
|
-
"js"
|
|
13
|
-
],
|
|
14
|
-
"author": "Netlify",
|
|
15
|
-
"license": "MIT",
|
|
16
|
-
"dependencies": {
|
|
17
|
-
"cookie-parser": "^1.4.5",
|
|
18
|
-
"express": "^4.17.1",
|
|
19
|
-
"jsonwebtoken": "^9.0.0",
|
|
20
|
-
"passport": "^0.6.0",
|
|
21
|
-
"passport-github2": "^0.1.12",
|
|
22
|
-
"passport-jwt": "^4.0.0",
|
|
23
|
-
"serverless-http": "^2.0.2"
|
|
24
|
-
}
|
|
25
|
-
}
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
const { sign } = require('jsonwebtoken')
|
|
2
|
-
const passport = require('passport')
|
|
3
|
-
const { Strategy: GitHubStrategy } = require('passport-github2')
|
|
4
|
-
const passportJwt = require('passport-jwt')
|
|
5
|
-
|
|
6
|
-
const { BASE_URL, ENDPOINT, GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET, SECRET } = require('./config.js')
|
|
7
|
-
|
|
8
|
-
const authJwt = function (email) {
|
|
9
|
-
return sign({ user: { email } }, SECRET)
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const applyPassportStrategies = function () {
|
|
13
|
-
passport.use(getGitHubStrategy())
|
|
14
|
-
passport.use(getJwtStrategy())
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const getGitHubStrategy = function () {
|
|
18
|
-
return new GitHubStrategy(
|
|
19
|
-
{
|
|
20
|
-
clientID: GITHUB_CLIENT_ID,
|
|
21
|
-
clientSecret: GITHUB_CLIENT_SECRET,
|
|
22
|
-
callbackURL: `${BASE_URL}${ENDPOINT}/auth/github/callback`,
|
|
23
|
-
scope: ['user:email'],
|
|
24
|
-
},
|
|
25
|
-
async (accessToken, refreshToken, profile, done) => {
|
|
26
|
-
try {
|
|
27
|
-
const email = profile.emails[0].value
|
|
28
|
-
// Here you'd typically create a new or load an existing user and
|
|
29
|
-
// store the bare necessary informations about the user in the JWT.
|
|
30
|
-
const jwt = authJwt(email)
|
|
31
|
-
|
|
32
|
-
return done(null, { email, jwt })
|
|
33
|
-
} catch (error) {
|
|
34
|
-
return done(error)
|
|
35
|
-
}
|
|
36
|
-
},
|
|
37
|
-
)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const getJwtStrategy = function () {
|
|
41
|
-
return new passportJwt.Strategy(
|
|
42
|
-
{
|
|
43
|
-
jwtFromRequest(req) {
|
|
44
|
-
if (!req.cookies) throw new Error('Missing cookie-parser middleware')
|
|
45
|
-
return req.cookies.jwt
|
|
46
|
-
},
|
|
47
|
-
secretOrKey: SECRET,
|
|
48
|
-
},
|
|
49
|
-
async ({ user: { email } }, done) => {
|
|
50
|
-
try {
|
|
51
|
-
// Here you'd typically load an existing user
|
|
52
|
-
// and use the data to create the JWT.
|
|
53
|
-
const jwt = authJwt(email)
|
|
54
|
-
|
|
55
|
-
return done(null, { email, jwt })
|
|
56
|
-
} catch (error) {
|
|
57
|
-
return done(error)
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
module.exports = {
|
|
64
|
-
applyPassportStrategies,
|
|
65
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
// lambda/utils/config.js
|
|
2
|
-
// Circumvent problem with Netlify CLI.
|
|
3
|
-
// https://github.com/netlify/netlify-dev-plugin/issues/147
|
|
4
|
-
const process = require('process')
|
|
5
|
-
|
|
6
|
-
const BASE_URL = process.env.NODE_ENV === 'development' ? 'http://localhost:8888' : process.env.BASE_URL
|
|
7
|
-
|
|
8
|
-
const COOKIE_SECURE = process.env.NODE_ENV !== 'development'
|
|
9
|
-
|
|
10
|
-
const ENDPOINT = process.env.NODE_ENV === 'development' ? '/.netlify/functions' : '/api'
|
|
11
|
-
|
|
12
|
-
const { GITHUB_CLIENT_ID } = process.env
|
|
13
|
-
const { GITHUB_CLIENT_SECRET } = process.env
|
|
14
|
-
|
|
15
|
-
const SECRET = process.env.SECRET || 'SUPERSECRET'
|
|
16
|
-
|
|
17
|
-
module.exports = {
|
|
18
|
-
BASE_URL,
|
|
19
|
-
COOKIE_SECURE,
|
|
20
|
-
ENDPOINT,
|
|
21
|
-
GITHUB_CLIENT_ID,
|
|
22
|
-
GITHUB_CLIENT_SECRET,
|
|
23
|
-
SECRET,
|
|
24
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
// details: https://markus.oberlehner.net/blog/implementing-an-authentication-flow-with-passport-and-netlify-functions/
|
|
2
|
-
|
|
3
|
-
const cookieParser = require('cookie-parser')
|
|
4
|
-
const express = require('express')
|
|
5
|
-
const passport = require('passport')
|
|
6
|
-
const serverless = require('serverless-http')
|
|
7
|
-
|
|
8
|
-
const { applyPassportStrategies } = require('./utils/auth.js')
|
|
9
|
-
const { COOKIE_SECURE, ENDPOINT } = require('./utils/config.js')
|
|
10
|
-
|
|
11
|
-
applyPassportStrategies()
|
|
12
|
-
|
|
13
|
-
const app = express()
|
|
14
|
-
|
|
15
|
-
app.use(express.urlencoded({ extended: true }))
|
|
16
|
-
app.use(express.json())
|
|
17
|
-
app.use(cookieParser())
|
|
18
|
-
app.use(passport.initialize())
|
|
19
|
-
|
|
20
|
-
const handleCallback = (req, res) => {
|
|
21
|
-
res.cookie('jwt', req.user.jwt, { httpOnly: true, COOKIE_SECURE }).redirect('/')
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
app.get(`${ENDPOINT}/auth/github`, passport.authenticate('github', { session: false }))
|
|
25
|
-
app.get(
|
|
26
|
-
`${ENDPOINT}/auth/github/callback`,
|
|
27
|
-
passport.authenticate('github', { failureRedirect: '/', session: false }),
|
|
28
|
-
handleCallback,
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
app.get(`${ENDPOINT}/auth/status`, passport.authenticate('jwt', { session: false }), (req, res) =>
|
|
32
|
-
res.json({ email: req.user.email }),
|
|
33
|
-
)
|
|
34
|
-
|
|
35
|
-
const handler = serverless(app)
|
|
36
|
-
|
|
37
|
-
module.exports = { handler }
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
const handler = async (event, context) => {
|
|
2
|
-
console.log('protected function!')
|
|
3
|
-
// Reading the context.clientContext will give us the current user
|
|
4
|
-
const claims = context.clientContext && context.clientContext.user
|
|
5
|
-
console.log('user claims', claims)
|
|
6
|
-
|
|
7
|
-
if (!claims) {
|
|
8
|
-
console.log('No claims! Begone!')
|
|
9
|
-
return {
|
|
10
|
-
statusCode: 401,
|
|
11
|
-
body: JSON.stringify({
|
|
12
|
-
data: 'NOT ALLOWED',
|
|
13
|
-
}),
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
return {
|
|
18
|
-
statusCode: 200,
|
|
19
|
-
body: JSON.stringify({
|
|
20
|
-
data: 'auth true',
|
|
21
|
-
}),
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
module.exports = { handler }
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "send-email",
|
|
3
|
-
"version": "1.0.0",
|
|
4
|
-
"description": "netlify functions:create - Send email with no SMTP server via 'sendmail' pkg",
|
|
5
|
-
"main": "send-email.js",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
|
-
},
|
|
9
|
-
"keywords": [
|
|
10
|
-
"netlify",
|
|
11
|
-
"serverless",
|
|
12
|
-
"apis",
|
|
13
|
-
"email",
|
|
14
|
-
"js"
|
|
15
|
-
],
|
|
16
|
-
"author": "Netlify",
|
|
17
|
-
"license": "MIT",
|
|
18
|
-
"dependencies": {
|
|
19
|
-
"sendmail": "1.6.1"
|
|
20
|
-
}
|
|
21
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
const validateEmail = (ctx, str) => {
|
|
2
|
-
if (typeof str !== 'string' && !(str instanceof String)) {
|
|
3
|
-
throw new TypeError(`${ctx} must be a string`)
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
validateLength(ctx, str, EMAIL_MIN_LENGTH, EMAIL_MAX_LENGTH)
|
|
7
|
-
|
|
8
|
-
if (!/^[\w.-]+@[\w.-]+\.\w+$/.test(str)) {
|
|
9
|
-
throw new TypeError(`${ctx} is not an email address`)
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const EMAIL_MIN_LENGTH = 5
|
|
14
|
-
const EMAIL_MAX_LENGTH = 30
|
|
15
|
-
|
|
16
|
-
const validateLength = (ctx, str, min, max) => {
|
|
17
|
-
if (max === undefined) {
|
|
18
|
-
max = min
|
|
19
|
-
min = 0
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (typeof str !== 'string' && !(str instanceof String)) {
|
|
23
|
-
throw new TypeError(`${ctx} must be a string`)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (str.length < min) {
|
|
27
|
-
throw new TypeError(`${ctx} must be at least ${min} chars long`)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (str.length > max) {
|
|
31
|
-
throw new TypeError(`${ctx} must contain ${max} chars at most`)
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
module.exports = {
|
|
36
|
-
validateEmail,
|
|
37
|
-
validateLength,
|
|
38
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
// with thanks to https://github.com/Urigo/graphql-modules/blob/8cb2fd7d9938a856f83e4eee2081384533771904/website/lambda/contact.js
|
|
2
|
-
const process = require('process')
|
|
3
|
-
const { promisify } = require('util')
|
|
4
|
-
|
|
5
|
-
const sendMailLib = require('sendmail')
|
|
6
|
-
|
|
7
|
-
const { validateEmail, validateLength } = require('./validations.js')
|
|
8
|
-
|
|
9
|
-
const sendMail = promisify(sendMailLib())
|
|
10
|
-
|
|
11
|
-
const NAME_MIN_LENGTH = 3
|
|
12
|
-
const NAME_MAX_LENGTH = 50
|
|
13
|
-
const DETAILS_MIN_LENGTH = 10
|
|
14
|
-
const DETAILS_MAX_LENGTH = 1e3
|
|
15
|
-
|
|
16
|
-
const handler = async (event) => {
|
|
17
|
-
if (!process.env.CONTACT_EMAIL) {
|
|
18
|
-
return {
|
|
19
|
-
statusCode: 500,
|
|
20
|
-
body: 'process.env.CONTACT_EMAIL must be defined',
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const body = JSON.parse(event.body)
|
|
25
|
-
|
|
26
|
-
try {
|
|
27
|
-
validateLength('body.name', body.name, NAME_MIN_LENGTH, NAME_MAX_LENGTH)
|
|
28
|
-
} catch (error) {
|
|
29
|
-
return {
|
|
30
|
-
statusCode: 403,
|
|
31
|
-
body: error.message,
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
try {
|
|
36
|
-
validateEmail('body.email', body.email)
|
|
37
|
-
} catch (error) {
|
|
38
|
-
return {
|
|
39
|
-
statusCode: 403,
|
|
40
|
-
body: error.message,
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
try {
|
|
45
|
-
validateLength('body.details', body.details, DETAILS_MIN_LENGTH, DETAILS_MAX_LENGTH)
|
|
46
|
-
} catch (error) {
|
|
47
|
-
return {
|
|
48
|
-
statusCode: 403,
|
|
49
|
-
body: error.message,
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const descriptor = {
|
|
54
|
-
from: `"${body.email}" <no-reply@gql-modules.com>`,
|
|
55
|
-
to: process.env.CONTACT_EMAIL,
|
|
56
|
-
subject: `${body.name} sent you a message from gql-modules.com`,
|
|
57
|
-
text: body.details,
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
try {
|
|
61
|
-
await sendMail(descriptor)
|
|
62
|
-
return { statusCode: 200, body: '' }
|
|
63
|
-
} catch (error) {
|
|
64
|
-
return { statusCode: 500, body: error.message }
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
module.exports = { handler }
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
/* Express App */
|
|
2
|
-
const process = require('process')
|
|
3
|
-
|
|
4
|
-
const compression = require('compression')
|
|
5
|
-
const cors = require('cors')
|
|
6
|
-
const express = require('express')
|
|
7
|
-
const morgan = require('morgan')
|
|
8
|
-
|
|
9
|
-
/* My express App */
|
|
10
|
-
module.exports = function expressApp(functionName) {
|
|
11
|
-
const app = express()
|
|
12
|
-
const router = express.Router()
|
|
13
|
-
|
|
14
|
-
// gzip responses
|
|
15
|
-
router.use(compression())
|
|
16
|
-
|
|
17
|
-
// Set router base path for local dev
|
|
18
|
-
const routerBasePath = process.env.NODE_ENV === 'dev' ? `/${functionName}` : `/.netlify/functions/${functionName}/`
|
|
19
|
-
|
|
20
|
-
/* define routes */
|
|
21
|
-
router.get('/', function onRequest(req, res) {
|
|
22
|
-
const html = `
|
|
23
|
-
<html>
|
|
24
|
-
<head>
|
|
25
|
-
<style>
|
|
26
|
-
body {
|
|
27
|
-
padding: 30px;
|
|
28
|
-
}
|
|
29
|
-
</style>
|
|
30
|
-
</head>
|
|
31
|
-
<body>
|
|
32
|
-
<h1>Express via '${functionName}' ⊂◉‿◉つ</h1>
|
|
33
|
-
|
|
34
|
-
<p>I'm using Express running via a <a href='https://docs.netlify.com/functions/overview/' target='_blank'>Netlify Function</a>.</p>
|
|
35
|
-
|
|
36
|
-
<p>Choose a route:</p>
|
|
37
|
-
|
|
38
|
-
<div>
|
|
39
|
-
<a href='/.netlify/functions/${functionName}/users'>View /users route</a>
|
|
40
|
-
</div>
|
|
41
|
-
|
|
42
|
-
<div>
|
|
43
|
-
<a href='/.netlify/functions/${functionName}/hello'>View /hello route</a>
|
|
44
|
-
</div>
|
|
45
|
-
|
|
46
|
-
<br/>
|
|
47
|
-
<br/>
|
|
48
|
-
|
|
49
|
-
<div>
|
|
50
|
-
<a href='/'>
|
|
51
|
-
Go back to demo homepage
|
|
52
|
-
</a>
|
|
53
|
-
</div>
|
|
54
|
-
|
|
55
|
-
<br/>
|
|
56
|
-
<br/>
|
|
57
|
-
|
|
58
|
-
<div>
|
|
59
|
-
<a href='https://github.com/DavidWells/netlify-functions-express' target='_blank'>
|
|
60
|
-
See the source code on GitHub
|
|
61
|
-
</a>
|
|
62
|
-
</div>
|
|
63
|
-
</body>
|
|
64
|
-
</html>
|
|
65
|
-
`
|
|
66
|
-
res.send(html)
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
router.get('/users', function onRequest(req, res) {
|
|
70
|
-
res.json({
|
|
71
|
-
users: [
|
|
72
|
-
{
|
|
73
|
-
name: 'steve',
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
name: 'joe',
|
|
77
|
-
},
|
|
78
|
-
],
|
|
79
|
-
})
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
router.get('/hello/', function onRequest(req, res) {
|
|
83
|
-
res.send('hello world')
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
// Attach logger
|
|
87
|
-
app.use(morgan(customLogger))
|
|
88
|
-
|
|
89
|
-
// Setup routes
|
|
90
|
-
app.use(routerBasePath, router)
|
|
91
|
-
|
|
92
|
-
// Apply express middlewares
|
|
93
|
-
router.use(cors())
|
|
94
|
-
router.use(express.json())
|
|
95
|
-
router.use(express.urlencoded({ extended: true }))
|
|
96
|
-
|
|
97
|
-
return app
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const customLogger = function (tokens, req, res) {
|
|
101
|
-
const log = [
|
|
102
|
-
tokens.method(req, res),
|
|
103
|
-
tokens.url(req, res),
|
|
104
|
-
tokens.status(req, res),
|
|
105
|
-
tokens.res(req, res, 'content-length'),
|
|
106
|
-
'-',
|
|
107
|
-
tokens['response-time'](req, res),
|
|
108
|
-
'ms',
|
|
109
|
-
].join(' ')
|
|
110
|
-
|
|
111
|
-
if (process.env.NODE_ENV !== 'dev') {
|
|
112
|
-
// Log only in AWS context to get back function logs
|
|
113
|
-
console.log(log)
|
|
114
|
-
}
|
|
115
|
-
return log
|
|
116
|
-
}
|