@ freeappstore/ sdk (英语)
浏览器 SDK 用于发布于 freeappstore. online 在线。 。 。 .
PWA 生命周期 API 生活在 @freeappstore/sdk/pwa,在
@freeappstore/sdk/pwa-config。见 安全更新和离线能力。 。 。 .
设备本地首选项、索引数据库和大文件元数据实时
@freeappstore/sdk/persist。这些数据不是注册账户。 账户
键还原 fas.kv。失败的保存返回状态而不是丢弃状态
成功之路,腐败的价值观依然存在。 见
设备本地持久性。 。 。 .
经验证的备份、导入和浏览器文件导出时间为 @freeappstore/sdk/backup。 。 。 .
这个子路径需要 @freeappstore/sdk >=0.16.21。 。 。 .
应用程序拥有记录和合并政策. 导入是全或全无的,是的
在安装或删除能力时,不删除数据。 见
备份和文件导出。 。 。 .
安装
npm i @freeappstore/sdk
使用量
import { initApp } from '@freeappstore/sdk';
const fas = initApp({ appId: 'my-app' });
// Capture the OAuth callback if we're returning from sign-in. Call this once
// at app start, before any UI that depends on auth state.
await fas.auth.init();
// React to sign-in / sign-out.
fas.auth.onChange((user) => {
console.log(user ? `Hello @${user.login}` : 'signed out');
});
// Trigger sign-in (redirects to GitHub).
document.querySelector('#signin')?.addEventListener('click', () => {
fas.auth.signIn();
});
模块
认证
GitHub OAuth通过重定向. 持续进行 localStorage。 。 。 .
fas.auth.user; // User | null
fas.auth.token; // string | null
fas.auth.signIn(); // redirects to GitHub
fas.auth.signOut(); // signs out of this app
fas.auth.onChange(cb); // fires immediately + on change, returns Unsubscribe
await fas.auth.init(); // capture callback, must be called once
数据存取合同
| 型号 | 服务 | 保证 |
|---|---|---|
| 设备本地 | @freeappstore/sdk/persist | 仅此浏览器配置和来源; 不是账户同步 . |
| 私人账户 | fas.kv | 服务器侧 (appId, userId) 孤立; 需要认证. |
| 共享文件 | fas.collections | 直到应用程序所有者分享收藏(fas db share);然后公开阅读,只写所有者. 共享收藏即使由所有者进行查询过滤,也是公开的. |
| 房间限制 | 后端数据室 HTTP API | 经认证的终点 强制加入会议室。 它们与公共收藏和实时会议室广播分开;SDK尚未提供包装. 见 数据室 API。 。 。 . |
一个收藏是 'private' (只拥有者) 默认. fas.collections.collection(name, { visibility: 'public-read' }) 在代码中声明收藏是共享的; 服务器执行应用程序所有者设定的内容 fas db share。任何其他可见度被 SDK 类型和运行时间拒绝.
用户名 KV
私人每个账户云存储范围 (appId, userId) 服务器侧 。 用于跟踪用户在设备上签名的数据。 请求需要账户;不要在登录后打开无关的公共屏幕.
await fas.kv.set('theme', { color: 'plum' });
const theme = await fas.kv.get<{ color: string }>('theme');
await fas.kv.delete('theme');
const allKeys = await fas.kv.list();
const noteKeys = await fas.kv.list({ prefix: 'note:' });
const notes = await fas.kv.getMany<Note>(noteKeys);
// All methods accept { signal } for AbortController cleanup
const ctrl = new AbortController();
await fas.kv.get('key', { signal: ctrl.signal });
限制(服务器强制):每个用户最大1MB,每个用户最大100个密钥,每个值最大64KB.
共享计数器
App-wide原子计数器——不是用户范围. 任何人都可以阅读;认证用户可以递增. 降级保留给具有特权的应用程序所有者和用户(除此之外的其他任何) member 编号 : viewer) (中文(简体) ). 用于计票,取景计票,领跑板.
// Read (no auth required)
const all = await fas.counters.list(); // { likes: 5, views: 100 }
const views = await fas.counters.get('views'); // 100
// Increment (auth required)
const newVal = await fas.counters.increment('likes'); // +1, returns new value
const newVal2 = await fas.counters.increment('score', 10); // +10
await fas.counters.increment('lives', -1); // decrement — owner / privileged role only
限制:每个应用程序的最大1000个计数器,每起呼叫的增量范围为-1000至+1000.
实时会议室
持久目标支持的WebSocket粉丝出道. 以至——信息没有持续存在。 以光标存在,光合作用,和斯利特风格的多人游戏机(低状态,高频)为标码.
const room = fas.rooms.join('lobby');
room.onPeers((peers) => console.log('peers:', peers));
room.onMessage<{ text: string }>((msg) => {
console.log(msg.from, msg.data.text);
});
room.send({ text: 'hello' });
// later:
room.close();
房间提供电平实时广播,而非耐用存储. 房间默认向任何登录用户开放. fas.rooms.join('staff', { private: true }) 标记一个私人房间:从那时起,只有拥有该应用程序的应用角色的用户(该应用程序的拥有者,或拥有者授予的角色与角色 API member 每个用户自动得到的角色不计数)可以加入,只有这样的用户才能让房间变得私密. 每个人都得到 room.denied === true (状态) error,没有重试). { private: false } 打开一个私人房间。 能够加入的私人房间大门;消息仍然被麻风广播,而不是存储. 除谁可以加入外,不要声称保密。 限制(服务器强制执行):每间32个同龄人,每同龄人100msg/sec,每条信息4KB,24h闲置驱逐,每套应用软件64个活动房间.
收藏(文件数据库)
可查询数据的文档存储 。 默认情况下,文件对所有人是保密的; fas db share <collection> 让每个人阅读一个集合(认证的拥有者仍然只写自己的集合). owner 只有你自己的身份证明,和 _owner 被隐藏于其他用户。 不需要SQL——只要JSON进入,JSON退出.
const posts = fas.collections.collection('posts', { visibility: 'public-read' });
// Create (auth required, you become the owner)
const post = await posts.create({ title: 'Hello', body: '...' });
// Query (your own documents, or everyone's once shared)
const { documents, total } = await posts.query({
limit: 20,
orderBy: 'created_at',
order: 'desc',
owner: userId, // optional: only ever your own id
});
// Get single document
const doc = await posts.get('doc-id');
// Update (owner only)
await posts.update('doc-id', { title: 'Updated' });
// Delete (owner only)
await posts.delete('doc-id');
限制:每集一万份文件,每份文件64KB.
免费 APIs 库( 不需要代理) (L)
许多有用的工具不需要 API 键 。 直接使用它们:叶片 (地图), Recharts (图表), Tiptap (丰富的文本), 日期-fns, 反应-markdown, qrcode. react, dnd-kit (drag & drop), Framer Motion, Lucide React (icons), React Hook Form, Zustand. 自由APIs:Open-Meteo (weather),Nominatim (geocoding),OSRM (路由),REST国家等. 见 杀手,md 完整名单.
加密输入代理
对于DO需要密钥的API,代理加密并注入服务器侧.
const res = await fas.proxy.fetch('api.openweathermap.org/data/2.5/weather?q=London');
const data = await res.json();
用户 API 密钥默认值
用户将自己的API密钥存储在平台上(加密了AES-256-GCM). Apps 从未看到纯文本密钥 .
// Check if user has a key configured
const hasKey = await fas.keys.has('openai');
// Redirect to platform key management page
fas.keys.manage('openai');
// Check all configured providers
const keys = await fas.keys.status();
被支持的提供商:OpenAI,Anthropic,Google AI,OpenRouter,复制,稳定AI,11Labs.
按下提醒键( P)fas.push(中文(简体) )
为登录用户预定的 Web Push 通知 。 当提醒到期(每15分钟检查一次)时,平台会向用户的每个设备发送一个推力,用于您的应用程序.
const { supported, reason } = fas.push.isSupported();
// reason 'requires-home-screen': on iPhone/iPad, add the app to the Home Screen first
// From a button tap (browsers block permission prompts outside a user gesture):
await fas.push.subscribe(); // asks permission, registers this device
await fas.push.schedule('period-due', { at: new Date('2026-11-02T09:00') });
await fas.push.schedule('log', { daily: '21:00' }, { quietHours: { start: '22:00', end: '07:00' } });
await fas.push.schedule('refill', { everyDays: 28, at: '09:00' }, { tz: 'Europe/London' });
const reminders = await fas.push.list(); // [{ reminderId, when, tz, quietHours, nextAt }]
await fas.push.cancel('log');
await fas.push.unsubscribe(); // this device only
错误 : PushNotSignedInError, (中文(简体) ), PushNotSupportedError (与 reason, (中文(简体) ), PushPermissionDeniedError, (中文(简体) ), PushNotConfiguredError。 。 。 .
推来推去 无有效载荷: 您的服务人员会显示通知文本, 所以提醒不会通过浏览器的推取服务 。 带着花花公子 injectManifest 策略,请将此添加到您的服务人员中:
import { registerFasPushHandler } from '@freeappstore/sdk/push-sw';
registerFasPushHandler({ title: 'Cycle', body: 'Time to check in.', onClick: () => '/' });
保留任何敏感的文字通用;它可以显示在锁屏幕上. 限制:每个应用程序有10个装置和20个提醒器.
反应钩
从 @freeappstore/sdk/hooks。要求将18+作为同伴依赖.
import { useAuth, useTheme } from '@freeappstore/sdk/hooks';
function App() {
const { user, loading, signIn, signOut, deleteAccount } = useAuth(fas);
const { theme, preference, setPreference } = useTheme();
// ...
}
应用程序外壳
每个应用程序都包入 Shell 从 @freeappstore/sdk/ui:上栏(应用程序名称、文本大小、主题、配置页的可视链接),应用程序的主要导航来自 nav,以及一个错误的边界,装入倒数,土司区域,离线横幅,并跳过屏幕周围的链接. 浮雕打开 /profile gitHub 和 Google 签出时的签入选择,签入时的帐号和首选项。 过 profileHref 用于一个应用程序的配置文件路径。 可选的登录门( :requireAuth)保护app内容,同时保持配置页面的可访问性.
import { type NavItem, PageHeader, Shell, useToast } from '@freeappstore/sdk/ui';
const NAV: NavItem[] = [
{ label: 'Notes', href: '/', title: 'Notes' },
{ label: 'Tags', href: '/tags', title: 'Tags — Notes' },
];
<Shell app={fas} appName="Notes" nav={NAV} onNavigate={navigate}>
<Screen />
</Shell>
// In a screen: its single h1, and feedback through the shell
<PageHeader title="Tags" />
const toast = useToast(); toast.show('Saved', { variant: 'success' });
onNavigate 使 nav 点击客户端侧(在路由更改时处理滚动和焦点);没有它,项目就是普通链接. FasShell 在其旧名下是同一组成部分。 全文 : 文献/文献。 。 。 .
奥米 profileHref 雕像打开了内嵌 /profile 页 次ProfilePage在两个认证州。 设定 profileHref 并让两个州都成为自己. headerActions 是标题控制槽。 自定义框架用途 ToastProvider, (中文(简体) ), AccountSection,以及路由器帮助器,而不是补补壳DOM. ProfileMenu 是一个遗留下来. Shell 不挂载。 布局属性 : 可混合启动合同. 移徙: 从 DOM 上移。 。 。 .
UI 组件
滴入反应组件 。 从 @freeappstore/sdk/ui. 组件使用 CSS 自定义属性( :--ink, (中文(简体) ), --accent)),以融合入您的应用主题.
import {
Shell, PageHeader, NavBar, useToast, useDocumentTitle, useOnline,
Avatar, SignInButton, ThemeToggle, ProfileMenu, ProfilePage,
Spinner, Badge, Card, Tabs, Modal, ConfirmDialog, EmptyState,
ProgressBar, SearchInput, ListRow, ErrorBoundary, KeyPrompt,
} from '@freeappstore/sdk/ui';
// Building blocks
<Spinner size={24} />
<Badge variant="success">Live</Badge>
<Card onClick={fn}>content</Card>
<Tabs tabs={[{key:'a',label:'A'}]} active="a" onChange={setTab} />
<Modal open={show} onClose={close} title="Settings">content</Modal>
<ConfirmDialog open={show} onConfirm={ok} onCancel={cancel} title="Delete?" message="Sure?" variant="danger" />
<EmptyState message="Nothing here yet" />
<ProgressBar value={75} label="Progress" />
<SearchInput value={q} onChange={setQ} />
<ListRow title="Item" subtitle="details" onClick={fn} />
<ErrorBoundary>{children}</ErrorBoundary>
<KeyPrompt app={fas} provider="openai" providerName="OpenAI" />
完整文档 : freeappstore.在线/技能.md
为大赦国际代理
用Claude Code, Cursor, 还是另一个AI工具? 两种选择:
MCP 服务器( 建议) -- 您的代理获得工具来检查部署, 查找 SDK 文档, 并列出应用程序 :
{
"mcpServers": {
"freeappstore": {
"command": "npx",
"args": ["mcp-remote", "https://mcp.freeappstore.online/mcp"]
}
}
}
杀手,md - 完整平台指南(技术堆栈、SDK参考、CLI、部署流量、遵守):
https://freeappstore.online/skills.md
许可证
麻省理工学院.
尾风型 (SDK 5.16+)
React UI 需要 Tailwind 4. SDK 样式由您的应用程序编译;它们不是
在运行时注入。 单位 web/src/index.css,在 Tailwind 导入后添加:
@source "../node_modules/@freeappstore/sdk/dist";
@source "../../node_modules/@freeappstore/sdk/dist";
路径与样式表相对并覆盖了网络局部和root自控安装.
还要加代号 @theme inline 绘图和动画键框来自
样式向导。 。 。 .
这两个正式模板都包含完整的设置. 浮动 UI 使用不透明
--popover (默认) var(--paper)(三); --panel 不透明,玻璃是选入的.
相接的草稿钩和示例是支持的SDK配方. 犬形生成的相接模板在#350中没有被接通到这个功能;携带起动器接线和被采纳到#352,而不是声称已经生成的模板被改变.
临时照片( E)fas.photos(中文(简体) )
const photo = await fas.photos.upload(file, { visibility: 'public' });
// photo.url works in <img>; photo.expiresAt is an epoch timestamp in milliseconds.
await fas.photos.delete(photo.id);
奥米 visibility 用于私人照片; 使用 fas.photos.download(id) 要检索
那些有认证. fas.photos.list() 返回您的现场照片.
SDK在最长边缘的缩放为 640 px, 重新编码为 JPEG( stripping)
目标为100KB或以下。 服务器独立执行 a
20万字节最大,JPEG/WebP仍为图像,维度和元数据剥取.
每次上传在90天后都会过期,包括私人相片. 上传配额
所有应用程序每天20/用户,100个直播/用户/应用程序和10,000个直播/应用程序,有字节和
应用日用限制也. 这是临时相片存储,不是耐用文件存储.
见 平台合同。 。 。 .