Socket
Socket
Sign inDemoInstall

streamsaver

Package Overview
Dependencies
0
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.0.1 to 1.2.0

2

package.json
{
"name": "streamsaver",
"version": "1.0.1",
"version": "1.2.0",
"description": "StreamSaver writes stream to the filesystem directly - asynchronous",

@@ -5,0 +5,0 @@ "main": "StreamSaver.js",

@@ -26,4 +26,4 @@ StreamSaver.js

| Chrome 52+ | Yes | |
| Firefox | No | Streams |
| Safari     | No       | SW |
| Firefox 65+| Yes | |
| Safari | No | download functionality |
| Edge | No | Streams, SW |

@@ -46,3 +46,3 @@ | IE | No | Everything (IE is dead) |

<script src="StreamSaver.js"></script> <!-- load before streams polyfill to detect support -->
<script src="https://cdn.rawgit.com/creatorrr/web-streams-polyfill/master/dist/polyfill.min.js"></script>
<script src="https://unpkg.com/@mattiasbuelens/web-streams-polyfill/dist/polyfill.min.js"></script>
<script>

@@ -79,3 +79,3 @@ // it also support commonJs and amd

```
That is pretty much all StreamSaver.js dose :)
That is pretty much all StreamSaver.js does :)

@@ -145,4 +145,2 @@

### Get a "stream" from ajax
res.body is a readableByteStream, but don't have pipeTo yet<br>
So we have to use the reader instead which is the underlying method in streams

@@ -153,5 +151,10 @@ ```javascript

const writer = fileStream.getWriter()
// Later you will be able to just simply do
// res.body.pipeTo(fileStream)
// more optimized
if (res.body.pipeTo) {
// like as we never did fileStream.getWriter()
writer.releaseLock()
return res.body.pipeTo(fileStream)
}
const reader = res.body.getReader()

@@ -257,3 +260,3 @@ const pump = () => reader.read()

[14]: https://streams.spec.whatwg.org/#rs-class
[15]: https://www.npmjs.com/package/web-streams-polyfill
[15]: https://www.npmjs.com/package/@mattiasbuelens/web-streams-polyfill
[16]: https://developer.microsoft.com/en-us/microsoft-edge/platform/status/fetchapi

@@ -260,0 +263,0 @@ [17]: https://developer.microsoft.com/en-us/microsoft-edge/platform/status/serviceworker

@@ -0,120 +1,168 @@

/* global location WritableStream ReadableStream define MouseEvent MessageChannel TransformStream */
;((name, definition) => {
'undefined' != typeof module ? module.exports = definition() :
'function' == typeof define && 'object' == typeof define.amd ? define(definition) :
this[name] = definition()
typeof module !== 'undefined'
? module.exports = definition()
: typeof define === 'function' && typeof define.amd === 'object'
? define(definition)
: this[name] = definition()
})('streamSaver', () => {
'use strict'
'use strict'
let
iframe, loaded,
secure = location.protocol == 'https:' || location.hostname == 'localhost',
streamSaver = {
createWriteStream,
supported: false,
version: {
full: '1.0.0',
major: 1, minor: 0, dot: 0
}
}
const secure = location.protocol === 'https:' ||
location.protocol === 'chrome-extension:' ||
location.hostname === 'localhost'
let iframe
let loaded
let transfarableSupport = false
let streamSaver = {
createWriteStream,
supported: false,
version: {
full: '1.2.0',
major: 1,
minor: 2,
dot: 0
}
}
streamSaver.mitm = 'https://jimmywarting.github.io/StreamSaver.js/mitm.html?version=' +
streamSaver.version.full
streamSaver.mitm = 'https://jimmywarting.github.io/StreamSaver.js/mitm.html?version=' +
streamSaver.version.full
try {
// Some browser has it but ain't allowed to construct a stream yet
streamSaver.supported = 'serviceWorker' in navigator && !!new ReadableStream() && !!new WritableStream()
} catch(err) {
// if you are running chrome < 52 then you can enable it
// `chrome://flags/#enable-experimental-web-platform-features`
}
try {
// Some browser has it but ain't allowed to construct a stream yet
streamSaver.supported = 'serviceWorker' in navigator && !!new ReadableStream() && !!new WritableStream()
} catch (err) {}
function createWriteStream(filename, queuingStrategy, size) {
try {
const { readable } = new TransformStream()
const mc = new MessageChannel()
mc.port1.postMessage(readable, [readable])
mc.port1.close()
mc.port2.close()
transfarableSupport = readable.locked === true
} catch (err) {
// Was first enabled in chrome v73
}
// normalize arguments
if (Number.isFinite(queuingStrategy))
[size, queuingStrategy] = [queuingStrategy, size]
function createWriteStream (filename, queuingStrategy, size) {
// normalize arguments
if (Number.isFinite(queuingStrategy)) {
[size, queuingStrategy] = [queuingStrategy, size]
}
let channel = new MessageChannel,
popup,
setupChannel = () => new Promise((resolve, reject) => {
channel.port1.onmessage = evt => {
if(evt.data.download) {
resolve()
if(!secure) popup.close() // don't need the popup any longer
let link = document.createElement('a')
let click = new MouseEvent('click')
let channel = new MessageChannel()
let popup
let setupChannel = readableStream => new Promise(resolve => {
const args = [ { filename, size }, '*', [ channel.port2 ] ]
link.href = evt.data.download
link.dispatchEvent(click)
}
}
// Pass along transfarable stream
if (readableStream) {
args[0].readableStream = readableStream
args[2].push(readableStream)
}
if(secure && !iframe) {
iframe = document.createElement('iframe')
iframe.src = streamSaver.mitm
iframe.hidden = true
document.body.appendChild(iframe)
}
channel.port1.onmessage = evt => {
// Service worker sent us a link from where
// we recive the readable link (stream)
if (evt.data.download) {
resolve() // Signal that the writestream are ready to recive data
if (!secure) popup.close() // don't need the popup any longer
if (window.chrome && chrome.extension &&
chrome.extension.getBackgroundPage &&
chrome.extension.getBackgroundPage() === window) {
chrome.tabs.create({ url: evt.data.download, active: false })
} else {
window.location = evt.data.download
}
if(secure && !loaded) {
let fn;
iframe.addEventListener('load', fn = evt => {
loaded = true
iframe.removeEventListener('load', fn)
iframe.contentWindow.postMessage(
{filename, size}, '*', [channel.port2])
})
}
// Cleanup
if (readableStream) {
// We don't need postMessages now when stream are transferable
channel.port1.close()
channel.port2.close()
}
if(secure && loaded) {
iframe.contentWindow.postMessage({filename, size}, '*', [channel.port2])
}
channel.port1.onmessage = null
}
}
if(!secure) {
popup = window.open(streamSaver.mitm, Math.random())
let onready = evt => {
if(evt.source === popup){
popup.postMessage({filename, size}, '*', [channel.port2])
removeEventListener('message', onready)
}
}
if (secure && !iframe) {
iframe = document.createElement('iframe')
iframe.src = streamSaver.mitm
iframe.hidden = true
document.body.appendChild(iframe)
}
// Another problem that cross origin don't allow is scripting
// so popup.onload() don't work but postMessage still dose
// work cross origin
addEventListener('message', onready)
}
})
if (secure && !loaded) {
let fn
iframe.addEventListener('load', fn = () => {
loaded = true
iframe.removeEventListener('load', fn)
iframe.contentWindow.postMessage(...args)
})
}
return new WritableStream({
start(error) {
// is called immediately, and should perform any actions
// necessary to acquire access to the underlying sink.
// If this process is asynchronous, it can return a promise
// to signal success or failure.
return setupChannel()
},
write(chunk) {
// is called when a new chunk of data is ready to be written
// to the underlying sink. It can return a promise to signal
// success or failure of the write operation. The stream
// implementation guarantees that this method will be called
// only after previous writes have succeeded, and never after
// close or abort is called.
if (secure && loaded) {
iframe.contentWindow.postMessage(...args)
}
// TODO: Kind of important that service worker respond back when
// it has been written. Otherwise we can't handle backpressure
channel.port1.postMessage(chunk)
},
close() {
channel.port1.postMessage('end')
console.log('All data successfully read!')
},
abort(e) {
channel.port1.postMessage('abort')
}
}, queuingStrategy)
}
if (!secure) {
popup = window.open(streamSaver.mitm, Math.random())
let onready = evt => {
if (evt.source === popup) {
popup.postMessage(...args)
window.removeEventListener('message', onready)
}
}
return streamSaver
// Another problem that cross origin don't allow is scripting
// so popup.onload() don't work but postMessage still dose
// work cross origin
window.addEventListener('message', onready)
}
})
if (transfarableSupport) {
const ts = new TransformStream({
start () {
return new Promise(resolve =>
setTimeout(() => setupChannel(ts.readable).then(resolve))
)
}
}, queuingStrategy)
return ts.writable
}
return new WritableStream({
start () {
// is called immediately, and should perform any actions
// necessary to acquire access to the underlying sink.
// If this process is asynchronous, it can return a promise
// to signal success or failure.
return setupChannel()
},
write (chunk) {
// is called when a new chunk of data is ready to be written
// to the underlying sink. It can return a promise to signal
// success or failure of the write operation. The stream
// implementation guarantees that this method will be called
// only after previous writes have succeeded, and never after
// close or abort is called.
// TODO: Kind of important that service worker respond back when
// it has been written. Otherwise we can't handle backpressure
// EDIT: Transfarable streams solvs this...
channel.port1.postMessage(chunk)
},
close () {
channel.port1.postMessage('end')
},
abort () {
channel.port1.postMessage('abort')
}
}, queuingStrategy)
}
return streamSaver
})

@@ -1,91 +0,81 @@

'use strict'
const map = new Map
/* global self ReadableStream Response */
const map = new Map()
// This should be called once per download
// Each event has a dataChannel that the data will be piped through
self.onmessage = event => {
// Create a uniq link for the download
let uniqLink = self.registration.scope + 'intercept-me-nr' + Math.random()
let port = event.ports[0]
// We send a heartbeat every x secound to keep the
// service worker alive
if (event.data === 'ping') {
return
}
let p = new Promise((resolve, reject) => {
let stream = createStream(resolve, reject, port)
map.set(uniqLink, [stream, event.data])
port.postMessage({download: uniqLink})
// Create a uniq link for the download
const uniqLink = self.registration.scope + 'intercept-me-nr' + Math.random()
const port = event.ports[0]
// Mistage adding this and have streamsaver.js rely on it
// depricated as from 0.2.1
port.postMessage({debug: 'Mocking a download request'})
})
const stream = event.data.readableStream || createStream(port)
map.set(uniqLink, [stream, event.data])
port.postMessage({ download: uniqLink, ping: self.registration.scope + 'ping' })
// Beginning in Chrome 51, event is an ExtendableMessageEvent, which supports
// the waitUntil() method for extending the lifetime of the event handler
// until the promise is resolved.
if ('waitUntil' in event) {
event.waitUntil(p)
}
// Without support for waitUntil(), there's a chance that if the promise chain
// takes "too long" to execute, the service worker might be automatically
// stopped before it's complete.
// Mistage adding this and have streamsaver.js rely on it
// depricated as from 0.2.1
port.postMessage({ debug: 'Mocking a download request' })
}
function createStream(resolve, reject, port){
// ReadableStream is only supported by chrome 52
var bytesWritten = 0
return new ReadableStream({
start(controller) {
// When we receive data on the messageChannel, we write
port.onmessage = ({data}) => {
if (data === 'end') {
resolve()
return controller.close()
}
function createStream (port) {
// ReadableStream is only supported by chrome 52
return new ReadableStream({
start (controller) {
// When we receive data on the messageChannel, we write
port.onmessage = ({ data }) => {
if (data === 'end') {
return controller.close()
}
if (data === 'abort') {
resolve()
controller.error('Aborted the download')
return
}
if (data === 'abort') {
controller.error('Aborted the download')
return
}
controller.enqueue(data)
bytesWritten += data.byteLength
port.postMessage({ bytesWritten })
}
},
cancel() {
console.log("user aborted")
}
})
controller.enqueue(data)
}
},
cancel () {
console.log('user aborted')
}
})
}
self.onfetch = event => {
let url = event.request.url
let hijacke = map.get(url)
let listener, filename, headers
const url = event.request.url
console.log("Handleing ", url)
if (url.endsWith('/ping')) {
return event.respondWith(new Response('pong', {
headers: { 'Access-Control-Allow-Origin': '*' }
}))
}
if(!hijacke) return null
const hijacke = map.get(url)
let [stream, data] = hijacke
if (!hijacke) return null
map.delete(url)
const [stream, data] = hijacke
filename = typeof data === 'string' ? data : data.filename
map.delete(url)
// Make filename RFC5987 compatible
filename = encodeURIComponent(filename)
.replace(/['()]/g, escape)
.replace(/\*/g, '%2A')
// Make filename RFC5987 compatible
const filename = encodeURIComponent(typeof data === 'string' ? data : data.filename)
.replace(/['()]/g, escape)
.replace(/\*/g, '%2A')
headers = {
'Content-Type': 'application/octet-stream; charset=utf-8',
'Content-Disposition': "attachment; filename*=UTF-8''" + filename
}
const headers = {
'Content-Type': 'application/octet-stream; charset=utf-8',
'Content-Disposition': "attachment; filename*=UTF-8''" + filename
}
if(data.size) headers['Content-Length'] = data.size
if (data.size) headers['Content-Length'] = data.size
event.respondWith(new Response(stream, { headers }))
event.respondWith(new Response(stream, { headers }))
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc