@@ -227,15 +227,19 @@ final class WorkerConnection extends ProtocolChannel {
227227final class DatabaseClient implements WebSqlite {
228228 final Uri workerUri;
229229 final Uri wasmUri;
230+ final DatabaseController _localController;
230231
231232 final Lock _startWorkersLock = Lock ();
232233 bool _startedWorkers = false ;
233234 WorkerConnection ? _connectionToDedicated;
234235 WorkerConnection ? _connectionToShared;
235236 WorkerConnection ? _connectionToDedicatedInShared;
237+
238+ WorkerConnection ? _connectionToLocal;
239+
236240 final Set <MissingBrowserFeature > _missingFeatures = {};
237241
238- DatabaseClient (this .workerUri, this .wasmUri);
242+ DatabaseClient (this .workerUri, this .wasmUri, this ._localController );
239243
240244 Future <void > startWorkers () {
241245 return _startWorkersLock.synchronized (() async {
@@ -244,36 +248,52 @@ final class DatabaseClient implements WebSqlite {
244248 }
245249 _startedWorkers = true ;
246250
247- if (globalContext.has ('Worker' )) {
248- final dedicated = Worker (
251+ await _startDedicated ();
252+ await _startShared ();
253+ });
254+ }
255+
256+ Future <void > _startDedicated () async {
257+ if (globalContext.has ('Worker' )) {
258+ final Worker dedicated;
259+ try {
260+ dedicated = Worker (
249261 workerUri.toString ().toJS,
250262 WorkerOptions (name: 'sqlite3_worker' ),
251263 );
252-
253- final (endpoint, channel) = await createChannel ();
254- ConnectRequest (endpoint: endpoint, requestId: 0 )
255- .sendToWorker (dedicated);
256-
257- _connectionToDedicated =
258- WorkerConnection (channel.injectErrorsFrom (dedicated));
259- } else {
264+ } on Object {
260265 _missingFeatures.add (MissingBrowserFeature .dedicatedWorkers);
266+ return ;
261267 }
262268
263- if (globalContext.has ('SharedWorker' )) {
264- final shared = SharedWorker (workerUri.toString ().toJS);
265- shared.port.start ();
269+ final (endpoint, channel) = await createChannel ();
270+ ConnectRequest (endpoint: endpoint, requestId: 0 ).sendToWorker (dedicated);
266271
267- final (endpoint, channel) = await createChannel ();
268- ConnectRequest (endpoint: endpoint, requestId: 0 )
269- .sendToPort (shared.port);
272+ _connectionToDedicated =
273+ WorkerConnection (channel.injectErrorsFrom (dedicated));
274+ } else {
275+ _missingFeatures.add (MissingBrowserFeature .dedicatedWorkers);
276+ }
277+ }
270278
271- _connectionToShared =
272- WorkerConnection (channel.injectErrorsFrom (shared));
273- } else {
279+ Future <void > _startShared () async {
280+ if (globalContext.has ('SharedWorker' )) {
281+ final SharedWorker shared;
282+ try {
283+ shared = SharedWorker (workerUri.toString ().toJS);
284+ shared.port.start ();
285+ } on Object {
274286 _missingFeatures.add (MissingBrowserFeature .sharedWorkers);
287+ return ;
275288 }
276- });
289+
290+ final (endpoint, channel) = await createChannel ();
291+ ConnectRequest (endpoint: endpoint, requestId: 0 ).sendToPort (shared.port);
292+
293+ _connectionToShared = WorkerConnection (channel.injectErrorsFrom (shared));
294+ } else {
295+ _missingFeatures.add (MissingBrowserFeature .sharedWorkers);
296+ }
277297 }
278298
279299 Future <WorkerConnection > _connectToDedicatedInShared () {
@@ -291,6 +311,22 @@ final class DatabaseClient implements WebSqlite {
291311 });
292312 }
293313
314+ Future <WorkerConnection > _connectToLocal () async {
315+ return _startWorkersLock.synchronized (() async {
316+ if (_connectionToLocal case final conn? ) {
317+ return conn;
318+ }
319+
320+ final local = Local ();
321+ final (endpoint, channel) = await createChannel ();
322+ WorkerRunner (_localController, environment: local).handleRequests ();
323+ local
324+ .addTopLevelMessage (ConnectRequest (requestId: 0 , endpoint: endpoint));
325+
326+ return _connectionToLocal = WorkerConnection (channel);
327+ });
328+ }
329+
294330 @override
295331 Future <void > deleteDatabase (
296332 {required String name, required StorageMode storage}) async {
@@ -310,6 +346,7 @@ final class DatabaseClient implements WebSqlite {
310346
311347 final existing = < ExistingDatabase > {};
312348 final available = < (StorageMode , AccessMode )> [];
349+ var workersReportedIndexedDbSupport = false ;
313350
314351 if (_connectionToDedicated case final connection? ) {
315352 final response = await connection.sendRequest (
@@ -327,6 +364,8 @@ final class DatabaseClient implements WebSqlite {
327364 if (result.canUseIndexedDb) {
328365 available
329366 .add ((StorageMode .indexedDb, AccessMode .throughDedicatedWorker));
367+
368+ workersReportedIndexedDbSupport = true ;
330369 } else {
331370 _missingFeatures.add (MissingBrowserFeature .indexedDb);
332371 }
@@ -363,6 +402,7 @@ final class DatabaseClient implements WebSqlite {
363402 final result = CompatibilityResult .fromJS (response.response as JSObject );
364403
365404 if (result.canUseIndexedDb) {
405+ workersReportedIndexedDbSupport = true ;
366406 available.add ((StorageMode .indexedDb, AccessMode .throughSharedWorker));
367407 } else {
368408 _missingFeatures.add (MissingBrowserFeature .indexedDb);
@@ -383,6 +423,12 @@ final class DatabaseClient implements WebSqlite {
383423 }
384424 }
385425
426+ available.add ((StorageMode .inMemory, AccessMode .inCurrentContext));
427+ if (workersReportedIndexedDbSupport || await checkIndexedDbSupport ()) {
428+ // If the workers can use IndexedDb, so can we.
429+ available.add ((StorageMode .indexedDb, AccessMode .inCurrentContext));
430+ }
431+
386432 return FeatureDetectionResult (
387433 missingFeatures: _missingFeatures.toList (),
388434 existingDatabases: existing.toList (),
@@ -425,7 +471,8 @@ final class DatabaseClient implements WebSqlite {
425471 connection = _connectionToDedicated! ;
426472 shared = false ;
427473 case AccessMode .inCurrentContext:
428- throw UnimplementedError ('todo: Open database locally' );
474+ connection = await _connectToLocal ();
475+ shared = false ;
429476 }
430477
431478 final response = await connection.sendRequest (
0 commit comments