generated at
Scrapboxの書き込みAPI案
Scrapbox UserScriptからSocket.IOを使って任意ページへの書き込みAPIを作ろうと考えている
共同projectでこれをやるとWOMが発生してよくない影響が出るかもしれないが、個人projectでやる分には何の問題もないし、むしろ出来たほうがいろいろ便利
nishioさんも井戸端でそんなこと言ってた

ここではそのAPIの設計案を書き出す

提供する機能
任意projectのStreamの購読
interface example
ts
import {listenStream} from "https://scrapbox.io/api/code/takker/Scrapboxの書き込みAPI案/mod.ts" const listen = await listenStream("5f2f02f3c4a48d00237e1534"); while (true) { const event = await listen(); console.info(event); // ... }
socket.io-requestを使ったほうがいいな
Promiseで包む処理を外部に切り出せる
socket.io-requestはtypescriptじゃなくて使いづらいので、ここから独自のError classとserver side対応を削ったものを自前で作る
いや、Scrapboxのwebsocketを操作する低レイヤーlibraryに組み込んでしまうか
機能
timeoutで例外を投げる
server io disconnect やerror propertyが返ってきたら例外として処理する
送信と受信をともにPromiseで包む
送信と通信時のobjects全てに型をつける
型は実際の通信内容とassets/index.jsから調べて列挙する
mod.ts
import { socketIO } from "../userscript-socket-io/mod.ts"; import { getPromiseSettledAnytimes } from "../getpromisesettledanytimes/mod.ts"; export async function listenStream(projectId: string) { const socket = await socketIO(); await new Promise((resolve, reject) => { const onDisconnect = (message: string) => { if (message !== "io server disconnect") return; reject(message); }; socket.emit("socket.io-request", { method: "room:join", data: { pageId: null, projectId, projectUpdatesStream: true, }, }, (e: unknown) => { socket.off("disconnect", onDisconnect); resolve(e); }); socket.once("disconnect", onDisconnect); }); const [waitForEvent, resolve] = getPromiseSettledAnytimes<unknown, unknown>(); socket.on("projectUpdatesStream:commit", resolve); socket.on("projectUpdatesStream:event", resolve); return waitForEvent; }
任意projectの任意のpageの
更新購読
ts
for await (const event of listenPageUpdate(projectId, pageId)) { //... }
書き込み
編集
ts
// 内部で/api/pages/:projectName/:pageTitleを呼び出してpage idとcommit idを取得しておく const { update, insert, delete, } = await joinPageRoom(projectName, pageTitle); await updateLine(lineId, newText);
任意行の下へ挿入
削除
一個ずつ命令するの面倒だろうから、宣言的UIのようにページ全体を書き換えるような関数を用意してしまおうかな
現在のページ内容と更新後のページ内容とを比較し、差分だけcommitを作って更新する
これにより、変更する必要のない行のテロメアをそのままにできる
使う側も、何行目に挿入するとか考えなくてすむから楽
差分計算はたとえばjsdiffとかを使う
ページ削除
ts
await deletePage(projectId, pageId);
ピン留め/ピン留め解除
commit Idは自動で作る
conflict時の処理はどうする
scrapboxは/scrapboxlab/api/commits/:projectname/:pageid ( pull )からcommitを辿ってpushし直しているとのこと
まあ個人用途でしか考えてないし、conflict解決機能はつけなくてもいいと思う
他のuserのカーソル位置の更新購読
これは要らないかも?
任意projectの新規ページ作成
これはいらないか
普通の空ページのpage idをとってきてそこに書き込めばいい
まあこんなところか

実装

#2021-12-23 09:24:35
#2021-10-25 17:51:42
#2021-10-24 22:20:11 typo
#2021-10-21 13:04:02
#2021-10-19 21:27:13