From 1e61585576bae1c10a43cd605b0a0500a403878c Mon Sep 17 00:00:00 2001 From: Dan Reynolds Date: Tue, 4 Nov 2025 09:31:37 -0500 Subject: [PATCH 1/3] autogenerate document IDs --- example/lib/random_operation_runner.dart | 3 ++- lib/broadcast_observer.dart | 4 +--- lib/collection.dart | 4 ++-- lib/loon.dart | 4 ++-- lib/persistor/worker/messages.dart | 6 ++--- lib/utils/id.dart | 29 ++++++++++++++++++++++++ pubspec.yaml | 3 +-- test/utils.dart | 2 -- 8 files changed, 39 insertions(+), 16 deletions(-) create mode 100644 lib/utils/id.dart diff --git a/example/lib/random_operation_runner.dart b/example/lib/random_operation_runner.dart index 581b3fa..7595e31 100644 --- a/example/lib/random_operation_runner.dart +++ b/example/lib/random_operation_runner.dart @@ -3,6 +3,7 @@ import 'dart:math'; import 'package:example/models/user.dart'; import 'package:loon/loon.dart'; +import 'package:loon/utils/id.dart'; enum Operations { hydrate, @@ -24,7 +25,7 @@ class RandomOperationRunner { _logger.log('Persist $count'); for (int i = 0; i < count; i++) { - final id = uuid.v4(); + final id = generateId(); UserModel.store.doc(id).create(UserModel(name: 'User $id')); } } else if (operationIndex >= 80 && operationIndex < 90) { diff --git a/lib/broadcast_observer.dart b/lib/broadcast_observer.dart index e0c8e55..8d7e549 100644 --- a/lib/broadcast_observer.dart +++ b/lib/broadcast_observer.dart @@ -1,7 +1,5 @@ part of './loon.dart'; -const uuid = Uuid(); - /// A mixin that provides an observable interface for the access and streaming of data broadcasted from the store. mixin BroadcastObserver { late final StreamController _controller; @@ -45,7 +43,7 @@ mixin BroadcastObserver { _controllerValue = initialValue; _controller.add(initialValue); - _observerId = "${path}__${uuid.v4()}"; + _observerId = "${path}__${generateId()}"; Loon._instance.broadcastManager.addObserver(this, initialValue); } diff --git a/lib/collection.dart b/lib/collection.dart index 7ee6eb4..a5c0633 100644 --- a/lib/collection.dart +++ b/lib/collection.dart @@ -86,10 +86,10 @@ class Collection implements Queryable, StoreReference { Loon._instance._isGlobalPersistenceEnabled; } - Document doc(String id) { + Document doc([String? id]) { return Document( path, - id, + id ?? generateId(), fromJson: fromJson, toJson: toJson, persistorSettings: persistorSettings, diff --git a/lib/loon.dart b/lib/loon.dart index 35e5165..982e3b7 100644 --- a/lib/loon.dart +++ b/lib/loon.dart @@ -4,7 +4,7 @@ import 'dart:async'; import 'dart:convert'; import 'package:flutter/foundation.dart' hide Key; import 'package:loon/persistor/data_store_encrypter.dart'; -import 'package:uuid/uuid.dart'; +import 'package:loon/utils/id.dart'; import 'dart:collection'; import 'persistor/index.dart'; @@ -121,7 +121,7 @@ class Loon { }, ).toList(); - return List>.from(snaps ?? []); + return snaps ?? []; } DocumentSnapshot writeDocument( diff --git a/lib/persistor/worker/messages.dart b/lib/persistor/worker/messages.dart index 5b01cc8..4fa5c39 100644 --- a/lib/persistor/worker/messages.dart +++ b/lib/persistor/worker/messages.dart @@ -1,13 +1,11 @@ import 'dart:isolate'; import 'package:loon/persistor/persist_payload.dart'; -import 'package:uuid/uuid.dart'; - -const uuid = Uuid(); +import 'package:loon/utils/id.dart'; abstract class Message {} abstract class MessageRequest extends Message { - final id = uuid.v4(); + final id = generateId(); MessageRequest(); diff --git a/lib/utils/id.dart b/lib/utils/id.dart new file mode 100644 index 0000000..6869f9a --- /dev/null +++ b/lib/utils/id.dart @@ -0,0 +1,29 @@ +import 'dart:math'; +import 'dart:typed_data'; + +const String _alphabet = + '_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; +final Uint8List _alphabytes = Uint8List.fromList(_alphabet.codeUnits); +const int _u32 = 0x100000000; // 2^32 + +final Random _rand = Random.secure(); + +/// Generates a cryptographically secure, URL-safe random ID. +/// Default: 21 chars ≈ 126 bits of entropy. +String generateId([int size = 21]) { + final out = Uint8List(size); + var i = 0; + + while (i < size) { + int r = _rand.nextInt(_u32); // 32 random bits → 5×6-bit chars + + var k = 0; + while (k < 5 && i < size) { + out[i++] = _alphabytes[r & 63]; + r >>= 6; + k++; + } + } + + return String.fromCharCodes(out); +} diff --git a/pubspec.yaml b/pubspec.yaml index 1483b50..bfc2de8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,11 +4,10 @@ version: 5.5.0 homepage: https://github.com/danReynolds/loon environment: - sdk: '>=3.0.0 <4.0.0' + sdk: '>=3.3.0 <4.0.0' flutter: ">=1.17.0" dependencies: - uuid: ^4.3.3 encrypt: ^5.0.3 flutter: sdk: flutter diff --git a/test/utils.dart b/test/utils.dart index fca9b3b..459c372 100644 --- a/test/utils.dart +++ b/test/utils.dart @@ -2,9 +2,7 @@ import 'dart:async'; import 'dart:convert'; import 'package:encrypt/encrypt.dart'; import 'package:loon/loon.dart'; -import 'package:uuid/uuid.dart'; -const uuid = Uuid(); final testEncryptionKey = Key.fromSecureRandom(32); String encryptData(Json json) { From 652cdfec75afd1d171f5b2500f41b3fc552a6194 Mon Sep 17 00:00:00 2001 From: Dan Reynolds Date: Tue, 4 Nov 2025 09:33:15 -0500 Subject: [PATCH 2/3] revert env change --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index bfc2de8..d368c7f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,7 +4,7 @@ version: 5.5.0 homepage: https://github.com/danReynolds/loon environment: - sdk: '>=3.3.0 <4.0.0' + sdk: '>=3.0.0 <4.0.0' flutter: ">=1.17.0" dependencies: From a778dd5118da4ea634fd599d749fb89a4b5fbd04 Mon Sep 17 00:00:00 2001 From: Dan Reynolds Date: Tue, 4 Nov 2025 09:36:51 -0500 Subject: [PATCH 3/3] revert env change --- lib/utils/id.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/utils/id.dart b/lib/utils/id.dart index 6869f9a..bb0db8c 100644 --- a/lib/utils/id.dart +++ b/lib/utils/id.dart @@ -15,7 +15,7 @@ String generateId([int size = 21]) { var i = 0; while (i < size) { - int r = _rand.nextInt(_u32); // 32 random bits → 5×6-bit chars + int r = _rand.nextInt(_u32); // 5×6-bit chars (30 bits used, 2 bits unused) var k = 0; while (k < 5 && i < size) {