Merge All Repositories into Monorepo for easier maintenance (#629)

* All projects into monorepo

* Update CI

* More CI updates

* Extracted a bunch of things into packages

* Publish

 - insomnia-plugin-base64@1.0.1
 - insomnia-plugin-default-headers@1.0.2
 - insomnia-plugin-file@1.0.1
 - insomnia-plugin-hash@1.0.1
 - insomnia-plugin-now@1.0.1
 - insomnia-plugin-request@1.0.1
 - insomnia-plugin-response@1.0.1
 - insomnia-plugin-uuid@1.0.1
 - insomnia-cookies@0.0.2
 - insomnia-importers@1.5.2
 - insomnia-prettify@0.0.3
 - insomnia-url@0.0.2
 - insomnia-xpath@0.0.2

* A bunch of small fixes

* Improved build script

* Fixed

* Merge dangling files

* Usability refactor

* Handle duplicate plugin names
This commit is contained in:
Gregory Schier authored and GitHub committed 2017-11-26 20:45:40 +00:00
1 parent c79d7fdd77
commit 549ce23ce8
957 files changed
+44840 -19355

No files matched your search

+3 -3
View File
@@ -20,7 +20,7 @@ install:
- npm --version
- npm config set msvs_version 2013
- npm install 7zip-bin-win > NUL
- npm install > NUL
- npm run bootstrap
- npm test
cache:
@@ -32,14 +32,14 @@ cache:
#---------------------------------#
build_script:
- if %APPVEYOR_REPO_TAG%==true npm run build-n-package
- if %APPVEYOR_REPO_TAG%==true npm run package-app
#---------------------------------#
# artifacts configuration #
#---------------------------------#
artifacts:
- path: dist\squirrel-windows\*
- path: packages\insomnia-app\dist\squirrel-windows\*
name: dist
#---------------------------------#
+14 -19
View File
@@ -1,27 +1,22 @@
node_modules
.idea
.vscode
dist/*
build/*
.DS_Store
coverage
# Generated
app/main.min.js
app/node_modules
# Logs
logs
*.log
npm-debug.log*
# Runtime data
yarn-debug.log*
yarn-error.log*
pids
*.pid
*.seed
# Optional npm cache directory
*.pid.lock
lib-cov
coverage
.lock-wscript
build/Release
node_modules/
.npm
# Optional REPL history
.eslintcache
.node_repl_history
*.tgz
.yarn-integrity
.env
.idea
.DS_Store
+8 -10
View File
@@ -35,16 +35,14 @@ cache:
- $HOME/.electron
- $HOME/.cache
install:
- npm install > /dev/null
script:
- node --version
- npm --version
script:
- npm run bootstrap
- npm test
before_deploy:
- npm run build-n-package
- npm run package-app
deploy:
provider: releases
@@ -53,10 +51,10 @@ deploy:
file_glob: true
prerelease: true
file:
- dist/**/*.zip
- dist/**/*.dmg
- dist/**/*.deb
- dist/**/*.AppImage
- dist/**/*.tar.gz
- packages/insomnia-app/dist/**/*.zip
- packages/insomnia-app/dist/**/*.dmg
- packages/insomnia-app/dist/**/*.deb
- packages/insomnia-app/dist/**/*.AppImage
- packages/insomnia-app/dist/**/*.tar.gz
on:
tags: true
+11 -13
View File
@@ -2,8 +2,6 @@
[![Insomnia](https://img.shields.io/badge/maintainer-Insomnia-purple.svg?colorB=6e60cc)](https://insomnia.rest)
[![Travis](https://api.travis-ci.org/getinsomnia/insomnia.svg)](https://travis-ci.org/getinsomnia/insomnia)
[![AppVeyor](https://img.shields.io/appveyor/ci/gschier/insomnia.svg)](https://ci.appveyor.com/project/gschier/insomnia)
[![license](https://img.shields.io/github/license/getinsomnia/insomnia.svg)](LICENSE)
[![Slack Channel](https://chat.insomnia.rest/badge.svg)](https://chat.insomnia.rest/)
[![Twitter Follow](https://img.shields.io/twitter/follow/getinsomnia.svg?style=social&label=%40GetInsomnia%20on%20Twitter&style=plastic)](https://twitter.com/getinsomnia)
@@ -43,16 +41,20 @@ Development on Insomnia can be done on Mac, Windows, or Linux as long as you hav
<details>
<summary>Initial Dev Setup</summary>
This repository is structured as a monorepo and contains many Node.JS packages. Each package has
it's own set of command, but the most common commands are available from the
root `[package.json](package.json)` adn can be accessed using the `npm run ...` command. Here
are the only three commands you should need to start developing on the app.
```bash
# Install dependencies and build add-ons for Electron
npm install
npm run rebuild
# Install and Link Dependencies
npm run bootstrap
# Start app
npm run dev
# Run tests
# Run Tests
npm test
# Start App with Live Reload
npm run start-app
```
</details>
@@ -83,7 +85,3 @@ Here is a list of plugins available for installation via NPM.
[Swaggymnia](https://github.com/mlabouardy/swaggymnia) – Generate [Swagger](https://swagger.io/) documentation for your existing API in Insomnia.
## License
[GNU AGPLv3](LICENSE) &copy; [Insomnia](https://insomnia.rest)
-146
View File
@@ -1,146 +0,0 @@
import {CookieJar} from 'tough-cookie';
import * as cookieUtils from '../cookies';
import {globalBeforeEach} from '../../__jest__/before-each';
describe('jarFromCookies()', () => {
beforeEach(globalBeforeEach);
it('returns valid cookies', done => {
const jar = cookieUtils.jarFromCookies([{
key: 'foo',
value: 'bar',
domain: 'google.com'
}]);
jar.store.getAllCookies((err, cookies) => {
expect(err).toBeNull();
expect(cookies[0].domain).toEqual('google.com');
expect(cookies[0].key).toEqual('foo');
expect(cookies[0].value).toEqual('bar');
expect(cookies[0].creation instanceof Date).toEqual(true);
expect(cookies[0].expires).toEqual('Infinity');
done();
});
});
it('handles malformed JSON', () => {
const jar = cookieUtils.jarFromCookies('not a jar');
expect(jar.constructor.name).toBe('CookieJar');
});
});
describe('cookiesFromJar()', () => {
beforeEach(globalBeforeEach);
it('returns valid jar', async () => {
const d = new Date();
const initialCookies = [{
key: 'bar',
value: 'baz',
domain: 'insomnia.rest',
expires: d
}, {
// This one will fail to parse, and be skipped
bad: 'cookie'
}];
const jar = CookieJar.fromJSON({cookies: initialCookies});
const cookies = await cookieUtils.cookiesFromJar(jar);
expect(cookies[0].domain).toBe('insomnia.rest');
expect(cookies[0].key).toBe('bar');
expect(cookies[0].value).toBe('baz');
expect(cookies[0].creation).toMatch(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/);
expect(cookies[0].expires).toEqual(d.toISOString());
});
it('handles bad jar', async () => {
const jar = CookieJar.fromJSON({cookies: []});
// MemoryStore never actually throws errors, so lets mock the
// function to force it to this time.
jar.store.getAllCookies = cb => cb(new Error('Dummy Error'));
const cookies = await cookieUtils.cookiesFromJar(jar);
// Cookies failed to p
expect(cookies.length).toBe(0);
});
});
describe('cookieHeaderValueForUri()', () => {
beforeEach(globalBeforeEach);
it('gets cookies for valid case', async () => {
const jar = cookieUtils.jarFromCookies([{
key: 'foo',
value: 'bar',
path: '/',
domain: 'google.com'
}, {
key: 'foo',
value: 'inner',
path: '/inner',
domain: 'google.com'
}]);
expect(await cookieUtils.cookieHeaderValueForUri(jar, 'https://google.com/foo/bar'))
.toBe('foo=bar');
expect(await cookieUtils.cookieHeaderValueForUri(jar, 'https://insomnia.rest/'))
.toBe('');
expect(await cookieUtils.cookieHeaderValueForUri(jar, 'https://google.com/inner'))
.toBe('foo=inner; foo=bar');
});
it('handles errors properly', async () => {
const jar = cookieUtils.jarFromCookies([]);
jar.getCookies = (uri, cb) => cb(new Error('Dummy error'));
expect(
await cookieUtils.cookieHeaderValueForUri(jar, 'https://google.com')
).toBe('');
});
describe('cookieToString()', () => {
beforeEach(globalBeforeEach);
it('does its thing', async () => {
const jar = cookieUtils.jarFromCookies([{
key: 'foo',
value: 'bar',
path: '/',
domain: 'google.com'
}, {
key: 'foo1',
value: 'bar',
path: '/',
domain: 'google.com',
hostOnly: true
}, {
key: 'foo2',
value: 'bar',
path: '/',
domain: 'google.com',
hostOnly: false
}, {
key: 'foo3',
value: 'bar',
path: '/somepath'
}]);
const cookies = await cookieUtils.cookiesFromJar(jar);
expect(cookies.length).toBe(4);
expect(cookieUtils.cookieToString(cookies[0]))
.toBe('foo=bar; Domain=google.com; Path=/');
expect(cookieUtils.cookieToString(cookies[1]))
.toBe('foo1=bar; Path=/; Domain=google.com');
expect(cookieUtils.cookieToString(cookies[2]))
.toBe('foo2=bar; Domain=google.com; Path=/');
expect(cookieUtils.cookieToString(cookies[3]))
.toBe('foo3=bar; Path=/somepath');
});
});
});
-234
View File
@@ -1,234 +0,0 @@
import * as misc from '../misc';
import {globalBeforeEach} from '../../__jest__/before-each';
describe('getBasicAuthHeader()', () => {
beforeEach(globalBeforeEach);
it('succeed with username and password', () => {
const header = misc.getBasicAuthHeader('user', 'password');
expect(header).toEqual({
name: 'Authorization',
value: 'Basic dXNlcjpwYXNzd29yZA=='
});
});
it('succeed with no username', () => {
const header = misc.getBasicAuthHeader(null, 'password');
expect(header).toEqual({
name: 'Authorization',
value: 'Basic OnBhc3N3b3Jk'
});
});
it('succeed with username and empty password', () => {
const header = misc.getBasicAuthHeader('user', '');
expect(header).toEqual({
name: 'Authorization',
value: 'Basic dXNlcjo='
});
});
it('succeed with username and null password', () => {
const header = misc.getBasicAuthHeader('user', null);
expect(header).toEqual({
name: 'Authorization',
value: 'Basic dXNlcjo='
});
});
});
describe('hasAuthHeader()', () => {
beforeEach(globalBeforeEach);
it('finds valid header', () => {
const yes = misc.hasAuthHeader([
{name: 'foo', value: 'bar'},
{name: 'authorization', value: 'foo'}
]);
expect(yes).toEqual(true);
});
it('finds valid header case insensitive', () => {
const yes = misc.hasAuthHeader([
{name: 'foo', value: 'bar'},
{name: 'AuthOrizAtiOn', value: 'foo'}
]);
expect(yes).toEqual(true);
});
});
describe('generateId()', () => {
beforeEach(globalBeforeEach);
it('generates a valid ID', () => {
const id = misc.generateId('foo');
expect(id).toMatch(/^foo_[a-z0-9]{32}$/);
});
it('generates without prefix', () => {
const id = misc.generateId();
expect(id).toMatch(/^[a-z0-9]{32}$/);
});
});
describe('setDefaultProtocol()', () => {
beforeEach(globalBeforeEach);
it('no-ops on empty url', () => {
const url = misc.setDefaultProtocol('');
expect(url).toBe('');
});
it('correctly sets protocol for empty', () => {
const url = misc.setDefaultProtocol('google.com');
expect(url).toBe('http://google.com');
});
it('does not set for valid url', () => {
const url = misc.setDefaultProtocol('https://google.com');
expect(url).toBe('https://google.com');
});
it('does not set for valid url', () => {
const url = misc.setDefaultProtocol('http://google.com');
expect(url).toBe('http://google.com');
});
it('does not set for invalid url', () => {
const url = misc.setDefaultProtocol('httbad://google.com');
expect(url).toBe('httbad://google.com');
});
});
describe('prepareUrlForSending()', () => {
beforeEach(globalBeforeEach);
it('does not touch normal url', () => {
const url = misc.prepareUrlForSending('http://google.com');
expect(url).toBe('http://google.com/');
});
it('works with no protocol', () => {
const url = misc.prepareUrlForSending('google.com');
expect(url).toBe('http://google.com/');
});
it('encodes pathname', () => {
const url = misc.prepareUrlForSending('https://google.com/foo bar/100%/foo');
expect(url).toBe('https://google.com/foo%20bar/100%25/foo');
});
it('encodes pathname mixed encoding', () => {
const url = misc.prepareUrlForSending('https://google.com/foo bar baz%20qux/100%/foo%25');
expect(url).toBe('https://google.com/foo%20bar%20baz%20qux/100%25/foo%25');
});
it('leaves already encoded pathname', () => {
const url = misc.prepareUrlForSending('https://google.com/foo%20bar%20baz/100%25/foo');
expect(url).toBe('https://google.com/foo%20bar%20baz/100%25/foo');
});
it('encodes querystring', () => {
const url = misc.prepareUrlForSending('https://google.com?s=foo bar 100%&hi');
expect(url).toBe('https://google.com/?s=foo%20bar%20100%25&hi');
});
it('encodes querystring with mixed spaces', () => {
const url = misc.prepareUrlForSending('https://google.com?s=foo %20100%');
expect(url).toBe('https://google.com/?s=foo%20%20100%25');
});
it('encodes querystring with repeated keys', () => {
const url = misc.prepareUrlForSending('https://google.com/;@,!?s=foo,;@-!&s=foo %20100%');
expect(url).toBe('https://google.com/;@,!?s=foo,%3B%40-!&s=foo%20%20100%25');
});
it('doesn\'t decode ignored characters', () => {
// Encoded should skip raw versions of @ ; ,
const url = misc.prepareUrlForSending('https://google.com/@;,&^+');
expect(url).toBe('https://google.com/@;,%26%5E+');
// Encoded should skip encoded versions of @ ; ,
const url2 = misc.prepareUrlForSending('https://google.com/%40%3B%2C%26%5E');
expect(url2).toBe('https://google.com/%40%3B%2C%26%5E');
});
it('leaves already encoded characters alone', () => {
const url = misc.prepareUrlForSending('https://google.com/%2B%2A%2F>');
expect(url).toBe('https://google.com/%2B%2A%2F%3E');
});
it('doesn\'t encode if last param set', () => {
const url = misc.prepareUrlForSending('https://google.com/%%?foo=%%', false);
expect(url).toBe('https://google.com/%%?foo=%%');
});
});
describe('filterHeaders()', () => {
beforeEach(globalBeforeEach);
it('handles bad headers', () => {
expect(misc.filterHeaders(null, null)).toEqual([]);
expect(misc.filterHeaders([], null)).toEqual([]);
expect(misc.filterHeaders(['bad'], null)).toEqual([]);
expect(misc.filterHeaders(['bad'], 'good')).toEqual([]);
expect(misc.filterHeaders(null, 'good')).toEqual([]);
expect(misc.filterHeaders([{name: 'good', value: 'valid'}], null)).toEqual([]);
expect(misc.filterHeaders([{name: 'good', value: 'valid'}], 'good'))
.toEqual([{name: 'good', value: 'valid'}]);
});
});
describe('keyedDebounce()', () => {
beforeEach(async () => {
await globalBeforeEach();
jest.useFakeTimers();
});
it('debounces correctly', () => {
const resultsList = [];
const fn = misc.keyedDebounce(results => {
resultsList.push(results);
}, 100);
fn('foo', 'bar');
fn('baz', 'bar');
fn('foo', 'bar2');
fn('foo', 'bar3');
fn('multi', 'foo', 'bar', 'baz');
expect(setTimeout.mock.calls.length).toBe(5);
expect(resultsList).toEqual([]);
jest.runAllTimers();
expect(resultsList).toEqual([{
foo: ['bar3'],
baz: ['bar'],
multi: ['foo', 'bar', 'baz']
}]);
});
});
describe('debounce()', () => {
beforeEach(async () => {
await globalBeforeEach();
jest.useFakeTimers();
});
it('debounces correctly', () => {
const resultList = [];
const fn = misc.debounce((...args) => {
resultList.push(args);
}, 100);
fn('foo');
fn('foo');
fn('multi', 'foo', 'bar', 'baz');
fn('baz', 'bar');
fn('foo', 'bar3');
expect(setTimeout.mock.calls.length).toBe(5);
expect(resultList).toEqual([]);
jest.runAllTimers();
expect(resultList).toEqual([['foo', 'bar3']]);
});
});
-176
View File
@@ -1,176 +0,0 @@
import * as querystringUtils from '../querystring';
import {globalBeforeEach} from '../../__jest__/before-each';
describe('getBasicAuthHeader()', () => {
beforeEach(globalBeforeEach);
it('gets joiner for bare URL', () => {
const joiner = querystringUtils.getJoiner('http://google.com');
expect(joiner).toBe('?');
});
it('gets joiner for invalid URL', () => {
const joiner = querystringUtils.getJoiner('hi');
expect(joiner).toBe('?');
});
it('gets joiner for URL with question mark', () => {
const joiner = querystringUtils.getJoiner('http://google.com?');
expect(joiner).toBe('&');
});
it('gets joiner for URL with params', () => {
const joiner = querystringUtils.getJoiner('http://google.com?foo=bar');
expect(joiner).toBe('&');
});
it('gets joiner for URL with hash', () => {
const joiner = querystringUtils.getJoiner('http://google.com?foo=bar#hi');
expect(joiner).toBe('&');
});
it('gets joiner for URL with ampersand', () => {
const joiner = querystringUtils.getJoiner(
'http://google.com?foo=bar&baz=qux'
);
expect(joiner).toBe('&');
});
});
describe('joinUrl()', () => {
beforeEach(globalBeforeEach);
it('joins bare URL', () => {
const url = querystringUtils.joinUrl(
'http://google.com',
'foo=bar'
);
expect(url).toBe('http://google.com?foo=bar');
});
it('joins with hash', () => {
const url = querystringUtils.joinUrl(
'http://google.com#hash',
'foo=bar'
);
expect(url).toBe('http://google.com?foo=bar#hash');
});
it('joins hash and querystring', () => {
const url = querystringUtils.joinUrl(
'http://google.com?baz=qux#hash',
'foo=bar'
);
expect(url).toBe('http://google.com?baz=qux&foo=bar#hash');
});
it('joins multi-hash and querystring', () => {
const url = querystringUtils.joinUrl(
'http://google.com?hi=there&baz=qux#hash#hi#hi',
'foo=bar'
);
expect(url).toBe('http://google.com?hi=there&baz=qux&foo=bar#hash#hi#hi');
});
it('joins URL with querystring', () => {
const url = querystringUtils.joinUrl(
'http://google.com?hi=there',
'foo=bar%20baz'
);
expect(url).toBe('http://google.com?hi=there&foo=bar%20baz');
});
});
describe('build()', () => {
beforeEach(globalBeforeEach);
it('builds simple param', () => {
const str = querystringUtils.build({name: 'foo', value: 'bar??'});
expect(str).toBe('foo=bar%3F%3F');
});
it('builds param without value', () => {
const str = querystringUtils.build({name: 'foo'});
expect(str).toBe('foo');
});
it('builds empty param without name', () => {
const str = querystringUtils.build({value: 'bar'});
expect(str).toBe('');
});
it('builds with numbers', () => {
const str = querystringUtils.build({name: 'number', value: 10});
const str2 = querystringUtils.build({name: 'number', value: 0});
expect(str).toBe('number=10');
expect(str2).toBe('number=0');
});
});
describe('buildFromParams()', () => {
beforeEach(globalBeforeEach);
it('builds from params', () => {
const str = querystringUtils.buildFromParams([
{name: 'foo', value: 'bar??'},
{name: 'hello'},
{name: 'hi there', value: 'bar??'},
{name: '', value: 'bar??'},
{name: '', value: ''}
]);
expect(str).toBe('foo=bar%3F%3F&hello&hi%20there=bar%3F%3F');
});
it('builds from params', () => {
const str = querystringUtils.buildFromParams([
{name: 'foo', value: 'bar??'},
{name: 'hello'},
{name: 'hi there', value: 'bar??'},
{name: '', value: 'bar??'},
{name: '', value: ''}
], false);
expect(str).toBe('foo=bar%3F%3F&hello=&hi%20there=bar%3F%3F&=bar%3F%3F&=');
});
});
describe('deconstructToParams()', () => {
beforeEach(globalBeforeEach);
it('builds from params', () => {
const str = querystringUtils.deconstructToParams(
'foo=bar%3F%3F&hello&hi%20there=bar%3F%3F&=&=val'
);
expect(str).toEqual([
{name: 'foo', value: 'bar??'},
{name: 'hello', value: ''},
{name: 'hi there', value: 'bar??'}
]);
});
it('builds from params with =', () => {
const str = querystringUtils.deconstructToParams(
'foo=bar&1=2=3=4&hi'
);
expect(str).toEqual([
{name: 'foo', value: 'bar'},
{name: '1', value: '2=3=4'},
{name: 'hi', value: ''}
]);
});
});
describe('deconstructToParams()', () => {
beforeEach(globalBeforeEach);
it('builds from params not strict', () => {
const str = querystringUtils.deconstructToParams(
'foo=bar%3F%3F&hello&hi%20there=bar%3F%3F&=&=val',
false
);
expect(str).toEqual([
{name: 'foo', value: 'bar??'},
{name: 'hello', value: ''},
{name: 'hi there', value: 'bar??'},
{name: '', value: ''},
{name: '', value: 'val'}
]);
});
});
-138
View File
@@ -1,138 +0,0 @@
// @flow
import * as util from './misc.js';
type Parameter = Object & {
name: string,
value: string
}
/** Join a URL with a querystring */
export function joinUrl (url: string, qs: string): string {
if (!qs) {
return url;
}
if (!url) {
return qs;
}
const [base, ...hashes] = url.split('#');
// TODO: Make this work with URLs that have a #hash component
const baseUrl = base || '';
const joiner = getJoiner(base);
const hash = hashes.length ? `#${hashes.join('#')}` : '';
return `${baseUrl}${joiner}${qs}${hash}`;
}
export function extractFromUrl (url: string): string {
if (!url) {
return '';
}
// NOTE: This only splits on first ? sign. '1=2=3' --> ['1', '2=3']
const things = url.split('?');
if (things.length === 1) {
return '';
} else {
const qsWithHash = things.slice(1).join('?');
return qsWithHash.replace(/#.*/, '');
}
}
export function getJoiner (url: string): string {
url = url || '';
return url.indexOf('?') === -1 ? '?' : '&';
}
/** Build a querystring param out of a name/value pair */
export function build (param: Parameter, strict: boolean = true): string {
// Skip non-name ones in strict mode
if (strict && !param.name) {
return '';
}
// Cast number values to strings
if (typeof param.value === 'number') {
param.value += '';
}
if (!strict || param.value) {
// Don't encode ',' in values
const value = util.flexibleEncodeComponent(param.value || '').replace(/%2C/gi, ',');
const name = util.flexibleEncodeComponent(param.name || '');
return `${name}=${value}`;
} else {
return util.flexibleEncodeComponent(param.name);
}
}
/**
* Build a querystring from a list of name/value pairs
* @param parameters
* @param strict allow empty names and values
*/
export function buildFromParams (
parameters: Array<Parameter>,
strict: boolean = true
): string {
let items = [];
for (const param of parameters) {
let built = build(param, strict);
if (!built) {
continue;
}
items.push(built);
}
return items.join('&');
}
/**
* Deconstruct a querystring to name/value pairs
* @param qs
* @param strict allow empty names and values
*/
export function deconstructToParams (qs: ?string, strict: boolean = true): Array<Parameter> {
const pairs: Array<Parameter> = [];
if (!qs) {
return pairs;
}
const stringPairs = qs.split('&');
for (let stringPair of stringPairs) {
// NOTE: This only splits on first equals sign. '1=2=3' --> ['1', '2=3']
const [encodedName, ...encodedValues] = stringPair.split('=');
const encodedValue = encodedValues.join('=');
let name = '';
try {
name = decodeURIComponent(encodedName || '');
} catch (e) {
// Just leave it
name = encodedName;
}
let value = '';
try {
value = decodeURIComponent(encodedValue || '');
} catch (e) {
// Just leave it
value = encodedValue;
}
if (strict && !name) {
continue;
}
pairs.push({name, value});
}
return pairs;
}
-2454
View File
File diff suppressed because it is too large. Load diff
-39
View File
@@ -1,39 +0,0 @@
{
"private": true,
"name": "insomnia",
"version": "5.12.0-beta.3",
"productName": "Insomnia",
"longName": "Insomnia REST Client",
"description": "Debug APIs like a human, not a robot",
"homepage": "https://insomnia.rest",
"author": "Insomnia <support@insomnia.rest>",
"main": "main.min.js",
"dependencies": {
"aws4": "^1.6.0",
"clone": "^2.1.0",
"deep-equal": "^1.0.1",
"electron-context-menu": "^0.9.0",
"electron-squirrel-startup": "^1.0.0",
"hawk": "^6.0.2",
"hkdf": "^0.0.2",
"html-entities": "^1.2.0",
"iconv-lite": "^0.4.15",
"insomnia-httpsnippet": "^1.16.5",
"insomnia-importers": "^1.5.0",
"insomnia-node-libcurl": "^1.2.3",
"jsonpath": "^0.2.12",
"marked": "^0.3.6",
"mime-types": "^2.1.14",
"mkdirp": "^0.5.1",
"moment": "^2.18.1",
"nedb": "^1.8.0",
"node-forge": "^0.7.0",
"oauth-1.0a": "^2.2.2",
"srp-js": "^0.2.0",
"tar": "^3.1.7",
"tough-cookie": "^2.3.1",
"vkbeautify": "^0.99.1",
"whatwg-fetch": "^2.0.1",
"xmldom": "^0.1.22"
}
}
@@ -1,32 +0,0 @@
import * as templating from '../../index';
import {globalBeforeEach} from '../../../__jest__/before-each';
function assertTemplate (txt, expected) {
return async function () {
const result = await templating.render(txt);
expect(result).toMatch(expected);
};
}
function assertTemplateFails (txt, expected) {
return async function () {
try {
await templating.render(txt);
fail(`Render should have thrown ${expected}`);
} catch (err) {
expect(err.message).toBe(expected);
}
};
}
describe('Base64EncodeExtension', () => {
beforeEach(globalBeforeEach);
it('encodes nothing', assertTemplate("{% base64 'encode' %}", ''));
it('encodes something', assertTemplate("{% base64 'encode', 'my string' %}", 'bXkgc3RyaW5n'));
it('decodes nothing', assertTemplate("{% base64 'decode' %}", ''));
it('decodes something', assertTemplate("{% base64 'decode', 'bXkgc3RyaW5n' %}", 'my string'));
it('fails on invalid op', assertTemplateFails(
"{% base64 'foo' %}",
'Unsupported operation "foo". Must be encode or decode.'
));
});
@@ -1,32 +0,0 @@
import path from 'path';
import * as templating from '../../index';
import {globalBeforeEach} from '../../../__jest__/before-each';
function assertTemplate (txt, context, expected) {
return async function () {
const result = await templating.render(txt, {context});
expect(result).toBe(expected);
};
}
function assertTemplateFails (txt, context, expected) {
return async function () {
try {
await templating.render(txt, {context});
fail(`Render should have thrown ${expected}`);
} catch (err) {
expect(err.message).toContain(expected);
}
};
}
describe('FileExtension', () => {
beforeEach(globalBeforeEach);
const ctx = {path: path.resolve(__dirname, path.join('./test.txt'))};
const escapedPath = ctx.path.replace(/\\/g, '\\\\');
it('reads from string', assertTemplate(`{% file "${escapedPath}" %}`, ctx, 'Hello World!'));
it('reads a file correctly', assertTemplate('{% file path %}', ctx, 'Hello World!'));
it('fails on missing file', assertTemplateFails('{% file "/foo" %}', ctx, `ENOENT: no such file or directory, open '${path.resolve('/foo')}'`));
it('fails on no 2nd param', assertTemplateFails('{% file %}', ctx, 'No file selected'));
it('fails on unknown variable', assertTemplateFails('{% file foo %}', ctx, 'No file selected'));
});
@@ -1,36 +0,0 @@
import * as templating from '../../index';
import {globalBeforeEach} from '../../../__jest__/before-each';
function assertTemplate (txt, expected) {
return async function () {
const result = await templating.render(txt);
expect(result).toMatch(expected);
};
}
function assertTemplateFails (txt, expected) {
return async function () {
try {
await templating.render(txt);
fail(`Render should have thrown ${expected}`);
} catch (err) {
expect(err.message).toBe(expected);
}
};
}
const isoRe = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/;
const secondsRe = /^\d{10}$/;
const millisRe = /^\d{13}$/;
describe('NowExtension', () => {
beforeEach(globalBeforeEach);
it('renders default ISO', assertTemplate('{% now %}', isoRe));
it('renders ISO-8601', assertTemplate('{% now "ISO-8601" %}', isoRe));
it('renders seconds', assertTemplate('{% now "seconds" %}', secondsRe));
it('renders s', assertTemplate('{% now "s" %}', secondsRe));
it('renders unix', assertTemplate('{% now "unix" %}', secondsRe));
it('renders millis', assertTemplate('{% now "millis" %}', millisRe));
it('renders ms', assertTemplate('{% now "ms" %}', millisRe));
it('fails on other', assertTemplateFails('{% now "foo" %}', 'Invalid date type "foo"'));
});
@@ -1,85 +0,0 @@
import * as templating from '../../index';
import * as models from '../../../models';
import {cookiesFromJar, jarFromCookies} from '../../../common/cookies';
import {getRenderContext} from '../../../common/render';
import {globalBeforeEach} from '../../../__jest__/before-each';
describe('RequestExtension cookie', async () => {
beforeEach(globalBeforeEach);
it('should get cookie by name', async () => {
// Create necessary models
const workspace = await models.workspace.create({name: 'Workspace'});
const request = await models.request.create({
parentId: workspace._id,
url: 'https://insomnia.rest/foo/bar'
});
const cookieJar = await models.cookieJar.getOrCreateForParentId(workspace._id);
const jar = jarFromCookies(cookieJar.cookies);
jar.setCookieSync([
'foo=bar',
'path=/',
'domain=.insomnia.rest',
'HttpOnly Cache-Control: public, no-cache'
].join('; '), request.url);
const cookies = await cookiesFromJar(jar);
await models.cookieJar.update(cookieJar, {cookies});
const context = await getRenderContext(request);
const result = await templating.render(`{% request 'cookie', 'foo' %}`, {context});
expect(result).toBe('bar');
});
});
describe('RequestExtension url', async () => {
beforeEach(globalBeforeEach);
it('should get url', async () => {
// Create necessary models
const workspace = await models.workspace.create({name: 'Workspace'});
const request = await models.request.create({
parentId: workspace._id,
url: 'https://insomnia.rest/foo/bar',
parameters: [{name: 'foo', value: 'bar'}]
});
const context = await getRenderContext(request);
const result = await templating.render(`{% request 'url' %}`, {context});
expect(result).toBe('https://insomnia.rest/foo/bar?foo=bar');
});
it('should get rendered url', async () => {
// Create necessary models
const workspace = await models.workspace.create({name: 'Workspace'});
const request = await models.request.create({
parentId: workspace._id,
url: 'https://insomnia.rest/foo/bar',
parameters: [{name: 'foo', value: '{{ foo }}'}]
});
const context = await getRenderContext(request);
context.foo = 'Hello World!';
const result = await templating.render(`{% request 'url' %}`, {context});
expect(result).toBe('https://insomnia.rest/foo/bar?foo=Hello%20World!');
});
});
describe('RequestExtension header', async () => {
beforeEach(globalBeforeEach);
it('should get url', async () => {
// Create necessary models
const workspace = await models.workspace.create({name: 'Workspace'});
const request = await models.request.create({
parentId: workspace._id,
url: 'https://insomnia.rest/foo/bar',
headers: [{name: 'foo', value: '{{ foo }}'}]
});
const context = await getRenderContext(request);
context.foo = 'Hello World!';
const result = await templating.render(`{% request 'header', 'foo' %}`, {context});
expect(result).toBe('Hello World!');
});
});
@@ -1,273 +0,0 @@
import * as templating from '../../index';
import * as models from '../../../models';
import {globalBeforeEach} from '../../../__jest__/before-each';
describe('ResponseExtension General', async () => {
beforeEach(globalBeforeEach);
it('fails on no responses', async () => {
const request = await models.request.create({parentId: 'foo'});
try {
await templating.render(`{% response "body", "${request._id}", "$.foo" %}`);
fail('JSON should have failed to parse');
} catch (err) {
expect(err.message).toContain('No responses for request');
}
});
it('fails on no request', async () => {
await models.response.create({parentId: 'req_test'}, '{"foo": "bar"}');
try {
await templating.render(`{% response "body", "req_test", "$.foo" %}`);
fail('JSON should have failed to parse');
} catch (err) {
expect(err.message).toContain('Could not find request req_test');
}
});
it('fails on empty filter', async () => {
const request = await models.request.create({parentId: 'foo'});
await models.response.create({parentId: request._id, statusCode: 200}, '{"foo": "bar"}');
try {
await templating.render(`{% response "body", "${request._id}", "" %}`);
fail('Should have failed');
} catch (err) {
expect(err.message).toContain('No body filter specified');
}
});
});
describe('ResponseExtension JSONPath', async () => {
beforeEach(globalBeforeEach);
it('renders basic response "body", query', async () => {
const request = await models.request.create({parentId: 'foo'});
await models.response.create({
parentId: request._id,
body: '{"foo": "bar"}',
statusCode: 200
});
const result = await templating.render(`{% response "body", "${request._id}", "$.foo" %}`);
expect(result).toBe('bar');
});
it('fails on invalid JSON', async () => {
const request = await models.request.create({parentId: 'foo'});
await models.response.create({
parentId: request._id,
body: '{"foo": "bar"',
statusCode: 200
});
try {
await templating.render(`{% response "body", "${request._id}", "$.foo" %}`);
fail('JSON should have failed to parse');
} catch (err) {
expect(err.message).toContain('Invalid JSON: Unexpected end of JSON input');
}
});
it('fails on invalid query', async () => {
const request = await models.request.create({parentId: 'foo'});
await models.response.create({
parentId: request._id,
body: '{"foo": "bar"}',
statusCode: 200
});
try {
await templating.render(`{% response "body", "${request._id}", "$$" %}`);
fail('JSON should have failed to parse');
} catch (err) {
expect(err.message).toContain('Invalid JSONPath query: $$');
}
});
it('fails on no results', async () => {
const request = await models.request.create({parentId: 'foo'});
await models.response.create({
parentId: request._id,
body: '{"foo": "bar"}',
statusCode: 200
});
try {
await templating.render(`{% response "body", "${request._id}", "$.missing" %}`);
fail('JSON should have failed to parse');
} catch (err) {
expect(err.message).toContain('Returned no results: $.missing');
}
});
it('fails on more than 1 result', async () => {
const request = await models.request.create({parentId: 'foo'});
await models.response.create({
parentId: request._id,
body: '{"array": [1,2,3]}',
statusCode: 200
});
try {
await templating.render(`{% response "body", "${request._id}", "$.array.*" %}`);
fail('JSON should have failed to parse');
} catch (err) {
expect(err.message).toContain('Returned more than one result: $.array.*');
}
});
});
describe('ResponseExtension XPath', async () => {
beforeEach(globalBeforeEach);
it('renders basic response "body" query', async () => {
const request = await models.request.create({parentId: 'foo'});
await models.response.create({
parentId: request._id,
body: '<foo><bar>Hello World!</bar></foo>',
statusCode: 200
});
const result = await templating.render(`{% response "body", "${request._id}", "/foo/bar" %}`);
expect(result).toBe('Hello World!');
});
it('renders basic response "body" attribute query', async () => {
const request = await models.request.create({parentId: 'foo'});
await models.response.create({
parentId: request._id,
body: '<foo><bar hello="World!">Hello World!</bar></foo>',
statusCode: 200
});
const result = await templating.render(`{% response "body", "${request._id}", "/foo/bar/@hello" %}`);
expect(result).toBe('World!');
});
it('no results on invalid XML', async () => {
const request = await models.request.create({parentId: 'foo'});
await models.response.create({
parentId: request._id,
body: '<hi></hi></sstr>',
statusCode: 200
});
try {
await templating.render(`{% response "body", "${request._id}", "/foo" %}`);
fail('should have failed');
} catch (err) {
expect(err.message).toContain('Returned no results: /foo');
}
});
it('fails on invalid query', async () => {
const request = await models.request.create({parentId: 'foo'});
await models.response.create({
parentId: request._id,
body: '<foo><bar>Hello World!</bar></foo>',
statusCode: 200
});
try {
await templating.render(`{% response "body", "${request._id}", "//" %}`);
fail('should have failed');
} catch (err) {
expect(err.message).toContain('Invalid XPath query: //');
}
});
it('fails on no results', async () => {
const request = await models.request.create({parentId: 'foo'});
await models.response.create({
parentId: request._id,
body: '<foo><bar>Hello World!</bar></foo>',
statusCode: 200
});
try {
await templating.render(`{% response "body", "${request._id}", "/missing" %}`);
fail('should have failed');
} catch (err) {
expect(err.message).toContain('Returned no results: /missing');
}
});
it('fails on more than 1 result', async () => {
const request = await models.request.create({parentId: 'foo'});
await models.response.create({
parentId: request._id,
body: '<foo><bar>Hello World!</bar><bar>And again!</bar></foo>',
statusCode: 200
});
try {
await templating.render(`{% response "body", "${request._id}", "/foo/*" %}`);
fail('should have failed');
} catch (err) {
expect(err.message).toContain('Returned more than one result: /foo/*');
}
});
});
describe('ResponseExtension Header', async () => {
beforeEach(globalBeforeEach);
it('renders basic response "header"', async () => {
const request = await models.request.create({parentId: 'foo'});
await models.response.create({
parentId: request._id,
statusCode: 200,
headers: [
{name: 'Content-Type', value: 'application/json'},
{name: 'Content-Length', value: '20'}
]
});
const id = request._id;
expect(await templating.render(`{% response "header", "${id}", "content-type" %}`))
.toBe('application/json');
expect(await templating.render(`{% response "header", "${id}", "Content-Type" %}`))
.toBe('application/json');
expect(await templating.render(`{% response "header", "${id}", "CONTENT-type" %}`))
.toBe('application/json');
expect(await templating.render(`{% response "header", "${id}", " CONTENT-type " %}`))
.toBe('application/json');
});
it('no results on missing header', async () => {
const request = await models.request.create({parentId: 'foo'});
await models.response.create({
parentId: request._id,
statusCode: 200,
headers: [
{name: 'Content-Type', value: 'application/json'},
{name: 'Content-Length', value: '20'}
]
});
try {
await templating.render(`{% response "header", "${request._id}", "dne" %}`);
fail('should have failed');
} catch (err) {
expect(err.message).toBe('No header with name "dne".\nChoices are [\n\t"Content-Type",\n\t"Content-Length"\n]');
}
});
});
describe('ResponseExtension Raw', async () => {
beforeEach(globalBeforeEach);
it('renders basic response "header"', async () => {
const request = await models.request.create({parentId: 'foo'});
await models.response.create({
parentId: request._id,
body: 'Hello World!',
statusCode: 200
});
const result = await templating.render(`{% response "raw", "${request._id}", "" %}`);
expect(result).toBe('Hello World!');
});
});
@@ -1,16 +0,0 @@
import * as templating from '../../index';
import {globalBeforeEach} from '../../../__jest__/before-each';
function assertTemplate (txt, expected) {
return async function () {
const result = await templating.render(txt);
expect(result).toMatch(expected);
};
}
const millisRe = /^\d{13}$/;
describe('TimestampExtension', () => {
beforeEach(globalBeforeEach);
it('renders basic', assertTemplate('{% timestamp %}', millisRe));
});
@@ -1,32 +0,0 @@
import * as templating from '../../index';
import {globalBeforeEach} from '../../../__jest__/before-each';
function assertTemplate (txt, expected) {
return async function () {
const result = await templating.render(txt);
expect(result).toMatch(expected);
};
}
function assertTemplateFails (txt, expected) {
return async function () {
try {
await templating.render(txt);
fail(`Render should have thrown ${expected}`);
} catch (err) {
expect(err.message).toBe(expected);
}
};
}
describe('UuidExtension', () => {
beforeEach(globalBeforeEach);
it('renders default v4', assertTemplate('{% uuid %}', 'dd2ccc1a-2745-477a-881a-9e8ef9d42403'));
it('renders 4', assertTemplate('{% uuid "4" %}', 'e3e96e5f-dd68-4229-8b66-dee1f0940f3d'));
it('renders 4 num', assertTemplate('{% uuid 4 %}', 'a262d22b-5fa8-491c-9bd9-58fba03e301e'));
it('renders v4', assertTemplate('{% uuid "v4" %}', '2e7c2688-09ee-44b8-900d-5cbbaa7d3a19'));
it('renders 1', assertTemplate('{% uuid "1" %}', 'f7272c80-f493-11e6-bc64-92361f002671'));
it('renders 1 num', assertTemplate('{% uuid 1 %}', 'f7272f0a-f493-11e6-bc64-92361f002671'));
it('renders v1', assertTemplate('{% uuid "v1" %}', 'f72733a6-f493-11e6-bc64-92361f002671'));
it('fails on other', assertTemplateFails('{% uuid "foo" %}', 'Invalid UUID type "foo"'));
});
@@ -1,9 +0,0 @@
export default {
deprecated: true,
name: 'timestamp',
displayName: 'Timestamp',
description: 'generate timestamp in milliseconds',
run (context) {
return Date.now();
}
};
+17
View File
@@ -0,0 +1,17 @@
{
"lerna": "2.5.1",
"version": "independent",
"packages": [
"plugins/*",
"packages/*",
"website"
],
"commands": {
"publish": {
"ignore": [
"insomnia-app",
"insomnia-website"
]
}
}
}
+9
View File
@@ -0,0 +1,9 @@
[build]
publish = "website/_speedpack"
command = "npm run build-website"
[context.production.environment]
HUGO_VERSION = "0.30"
[context.deploy-preview.environment]
HUGO_VERSION = "0.30"
+1879 -15097
View File
File diff suppressed because it is too large. Load diff
+14 -150
View File
@@ -1,161 +1,25 @@
{
"name": "insomnia-dev",
"name": "insomnia",
"private": true,
"version": "1.0.0",
"description": "Insomnia App",
"cache": 3,
"main": "main.js",
"licence": "GNU AGPLv3",
"homepage": "https://insomnia.rest",
"repository": {
"type": "git",
"author": "Gregory Schier <gschier1990@gmail.com>",
"repository": "https://github.com/getinsomnia/insomnia",
"bugs": {
"url": "https://github.com/getinsomnia/insomnia"
},
"scripts": {
"test:lint": "eslint \"**/*.js\" \"**/*.html\" \"**/*.json\"",
"test:noisy": "cross-env NODE_ENV=test jest",
"test:coverage": "cross-env NODE_ENV=test jest --coverage --silent && open ./coverage/lcov-report/index.html",
"test:watch": "cross-env NODE_ENV=test jest --silent --watch",
"test:flow": "flow check",
"test": "npm run test:flow && npm run test:lint && cross-env NODE_ENV=test jest --silent --maxWorkers 1",
"start-hot": "npm run build-main && cross-env HOT=1 INSOMNIA_ENV=development electron app",
"build-main": "cross-env NODE_ENV=development webpack --config ./webpack/webpack.config.electron.babel.js",
"hot-server": "webpack-dev-server --config ./webpack/webpack.config.development.babel.js",
"dev": "concurrently --kill-others \"npm run hot-server\" \"npm run start-hot\"",
"rebuild": "electron-rebuild -f -w node-libcurl",
"package": "node ./scripts/package.js",
"build": "node ./scripts/build.js",
"build-n-package": "npm run build && npm run package"
},
"dev": {
"webpack-dev-server-port": 3333
},
"jest": {
"setupFiles": [
"./__jest__/setup.js"
],
"moduleNameMapper": {
"\\.(css|less|png)$": "<rootDir>/__mocks__/dummy.js",
"^worker-loader!": "<rootDir>/__mocks__/dummy.js"
},
"testMatch": [
"**/__tests__/**/*.test.js?(x)"
],
"rootDir": "app",
"verbose": false,
"resetMocks": true,
"resetModules": true,
"collectCoverage": false,
"collectCoverageFrom": [
"**/*.js",
"!**/*.min.js",
"!**/main.development.js",
"!**/static/**",
"!**/ui/components/**",
"!**/__fixtures__/**",
"!**/__tests__/**",
"!**/__jest__/**",
"!**/__mocks__/**",
"!**/node_modules/**"
]
},
"dependencies": {
"autobind-decorator": "^1.3.4",
"aws4": "^1.6.0",
"classnames": "^2.2.5",
"clone": "^2.1.0",
"codemirror": "^5.24.2",
"codemirror-graphql": "^0.6.11",
"deep-equal": "^1.0.1",
"electron-context-menu": "^0.9.0",
"electron-squirrel-startup": "^1.0.0",
"graphql": "^0.10.5",
"hawk": "^6.0.2",
"highlight.js": "^9.12.0",
"hkdf": "^0.0.2",
"html-entities": "^1.2.0",
"iconv-lite": "^0.4.15",
"insomnia-httpsnippet": "^1.16.5",
"insomnia-importers": "^1.5.0",
"insomnia-node-libcurl": "^1.2.3",
"jsonlint": "^1.6.2",
"jsonpath": "^0.2.12",
"jwt-authentication": "^0.3.3",
"marked": "^0.3.6",
"mime-types": "^2.1.14",
"mkdirp": "^0.5.1",
"moment": "^2.18.1",
"multiparty": "^4.1.3",
"nedb": "^1.8.0",
"node-forge": "^0.7.0",
"nunjucks": "^3.0.0",
"oauth-1.0a": "^2.2.2",
"pdfjs-dist": "^1.9.640",
"prop-types": "^15.5.10",
"react": "^16.0.0",
"react-dnd": "^2.4.0",
"react-dnd-html5-backend": "^2.4.1",
"react-dom": "^16.0.0",
"react-redux": "^5.0.6",
"react-tabs": "^2.1.1",
"redux": "^3.7.2",
"redux-thunk": "^2.2.0",
"reselect": "^3.0.1",
"srp-js": "^0.2.0",
"tar": "^3.1.7",
"tough-cookie": "^2.3.1",
"uuid": "^3.0.0",
"vkbeautify": "^0.99.1",
"whatwg-fetch": "^2.0.1",
"xmldom": "^0.1.22",
"xpath": "^0.0.23"
"bootstrap": "lerna bootstrap && lerna run rebuild",
"clean": "lerna run clean --stream",
"test": "lerna run test --stream",
"start-app": "lerna run start --stream --scope=insomnia-app",
"start-website": "lerna run start --stream --scope=insomnia-website",
"build-app": "lerna run build --stream --scope=insomnia-app",
"build-website": "lerna run build --stream --scope=insomnia-website",
"package-app": "lerna run package --stream --scope=insomnia-app"
},
"devDependencies": {
"babel-cli": "^6.23.0",
"babel-core": "^6.23.1",
"babel-eslint": "^7.1.1",
"babel-jest": "^19.0.0",
"babel-loader": "^7.1.2",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-plugin-transform-object-rest-spread": "^6.23.0",
"babel-preset-env": "^1.6.0",
"babel-preset-flow": "^6.23.0",
"babel-preset-react": "^6.23.0",
"concurrently": "^3.5.0",
"cross-env": "^2.0.0",
"css-loader": "^0.28.7",
"electron": "^1.7.9",
"electron-builder": "^19.45.5",
"electron-builder-lib": "^19.46.3",
"electron-builder-squirrel-windows": "^19.46.0",
"electron-rebuild": "^1.6.0",
"eslint": "^3.16.1",
"eslint-config-semistandard": "^11.0.0",
"eslint-config-standard": "^10.2.1",
"eslint-plugin-filenames": "^1.1.0",
"eslint-plugin-flowtype": "^2.36.0",
"eslint-plugin-html": "^2.0.1",
"eslint-plugin-import": "^2.8.0",
"eslint-plugin-jest": "^19.0.1",
"eslint-plugin-json": "^1.2.0",
"eslint-plugin-node": "^5.2.1",
"eslint-plugin-promise": "^3.5.0",
"eslint-plugin-react": "^7.4.0",
"eslint-plugin-standard": "^3.0.1",
"file-loader": "^1.1.5",
"flow-bin": "^0.58.0",
"flow-bin": "^0.59.0",
"jest": "^21.2.1",
"less": "^2.7.2",
"less-loader": "^4.0.5",
"ncp": "^2.0.0",
"npm": "^5.5.1",
"react-hot-loader": "^3.1.3",
"redux-mock-store": "^1.0.2",
"rimraf": "^2.6.2",
"style-loader": "^0.19.0",
"url-loader": "^0.6.2",
"webpack": "^3.5.5",
"webpack-dev-server": "^2.9.4",
"webpack-target-electron-renderer": "^0.4.0"
"lerna": "^2.5.1"
}
}
File renamed without changes.
+59
View File
@@ -0,0 +1,59 @@
{
"appId": "com.insomnia.app",
"publish": false,
"extraResources": [
{
"from": "./bin",
"to": "./bin",
"filter": "yarn-standalone.js"
}
],
"protocols": [
{
"name": "Insomnia",
"role": "Viewer",
"schemes": [
"insomnia"
]
}
],
"fileAssociations": [],
"directories": {
"app": "build",
"output": "dist"
},
"mac": {
"category": "public.app-category.developer-tools",
"target": [
"dmg",
"zip"
]
},
"win": {
"target": [
"squirrel",
"zip"
]
},
"linux": {
"executableName": "insomnia",
"synopsis": "A simple, beautiful, and free REST API client",
"category": "Development",
"target": [
"AppImage",
"deb",
"tar.gz"
]
},
"deb": {
"depends": [
"gconf2",
"gconf-service",
"libnotify4",
"libappindicator1",
"libxtst6",
"libnss3",
"libcurl3"
]
}
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
+6
View File
@@ -0,0 +1,6 @@
dist
build
# Generated
app/main.min.js
+1
View File
@@ -0,0 +1 @@
8
File renamed without changes.
+3
View File
@@ -0,0 +1,3 @@
# Insomnia App
The main desktop application.
@@ -17,6 +17,7 @@ const localStorageMock = (function () {
})();
// Don't console log during testing. It's annoying
global.__DEV__ = false;
global.console.log = () => null;
global.localStorage = localStorageMock;
global.requestAnimationFrame = cb => process.nextTick(cb);
File renamed without changes.
File renamed without changes.
@@ -1,14 +1,12 @@
import * as appPackage from '../package.json';
import * as globalPackage from '../../package.json';
import {globalBeforeEach} from '../__jest__/before-each';
describe('package.json', () => {
beforeEach(globalBeforeEach);
it('all app dependencies should be same in global', () => {
for (const name of Object.keys(appPackage.dependencies)) {
const expected = globalPackage.dependencies[name];
const actual = appPackage.dependencies[name];
expect(`${name}::${actual}`).toBe(`${name}::${expected}`);
it('all packed dependencies should exist', () => {
for (const name of globalPackage.packedDependencies) {
const version = globalPackage.dependencies[name];
expect(version).toBeDefined();
}
});
@@ -0,0 +1,108 @@
import * as misc from '../misc';
import {globalBeforeEach} from '../../__jest__/before-each';
describe('hasAuthHeader()', () => {
beforeEach(globalBeforeEach);
it('finds valid header', () => {
const yes = misc.hasAuthHeader([
{name: 'foo', value: 'bar'},
{name: 'authorization', value: 'foo'}
]);
expect(yes).toEqual(true);
});
it('finds valid header case insensitive', () => {
const yes = misc.hasAuthHeader([
{name: 'foo', value: 'bar'},
{name: 'AuthOrizAtiOn', value: 'foo'}
]);
expect(yes).toEqual(true);
});
});
describe('generateId()', () => {
beforeEach(globalBeforeEach);
it('generates a valid ID', () => {
const id = misc.generateId('foo');
expect(id).toMatch(/^foo_[a-z0-9]{32}$/);
});
it('generates without prefix', () => {
const id = misc.generateId();
expect(id).toMatch(/^[a-z0-9]{32}$/);
});
});
describe('filterHeaders()', () => {
beforeEach(globalBeforeEach);
it('handles bad headers', () => {
expect(misc.filterHeaders(null, null)).toEqual([]);
expect(misc.filterHeaders([], null)).toEqual([]);
expect(misc.filterHeaders(['bad'], null)).toEqual([]);
expect(misc.filterHeaders(['bad'], 'good')).toEqual([]);
expect(misc.filterHeaders(null, 'good')).toEqual([]);
expect(misc.filterHeaders([{name: 'good', value: 'valid'}], null)).toEqual([]);
expect(misc.filterHeaders([{name: 'good', value: 'valid'}], 'good'))
.toEqual([{name: 'good', value: 'valid'}]);
});
});
describe('keyedDebounce()', () => {
beforeEach(async () => {
await globalBeforeEach();
jest.useFakeTimers();
});
it('debounces correctly', () => {
const resultsList = [];
const fn = misc.keyedDebounce(results => {
resultsList.push(results);
}, 100);
fn('foo', 'bar');
fn('baz', 'bar');
fn('foo', 'bar2');
fn('foo', 'bar3');
fn('multi', 'foo', 'bar', 'baz');
expect(setTimeout.mock.calls.length).toBe(5);
expect(resultsList).toEqual([]);
jest.runAllTimers();
expect(resultsList).toEqual([{
foo: ['bar3'],
baz: ['bar'],
multi: ['foo', 'bar', 'baz']
}]);
});
});
describe('debounce()', () => {
beforeEach(async () => {
await globalBeforeEach();
jest.useFakeTimers();
});
it('debounces correctly', () => {
const resultList = [];
const fn = misc.debounce((...args) => {
resultList.push(args);
}, 100);
fn('foo');
fn('foo');
fn('multi', 'foo', 'bar', 'baz');
fn('baz', 'bar');
fn('foo', 'bar3');
expect(setTimeout.mock.calls.length).toBe(5);
expect(resultList).toEqual([]);
jest.runAllTimers();
expect(resultList).toEqual([['foo', 'bar3']]);
});
});
@@ -1,11 +1,11 @@
// @flow
import * as models from '../models/index';
import {buildQueryStringFromParams, joinUrlAndQueryString} from 'insomnia-url';
import * as electron from 'electron';
import uuid from 'uuid';
import {GA_ID, GA_LOCATION, getAppPlatform, getAppVersion, isDevelopment} from './constants';
import {getAccountId} from '../sync/session';
import type {RequestParameter} from '../models/request';
import * as querystring from './querystring';
import {getScreenResolution, getUserLanguage, getViewportSize} from './misc';
const DIMENSION_PLATFORM = 1;
@@ -137,11 +137,11 @@ async function _sendToGoogle (params: Array<RequestParameter>) {
const baseParams = await _getDefaultParams();
const allParams = [...baseParams, ...params];
const qs = querystring.buildFromParams(allParams);
const qs = buildQueryStringFromParams(allParams);
const baseUrl = isDevelopment()
? 'https://www.google-analytics.com/debug/collect'
: 'https://www.google-analytics.com/collect';
const url = querystring.joinUrl(baseUrl, qs);
const url = joinUrlAndQueryString(baseUrl, qs);
const net = (electron.remote || electron).net;
const request = net.request(url);
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -4,7 +4,7 @@ import {Cookie as toughCookie} from 'tough-cookie';
import * as models from '../models';
import {getRenderedRequest} from './render';
import type {RenderedRequest} from './render';
import {jarFromCookies} from './cookies';
import {jarFromCookies} from 'insomnia-cookies';
import * as misc from './misc';
import type {Cookie} from '../models/cookie-jar';
import {newBodyRaw} from '../models/request';
@@ -13,6 +13,7 @@ import type {Response as ResponseModel} from '../models/response';
import {getAuthHeader} from '../network/authentication';
import {getAppVersion} from './constants';
import {RenderError} from '../templating/index';
import {smartEncodeUrl} from 'insomnia-url';
export type HarCookie = {
name: string,
@@ -288,7 +289,7 @@ export async function exportHarWithRenderedRequest (
renderedRequest: RenderedRequest,
addContentLength: boolean = false
): Promise<HarRequest> {
const url = misc.prepareUrlForSending(renderedRequest.url, renderedRequest.settingEncodeUrl);
const url = smartEncodeUrl(renderedRequest.url, renderedRequest.settingEncodeUrl);
if (addContentLength) {
const hasContentLengthHeader = misc.filterHeaders(
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -1,14 +1,12 @@
// @flow
import * as electron from 'electron';
import {Readable, Writable} from 'stream';
import {joinUrlAndQueryString} from 'insomnia-url';
import uuid from 'uuid';
import zlib from 'zlib';
import {join as pathJoin} from 'path';
import {format as urlFormat, parse as urlParse} from 'url';
import {DEBOUNCE_MILLIS, getAppVersion, isDevelopment} from './constants';
import * as querystring from './querystring';
const URL_PATH_CHARACTER_WHITELIST = '+,;@=:';
const ESCAPE_REGEX_MATCH = /[-[\]/{}()*+?.\\^$|]/g;
type Header = {
@@ -16,20 +14,6 @@ type Header = {
value: string
};
export function getBasicAuthHeader (username: ?string, password: ?string): Header {
const name = 'Authorization';
const header = `${username || ''}:${password || ''}`;
const authString = Buffer.from(header, 'utf8').toString('base64');
const value = `Basic ${authString}`;
return {name, value};
}
export function getBearerAuthHeader (token: string): Header {
const name = 'Authorization';
const value = `Bearer ${token}`;
return {name, value};
}
export function filterHeaders<T: Header> (headers: Array<T>, name: string): Array<T> {
if (!Array.isArray(headers) || !name) {
return [];
@@ -92,20 +76,6 @@ export function getContentLengthHeader<T: Header> (headers: Array<T>): T | null
return matches.length ? matches[0] : null;
}
export function setDefaultProtocol (url: string, defaultProto: string = 'http:'): string {
// If no url, don't bother returning anything
if (!url) {
return '';
}
// Default the proto if it doesn't exist
if (url.indexOf('://') === -1) {
url = `${defaultProto}//${url}`;
}
return url;
}
/**
* Generate an ID of the format "<MODEL_NAME>_<TIMESTAMP><RANDOM>"
* @param prefix
@@ -121,84 +91,6 @@ export function generateId (prefix: string): string {
}
}
export function flexibleEncodeComponent (str: string, ignore: string = ''): string {
// Sometimes spaces screw things up because of url.parse
str = str.replace(/%20/g, ' ');
// Handle all already-encoded characters so we don't touch them
str = str.replace(/%([0-9a-fA-F]{2})/g, '__ENC__$1');
// Do a special encode of ignored chars, so they aren't touched.
// This first pass, surrounds them with a special tag (anything unique
// will work), so it can change them back later
// Example: will replace %40 with __LEAVE_40_LEAVE__, and we'll change
// it back to %40 at the end.
for (const c of ignore) {
const code = encodeURIComponent(c).replace('%', '');
const re2 = new RegExp(escapeRegex(c), 'g');
str = str.replace(re2, `__RAW__${code}`);
}
// Encode it
str = encodeURIComponent(str);
// Put back the raw version of the ignored chars
for (const match of str.match(/__RAW__([0-9a-fA-F]{2})/g) || []) {
const code = match.replace('__RAW__', '');
str = str.replace(match, decodeURIComponent(`%${code}`));
}
// Put back the encoded version of the ignored chars
for (const match of str.match(/__ENC__([0-9a-fA-F]{2})/g) || []) {
const code = match.replace('__ENC__', '');
str = str.replace(match, `%${code}`);
}
return str;
}
export function prepareUrlForSending (url: string, autoEncode: boolean = true): string {
const urlWithProto = setDefaultProtocol(url);
if (!autoEncode) {
return urlWithProto;
} else {
// Parse the URL into components
const parsedUrl = urlParse(urlWithProto);
// ~~~~~~~~~~~ //
// 1. Pathname //
// ~~~~~~~~~~~ //
if (parsedUrl.pathname) {
const segments = parsedUrl.pathname.split('/');
parsedUrl.pathname = segments.map(
s => flexibleEncodeComponent(s, URL_PATH_CHARACTER_WHITELIST)
).join('/');
}
// ~~~~~~~~~~~~~~ //
// 2. Querystring //
// ~~~~~~~~~~~~~~ //
if (parsedUrl.query) {
const qsParams = querystring.deconstructToParams(parsedUrl.query);
const encodedQsParams = [];
for (const {name, value} of qsParams) {
encodedQsParams.push({
name: flexibleEncodeComponent(name),
value: flexibleEncodeComponent(value)
});
}
parsedUrl.query = querystring.buildFromParams(encodedQsParams);
parsedUrl.search = `?${parsedUrl.query}`;
}
return urlFormat(parsedUrl);
}
}
export function delay (milliseconds: number = DEBOUNCE_MILLIS): Promise<void> {
return new Promise(resolve => setTimeout(resolve, milliseconds));
}
@@ -271,7 +163,7 @@ export function attributeHref (href: string): string {
if (href.match(/^http/i)) {
const appName = isDevelopment() ? 'Insomnia Dev' : 'Insomnia';
const qs = `utm_source=${appName}&utm_medium=app&utm_campaign=v${getAppVersion()}`;
return querystring.joinUrl(href, qs);
return joinUrlAndQueryString(href, qs);
} else {
// Don't modify non-http urls
return href;
@@ -2,9 +2,9 @@
import type {Request} from '../models/request';
import type {BaseModel} from '../models/index';
import {setDefaultProtocol} from 'insomnia-url';
import clone from 'clone';
import * as models from '../models';
import {setDefaultProtocol} from './misc';
import * as db from './database';
import * as templating from '../templating';
import type {CookieJar} from '../models/cookie-jar';
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -2,7 +2,7 @@
import electron from 'electron';
import {CHECK_FOR_UPDATES_INTERVAL, getAppVersion, isDevelopment, UPDATE_URL_MAC, UPDATE_URL_WINDOWS} from '../common/constants';
import * as models from '../models/index';
import * as querystring from '../common/querystring';
import {buildQueryStringFromParams, joinUrlAndQueryString} from 'insomnia-url';
import {delay} from '../common/misc';
const {autoUpdater, BrowserWindow, ipcMain} = electron;
@@ -25,8 +25,8 @@ async function getUpdateUrl (force: boolean): Promise<string | null> {
{name: 'channel', value: settings.updateChannel}
];
const qs = querystring.buildFromParams(params);
const fullUrl = querystring.joinUrl(updateUrl, qs);
const qs = buildQueryStringFromParams(params);
const fullUrl = joinUrlAndQueryString(updateUrl, qs);
console.log(`[updater] Using url ${fullUrl}`);
if (isDevelopment()) {
@@ -96,7 +96,7 @@ export function createWindow () {
});
// Load the html of the app.
const appUrl = process.env.APP_RENDER_URL || `file://${__dirname}/renderer.html`;
const appUrl = process.env.APP_RENDER_URL || `file://${app.getAppPath()}/renderer.html`;
console.log(`[main] Loading ${process.env.APP_RENDER_URL}`);
mainWindow.loadURL(appUrl);
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loaded 100 of 957 files, more files were not shown because too many files have changed in this diff. Show more