timsoft_os 0.1.2 copy "timsoft_os: ^0.1.2" to clipboard
timsoft_os: ^0.1.2 copied to clipboard

TIMSoft Platform OS — Backend-less Application Engine. Local-first database with Sync, Auth, Realtime, RBAC, and Admin tools inside a single SDK. No external server required.

example/main.dart

// example/main.dart
// ─────────────────────────────────────────────────────────────────────────────
// TIMSoft Platform OS — Complete Todo Application Example
// ─────────────────────────────────────────────────────────────────────────────
// Demonstrates: boot, auth, RBAC, create/read/update/delete, live query,
//               pagination, validation, change log, and sync.
//
// Run: dart run example/main.dart
// ─────────────────────────────────────────────────────────────────────────────

import 'package:timsoft_os/timsoft_os.dart';

// ── Entity ────────────────────────────────────────────────────────────────────

enum TodoPriority { low, medium, high }

@TimEntity(collection: 'todos', syncable: true)
class Todo {
  final String? id;
  final String title;
  final String? description;
  final bool done;
  final TodoPriority priority;
  final List<String> tags;

  const Todo({
    this.id,
    required this.title,
    this.description,
    this.done = false,
    this.priority = TodoPriority.medium,
    this.tags = const [],
  });

  Map<String, Object?> toMap() => {
        'title': title,
        'description': description,
        'done': done,
        'priority': priority.name,
        'tags': tags,
      };

  factory Todo.fromMap(Map<String, Object?> m) => Todo(
        id: m['__id'] as String?,
        title: m['title'] as String,
        description: m['description'] as String?,
        done: (m['done'] as bool?) ?? false,
        priority: TodoPriority.values.firstWhere(
          (p) => p.name == m['priority'],
          orElse: () => TodoPriority.medium,
        ),
        tags: ((m['tags'] as List?) ?? []).cast<String>(),
      );

  @override
  String toString() =>
      'Todo(${done ? "✅" : "⬜"} [$priority] $title'
      '${tags.isNotEmpty ? " #${tags.join(" #")}" : ""})';
}

// ── Main ──────────────────────────────────────────────────────────────────────

Future<void> main() async {
  print('═══════════════════════════════════════════');
  print('  TIMSoft Platform OS — Todo App Example   ');
  print('═══════════════════════════════════════════\n');

  // ── 1. Boot ─────────────────────────────────────────────────────────────────
  print('▶ Booting platform...');

  // Setup JWT provider with a user
  final jwtProvider = JwtAuthProvider(
    secret: 'my-super-secret-key-change-in-prod',
    tokenTtl: const Duration(hours: 2),
  );
  jwtProvider.registerUser(
    email: 'admin@timsoft.dz',
    password: 'admin123',
    roles: {'admin', 'user'},
    displayName: 'TIMSoft Admin',
  );

  // RBAC: admin can do everything, user can read+write todos
  final policy = RbacPolicy([
    Role('admin', [Permission.fullAccess('*')]),
    Role('user', [
      Permission('todos', canRead: true, canWrite: true, canDelete: true),
    ]),
  ]);

  final boot = await TimPlatform.boot(
    authProvider: jwtProvider,
    rbac: policy,
    conflictResolver: const FieldMergeResolver(),
    config: PlatformConfig.development,
  );

  boot
    ..onSuccess((_) => print('  ✅ Platform booted\n'))
    ..onFailure((e) {
      print('  ❌ Boot failed: $e');
      return;
    });

  final tim = TimPlatform.instance;

  // ── 2. Authenticate ──────────────────────────────────────────────────────────
  print('▶ Signing in...');
  final authResult = await tim.auth.signIn({
    'email': 'admin@timsoft.dz',
    'password': 'admin123',
  });
  authResult
    ..onSuccess((s) => print('  ✅ Signed in as ${s.email} (roles: ${s.roles})\n'))
    ..onFailure((e) => print('  ❌ Auth failed: $e'));

  // ── 3. Create repository ─────────────────────────────────────────────────────
  final todos = tim.collection<Todo>(
    'todos',
    toMap: (t) => t.toMap(),
    fromMap: Todo.fromMap,
    validator: ValidatorChain<Todo>(validators: [
      (t) => t.title.trim().isEmpty ? 'Title cannot be empty' : null,
      (t) => t.title.length > 200 ? 'Title too long (max 200 chars)' : null,
    ]),
  );

  // ── 4. Live Query ────────────────────────────────────────────────────────────
  print('▶ Starting live query...');
  final liveQ = tim.liveQuery<Todo>(
    'todos',
    fromMap: Todo.fromMap,
    query: const Query()
        .orderBy('__createdAt', descending: true)
        .take(5),
  );
  final liveSub = liveQ.watch().listen((result) {
    if (!result.isLoading) {
      print('  📡 Live: ${result.items.length} todo(s) in view');
    }
  });

  // ── 5. CREATE ────────────────────────────────────────────────────────────────
  print('\n▶ Creating todos...');
  await Future.delayed(const Duration(milliseconds: 50));

  final t1 = await todos.create(Todo(
    title: 'Build TIMSoft Platform OS',
    priority: TodoPriority.high,
    tags: ['dart', 'platform'],
  ));
  t1.onSuccess((t) => print('  ✅ Created: $t'));

  final t2 = await todos.create(Todo(
    title: 'Write comprehensive tests',
    priority: TodoPriority.high,
    tags: ['testing'],
  ));

  final t3 = await todos.create(Todo(
    title: 'Publish to pub.dev',
    description: 'Run dart pub publish',
    priority: TodoPriority.medium,
    tags: ['release', 'dart'],
  ));

  final t4 = await todos.create(Todo(
    title: 'Build Flutter UI package',
    priority: TodoPriority.low,
    tags: ['flutter', 'ui'],
  ));

  // Test validation
  print('\n▶ Testing validator...');
  final invalid = await todos.create(Todo(title: '', priority: TodoPriority.low));
  invalid.onFailure((e) => print('  ✅ Validation blocked: ${e.message}'));

  // ── 6. READ ──────────────────────────────────────────────────────────────────
  print('\n▶ Querying todos...');

  // All todos
  final all = await todos.findMany();
  all.onSuccess((list) => print('  📋 All: ${list.length} todos'));

  // Filter by priority
  final highPrio = await todos.findMany(
    const Query().whereEq('priority', 'high').orderBy('__createdAt'),
  );
  highPrio.onSuccess((list) {
    print('  🔴 High priority: ${list.length}');
    for (final t in list) print('     $t');
  });

  // Search by title
  final search = await todos.findMany(
    const Query().whereContains('title', 'dart'),
  );
  search.onSuccess((list) => print('  🔍 Contains "dart": ${list.length}'));

  // Count
  final cnt = await todos.count();
  cnt.onSuccess((n) => print('  📊 Total count: $n'));

  // ── 7. UPDATE ────────────────────────────────────────────────────────────────
  print('\n▶ Updating first todo...');
  final firstId = t1.value.id!;
  final updated = await todos.update(firstId, Todo(
    title: 'Build TIMSoft Platform OS',
    done: true,
    priority: TodoPriority.high,
    tags: ['dart', 'platform', 'completed'],
  ));
  updated.onSuccess((t) => print('  ✅ Updated: $t'));

  // PATCH — only change price
  print('\n▶ Patching second todo...');
  final patched = await todos.patch(t2.value.id!, {'done': true});
  patched.onSuccess((t) => print('  ✅ Patched: $t'));

  // ── 8. FILTER: done vs undone ─────────────────────────────────────────────────
  print('\n▶ Done vs undone...');
  final done = await todos.findMany(const Query().whereEq('done', true));
  final undone = await todos.findMany(const Query().whereEq('done', false));
  done.onSuccess((l) => print('  ✅ Done: ${l.length}'));
  undone.onSuccess((l) => print('  ⬜ Undone: ${l.length}'));

  // ── 9. DELETE ────────────────────────────────────────────────────────────────
  print('\n▶ Deleting last todo (soft delete)...');
  final del = await todos.delete(t4.value.id!);
  del.onSuccess((_) => print('  🗑️  Soft deleted'));

  final afterDel = await todos.count();
  afterDel.onSuccess((n) => print('  📊 Remaining: $n'));

  // ── 10. CHANGE LOG ────────────────────────────────────────────────────────────
  print('\n▶ Change log...');
  print('  📝 Total entries: ${tim.pendingChanges} pending');
  print('  📝 All entries: ${tim.changeLog.length}');
  for (final entry in tim.changeLog.take(3)) {
    print('     ${entry.op.name} → ${entry.recordId.substring(0, 12)}... '
        '[${entry.syncState.name}]');
  }

  // ── 11. SYNC ─────────────────────────────────────────────────────────────────
  print('\n▶ Running sync cycle (NoOp adapter)...');
  final syncResult = await tim.syncNow();
  syncResult.onSuccess((s) => print(
      '  🔄 Sync: pushed=${s.pushed}, pulled=${s.pulled}, '
      'conflicts=${s.conflicts}, deadLetters=${s.deadLetters}'));

  // ── 12. ADMIN SPEC ────────────────────────────────────────────────────────────
  print('\n▶ Generating admin spec...');
  const todoSchema = CollectionSchema(
    collection: 'todos',
    label: 'Tasks',
    fields: [
      FieldSchema(
        name: 'title',
        type: FieldType.string,
        constraints: FieldConstraints(required: true, minLength: 1),
        listColumn: true,
        searchable: true,
        label: 'Title',
      ),
      FieldSchema(
        name: 'done',
        type: FieldType.boolean,
        listColumn: true,
        label: 'Done',
      ),
      FieldSchema(
        name: 'priority',
        type: FieldType.enumValue,
        enumValues: ['low', 'medium', 'high'],
        listColumn: true,
        label: 'Priority',
      ),
      FieldSchema(
        name: 'tags',
        type: FieldType.list,
        label: 'Tags',
      ),
    ],
  );

  final generator = const DashboardGenerator(title: 'TIMSoft Todo Admin');
  final spec = generator.generate([todoSchema]);
  print('  🎛️  Collections: ${spec.collections.length}');
  print('  🎛️  Title: ${spec.title}');

  // ── 13. DIAGNOSTICS ───────────────────────────────────────────────────────────
  print('\n▶ Platform diagnostics:');
  final diag = tim.diagnostics();
  diag.forEach((k, v) => print('  $k: $v'));

  // ── Cleanup ───────────────────────────────────────────────────────────────────
  await liveSub.cancel();
  await tim.shutdown();

  print('\n═══════════════════════════════════════════');
  print('  ✅ Example complete!');
  print('═══════════════════════════════════════════');
}
2
likes
120
points
134
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

TIMSoft Platform OS — Backend-less Application Engine. Local-first database with Sync, Auth, Realtime, RBAC, and Admin tools inside a single SDK. No external server required.

Topics

#database #local-first #offline-first #sync #flutter

License

unknown (license)

Dependencies

http

More

Packages that depend on timsoft_os