@sveltejs/app-utils
Advanced tools
Comparing version 0.0.17 to 0.0.18
# @sveltejs/app-utils | ||
## 0.0.18 | ||
### Patch Changes | ||
- b475ed4: Overhaul adapter API - fixes #166 | ||
## 0.0.17 | ||
@@ -4,0 +10,0 @@ |
@@ -9,27 +9,31 @@ 'use strict'; | ||
function mkdirp(dir) { | ||
try { | ||
fs.mkdirSync(dir, { recursive: true }); | ||
} | ||
catch (e) { | ||
if (e.code === 'EEXIST') | ||
return; | ||
throw e; | ||
} | ||
try { | ||
fs.mkdirSync(dir, { recursive: true }); | ||
} catch (e) { | ||
if (e.code === 'EEXIST') return; | ||
throw e; | ||
} | ||
} | ||
function copy(from, to, filter = () => true) { | ||
if (!filter(path.basename(from))) | ||
return []; | ||
const files = []; | ||
const stats = fs.statSync(from); | ||
if (stats.isDirectory()) { | ||
fs.readdirSync(from).forEach(file => { | ||
files.push(...copy(path.join(from, file), path.join(to, file))); | ||
}); | ||
} | ||
else { | ||
mkdirp(path.dirname(to)); | ||
fs.copyFileSync(from, to); | ||
files.push(to); | ||
} | ||
return files; | ||
function copy( | ||
from, | ||
to, | ||
filter = () => true | ||
) { | ||
if (!filter(path.basename(from))) return []; | ||
const files = []; | ||
const stats = fs.statSync(from); | ||
if (stats.isDirectory()) { | ||
fs.readdirSync(from).forEach((file) => { | ||
files.push(...copy(path.join(from, file), path.join(to, file))); | ||
}); | ||
} else { | ||
mkdirp(path.dirname(to)); | ||
fs.copyFileSync(from, to); | ||
files.push(to); | ||
} | ||
return files; | ||
} | ||
@@ -36,0 +40,0 @@ |
@@ -5,201 +5,219 @@ 'use strict'; | ||
/*! ***************************************************************************** | ||
Copyright (c) Microsoft Corporation. | ||
function read_only_form_data() { | ||
const map = new Map(); | ||
Permission to use, copy, modify, and/or distribute this software for any | ||
purpose with or without fee is hereby granted. | ||
return { | ||
append(key, value) { | ||
if (map.has(key)) { | ||
(map.get(key) ).push(value); | ||
} else { | ||
map.set(key, [value]); | ||
} | ||
}, | ||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH | ||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | ||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, | ||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | ||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR | ||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | ||
PERFORMANCE OF THIS SOFTWARE. | ||
***************************************************************************** */ | ||
function __classPrivateFieldGet(receiver, privateMap) { | ||
if (!privateMap.has(receiver)) { | ||
throw new TypeError("attempted to get private field on non-instance"); | ||
} | ||
return privateMap.get(receiver); | ||
data: new ReadOnlyFormData(map) | ||
}; | ||
} | ||
function __classPrivateFieldSet(receiver, privateMap, value) { | ||
if (!privateMap.has(receiver)) { | ||
throw new TypeError("attempted to set private field on non-instance"); | ||
} | ||
privateMap.set(receiver, value); | ||
return value; | ||
} | ||
class ReadOnlyFormData { | ||
#map | ||
var _map; | ||
function read_only_form_data() { | ||
const map = new Map(); | ||
return { | ||
append(key, value) { | ||
if (map.has(key)) { | ||
map.get(key).push(value); | ||
} | ||
else { | ||
map.set(key, [value]); | ||
} | ||
}, | ||
data: new ReadOnlyFormData(map) | ||
}; | ||
constructor(map) { | ||
this.#map = map; | ||
} | ||
get(key) { | ||
const value = this.#map.get(key); | ||
return value && value[0]; | ||
} | ||
getAll(key) { | ||
return this.#map.get(key); | ||
} | ||
has(key) { | ||
return this.#map.has(key); | ||
} | ||
*[Symbol.iterator]() { | ||
for (const [key, value] of this.#map) { | ||
for (let i = 0; i < value.length; i += 1) { | ||
yield [key, value[i]]; | ||
} | ||
} | ||
} | ||
*entries() { | ||
for (const [key, value] of this.#map) { | ||
for (let i = 0; i < value.length; i += 1) { | ||
yield [key, value[i]]; | ||
} | ||
} | ||
} | ||
*keys() { | ||
for (const [key, value] of this.#map) { | ||
for (let i = 0; i < value.length; i += 1) { | ||
yield key; | ||
} | ||
} | ||
} | ||
*values() { | ||
for (const [, value] of this.#map) { | ||
for (let i = 0; i < value.length; i += 1) { | ||
yield value; | ||
} | ||
} | ||
} | ||
} | ||
class ReadOnlyFormData { | ||
constructor(map) { | ||
_map.set(this, void 0); | ||
__classPrivateFieldSet(this, _map, map); | ||
} | ||
get(key) { | ||
var _a; | ||
return (_a = __classPrivateFieldGet(this, _map).get(key)) === null || _a === void 0 ? void 0 : _a[0]; | ||
} | ||
getAll(key) { | ||
return __classPrivateFieldGet(this, _map).get(key); | ||
} | ||
has(key) { | ||
return __classPrivateFieldGet(this, _map).has(key); | ||
} | ||
*[(_map = new WeakMap(), Symbol.iterator)]() { | ||
for (const [key, value] of __classPrivateFieldGet(this, _map)) { | ||
for (let i = 0; i < value.length; i += 1) { | ||
yield [key, value[i]]; | ||
} | ||
} | ||
} | ||
*entries() { | ||
for (const [key, value] of __classPrivateFieldGet(this, _map)) { | ||
for (let i = 0; i < value.length; i += 1) { | ||
yield [key, value[i]]; | ||
} | ||
} | ||
} | ||
*keys() { | ||
for (const [key, value] of __classPrivateFieldGet(this, _map)) { | ||
for (let i = 0; i < value.length; i += 1) { | ||
yield key; | ||
} | ||
} | ||
} | ||
*values() { | ||
for (const [, value] of __classPrivateFieldGet(this, _map)) { | ||
for (let i = 0; i < value.length; i += 1) { | ||
yield value; | ||
} | ||
} | ||
} | ||
} | ||
function get_body(req) { | ||
const has_body = (req.headers['content-type'] !== undefined && | ||
// https://github.com/jshttp/type-is/blob/c1f4388c71c8a01f79934e68f630ca4a15fffcd6/index.js#L81-L95 | ||
(req.headers['transfer-encoding'] !== undefined || !isNaN(Number(req.headers['content-length'])))); | ||
if (!has_body) | ||
return Promise.resolve(undefined); | ||
const [type, ...directives] = req.headers['content-type'].split(/;\s*/); | ||
switch (type) { | ||
case 'application/octet-stream': | ||
return get_buffer(req); | ||
case 'text/plain': | ||
return get_text(req); | ||
case 'application/json': | ||
return get_json(req); | ||
case 'application/x-www-form-urlencoded': | ||
return get_urlencoded(req); | ||
case 'multipart/form-data': | ||
const boundary = directives.find(directive => directive.startsWith('boundary=')); | ||
if (!boundary) | ||
throw new Error(`Missing boundary`); | ||
return get_multipart(req, boundary.slice('boundary='.length)); | ||
default: | ||
throw new Error(`Invalid Content-Type ${type}`); | ||
} | ||
const headers = req.headers; | ||
const has_body = | ||
headers['content-type'] !== undefined && | ||
// https://github.com/jshttp/type-is/blob/c1f4388c71c8a01f79934e68f630ca4a15fffcd6/index.js#L81-L95 | ||
(headers['transfer-encoding'] !== undefined || !isNaN(Number(headers['content-length']))); | ||
if (!has_body) return Promise.resolve(undefined); | ||
const [type, ...directives] = (headers['content-type'] ).split(/;\s*/); | ||
switch (type) { | ||
case 'application/octet-stream': | ||
return get_buffer(req); | ||
case 'text/plain': | ||
return get_text(req); | ||
case 'application/json': | ||
return get_json(req); | ||
case 'application/x-www-form-urlencoded': | ||
return get_urlencoded(req); | ||
case 'multipart/form-data': | ||
const boundary = directives.find((directive) => directive.startsWith('boundary=')); | ||
if (!boundary) throw new Error(`Missing boundary`); | ||
return get_multipart(req, boundary.slice('boundary='.length)); | ||
default: | ||
throw new Error(`Invalid Content-Type ${type}`); | ||
} | ||
} | ||
async function get_json(req) { | ||
return JSON.parse(await get_text(req)); | ||
return JSON.parse(await get_text(req)); | ||
} | ||
async function get_urlencoded(req) { | ||
const text = await get_text(req); | ||
const { data, append } = read_only_form_data(); | ||
text.replace(/\+/g, ' ').split('&').forEach(str => { | ||
const [key, value] = str.split('='); | ||
append(decodeURIComponent(key), decodeURIComponent(value)); | ||
}); | ||
return data; | ||
const text = await get_text(req); | ||
const { data, append } = read_only_form_data(); | ||
text | ||
.replace(/\+/g, ' ') | ||
.split('&') | ||
.forEach((str) => { | ||
const [key, value] = str.split('='); | ||
append(decodeURIComponent(key), decodeURIComponent(value)); | ||
}); | ||
return data; | ||
} | ||
async function get_multipart(req, boundary) { | ||
const text = await get_text(req); | ||
const parts = text.split(`--${boundary}`); | ||
const nope = () => { | ||
throw new Error('Malformed form data'); | ||
}; | ||
if (parts[0] !== '' || parts[parts.length - 1].trim() !== '--') { | ||
nope(); | ||
} | ||
const { data, append } = read_only_form_data(); | ||
parts.slice(1, -1).forEach(part => { | ||
const match = /\s*([\s\S]+?)\r\n\r\n([\s\S]*)\s*/.exec(part); | ||
const raw_headers = match[1]; | ||
const body = match[2].trim(); | ||
let key; | ||
raw_headers.split('\r\n').forEach(str => { | ||
const [raw_header, ...raw_directives] = str.split('; '); | ||
let [name, value] = raw_header.split(': '); | ||
name = name.toLowerCase(); | ||
const directives = {}; | ||
raw_directives.forEach(raw_directive => { | ||
const [name, value] = raw_directive.split('='); | ||
directives[name] = JSON.parse(value); // TODO is this right? | ||
}); | ||
if (name === 'content-disposition') { | ||
if (value !== 'form-data') | ||
nope(); | ||
if (directives.filename) { | ||
// TODO we probably don't want to do this automatically | ||
throw new Error('File upload is not yet implemented'); | ||
} | ||
if (directives.name) { | ||
key = directives.name; | ||
} | ||
} | ||
}); | ||
if (!key) | ||
nope(); | ||
append(key, body); | ||
}); | ||
return data; | ||
const text = await get_text(req); | ||
const parts = text.split(`--${boundary}`); | ||
const nope = () => { | ||
throw new Error('Malformed form data'); | ||
}; | ||
if (parts[0] !== '' || parts[parts.length - 1].trim() !== '--') { | ||
nope(); | ||
} | ||
const { data, append } = read_only_form_data(); | ||
parts.slice(1, -1).forEach((part) => { | ||
const match = /\s*([\s\S]+?)\r\n\r\n([\s\S]*)\s*/.exec(part) ; | ||
const raw_headers = match[1]; | ||
const body = match[2].trim(); | ||
let key; | ||
raw_headers.split('\r\n').forEach((str) => { | ||
const [raw_header, ...raw_directives] = str.split('; '); | ||
let [name, value] = raw_header.split(': '); | ||
name = name.toLowerCase(); | ||
const directives = {}; | ||
raw_directives.forEach((raw_directive) => { | ||
const [name, value] = raw_directive.split('='); | ||
directives[name] = JSON.parse(value); // TODO is this right? | ||
}); | ||
if (name === 'content-disposition') { | ||
if (value !== 'form-data') nope(); | ||
if (directives.filename) { | ||
// TODO we probably don't want to do this automatically | ||
throw new Error('File upload is not yet implemented'); | ||
} | ||
if (directives.name) { | ||
key = directives.name; | ||
} | ||
} | ||
}); | ||
if (!key) nope(); | ||
append(key, body); | ||
}); | ||
return data; | ||
} | ||
function get_text(req) { | ||
return new Promise((fulfil, reject) => { | ||
let data = ''; | ||
req.on('error', reject); | ||
req.on('data', chunk => { | ||
data += chunk; | ||
}); | ||
req.on('end', () => { | ||
fulfil(data); | ||
}); | ||
}); | ||
return new Promise((fulfil, reject) => { | ||
let data = ''; | ||
req.on('error', reject); | ||
req.on('data', (chunk) => { | ||
data += chunk; | ||
}); | ||
req.on('end', () => { | ||
fulfil(data); | ||
}); | ||
}); | ||
} | ||
function get_buffer(req) { | ||
return new Promise((fulfil, reject) => { | ||
let data = new Uint8Array(0); | ||
req.on('error', reject); | ||
req.on('data', chunk => { | ||
const new_data = new Uint8Array(data.length + chunk.length); | ||
for (let i = 0; i < data.length; i += 1) { | ||
new_data[i] = data[i]; | ||
} | ||
for (let i = 0; i < chunk.length; i += 1) { | ||
new_data[i + data.length] = chunk[i]; | ||
} | ||
data = new_data; | ||
}); | ||
req.on('end', () => { | ||
fulfil(data.buffer); | ||
}); | ||
}); | ||
return new Promise((fulfil, reject) => { | ||
let data = new Uint8Array(0); | ||
req.on('error', reject); | ||
req.on('data', (chunk) => { | ||
const new_data = new Uint8Array(data.length + chunk.length); | ||
for (let i = 0; i < data.length; i += 1) { | ||
new_data[i] = data[i]; | ||
} | ||
for (let i = 0; i < chunk.length; i += 1) { | ||
new_data[i + data.length] = chunk[i]; | ||
} | ||
data = new_data; | ||
}); | ||
req.on('end', () => { | ||
fulfil(data.buffer); | ||
}); | ||
}); | ||
} | ||
@@ -206,0 +224,0 @@ |
{ | ||
"name": "@sveltejs/app-utils", | ||
"version": "0.0.17", | ||
"version": "0.0.18", | ||
"scripts": { | ||
@@ -8,6 +8,7 @@ "clean": "node rimraf.js common files http renderer", | ||
"build": "npm run clean && rollup -c", | ||
"lint": "eslint --ignore-pattern node_modules/ --ignore-pattern dist/ --ignore-pattern files/ --ignore-pattern http/ --ignore-pattern renderer/ '**/*.{ts,js,svelte}'", | ||
"prepare": "npm run build", | ||
"lint": "eslint --ignore-pattern node_modules/ --ignore-pattern dist/ --ignore-pattern files/ --ignore-pattern http/ --ignore-pattern renderer/ \"**/*.{ts,js,svelte}\" && npm run check-format", | ||
"format": "prettier --write . --config ../../.prettierrc --ignore-path .gitignore", | ||
"check-format": "prettier --check . --config ../../.prettierrc --ignore-path .gitignore", | ||
"prepublishOnly": "npm run build", | ||
"test": "uvu -r ts-node/register" | ||
"test": "uvu -r esm" | ||
}, | ||
@@ -22,6 +23,6 @@ "dependencies": { | ||
"devalue": "^2.0.1", | ||
"esm": "^3.2.25", | ||
"node-fetch": "^2.6.1", | ||
"rollup": "^2.32.0", | ||
"svelte": "^3.29.0", | ||
"ts-node": "^9.0.0", | ||
"uvu": "^0.3.4" | ||
@@ -37,6 +38,2 @@ }, | ||
"import": "./http/index.mjs" | ||
}, | ||
"./renderer": { | ||
"require": "./renderer/index.js", | ||
"import": "./renderer/index.mjs" | ||
} | ||
@@ -43,0 +40,0 @@ }, |
# app-utils | ||
Utilities required by svelte-app and its various adapters | ||
Utilities required by svelte-app and its various adapters |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 3 instances in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
4
3
1
42119
12
407