Gathering detailed insights and metrics for poteto
Gathering detailed insights and metrics for poteto
Gathering detailed insights and metrics for poteto
Gathering detailed insights and metrics for poteto
remark-lint-hiring-without-whiteboards-links
Checks that all resources links are formatted according to poteto/hiring-without-whiteboards guidelines
@potetotown/google_news_api
Google News RSS feed to JSON converter
@h3poteto/tauri-snap-packager
Snap packager for Tauri.
react-validated-proxy
An approach to form validation in React that makes use of [ES6 Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy), by way of [**@poteto**](https://github.com/poteto)'s [`validated-proxy`](https://github.com/pote
poteto is HTTP-alike fetch for FILE protocol, e.g. fetch('file:///usr/bin/node')
npm install poteto
Typescript
Module System
Node Version
NPM Version
73.6
Supply Chain
98.9
Quality
76.1
Maintenance
100
Vulnerability
80.9
License
JavaScript (100%)
Total Downloads
2,998
Last Day
1
Last Week
4
Last Month
46
Last Year
453
GPL-3.0 License
2 Stars
142 Commits
1 Forks
1 Watchers
6 Branches
1 Contributors
Updated on Jul 14, 2024
Minified
Minified + Gzipped
Latest Version
0.9.3
Package Id
poteto@0.9.3
Unpacked Size
87.52 kB
Size
26.87 kB
File Count
33
NPM Version
9.8.0
Node Version
20.5.1
Published on
Sep 04, 2023
Cumulative downloads
Total Downloads
Last Day
0%
1
Compared to previous day
Last Week
-50%
4
Compared to previous week
Last Month
-41%
46
Compared to previous month
Last Year
-82.2%
453
Compared to previous year
1
poteto
allows fetch
to work with local files over non-standartized file:
protocol.
It can work as fetch
polyfill (setting Proxy
over globalThis.fetch
and globalThis.Request
) or as ponyfill (providing a separate drop-in replacements for them).
It can understand:
URL
instance having .protocol === 'file:'
file
protocol, e.g. file:///usr/bin/node
file
protocol, e.g. file:file.ext
, file:../subdir/file.ext
1file.ext
or subdir/file.ext
.
, e.g. ./file.ext
or ../subdir/file.ext
/
, e.g. /usr/bin/node
///
, e.g. ///usr/bin/node
file:
or .
...and work with them in somewhat HTTP-compatible manner.
Relative paths are resolved against CWD2.
URLs that are normally supported by standard fetch
are fetched like usual.
Zero dependencies. Can work with Node.js's builtin fetch
or with user-provided implementation.
1$ npm i poteto
1import poteto from 'poteto'; 2 3// read files with GET 4{ 5 const text = await poteto(import.meta.url).then(r => r.text()); 6 const json = await poteto('node_modules/poteto/package.json').then(r => r.json()); 7 const buffer = await poteto('/usr/bin/node').then(r => r.arrayBuffer()); 8} 9 10// read files with READ in memory-efficient stream-based way 11{ 12 const { body } = await poteto('/dev/urandom', { method: 'READ' }); 13} 14 15// read file ranges and validate result using SRI 16{ 17 const text = await poteto('./node_modules/poteto/LICENSE', { 18 headers: { 19 'Range': 'bytes=34264-34266,17303-17304,19991-19991', 20 }, 21 integrity: 'sha512-pmndJoYi4kwRRbKcFCVXRnwT0nF/4d73zYKnqredfUIhfKddjRqL3Zbi+CjjkyMIX2e2HQEkV89kZeWdhj1MJQ==', 22 }).then(r => r.text()); 23} 24 25// write files with PUT 26{ 27 const { status } = await poteto('file:./new_file.txt', { 28 method: 'PUT', 29 body: 'new ifel contents', 30 }); 31} 32 33// write partial file range with POST 34{ 35 const { statusText } = await poteto('new_file.txt', { 36 method: 'POST', 37 body: 'fileUNUSED', 38 headers: { 39 'Range': 'bytes=4-7', 40 }, 41 }); 42} 43 44// write files with WRITE for no particular reason 45{ 46 const potentialErrorMessage = await poteto('./new_file.txt', { 47 method: 'WRITE', 48 body: 'newer file contents', 49 }).then(r => r.text()); 50} 51 52// append to files with APPEND 53{ 54 const { ok } = await poteto('oops/../new_file.txt', { 55 method: 'APPEND', 56 body: '\nbut wait, there is more\n', 57 }); 58} 59 60// list files and directories with LIST 61{ 62 const filenames = await poteto('.', { method: 'LIST' }).then(r => r.json()); 63} 64 65// get stats without reading the file with HEAD 66// (GET, READ and LIST also return fs stats) 67{ 68 const { headers } = await poteto('file:package.json', { method: 'HEAD' }); 69 const filesize = headers.get('Content-Length'); 70 const mtimeHTTPdate = headers.get('Last-Modified'); 71 const mtimeTemporal = new Temporal.Instant(headers.get('X-Poteto-MtimeNs')); 72} 73 74// make conditional request (also supports ETag and If-None-Match) 75{ 76 const response = await poteto('file:///var/log/auth.log', { 77 headers: { 78 'If-Modified-Since': 'Wed, 07 Aug 2019 10:00:12 GMT', 79 }, 80 }); 81 const isNotModified = response.status === 304; 82} 83 84// get symlink destination using manual redirect 85{ 86 const { headers } = await poteto('/etc/mtab', { redirect: 'manual' }); 87 const location = headers.get('Location'); 88} 89 90// get errors as JSON 91{ 92 const errorInfo = await poteto('file:///non/existent/path', { 93 method: 'PUT', 94 body: 'some data', 95 headers: { 96 'Accept': 'application/json', 97 }, 98 }).then(r => r.json()); 99} 100 101// and do usual fetches transparently 102{ 103 const response = await poteto('https://github.com/LiviaMedeiros/poteto', { 104 headers: { 105 'User-Agent': 'Poteto', 106 }, 107 }); 108}
GET
Reads file. Supports If-Modified-Since
, If-Unmodified-Since
, If-None-Match
, If-Match
, Range
, and SRI3.
Returns HTTP 200
or HTTP 206
and file body; or HTTP 304
.
HEAD
Returns fs.Stats
of file in headers. Note that GET
also does it.
Returns HTTP 200
without body.
DELETE
Deletes file or directory.
Returns HTTP 204
.
POST
and PUT
Writes request body to file. Supports Range
header (only one range is allowed).
POST
opens file with r+
flag while PUT
uses w+
. Which means:
POST
can write partial file range in existing file without rewriting, but PUT
will truncate the end and fill beginning with NUL bytes.PUT
will create new files or overwrite existing ones, but POST
will return HTTP 404
if the file doesn't exist yet.Returns HTTP 201
.
These are case-sensitive.
APPEND
Appends request body to file.
Returns HTTP 201
.
LIST
Reads directory contents. Also gets fs.Stats
for the directory.
Returns HTTP 200
with JSON response, containing array of items. Subdirectory names will have trailing /
.
READ
Reads file. See Why there is GET
and READ
.
Returns HTTP 200
and file body.
WRITE
Alias to PUT
.
Returns HTTP 201
.
The following HTTP headers are supported:
Server
with fixed value poteto
Accept-Ranges
with fixed value bytes
Date
with RFC 7231 date of forming the response headersContent-Length
with filesize in bytes if applicableLast-Modified
with RFC 7231 date of last file modification if applicableETag
with weak entity tag if applicable 4Poteto-specific headers are be prefixed with X-Poteto-
prefix. For example, filesize can be accessed via X-Poteto-Size
header.
If there is an error and it's known, returned promise is resolved with Response
having reasonable HTTP status. For example, ENOENT
translates to HTTP 404
and EACCES
translates to HTTP 403
.
The headers contain error information. If Accept
header is application/json
, the body will contain serialized error as JSON; otherwise, it will contain its .message
.
If the error is unknown, returned promise is rejected with it.
If request.redirect === 'follow'
(default), symlinks will be quietly resolved.
If request.redirect === 'error'
, returned promise will be rejected with TypeError
.
If request.redirect === 'manual'
, returned promise will be resolved with HTTP 302
response with target URL in Location
header.
Subpath imports allow to add poteto
to the project in different ways.
poteto/polyfill
1import 'poteto/polyfill'; 2 3await fetch('/dev/null'); 4(new Request('/dev/null')).url === 'file:///dev/null'
Replaces globalThis.fetch
and globalThis.Request
with proxies.
Constructing Request
with applicable URL results in regular Request
instance but with fully-resolved file:
URL.
For non-file:
URLs, it works transparently.
poteto/ponyfill
1import ponyfill from 'poteto/ponyfill'; 2import { fetch as potetoFetch, Request as PotetoRequest } from 'poteto/ponyfill'; 3 4ponyfill === potetoFetch;
Provides separate AsyncFunction fetch
and Class Request
that use globalThis.fetch
and globalThis.Request
internally but do not allow to indirectly mutate them.
poteto/factory
1import { proxify, wrap } from 'poteto/factory'; 2 3const mutableFetch = proxify(fetch); 4const independentFetch = wrap(fetch);
proxify
allows to make poteto-like proxy around user-specified fetch
function. This will use proxified Request
internally.
wrap
returns a new function that will use user-specified fetch
function as fallback for non-file:
URLs. This will use PotetoRequest
class that extends Request
.
poteto/internal
1import { methods, execute } from 'poteto/internal'; 2 3methods.set('HELLO', async (url, request) => new Response('WORLD')); 4 5await execute(new Request('file:///dev/zero', { method: 'HELLO' }));
Exposes internal Map methods
and AsyncFunction execute
.
methods
has methods in a form of functions that take the URL
instance as first argument and Request
instance as second. This was made for convenience, because request.url
exposes string instead of URL
instance.
execute(request[, url])
performs fetch using the methods map. Unlike in other imports, this one does not fallback for non-file:
URL and executes request anyway. Optional url
parameter allows to override first argument passing to the method.
Sometimes we just want to be able to read local and remote files in the same manner.
Some other languages have similar capabilities, for example, file_get_contents()
in PHP can read files over http(s).
Sometimes we want to avoid explicitly using node:fs
for trivial reading operation.
Sometimes we want convenience methods such as response.json()
Sometimes we don't want to switch context of thinking between node:fs
and Fetch API.
Sometimes we have urlstring pointing on file instead of pathstring or URL
instance.
Sometimes we have relative URL rather than relative path.
Sometimes we want to read a file requested by URL and have appropriate HTTP Response
to return.
file:
Right now file
protocol is not standartized, and HTTP entities such as status codes, headers and algorithms are not related to it.
However, some projections such as GET
=> read file
, ENOENT
=> 404 Not Found
, Accept: application/json
=> return data as json
are intuitive enough to be implemented, so here we are.
There are a few things in /bin/
that work as minimalistic examples.
poteto-cat fileurl1[, fileurl2[, ...]]
Works as cat(1)
: reads files in order, concatenates and prints on the stdout.
Uses GET
method (hence, can be used with https:
URLs as is).
poteto-dog fileurl1[, fileurl2[, ...]]
Like poteto-cat
, but insane: reads everything in async, and prints chunks on the stdout as fast as it can. If there are multiple files, depending on I/O, they may partially diffuse.
Uses READ
method (depending on web server, can be used with https:
URLs, but not recommended).
poteto-ls [dirurl1[, dirurl2[, ...]]]
Works like recursive ls(1)
: reads directories recursively, and outputs as pretty-printed JSON.
1// poteto-ls lib testdir 2{ 3 "lib/": [ 4 "constants.mjs", 5 "fs.mjs", 6 "generic.mjs", 7 "http.mjs", 8 "methods.mjs", 9 "poteto.mjs", 10 "request.mjs", 11 "sri.mjs" 12 ], 13 "testdir/": [ 14 ".keep", 15 { 16 "bin/": [ 17 ".keep" 18 ] 19 }, 20 { 21 "redirect/": [ 22 ".keep", 23 "link1", 24 "link2", 25 "target" 26 ] 27 }, 28 { 29 "sequence/": [ 30 ".keep" 31 ] 32 } 33 ] 34}
Uses LIST
method, don't use on https:
URLs.
poteto-put fileurl
Reads data from stdin and prints to file. Overwrites existing files, can create new files, can read from interactive (keyboard) input.
Uses PUT
method, can be used with https:
URL.
poteto-rm fileurl1[, fileurl2[, ...]]
Works like rm()
: deletes files. Not recursive, not interactive.
Uses DELETE
method, can be used with https:
URLs.
GET
and READ
GET
loads the whole file in memory before responding. This might be significantly faster, but also means that getting 1Gb file will require >1Gb of memory to be used, no matter what.
Also GET
supports Range
header and SRI3, and might support other features that require checking file body (e.g. magic to determine Content-Type
).
READ
is stream-based. If the file body might not be consumed, or consumed partially, or consumed chunk-by-chunk, it will not allocate unnecessarily big amounts of memory.
Also READ
leaks filehandles.
PUT
and WRITE
Just to mirror GET
and READ
. PUT
is preferable.
No particular reason.
Why not, but be aware that there is no standard at the moment.
Note that unary URL
constructor in Node.js resolves these as absolute paths, i.e. new URL('file:file.txt').href === new URL('file:./file.txt').href === new URL('file:../file.txt').href === 'file:///file.txt'
. But if baseURL
is provided, it's interpreted as relative path. ↩
Current Working Directory ↩
Weak ETag
is calculated from device id, inode, filesize and last modification time. Length is variable. ↩
No vulnerabilities found.
No security vulnerabilities found.