nia-sync 0.1.0__py3-none-any.whl → 0.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- auth.py +48 -48
- config.py +1 -1
- extractor.py +1 -1
- main.py +8 -3
- {nia_sync-0.1.0.dist-info → nia_sync-0.1.1.dist-info}/METADATA +1 -1
- nia_sync-0.1.1.dist-info/RECORD +11 -0
- sync.py +1 -6
- watcher.py +2 -2
- nia_sync-0.1.0.dist-info/RECORD +0 -11
- {nia_sync-0.1.0.dist-info → nia_sync-0.1.1.dist-info}/WHEEL +0 -0
- {nia_sync-0.1.0.dist-info → nia_sync-0.1.1.dist-info}/entry_points.txt +0 -0
- {nia_sync-0.1.0.dist-info → nia_sync-0.1.1.dist-info}/top_level.txt +0 -0
auth.py
CHANGED
|
@@ -104,64 +104,64 @@ def login() -> bool:
|
|
|
104
104
|
def _poll_for_api_key(session_id: str, user_code: str) -> str | None:
|
|
105
105
|
"""Poll the exchange endpoint until authentication completes."""
|
|
106
106
|
with httpx.Client(timeout=30) as client:
|
|
107
|
-
for
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
107
|
+
with console.status("[dim]Waiting for browser authentication...[/dim]") as status:
|
|
108
|
+
for attempt in range(MAX_POLL_ATTEMPTS):
|
|
109
|
+
try:
|
|
110
|
+
response = client.post(
|
|
111
|
+
f"{API_BASE_URL}/public/mcp-device/exchange",
|
|
112
|
+
json={
|
|
113
|
+
"authorization_session_id": session_id,
|
|
114
|
+
"user_code": user_code,
|
|
115
|
+
}
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
if response.status_code == 200:
|
|
119
|
+
data = response.json()
|
|
120
|
+
status.stop()
|
|
121
|
+
console.print("[green]Authentication successful![/green]")
|
|
122
|
+
return data.get("api_key")
|
|
123
|
+
|
|
124
|
+
elif response.status_code == 400:
|
|
125
|
+
# Not ready yet - still pending or authorized but not ready
|
|
126
|
+
detail = response.json().get("detail", "")
|
|
127
|
+
if "not yet authorized" in detail.lower() or "complete the setup" in detail.lower():
|
|
128
|
+
# Still waiting for user to complete in browser
|
|
129
|
+
time.sleep(POLL_INTERVAL_SECONDS)
|
|
130
|
+
continue
|
|
131
|
+
else:
|
|
132
|
+
status.stop()
|
|
133
|
+
console.print(f"[red]Error: {detail}[/red]")
|
|
134
|
+
return None
|
|
135
|
+
|
|
136
|
+
elif response.status_code == 410:
|
|
137
|
+
status.stop()
|
|
138
|
+
console.print("[red]Session expired. Please try again.[/red]")
|
|
132
139
|
return None
|
|
133
140
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
elif response.status_code == 409:
|
|
139
|
-
console.print("[red]Session already used. Please try again.[/red]")
|
|
140
|
-
return None
|
|
141
|
+
elif response.status_code == 409:
|
|
142
|
+
status.stop()
|
|
143
|
+
console.print("[red]Session already used. Please try again.[/red]")
|
|
144
|
+
return None
|
|
141
145
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
146
|
+
elif response.status_code == 404:
|
|
147
|
+
status.stop()
|
|
148
|
+
console.print("[red]Invalid session. Please try again.[/red]")
|
|
149
|
+
return None
|
|
145
150
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
151
|
+
else:
|
|
152
|
+
status.stop()
|
|
153
|
+
console.print(f"[red]Unexpected error: {response.status_code}[/red]")
|
|
154
|
+
return None
|
|
149
155
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
156
|
+
except httpx.RequestError as e:
|
|
157
|
+
console.print(f"[yellow]Network error, retrying... ({e})[/yellow]")
|
|
158
|
+
time.sleep(POLL_INTERVAL_SECONDS)
|
|
159
|
+
continue
|
|
154
160
|
|
|
155
161
|
console.print("[red]Timeout waiting for authentication. Please try again.[/red]")
|
|
156
162
|
return None
|
|
157
163
|
|
|
158
164
|
|
|
159
|
-
def _show_waiting_indicator(attempt: int):
|
|
160
|
-
"""Show a waiting indicator."""
|
|
161
|
-
dots = "." * ((attempt % 3) + 1)
|
|
162
|
-
console.print(f"\r[dim]Waiting for browser authentication{dots} [/dim]", end="")
|
|
163
|
-
|
|
164
|
-
|
|
165
165
|
def logout():
|
|
166
166
|
"""Clear stored credentials."""
|
|
167
167
|
clear_config()
|
config.py
CHANGED
|
@@ -16,7 +16,7 @@ NIA_SYNC_DIR = Path.home() / ".nia-sync"
|
|
|
16
16
|
CONFIG_FILE = NIA_SYNC_DIR / "config.json"
|
|
17
17
|
|
|
18
18
|
# API configuration
|
|
19
|
-
API_BASE_URL = os.getenv("NIA_API_URL", "https://
|
|
19
|
+
API_BASE_URL = os.getenv("NIA_API_URL", "https://apigcp.trynia.ai")
|
|
20
20
|
|
|
21
21
|
# Default directories to search for folders (no config needed)
|
|
22
22
|
DEFAULT_WATCH_DIRS = [
|
extractor.py
CHANGED
main.py
CHANGED
|
@@ -261,8 +261,10 @@ def add(path: str = typer.Argument(..., help="Path to sync (folder or database)"
|
|
|
261
261
|
result = add_source(path, detected_type)
|
|
262
262
|
|
|
263
263
|
if result:
|
|
264
|
+
folder_id = result.get('local_folder_id', '')
|
|
265
|
+
short_id = folder_id[:8] if folder_id else 'unknown'
|
|
264
266
|
console.print(f"[green]✓ Added:[/green] {result.get('display_name', path)}")
|
|
265
|
-
console.print(f"[dim]ID: {
|
|
267
|
+
console.print(f"[dim]ID: {short_id}[/dim]")
|
|
266
268
|
console.print("\n[dim]Run [cyan]nia[/cyan] to start syncing.[/dim]")
|
|
267
269
|
else:
|
|
268
270
|
console.print("[red]Failed to add source.[/red]")
|
|
@@ -478,8 +480,11 @@ def daemon(
|
|
|
478
480
|
# Remove old watchers (source deleted from UI)
|
|
479
481
|
for source_id in current_watching - new_source_ids:
|
|
480
482
|
old_name = sources_by_id.get(source_id, {}).get("display_name", source_id[:8])
|
|
481
|
-
|
|
482
|
-
|
|
483
|
+
try:
|
|
484
|
+
watcher.unwatch(source_id)
|
|
485
|
+
console.print(f" [dim]- Stopped watching {old_name}[/dim]")
|
|
486
|
+
except Exception as e:
|
|
487
|
+
logger.warning(f"Failed to unwatch {old_name}: {e}")
|
|
483
488
|
|
|
484
489
|
sources_by_id = new_sources_by_id
|
|
485
490
|
return resolved, newly_added
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
auth.py,sha256=n0ezRqIbz3kZYcyIjH47_MDKgwNgAaVr0Y2NEfRxa50,5704
|
|
2
|
+
config.py,sha256=JWxdL8INKo23lam4F49ZbllxbW3yorqczm7aaqepQCc,7507
|
|
3
|
+
extractor.py,sha256=ViqOZQBtwrKUK_W0bOFTNU8Ar726mcZ6TJ6dS_PfVyk,28599
|
|
4
|
+
main.py,sha256=k_4KXmQb8sRI-Wf8r2MMKUZbIa1SLuGUVtpU30ej63E,22975
|
|
5
|
+
sync.py,sha256=W31mWjvo2qEszUaH_C9m7bQu0FMUsBFUaiw8QdcYDxs,5427
|
|
6
|
+
watcher.py,sha256=9RvHVpn1ozTBgxPeOe20kkW6x5gb8A1b7e33D_7JBc4,9598
|
|
7
|
+
nia_sync-0.1.1.dist-info/METADATA,sha256=3hhEQsrIu8LLcOm3uvUo_lyGSzQH5GmlSly8BXXRQ_o,240
|
|
8
|
+
nia_sync-0.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
9
|
+
nia_sync-0.1.1.dist-info/entry_points.txt,sha256=Fx8TIOgXqWdZzZEkEateDtcNfgnwuPW4jZTqlEUrHVs,33
|
|
10
|
+
nia_sync-0.1.1.dist-info/top_level.txt,sha256=_ZWBugSHWwSpLXYJAcF6TlWmzECu18k0y1-EX27jtBw,40
|
|
11
|
+
nia_sync-0.1.1.dist-info/RECORD,,
|
sync.py
CHANGED
|
@@ -12,7 +12,7 @@ from pathlib import Path
|
|
|
12
12
|
from typing import Any
|
|
13
13
|
import httpx
|
|
14
14
|
|
|
15
|
-
from config import API_BASE_URL, get_api_key
|
|
15
|
+
from config import API_BASE_URL, get_api_key
|
|
16
16
|
from extractor import extract_incremental, detect_source_type
|
|
17
17
|
|
|
18
18
|
logger = logging.getLogger(__name__)
|
|
@@ -69,11 +69,6 @@ def sync_source(source: dict[str, Any]) -> dict[str, Any]:
|
|
|
69
69
|
"error": f"Path does not exist: {path}",
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
# Auto-enable sync if source exists locally but sync not enabled
|
|
73
|
-
if not source.get("sync_enabled", False):
|
|
74
|
-
logger.info(f"Auto-enabling sync for {path}")
|
|
75
|
-
enable_source_sync(local_folder_id, path)
|
|
76
|
-
|
|
77
72
|
# Auto-detect type if not specified
|
|
78
73
|
if not detected_type:
|
|
79
74
|
detected_type = detect_source_type(path)
|
watcher.py
CHANGED
|
@@ -7,7 +7,7 @@ with debouncing to prevent rapid-fire updates.
|
|
|
7
7
|
import os
|
|
8
8
|
import threading
|
|
9
9
|
import logging
|
|
10
|
-
from typing import Callable
|
|
10
|
+
from typing import Any, Callable
|
|
11
11
|
from pathlib import Path
|
|
12
12
|
|
|
13
13
|
from watchdog.observers import Observer
|
|
@@ -148,7 +148,7 @@ class FileWatcher:
|
|
|
148
148
|
self.debounce_sec = debounce_sec
|
|
149
149
|
self.observer = Observer()
|
|
150
150
|
self.handlers: dict[str, SyncEventHandler] = {}
|
|
151
|
-
self._watches: dict[str,
|
|
151
|
+
self._watches: dict[str, Any] = {}
|
|
152
152
|
self._lock = threading.Lock()
|
|
153
153
|
self._started = False
|
|
154
154
|
|
nia_sync-0.1.0.dist-info/RECORD
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
auth.py,sha256=_Q-wzLLtinoy8qtTihZNqdRAECPEzVjC5NgCXOLftJ8,5487
|
|
2
|
-
config.py,sha256=tJD3k3mBP9KORg4tX692uKk3Z92tEeYRI8jmgPjY5P0,7504
|
|
3
|
-
extractor.py,sha256=GxKmBTq04AxCjhtimlHZ2Gh3auvEEUyMHT-vM4YqWzI,28570
|
|
4
|
-
main.py,sha256=-ZWWs-5pQx_gR2QLwMrhbmuTKZo_8PQnVoExi85lqUU,22744
|
|
5
|
-
sync.py,sha256=iH9N22NEr2Nt5O6GeDP_X--G6IXhr8Hx3Z2xfJWkXc0,5667
|
|
6
|
-
watcher.py,sha256=BfdGwcfNDJiddUBMIPx61En2tSkLb3YnfxePKjSFQTc,9593
|
|
7
|
-
nia_sync-0.1.0.dist-info/METADATA,sha256=Qm4BGkM9fO0tiZg1AgKmA8-S_8f9674DtZZXBY_u0hc,240
|
|
8
|
-
nia_sync-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
9
|
-
nia_sync-0.1.0.dist-info/entry_points.txt,sha256=Fx8TIOgXqWdZzZEkEateDtcNfgnwuPW4jZTqlEUrHVs,33
|
|
10
|
-
nia_sync-0.1.0.dist-info/top_level.txt,sha256=_ZWBugSHWwSpLXYJAcF6TlWmzECu18k0y1-EX27jtBw,40
|
|
11
|
-
nia_sync-0.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|