generated from freckle/npm-package-template
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
21 changed files
with
935 additions
and
57 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,19 @@ | ||
# npm Package Template | ||
# @freckle/ajax | ||
|
||
Our custom template repository for creating a package published to npm. | ||
## Install | ||
|
||
[Creating a repository from a template][docs]. | ||
```sh | ||
yarn add @freckle/ajax | ||
``` | ||
|
||
[docs]: https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-repository-from-a-template | ||
## Ajax helpers | ||
|
||
**NOTE**: Be sure to look for strings like "TODO", "Package name", or "package-name" and update | ||
them accordingly. | ||
See [ajax.ts](./src/ajax.ts). | ||
|
||
## Install | ||
## Link header | ||
|
||
```sh | ||
yarn add package-name | ||
``` | ||
See [link-header.ts](./src/link-header.ts). | ||
|
||
## process(input) | ||
--- | ||
|
||
TODO: Document public API for package. | ||
[LICENSE](./LICENSE) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
type MethodT = 'POST' | 'GET' | 'PATCH' | 'PUT' | 'HEAD' | 'DELETE'; | ||
type ContentTypeT = 'application/json; charset=utf-8' | 'application/x-www-form-urlencoded' | 'text/plain' | 'text/csv'; | ||
type DataTypeT = 'json' | 'text'; | ||
type AjaxCallOptionsT = { | ||
url: string; | ||
method: MethodT; | ||
data?: any; | ||
contentType?: ContentTypeT | null; | ||
dataType: DataTypeT; | ||
cache?: boolean; | ||
xhrFields?: { | ||
withCredentials: boolean; | ||
}; | ||
timeout?: number; | ||
}; | ||
export declare function ajaxCall<T>(options: AjaxCallOptionsT): Promise<T>; | ||
type MethodWithStringifiedDataT = 'POST' | 'PATCH' | 'PUT' | 'HEAD' | 'DELETE'; | ||
type MethodWithRawDataT = 'GET'; | ||
export type AjaxJsonCallOptionsT = { | ||
url: string; | ||
method: MethodWithStringifiedDataT; | ||
data?: string; | ||
cache?: boolean; | ||
xhrFields?: { | ||
withCredentials: boolean; | ||
}; | ||
timeout?: number; | ||
} | { | ||
url: string; | ||
method: MethodWithRawDataT; | ||
data?: any; | ||
cache?: boolean; | ||
xhrFields?: { | ||
withCredentials: boolean; | ||
}; | ||
timeout?: number; | ||
}; | ||
export declare function ajaxJsonCall<T>(options: AjaxJsonCallOptionsT): Promise<T>; | ||
type AjaxFormCallOptionsT = { | ||
url: string; | ||
method: MethodT; | ||
data?: any; | ||
}; | ||
export declare function ajaxFormCall<T>(options: AjaxFormCallOptionsT): Promise<T>; | ||
type AjaxFormFileUploadOptionsT = { | ||
url: string; | ||
data: any; | ||
method?: MethodT; | ||
timeout?: number; | ||
}; | ||
export declare function ajaxFormFileUpload<T>(options: AjaxFormFileUploadOptionsT): Promise<T>; | ||
export type AjaxFileDownloadOptionsT = { | ||
url: string; | ||
accept: ContentTypeT; | ||
defaultFilename: string; | ||
}; | ||
export declare function ajaxFileDownload(options: AjaxFileDownloadOptionsT): Promise<void>; | ||
type SendBeaconOptionsT = Inexact<{ | ||
url: string; | ||
data: Inexact<{ | ||
[x: string]: any; | ||
}>; | ||
}>; | ||
export declare function sendBeacon(options: SendBeaconOptionsT): void; | ||
export declare function checkUrlExistence(url: string): Promise<boolean>; | ||
/** | ||
* This hack gets around a Chrome caching bug wherein the audio request generated | ||
* by the audio web api leads to chrome caching a response that does not contain | ||
* the appropriate CORS headers. Any subsequent testing of that resource by this method | ||
* would then attempt to fetch the resource from cache and would error out with a missing | ||
* access-control-allow-origin error. By appending the path name to the audioPath | ||
* here, but not for the audio web api, we create a separate cache for this | ||
* resource request and bypass using the cached response with the missing | ||
* CORS Headers. This is reproducible in Chrome only. | ||
* | ||
* Root cause: https://bugs.chromium.org/p/chromium/issues/detail?id=260239 | ||
*/ | ||
export declare function appendParamToRemedyCorsBug(path: string): string; | ||
export {}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.appendParamToRemedyCorsBug = exports.checkUrlExistence = exports.sendBeacon = exports.ajaxFileDownload = exports.ajaxFormFileUpload = exports.ajaxFormCall = exports.ajaxJsonCall = exports.ajaxCall = void 0; | ||
const maybe_1 = require("@freckle/maybe"); | ||
function ajaxCall(options) { | ||
const { url, method, data, contentType, dataType, cache, xhrFields, timeout } = options; | ||
const contentTypeHeader = contentType !== null && contentType !== undefined ? { contentType } : {}; | ||
const timeoutParam = timeout !== null && timeout !== undefined ? { timeout } : {}; | ||
return new Promise((resolve, reject) => { | ||
$.ajax(Object.assign(Object.assign({ url, type: method, data, | ||
dataType, | ||
cache, | ||
xhrFields }, timeoutParam), contentTypeHeader)) | ||
.then(resolve) | ||
.fail(reject); | ||
}); | ||
} | ||
exports.ajaxCall = ajaxCall; | ||
function ajaxJsonCall(options) { | ||
const { url, method, data, cache, xhrFields, timeout } = options; | ||
// If we are not sending any data along with the request then there is no need to specify the contentType | ||
// For cross-domain requests, setting the content type to anything other than application/x-www-form-urlencoded, | ||
// multipart/form-data, or text/plain will trigger the browser to send a preflight OPTIONS request to the server. | ||
// We don't want to make a preflight request where it has no use. | ||
const contentType = data !== null && data !== undefined ? 'application/json; charset=utf-8' : null; | ||
const dataType = 'json'; | ||
return ajaxCall({ url, method, data, contentType, dataType, cache, xhrFields, timeout }); | ||
} | ||
exports.ajaxJsonCall = ajaxJsonCall; | ||
function ajaxFormCall(options) { | ||
const { url, method, data } = options; | ||
const contentType = 'application/x-www-form-urlencoded'; | ||
const dataType = 'json'; | ||
const cache = false; | ||
return ajaxCall({ url, method, data, contentType, dataType, cache }); | ||
} | ||
exports.ajaxFormCall = ajaxFormCall; | ||
function ajaxFormFileUpload(options) { | ||
const { url, data, method, timeout } = options; | ||
const timeoutParam = timeout !== null && timeout !== undefined ? { timeout } : {}; | ||
return new Promise((resolve, reject) => { | ||
$.ajax(Object.assign({ url, type: method ? method : 'POST', data, contentType: false, processData: false }, timeoutParam)) | ||
.then(resolve) | ||
.fail(reject); | ||
}); | ||
} | ||
exports.ajaxFormFileUpload = ajaxFormFileUpload; | ||
function ajaxFileDownload(options) { | ||
const { url, accept, defaultFilename } = options; | ||
return new Promise((resolve, reject) => { | ||
const request = new XMLHttpRequest(); | ||
request.open('GET', url, true); | ||
request.withCredentials = true; | ||
request.responseType = 'blob'; | ||
request.setRequestHeader('Accept', accept); | ||
// Reject on error | ||
request.onerror = () => { | ||
reject({ | ||
status: request.status, | ||
statusText: request.statusText | ||
}); | ||
}; | ||
// Create an anchor that downloads Blob using FileReader | ||
request.onload = () => { | ||
var _a; | ||
if (request.status >= 200 && request.status < 300) { | ||
const contentType = request.getResponseHeader('Content-Type'); | ||
const disposition = request.getResponseHeader('Content-Disposition'); | ||
const blob = new Blob([(_a = request.response) !== null && _a !== void 0 ? _a : ''], { type: contentType !== null && contentType !== void 0 ? contentType : undefined }); | ||
const reader = new FileReader(); | ||
reader.onload = e => { | ||
const anchor = document.createElement('a'); | ||
anchor.style.display = 'none'; | ||
const target = e.target; | ||
if (target instanceof FileReader && typeof target.result === 'string') { | ||
anchor.href = target.result; | ||
anchor.download = (0, maybe_1.fromMaybe)(() => defaultFilename, contentDispositionFilename(disposition)); | ||
anchor.click(); | ||
resolve(); | ||
} | ||
else { | ||
reject({ | ||
status: request.status, | ||
statusText: request.statusText | ||
}); | ||
} | ||
}; | ||
reader.readAsDataURL(blob); | ||
} | ||
else { | ||
reject({ | ||
status: request.status, | ||
statusText: request.statusText | ||
}); | ||
} | ||
}; | ||
// Go | ||
request.send(); | ||
}); | ||
} | ||
exports.ajaxFileDownload = ajaxFileDownload; | ||
function contentDispositionFilename(mDisposition) { | ||
return (0, maybe_1.mthen)(mDisposition, disposition => (0, maybe_1.mthen)(disposition.trim().match(/attachment; filename="(.*)"/), ([_ignore, filename]) => filename)); | ||
} | ||
function sendBeacon(options) { | ||
const { url, data } = options; | ||
try { | ||
const jsonData = JSON.stringify(data); | ||
window.navigator.sendBeacon(url, jsonData); | ||
// eslint-disable-next-line no-empty | ||
} | ||
catch (e) { } | ||
} | ||
exports.sendBeacon = sendBeacon; | ||
function checkUrlExistence(url) { | ||
return new Promise(resolve => { | ||
ajaxCall({ | ||
url, | ||
method: 'HEAD', | ||
contentType: 'text/plain', | ||
dataType: 'text' | ||
}) | ||
.then(() => { | ||
resolve(true); | ||
}) | ||
.catch(() => { | ||
resolve(false); | ||
}); | ||
}); | ||
} | ||
exports.checkUrlExistence = checkUrlExistence; | ||
/** | ||
* This hack gets around a Chrome caching bug wherein the audio request generated | ||
* by the audio web api leads to chrome caching a response that does not contain | ||
* the appropriate CORS headers. Any subsequent testing of that resource by this method | ||
* would then attempt to fetch the resource from cache and would error out with a missing | ||
* access-control-allow-origin error. By appending the path name to the audioPath | ||
* here, but not for the audio web api, we create a separate cache for this | ||
* resource request and bypass using the cached response with the missing | ||
* CORS Headers. This is reproducible in Chrome only. | ||
* | ||
* Root cause: https://bugs.chromium.org/p/chromium/issues/detail?id=260239 | ||
*/ | ||
function appendParamToRemedyCorsBug(path) { | ||
return path.includes('?') ? `${path}&via=xmlHttpRequest` : `${path}?via=xmlHttpRequest`; | ||
} | ||
exports.appendParamToRemedyCorsBug = appendParamToRemedyCorsBug; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
// @flow | ||
declare type MethodT = "POST" | "GET" | "PATCH" | "PUT" | "HEAD" | "DELETE"; | ||
declare type ContentTypeT = | ||
| "application/json; charset=utf-8" | ||
| "application/x-www-form-urlencoded" | ||
| "text/plain" | ||
| "text/csv"; | ||
declare type DataTypeT = "json" | "text"; | ||
declare type AjaxCallOptionsT = {| | ||
url: string, | ||
method: MethodT, | ||
data?: any, | ||
contentType?: ContentTypeT | null, | ||
dataType: DataTypeT, | ||
cache?: boolean, | ||
xhrFields?: {| | ||
withCredentials: boolean, | ||
|}, | ||
timeout?: number, | ||
|}; | ||
declare export function ajaxCall<T>(options: AjaxCallOptionsT): Promise<T>; | ||
declare type MethodWithStringifiedDataT = | ||
| "POST" | ||
| "PATCH" | ||
| "PUT" | ||
| "HEAD" | ||
| "DELETE"; | ||
declare type MethodWithRawDataT = "GET"; | ||
export type AjaxJsonCallOptionsT = | ||
| {| | ||
url: string, | ||
method: MethodWithStringifiedDataT, | ||
data?: string, | ||
cache?: boolean, | ||
xhrFields?: {| | ||
withCredentials: boolean, | ||
|}, | ||
timeout?: number, | ||
|} | ||
| {| | ||
url: string, | ||
method: MethodWithRawDataT, | ||
data?: any, | ||
cache?: boolean, | ||
xhrFields?: {| | ||
withCredentials: boolean, | ||
|}, | ||
timeout?: number, | ||
|}; | ||
declare export function ajaxJsonCall<T>( | ||
options: AjaxJsonCallOptionsT | ||
): Promise<T>; | ||
declare type AjaxFormCallOptionsT = {| | ||
url: string, | ||
method: MethodT, | ||
data?: any, | ||
|}; | ||
declare export function ajaxFormCall<T>( | ||
options: AjaxFormCallOptionsT | ||
): Promise<T>; | ||
declare type AjaxFormFileUploadOptionsT = {| | ||
url: string, | ||
data: any, | ||
method?: MethodT, | ||
timeout?: number, | ||
|}; | ||
declare export function ajaxFormFileUpload<T>( | ||
options: AjaxFormFileUploadOptionsT | ||
): Promise<T>; | ||
export type AjaxFileDownloadOptionsT = {| | ||
url: string, | ||
accept: ContentTypeT, | ||
defaultFilename: string, | ||
|}; | ||
declare export function ajaxFileDownload( | ||
options: AjaxFileDownloadOptionsT | ||
): Promise<void>; | ||
declare type SendBeaconOptionsT = Inexact<{| | ||
url: string, | ||
data: Inexact<{ | ||
[x: string]: any, | ||
}>, | ||
|}>; | ||
declare export function sendBeacon(options: SendBeaconOptionsT): void; | ||
declare export function checkUrlExistence(url: string): Promise<boolean>; | ||
|
||
/** | ||
* This hack gets around a Chrome caching bug wherein the audio request generated | ||
* by the audio web api leads to chrome caching a response that does not contain | ||
* the appropriate CORS headers. Any subsequent testing of that resource by this method | ||
* would then attempt to fetch the resource from cache and would error out with a missing | ||
* access-control-allow-origin error. By appending the path name to the audioPath | ||
* here, but not for the audio web api, we create a separate cache for this | ||
* resource request and bypass using the cached response with the missing | ||
* CORS Headers. This is reproducible in Chrome only. | ||
* | ||
* Root cause: https://bugs.chromium.org/p/chromium/issues/detail?id=260239 | ||
*/ | ||
declare export function appendParamToRemedyCorsBug(path: string): string; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,4 @@ | ||
export { process } from './process'; | ||
export { ajaxCall, ajaxJsonCall, ajaxFormCall, ajaxFormFileUpload, ajaxFileDownload, sendBeacon, checkUrlExistence, appendParamToRemedyCorsBug } from './ajax'; | ||
export type { AjaxJsonCallOptionsT, AjaxFileDownloadOptionsT } from './ajax'; | ||
export { fromString, toString, parseLinkHeader, fetchWithLinks } from './link-header'; | ||
export type { LinkName, LinkPathT, LinksT } from './link-header'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,17 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.process = void 0; | ||
var process_1 = require("./process"); | ||
Object.defineProperty(exports, "process", { enumerable: true, get: function () { return process_1.process; } }); | ||
exports.fetchWithLinks = exports.parseLinkHeader = exports.toString = exports.fromString = exports.appendParamToRemedyCorsBug = exports.checkUrlExistence = exports.sendBeacon = exports.ajaxFileDownload = exports.ajaxFormFileUpload = exports.ajaxFormCall = exports.ajaxJsonCall = exports.ajaxCall = void 0; | ||
var ajax_1 = require("./ajax"); | ||
Object.defineProperty(exports, "ajaxCall", { enumerable: true, get: function () { return ajax_1.ajaxCall; } }); | ||
Object.defineProperty(exports, "ajaxJsonCall", { enumerable: true, get: function () { return ajax_1.ajaxJsonCall; } }); | ||
Object.defineProperty(exports, "ajaxFormCall", { enumerable: true, get: function () { return ajax_1.ajaxFormCall; } }); | ||
Object.defineProperty(exports, "ajaxFormFileUpload", { enumerable: true, get: function () { return ajax_1.ajaxFormFileUpload; } }); | ||
Object.defineProperty(exports, "ajaxFileDownload", { enumerable: true, get: function () { return ajax_1.ajaxFileDownload; } }); | ||
Object.defineProperty(exports, "sendBeacon", { enumerable: true, get: function () { return ajax_1.sendBeacon; } }); | ||
Object.defineProperty(exports, "checkUrlExistence", { enumerable: true, get: function () { return ajax_1.checkUrlExistence; } }); | ||
Object.defineProperty(exports, "appendParamToRemedyCorsBug", { enumerable: true, get: function () { return ajax_1.appendParamToRemedyCorsBug; } }); | ||
var link_header_1 = require("./link-header"); | ||
Object.defineProperty(exports, "fromString", { enumerable: true, get: function () { return link_header_1.fromString; } }); | ||
Object.defineProperty(exports, "toString", { enumerable: true, get: function () { return link_header_1.toString; } }); | ||
Object.defineProperty(exports, "parseLinkHeader", { enumerable: true, get: function () { return link_header_1.parseLinkHeader; } }); | ||
Object.defineProperty(exports, "fetchWithLinks", { enumerable: true, get: function () { return link_header_1.fetchWithLinks; } }); |
Oops, something went wrong.