@sunerpy/opencode-kiro-auth 0.13.6 → 0.13.7

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.
@@ -5,16 +5,14 @@ import lockfile from 'proper-lockfile';
5
5
  import { isPermanentError } from '../health.js';
6
6
  import { getKeepAliveLockPath, getRefreshLockPath } from '../paths.js';
7
7
  export { getKeepAliveLockPath, getRefreshLockPath } from '../paths.js';
8
- const LOCK_OPTIONS = {
8
+ const DATABASE_LOCK_OPTIONS = {
9
9
  stale: 10000,
10
- retries: {
11
- retries: 5,
12
- minTimeout: 100,
13
- maxTimeout: 1000,
14
- factor: 2
15
- },
10
+ retries: 0,
16
11
  realpath: false
17
12
  };
13
+ const DATABASE_LOCK_DEADLINE_MS = 10000;
14
+ const DATABASE_LOCK_MIN_BACKOFF_MS = 25;
15
+ const DATABASE_LOCK_MAX_BACKOFF_MS = 250;
18
16
  const REFRESH_LOCK_OPTIONS = {
19
17
  stale: 15000,
20
18
  retries: {
@@ -38,6 +36,29 @@ function blockingBackoff(ms) {
38
36
  function isLockContention(e) {
39
37
  return typeof e === 'object' && e !== null && 'code' in e && e.code === 'ELOCKED';
40
38
  }
39
+ function asyncBackoff(attempt, remainingMs) {
40
+ const ceiling = Math.min(DATABASE_LOCK_MIN_BACKOFF_MS * 2 ** Math.min(attempt, 4), DATABASE_LOCK_MAX_BACKOFF_MS, remainingMs);
41
+ const floor = Math.max(1, Math.floor(ceiling / 2));
42
+ const delay = floor + Math.floor(Math.random() * (ceiling - floor + 1));
43
+ return new Promise((resolve) => setTimeout(resolve, delay));
44
+ }
45
+ async function acquireDatabaseLock(dbPath) {
46
+ // A deadline avoids fixed retry-count starvation; jitter keeps contenders
47
+ // from repeatedly attempting the atomic mkdir in lockstep.
48
+ const deadline = Date.now() + DATABASE_LOCK_DEADLINE_MS;
49
+ let attempt = 0;
50
+ for (;;) {
51
+ try {
52
+ return await lockfile.lock(dbPath, DATABASE_LOCK_OPTIONS);
53
+ }
54
+ catch (e) {
55
+ const remainingMs = deadline - Date.now();
56
+ if (!isLockContention(e) || remainingMs <= 0)
57
+ throw e;
58
+ await asyncBackoff(attempt++, remainingMs);
59
+ }
60
+ }
61
+ }
41
62
  export function withDatabaseLockSync(dbPath, fn) {
42
63
  if (!existsSync(dbPath)) {
43
64
  mkdirSync(dirname(dbPath), { recursive: true });
@@ -73,13 +94,12 @@ export function withDatabaseLockSync(dbPath, fn) {
73
94
  }
74
95
  export async function withDatabaseLock(dbPath, fn) {
75
96
  if (!existsSync(dbPath)) {
76
- const dir = dbPath.substring(0, dbPath.lastIndexOf('/'));
77
- await fs.mkdir(dir, { recursive: true });
97
+ await fs.mkdir(dirname(dbPath), { recursive: true });
78
98
  await fs.writeFile(dbPath, '');
79
99
  }
80
100
  let release = null;
81
101
  try {
82
- release = await lockfile.lock(dbPath, LOCK_OPTIONS);
102
+ release = await acquireDatabaseLock(dbPath);
83
103
  return await fn();
84
104
  }
85
105
  finally {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sunerpy/opencode-kiro-auth",
3
- "version": "0.13.6",
3
+ "version": "0.13.7",
4
4
  "description": "OpenCode plugin for AWS Kiro (CodeWhisperer) providing access to Claude models",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",