@stiva-app/平台
浏览器使用周期 2 Estiva apps 共享.
@estiva-app/protocol 拥有电线——事件构造、身份证、签名和
两个中继客户端——并刻意包含无折叠. 这个包裹坐着
在它上面,并有关于它的东西 在标签中运行: 一个
设置一个标签, 它的证书读取在每个连接和网络上
回来.
npm install @estiva-app/platform
@estiva-app/protocol 是同级依赖.
为什么它存在
createLiveRelay 财务报告和审定财务报表 createChannelSubscriptions 已提取到
protocol 与一个呼叫者, 和管道a 第二届 应用程序不需要
和他们一起移动。 它留在这 peek-app/src/nostr/liveTopics.ts,哪个
ADR 0002 (韩语)
§10分=========================================================================================================================================================================================
(环境注入),并称"SHA-7法案正在支付".
3个行为,每个行为都失败了 作为一个健康的外观插座提供 无:
- 每个标签一个实例.
max_subscriptions是每个连接和中继器 认证一次连接, 因此每个组件挂载的连接错误 而不是只是浪费。 React Best Mode 使它变得具体:任何 由效果所拥有是两次构建的. - 证书读取每个连接,从来没有捕获. 被俘的标志
模块载荷在无声更新后作为已死证书存活,并重新连接
然后签署其
22242带着它. - 网相还来. 重新连接由
onclose,则a 套接字,其对等点变得无法接触OPEN直到TCP放弃。 无 a 一个online编号 :offline信号它报告live,没有带来什么,从来没有 重试.
使用量
import {
browserOnlineSource,
createLiveClientHolder,
} from '@estiva-app/platform'
// The app holds the one module-scope binding. This package holds none — that
// is the constraint-2 failure it exists to stop repeating.
const holder = createLiveClientHolder()
export function liveClient() {
return holder.get({
relayUrl: RELAY_URL,
// Read fresh on every connect attempt.
getCredential: () => {
const token = validToken()
return token && { accessToken: token.accessToken, pubkey: token.pubkey }
},
sign: signViaEstivaId,
online: browserOnlineSource(window),
subscriptionPrefix: 'my-app-',
// Told what happened, never asked what to do — your freshness model stays
// yours.
observe: { onState: recordRelayState, onOnline: recordOnline },
})
}
观看一个频道或整个工作空间
两道道相去相去相去相去,相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相相去相去相去相去相去相去相去相去相去相相去相去相去相去相相去相去相去相去相去相去相去相去相去相去相去相去相去相去相去相相相相相去相.
// Per channel, refcounted: one REQ each, every consumer sees every event.
// What a message projection wants.
client.subscriptions.subscribe(channelUuid, (event) => project(event))
// A whole workspace in one REQ per 128 Folders. You are told which Folder
// changed, never what changed.
client.watchFolders(folderIds, (folder) => refresh(folder), { kinds: [9, 1111] })
REQ 是一个客户端 – 服务器框架, 所以它是在中继器的调制
LimitType::WsEvents以生产计量: 50个无节奏的要求是
被接受,51号被拒绝 rate-limited: quota exceeded因此,一个
34-每个通道路径的Folder工作空间在每一个连接上花费34帧
和每次连接· ; watchFolders 花一个.
相反,持有订阅费没有多少可衡量的费用——探险回合 无论是1,34还是100米是开放的,行程是44.2米.
在依赖之前要知道一件事 watchFolders
宽滤波器是测量的,没有假定:一个滤波器携带34个 #h 已交付
34人中的34人反对 wss://estiva.estiva.app。 。 。 .
它也是人类的财产 部署的中继分支。 。 。 . nfb-demo-kinds 携带
复数 extract_channel_ids_from_filters 返回整个频道设置;
打开 origin/main单数版本的过滤器登记符与 全球
订阅,和 fan_out_scoped 活动上的分会 channel_id 财务报告和审定财务报表
从来没有咨询它的任何携带 h。这种构建提供了 34个中的0个,
完全没有出错 - 欧塞, live安静.
因此,任何取决于这一点的, 应该能够回答 "有件事我没有
发表实际上到达?",因为没有其他东西能区分这两个案件.
过 kinds 当你在乐园里的时候,一个宽广的过滤器被拒绝
其他建筑与 restricted: p-gated events require #p matching your pubkey。 。 。 .
刷新,等待当接力说
巴斯计数器 POST /query 300分钟 每桶因此,每个标签和应用程序
一人签入,共用一项津贴。 构建一个预算和一个预算
每个标签的调度器 :
import { createRefreshScheduler, createRelayBudget } from '@estiva-app/platform'
// The transport writes it; the cadence reads it.
export const relayBudget = createRelayBudget({
// Optional: the app's other tabs learn a pause from this one.
channel: new BroadcastChannel('my-app-relay-budget'),
})
export const refreshScheduler = createRefreshScheduler({ document, window, budget: relayBudget })
// In the transport, on every answer:
if (status === 429 || isRateLimited(body)) relayBudget.noteRateLimited(body)
// In a hook: focus, becoming visible, and every 30 s while visible. A tab
// switch raises two events and costs one read; nothing runs while paused.
useEffect(() => refreshScheduler.subscribe(reload, { interval: !live }), [live])
// Before retrying a refused read: every waiter goes after the longest pause
// anybody learned, not its own shorter one.
await relayBudget.whenClear()
这里什么也没有打开读取。 点击请求读取的读物仍会外出 一次;只有节奏后退.
设备上的复制件,所以一次重新装入
createEventSnapshot 保留中继器告诉一个人的 签名事件,
从来没有一个折叠的视图——在下一个负载上回答同样的过滤器.
把它的答案叠起来,然后发送中继器读作
前后再折:接力的接力回答取代了副本的接力.
import { createEventSnapshot, indexedDbSnapshotStorage, snapshotScope } from '@estiva-app/platform'
const storage = indexedDbSnapshotStorage(indexedDB, 'my-app-copy')
const copy = createEventSnapshot({
storage,
scope: snapshotScope(relayUrl, pubkey),
version: 1, // bump when what you fold from it changes meaning
})
// In the transport, on every answer the relay gives:
copy.absorb(filters, events)
// Before the relay answers: null means the copy cannot answer this read whole.
await copy.ready
const drawnFirst = copy.answer(filters)
// Signing out: every copy goes, and one still open — in this tab or another —
// can never write the person's data back (the storage counts sign-outs).
copy.discard()
await storage.clear()
它回答一个读数 它看到的答案, 和集合列表 它没有,何时
在所有其他领域读取相同(limit 答复全文
一起命名了其中的每一个价值—— '#e': [the newest messages] 之后
最新变化. since 财务报告和审定财务报表 until 是时钟而不是问题的一部分.
每一个答案也是一个更正:副本中包含的匹配
过滤刚才回答的中继器,而不在该答案中,被删除——a
删除, 或是丢失的文件夹 。 A 类 kind:5 放弃其作者
签名. keepPlaintext 保持 平话直说的人自己的blob 旁边
事件,所以一个不变的blob 不需要解密下一个负载。 从不
发布从副本中抽出的东西:它可能比中继器老.
正在装入下一个打开的, 不减慢点击
createPacer 持有标签的套接字读取到中继器的仪表( buz: 50 REQs)
每平方公尺5分),为两道. A 类 click 读取——该人要求的——
并可能会在等待后溢出到HTTP。 一个 ahead 读取
只有窗口留下的东西: 永远不要等待, 永远不要过去
perWindow - reserve,仅在HTTP本身 spill 允许——应用程序
给它一个较小的 HTTP 允许比点击. promote() 移动 ahead 读取
仍在等待在点击道上
缓存会按下已经读出的内容来读取相同的内容. createInFlight
在电线上保持相同的分数.
loadAhead 运行一个应用程序的步骤列表顺序,一次几个
首先,抛出停止它, 和什么装载停留.
import { createInFlight, createPacer, loadAhead } from '@estiva-app/platform'
const pacer = createPacer({ perWindow: 40, windowMs: 5_000, reserve: 15 })
const wire = createInFlight(4) // two of them at most for `ahead`
// In the socket reader:
await pacer.take(reqs, { lane, spill })
const release = await wire.acquire(lane)
// Once the first page has drawn:
const loader = loadAhead([
{ label: 'Topics', run: () => readTopicsAhead() },
{ label: 'Open work 1', run: () => readTopicAhead(first) },
])
addEventListener('pointerdown', () => pacer.promote(), true)
const { loaded, stoppedBy } = await loader.done
如何一步读取和保存它 是应用程序的: 一步读入 点击时读取的相同缓存是使点击立即绘制的.
这刻意不知道的
在任何存储的地方,除了副本的存储,你交给它。 皮克的版本用了一个 LiveProjectionApi,以及
将康维克斯的假设制成第二包
应用程序取决于。 这能提供框架和连接状态 而不是别的,所以
如果Convex不留任何东西
改变,如果它走了,这已经是正确的.
你的新鲜度和复制品是产品的声音 留在你的应用程序里.
observe 他们是如何得到他们需要的.
许可证
麻省理工学院