opencode-plugin-hub 0.1.1 → 0.1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-plugin-hub",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Plugin manager for OpenCode Desktop: browse community plugins, search npm, inspect README and downloads, install and update without editing JSON.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/contract.ts CHANGED
@@ -131,6 +131,8 @@ export const CatalogResult = Schema.Struct({
131
131
  entries: Schema.Array(CatalogEntry),
132
132
  /** `network`, `cache` or `builtin`. */
133
133
  source: Schema.String,
134
+ /** The registry URL the entries came from. Optional for older cached results. */
135
+ registry: Schema.optional(Schema.String),
134
136
  fetchedAt: Schema.Number,
135
137
  error: Schema.String,
136
138
  })
@@ -27,6 +27,8 @@ export interface CatalogResultValue {
27
27
  entries: CatalogEntryValue[]
28
28
  /** Where the list came from: `network`, `cache` or `builtin`. */
29
29
  source: string
30
+ /** The registry URL the entries came from. */
31
+ registry: string
30
32
  /** Epoch milliseconds of the data, 0 for the built-in snapshot. */
31
33
  fetchedAt: number
32
34
  error: string
@@ -129,7 +131,7 @@ function toEntries(raw: RawEntry[], installed: Set<string>): CatalogEntryValue[]
129
131
  return out
130
132
  }
131
133
 
132
- async function fetchRemote(): Promise<RawEntry[]> {
134
+ async function fetchRemote(): Promise<{ entries: RawEntry[]; url: string }> {
133
135
  let lastError = ""
134
136
  for (const url of SOURCES) {
135
137
  try {
@@ -143,7 +145,7 @@ async function fetchRemote(): Promise<RawEntry[]> {
143
145
  lastError = "registry 格式不是数组"
144
146
  continue
145
147
  }
146
- return body as RawEntry[]
148
+ return { entries: body as RawEntry[], url }
147
149
  } catch (error) {
148
150
  lastError = describe(error)
149
151
  }
@@ -153,6 +155,8 @@ async function fetchRemote(): Promise<RawEntry[]> {
153
155
 
154
156
  interface CacheFile {
155
157
  fetchedAt: number
158
+ /** The source URL that produced this cache. Older caches do not have it. */
159
+ url?: string
156
160
  entries: RawEntry[]
157
161
  }
158
162
 
@@ -167,11 +171,11 @@ async function readCache(): Promise<CacheFile | undefined> {
167
171
  }
168
172
  }
169
173
 
170
- async function writeCache(entries: RawEntry[]): Promise<number> {
174
+ async function writeCache(entries: RawEntry[], url: string): Promise<number> {
171
175
  const fetchedAt = Date.now()
172
176
  try {
173
177
  await mkdir(cacheDir(), { recursive: true })
174
- await writeFile(cacheFile(), JSON.stringify({ fetchedAt, entries }), "utf8")
178
+ await writeFile(cacheFile(), JSON.stringify({ fetchedAt, url, entries }), "utf8")
175
179
  } catch {
176
180
  // A failed cache write still leaves the in-memory result usable.
177
181
  }
@@ -186,17 +190,30 @@ export async function browse(installed: Set<string>, force: boolean): Promise<Ca
186
190
  const cache = await readCache()
187
191
  const fresh = cache !== undefined && Date.now() - cache.fetchedAt < TTL
188
192
  if (cache && fresh && !force) {
189
- return { entries: toEntries(cache.entries, installed), source: "cache", fetchedAt: cache.fetchedAt, error: "" }
193
+ return {
194
+ entries: toEntries(cache.entries, installed),
195
+ source: "cache",
196
+ registry: cache.url ?? SOURCES[0]!,
197
+ fetchedAt: cache.fetchedAt,
198
+ error: "",
199
+ }
190
200
  }
191
201
  try {
192
202
  const remote = await fetchRemote()
193
- const fetchedAt = await writeCache(remote)
194
- return { entries: toEntries(remote, installed), source: "network", fetchedAt, error: "" }
203
+ const fetchedAt = await writeCache(remote.entries, remote.url)
204
+ return {
205
+ entries: toEntries(remote.entries, installed),
206
+ source: "network",
207
+ registry: remote.url,
208
+ fetchedAt,
209
+ error: "",
210
+ }
195
211
  } catch (error) {
196
212
  if (cache) {
197
213
  return {
198
214
  entries: toEntries(cache.entries, installed),
199
215
  source: "cache",
216
+ registry: cache.url ?? SOURCES[0]!,
200
217
  fetchedAt: cache.fetchedAt,
201
218
  error: describe(error),
202
219
  }
@@ -204,6 +221,7 @@ export async function browse(installed: Set<string>, force: boolean): Promise<Ca
204
221
  return {
205
222
  entries: toEntries(SNAPSHOT.map(toRaw), installed),
206
223
  source: "builtin",
224
+ registry: SOURCES[0]!,
207
225
  fetchedAt: 0,
208
226
  error: describe(error),
209
227
  }