Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ jobs:
steps:
- uses: actions/checkout@v4

- uses: subosito/flutter-action@v2
with:
channel: 'stable'

- uses: actions/setup-node@v4
with:
node-version: 20
Expand All @@ -29,6 +33,10 @@ jobs:
steps:
- uses: actions/checkout@v4

- uses: subosito/flutter-action@v2
with:
channel: 'stable'

- uses: actions/setup-node@v4
with:
node-version: 20
Expand All @@ -53,6 +61,10 @@ jobs:
steps:
- uses: actions/checkout@v4

- uses: subosito/flutter-action@v2
with:
channel: 'stable'

- uses: actions/setup-node@v4
with:
node-version: 20
Expand Down
4 changes: 4 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- **Node.js**: 20+ (managed by `npm`)
- **Docker**: Required for simulation engine
- **Package Manager**: `npm` (Node)
- **Flutter**: stable channel (worker_flutter)

## Setup
- **Install Node Dependencies**: `npm run install:all`
Expand All @@ -29,6 +30,8 @@
- **Worker Install**: `cd worker && npm install`
- **Worker Dev**: `cd worker && npm run dev`
- **Worker Test**: `cd worker && npm run test:unit`
- **Worker Flutter Lint**: `cd worker_flutter && flutter analyze --no-fatal-infos`
- **Worker Flutter Test**: `cd worker_flutter && flutter test`

## Deployment
- **CI**: `.github/workflows/ci.yml` (Runs on PR)
Expand All @@ -38,3 +41,4 @@
- `frontend/`: React app
- `api/`: Next.js API, ingestion, and analysis
- `worker/`: Node.js + Docker simulation runner
- `worker_flutter/`: Cross-platform desktop worker (macOS/Windows)
4 changes: 4 additions & 0 deletions scripts/lint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@ cd frontend && npm ci && npm run lint && cd ..
# API
echo "=== API lint ==="
cd api && npm ci && npm run lint && cd ..

# Worker Flutter
echo "=== Worker Flutter lint ==="
cd worker_flutter && flutter pub get && flutter analyze --no-fatal-infos && cd ..
4 changes: 4 additions & 0 deletions scripts/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,7 @@ npm run test:ingestion && cd ..
# Worker tests
echo "=== Worker unit tests ==="
cd worker && npm ci && npm run test:unit && cd ..

# Worker Flutter tests
echo "=== Worker Flutter tests ==="
cd worker_flutter && flutter pub get && flutter test && cd ..
1 change: 0 additions & 1 deletion worker_flutter/lib/api_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import 'dart:io';

import 'package:firebase_app_check/firebase_app_check.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
import 'package:worker_flutter/main.dart';

Expand Down
2 changes: 1 addition & 1 deletion worker_flutter/lib/offline/db/app_db.dart
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class AppDb extends _$AppDb {
/// test suite with `NativeDatabase.memory()` for hermetic, fast
/// integration tests that exercise the same SQL the app does at
/// runtime β€” but without touching disk.
AppDb.forTesting(QueryExecutor e) : super(e);
AppDb.forTesting(super.e);

@override
int get schemaVersion => 2;
Expand Down
2 changes: 1 addition & 1 deletion worker_flutter/lib/offline/deck_source.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class PreconDeck {
}

/// Loads precons from the Flutter asset bundle PLUS any extra .dck
/// files the user may have dropped into `<forgePath>/res/Decks/
/// files the user may have dropped into `&lt;forgePath&gt;/res/Decks/
/// Commander/`. The bundled set is the floor β€” offline mode works
/// from a fresh install without a Forge download.
Future<List<PreconDeck>> loadBundledPrecons(String forgePath) async {
Expand Down
4 changes: 2 additions & 2 deletions worker_flutter/lib/sims/deck_picker_section.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ class DeckPickerSection extends StatefulWidget {
}

class _DeckPickerSectionState extends State<DeckPickerSection> {
late final ExpansionTileController _ctrl;
late final ExpansibleController _ctrl;

@override
void initState() {
super.initState();
_ctrl = ExpansionTileController();
_ctrl = ExpansibleController();
}

@override
Expand Down
7 changes: 2 additions & 5 deletions worker_flutter/lib/telemetry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,7 @@ class Telemetry {
tags.forEach(scope.setTag);
}
if (extra != null) {
// ignore: deprecated_member_use β€” `setExtra` is the documented
// 8.x API. Sentry's 9.x release moves to structured contexts.
extra.forEach(scope.setExtra);
scope.setContexts('extra', extra);
}
},
);
Expand Down Expand Up @@ -111,8 +109,7 @@ SentryEvent? scrubPii(SentryEvent event, {Hint? hint}) {
? event
: event.copyWith(user: SentryUser(id: '[redacted]'));

// ignore: deprecated_member_use β€” see comment in Telemetry.captureError.
final extra = cleaned.extra;
final extra = cleaned.contexts['extra'] as Map<String, dynamic>?;
if (extra != null) {
for (final key in extra.keys.toList()) {
if (_piiKeys.contains(key)) {
Expand Down
10 changes: 5 additions & 5 deletions worker_flutter/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -692,10 +692,10 @@ packages:
dependency: transitive
description:
name: matcher
sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6"
url: "https://pub.dev"
source: hosted
version: "0.12.19"
version: "0.12.18"
material_color_utilities:
dependency: transitive
description:
Expand Down Expand Up @@ -1193,10 +1193,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636"
url: "https://pub.dev"
source: hosted
version: "0.7.10"
version: "0.7.9"
tray_manager:
dependency: "direct main"
description:
Expand Down Expand Up @@ -1374,5 +1374,5 @@ packages:
source: hosted
version: "3.1.3"
sdks:
dart: ">=3.11.5 <4.0.0"
dart: ">=3.11.0 <4.0.0"
flutter: ">=3.38.4"
2 changes: 1 addition & 1 deletion worker_flutter/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ publish_to: 'none'
version: 0.2.0+1

environment:
sdk: ^3.11.5
sdk: '>=3.11.0 <4.0.0'

dependencies:
flutter:
Expand Down
1 change: 0 additions & 1 deletion worker_flutter/test/offline/resume_test.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import 'dart:async';
import 'dart:io';

import 'package:drift/drift.dart' show Value;
Expand Down
20 changes: 10 additions & 10 deletions worker_flutter/test/telemetry_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ void main() {
group('scrubPii', () {
test('redacts email-shaped values in event extras', () {
final event = SentryEvent(message: const SentryMessage('hi')).copyWith(
extra: <String, dynamic>{
contexts: Contexts()..['extra'] = <String, dynamic>{
'note': 'user contacted me at someone@example.com about it',
'okField': 'no pii here',
},
Expand All @@ -28,14 +28,14 @@ void main() {
final scrubbed = scrubPii(event);

expect(scrubbed, isNotNull);
expect(scrubbed!.extra!['note'], contains('[redacted-email]'));
expect(scrubbed.extra!['note'], isNot(contains('someone@example.com')));
expect(scrubbed.extra!['okField'], 'no pii here');
expect(((scrubbed!.contexts['extra'] as Map<String, dynamic>))['note'], contains('[redacted-email]'));
expect(((scrubbed.contexts['extra'] as Map<String, dynamic>))['note'], isNot(contains('someone@example.com')));
expect(((scrubbed.contexts['extra'] as Map<String, dynamic>))['okField'], 'no pii here');
});

test('redacts known PII keys', () {
final event = SentryEvent(message: const SentryMessage('hi')).copyWith(
extra: <String, dynamic>{
contexts: Contexts()..['extra'] = <String, dynamic>{
'email': 'a@b.com',
'uid': 'xyz',
'displayName': 'Tyler',
Expand All @@ -46,11 +46,11 @@ void main() {

final scrubbed = scrubPii(event);

expect(scrubbed!.extra!['email'], '[redacted]');
expect(scrubbed.extra!['uid'], '[redacted]');
expect(scrubbed.extra!['displayName'], '[redacted]');
expect(scrubbed.extra!['user_id'], '[redacted]');
expect(scrubbed.extra!['safe'], 'keep me');
expect(((scrubbed!.contexts['extra'] as Map<String, dynamic>))['email'], '[redacted]');
expect(((scrubbed.contexts['extra'] as Map<String, dynamic>))['uid'], '[redacted]');
expect(((scrubbed.contexts['extra'] as Map<String, dynamic>))['displayName'], '[redacted]');
expect(((scrubbed.contexts['extra'] as Map<String, dynamic>))['user_id'], '[redacted]');
expect(((scrubbed.contexts['extra'] as Map<String, dynamic>))['safe'], 'keep me');
});

test('replaces user with redacted placeholder', () {
Expand Down
1 change: 0 additions & 1 deletion worker_flutter/test/worker/log_uploader_test.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import 'dart:async';
import 'dart:convert';

import 'package:flutter_test/flutter_test.dart';
Expand Down
Loading