Skip to content
This repository was archived by the owner on Feb 3, 2022. It is now read-only.

Commit dcae828

Browse files
committed
Adds somee more involved examples for the base function that is created.
1 parent e8c7c0b commit dcae828

File tree

11 files changed

+229
-28
lines changed

11 files changed

+229
-28
lines changed

src/create-twilio-function.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const { promptForAccountDetails } = require('./create-twilio-function/prompt');
22
const {
33
createDirectory,
44
createEnvFile,
5-
createExampleFunction,
5+
createExampleFromTemplates,
66
createPackageJSON,
77
createNvmrcFile
88
} = require('./create-twilio-function/create-files');
@@ -52,14 +52,14 @@ async function createTwilioFunction(config) {
5252
// Scaffold project
5353
const spinner = ora();
5454
spinner.start('Creating project directories and files');
55-
await createDirectory(projectDir, 'functions');
56-
await createDirectory(projectDir, 'assets');
55+
// await createDirectory(projectDir, 'functions');
56+
// await createDirectory(projectDir, 'assets');
5757
await createEnvFile(projectDir, {
5858
accountSid: config.accountSid,
5959
authToken: config.authToken
6060
});
6161
await createNvmrcFile(projectDir);
62-
await createExampleFunction(`${projectDir}/functions`);
62+
await createExampleFromTemplates(projectDir);
6363
await createPackageJSON(projectDir, config.name);
6464
spinner.succeed();
6565

src/create-twilio-function/create-files.js

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ const { promisify } = require('util');
44
const mkdir = promisify(fs.mkdir);
55
const open = promisify(fs.open);
66
const write = promisify(fs.write);
7+
const readdir = promisify(fs.readdir);
8+
const copyFile = promisify(fs.copyFile);
79

810
function createDirectory(path, dirName) {
911
return mkdir(path + '/' + dirName);
@@ -37,14 +39,22 @@ function createPackageJSON(path, name) {
3739
return createFile(fullPath, packageJSON);
3840
}
3941

40-
function createExampleFunction(path) {
41-
const content = `exports.handler = function(context, event, callback) {
42-
const twiml = new Twilio.twiml.VoiceResponse();
43-
twiml.say("Hello World!");
44-
callback(null, twiml);
45-
};`;
46-
const fullPath = `${path}/example.js`;
47-
return createFile(fullPath, content);
42+
function createExampleFromTemplates(path) {
43+
return readdir('./templates').then(dirs =>
44+
Promise.all(
45+
dirs.map(dir =>
46+
mkdir(`${path}/${dir}`)
47+
.then(() => readdir(`./templates/${dir}`))
48+
.then(files =>
49+
Promise.all(
50+
files.map(file =>
51+
copyFile(`./templates/${dir}/${file}`, `${path}/${dir}/${file}`)
52+
)
53+
)
54+
)
55+
)
56+
)
57+
);
4858
}
4959

5060
function createEnvFile(path, { accountSid, authToken }) {
@@ -63,7 +73,7 @@ function createNvmrcFile(path) {
6373
module.exports = {
6474
createDirectory,
6575
createPackageJSON,
66-
createExampleFunction,
76+
createExampleFromTemplates,
6777
createEnvFile,
6878
createNvmrcFile
6979
};

src/create-twilio-function/success-message.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ async function successMessage(config) {
1010
Inside that directory, you can run the following command:
1111
1212
{blue ${packageManager} start}
13-
Serves all functions in the ./functions subdirectory
13+
Serves all functions in the ./functions subdirectory and assets in the ./assets directory
1414
1515
Get started by running:
1616

templates/assets/index.html

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
7+
<link rel="stylesheet" href="./style.css" />
8+
<title>Hello Twilio Serverless!</title>
9+
</head>
10+
<body>
11+
<header><h1>Hello Twilio Serverless!</h1></header>
12+
13+
<main>
14+
<p>
15+
<strong>Congratulations</strong> you just started a new Twilio
16+
Serverless project.
17+
</p>
18+
19+
<h2>Assets</h2>
20+
<p>
21+
Assets are static files, like HTML, CSS, JavaScript, images or audio
22+
files.
23+
</p>
24+
25+
<p>
26+
This HTML page is an example of a <strong>public</strong> asset, you can
27+
access this by loading it in the browser. The HTML also refers to
28+
another public asset for CSS styles.
29+
</p>
30+
<p>
31+
You can also have <strong>private</strong> assets, there is an example
32+
private asset called <code>message.private.js</code> in the
33+
<code>/assets</code> directory. This file cannot be loaded in the
34+
browser, but you can load it as part of a function by finding its path
35+
using <code>Runtime.getAssets()</code> and then requiring the file.
36+
There is an example of this in
37+
<code>/functions/private-message.protected.js</code>.
38+
</p>
39+
40+
<h2>Functions</h2>
41+
<p>
42+
Functions are JavaScript files that will respond to incoming HTTP
43+
requests. There are <strong>public</strong> and
44+
<strong>protected</strong> functions.
45+
</p>
46+
47+
<p>
48+
<strong>Public</strong> functions respond to all HTTP requests. There is
49+
an example of a public function in
50+
<code>/functions/hello-world.js</code>.
51+
</p>
52+
53+
<p>
54+
<strong>Protected</strong> functions will only respond to HTTP requests
55+
with a valid Twilio signature in the header. You can read more about
56+
<a href="https://www.twilio.com/docs/usage/security#validating-requests"
57+
>validating requests from Twilio in the documentation</a
58+
>. There is an example of a protected function in
59+
<code>/functions/private-message.protected.js</code>
60+
</p>
61+
62+
<h2>twilio-run</h2>
63+
64+
<p>
65+
Functions and assets are served, deployed and debugged using
66+
<a href="https://github.com/twilio-labs/twilio-run"
67+
><code>twilio-run</code></a
68+
>. You can serve the project locally with the command
69+
<code>npm start</code> which is really running
70+
<code>twilio-run --env</code> under the hood. If you want to see what
71+
else you can do with <code>twilio-run</code> enter
72+
<code>npx twilio-run --help</code> on the command line or check out
73+
<a href="https://github.com/twilio-labs/twilio-run"
74+
>the project documentation on GitHub</a
75+
>.
76+
</p>
77+
</main>
78+
79+
<footer>
80+
<p>
81+
Made with 💖 by your friends at
82+
<a href="https://www.twilio.com">Twilio</a>
83+
</p>
84+
</footer>
85+
</body>
86+
</html>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
const privateMessage = () => {
2+
return 'This is private!';
3+
};
4+
5+
module.exports = privateMessage;

templates/assets/style.css

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
* {
2+
margin: 0;
3+
padding: 0;
4+
box-sizing: border-box;
5+
}
6+
7+
::selection {
8+
background: #f22f46;
9+
color: white;
10+
}
11+
12+
body {
13+
font-family: -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI', Roboto,
14+
'Helvetica Neue', Arial, sans-serif;
15+
color: #0d122b;
16+
border-top: 5px solid #f22f46;
17+
}
18+
19+
header {
20+
padding: 2em;
21+
margin-bottom: 2em;
22+
max-width: 800px;
23+
margin: 0 auto;
24+
}
25+
26+
header h1 {
27+
padding-bottom: 14px;
28+
border-bottom: 1px solid rgba(148, 151, 155, 0.2);
29+
}
30+
31+
a {
32+
color: #008cff;
33+
}
34+
35+
main {
36+
margin: 0 auto 6em;
37+
padding: 0 2em;
38+
max-width: 800px;
39+
}
40+
41+
main p {
42+
margin-bottom: 2em;
43+
}
44+
45+
main p code {
46+
font-size: 16px;
47+
font-family: 'Fira Mono', monospace;
48+
color: #f22f46;
49+
background-color: #f9f9f9;
50+
box-shadow: inset 0 0 0 1px #e8e8e8;
51+
font-size: inherit;
52+
line-height: 1.2;
53+
padding: 0.15em 0.4em;
54+
border-radius: 4px;
55+
display: inline-block;
56+
white-space: pre-wrap;
57+
}
58+
59+
main h2 {
60+
margin-bottom: 1em;
61+
}
62+
63+
footer {
64+
margin: 0 auto;
65+
max-width: 800px;
66+
text-align: center;
67+
}
68+
69+
footer p {
70+
border-top: 1px solid rgba(148, 151, 155, 0.2);
71+
padding-top: 2em;
72+
margin: 0 2em;
73+
}

templates/functions/assets.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
exports.handler = function(context, event, callback) {
2+
callback(null, Runtime.getAssets());
3+
};

templates/functions/hello-world.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
exports.handler = function(context, event, callback) {
2+
const twiml = new Twilio.twiml.VoiceResponse();
3+
twiml.say('Hello World!');
4+
callback(null, twiml);
5+
};
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
exports.handler = function(context, event, callback) {
2+
const assets = Runtime.getAssets();
3+
const privateMessageAsset = assets['/message.js'];
4+
const privateMessagePath = privateMessageAsset.path;
5+
const privateMessage = require(privateMessagePath);
6+
const twiml = new Twilio.twiml.MessagingResponse();
7+
twiml.message(privateMessage());
8+
callback(null, twiml);
9+
};

tests/create-files.test.js

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const {
22
createPackageJSON,
33
createDirectory,
4-
createExampleFunction,
4+
createExampleFromTemplates,
55
createEnvFile,
66
createNvmrcFile
77
} = require('../src/create-twilio-function/create-files');
@@ -12,6 +12,7 @@ const rimraf = promisify(require('rimraf'));
1212
const mkdir = promisify(fs.mkdir);
1313
const readFile = promisify(fs.readFile);
1414
const stat = promisify(fs.stat);
15+
const readdir = promisify(fs.readdir);
1516

1617
beforeAll(async () => {
1718
await rimraf('./scratch');
@@ -67,22 +68,28 @@ describe('createPackageJSON', () => {
6768
});
6869
});
6970

70-
describe('createExampleFunction', () => {
71-
test('it creates a new example function', async () => {
72-
await createExampleFunction('./scratch');
73-
const file = await stat('./scratch/example.js');
74-
expect(file.isFile());
75-
const contents = await readFile('./scratch/example.js', {
76-
encoding: 'utf-8'
77-
});
78-
expect(contents).toMatch('Twilio.twiml.VoiceResponse');
71+
describe('createExampleFromTemplates', () => {
72+
test('it creates functions and assets directories', async () => {
73+
await createExampleFromTemplates('./scratch');
74+
75+
const dirs = await readdir('./scratch');
76+
const templateDirs = await readdir('./templates');
77+
expect(dirs).toEqual(templateDirs);
78+
});
79+
80+
test('it copies the functions from the templates/functions directory', async () => {
81+
await createExampleFromTemplates('./scratch');
82+
83+
const functions = await readdir('./scratch/functions');
84+
const templateFunctions = await readdir('./templates/functions');
85+
expect(functions).toEqual(templateFunctions);
7986
});
8087

81-
test('it rejects if there is already an example function', async () => {
82-
fs.closeSync(fs.openSync('./scratch/example.js', 'w'));
88+
test('it rejects if there is already a functions directory', async () => {
89+
await mkdir('./scratch/functions');
8390
expect.assertions(1);
8491
try {
85-
await createExampleFunction('./scratch');
92+
await createExampleFromTemplates('./scratch');
8693
} catch (e) {
8794
expect(e.toString()).toMatch('file already exists');
8895
}

0 commit comments

Comments
 (0)