@@ -3,6 +3,8 @@ import { cdnImports, importFromCdnWithFallback } from './cdn.js'
33const workspaceDbName = 'knighted-develop-workspaces'
44const workspaceDbVersion = 1
55const workspaceStoreName = 'prWorkspaces'
6+ const workspaceByRepoIndexName = 'byRepo'
7+ const workspaceByLastModifiedIndexName = 'byLastModified'
68
79const normalizeTabRecord = tab => {
810 if ( ! tab || typeof tab !== 'object' ) {
@@ -93,8 +95,8 @@ const openWorkspaceDb = async ({ loadRuntime } = {}) => {
9395 const store = db . createObjectStore ( workspaceStoreName , {
9496 keyPath : 'id' ,
9597 } )
96- store . createIndex ( 'byRepo' , 'repo' )
97- store . createIndex ( 'byLastModified' , 'lastModified' )
98+ store . createIndex ( workspaceByRepoIndexName , 'repo' )
99+ store . createIndex ( workspaceByLastModifiedIndexName , 'lastModified' )
98100 }
99101 } ,
100102 } )
@@ -112,7 +114,10 @@ export const createWorkspaceStorageAdapter = ({ loadRuntime } = {}) => {
112114
113115 const ensureDb = ( ) => {
114116 if ( ! dbPromise ) {
115- dbPromise = openWorkspaceDb ( { loadRuntime } )
117+ dbPromise = openWorkspaceDb ( { loadRuntime } ) . catch ( error => {
118+ dbPromise = null
119+ throw error
120+ } )
116121 }
117122
118123 return dbPromise
@@ -135,15 +140,24 @@ export const createWorkspaceStorageAdapter = ({ loadRuntime } = {}) => {
135140
136141 const listWorkspaces = async ( { repo } = { } ) => {
137142 const db = await ensureDb ( )
138- const items = await db . getAll ( workspaceStoreName )
143+ const hasRepoFilter = typeof repo === 'string' && repo . length > 0
139144
140- const normalized = items . map ( normalizeWorkspaceRecord )
141- const filtered =
142- typeof repo === 'string' && repo . length > 0
143- ? normalized . filter ( item => item . repo === repo )
144- : normalized
145+ if ( hasRepoFilter ) {
146+ const byRepo = await db . getAllFromIndex (
147+ workspaceStoreName ,
148+ workspaceByRepoIndexName ,
149+ repo ,
150+ )
145151
146- return filtered . sort ( byLastModifiedDesc )
152+ return byRepo . map ( normalizeWorkspaceRecord ) . sort ( byLastModifiedDesc )
153+ }
154+
155+ const byLastModified = await db . getAllFromIndex (
156+ workspaceStoreName ,
157+ workspaceByLastModifiedIndexName ,
158+ )
159+
160+ return byLastModified . map ( normalizeWorkspaceRecord ) . reverse ( )
147161 }
148162
149163 const upsertWorkspace = async record => {
@@ -186,17 +200,37 @@ export const createWorkspaceStorageAdapter = ({ loadRuntime } = {}) => {
186200 const existingIndex = nextTabs . findIndex ( tab => tab . id === tabId )
187201 const previous = existingIndex >= 0 ? nextTabs [ existingIndex ] : null
188202
189- const next = normalizeTabRecord ( {
190- ...previous ,
203+ const nextTabRecord = {
204+ ...( previous ?? { } ) ,
191205 id : tabId ,
192- name,
193- path,
194- language,
195- content,
196- scroll,
197- isActive,
198206 lastModified : Date . now ( ) ,
199- } )
207+ }
208+
209+ if ( name !== undefined ) {
210+ nextTabRecord . name = name
211+ }
212+
213+ if ( path !== undefined ) {
214+ nextTabRecord . path = path
215+ }
216+
217+ if ( language !== undefined ) {
218+ nextTabRecord . language = language
219+ }
220+
221+ if ( content !== undefined ) {
222+ nextTabRecord . content = content
223+ }
224+
225+ if ( scroll !== undefined ) {
226+ nextTabRecord . scroll = scroll
227+ }
228+
229+ if ( isActive !== undefined ) {
230+ nextTabRecord . isActive = isActive
231+ }
232+
233+ const next = normalizeTabRecord ( nextTabRecord )
200234
201235 if ( ! next ) {
202236 throw new Error ( 'Unable to persist tab content because tab record is invalid.' )
@@ -255,6 +289,7 @@ export const createWorkspaceStorageAdapter = ({ loadRuntime } = {}) => {
255289
256290export const createDebouncedWorkspaceSaver = ( {
257291 save,
292+ onError,
258293 waitMs = 800 ,
259294 now = ( ) => Date . now ( ) ,
260295 schedule = setTimeout ,
@@ -269,6 +304,18 @@ export const createDebouncedWorkspaceSaver = ({
269304 let inFlight = Promise . resolve ( )
270305 let lastScheduledAt = 0
271306
307+ const reportSaveError = ( { error, payload } ) => {
308+ if ( typeof onError !== 'function' ) {
309+ return
310+ }
311+
312+ try {
313+ onError ( error , payload )
314+ } catch {
315+ /* Swallow reporter failures so saving can continue. */
316+ }
317+ }
318+
272319 const flush = async ( ) => {
273320 if ( ! pendingPayload ) {
274321 return
@@ -277,8 +324,15 @@ export const createDebouncedWorkspaceSaver = ({
277324 const payload = pendingPayload
278325 pendingPayload = null
279326
280- inFlight = inFlight . then ( ( ) => save ( payload ) )
281- await inFlight
327+ const continueChain = inFlight . catch ( ( ) => undefined )
328+ inFlight = continueChain . then ( ( ) => save ( payload ) )
329+
330+ try {
331+ await inFlight
332+ } catch ( error ) {
333+ reportSaveError ( { error, payload } )
334+ throw error
335+ }
282336 }
283337
284338 const queue = payload => {
@@ -291,7 +345,11 @@ export const createDebouncedWorkspaceSaver = ({
291345
292346 timer = schedule ( async ( ) => {
293347 timer = null
294- await flush ( )
348+ try {
349+ await flush ( )
350+ } catch {
351+ /* Background flush errors are surfaced through onError when provided. */
352+ }
295353 } , waitMs )
296354 }
297355
0 commit comments