@magpie-community/opencode-mimo-auth 0.1.5 → 0.1.6

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.
Files changed (3) hide show
  1. package/README.md +7 -1
  2. package/index.mjs +58 -19
  3. package/package.json +3 -2
package/README.md CHANGED
@@ -29,7 +29,13 @@ Chat completions go to `https://mimo-server-<region>.xiaomimimo.com/api/route/ch
29
29
 
30
30
  `mimo-auto`, the app's default model, is requested as `mimo-pro`.
31
31
 
32
- The session is renewed with the passToken a day after it was issued. A model
32
+ The session is renewed with the passToken a day after it was issued.
33
+ magpie (0.1.684 and later) does it ahead of time through `auth.refresh`, ten
34
+ minutes before that day is out (`refreshLead`), once for the account and
35
+ before its requests, models and usage ask for it; a passToken Xiaomi no
36
+ longer takes marks the account for a new sign-in. The check before each
37
+ request stays for OpenCode, which doesn't call `auth.refresh`, and one
38
+ sign-on at a time serves both. A model
33
39
  request the server turns away (a 401) is answered as the server answered it,
34
40
  as magpie's built-in MiMo account did; reading usage renews the session once
35
41
  when the server turns it away. If the passToken no longer works, sign in
package/index.mjs CHANGED
@@ -18,6 +18,7 @@ const APP_VERSION = "26.929.292248"
18
18
  const SOURCE = "mimocode-cli-free"
19
19
  const UA = "miNative PC/Normal Windows_NT/10.0.26100 SDKV/1.0.0 DEVT/PC DEVS/Windows APP/miaccount_desktop APPV/0.1.0"
20
20
  const RENEW_AFTER = 24 * 60 * 60 * 1000 // the app signs on again after a day
21
+ const LEAD_MS = 10 * 60 * 1000 // this close to it, magpie signs on again ahead of time (auth.refresh)
21
22
  const SIGN_IN_LIFE = 10 * 60 * 1000
22
23
 
23
24
  const MODEL = { release_date: "2026-07-01", attachment: true, tool_call: true, limit: { context: 1_000_000, output: 128_000 }, modalities: { input: ["text", "image"], output: ["text"] } }
@@ -338,8 +339,11 @@ function serverTime(v) {
338
339
 
339
340
  export const MimoAuthPlugin = async ({ client }) => {
340
341
  // renewals under way, one to an account: two accounts signing on at
341
- // once each keep their own session
342
+ // once each keep their own session. renewed is the last session each
343
+ // account got here, so magpie's auth.refresh handed a sign-in from
344
+ // before it gives that one rather than signing on again.
342
345
  const renewing = new Map()
346
+ const renewed = new Map()
343
347
 
344
348
  const save = async (auth) => {
345
349
  try {
@@ -347,28 +351,20 @@ export const MimoAuthPlugin = async ({ client }) => {
347
351
  } catch {}
348
352
  }
349
353
 
350
- // fresh is the account with a live session, signed on again when it is
351
- // older than the app lets one get, or when force is set (the server
352
- // turned the last one away); renewed when it was signed on again, which
353
- // took the built-in's lapse mark off
354
- const fresh = async (getAuth, force) => {
355
- const a = fromAuth(await getAuth())
356
- if (!a) throw new Error("Xiaomi MiMo: not signed in")
357
- if (!force && Object.keys(a.cookies).length && Date.now() < a.expires) return a
354
+ // renew signs the account on again, once at a time: those who come
355
+ // while it runs wait for it. keep saves the new session (the request
356
+ // path); magpie's auth.refresh saves what it gives itself.
357
+ const renew = (a, keep) => {
358
358
  const who = String(a.creds.userId ?? "")
359
359
  let r = renewing.get(who)
360
360
  if (!r) {
361
361
  r = (async () => {
362
- try {
363
- const s = await session(a.creds, a.creds.base)
364
- const issued = Date.now()
365
- await save(toAuth(a.creds, s.cookies, issued))
366
- return { creds: a.creds, cookies: s.cookies, expires: issued + RENEW_AFTER, renewed: true }
367
- } catch (e) {
368
- // a hiccup: the session in hand may still do
369
- if (!(e instanceof Lapsed) && !force && Object.keys(a.cookies).length) return a
370
- throw e
371
- }
362
+ const s = await session(a.creds, a.creds.base)
363
+ const issued = Date.now()
364
+ const got = { creds: a.creds, cookies: s.cookies, expires: issued + RENEW_AFTER, renewed: true }
365
+ renewed.set(who, got)
366
+ if (keep) await save(toAuth(a.creds, s.cookies, issued))
367
+ return got
372
368
  })().finally(() => {
373
369
  renewing.delete(who)
374
370
  })
@@ -377,6 +373,44 @@ export const MimoAuthPlugin = async ({ client }) => {
377
373
  return r
378
374
  }
379
375
 
376
+ // fresh is the account with a live session, signed on again when it is
377
+ // older than the app lets one get, or when force is set (the server
378
+ // turned the last one away); renewed when it was signed on again, which
379
+ // took the built-in's lapse mark off
380
+ const fresh = async (getAuth, force) => {
381
+ const a = fromAuth(await getAuth())
382
+ if (!a) throw new Error("Xiaomi MiMo: not signed in")
383
+ if (!force && Object.keys(a.cookies).length && Date.now() < a.expires) return a
384
+ try {
385
+ return await renew(a, true)
386
+ } catch (e) {
387
+ // a hiccup: the session in hand may still do
388
+ if (!(e instanceof Lapsed) && !force && Object.keys(a.cookies).length) return a
389
+ throw e
390
+ }
391
+ }
392
+
393
+ // refresh is magpie's auth.refresh: the session signed on again
394
+ // LEAD_MS before the app would, as the fields that changed (the Xiaomi
395
+ // account in refresh stays as it is). A passToken Xiaomi no longer takes
396
+ // is signIn "expired"; any other failure throws as it is.
397
+ const refresh = async (auth) => {
398
+ const a = fromAuth(auth)
399
+ if (!a) return undefined
400
+ const last = renewed.get(String(a.creds.userId ?? ""))
401
+ // signed on again here already, the store not yet saying so
402
+ if (last && last.expires > a.expires && Date.now() < last.expires - LEAD_MS) {
403
+ return { access: JSON.stringify(last.cookies), expires: last.expires }
404
+ }
405
+ try {
406
+ const s = await renew(a, false)
407
+ return { access: JSON.stringify(s.cookies), expires: s.expires }
408
+ } catch (e) {
409
+ if (e instanceof Lapsed) throw Object.assign(new Error(e.message), { signIn: "expired" })
410
+ throw e
411
+ }
412
+ }
413
+
380
414
  // page asks the MiMo server for one of the account's pages, signing on
381
415
  // again once when it is turned away, and gives its data. read.signIn is
382
416
  // what that did to the built-in's lapse mark: signed on again took it
@@ -472,6 +506,11 @@ export const MimoAuthPlugin = async ({ client }) => {
472
506
  auth: {
473
507
  provider: ID,
474
508
  usage,
509
+ // magpie signs the account on again LEAD_MS before the day is out,
510
+ // once, before its requests, models and usage ask; fresh's check
511
+ // before each request stays for OpenCode, which doesn't call this
512
+ refreshLead: LEAD_MS,
513
+ refresh,
475
514
  loader: async (getAuth) => {
476
515
  const a = fromAuth(await getAuth())
477
516
  if (!a) return {}
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@magpie-community/opencode-mimo-auth",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "OpenCode provider plugin for Xiaomi MiMo: the MiMo app's Xiaomi-account sign-in, MiMo Pro and MiMo Flash",
5
5
  "type": "module",
6
6
  "main": "./index.mjs",
7
7
  "exports": "./index.mjs",
8
8
  "files": ["index.mjs", "README.md"],
9
9
  "keywords": ["opencode", "opencode-plugin", "xiaomi", "mimo"],
10
- "license": "MIT"
10
+ "license": "MIT",
11
+ "repository": { "type": "git", "url": "git+https://github.com/magpie-community/plugins.git", "directory": "packages/mimo" }
11
12
  }