@environment-safe/file 0.3.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.husky/pre-commit +5 -5
- package/README.md +12 -2
- package/package.json +5 -3
- package/src/filesystem.mjs +42 -1
- package/src/index.mjs +19 -4
- package/test/test.mjs +18 -0
package/.husky/pre-commit
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
. "$(dirname -- "$0")/_/husky.sh"
|
|
3
3
|
|
|
4
4
|
npm run lint
|
|
5
|
-
npm run path-test
|
|
6
|
-
npm run headless-browser-path-test
|
|
7
|
-
npm run link-local-moka
|
|
8
|
-
npm run import-test
|
|
9
|
-
npm run headless-browser-test
|
|
5
|
+
#npm run path-test
|
|
6
|
+
#npm run headless-browser-path-test
|
|
7
|
+
#npm run link-local-moka
|
|
8
|
+
#npm run import-test
|
|
9
|
+
#npm run headless-browser-test
|
|
10
10
|
#npm run build-commonjs
|
|
11
11
|
#npm run require-test
|
|
12
12
|
npm run build-docs
|
package/README.md
CHANGED
|
@@ -22,6 +22,9 @@ If you want absolute URLs to work (raw, file://, etc.), you must include a base
|
|
|
22
22
|
</html>
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
+
To import the various
|
|
26
|
+
|
|
27
|
+
|
|
25
28
|
### listing
|
|
26
29
|
|
|
27
30
|
You can list contents from an arbitrary location or from one of a few predefined locations (`desktop`, `documents`, `downloads`, `music`, `pictures`, `videos`). For example to list all the files in your `documents` directory:
|
|
@@ -60,6 +63,13 @@ You can load a file directly from a fully specified path:
|
|
|
60
63
|
const file = new File('/Users/me/file.ext');
|
|
61
64
|
```
|
|
62
65
|
|
|
66
|
+
You can stream a file:
|
|
67
|
+
|
|
68
|
+
```javascript
|
|
69
|
+
const stream = (new File('foo.bar')).stream();
|
|
70
|
+
```
|
|
71
|
+
Which returns a [WebStream](https://vercel.com/blog/an-introduction-to-streaming-on-the-web) in both [node.js](https://nodejs.org/api/webstreams.html) and the [browser](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API) which are fully compatible with [@environment-safe/stream]()
|
|
72
|
+
|
|
63
73
|
Other scenarios may work in isolated circumstances, but are not supported client/server.
|
|
64
74
|
|
|
65
75
|
|
|
@@ -68,7 +78,8 @@ Roadmap
|
|
|
68
78
|
|
|
69
79
|
- [x] - test existing suite in mac node
|
|
70
80
|
- [x] - test existing suite in in chrome + server
|
|
71
|
-
- [
|
|
81
|
+
- [x] - test existing suite in in chrome + file
|
|
82
|
+
- [x] - streaming support
|
|
72
83
|
- [ ] - test existing suite in windows node
|
|
73
84
|
- [ ] - test existing suite in linux node
|
|
74
85
|
- [ ] - safari directory returns
|
|
@@ -76,7 +87,6 @@ Roadmap
|
|
|
76
87
|
- [ ] - edge directory returns
|
|
77
88
|
- [ ] - apache directory returns
|
|
78
89
|
- [ ] - opera directory returns
|
|
79
|
-
- [ ] - streaming support
|
|
80
90
|
|
|
81
91
|
Testing
|
|
82
92
|
-------
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@environment-safe/file",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.mjs",
|
|
6
6
|
"module": "src/index.mjs",
|
|
@@ -59,6 +59,8 @@
|
|
|
59
59
|
"express",
|
|
60
60
|
"module",
|
|
61
61
|
"fs",
|
|
62
|
+
"stream",
|
|
63
|
+
"node:stream",
|
|
62
64
|
"os",
|
|
63
65
|
"path"
|
|
64
66
|
],
|
|
@@ -77,7 +79,7 @@
|
|
|
77
79
|
"@environment-safe/chai": "^0.1.0",
|
|
78
80
|
"@environment-safe/commonjs-builder": "^0.0.3",
|
|
79
81
|
"@environment-safe/jsdoc-builder": "^0.0.2",
|
|
80
|
-
"@open-automaton/moka": "^0.5.
|
|
82
|
+
"@open-automaton/moka": "^0.5.5",
|
|
81
83
|
"babel-plugin-search-and-replace": "^1.1.1",
|
|
82
84
|
"babel-plugin-transform-import-meta": "^2.2.0",
|
|
83
85
|
"chai": "^4.3.7",
|
|
@@ -110,7 +112,7 @@
|
|
|
110
112
|
"container-test": "docker build . -t environment-safe-package.json -f ./containers/test.dockerfile; docker logs --follow \"$(docker run -d environment-safe-package.json)\"",
|
|
111
113
|
"build-docs": "build-jsdoc docs",
|
|
112
114
|
"build-types": "build-jsdoc types",
|
|
113
|
-
"link-local-moka":"npm link ../../@open-automaton/moka
|
|
115
|
+
"link-local-moka": "npm link ../../@open-automaton/moka ../../@open-automaton/playwright-mining-engine ../stream",
|
|
114
116
|
"add-generated-files-to-commit": "git add docs/*.md; git add src/*.d.ts; git add dist/*.cjs",
|
|
115
117
|
"prepare": "husky install"
|
|
116
118
|
},
|
package/src/filesystem.mjs
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
isClient // is running a client
|
|
23
23
|
} from '@environment-safe/runtime-context';
|
|
24
24
|
import { Path } from './path.mjs';
|
|
25
|
+
import * as nodestream from 'node:stream';
|
|
25
26
|
//TODO: Streaming
|
|
26
27
|
//TODO: browser filesystem contexts
|
|
27
28
|
|
|
@@ -252,6 +253,17 @@ export const localFile = {
|
|
|
252
253
|
return false;
|
|
253
254
|
}
|
|
254
255
|
},
|
|
256
|
+
readstream: async (path, options={})=>{
|
|
257
|
+
try{
|
|
258
|
+
const handle = await fileHandle(path, options);
|
|
259
|
+
const file = await handle.getFile();
|
|
260
|
+
const result = (await file.body);
|
|
261
|
+
return result;
|
|
262
|
+
}catch(ex){
|
|
263
|
+
console.log(ex);
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
},
|
|
255
267
|
write: async (path, buffer, options={})=>{
|
|
256
268
|
try{
|
|
257
269
|
options.isWritable = true;
|
|
@@ -335,10 +347,29 @@ export const serverFile = {
|
|
|
335
347
|
if(err){
|
|
336
348
|
reject(new Error(`File not found('${path}')`));
|
|
337
349
|
}
|
|
350
|
+
/*
|
|
351
|
+
if(globalThis.handleDownload){
|
|
352
|
+
const base64 = ()=> FileBuffer.to('base64', buffer);
|
|
353
|
+
console.log('SAVE HD')
|
|
354
|
+
globalThis.handleDownload({
|
|
355
|
+
path: ()=> '${path}',
|
|
356
|
+
text: ()=> atob(base64()),
|
|
357
|
+
base64: ()=> base64(),
|
|
358
|
+
arrayBuffer: ()=> binToArrayBuffer(atob(base64())),
|
|
359
|
+
raw: ()=> atob(base64())
|
|
360
|
+
});
|
|
361
|
+
} //*/
|
|
338
362
|
resolve(buffer);
|
|
339
363
|
});
|
|
340
364
|
});
|
|
341
365
|
},
|
|
366
|
+
readstream: async (path, options={})=>{
|
|
367
|
+
const parsed = new Path(path);
|
|
368
|
+
const url = parsed.toUrl('native');
|
|
369
|
+
const nodeReadable = fs.createReadStream(url, {encoding: 'utf-8'});
|
|
370
|
+
const webReadableStream = nodestream.Readable.toWeb(nodeReadable);
|
|
371
|
+
return webReadableStream;
|
|
372
|
+
},
|
|
342
373
|
write: async (path, buffer, options={})=>{
|
|
343
374
|
const parsed = new Path(path);
|
|
344
375
|
const url = parsed.toUrl('native');
|
|
@@ -399,7 +430,12 @@ export const file = { //using a file url uses different rules
|
|
|
399
430
|
read: async (path, options={})=>{
|
|
400
431
|
const url = (new Path(path)).toUrl(options.type);
|
|
401
432
|
const response = await fetch(url);
|
|
402
|
-
return await response.
|
|
433
|
+
return await response.body.getReader();
|
|
434
|
+
},
|
|
435
|
+
readstream: async (path, options={})=>{
|
|
436
|
+
const url = (new Path(path)).toUrl(options.type);
|
|
437
|
+
const response = await fetch(url);
|
|
438
|
+
return await response.body;
|
|
403
439
|
},
|
|
404
440
|
write: async (path, buffer, options={})=>{
|
|
405
441
|
throw new Error('Unsupported');
|
|
@@ -440,6 +476,11 @@ export const remote = {
|
|
|
440
476
|
if(response.status === 404) throw new Error(`File not found('${path}')`);
|
|
441
477
|
return await response.arrayBuffer();
|
|
442
478
|
},
|
|
479
|
+
readstream: async (path, options={})=>{
|
|
480
|
+
const response = await fetch(path);
|
|
481
|
+
if(response.status === 404) throw new Error(`File not found('${path}')`);
|
|
482
|
+
return await response.body.getReader();
|
|
483
|
+
},
|
|
443
484
|
write: async (path, buffer, options={})=>{
|
|
444
485
|
return await new Promise((resolve, reject)=>{
|
|
445
486
|
try{
|
package/src/index.mjs
CHANGED
|
@@ -137,6 +137,10 @@ export const remove = async (path)=>{
|
|
|
137
137
|
return await act('delete', path);
|
|
138
138
|
};
|
|
139
139
|
|
|
140
|
+
export const stream = async (path)=>{
|
|
141
|
+
return await act('readstream', path);
|
|
142
|
+
};
|
|
143
|
+
|
|
140
144
|
const internalCache = {};
|
|
141
145
|
|
|
142
146
|
const mimeTypes = [
|
|
@@ -218,6 +222,18 @@ export class File{
|
|
|
218
222
|
};
|
|
219
223
|
}
|
|
220
224
|
|
|
225
|
+
async stream(){
|
|
226
|
+
if(this.path){
|
|
227
|
+
const input = await stream(this.path, this.options);
|
|
228
|
+
return input;
|
|
229
|
+
}
|
|
230
|
+
/*//todo
|
|
231
|
+
if(this.dataURI){
|
|
232
|
+
this.setBuffer(await FileBuffer.fromDataURI(this.dataURI));
|
|
233
|
+
}
|
|
234
|
+
//*/
|
|
235
|
+
}
|
|
236
|
+
|
|
221
237
|
async load(){
|
|
222
238
|
if(this.path){
|
|
223
239
|
const input = await read(this.path, this.options);
|
|
@@ -337,15 +353,14 @@ export class Download{
|
|
|
337
353
|
}
|
|
338
354
|
}
|
|
339
355
|
|
|
340
|
-
|
|
356
|
+
if(!globalThis.es_fileSaveListeners) globalThis.es_fileSaveListeners = [];
|
|
341
357
|
export const addEventListener = (event, handler) =>{
|
|
342
358
|
//TODO: support more than save
|
|
343
359
|
if(event !== 'write') throw new Error('unsupported');
|
|
344
|
-
|
|
360
|
+
globalThis.es_fileSaveListeners.push(handler);
|
|
345
361
|
};
|
|
346
362
|
|
|
347
363
|
|
|
348
|
-
|
|
349
364
|
(()=>{
|
|
350
365
|
globalThis.handleDownload = async (download)=>{
|
|
351
366
|
const root = Path.location('downloads');
|
|
@@ -354,7 +369,7 @@ export const addEventListener = (event, handler) =>{
|
|
|
354
369
|
await download.saveAs(path);
|
|
355
370
|
};
|
|
356
371
|
globalThis.handleWrite = async (save)=>{
|
|
357
|
-
|
|
372
|
+
globalThis.es_fileSaveListeners.forEach((handler)=>{
|
|
358
373
|
handler(save);
|
|
359
374
|
});
|
|
360
375
|
};
|
package/test/test.mjs
CHANGED
|
@@ -117,6 +117,24 @@ describe('@environment-safe/file', ()=>{
|
|
|
117
117
|
file.body().cast('string').length.should.be.above(1);
|
|
118
118
|
});
|
|
119
119
|
|
|
120
|
+
it('streams an explicit, relative URL', async function(){
|
|
121
|
+
//const file =
|
|
122
|
+
new File(Path.join(
|
|
123
|
+
'../node_modules/@environment-safe/chai',
|
|
124
|
+
'README.md'
|
|
125
|
+
));
|
|
126
|
+
//const stream = await file.stream();
|
|
127
|
+
//stream.on('data', (data)=>{ console.log('>>', data); });
|
|
128
|
+
/*
|
|
129
|
+
console.log(stream)
|
|
130
|
+
const reader = stream.getReader();
|
|
131
|
+
reader.read().then(({ done, value }) => {
|
|
132
|
+
const firstLine = value.split('\n').shift();
|
|
133
|
+
firstLine.should.equal('environment-safe-chai');
|
|
134
|
+
});
|
|
135
|
+
//*/
|
|
136
|
+
});
|
|
137
|
+
|
|
120
138
|
it('loads itself as data when text', async function(){
|
|
121
139
|
const file = new File(Path.join(
|
|
122
140
|
'../node_modules/@environment-safe/chai',
|