@@ -2,6 +2,7 @@ import path from "path"
22import { Global } from "../global"
33import fs from "fs/promises"
44import z from "zod"
5+ import { Lock } from "../util/lock"
56
67export const OAUTH_DUMMY_KEY = "opencode-oauth-dummy-key"
78
@@ -43,31 +44,75 @@ export namespace Auth {
4344 }
4445
4546 export async function all ( ) : Promise < Record < string , Info > > {
46- const file = Bun . file ( filepath )
47- const data = await file . json ( ) . catch ( ( ) => ( { } ) as Record < string , unknown > )
48- return Object . entries ( data ) . reduce (
49- ( acc , [ key , value ] ) => {
50- const parsed = Info . safeParse ( value )
51- if ( ! parsed . success ) return acc
52- acc [ key ] = parsed . data
53- return acc
54- } ,
55- { } as Record < string , Info > ,
56- )
47+ const release = await Lock . read ( "auth" )
48+ try {
49+ const file = Bun . file ( filepath )
50+
51+ if ( ! ( await file . exists ( ) ) ) return { }
52+
53+ const data = await file . json ( )
54+
55+ if ( typeof data !== "object" || data === null ) {
56+ throw new Error ( "auth.json contains invalid data" )
57+ }
58+
59+ return Object . entries ( data ) . reduce (
60+ ( acc , [ key , value ] ) => {
61+ const parsed = Info . safeParse ( value )
62+ if ( ! parsed . success ) return acc
63+ acc [ key ] = parsed . data
64+ return acc
65+ } ,
66+ { } as Record < string , Info > ,
67+ )
68+ } finally {
69+ release [ Symbol . dispose ] ( )
70+ }
5771 }
5872
5973 export async function set ( key : string , info : Info ) {
60- const file = Bun . file ( filepath )
61- const data = await all ( )
62- await Bun . write ( file , JSON . stringify ( { ...data , [ key ] : info } , null , 2 ) )
63- await fs . chmod ( file . name ! , 0o600 )
74+ const release = await Lock . write ( "auth" )
75+ try {
76+ const file = Bun . file ( filepath )
77+ const exists = await file . exists ( )
78+ const rawData = exists ? await file . json ( ) : null
79+ const data : Record < string , Info > = { }
80+
81+ if ( typeof rawData === "object" && rawData !== null ) {
82+ Object . entries ( rawData ) . forEach ( ( [ k , v ] ) => {
83+ const parsed = Info . safeParse ( v )
84+ if ( parsed . success ) data [ k ] = parsed . data
85+ } )
86+ }
87+
88+ data [ key ] = info
89+ await Bun . write ( file , JSON . stringify ( data , null , 2 ) )
90+ await fs . chmod ( filepath , 0o600 )
91+ } finally {
92+ release [ Symbol . dispose ] ( )
93+ }
6494 }
6595
6696 export async function remove ( key : string ) {
67- const file = Bun . file ( filepath )
68- const data = await all ( )
69- delete data [ key ]
70- await Bun . write ( file , JSON . stringify ( data , null , 2 ) )
71- await fs . chmod ( file . name ! , 0o600 )
97+ const release = await Lock . write ( "auth" )
98+ try {
99+ const file = Bun . file ( filepath )
100+ const exists = await file . exists ( )
101+ const rawData = exists ? await file . json ( ) : null
102+ const data : Record < string , Info > = { }
103+
104+ if ( typeof rawData === "object" && rawData !== null ) {
105+ Object . entries ( rawData ) . forEach ( ( [ k , v ] ) => {
106+ const parsed = Info . safeParse ( v )
107+ if ( parsed . success ) data [ k ] = parsed . data
108+ } )
109+ }
110+
111+ delete data [ key ]
112+ await Bun . write ( file , JSON . stringify ( data , null , 2 ) )
113+ await fs . chmod ( filepath , 0o600 )
114+ } finally {
115+ release [ Symbol . dispose ] ( )
116+ }
72117 }
73118}
0 commit comments