dsh-fish-memory 0.0.0-stage → 1.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +285 -2
- package/cordis.patch.yml +3 -0
- package/lib/atomic-file.mjs +32 -0
- package/lib/client.js +4043 -0
- package/lib/hostdeps.mjs +157 -0
- package/lib/index.js +6500 -0
- package/lib/selfupdate.mjs +151 -0
- package/lib/store-merge.mjs +31 -0
- package/lib//347/224/237/346/210/220/346/241/243/346/241/210.js +573 -0
- package/lib//350/257/215/345/205/270-/346/235/245/346/272/220.txt +53 -0
- package/lib//350/257/215/345/205/270.txt +109750 -0
- package/lib//350/257/215/351/242/221.txt +20000 -0
- package/package.json +56 -6
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// 插件自查更新 —— 查的是**这个插件自己的仓库**
|
|
2
|
+
//
|
|
3
|
+
// 每个插件在自己设置页放一个「检查更新」,点一下就去自己的仓库看 package.json 里的版本。
|
|
4
|
+
//
|
|
5
|
+
// 原则:
|
|
6
|
+
// · 仓库地址从包里自己的 package.json 读(`repository`),不在代码里写死
|
|
7
|
+
// · 只查,不装不删 —— 更新命令交给用户自己复制去跑
|
|
8
|
+
// · **查不到要如实说"查不到",绝不能显示成"已是最新"**
|
|
9
|
+
// · 结果缓存 6 小时;点按钮(refresh)就绕过缓存
|
|
10
|
+
//
|
|
11
|
+
// ⚠ 内容会进客户端的一份说明:这个文件是**复制多份**到各个插件里的同一份实现,
|
|
12
|
+
// 只在这一个地方改了,记得同步给其它插件(别各改各的)。
|
|
13
|
+
|
|
14
|
+
import { readFileSync } from 'node:fs'
|
|
15
|
+
import { join } from 'node:path'
|
|
16
|
+
|
|
17
|
+
const TTL = 6 * 3600 * 1000
|
|
18
|
+
const TIMEOUT = 8000
|
|
19
|
+
|
|
20
|
+
function parseVer(v) {
|
|
21
|
+
const s = String(v || '').trim().replace(/^v/i, '')
|
|
22
|
+
const cut = s.indexOf('-')
|
|
23
|
+
const core = cut >= 0 ? s.slice(0, cut) : s
|
|
24
|
+
const pre = cut >= 0 ? s.slice(cut + 1) : ''
|
|
25
|
+
const nums = core.split('.').map((x) => Number(x) || 0)
|
|
26
|
+
return { nums: [nums[0] || 0, nums[1] || 0, nums[2] || 0], pre }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// 1.2.3 / v1.2.3 / 1.2.3-beta.1 都认
|
|
30
|
+
export function cmpVer(a, b) {
|
|
31
|
+
const x = parseVer(a)
|
|
32
|
+
const y = parseVer(b)
|
|
33
|
+
for (let i = 0; i < 3; i++) {
|
|
34
|
+
if (x.nums[i] !== y.nums[i]) return x.nums[i] > y.nums[i] ? 1 : -1
|
|
35
|
+
}
|
|
36
|
+
if (x.pre === y.pre) return 0
|
|
37
|
+
if (!x.pre) return 1 // 正式版比预发布新
|
|
38
|
+
if (!y.pre) return -1
|
|
39
|
+
return x.pre > y.pre ? 1 : -1
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function rawUrls(repo) {
|
|
43
|
+
const s = String(repo || '').trim()
|
|
44
|
+
const m = /github\.com[/:]([^/]+)\/([^/#?]+)/i.exec(s)
|
|
45
|
+
if (!m) return []
|
|
46
|
+
const owner = m[1]
|
|
47
|
+
const name = m[2].replace(/\.git$/i, '')
|
|
48
|
+
return [
|
|
49
|
+
`https://raw.githubusercontent.com/${owner}/${name}/HEAD/package.json`,
|
|
50
|
+
// 备用:jsDelivr 也能读 GitHub,但**有缓存**,可能滞后 —— 消息里会标出来
|
|
51
|
+
`https://cdn.jsdelivr.net/gh/${owner}/${name}@main/package.json`,
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function createSelfUpdate({ packageRoot, diag }) {
|
|
56
|
+
const noop = () => {}
|
|
57
|
+
const log = typeof diag === 'function' ? diag : noop
|
|
58
|
+
|
|
59
|
+
let meta = {}
|
|
60
|
+
try {
|
|
61
|
+
meta = JSON.parse(readFileSync(join(packageRoot, 'package.json'), 'utf8'))
|
|
62
|
+
} catch (e) {
|
|
63
|
+
log('读自己的 package.json 失败:' + (e && e.message))
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const current = String(meta.version || '')
|
|
67
|
+
const repo = String(
|
|
68
|
+
(meta.repository && (meta.repository.url || meta.repository)) || meta.homepage || ''
|
|
69
|
+
)
|
|
70
|
+
const repoUrl = repo
|
|
71
|
+
.replace(/^git\+/, '')
|
|
72
|
+
.replace(/^git:/, 'https:')
|
|
73
|
+
.replace(/\.git$/, '')
|
|
74
|
+
.replace(/#readme$/i, '')
|
|
75
|
+
|
|
76
|
+
let cache = null
|
|
77
|
+
|
|
78
|
+
async function fetchLatest() {
|
|
79
|
+
const urls = rawUrls(repo)
|
|
80
|
+
if (!urls.length) return { latest: null, error: '包里没写 GitHub 仓库地址,没法查' }
|
|
81
|
+
let lastErr = ''
|
|
82
|
+
for (const url of urls) {
|
|
83
|
+
try {
|
|
84
|
+
const res = await fetch(url, {
|
|
85
|
+
signal: AbortSignal.timeout(TIMEOUT),
|
|
86
|
+
headers: { accept: 'application/json', 'user-agent': 'dsh-plugin-selfupdate' },
|
|
87
|
+
})
|
|
88
|
+
if (!res.ok) { lastErr = 'HTTP ' + res.status; continue }
|
|
89
|
+
const j = await res.json()
|
|
90
|
+
if (!j || !j.version) { lastErr = '仓库里的 package.json 没有 version'; continue }
|
|
91
|
+
return {
|
|
92
|
+
latest: String(j.version),
|
|
93
|
+
from: url.includes('jsdelivr') ? 'jsDelivr(有缓存,可能滞后)' : 'GitHub',
|
|
94
|
+
}
|
|
95
|
+
} catch (e) {
|
|
96
|
+
lastErr = String((e && e.message) || e)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return { latest: null, error: lastErr || '查询失败' }
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async function check(force) {
|
|
103
|
+
if (!force && cache && Date.now() - cache.checkedAt < TTL) return { ...cache, cached: true }
|
|
104
|
+
const r = await fetchLatest()
|
|
105
|
+
const hasUpdate = Boolean(r.latest && current && cmpVer(r.latest, current) > 0)
|
|
106
|
+
cache = {
|
|
107
|
+
ok: Boolean(r.latest),
|
|
108
|
+
current,
|
|
109
|
+
latest: r.latest || null,
|
|
110
|
+
hasUpdate,
|
|
111
|
+
// 本机比仓库还新 —— 自己改过还没推,正常
|
|
112
|
+
ahead: Boolean(r.latest && current && cmpVer(r.latest, current) < 0),
|
|
113
|
+
error: r.error || null,
|
|
114
|
+
from: r.from || null,
|
|
115
|
+
repoUrl: repoUrl || null,
|
|
116
|
+
checkedAt: Date.now(),
|
|
117
|
+
}
|
|
118
|
+
log('查更新:当前 ' + current + ' / 最新 ' + (r.latest || '查不到') + (r.error ? '(' + r.error + ')' : ''))
|
|
119
|
+
return cache
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function register(ctx, route) {
|
|
123
|
+
try {
|
|
124
|
+
ctx.effect(() => ctx.webServer.register({
|
|
125
|
+
kind: 'exact',
|
|
126
|
+
path: route + '/update',
|
|
127
|
+
handler: async (req, res) => {
|
|
128
|
+
const send = (code, obj) => {
|
|
129
|
+
res.writeHead(code, {
|
|
130
|
+
'content-type': 'application/json; charset=utf-8',
|
|
131
|
+
'cache-control': 'no-store',
|
|
132
|
+
})
|
|
133
|
+
res.end(JSON.stringify(obj))
|
|
134
|
+
}
|
|
135
|
+
try {
|
|
136
|
+
const url = new URL(req.url, 'http://127.0.0.1')
|
|
137
|
+
const force = url.searchParams.get('refresh') === '1'
|
|
138
|
+
send(200, { ok: true, ...(await check(force)) })
|
|
139
|
+
} catch (e) {
|
|
140
|
+
log('查更新路由失败:' + (e && e.message))
|
|
141
|
+
send(200, { ok: false, current, latest: null, error: String((e && e.message) || e) })
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
}))
|
|
145
|
+
} catch (e) {
|
|
146
|
+
log('查更新路由注册失败:' + (e && e.message))
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return { current, repo, repoUrl, check, register }
|
|
151
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// 纯合并逻辑:不访问磁盘、宿主或模型,便于复现后台旧快照与删除交错。
|
|
2
|
+
export function 合并库(盘, 写, 选项 = {}) {
|
|
3
|
+
const 更新时间 = (m) => Math.max(
|
|
4
|
+
Date.parse(m.editedAt || 0) || 0,
|
|
5
|
+
Date.parse(m.relatedAt || 0) || 0,
|
|
6
|
+
Date.parse(m.reinforcedAt || 0) || 0,
|
|
7
|
+
Date.parse(m.deletedAt || 0) || 0,
|
|
8
|
+
Date.parse(m.createdAt || 0) || 0,
|
|
9
|
+
)
|
|
10
|
+
const 写记 = new Map((写.memories || []).map((m) => [String(m.id), m]))
|
|
11
|
+
const 合记 = new Map((盘.memories || []).map((m) => [String(m.id), m]))
|
|
12
|
+
for (const [id, m] of 写记) {
|
|
13
|
+
const 旧 = 合记.get(id)
|
|
14
|
+
合记.set(id, !旧 || 更新时间(m) >= 更新时间(旧) ? m : 旧)
|
|
15
|
+
}
|
|
16
|
+
const 删们 = new Map((盘.deleted || []).map((m) => [String(m.id), m]))
|
|
17
|
+
for (const m of 写.deleted || []) 删们.set(String(m.id), m)
|
|
18
|
+
// 内存里仍有一条,不等于用户要求找回。只有同步找回入口显式列出的 id 能撤销删除。
|
|
19
|
+
const 找回 = Array.isArray(选项?.restoreIds) ? 选项.restoreIds : []
|
|
20
|
+
for (const value of 找回) {
|
|
21
|
+
const id = String(value)
|
|
22
|
+
if (写记.has(id)) 删们.delete(id)
|
|
23
|
+
}
|
|
24
|
+
const memories = [...合记.values()].filter((m) => !删们.has(String(m.id)))
|
|
25
|
+
const 记录表 = new Map()
|
|
26
|
+
const 键 = (t) => String(t && t.at) + '|' + String((t && t.query) || '').slice(0, 80)
|
|
27
|
+
for (const t of 写.traces || []) 记录表.set(键(t), t)
|
|
28
|
+
for (const t of 盘.traces || []) if (!记录表.has(键(t))) 记录表.set(键(t), t)
|
|
29
|
+
const traces = [...记录表.values()].sort((a, b) => (a.at || 0) - (b.at || 0)).slice(-100)
|
|
30
|
+
return { version: 2, policy: 写.policy || 盘.policy, memories, traces, deleted: [...删们.values()] }
|
|
31
|
+
}
|