ServerJS/Filesystem API/Names
Contents
API and Proposed Names
The following sections are organized with a bullet point per function. Each point includes a specification for the behavior of a given method, intended to be suitable for documentation. Under each definition is a list of potential names for that function, and in bullets beneath that, everyone is encouraged to write their name under their preference. Please feel to leave comments as well.
In the next section, "General Preferences", there are several broad sweeping points about whether to use certain conventions in a consistent fashion. All of the name options are intended to conform to the prevalent opinion among those elections. For example, "make" and "create" and "dir" and "directory" are both general preference elections, so if you would prefer "makeDir" over "createDirectory", please vote independently for "make" and "dir" in the general preferences.
File System Object
The "file" module would conform to the File System API, as well as objects returned by "chroot". There is no definitive implementation of a FileSystem class, so "chroot" is the only way to construct new objects that conform to the FileSystem API. In permissive platforms, the "file" module may have direct access to ambient authority through a foreign function interface, or may itself be a dynamically loaded module. In secured platform, the "file" module must copy the properties of "system.fs" onto its exports.
In a secure sandbox, the following statements would be equivalent.
require('file').open(foo) system.fs.open(foo)
Since "fs" must be frozen to be secure, there is no need for the "file" module to assemble aparatus for late binding to "fs" methods.
- whether a file exists at a given path: receives a path and returns whether that path, joined on the current working directory, corresponds to a file that exists. If the file is a broken symbolic link, returns false.
- exists(path):
- Kris Kowal
- Wes Garland
- (Python: os.path.exists, Ruby: exist?, exists?, Java: exists, JSExt: access, Spidermonkey: Helma: v8cgi: JSExt: EJScript: Synchronet: exists, jslibs: exist, PHP: file_exists)
- exists(path):
- whether a symbolic link or file exists at a given path: receives a path and returns whether that path, joined on the current working directory, corresponds to a file, albeit a broken symbolic link, that exists.
- exists(path, true):
- Wes Garland
- Mario Valente
- linkExists(path):
- Kris Kowal
- exists(path, "link"):
- Kris Kowal (as a compromise)
- (Python: os.path.lexists)
- exists(path, true):
- moves a file from a source to a target path. Both paths are joined on the current working directory.
- move(source, target):
- (Ruby: move, Python: shutil.move, Java: File.renameTo, PHP: rename)
- renames a file: receives two paths. The first is a path, joined on the current working directory, that refers to the file to rename. The second argument is a path relative to the former file's fully qualified path.
- rename(path, name):
- should not be included in the spec:
- Kris Kowal
- (Ruby: rename)
- copies a file from a source to a target path. Both paths are joined on the current working directory.
- copy(source, target):
- (Ruby: copy, systemCopy, Python:PHP: copy, Unix: cp)
- copies a file and its recursive contents to a target path. Both paths are joined on the current working directory. If "synbolicLinks" is truthy, symbolic links in the source tree are represented as symbolic links in the new tree; if falsy, the contents of the linked files are copied to the new tree. If ignore is given, it must be a relation that will receive as its arguments the directory being visited by copytree(), and a list of its contents. Since this is called recursively (or walking an equivalent iteration), the ignore relation will be called once for each directory that is copied. The relation must return a sequence of directory and file names relative to the current directory (i.e. a subset of the items in its second argument); these names will then be ignored in the copy process.
- copyTree(source, target, symbolicLinks = false, ignore = undefined)
- copy(source, target, "recursive")
- copy(source, target, true)
- (Python: copytree)
- makes a directory at a given path in the base directory implied by the given path. Throws an exception if the base directory does not exist, or if the given path already exists.
- makeDirectory(path):
- Kris Kowal
- createDirectory(path):
- Mario Valente
- mkdir(path)
- Kevin Dangoor
- (Unix:PHP: mkdir)
- makeDirectory(path):
- creates recursive directories. Makes all intermediate-level directories needed to contain the leaf directory. Throws an exception if the leaf directory already exists or cannot be created. The default mode is 0777 (octal). On some systems, mode is ignored. Where it is used, the current umask value is first masked out.
- makePath(path):
- Kris Kowal
- makeDirectory(path, true):
- Wes Garland
- makeDirectory(path, "recursive"):
- makeDirectory(path, "path"):
- Kris Kowal (as a compromise)
- makeTree(path)
- (Unix: mkdir -p, Ruby: makedirs, mkpath, Python: os.makedirs)
- mkdirs(path)
- Kevin Dangoor
- (PHP: mkdir(path, mode, true))
- makePath(path):
- removes a file.
- remove(path):
- Kris Kowal
- Tom Robinson
- Kevin Dangoor
- Wes Garland (as a compromise)
- unlink(path):
- Wes Garland
- (Ruby: unlink, delete, Python: unlink, remove, Java: delete, Posix:PHP: unlink, Unix: rm, Spidermonkey: Helma: EJScript: Synchronet: remove, jslibs: Delete)
- remove(path):
- removes a file or directory and its recursive contents.
- remove(path):
- remove(path, true):
- remove(path, "recursive")
- removeRecursive(path)
- removeTree(path, ignoreErrors = false, onError = undefined)
- (Unix: rm -r, Python: rmtree)
- creates a hard link of the source path as the target path. Both paths are joined on the current working directory.
- link(source, target):
- uncontested
- (Python:Ruby:PHP: link, Unix: ln)
- link(source, target):
- creates a symbolic link on a given "target" file name. The source path becomes the text of the symbolic link, which the underlying system will join on the containing directory when it's followed, while the target path is joined on the current working directory.
- symbolicLink(source, target):
- Kris Kowal
- link(source, target, true):
- Wes Garland
- link(source, target, "symbolic"):
- Kris Kowal (as a compromise)
- (Ruby:Python:PHP: symlink, Unix: ln -s)
- symbolicLink(source, target):
- creates an empty file at a given path in its implied base directory. The path is resolved relative to the current working directory. Accepts an optional ``Permissions`` object (or a duck-type thereof, or the, typically octal, numeric representation of permissions in Unix) that notes which permissions the file will be created with, assuming that those permissions are in the "umask".
- create(path, [permissions]):
- Mario Valente
- unnecessary:
- Kris Kowal,
- Wes Garland
- (Java: createNewFile, Posix: creat, Unix:PHP: touch)
- create(path, [permissions]):
- truncates a the file at a given path. Accepts an optional length that default to zero. The path is resolved on the current working directory.
- truncate(path, [length = 0]):
- omit entirely:
- Kris Kowal
- (Ruby: truncate, Python:PHP: ftruncate applies to open files only)
- updates the stat/metadata of the file at a given path. Accepts a stat object. Implicitly updates the time that the file's metadata/stat was updated to the current time, regardless of the metadata modification time provided by the stat object.
- Wes Garland
- update(path, stat):
- chstat(path, stat):
- setStat(path, stat):
- restat(path, stat):
- (a low-level alternative to Python's copy2 and copyStat)
- updates the modification time of the file at a given path. Accepts an alternate modification time to set the file. Also implicitly updates the time that the file's metadata/stat object was updated to the current time, regardless of the chosen modification time.
- touch(path, [date]):
- Kris Kowal
- (Unix:PHP: touch)
- touch(path, [date]):
- locks the file at a given path with either an exclusive or shared advisory lock. The path is resolved on the current working directory. Blocks until the lock is acquired, or if a timeout is defined, when that timeout occurs.
- lock(path, "shared|exclusive", [timeout=undefined]):
- Wes Garland
- Kris Kowal
- lock(path, "rw|")
- (Posix:Python: lock)
- lock(path, "shared|exclusive", [timeout=undefined]):
- attempts to acquire an advisory lock a file at a given path but does not block. The path is resolved relative to the current working directory. Does not block if the file is not lockable. Returns whether the lock was obtained.
- Wes Garland
- tryLock(path, "shared|exclusive"):
- lock(path, "rw")
- (Python: lock, PHP: flock($handle))
- releases a lock for a given path.
- unlock(path):
- Kris Kowal
- lock(path, "unlock")
- lock(path, "u")
- (Python: lock, PHP: flock($handle, LOCK_UN))
- unlock(path):
- retrieves an object that represents the metadata of a distinct file, for a given path. The path is resolved relative to the current working directory. The returned object has the properties described in the Stat API.
- stat(path):
- Mario Valente
- (Python: os.stat, Ruby: File.stat, Posix:PHP: stat)
- stat(path):
- retrieves an object that represents the metadata of a distinct file or symbolic link to a file at a given path. The path is resolved relative to the current working directory. The returned object has the properties described in the Stat API.
- stat(path, true):
- Wes Garland
- linkStat(path):
- Kris Kowal
- stat(path, "link"):
- Kris Kowal (as a compromise)
- (Python: os.lstat, Ruby: File.lstat, PHP: lstat)
- stat(path, true):
- returns the size of the corresponding file.
- size(path)
- (Python: size, Ruby: size?: Java: length, Posix: st_size, PHP: filesize)
- returns the total size of a tree of files.
- size(path) // as a special case for a directory
- size(path, "recursive")
- recursiveSize(path)
- returns an IO object for accessing or manipulating the data in a file at a given path. The path is resolved relative to the current working directory. The given permissions object may be a Unix numeric representation of permissions, a Stat object, or any object that provides the members of Stat regarding permissions.
- open(path, "+arwxc", permissions, encoding):
- Mario Valente
- Kris Kowal
- Mode:
- +, update
- a, append
- r, read
- w, write
- x, exclusive (lock)
- c, canon (nonblocking)
- (Java: FileStream classes, Python: open, file, Ruby: File.new, universal precedent among SSJS frameworks)
- open([path,] [mode,] {[path: path,] mode: "+arxwc", permissions: permissions, encoding: encoding})
(keyword-style parameters, first parameter is path or keyword object containing path)- Aristid Breitkreuz
- Kris Kowal
- open(path, "+arwxc", permissions, encoding):
- return a Dir object for a given directory path. The path is resolved relative to the current working directory. The Dir object is an bidirectional iterator of a snapshot of the contents of the directory, and may be either a lazy Array or genuine array, depending on whether the underlying implementation can retrieve indicies on demand.
- list(path)
- (Python: os.listdir, Ruby: Dir, PHP: dir)
- returns an object that, like a Dir, supports the iterator protocol (next, prev) and the Array protocol (length, [index]) for all files that match a given glob pattern.
- The glob pattern may include any of the following productions:
- ? - exactly one character in a path component
- * - any number of characters in a path component
- ** - any number of characters in a path
- {a,b,c} - the letters a, b, or c, or any other union of paths.
- glob(pattern)
- (Ruby: Dir[])
- The glob pattern may include any of the following productions:
- returns whether a given path matches a glob pattern.
- match(pattern, path)
- (Ruby: fnmatch)
- returns a new object that implements the file system API that uses the directory at the given path as its root. Resolves the path relative to the current working directory.
- chroot(path)
Paths
More properites of a FileSystem object.
- a string directing a path up to the parent of the current directory, usually '..'.
- PARENT
- (a function that gets an opaque reference to the actual parent node on the file system, as referenced by the directory's parent hard link, has been deliberately omitted to avoid leaking the capability to access that object from within a chroot file system)
- (Python: pardir)
- a string directing a path back to itself, usually '.'.
- SELF
- (Python: curdir)
- a string that contains the path separator, usually '/', '\', or ':'.
- SEPARATOR
- (Python: sep, Spidermonkey: separator, Ruby: SEPARATOR, Separator)
- a string that contains the alternate path separator, if it exists. Otherwise, undefined.
- ALTERNATE_SEPARATOR
- (Python: altsep, Ruby: ALT_SEPARATOR)
- a string that contains the extension separator, usually '.'.
- EXTENSION_SEPRATOR
- (Python: extsep)
- whether the file system supports unicode file names
- SUPPORTS_UNICODE_FILE_NAMES
- accepts a variadic list of paths as arguments and follows each successive path from the current working directory, left to right, and returns the normalized path of the ultimate file or directory. Paths that end with a directory separator refer to the contents of a directory as a place to continue resolving, whereas paths that do not end with a directory separator indicate that the next path should be followed from the directory containing that file.
- join([path, [path, [path, [...]]]])
- returns the path components for a given path
- split(path)
- takes a string and returns an escaped path component of that string, such that directory separators and other special characters do not partition it into multiple path components
- escape(string)
- (not precedented)
- returns the path of the directory containing a given path.
- dirName(path):
- Kris Kowal
- dirname(path)
- Wes Garland
- (Python: Unix: dirname)
- dirName(path):
- returns the last path component without its extension. The extension begins after the first extension separator.
- baseName(path):
- Kris Kowal
- basename(path):
- Wes Garland
- (Python: Unix: basename)
- baseName(path):
- returns the extension of the given path. The extension begins after the first extension separator.
- extension(path):
- George Mosochovitis
- Kris Kowal
- Wes Garland
- (Ruby: extname)
- extension(path):
- removes '.' path components and simplifies '..' paths, if possible for a given path. If the file system is case sensitive, transforms all letters to lower-case to make them unambiguous.
- normal(path)
- (Python: normpath)
- returns the absolute path, starting with the root of this file system object, for the given path, resolved relative to the current working directory. If the file system supports home directory aliases, absolute resolves those from the root of the file system. The resulting path is in normal form. On most systems, this is equivalent to epxanding any user directory alias, joining the path to the current working directory, and normalizing the result.
- absolute(path)
- (Python: abspath)
- returns the canonical path to a given abstract path. Canonical paths are both absolute and intrinsic, such that all paths that refer to a given file (whether it exists or not) have the same corresponding canonical path. This function may not communicate information about the true parent directories of files in chroot environments. This function is equivalent to expanding an user directory alias, joining the given path to the current working directory, joining all symbolic links along the path, and normalizing the result.
- canonical(path)
- (Python: realpath)
- returns whether a given path has no self and parent path components.
- isNormal(path)
- returns whether the given path is normal and starts with the root of the file system.
- isAbsolute(path)
- (Python: isabs)
- returns whether the given path is the same as the corresponding cannonical path.
- isCanonical(path)
- returns whether the given paths both refer to the same intrinsic file. Both paths are resolved relative to the working directory.
- same(path, path)
Stat Object
- the Date that the file was last accessed.
- atime:
- Tom Robinson
- Kevin Dangoor
- Ondrej Zara
- lastAccessed:
- Kris Kowal
- (Python: getatime, Ruby: atime)
- atime:
- the Date that the file was last modified.
- mtime:
- Tom Robinson
- Kevin Dangoor
- Ondrej Zara
- lastModified:
- Kris Kowal
- Mario Valente
- Daniel Friessen
- (Python: getmtime, Ruby: mtime, Java: Spidermonkey: Helma: lastModified, jslibs: modifyTime, EJScript: modified, Synchronet: date)
- mtime:
- the Date that the file's stat/metadata was last modified.
- ctime:
- Tom Robinson
- Kevin Dangoor
- Ondrej Zara
- lastChanged:
- Wes Garland
- Kris Kowal
- (Ruby: ctime, Python: getctime)
- ctime:
- the Date that the file was created, if the underlying file system makes that datum available (most Unix systems do not store creation time, but Windows and some Unix varieties do). Returns undefined if the underlying file system does not provide a time.
- created:
- creationTime:
- firstModified:
- omit entirely:
- Kris Kowal
- (Spidermonkey: jslibs: creationTime, EJScript: create)
- a String name for the type of the file. One of: "file", "directory", "characterSpecial", "blockSpecial", "fifo", "link", "socket", or "unknown"
- type:
- kind:
- omit entirely:
- Kris Kowal
- whether the corresponding object is a file (not a directory).
- isFile:
- Kris Kowal
- isFile:
- whether the corresponding object is a directory
- isDirectory
- (Spidermonkey: isDir, Helma: isDir, JSExt: isdir)
- whether the corresponding object is a symbolic link
- isLink
- whether the corresponding object is a mount point
- isMountPoint:
- omit entirely:
- Wes Garland
- Ondrej Zara
- whether the corresponding object is a socket
- isSocket
- whether the corresponding object is a pipe
- isPipe
- isFifo
- whether the correpsonding object is a block device
- isBlockDevice
- the size of the corresponding object in bytes
- size
- Ondrej Zara
- (jslibs: size, Helma: getLength, Spidermonkey: wxJS: EJScript: Synchronet: length)
- size
- the name or id of the owner of the file (following symlinks)
- owner
- the name or id of the group owner of the file (following symlinks)
- groupOwner
- the name or id of the owner of the file or symbolic link
- linkOwner
- the name or id of the group owner of the file or symbolic link
- linkGroupOwner
- whether the owner of the process at the time of this stat object's construction is the same as the owner of this file.
- owned
- whether the corresponding object can be opened for reading by the current process owner
- isReadable
- whether the corresponding object can be opened for writing by the current process owner
- isWritable
- whether the corresponding object is an executable for the current process owner
- isExecutable
- whether the corresponding executable file will be forced to run as the owner of the file if any user executes it.
- executesAsOwner
- setuid
- whether the corresponding executable file wil be forced to run with its group owner if any user executes it.
- executesAsGroupOwner
- setgid
- whether the corresponding directory will permit anyone to create files in it, but only let the owner of a file delete it.
- sticky
- an object that represents the permissions granted to the owner of the file.
- This object would contain:
- isReadable
- isWritable
- isExecutable
- ownerPermissions
- This object would contain:
- an object that represents the permissions granted to the group that owns the file.
- The object would contain:
- isReadable
- isWritable
- isExecutable
- groupPermissions
- The object would contain:
- an object that represents the permissions granted to anyone who has no claim to the file.
- The object would contain:
- isReadable
- isWritable
- isExecutable
- worldPermissions
- The object would contain:
- returns an object that represents the permissions granted to the user corresponding to a particular name or identifier.
- The returned object would contain:
- isReadable
- isWritable
- isExecutable
- getPermissions(user)
- The returned object would contain:
- the inode/vnode number of the underlying object (optional)
- inode
- the device number of the underlying object (optional)
- device
File Object
File objects can only be constructed by methods of FileSystem objects. Different IO types might be returned for calls to open with different modes, generally following the protocol outlined in Python's PEP 3116.
IO Objects
- reads as many bytes as are available from an IO stream and returns the number of actually read bytes.
- read()
- reads as many bytes as are available but less than a given number from an IO stream and returns the number of actually read bytes.
- read(n)
- reads a line of characters from a line buffered IO object. Returns a blank line on EOF.
- readLine()
- (Python: JSExt: readline, Spidermonkey: Helma: Synchronet: readln)
- returns an Array-like view of the lines in an IO stream, or simply an Array of Strings.
- readLines()
- (Python: readlines, JSExt: readlines, EJScript: getLines)
- returns the next line in the stream. Throws a StopIteration exception on EOF.
- next()
- returns an iteration on the lines of the IO stream, which is simply itself since it implements "next".
- iter()
- calls a relation with each line of input from the IO stream.
- forEach(relation)
- reads bytes into a buffer, up to as many as the length of the buffer, pending availablility. Returns the number of bytes actually read.
- readInto(buffer)
- writes bytes to a stream. Returns the number of bytes that were actually written.
- write(buffer)
- moves the position of the cursor in a random access IO stream.
- Accepts a code that determines whether to move the position relative to the beginning, end, or current position:
- 0 or "begin": beginning of file (default)
- 1 or "relative": current position
- 2 or "end": end of file
- seek(pos, whence)
- (universal precedent)
- Accepts a code that determines whether to move the position relative to the beginning, end, or current position:
- returns the current position of the random access cursor for an IO stream. The position may be a "cookie" object or a Number, depending on the IO type.
- tell()
- (wxJS: JSExt: Python: Ruby: tell)
- truncates the size of a file to the current cursor position or a given position, which must be either a "cookie" object or a Number, depending on the IO type.
- truncate(pos)
- (Ruby: truncate, Python: ftruncate)
- returns whether the cursor is at the end of the IO stream.
- eof()
- Kris Kowal
- atEOF():
- Wes Garland (non-commital)
- (Helma: wxJS: JSExt: Synchronet: eof)
- eof()
- flushes buffers for an IO stream
- flush()
- (universal precedent)
- blocks until an advisory lock is acquired. Throws an error if a lock cannot be acquired on the system.
- lock("exclusive|shared")
- tries to grab an advisory lock without blocking, and returns whether it succeeded.
- tryLock("exclusive|shared")
- (related to isOpen in many existing SSJS frameworks, but without a race condition hazard)
- releases an advisory lock.
- unlock()
- closes a stream
- close()
- whether the IO stream is readable
- isReadable
- whether the IO stream is writable
- isWritable
- whether the IO stream supports random access
- isSeekable
- whether the IO stream is attached to a virtual or real teletype.
- isTTY:
- Wes Garland
- isTty:
- Kris Kowal
- isTTY:
- the descriptor of the underlying file, an opaque reference to the file descriptor, or undefined if file descriptors are not supported.
- fileNo
- the underlying unbuffered IO stream, if it exists. Otherwise undefined.
- raw
- creates a duplicate of the IO stream, with its own buffereing and cursor.
- copy()
- Kris Kowal
- dup()
- copy()
Notes for Further Discussion
- input, output, stdin, stdout, STDIN, STDOUT
- ...placed on environment or in a module?
- separation of knowledge of paths between file system and files
- currentDirectory, getCurrentDirectory
- temporary files and directories
- opening a temp file with an implied immediate exclusive lock
- dup and dup2 and other file-descriptor specific constructs for permissive environments.
- canRead, canWrite, poll, select
- taxonomy of IO classes
- default encoding for String, line-buffered IO
General Preferences
- make vs. create
- make:
- Mario Valente,
- Wes Garland (but only for directories)
- Kris Kowal (but only for directories)
- create:
- George Moschovitis,
- Wes Garland (but only for files)
- Kris Kowal (but only for files)
- Ondrej Zara
- make:
- dir vs. directory
- directory:
- Tom Robinson,
- Kevin Dangoor,
- George Mosochovitis,
- Wes Garland
- Ondrej Zara
- dir:
- Mario Valente
- directory:
- cur vs. current
- current:
- Tom Robinson,
- Kevin Dangoor,
- Wes Garland,
- Kris Kowal,
- Mario Valente
- Ondrej Zara
- George Moschovitis
- cur:
- current:
- canonize, realize, normalize, qualify, cannon, real, normal, qualified, absolute, cannonicalize
- remove . and ..:
- normalize:
- Tom Robinson,
- Kevin Dangoor,
- Kris Kowal,
- George Mosochovitis
- qualify:
- Wes Garland
- expand:
- Ondrej Zara
- normalize:
- remove . and .., start at /:
- absolute:
- Tom Robinson,
- Kevin Dangoor,
- Kris Kowal,
- George Mosochovitis,
- Wes Garland,
- Mario Valente
- qualified:
- Wes Garland
- normalize:
- Ondrej Zara
- absolute:
- remove . and .., start at /, follow symlinks:
- canonical:
- Tom Robinson,
- Kevin Dangoor,
- Kris Kowal
- absolute:
- George Mosochovitis,
- Wes Garland,
- Mario Valente,
- real:
- Tom Robinson,
- Kevin Dangoor
- qualified:
- Wes Garland
- canonical:
- remove . and ..:
- constantCase, CONSTANT_CASE, kConstantCase
- CONSTANT_CASE:
- Tom Robinson,
- Kevin Dangoor
- Ondrej Zara
- George Moschovitis
- constantCase:
- Kris Kowal,
- Wes Garland,
- Mario Valente,
- CONSTANT_CASE:
- "static" methods
- require(module).staticMethod:
- Kris Kowal
- Wes Garland
- Mario Valente
- Ondrej Zara
- require(module).Klass.staticMethod:
- Tom Robinson
- George Mosochovitis
- require(module).staticMethod:
- properties, accessors, mutators
- foo.setX(x); foo.getX()
- For:
- Against:
- foo.setX(x); foo.X()
- For:
- Against:
- no convention
- For:
- Against:
- foo.x = x; foo.x
- For:
- Davey Waterson
- Wes Garland
- Daniel Friesen
- Sam Phillips
- Against:
- Tom Robinson
- Kris Kowal
- For:
- foo.setX(x); foo.getX()
References
- http://www.python.org/dev/peps/pep-3116/
- PEP on new File IO
- http://java.sun.com/j2se/1.4.2/docs/api/java/io/File.html
- Java File API
- http://java.sun.com/j2se/1.4.2/docs/api/java/io/FileOutputStream.html
- Java Output API
- http://java.sun.com/j2se/1.4.2/docs/api/java/io/FileInputStream.html
- Java Input API
- http://www.erights.org/javadoc/java/io/File.html
- E Secure File API
- http://www.cs.berkeley.edu/~daw/joe-e/api/org/joe_e/file/Filesystem.html
- Joe-E Secure File System API
- http://docs.python.org/library/os.path.html
- Python Path API
- http://www.ruby-doc.org/core/classes/File.html
- Ruby File API
- http://www.ruby-doc.org/core/classes/IO.html
- Ruby IO API
- http://spreadsheets.google.com/pub?key=p9uiX8MUHeTiP0kPT591RUw
- A matrix of existing ServerJS File API nomenclature and support