├── .prettierrc ├── pubspec.yaml ├── .metadata ├── LICENSE ├── CHANGELOG.md ├── example └── example.dart ├── README.md ├── .gitignore ├── lib └── jwt_decoder.dart ├── test └── jwt_decoder_test.dart └── pubspec.lock /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 2, 3 | "useTabs": false, 4 | "printWidth": 110, 5 | "semi": true 6 | } 7 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: jwt_decoder 2 | description: >- 3 | This small library helps you to decode Json Web Tokens, 4 | you can also know if a JWT is already expired. 5 | version: 2.0.2 6 | homepage: https://github.com/gustavo0197/dart-jwt-decoder 7 | 8 | environment: 9 | sdk: ">=3.5.2 <4.0.0" 10 | 11 | dev_dependencies: 12 | test: ^1.25.8 13 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: f139b11009aeb8ed2a3a3aa8b0066e482709dde3 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2020 Gustavo Velazquez 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # [2.0.2] - Changes expiration date's API 2 | 3 | - Makes `isExpired` return false when when there's no `exp` claim. 4 | - Makes both `getExpirationDate` and `getRemainingTime` return null when there's no `exp` claim. 5 | - Makes `getTokenTime` return null when there's no `iat` claim. 6 | 7 | # [2.0.1] 8 | 9 | - getRemainingTime() method 10 | 11 | # [2.0.0] 12 | 13 | - Migration to null safety 14 | - Updated SDK dependency version to 2.12.0+ 15 | - Avoid all null returns and replaced them with `FormatException` throws when tokens are not valid. This is a breaking change as users expecting null returns will now get an exception instead. 16 | - Added `JwtDecoder` methods documentation. 17 | - Replaced flutter framework dependencies to Dart only dependency. 18 | 19 | # [1.0.4] 20 | 21 | - isExpired() and getExpirationDate() the expiration time is converted to int 22 | 23 | # [1.0.3] 24 | 25 | - getExpirationDate() returns the expiration date of the token 26 | - getTokenTime() you can use this method to know how old your token is 27 | 28 | # [1.0.2] 29 | 30 | - License was added 31 | 32 | # [1.0.1] 33 | 34 | - An example file was added 35 | 36 | # [1.0.0] 37 | 38 | - decode method will decode your token's payload and return a Map 39 | - isExpired method is used to know if a token is already expired or not -------------------------------------------------------------------------------- /example/example.dart: -------------------------------------------------------------------------------- 1 | import 'package:jwt_decoder/jwt_decoder.dart'; 2 | 3 | main() { 4 | String token = 5 | "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikd1c3Rhdm8iLCJpYXQiOjE1MTYyMzkwMjIsImV4cCI6NDczNDYxNTg1OH0.hh-TTBPS8z-UxdmfXWn7AwW2y_Lq3aPnlIQdqV2KEC4"; 6 | 7 | /* decode() method will decode your token's payload */ 8 | Map decodedToken = JwtDecoder.decode(token); 9 | // Now you can use your decoded token 10 | print(decodedToken["name"]); 11 | 12 | /* isExpired() - you can use this method to know if your token is already expired or not. 13 | An useful method when you have to handle sessions and you want the user 14 | to authenticate if has an expired token */ 15 | bool isTokenExpired = JwtDecoder.isExpired(token); 16 | 17 | if (!isTokenExpired) { 18 | // The user should authenticate 19 | } 20 | 21 | /* getExpirationDate() - this method returns the expiration date of the token */ 22 | DateTime? expirationDate = JwtDecoder.getExpirationDate(token); 23 | if (expirationDate != null) { 24 | // 2120-01-13 16:04:18.000 25 | print(expirationDate); 26 | } 27 | 28 | /* getTokenTime() - You can use this method to know how old your token is */ 29 | Duration? tokenTime = JwtDecoder.getTokenTime(token); 30 | if (tokenTime != null) { 31 | print(tokenTime.inDays); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## JWT Decoder 2 | 3 | This is a small library for decoding a json web token for dart / flutter. Since the header and payload is base64 encoded you can easily know the stored data with no password, you can also know if the token is expired or not. 4 | 5 | If you like this library there's a version for Vue [here](https://github.com/gustavo0197/vue-easy-jwt). And for React [here](https://github.com/gustavo0197/react-jwt) 6 | 7 | ## Getting Started 8 | 9 | #### Decode a token 10 | 11 | ```dart 12 | main () { 13 | String yourToken = "Your JWT"; 14 | Map decodedToken = JwtDecoder.decode(yourToken); 15 | 16 | /* 17 | If the token has a valid format, you will get a Map 18 | Your decoded token can look like: 19 | { 20 | "sub": "1234567890", 21 | "name": "Gustavo", 22 | "iat": 1516239022, 23 | "exp": 1516239022, 24 | "randomKey": "something else" 25 | } 26 | */ 27 | } 28 | ``` 29 | 30 | #### Know if the token is expired 31 | 32 | ```dart 33 | main () { 34 | String yourToken = "Your JWT"; 35 | bool hasExpired = JwtDecoder.isExpired(yourToken); 36 | 37 | // You will get a true / false response 38 | // true: if the token is already expired 39 | // false: if the token is not expired 40 | } 41 | ``` 42 | 43 | #### Get expiration date 44 | 45 | ```dart 46 | main () { 47 | String yourToken = "Your JWT"; 48 | DateTime expirationDate = JwtDecoder.getExpirationDate(token); 49 | 50 | // 2025-01-13 13:04:18.000 51 | print(expirationDate); 52 | } 53 | ``` 54 | 55 | #### You can know how old your token is 56 | 57 | ```dart 58 | // Token payload must include an 'iat' field 59 | main () { 60 | String yourToken = "Your JWT"; 61 | Duration tokenTime = JwtDecoder.getTokenTime(token); 62 | 63 | // 15 64 | print(tokenTime.inDays); 65 | } 66 | ``` 67 | 68 | ## License 69 | 70 | MIT 71 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .flutter-plugins-dependencies 28 | .packages 29 | .pub-cache/ 30 | .pub/ 31 | build/ 32 | 33 | # Android related 34 | **/android/**/gradle-wrapper.jar 35 | **/android/.gradle 36 | **/android/captures/ 37 | **/android/gradlew 38 | **/android/gradlew.bat 39 | **/android/local.properties 40 | **/android/**/GeneratedPluginRegistrant.java 41 | 42 | # iOS/XCode related 43 | **/ios/**/*.mode1v3 44 | **/ios/**/*.mode2v3 45 | **/ios/**/*.moved-aside 46 | **/ios/**/*.pbxuser 47 | **/ios/**/*.perspectivev3 48 | **/ios/**/*sync/ 49 | **/ios/**/.sconsign.dblite 50 | **/ios/**/.tags* 51 | **/ios/**/.vagrant/ 52 | **/ios/**/DerivedData/ 53 | **/ios/**/Icon? 54 | **/ios/**/Pods/ 55 | **/ios/**/.symlinks/ 56 | **/ios/**/profile 57 | **/ios/**/xcuserdata 58 | **/ios/.generated/ 59 | **/ios/Flutter/App.framework 60 | **/ios/Flutter/Flutter.framework 61 | **/ios/Flutter/Flutter.podspec 62 | **/ios/Flutter/Generated.xcconfig 63 | **/ios/Flutter/app.flx 64 | **/ios/Flutter/app.zip 65 | **/ios/Flutter/flutter_assets/ 66 | **/ios/Flutter/flutter_export_environment.sh 67 | **/ios/ServiceDefinitions.json 68 | **/ios/Runner/GeneratedPluginRegistrant.* 69 | 70 | # Exceptions to above rules. 71 | !**/ios/**/default.mode1v3 72 | !**/ios/**/default.mode2v3 73 | !**/ios/**/default.pbxuser 74 | !**/ios/**/default.perspectivev3 75 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 76 | -------------------------------------------------------------------------------- /lib/jwt_decoder.dart: -------------------------------------------------------------------------------- 1 | library jwt_decoder; 2 | 3 | import 'dart:convert'; 4 | 5 | class JwtDecoder { 6 | /// Decode a string JWT token into a `Map` 7 | /// containing the decoded JSON payload. 8 | /// 9 | /// Note: header and signature are not returned by this method. 10 | /// 11 | /// Throws [FormatException] if parameter is not a valid JWT token. 12 | static Map decode(String token) { 13 | final splitToken = token.split("."); // Split the token by '.' 14 | if (splitToken.length != 3) { 15 | throw FormatException('Invalid token'); 16 | } 17 | try { 18 | final payloadBase64 = splitToken[1]; // Payload is always the index 1 19 | // Base64 should be multiple of 4. Normalize the payload before decode it 20 | final normalizedPayload = base64.normalize(payloadBase64); 21 | // Decode payload, the result is a String 22 | final payloadString = utf8.decode(base64.decode(normalizedPayload)); 23 | // Parse the String to a Map 24 | final decodedPayload = jsonDecode(payloadString); 25 | 26 | // Return the decoded payload 27 | return decodedPayload; 28 | } catch (error) { 29 | throw FormatException('Invalid payload'); 30 | } 31 | } 32 | 33 | /// Decode a string JWT token into a `Map` 34 | /// containing the decoded JSON payload. 35 | /// 36 | /// Note: header and signature are not returned by this method. 37 | /// 38 | /// Returns null if the token is not valid 39 | static Map? tryDecode(String token) { 40 | try { 41 | return decode(token); 42 | } catch (error) { 43 | return null; 44 | } 45 | } 46 | 47 | /// Tells whether a token is expired. 48 | /// 49 | /// Returns false if the token is valid, true if it is expired. 50 | /// 51 | /// Throws [FormatException] if parameter is not a valid JWT token. 52 | static bool isExpired(String token) { 53 | final expirationDate = getExpirationDate(token); 54 | if (expirationDate == null) { 55 | return false; 56 | } 57 | // If the current date is after the expiration date, the token is already expired 58 | return DateTime.now().isAfter(expirationDate); 59 | } 60 | 61 | static DateTime? _getDate({required String token, required String claim}) { 62 | final decodedToken = decode(token); 63 | final expiration = decodedToken[claim] as int?; 64 | if (expiration == null) { 65 | return null; 66 | } 67 | return DateTime.fromMillisecondsSinceEpoch(expiration * 1000); 68 | } 69 | 70 | /// Returns token expiration date 71 | /// 72 | /// Throws [FormatException] if parameter is not a valid JWT token. 73 | static DateTime? getExpirationDate(String token) { 74 | return _getDate(token: token, claim: 'exp'); 75 | } 76 | 77 | /// Returns token issuing date (iat) 78 | /// 79 | /// Throws [FormatException] if parameter is not a valid JWT token. 80 | static Duration? getTokenTime(String token) { 81 | final issuedAtDate = _getDate(token: token, claim: 'iat'); 82 | if (issuedAtDate == null) { 83 | return null; 84 | } 85 | return DateTime.now().difference(issuedAtDate); 86 | } 87 | 88 | /// Returns remaining time until expiry date. 89 | /// 90 | /// Throws [FormatException] if parameter is not a valid JWT token. 91 | static Duration? getRemainingTime(String token) { 92 | final expirationDate = getExpirationDate(token); 93 | if (expirationDate == null) { 94 | return null; 95 | } 96 | 97 | return expirationDate.difference(DateTime.now()); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /test/jwt_decoder_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:jwt_decoder/jwt_decoder.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | const token = 5 | "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikd1c3Rhdm8iLCJpYXQiOjE1MTYyMzkwMjIsImV4cCI6NDczNDYxNTg1OH0.hh-TTBPS8z-UxdmfXWn7AwW2y_Lq3aPnlIQdqV2KEC4"; 6 | const expiredToken = 7 | "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE1MjYyMzkwMjJ9.GMdV0dx1F8rZuHUebeXL5tR2DROlc03IuDc2DeDTExI"; 8 | const tokenWithoutExpirationTime = 9 | "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; 10 | const tokenWithoutIatClaim = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIn0.Gfx6VO9tcxwk6xqx9yYzSfebfeakZp5JYIgP_edcw_A"; 11 | 12 | void main() { 13 | group('Decode', () { 14 | test("a valid token", () { 15 | expect(JwtDecoder.decode(token)["name"], "Gustavo"); 16 | }); 17 | 18 | test("an invalid token", () { 19 | expect( 20 | () => JwtDecoder.decode(""), 21 | throwsA(isA().having((e) => e.message, 'message', 'Invalid token')), 22 | ); 23 | }); 24 | 25 | test("an invalid payload", () { 26 | expect( 27 | () => JwtDecoder.decode("a.b.c"), 28 | throwsA(isA().having((e) => e.message, 'message', 'Invalid payload')), 29 | ); 30 | }); 31 | }); 32 | 33 | group('Try decode', () { 34 | test("a valid token", () { 35 | expect(JwtDecoder.tryDecode(token)!["name"], "Gustavo"); 36 | }); 37 | 38 | test("an invalid token", () { 39 | expect(JwtDecoder.tryDecode(""), isNull); 40 | }); 41 | 42 | test("an invalid payload", () { 43 | expect(JwtDecoder.tryDecode("a.b.c"), isNull); 44 | }); 45 | }); 46 | 47 | test("isExpired? Valid and no expired token", () { 48 | expect(JwtDecoder.isExpired(token), false); 49 | }); 50 | 51 | test("token without exp claim is not expired", () { 52 | expect(JwtDecoder.isExpired(tokenWithoutExpirationTime), false); 53 | }); 54 | 55 | test("isExpired? Valid but expired token", () { 56 | expect(JwtDecoder.isExpired(expiredToken), true); 57 | }); 58 | 59 | test("isExpired? Invalid token", () { 60 | expect( 61 | () => JwtDecoder.isExpired("lñaslksa"), 62 | throwsA(isA().having((e) => e.message, 'message', 'Invalid token')), 63 | ); 64 | }); 65 | 66 | test("Expiration date", () { 67 | expect(JwtDecoder.getExpirationDate(token)!.isAfter(new DateTime.now()), true); 68 | }); 69 | 70 | test("expiration date from token without exp claim is null", () { 71 | expect(JwtDecoder.getExpirationDate(tokenWithoutExpirationTime), isNull); 72 | }); 73 | 74 | test("Expiration date with invalid token", () { 75 | expect( 76 | () => JwtDecoder.getExpirationDate("an.invalid.payload"), 77 | throwsA(isA().having((e) => e.message, 'message', 'Invalid payload')), 78 | ); 79 | }); 80 | 81 | test("Expiration time", () { 82 | expect(JwtDecoder.getTokenTime(token)!.inDays, greaterThan(1)); 83 | }); 84 | 85 | test("token time from token without iat claim is null", () { 86 | expect(JwtDecoder.getTokenTime(tokenWithoutIatClaim), isNull); 87 | }); 88 | 89 | test("Expiration time with invalid token", () { 90 | expect( 91 | () => JwtDecoder.getTokenTime("invalid.token"), 92 | throwsA(isA().having((e) => e.message, 'message', 'Invalid token')), 93 | ); 94 | }); 95 | 96 | test("Remaining time from now", () { 97 | expect(JwtDecoder.getRemainingTime(token)!.inSeconds, greaterThan(0)); 98 | }); 99 | 100 | test("remaining time from token without exp claim is null", () { 101 | expect(JwtDecoder.getRemainingTime(token)!.inSeconds, greaterThan(0)); 102 | }); 103 | } 104 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | _fe_analyzer_shared: 5 | dependency: transitive 6 | description: 7 | name: _fe_analyzer_shared 8 | sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "67.0.0" 12 | analyzer: 13 | dependency: transitive 14 | description: 15 | name: analyzer 16 | sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "6.4.1" 20 | args: 21 | dependency: transitive 22 | description: 23 | name: args 24 | sha256: "37a4264b0b7fb930e94c0c47558f3b6c4f4e9cb7e655a3ea373131d79b2dc0cc" 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "2.0.0" 28 | async: 29 | dependency: transitive 30 | description: 31 | name: async 32 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "2.11.0" 36 | boolean_selector: 37 | dependency: transitive 38 | description: 39 | name: boolean_selector 40 | sha256: "5bbf32bc9e518d41ec49718e2931cd4527292c9b0c6d2dffcf7fe6b9a8a8cf72" 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "2.1.0" 44 | charcode: 45 | dependency: transitive 46 | description: 47 | name: charcode 48 | sha256: "8e36feea6de5ea69f2199f29cf42a450a855738c498b57c0b980e2d3cca9c362" 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "1.2.0" 52 | collection: 53 | dependency: transitive 54 | description: 55 | name: collection 56 | sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf 57 | url: "https://pub.dev" 58 | source: hosted 59 | version: "1.19.0" 60 | convert: 61 | dependency: transitive 62 | description: 63 | name: convert 64 | sha256: df567b950053d83b4dba3e8c5799c411895d146f82b2147114b666a4fd9a80dd 65 | url: "https://pub.dev" 66 | source: hosted 67 | version: "3.0.0" 68 | coverage: 69 | dependency: transitive 70 | description: 71 | name: coverage 72 | sha256: f63518ac8e08ea3288130fbc276ca7e66ce2298e04462ab1460038ad22fb3747 73 | url: "https://pub.dev" 74 | source: hosted 75 | version: "1.0.1" 76 | crypto: 77 | dependency: transitive 78 | description: 79 | name: crypto 80 | sha256: "8be10341257b613566fdc9fd073c46f7c032ed329b1c732bda17aca29f2366c8" 81 | url: "https://pub.dev" 82 | source: hosted 83 | version: "3.0.0" 84 | file: 85 | dependency: transitive 86 | description: 87 | name: file 88 | sha256: "9fd2163d866769f60f4df8ac1dc59f52498d810c356fe78022e383dd3c57c0e1" 89 | url: "https://pub.dev" 90 | source: hosted 91 | version: "6.1.0" 92 | frontend_server_client: 93 | dependency: transitive 94 | description: 95 | name: frontend_server_client 96 | sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 97 | url: "https://pub.dev" 98 | source: hosted 99 | version: "4.0.0" 100 | glob: 101 | dependency: transitive 102 | description: 103 | name: glob 104 | sha256: "36a6ea2cac1f93742ecee02250fb498122c0993eb948120ff0dbef6cd694beb8" 105 | url: "https://pub.dev" 106 | source: hosted 107 | version: "2.0.0" 108 | http_multi_server: 109 | dependency: transitive 110 | description: 111 | name: http_multi_server 112 | sha256: ac10cae1b9a06fb638a92a72b00570bac856f524f7ee0d9a13eaed4960c7fd43 113 | url: "https://pub.dev" 114 | source: hosted 115 | version: "3.0.0" 116 | http_parser: 117 | dependency: transitive 118 | description: 119 | name: http_parser 120 | sha256: e362d639ba3bc07d5a71faebb98cde68c05bfbcfbbb444b60b6f60bb67719185 121 | url: "https://pub.dev" 122 | source: hosted 123 | version: "4.0.0" 124 | io: 125 | dependency: transitive 126 | description: 127 | name: io 128 | sha256: "15a5436d2a02dc60e6dc2fb5d7dfaac08b7b137cff3d4bf3158d38ecab656b69" 129 | url: "https://pub.dev" 130 | source: hosted 131 | version: "1.0.0" 132 | js: 133 | dependency: transitive 134 | description: 135 | name: js 136 | sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf 137 | url: "https://pub.dev" 138 | source: hosted 139 | version: "0.7.1" 140 | logging: 141 | dependency: transitive 142 | description: 143 | name: logging 144 | sha256: "3730d4c02b0c2d1db80ef9904e27fa796d75474f572a70011e0e616ee6bfc0ff" 145 | url: "https://pub.dev" 146 | source: hosted 147 | version: "1.0.0" 148 | matcher: 149 | dependency: transitive 150 | description: 151 | name: matcher 152 | sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb 153 | url: "https://pub.dev" 154 | source: hosted 155 | version: "0.12.16+1" 156 | meta: 157 | dependency: transitive 158 | description: 159 | name: meta 160 | sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 161 | url: "https://pub.dev" 162 | source: hosted 163 | version: "1.15.0" 164 | mime: 165 | dependency: transitive 166 | description: 167 | name: mime 168 | sha256: a7a98ea7f366e2cc9d2b20873815aebec5e2bc124fe0da9d3f7f59b0625ea180 169 | url: "https://pub.dev" 170 | source: hosted 171 | version: "1.0.0" 172 | node_preamble: 173 | dependency: transitive 174 | description: 175 | name: node_preamble 176 | sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" 177 | url: "https://pub.dev" 178 | source: hosted 179 | version: "2.0.2" 180 | package_config: 181 | dependency: transitive 182 | description: 183 | name: package_config 184 | sha256: "20e7154d701fedaeb219dad732815ecb66677667871127998a9a6581c2aba4ba" 185 | url: "https://pub.dev" 186 | source: hosted 187 | version: "2.0.0" 188 | path: 189 | dependency: transitive 190 | description: 191 | name: path 192 | sha256: "2ad4cddff7f5cc0e2d13069f2a3f7a73ca18f66abd6f5ecf215219cdb3638edb" 193 | url: "https://pub.dev" 194 | source: hosted 195 | version: "1.8.0" 196 | pedantic: 197 | dependency: transitive 198 | description: 199 | name: pedantic 200 | sha256: "8f6460c77a98ad2807cd3b98c67096db4286f56166852d0ce5951bb600a63594" 201 | url: "https://pub.dev" 202 | source: hosted 203 | version: "1.11.0" 204 | pool: 205 | dependency: transitive 206 | description: 207 | name: pool 208 | sha256: "05955e3de2683e1746222efd14b775df7131139e07695dc8e24650f6b4204504" 209 | url: "https://pub.dev" 210 | source: hosted 211 | version: "1.5.0" 212 | pub_semver: 213 | dependency: transitive 214 | description: 215 | name: pub_semver 216 | sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" 217 | url: "https://pub.dev" 218 | source: hosted 219 | version: "2.1.4" 220 | shelf: 221 | dependency: transitive 222 | description: 223 | name: shelf 224 | sha256: c0710a5ca61f1a96e9aae37081040f537c1b96265040edeb70c8817a10d361c6 225 | url: "https://pub.dev" 226 | source: hosted 227 | version: "1.0.0" 228 | shelf_packages_handler: 229 | dependency: transitive 230 | description: 231 | name: shelf_packages_handler 232 | sha256: e0b44ebddec91e70a713e13adf93c1b2100821303b86a18e1ef1d082bd8bd9b8 233 | url: "https://pub.dev" 234 | source: hosted 235 | version: "3.0.0" 236 | shelf_static: 237 | dependency: transitive 238 | description: 239 | name: shelf_static 240 | sha256: "8584c0aa0f5756a61519b1a2fc2cd22ddbc518e9396bd33ebf06b9836bb23d13" 241 | url: "https://pub.dev" 242 | source: hosted 243 | version: "1.0.0" 244 | shelf_web_socket: 245 | dependency: transitive 246 | description: 247 | name: shelf_web_socket 248 | sha256: "520368a1a49798425310ca0ee28eb92b3c737e4e9d173c31b6c66fe090ebc6fc" 249 | url: "https://pub.dev" 250 | source: hosted 251 | version: "1.0.0" 252 | source_map_stack_trace: 253 | dependency: transitive 254 | description: 255 | name: source_map_stack_trace 256 | sha256: "8c463326277f68a628abab20580047b419c2ff66756fd0affd451f73f9508c11" 257 | url: "https://pub.dev" 258 | source: hosted 259 | version: "2.1.0" 260 | source_maps: 261 | dependency: transitive 262 | description: 263 | name: source_maps 264 | sha256: "52de2200bb098de739794c82d09c41ac27b2e42fd7e23cce7b9c74bf653c7296" 265 | url: "https://pub.dev" 266 | source: hosted 267 | version: "0.10.10" 268 | source_span: 269 | dependency: transitive 270 | description: 271 | name: source_span 272 | sha256: d5f89a9e52b36240a80282b3dc0667dd36e53459717bb17b8fb102d30496606a 273 | url: "https://pub.dev" 274 | source: hosted 275 | version: "1.8.1" 276 | stack_trace: 277 | dependency: transitive 278 | description: 279 | name: stack_trace 280 | sha256: f8d9f247e2f9f90e32d1495ff32dac7e4ae34ffa7194c5ff8fcc0fd0e52df774 281 | url: "https://pub.dev" 282 | source: hosted 283 | version: "1.10.0" 284 | stream_channel: 285 | dependency: transitive 286 | description: 287 | name: stream_channel 288 | sha256: db47e4797198ee601990820437179bb90219f918962318d494ada2b4b11e6f6d 289 | url: "https://pub.dev" 290 | source: hosted 291 | version: "2.1.0" 292 | string_scanner: 293 | dependency: transitive 294 | description: 295 | name: string_scanner 296 | sha256: dd11571b8a03f7cadcf91ec26a77e02bfbd6bbba2a512924d3116646b4198fc4 297 | url: "https://pub.dev" 298 | source: hosted 299 | version: "1.1.0" 300 | term_glyph: 301 | dependency: transitive 302 | description: 303 | name: term_glyph 304 | sha256: a88162591b02c1f3a3db3af8ce1ea2b374bd75a7bb8d5e353bcfbdc79d719830 305 | url: "https://pub.dev" 306 | source: hosted 307 | version: "1.2.0" 308 | test: 309 | dependency: "direct dev" 310 | description: 311 | name: test 312 | sha256: "713a8789d62f3233c46b4a90b174737b2c04cb6ae4500f2aa8b1be8f03f5e67f" 313 | url: "https://pub.dev" 314 | source: hosted 315 | version: "1.25.8" 316 | test_api: 317 | dependency: transitive 318 | description: 319 | name: test_api 320 | sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" 321 | url: "https://pub.dev" 322 | source: hosted 323 | version: "0.7.3" 324 | test_core: 325 | dependency: transitive 326 | description: 327 | name: test_core 328 | sha256: "12391302411737c176b0b5d6491f466b0dd56d4763e347b6714efbaa74d7953d" 329 | url: "https://pub.dev" 330 | source: hosted 331 | version: "0.6.5" 332 | typed_data: 333 | dependency: transitive 334 | description: 335 | name: typed_data 336 | sha256: "53bdf7e979cfbf3e28987552fd72f637e63f3c8724c9e56d9246942dc2fa36ee" 337 | url: "https://pub.dev" 338 | source: hosted 339 | version: "1.3.0" 340 | vm_service: 341 | dependency: transitive 342 | description: 343 | name: vm_service 344 | sha256: "9a71c98ff3cb902be7d6df76d0e14c41d2f1727a1fc38b7c354fe03abb5c1753" 345 | url: "https://pub.dev" 346 | source: hosted 347 | version: "6.1.0+1" 348 | watcher: 349 | dependency: transitive 350 | description: 351 | name: watcher 352 | sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" 353 | url: "https://pub.dev" 354 | source: hosted 355 | version: "1.1.0" 356 | web_socket_channel: 357 | dependency: transitive 358 | description: 359 | name: web_socket_channel 360 | sha256: "500e6014efebd305a30ebf1c6006d13faa82dcd85c7a2a7793679a64ed69ec48" 361 | url: "https://pub.dev" 362 | source: hosted 363 | version: "2.0.0" 364 | webkit_inspection_protocol: 365 | dependency: transitive 366 | description: 367 | name: webkit_inspection_protocol 368 | sha256: "5adb6ab8ed14e22bb907aae7338f0c206ea21e7a27004e97664b16c120306f00" 369 | url: "https://pub.dev" 370 | source: hosted 371 | version: "1.0.0" 372 | yaml: 373 | dependency: transitive 374 | description: 375 | name: yaml 376 | sha256: "3cee79b1715110341012d27756d9bae38e650588acd38d3f3c610822e1337ace" 377 | url: "https://pub.dev" 378 | source: hosted 379 | version: "3.1.0" 380 | sdks: 381 | dart: ">=3.5.2 <4.0.0" 382 | --------------------------------------------------------------------------------