[
  {
    "path": ".babelrc",
    "content": "{\n  \"presets\": [\n    \"react\",\n    \"env\",\n    \"es2015\"\n  ],\n  \"plugins\": [\n    \"react-hot-loader/babel\",\n    \"transform-object-rest-spread\",\n    \"transform-class-properties\"\n  ]\n}\n"
  },
  {
    "path": ".eslintrc",
    "content": "{\n  \"plugins\": [\n    \"prettier\"\n  ],\n  \"rules\": {\n    \"prettier/prettier\": \"error\"\n  },\n  \"extends\": [\n      \"prettier\"\n  ]\n}\n"
  },
  {
    "path": ".gitignore",
    "content": ".env\n.DS_Store\nassets/\nnode_modules/\ndump.rdb\nmain.js\ndb.sqlite3\n"
  },
  {
    "path": ".nvmrc",
    "content": "8.1.0\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# How to contribute\n\nThis project is deprecated. Contributions will not be accepted.\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2017 Shopify Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# This project is deprecated\n\nThis project is deprecated and not supported by Shopify.\n\nThis project contains **out-of-date dependencies** with **known security vulnerabilities** and **should not be used in a production environment**.\n\nIf you are looking for information about building a Shopify app with Node.js, please see our [Build a Shopify App with Node.js and React](https://developers.shopify.com/tutorials/build-a-shopify-app-with-node-and-react) tutorial.\n"
  },
  {
    "path": "bin/www.js",
    "content": "#!/usr/bin/env node\nrequire('dotenv').config();\nconst chalk = require('chalk');\nconst http = require('http');\nconst app = require('../server');\n\nconst port = process.env.SHOPIFY_APP_PORT || '3000';\napp.set('port', port);\n\nconst server = http.createServer(app);\n\nserver.listen(port, err => {\n  if (err) {\n    return console.log('😫', chalk.red(err));\n  }\n  console.log(`🚀 Now listening on port ${chalk.green(port)}`);\n});\n"
  },
  {
    "path": "client/App.js",
    "content": "import React, { Component } from 'react';\nimport { Page, AppProvider } from '@shopify/polaris';\n\nimport ApiConsole from './components/ApiConsole'\n\nclass App extends Component {\n  render() {\n    const { apiKey, shopOrigin } = window;\n\n    return (\n      <AppProvider shopOrigin={shopOrigin} apiKey={apiKey}>\n        <Page\n          title=\"My application\"\n          breadcrumbs={[{ content: 'Home', url: '/foo' }]}\n          primaryAction={{ content: 'Add something' }}\n        >\n          <ApiConsole />\n        </Page>\n      </AppProvider>\n    );\n  }\n}\n\nexport default App;\n"
  },
  {
    "path": "client/actions/index.js",
    "content": "export function updateVerb(verb) {\n  return {\n    type: 'UPDATE_VERB',\n    payload: {\n      verb,\n    },\n  };\n}\n\nexport function updatePath(path) {\n  return {\n    type: 'UPDATE_PATH',\n    payload: {\n      path,\n    },\n  };\n}\n\nexport function updateParams(params) {\n  return {\n    type: 'UPDATE_PARAMS',\n    payload: {\n      params,\n    },\n  };\n}\n\nexport function sendRequest(requestFields) {\n  const { verb, path, params } = requestFields;\n\n  const fetchOptions = {\n    method: verb,\n    headers: {\n      'Accept': 'application/json',\n      'Content-Type': 'application/json'\n    },\n    credentials: 'include',\n  }\n\n  if (verb !== 'GET') {\n    fetchOptions['body'] = params\n  }\n\n  return dispatch => {\n    dispatch(requestStartAction());\n\n    return fetch(`/shopify/api${path}`, fetchOptions)\n      .then(response => response.json())\n      .then(json => dispatch(requestCompleteAction(json)))\n      .catch(error => {\n        dispatch(requestErrorAction(error));\n      });\n  };\n}\n\nfunction requestStartAction() {\n  return {\n    type: 'REQUEST_START',\n    payload: {},\n  };\n}\n\nfunction requestCompleteAction(json) {\n  const responseBody = JSON.stringify(json, null, 2);\n\n  return {\n    type: 'REQUEST_COMPLETE',\n    payload: {\n      responseBody\n    },\n  };\n}\n\nfunction requestErrorAction(requestError) {\n  return {\n    type: 'REQUEST_ERROR',\n    payload: {\n      requestError,\n    },\n  };\n}\n"
  },
  {
    "path": "client/components/ApiConsole.js",
    "content": "import React, { Component} from 'react';\nimport { connect } from 'react-redux';\n\nimport { Layout, Stack, Card, TextField, Button } from '@shopify/polaris';\nimport ObjectInspector from 'react-object-inspector';\nimport { updatePath, updateParams, sendRequest } from '../actions';\n\nimport VerbPicker from './VerbPicker';\n\nclass ApiConsole extends Component {\n  render() {\n    return (\n      <Layout sectioned>\n        { this.renderForm() }\n        { this.renderResponse() }\n      </Layout>\n    )\n  }\n\n  renderForm() {\n    const { dispatch, requestFields } = this.props;\n\n    return (\n      <div>\n        <Layout.Section>\n          <Stack>\n            <VerbPicker verb={requestFields.verb} />\n            <TextField\n              value={requestFields.path}\n              onChange={path => dispatch(updatePath(path))}\n            />\n            <Button primary onClick={() => dispatch(sendRequest(requestFields))}>\n              Send\n            </Button>\n          </Stack>\n        </Layout.Section>\n\n        {this.renderParams()}\n      </div>\n    )\n  }\n\n  renderParams() {\n    const { dispatch, requestFields } = this.props;\n\n    if (requestFields.verb === 'GET') {\n      return null;\n    } else {\n      return (\n        <Layout.Section>\n          <TextField\n            label=\"Request Params\"\n            value={requestFields.params}\n            onChange={params => dispatch(updateParams(params))}\n            multiline={12}\n          />\n        </Layout.Section>\n      );\n    }\n  }\n\n  renderResponse() {\n    const { requestInProgress, requestError, responseBody } = this.props;\n\n    if (responseBody === '') {\n      return null;\n    }\n\n    if (requestInProgress) {\n      return (\n        <Layout.Section>\n          'requesting...';\n        </Layout.Section>\n      )\n    }\n\n    const data = JSON.parse(responseBody)\n\n    return (\n      <Layout.Section>\n        <Card>\n          <div style={{margin: '15px 15px'}}>\n            <ObjectInspector data={data} initialExpandedPaths={['root', 'root.*']}/>\n          </div>\n        </Card>\n      </Layout.Section>\n    )\n  }\n}\n\nfunction mapStateToProps({\n  requestFields,\n  requestInProgress,\n  requestError,\n  responseBody,\n}) {\n  return {\n    requestFields,\n    requestInProgress,\n    requestError,\n    responseBody,\n  };\n}\n\nexport default connect(mapStateToProps)(ApiConsole);\n"
  },
  {
    "path": "client/components/VerbPicker.js",
    "content": "import React, { Component} from 'react';\nimport { connect } from 'react-redux';\nimport { Popover, ActionList, Button } from '@shopify/polaris';\nimport { updateVerb } from '../actions';\n\n\nclass VerbPicker extends Component {\n  constructor(props) {\n    super(props)\n    this.state = {\n      opened: false\n    }\n  }\n\n  toggleOpened() {\n    this.setState({ opened: !this.state.opened })\n  }\n\n  close() {\n    this.setState({ opened: false })\n  }\n\n  onAction(verb) {\n    this.props.dispatch(updateVerb(verb))\n    this.close()\n  }\n\n  render() {\n    const button = (\n      <Button onClick={() => this.toggleOpened()}>\n        {this.props.verb}\n      </Button>\n    )\n\n    return (\n      <Popover active={this.state.opened} activator={button} onClose={() => this.close()}>\n        <ActionList\n          items={['GET', 'POST', 'PUT', 'DELETE'].map(verb => {\n            return { content: verb, onAction: () => this.onAction(verb) }\n          })}\n        />\n      </Popover>\n    )\n  }\n}\n\nexport default connect()(VerbPicker);\n"
  },
  {
    "path": "client/index.js",
    "content": "import * as React from 'react';\nimport 'isomorphic-fetch';\nimport { render } from 'react-dom';\nimport { Provider } from 'react-redux';\nimport { AppContainer } from 'react-hot-loader';\nimport store from '../client/store';\nimport App from './App';\n\nfunction renderApp() {\n  render(\n    <AppContainer>\n      <Provider store={store}>\n        <App />\n      </Provider>\n    </AppContainer>,\n    document.getElementById('root')\n  );\n}\n\nrenderApp();\n\nif (module.hot) {\n  module.hot.accept();\n}\n"
  },
  {
    "path": "client/store/index.js",
    "content": "import { createStore, applyMiddleware } from 'redux';\nimport thunkMiddleware from 'redux-thunk';\nimport logger from 'redux-logger';\n\nconst requestFields = {\n  verb: 'POST',\n  path: '/products.json',\n  params: JSON.stringify({\n    product: {\n      title: \"Burton Custom Freestyle 151\",\n      body_html: \"<strong>Good snowboard!<\\/strong>\",\n      vendor: \"Burton\",\n      product_type: \"Snowboard\"\n    }\n  }, null, 2)\n};\n\nconst initState = {\n  requestFields,\n  requestInProgress: false,\n  requestError: null,\n  responseBody: '',\n};\n\nfunction reducer(state = initState, action) {\n  switch (action.type) {\n    case 'UPDATE_VERB':\n      return {\n        ...state,\n        responseBody: '',\n        requestFields: {\n          ...state.requestFields,\n          verb: action.payload.verb,\n        },\n      };\n    case 'UPDATE_PATH':\n      return {\n        ...state,\n        responseBody: '',\n        requestFields: {\n          ...state.requestFields,\n          path: action.payload.path,\n        },\n      };\n    case 'UPDATE_PARAMS':\n      return {\n        ...state,\n        responseBody: '',\n        requestFields: {\n          ...state.requestFields,\n          params: action.payload.params,\n        },\n      };\n    case 'REQUEST_START':\n      return {\n        ...state,\n        requestInProgress: true,\n        requestError: null,\n        responseBody: ''\n      };\n    case 'REQUEST_COMPLETE':\n      return {\n        ...state,\n        requestInProgress: false,\n        requestError: null,\n        responseBody: action.payload.responseBody\n      };\n    case 'REQUEST_ERROR':\n      return {\n        ...state,\n        requestInProgress: false,\n        requestError: action.payload.requestError,\n      };\n    default:\n      return state;\n  }\n}\n\nconst middleware = applyMiddleware(thunkMiddleware, logger);\n\nconst store = createStore(reducer, middleware);\n\nexport default store;\n"
  },
  {
    "path": "config/webpack.config.js",
    "content": "const path = require('path');\nconst webpack = require('webpack');\nconst autoprefixer = require('autoprefixer');\n\nconst isDevelopment = process.env.NODE_ENV !== 'production';\n\nconst sourceMap = isDevelopment;\nconst plugins = isDevelopment\n  ? [\n      new webpack.DefinePlugin({\n        'process.env.NODE_ENV': JSON.stringify('development'),\n      }),\n      new webpack.HotModuleReplacementPlugin(),\n    ]\n  : [\n      new webpack.DefinePlugin({\n        'process.env.NODE_ENV': JSON.stringify('production'),\n      }),\n      new webpack.optimize.DedupePlugin(),\n      new webpack.optimize.UglifyJsPlugin({\n        compressor: {\n          warnings: false,\n        },\n        minimize: true,\n      }),\n    ];\n\nconst extraEntryFiles = isDevelopment\n  ? ['react-hot-loader/patch', 'webpack-hot-middleware/client']\n  : [];\n\nmodule.exports = {\n  plugins,\n  target: 'web',\n  devtool: 'eval',\n  entry: {\n    main: [\n      ...extraEntryFiles,\n      '@shopify/polaris/styles.css',\n      path.resolve(__dirname, '../client/index.js'),\n    ],\n  },\n  output: {\n    filename: '[name].js',\n    path: path.resolve(__dirname, '../assets'),\n    publicPath: '/assets/',\n    libraryTarget: 'var',\n  },\n  module: {\n    loaders: [\n      {\n        test: /\\.jsx?$/,\n        loader: 'babel-loader',\n        exclude: /node_modules/,\n      },\n      {\n        test: /\\.css$/,\n        exclude: /node_modules/,\n        loaders: [\n          {\n            loader: 'style-loader',\n          },\n          {\n            loader: 'css-loader',\n            query: {\n              sourceMap,\n              modules: true,\n              importLoaders: 1,\n              localIdentName: '[name]-[local]_[hash:base64:5]',\n            },\n          },\n          {\n            loader: 'postcss-loader',\n            options: {\n              plugins: () => autoprefixer(),\n              sourceMap,\n            },\n          },\n        ],\n      },\n      {\n        test: /\\.css$/,\n        include: path.resolve(__dirname, '../node_modules/@shopify/polaris'),\n        loaders: [\n          {\n            loader: 'style-loader',\n          },\n          {\n            loader: 'css-loader',\n            query: {\n              sourceMap,\n              modules: true,\n              importLoaders: 1,\n              localIdentName: '[local]',\n            },\n          },\n        ],\n      },\n    ],\n  },\n};\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"shopify-node-app\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"prod\": \"yarn run clean && yarn run build && cross-env NODE_ENV=production yarn run start\",\n    \"dev\": \"cross-env NODE_ENV=development yarn run start\",\n    \"start\": \"nodemon ./bin/www\",\n    \"build\": \"cross-env NODE_ENV=production webpack --config ./config/webpack.config.js --progress --profile --colors\",\n    \"clean\": \"rm -rf ./assets && mkdir ./assets\",\n    \"pretty\": \"prettier --single-quote --trailing-comma es5 --write {client,bin,config,server}{/*,/**/*}.js\",\n    \"precommit\": \"yarn run pretty\"\n  },\n  \"engines\": {\n    \"node\": \">= 8.1.0\"\n  },\n  \"browsers\": [\n    \"last 3 chrome versions\",\n    \"last 3 firefox versions\",\n    \"last 2 versions\",\n    \"safari >= 8\",\n    \"ios >= 8\",\n    \"ie >= 11\",\n    \"explorermobile >= 11\",\n    \"android >= 4.4\"\n  ],\n  \"dependencies\": {\n    \"@shopify/polaris\": \"^2.3.1\",\n    \"@shopify/shopify-express\": \"^1.0.0-alpha.7\",\n    \"chalk\": \"^1.1.3\",\n    \"connect-redis\": \"^3.3.0\",\n    \"cross-env\": \"^5.1.3\",\n    \"debug\": \"~2.6.3\",\n    \"dotenv\": \"^4.0.0\",\n    \"ejs\": \"~2.5.6\",\n    \"express\": \"~4.15.2\",\n    \"express-session\": \"^1.15.3\",\n    \"knex\": \"^0.13.0\",\n    \"morgan\": \"~1.8.1\",\n    \"react\": \"^16.4.0\",\n    \"react-dom\": \"^16.4.0\",\n    \"nodemon\": \"^1.17.1\",\n    \"react-object-inspector\": \"^0.2.1\",\n    \"react-redux\": \"^5.0.5\",\n    \"redis\": \"^2.7.1\",\n    \"redux\": \"^3.6.0\",\n    \"redux-logger\": \"^3.0.6\",\n    \"redux-thunk\": \"^2.2.0\",\n    \"shopify-api-node\": \"^2.11.0\",\n    \"sqlite3\": \"^3.1.9\",\n    \"url\": \"^0.11.0\",\n    \"webpack-hot-middleware\": \"^2.18.0\",\n    \"webpack-middleware\": \"^1.5.1\"\n  },\n  \"devDependencies\": {\n    \"autoprefixer\": \"^7.1.1\",\n    \"babel-core\": \"^6.25.0\",\n    \"babel-loader\": \"^7.0.0\",\n    \"babel-plugin-transform-object-rest-spread\": \"^6.23.0\",\n    \"babel-plugin-transform-class-properties\": \"^6.24.1\",\n    \"babel-preset-env\": \"^1.5.2\",\n    \"babel-preset-es2015\": \"^6.24.1\",\n    \"babel-preset-react\": \"^6.24.1\",\n    \"css-loader\": \"^0.28.4\",\n    \"eslint\": \"3.19.0\",\n    \"eslint-plugin-prettier\": \"^2.1.2\",\n    \"global\": \"^4.3.2\",\n    \"postcss-loader\": \"^2.0.6\",\n    \"prettier\": \"^1.5.2\",\n    \"react-hot-loader\": \"^3.0.0-beta.7\",\n    \"style-loader\": \"^0.18.2\",\n    \"webpack\": \"^2.6.1\",\n    \"webpack-dev-server\": \"^2.4.5\"\n  }\n}\n"
  },
  {
    "path": "server/index.js",
    "content": "require('isomorphic-fetch');\nrequire('dotenv').config();\n\nconst fs = require('fs');\nconst express = require('express');\nconst session = require('express-session');\nconst RedisStore = require('connect-redis')(session);\nconst path = require('path');\nconst logger = require('morgan');\n\nconst webpack = require('webpack');\nconst webpackMiddleware = require('webpack-dev-middleware');\nconst webpackHotMiddleware = require('webpack-hot-middleware');\nconst config = require('../config/webpack.config.js');\n\nconst ShopifyAPIClient = require('shopify-api-node');\nconst ShopifyExpress = require('@shopify/shopify-express');\nconst {MemoryStrategy} = require('@shopify/shopify-express/strategies');\n\nconst {\n  SHOPIFY_APP_KEY,\n  SHOPIFY_APP_HOST,\n  SHOPIFY_APP_SECRET,\n  NODE_ENV,\n} = process.env;\n\nconst shopifyConfig = {\n  host: SHOPIFY_APP_HOST,\n  apiKey: SHOPIFY_APP_KEY,\n  secret: SHOPIFY_APP_SECRET,\n  scope: ['write_orders, write_products'],\n  shopStore: new MemoryStrategy(),\n  afterAuth(request, response) {\n    const { session: { accessToken, shop } } = request;\n\n    registerWebhook(shop, accessToken, {\n      topic: 'orders/create',\n      address: `${SHOPIFY_APP_HOST}/order-create`,\n      format: 'json'\n    });\n\n    return response.redirect('/');\n  },\n};\n\nconst registerWebhook = function(shopDomain, accessToken, webhook) {\n  const shopify = new ShopifyAPIClient({ shopName: shopDomain, accessToken: accessToken });\n  shopify.webhook.create(webhook).then(\n    response => console.log(`webhook '${webhook.topic}' created`),\n    err => console.log(`Error creating webhook '${webhook.topic}'. ${JSON.stringify(err.response.body)}`)\n  );\n}\n\nconst app = express();\nconst isDevelopment = NODE_ENV !== 'production';\n\napp.set('views', path.join(__dirname, 'views'));\napp.set('view engine', 'ejs');\napp.use(logger('dev'));\napp.use(\n  session({\n    store: isDevelopment ? undefined : new RedisStore(),\n    secret: SHOPIFY_APP_SECRET,\n    resave: true,\n    saveUninitialized: false,\n  })\n);\n\n// Run webpack hot reloading in dev\nif (isDevelopment) {\n  const compiler = webpack(config);\n  const middleware = webpackMiddleware(compiler, {\n    hot: true,\n    inline: true,\n    publicPath: config.output.publicPath,\n    contentBase: 'src',\n    stats: {\n      colors: true,\n      hash: false,\n      timings: true,\n      chunks: false,\n      chunkModules: false,\n      modules: false,\n    },\n  });\n\n  app.use(middleware);\n  app.use(webpackHotMiddleware(compiler));\n} else {\n  const staticPath = path.resolve(__dirname, '../assets');\n  app.use('/assets', express.static(staticPath));\n}\n\n// Install\napp.get('/install', (req, res) => res.render('install'));\n\n// Create shopify middlewares and router\nconst shopify = ShopifyExpress(shopifyConfig);\n\n// Mount Shopify Routes\nconst {routes, middleware} = shopify;\nconst {withShop, withWebhook} = middleware;\n\napp.use('/shopify', routes);\n\n// Client\napp.get('/', withShop({authBaseUrl: '/shopify'}), function(request, response) {\n  const { session: { shop, accessToken } } = request;\n  response.render('app', {\n    title: 'Shopify Node App',\n    apiKey: shopifyConfig.apiKey,\n    shop: shop,\n  });\n});\n\napp.post('/order-create', withWebhook((error, request) => {\n  if (error) {\n    console.error(error);\n    return;\n  }\n\n  console.log('We got a webhook!');\n  console.log('Details: ', request.webhook);\n  console.log('Body:', request.body);\n}));\n\n// Error Handlers\napp.use(function(req, res, next) {\n  const err = new Error('Not Found');\n  err.status = 404;\n  next(err);\n});\n\napp.use(function(error, request, response, next) {\n  response.locals.message = error.message;\n  response.locals.error = request.app.get('env') === 'development' ? error : {};\n\n  response.status(error.status || 500);\n  response.render('error');\n});\n\nmodule.exports = app;\n"
  },
  {
    "path": "server/views/app.ejs",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <title><%= title %></title>\n  </head>\n  <body>\n    <script src=\"https://cdn.shopify.com/s/assets/external/app.js\"></script>\n\n    <script>\n      window.apiKey = \"<%= apiKey %>\"\n      window.shopOrigin = \"https://<%= shop %>\"\n\n      const shopifyAppConfig = {\n        apiKey: window.apiKey,\n        shopOrigin: window.shopOrigin,\n      }\n\n      // This will allow you to access the app outside of the Shopify\n      // parent iframe in development mode. Doing this will give you\n      // access to React and Redux dev tools, but will also disrupt\n      // postmessages to the parent and block EASDK calls\n      // https://help.shopify.com/api/sdks/shopify-apps/embedded-app-sdk/methods#shopifyapp-init-config\n      if (\"<%= process.env.NODE_ENV %>\" === 'development') {\n        shopifyAppConfig.forceRedirect = false;\n      }\n\n      ShopifyApp.init(shopifyAppConfig);\n    </script>\n\n    <div id=\"root\"></div>\n    <script src=\"/assets/main.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "server/views/error.ejs",
    "content": "<h1><%= message %></h1>\n<h2><%= error.status %></h2>\n<pre><%= error.stack %></pre>\n"
  },
  {
    "path": "server/views/install.ejs",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Shopify Node App</title>\n    <style>\n      html, body { padding: 0; margin: 0; }\n      body {\n        font-family: \"ProximaNovaLight\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n        background-color: #f2f7fa;\n      }\n      h1 {\n        font-weight: 300;\n        font-size: 40px;\n        margin-bottom: 10px;\n      }\n      .subhead {\n        font-size: 17px;\n        line-height: 32px;\n        font-weight: 300;\n        color: #969A9C;\n      }\n      input {\n        width: 300px;\n        height: 50px;\n        padding: 10px;\n        border: 1px solid #479CCf;\n        color: #575757;\n        background-color: #ffffff;\n        box-sizing: border-box;\n        border-radius: 4px 0 0 4px;\n        font-size: 18px;\n        float: left;\n      }\n      button {\n        color: #ffffff;\n        background-color: #3793cb;\n        width: 100px;\n        height: 50px;\n        padding: 10px 20px 10px 20px;\n        box-sizing: border-box;\n        border: none;\n        text-shadow: 0 1px 0 #3188bc;\n        font-size: 18px;\n        cursor: pointer;\n        border-radius: 0 4px 4px 0;\n        float: right;\n      }\n      button:hover {\n        background-color: #479CCf;\n      }\n      form {\n        display: block;\n      }\n      .container {\n        text-align: center;\n        margin-top: 100px;\n        padding: 20px;\n      }\n      .container__form {\n        width: 400px;\n        margin: auto;\n      }\n    </style>\n  </head>\n  <body>\n    <div class=\"container\">\n      <header>\n        <h1>Shopify Node App – Installation</h1>\n        <p class=\"subhead\">\n          <label for=\"shop\">Enter your shop domain to log in or install this app.</label>\n        </p>\n      </header>\n\n      <div class=\"container__form\">\n        <form method=\"GET\" action=\"/shopify/auth\">\n          <input type=\"text\" name=\"shop\" id=\"shop\" placeholder=\"example.myshopify.com\"/>\n          <button type=\"submit\">Install</button>\n        </form>\n      </div>\n    </div>\n  </body>\n</html>\n"
  }
]