@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 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
- - [ ] - test existing suite in in chrome + file
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.2",
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.1",
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; cd ../../@open-automaton/moka; npm link ../../@environment-safe/file",
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
  },
@@ -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.json();
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
- const saveListeners = [];
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
- saveListeners.push(handler);
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
- saveListeners.forEach((handler)=>{
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',