@filefreak.io/sdk

中文文档
0.20.0发布于 2026/11/11Apache-2.0TypeScriptES Module零依赖近 30 天下载 4374

FileFreak的开发者API用于节点和浏览器:每个端点,直接上传到部分存储,下载范围,以及接下来的更改.

中文使用文档
文档目录12 节
  1. 在服务器上
  2. 每次下载都被检查
  3. 一个大文件的新版本
  4. 在网页中
  5. 预览
  6. 一个较小的图像
  7. 从链接中保存
  8. 每个终点
  9. 读取到结尾
  10. 当上传停止时
  11. 当某事被拒绝时
  12. 许可证

@ filefreak.io/sdk (英语)

FileFreak 开发者 API,来自 TypeScript 或 JavaScript, 在节点 20 和 后入并入于浏览器. 无相依相.

每个端点都是函数,从相同的表格中键入 API 构建 从. 周围:直接上传至部分存储并继续进行 中断后, 一个大文件的新版本只发送什么 已更改, 下载到区域中, 并对照文件 SHA-256,列表和修改读取到尾端,被发送并读取的被Shard Protection下的文件被密封 通过他们的地图,共享链接所保存的没有密钥,并且请求仅在此时再次发出 无法使任何东西两次。 参考文献为: https://filefreak.io/developers/参考文献 互联网档案馆的存檔,存档日期2014-12-22。 。 。 .

在服务器上

import { FileFreak } from "@filefreak.io/sdk";
import { fromPath, toPath } from "@filefreak.io/sdk/node";

const ff = new FileFreak({ apiKey: process.env.FILEFREAK_KEY });

const { item: folder } = await ff.folders.create({ name: "uploads", ifExists: "use" });
const file = await ff.upload(await fromPath("film.mp4"), {
  parentId: folder.id,
  onProgress: (sent, total) => console.log(`${Math.round((sent / total) * 100)}%`),
});

await ff.download(file.id, await toPath("copy.mp4"));
const bytes = await ff.bytes(file.id); // for a file small enough to hold in memory

fromPath 在发送时读取文件的一部分, 所以文件更大 比记忆还好. toPath 在文件旁边写并给出它的名字 只有每个字节存在一次:一个失败的下载会留下一无所有. 在Shard Protection下的文件没有地址 download 财务报告和审定财务报表 bytes 在地图上读一下,每个碎片都检查过了 一个 以粗体格式第2版所写,按其内容剪去的块表示: 读取方式相同,在获取任何块前检查其大纲. 进入Shard保护下的文件夹, upload 以 文件在发送前是自己的密钥, 所以文件中没有任何一个是普通的 存储。 键是用于上传的 API , 并且没有被保存到 上传一个询问,在发送任何文件之前,哪些片段储存.

保存在存储中的文件会在读取时重新组合,从 0.7.0 (英语). download, (中文(简体) ), bytes 财务报告和审定财务报表 get 问其地址 说他们可以, 取出每个地方作为地址,并充气 存储压缩, 每一个检查以给出精确的 API 版式 说它坚持。 不添加的文件被拒绝, 且没有保存 : layout 当布局本身没有的时候, blob_size 存储时 比它说, place_damaged 当一个地方不是储藏的 place_unavailable 当存储在多次尝试后不会给出.

上传到公共文件夹或取代公共文件的文件是 从未被压缩过,档案、图片、视频或 安装器(其中AppImage、msi或pkg)。 内容 publicUrl 给 它的字节,用于下载链接或 <img>。一个存储在压缩之前 它被公之于众 packed: true,以及 publicUrl 打开它的页面, 它在浏览器中重现: 再次上传到公众 用于提供字节的地址的文件夹.

在服务器上保留密钥 。 从网页发送的密钥被拒绝 .

每次下载都被检查

每一次上传都会从它发送的字节中找到它的SHA-256 记录在文件,从0.15.0, 无论是否 sha256 给出; 1 给定时与它相对应。 每次下载, bytes 财务报告和审定财务报表 get 开什么玩笑 写它和API给文件的 SHA-256 相比较,从来没有 一个从存储器读取,所以一个文件在存储器中或途中更改被捕获. 一个不匹配抛出 IntegrityError 其水槽被中止,所以 toPath 留下任何东西.

import { IntegrityError } from "@filefreak.io/sdk";

const got = await ff.download(file.id, await toPath("copy.mp4"));
got.verification; // { verified: true, by: "sha256", sha256: "1a2b..." }

verification 说如何检查: by: "sha256"· ; by: "seals" (单位:千美元) 在Shard 保护下的文件, 每件文件都要对照它的封条检查 当它到达时;或 verified: false 与 reason: "no_checksum" 用于文件 2026年11月前从网站发送的文件 对. get 给出它保存的每个文件 verification 属于自己的.

一个大文件作为数个范围同时取出,从中运出 秩序。 秩序。 所到之事,已随所至而散去;所取之事,已读回去 一旦每个字节被写成,就从水槽中报告 onVerifying该 需要水槽拥有 read,哪个 toPath 财务报告和审定财务报表 bytes 有; 您的下水道 自己没有它,则按顺序给文件,作为一个范围,较慢. { verify: false } 当下载到达时, 正在写入, 不加限制 .

在网页上, @filefreak.io/sdk/badge 显示: 有盾牌的"验证", 当它被打开,那意味着什么.

import { verifiedBadge } from "@filefreak.io/sdk/badge";

row.append(verifiedBadge(got.verification));
// After an IntegrityError: verifiedBadge(null, true), "Did not match".

它吸收了自身的影子根而没有任何依赖性. 它的颜色是 --filefreak-verified-good, (中文(简体) ), --filefreak-verified-bad 财务报告和审定财务报表 --filefreak-verified-muted检查结果显示,文件是 上传; 它不表示文件可以安全打开 .

一个大文件的新版本

16个米B以上的文件在发送和剪切前被读取 它的内容说,每个部分都是它的块之一。 一个新的版本 它,发送与 onConflict: "replace",只发送文件的块 还没有:那些它与里面的新的东西结合在一起 存储。 SDK 和 CLI 切出一个文件, 所以下一个版本的文件 不管是谁派来的 都不要离开.

await ff.upload(await fromPath("disk.img"), { parentId: folder.id, onConflict: "replace" });

在Shard Protection的文件夹中,每个块都一样 离开前加密了 超过 16 MiB 的保护文件被剪切 它自己的钥匙,这样没有钥匙的任何人都可以照样剪掉它的副本 方法与比较,它的下一个版本 保留了最后一个的块 当密钥可能读取文件时; 只能写入的密钥启动新文件 键并发送每个块。 每个区块在发送时都会再次被读取 检查上传的起始内容, 因此文件在上传时更改 发送停止上传( i)source_changed),而不是存储两个组合.

在网页中

页面是由您的服务器给出一个符号 。 你的服务器是用它的 键 :

// On your server, behind your own sign-in.
const { token } = await ff.tokens.create({
  scopes: ["files:read", "files:write"],
  folderId: customerFolderId,
  expiresInSeconds: 900,
});

页面用它作为钥匙 鉴于一个职能而不是一个 字符串中, SDK 请求您的服务器在最后一个符号耗尽时需要一个新的符号 :

import { FileFreak } from "@filefreak.io/sdk";

const ff = new FileFreak({
  token: async () => (await fetch("/my-server/filefreak-token")).text(),
});

const input = document.querySelector<HTMLInputElement>("input[type=file]")!;
const file = await ff.upload(input.files![0]!); // into the token's folder

一个标志可以做它的关键可能,或更少的: 范围要求 请求文件夹, 从一分钟到一小时。 检查其密钥 每一个请求,所以撤销钥匙 停止它的标志立即。 符号不能 做另一个.

预览

服务完成后, 在上传几分钟内, 就会有文件 已经 thumbnailUrl,一个图像的小WebP图片,一个来自 iPhone, PDF 第1页, 音频文件标签或框中的封面 视频;或 previewTextUrl,文本或代码文件的第一行 文档,作为文本。 两者都是存储本身的地址,不需要钥匙. 每个都是一样的一天,所以一个浏览器 保留它得到的东西,并获取 一无是处 它们是无效的,直到制作, 和一个没有文件.

const { items } = await ff.files.list({ parent: folder.id });
for (const item of items) {
  if (item.thumbnailUrl) gallery.append(Object.assign(new Image(), { src: item.thumbnailUrl, alt: item.name }));
}

files.preview(item) 取出一个,并把它还回来 准备使用,因为 { kind: "picture", bytes, contentType: "image/webp" } 或者说 { kind: "text", text },或者对一个没有的文件无效. files.previewsOf(items) 一次对许多人做同样的事情,就像一张由 id 绘制的地图,留下文件 没有.

const previews = await ff.files.previewsOf(items);
for (const [id, preview] of previews) {
  if (preview.kind === "text") console.log(id, preview.text.split("\n")[0]);
}

服务从不看视频, 所以视频的照片是一个框架 你来 在网页上, upload 从文件中画出一秒钟左右 页面已存在,一旦文件存储就发送,而不上传 等待着它; frame: false 无。 在服务器上,将 JPEG 制作为 并发送:

import { execFile } from "node:child_process";
import { readFile } from "node:fs/promises";
import { promisify } from "node:util";

// The frame a second in, 960 pixels wide, as a JPEG.
await promisify(execFile)("ffmpeg", ["-ss", "1", "-i", "film.mp4", "-frames:v", "1", "-vf", "scale=960:-2", "-y", "frame.jpg"]);
await ff.files.sendFrame(file.id, new Blob([await readFile("frame.jpg")]));

视频的照片是JPEG,最多2 MB,发送一次. Shard 下的文件 保护没有预览 .

一个较小的图像

files.image(id, { size }) 不再提供图像副本的地址 比起来 size 最长的一面像素, 如相机元数据 WebP 删除:64、128、256、512、1024或2048。 每个尺寸一次,第一个 时间要求,并保存。 直到得到答案为止 { status: "pending", retryAfterSeconds },那么那么在那么长的时间之后再问:

async function sized(id: string, size: number) {
  for (;;) {
    const answer = await ff.files.image(id, { size });
    if (answer.status === "ready") return answer; // { url, width, height, expiresAt }
    await new Promise((r) => setTimeout(r, answer.retryAfterSeconds * 1000));
  }
}

在图像上传时命名大小, 并在图像上传时准备好 通缉: ff.upload(file, { imageSizes: [512, 2048] })。公开文件 不需要这些:添加 ?size=512 联合国 publicUrl。 。 。 .

get 保存共享链接或公共页面。 它不需要钥匙,而且 没有任何信息显示是谁在问:没有密钥,从浏览器看没有 饼干。 文件会进入一个槽; 文件夹需要某个位置 文件,哪个 toFolder 在磁盘上.

import { get } from "@filefreak.io/sdk";
import { toFolder, toPath } from "@filefreak.io/sdk/node";

await get("https://filefreak.link/share/...", await toPath("report.pdf"));

const got = await get("https://filefreak.link/share/...", toFolder("downloads"), {
  password: "open sesame", // for a link that has one
  onProgress: (written, total) => console.log(`${written} of ${total} bytes`),
});
console.log(`${got.files.length} files, ${got.sizeBytes} bytes`);

它需要一个共享链接,一个公共文件或文件夹的页面,一个文件的直接 地址 电话 文件夹全部到来: 每个文件到函数生成的下沉 因为它的名字和文件夹。 每个保存的文件都是其中之一 链接的下载,如其页面上的下载, 以及左下方的链接 文件不保存( e)not_enough_downloads) (中文(简体) ). Shard 下的文件 保护通过链接的地图读取,并计算一次. 每个文件都是 检查为 download 对照SHA -256 连接自己的网站 给它.

链接给出的每一个名称都是其共享者,并且可以是任何东西: ../../.bashrc, (中文(简体) ), 或者一个反向读取. toFolder 让每个人都安全 safeName 在写前, 并且从不在文件夹外写它。 一个程序 来自链接本身的名称文件应当使用 safeName 我也一样.

每个终点

这些功能被归类为参照组: ff.files, (中文(简体) ), ff.folders, (中文(简体) ), ff.tree, (中文(简体) ), ff.changes, (中文(简体) ), ff.uploads, (中文(简体) ), ff.usage, (中文(简体) ), ff.me, (中文(简体) ), ff.tokens 财务报告和审定财务报表 ff.shares (共享链接, 只有设备签名) 输入 filefreak login 可能这样做)和 ff.sites 一个应用程序的网站,与 允许的密钥 sites:deploy地址上的证件先来,然后是尸体或 查询,然后选择:

const { items, nextCursor } = await ff.files.list({ parent: folder.id, limit: 50 });
await ff.files.update(file.id, { name: "renamed.mp4" });
await ff.files.delete(file.id, { permanent: true });
await ff.sites.update(site.id, { singlePage: false }); // missing pages are 404s again

ff.call("files.get", { params: { id } }) 达到任何终点 名称.

读取到结尾

for await (const item of ff.files.each({ parent: folder.id })) console.log(item.name);

// Everything under a folder, then only what changes.
const walk = ff.tree.walk({ parent: folder.id });
for await (const item of walk) keep(item);
for await (const answer of ff.changes.follow(walk.changesCursor)) {
  for (const change of answer.changes) apply(change);
  save(answer.cursor); // to carry on from after a restart
}

follow 在API上等待下一次更改,一次一分钟,然后去 ,直到循环左出或其出 signal 已中止.

复制件,也发送自己的更改 后名的文件,因为它读它, 这样它就不会重复或删除它没有看到的变化。 无论是 以409拒绝 revision_changed 如果文件已移动 :

await ff.upload(source, { name: file.name, parentId: file.parentId, onConflict: "replace", replacing: { id: file.id, revision: file.revision } });
await ff.files.delete(file.id, { ifRevision: file.revision });

当上传停止时

所到达的存储被保存到上传过期 。 保留上传代码 从 onBegun,并使用同一文件进行:只有部件存储 未发送。 按内容剪取的文件被逐个块地带入, 每个都检查了上传开始的内容, 所以继续另一个 文件在第一个块被拒绝.

import { UploadStopped } from "@filefreak.io/sdk";

try {
  await ff.upload(source, { name: "big.iso", onBegun: (u) => remember(u.id) });
} catch (e) {
  if (e instanceof UploadStopped) await ff.upload(source, { resume: e.uploadId });
  else throw e;
}

当某事被拒绝时

拒绝是 FileFreakError,与API的 status页:1 code 没错 不改变,什么是树枝,a message 为了一个人.

import { FileFreakError } from "@filefreak.io/sdk";

try {
  await ff.folders.create({ name: "reports" });
} catch (e) {
  if (e instanceof FileFreakError && e.code === "name_taken") {
    // already there
  } else throw e;
}

SDK只有在不能做两次任何事时才会再次发出请求: a 已读;请求中包含一个“同上强度-关键”键,它为每个端点都提出了该键 尊贵的,除非你们自受其赐{ idempotencyKey } 输入 选项); 完成上传或制作令牌;或 回答不说 已经做了,例如429。 当服务在静静地咒语后醒来 等待,最多几分钟. Retry-After 很荣幸.

许可证

阿帕奇2.0 (英语).

版本与发布记录

@filefreak.io/sdk 共发布 23 个版本,首次发布于 2026/10/26;过去 12 个月发布了 23 个版本。

版本发布日期距今
0.20.0latest2026/11/113 天前
0.19.02026/11/104 天前
0.18.02026/11/095 天前
0.17.02026/11/086 天前
0.16.02026/11/068 天前
0.15.02026/11/068 天前

关于 @filefreak.io/sdk 的常见问题

@filefreak.io/sdk 是什么?

FileFreak的开发者API用于节点和浏览器:每个端点,直接上传到部分存储,下载范围,以及接下来的更改.

如何安装 @filefreak.io/sdk?

在项目目录运行 npm install @filefreak.io/sdk,或使用 pnpm add / yarn add / bun add。

@filefreak.io/sdk 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@filefreak.io/sdk 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@filefreak.io/sdk 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@filefreak.io/sdk 可以商用吗?

@filefreak.io/sdk 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@filefreak.io/sdk 的下载量有多少?

根据 npm 官方下载统计,@filefreak.io/sdk 在 2026/10/15 – 2026/11/13 这 30 天内被下载 4,374 次,日均约 146 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@filefreak.io/sdk 还在维护吗?

最新版本 0.20.0 发布于 2026/11/11(3 天前);至今共发布 23 个版本,其中过去 12 个月发布了 23 个;首次发布于 2026/10/26。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。