# Metro Live

<!-- uncertain: newly created translation; needs full human review -->

<div id="introduction"></div>

## परिचय

<div class="ny-doc-strip">
<span class="ny-doc-strip-label">आवश्यक</span>
<span class="ny-doc-strip-item">Nylo 7.2.0+</span>
<span class="ny-doc-strip-dot"></span>
<span class="ny-doc-strip-item">nylo_support 7.30.0+</span>
</div>

**Nylo Live** Metro को Dart VM सर्विस के माध्यम से आपके ऐप में पहुंचने देता है, जब वह डिबग (या प्रोफाइल) मोड में चल रहा हो। यह बिना किसी सेटअप के Dart Tooling Daemon के माध्यम से ऐप को ढूंढता है, और केवल वर्तमान प्रोजेक्ट से बने ऐप्स से ही कनेक्ट होता है।

Nylo Live डिबग और प्रोफाइल बिल्ड में डिफ़ॉल्ट रूप से चालू रहता है; एक रिलीज़ बिल्ड कुछ भी रजिस्टर नहीं करता। जो कमांड केवल ऐप को पढ़ते हैं (`live:status`, `live:run data`, `live:run routes`, ...) वे प्रोफाइल बिल्ड में भी काम करते हैं। जो कमांड ऐप को बदलते हैं (`route`, `storage`, `auth`, सीडर्स, ...) उन्हें डिबग बिल्ड की आवश्यकता होती है।

इसे किसी भी अन्य चीज़ के चलने से पहले, एक प्रोवाइडर से खुद बंद करें:

``` dart
class AppProvider implements NyProvider {
  @override
  setup(Nylo nylo) async {
    nylo.useLive(false);
    return nylo;
  }

  @override
  boot(Nylo nylo) async {}
}
```

<div id="metro-live-shell"></div>

## metro live शेल

<div class="ny-doc-strip">
<span class="ny-doc-strip-label">आवश्यक</span>
<span class="ny-doc-strip-item">Nylo 7.2.0+</span>
<span class="ny-doc-strip-dot"></span>
<span class="ny-doc-strip-item">nylo_support 7.30.0+</span>
</div>

अपने चल रहे ऐप से जुड़ा एक शेल खोलें:

``` bash
metro live
```

Nylo Live प्रोजेक्ट के चल रहे ऐप्स को खोजता है और किसी एक से कनेक्ट होता है -- जब एक से अधिक चल रहे हों तो यह आपसे चुनने के लिए कहता है। कनेक्ट होने के बाद, प्रॉम्प्ट डिवाइस और स्क्रीन पर मौजूदा रूट दिखाता है:

``` plaintext
Nylo Live · my_app
Connected to iPhone 15 Pro (debug)
Type help to see commands, and exit to leave.
iPhone 15 Pro /home ›
```

लाइव कमांड शेल के अंदर अपना `metro live:` प्रीफिक्स छोड़ देते हैं -- `metro live:status` की बजाय `status`, `metro live:run route /profile` की बजाय `route /profile`। कुछ कमांड केवल शेल के अंदर ही चलते हैं: `seed`, `seed:rollback`, `export`, `reload` और `restart`। हर कमांड को सूचीबद्ध करने के लिए `help` टाइप करें, या किसी एक कमांड के विकल्प देखने के लिए `help <command>` टाइप करें। बाहर निकलने के लिए `exit` (या Ctrl+D) टाइप करें।

अगर कनेक्टेड रहते हुए ऐप रीस्टार्ट होता है, तो शेल अपने आप फिर से कनेक्ट हो जाता है।

<div id="shared-options"></div>

### साझा विकल्प

हर लाइव कमांड -- चाहे शेल के अंदर हो या `metro live:*` के रूप में -- एक जैसे विकल्प स्वीकार करता है:

| विकल्प | विवरण |
|--------|-------------|
| `-d, --device <#\|name>` | `metro live:devices` में उसकी संख्या या डिवाइस नाम से एक ऐप को टारगेट करें |
| `--all` | इस प्रोजेक्ट के हर चल रहे ऐप पर चलाएं |
| `--json` | मशीन-रीडेबल JSON प्रिंट करें |
| `--uri` | ऐप्स खोजने की बजाय इस VM सर्विस एड्रेस का उपयोग करें |
| `--timeout` | खोजते समय हर ऐप के लिए प्रतीक्षा करने के सेकंड (डिफ़ॉल्ट `3`) |

`@path` के रूप में लिखा गया एक विकल्प मान उस फ़ाइल से पढ़ा जाता है -- एक बड़े `--data` पेलोड के लिए उपयोगी:

``` bash
metro live:run route /profile --data @user.json
```

अगर मान वास्तव में `@` से शुरू होता है, तो उसे `@@` से शुरू करें।

<div id="tab-completion-and-history"></div>

### टैब पूर्णता और इतिहास

शेल के अंदर, Tab कनेक्टेड ऐप के विरुद्ध कमांड नाम, विकल्प, रूट, स्टोरेज और Backpack कीज़, और सीडर नामों को पूरा करता है। इतिहास `.dart_tool/nylo/live_history` में रखा जाता है और सत्रों के बीच बना रहता है।

<div id="running-a-script"></div>

### स्क्रिप्ट चलाना

एक फ़ाइल को `metro live` में पाइप करके उसे एक स्क्रिप्ट के रूप में चलाएं, प्रति लाइन एक कमांड, पहले असफल कमांड पर रुकते हुए:

``` bash
metro live < seeds/demo.live
```

खाली लाइनें और `#` से शुरू होने वाली लाइनें छोड़ दी जाती हैं।

<div id="live-devices"></div>

## live:devices

<div class="ny-doc-strip">
<span class="ny-doc-strip-label">आवश्यक</span>
<span class="ny-doc-strip-item">Nylo 7.2.0+</span>
<span class="ny-doc-strip-dot"></span>
<span class="ny-doc-strip-item">nylo_support 7.30.0+</span>
</div>

इस प्रोजेक्ट के चल रहे ऐप्स को सूचीबद्ध करता है, `-d` के लिए क्रमांकित:

``` bash
metro live:devices
```
``` plaintext
Running apps for my_app:
#  DEVICE          PLATFORM  MODE   ROUTE   APP
1  iPhone 15 Pro   ios       debug  /home   my_app
2  Pixel 8         android   debug  /login  my_app
```

<div id="live-status"></div>

## live:status

<div class="ny-doc-strip">
<span class="ny-doc-strip-label">आवश्यक</span>
<span class="ny-doc-strip-item">Nylo 7.2.0+</span>
<span class="ny-doc-strip-dot"></span>
<span class="ny-doc-strip-item">nylo_support 7.30.0+</span>
</div>

ऐप, डिवाइस, बिल्ड मोड, वर्तमान रूट और स्टैक, लोकेल, थीम, और क्या कोई यूज़र साइन इन है, यह दिखाता है:

``` bash
metro live:status
```
``` plaintext
App            my_app (development)
Device         iPhone 15 Pro · ios 17.4
Mode           debug
Route          /home
Stack          /home
Locale         en
Theme          default
Authenticated  yes
Live commands  cart:seed
Seeders        demo_user
```

<div id="live-run"></div>

## live:run

<div class="ny-doc-strip">
<span class="ny-doc-strip-label">आवश्यक</span>
<span class="ny-doc-strip-item">Nylo 7.2.0+</span>
<span class="ny-doc-strip-dot"></span>
<span class="ny-doc-strip-item">nylo_support 7.30.0+</span>
</div>

एक बिल्ट-इन कमांड चलाता है जो ऐप का निरीक्षण करता है या उसे संचालित करता है:

``` bash
metro live:run <command> [arguments]
```

| कमांड | विवरण |
|---------|-------------|
| `data` | स्क्रीन पर मौजूद पेज का डेटा और फ़ील्ड दिखाएं |
| `routes` | रजिस्टर्ड रूट्स की सूची दिखाएं |
| `route` | वैकल्पिक `--data` के साथ एक पेज खोलें |
| `back` | एक पेज पीछे जाएं, या किसी रूट पर वापस जाएं |
| `deeplink` | एक डीप लिंक खोलें, या दिखाएं कि वे कैसे सेट अप किए गए हैं |
| `storage` | लोकल स्टोरेज सूचीबद्ध करें, या एक वैल्यू दिखाएं, सेव करें या डिलीट करें |
| `storage:clear` | वैकल्पिक `--keep` के साथ लोकल स्टोरेज साफ़ करें |
| `backpack` | Backpack वैल्यूज़ सूचीबद्ध करें, या एक दिखाएं, सेव करें या डिलीट करें |
| `auth` | दिखाएं कौन साइन इन है, या साइन इन और आउट करें |
| `locale` | ऐप की भाषा बदलें |
| `theme` | ऐप की थीम बदलें |
| `state` | `updateState` के साथ एक स्टेट को डेटा भेजें |
| `event` | अपने किसी इवेंट को फायर करें |
| `toast` | एक टोस्ट नोटिफिकेशन दिखाएं |

`metro live` के अंदर, `live:run` वाला हिस्सा छोड़ दें -- `metro live:run route /profile` की बजाय `route /profile`:

``` bash
metro live:run route /profile --data '{"id": 42}'
metro live:run storage SK_COINS 10
metro live:run backpack auth_user
metro live:run auth login --data '{"id": 42}'
metro live:run deeplink myapp://product/42
metro live:run state HomePage --data '{"count": 2}'
metro live:run event LogoutEvent --data '{"reason": "test"}'
metro live:run toast "Item saved" --title Success
```

`data` आपके पेज के स्टेट द्वारा घोषित फ़ील्ड को भी सीधे चल रहे ऐप से पढ़ता है -- Flutter में कोई रिफ्लेक्शन नहीं है, इसलिए यह केवल उस स्टेट के लिए काम करता है जो वास्तव में स्क्रीन पर है:

``` bash
metro live:run data HomePage
```

<div id="live-commands"></div>

## लाइव कमांड

<div class="ny-doc-strip">
<span class="ny-doc-strip-label">आवश्यक</span>
<span class="ny-doc-strip-item">Nylo 7.2.0+</span>
<span class="ny-doc-strip-dot"></span>
<span class="ny-doc-strip-item">nylo_support 7.30.0+</span>
</div>

ऊपर दिए गए बिल्ट-इन कमांड्स के साथ-साथ, ऐप के अंदर चलाने के लिए अपने खुद के कमांड रजिस्टर करें।

<div id="creating-a-live-command"></div>

### एक लाइव कमांड बनाना

``` bash
metro make:command seed_cart --live
```

| विकल्प | विवरण |
|--------|-------------|
| `--category`, `-c` | कमांड के लिए श्रेणी (डिफ़ॉल्ट: `app`) |
| `--description` | कमांड के `--help` द्वारा दिखाया गया एक-पंक्ति विवरण |
| `--force`, `-f` | पहले से मौजूद होने पर भी फ़ाइल बनाता है |

यह `lib/app/commands/` में एक `LiveCommand` बनाता है, इसे `commands.json` में `"type": "live"` के रूप में चिह्नित करता है, इसे `lib/bootstrap/live_commands.dart` में रजिस्टर करता है, और `app_provider.dart` में `nylo.configure(...)` में `liveCommands: liveCommands` को जोड़ता है:

``` dart
class SeedCartCommand extends LiveCommand {
  @override
  CommandBuilder builder(CommandBuilder command) {
    command.addOption('count', abbr: 'c', defaultValue: '3');
    command.addFlag('open', help: 'Open the cart afterwards');
    return command;
  }

  @override
  Future<void> handle(CommandResult result) async {
    final int count = result.getInt('count') ?? 3;
    await CartItem.seed(count: count);
    success('Seeded $count cart items');
  }
}
```

`LiveCommand`, Metro के अपने कमांड्स के साथ `builder`/`handle` संरचना साझा करता है, लेकिन `handle` **ऐप के अंदर** चलता है, इसलिए यह `NyStorage`, `routeTo`, `Auth` और आपके मॉडल्स का उपयोग कर सकता है। `package:nylo_framework/live.dart`, `Seeder`, `StorageSnapshot`, `LiveException` और `LiveOutput` के साथ-साथ `LiveCommand` को एक्सपोर्ट करता है।

<div id="running-a-live-command"></div>

### एक लाइव कमांड चलाना

एक नए लाइव कमांड को चल रहे ऐप द्वारा चलाए जाने से पहले एक हॉट रीस्टार्ट की आवश्यकता होती है। फिर, टर्मिनल से:

``` bash
metro app:seed_cart --count 5
```

<div id="seeders"></div>

## सीडर्स

<div class="ny-doc-strip">
<span class="ny-doc-strip-label">आवश्यक</span>
<span class="ny-doc-strip-item">Nylo 7.2.0+</span>
<span class="ny-doc-strip-dot"></span>
<span class="ny-doc-strip-item">nylo_support 7.30.0+</span>
</div>

एक `Seeder` आपके चल रहे ऐप को एक ज्ञात स्थिति में डालता है -- साइन इन, ऑनबोर्डिंग पूरी, नमूना रिकॉर्ड्स -- और फिर उसे वापस बाहर निकालता है।

<div id="creating-a-seeder"></div>

### एक सीडर बनाना

``` bash
metro make:seeder demo_user
```

| विकल्प | विवरण |
|--------|-------------|
| `--description` | एक-पंक्ति विवरण, जो `seed` द्वारा सीडर्स सूचीबद्ध करते समय दिखाया जाता है |
| `--force`, `-f` | पहले से मौजूद होने पर भी फ़ाइल बनाता है |

यह `lib/app/seeders/` में एक `Seeder` बनाता है, इसे `lib/bootstrap/seeders.dart` में रजिस्टर करता है, और `nylo.configure(...)` में `seeders: seeders` को जोड़ता है:

``` dart
class DemoUserSeeder extends Seeder {
  @override
  String get description => 'Jane Doe, signed in, onboarding done';

  @override
  Future<void> up() async {
    await Auth.authenticate(data: {'name': 'Jane Doe', 'token': 'demo'});
    await saveToStorage({'onboarding_complete': true});
    success('Signed in as Jane Doe');
  }

  @override
  Future<void> down() async {
    await restore();
  }
}
```

हर स्टोरेज और Backpack वैल्यू जिसे `up()` बदलता है, स्वचालित रूप से रिकॉर्ड की जाती है, इसलिए डिफ़ॉल्ट `down()` (`restore()`) हर एक को बिल्कुल वैसे ही वापस रख देता है जैसे वह पहले था, उल्टे क्रम में -- यहां तक कि एक हॉट रीस्टार्ट के पार भी। किसी सीडर के अंदर से दूसरों को उसके हिस्से के रूप में चलाने के लिए `seed(otherSeeders)` को कॉल करें; उनके बदलाव भी रिकॉर्ड और रोलबैक किए जाते हैं।

<div id="seeding-and-rolling-back"></div>

### सीडिंग और रोलिंग बैक

सीडिंग, रोलिंग बैक और एक्सपोर्टिंग केवल `metro live` शेल के अंदर चलते हैं:

``` plaintext
› seed demo_user
Seeding demo_user
  + storage    SK_ONBOARDING  added
  ✓ Signed in as Jane Doe
✓ Seeded demo_user in 42ms
Undo with seed:rollback demo_user

› seed:rollback demo_user
Rolling back demo_user
  - storage    SK_ONBOARDING  removed
✓ Rolled back demo_user in 8ms
```

अकेला `seed` रजिस्टर्ड सीडर्स को सूचीबद्ध करता है। `--fresh` सीडिंग से पहले स्टोरेज और Backpack को साफ़ करता है, और `--restart` उसके बाद ऐप को हॉट रीस्टार्ट करता है, ताकि वह पहले से सीडेड होकर शुरू हो:

``` plaintext
› seed demo_user --fresh --restart
```

<div id="storage-snapshots"></div>

## स्टोरेज स्नैपशॉट

<div class="ny-doc-strip">
<span class="ny-doc-strip-label">आवश्यक</span>
<span class="ny-doc-strip-item">Nylo 7.2.0+</span>
<span class="ny-doc-strip-dot"></span>
<span class="ny-doc-strip-item">nylo_support 7.30.0+</span>
</div>

`export`, ऐप वर्तमान में स्टोरेज और Backpack में जो कुछ भी रखता है, उसे सेव करता है -- एक सीडर के रूप में, या एक पोर्टेबल JSON फ़ाइल के रूप में -- और `seed <file>` इसे वापस लोड करता है।

<div id="exporting-a-snapshot"></div>

### स्नैपशॉट एक्सपोर्ट करना

यह देखने के लिए कि क्या कैप्चर किया जाएगा, इसे बिना नाम के चलाएं:

``` plaintext
› export
Storage on iPhone 15 Pro (2 values, 96 B)
KEY          TYPE    VALUE
SK_THEME     string  dark
SK_USER      model   {id: 1, name: Jane Doe}

Backpack (0 values)
Backpack is empty

Save it as a seeder with export <name>, or as a file with export --to <path>.json
```

इसे `export <name>` के साथ `lib/app/seeders/` में एक सीडर के रूप में सेव करने के लिए नाम दें (`make:seeder` जैसा ही, लेकिन पहले से कैप्चर की गई वैल्यूज़ के साथ भरा हुआ):

``` plaintext
› export pro_user
```

या इसके बजाय इसे एक फ़ाइल में लिखें:

``` plaintext
› export pro_user --to snapshots/pro_user.json
```

| विकल्प | विवरण |
|--------|-------------|
| `--to <path>` | सीडर की बजाय स्नैपशॉट को इस JSON फ़ाइल में लिखें |
| `--description` | सीडर के लिए एक-पंक्ति विवरण |
| `--only <keys>` | एक्सपोर्ट करने के लिए कॉमा-सेपरेटेड कीज़; `*` किसी भी चीज़ से मेल खाता है, जैसे `--only SK_USER,onboarding_*` |
| `--except <keys>` | छोड़ने के लिए कॉमा-सेपरेटेड कीज़, जैसे `--except 'cache_*'` |
| `--backpack` / `--no-backpack` | Backpack वैल्यूज़ शामिल करें (डिफ़ॉल्ट: शामिल) |
| `--force`, `-f` | पहले से मौजूद सीडर या फ़ाइल को बदलें |

एक `Model`, या रजिस्टर्ड डिकोडर वाली कोई भी क्लास, क्लास नाम से टैग की जाती है ताकि वह एक साधारण मैप की बजाय अपने खुद के डिकोडर के माध्यम से वापस आए। `export` तब चेतावनी देता है जब स्नैपशॉट में ऐसी कीज़ होती हैं जो क्रेडेंशियल्स जैसी दिखती हैं, और जब यह इतना बड़ा हो कि आपको संभवतः `--except` की आवश्यकता हो।

<div id="loading-a-snapshot"></div>

### स्नैपशॉट लोड करना

``` plaintext
› seed snapshots/pro_user.json
```

एक फ़ाइल लोड करना उसी तरह रिकॉर्ड की जाती है जैसे एक सीडर होती है, इसलिए `seed:rollback <name>` (फ़ाइल का नाम, या जो भी `--as` ने दिया हो) इसे भी पूर्ववत करता है। कोड से, एक सीडर `importSnapshot` के साथ एक कैप्चर किए गए स्नैपशॉट को लागू कर सकता है:

``` dart
class ProUserSeeder extends Seeder {
  @override
  Future<void> up() async {
    await importSnapshot(snapshot);
  }

  static const Map<String, Object?> snapshot = {
    'storage': {
      'SK_USER': {'type': 'model', 'model': 'User', 'value': {'id': 1}},
    },
    'backpack': {},
  };
}
```

`export` बिल्कुल इसी संरचना में लिखता है, इसलिए `--to` के साथ लिखी गई फ़ाइल को सीधे किसी सीडर के `snapshot` फ़ील्ड में पेस्ट किया जा सकता है।

<div id="page-actions"></div>

## पेज एक्शन्स

<div class="ny-doc-strip">
<span class="ny-doc-strip-label">आवश्यक</span>
<span class="ny-doc-strip-item">Nylo 7.2.0+</span>
<span class="ny-doc-strip-dot"></span>
<span class="ny-doc-strip-item">nylo_support 7.30.0+</span>
</div>

किसी पेज पर `path.actions`, इसके बाहर से उस पेज को कॉल करने के लिए एक `PageStateActions` देता है, बिना खुद हाथ से एक `stateAction(...)` कॉल बनाए:

``` dart
class ProductPage extends NyStatefulWidget {
  static RouteView path = ("/product", (_) => ProductPage());
  static final actions = path.actions;

  ProductPage({super.key}) : super(child: () => _ProductPageState());
}

ProductPage.actions.showToast("Added to bag");
ProductPage.actions.refreshPage();
```

बिल्ट-इन एक्शन्स के पूरे सेट और अपने खुद के टाइप्ड एक्शन्स कैसे घोषित करें, इसके लिए [एक पेज के एक्शन्स को कॉल करना](/docs/7.x/state-management#page-actions-shortcut) देखें। Nylo Live उन्हीं एक्शन्स को पढ़ता और उपयोग करता है: `metro live:run data`, स्क्रीन पर मौजूद किसी पेज द्वारा `actions` के अंतर्गत एक्सपोज़ किए गए को सूचीबद्ध करता है, और `metro live:run state`, पेज को सीधे उसके स्टेट नाम से डेटा भेजता है।
