nlbone 0.6.20__py3-none-any.whl → 0.7.0__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.
Files changed (41) hide show
  1. nlbone/adapters/db/postgres/__init__.py +1 -1
  2. nlbone/adapters/db/postgres/base.py +2 -1
  3. nlbone/adapters/db/postgres/repository.py +254 -29
  4. nlbone/adapters/db/postgres/uow.py +36 -1
  5. nlbone/adapters/messaging/__init__.py +1 -1
  6. nlbone/adapters/messaging/event_bus.py +97 -17
  7. nlbone/adapters/messaging/rabbitmq.py +45 -0
  8. nlbone/adapters/outbox/__init__.py +1 -0
  9. nlbone/adapters/outbox/outbox_consumer.py +112 -0
  10. nlbone/adapters/outbox/outbox_repo.py +191 -0
  11. nlbone/adapters/ticketing/client.py +39 -0
  12. nlbone/config/settings.py +9 -5
  13. nlbone/container.py +1 -8
  14. nlbone/core/application/bus.py +7 -7
  15. nlbone/core/application/di.py +43 -14
  16. nlbone/core/application/registry.py +12 -6
  17. nlbone/core/domain/base.py +30 -9
  18. nlbone/core/domain/models.py +46 -3
  19. nlbone/core/ports/__init__.py +0 -2
  20. nlbone/core/ports/event_bus.py +23 -6
  21. nlbone/core/ports/outbox.py +73 -0
  22. nlbone/core/ports/repository.py +10 -9
  23. nlbone/core/ports/uow.py +20 -1
  24. nlbone/interfaces/api/additional_filed/field_registry.py +2 -0
  25. nlbone/interfaces/cli/init_db.py +39 -2
  26. nlbone/interfaces/cli/main.py +2 -0
  27. nlbone/interfaces/cli/ticket.py +29 -0
  28. nlbone/interfaces/jobs/dispatch_outbox.py +2 -2
  29. nlbone/utils/crypto.py +7 -4
  30. {nlbone-0.6.20.dist-info → nlbone-0.7.0.dist-info}/METADATA +3 -2
  31. {nlbone-0.6.20.dist-info → nlbone-0.7.0.dist-info}/RECORD +35 -34
  32. nlbone/adapters/repositories/outbox_repo.py +0 -18
  33. nlbone/core/application/events.py +0 -20
  34. nlbone/core/application/services.py +0 -0
  35. nlbone/core/domain/events.py +0 -0
  36. nlbone/core/ports/messaging.py +0 -0
  37. nlbone/core/ports/repo.py +0 -19
  38. /nlbone/adapters/{messaging/redis.py → ticketing/__init__.py} +0 -0
  39. {nlbone-0.6.20.dist-info → nlbone-0.7.0.dist-info}/WHEEL +0 -0
  40. {nlbone-0.6.20.dist-info → nlbone-0.7.0.dist-info}/entry_points.txt +0 -0
  41. {nlbone-0.6.20.dist-info → nlbone-0.7.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,73 @@
1
+ from __future__ import annotations
2
+
3
+ from datetime import datetime, timedelta
4
+ from typing import Any, Dict, Iterable, List, Optional, Protocol, Tuple
5
+
6
+ from nlbone.core.domain.models import Outbox, OutboxStatus
7
+
8
+
9
+ class OutboxRepository(Protocol):
10
+ def enqueue(
11
+ self,
12
+ topic: str,
13
+ payload: Dict[str, Any],
14
+ *,
15
+ headers: Optional[Dict[str, Any]] = None,
16
+ key: Optional[str] = None,
17
+ available_at: Optional[datetime] = None,
18
+ ) -> Outbox: ...
19
+
20
+ def enqueue_many(
21
+ self,
22
+ items: Iterable[Tuple[str, Dict[str, Any]]],
23
+ *,
24
+ headers: Optional[Dict[str, Any]] = None,
25
+ available_at: Optional[datetime] = None,
26
+ ) -> List[Outbox]: ...
27
+
28
+ def claim_batch(
29
+ self,
30
+ *,
31
+ topics: list[str] = None,
32
+ limit: int = 100,
33
+ now: Optional[datetime] = None,
34
+ ) -> List[Outbox]: ...
35
+
36
+ def mark_published(self, ids: Iterable[int]) -> None: ...
37
+
38
+ def mark_failed(self, id: int, error: str, *, backoff: timedelta = timedelta(seconds=30)) -> None: ...
39
+
40
+ def delete_older_than(self, *, before: datetime, status: Optional[OutboxStatus] = None) -> int: ...
41
+
42
+
43
+ class AsyncOutboxRepository(Protocol):
44
+ async def enqueue(
45
+ self,
46
+ topic: str,
47
+ payload: Dict[str, Any],
48
+ *,
49
+ headers: Optional[Dict[str, Any]] = None,
50
+ key: Optional[str] = None,
51
+ available_at: Optional[datetime] = None,
52
+ ) -> Outbox: ...
53
+
54
+ async def enqueue_many(
55
+ self,
56
+ items: Iterable[Tuple[str, Dict[str, Any]]],
57
+ *,
58
+ headers: Optional[Dict[str, Any]] = None,
59
+ available_at: Optional[datetime] = None,
60
+ ) -> List[Outbox]: ...
61
+
62
+ async def claim_batch(
63
+ self,
64
+ *,
65
+ limit: int = 100,
66
+ now: Optional[datetime] = None,
67
+ ) -> List[Outbox]: ...
68
+
69
+ async def mark_published(self, ids: Iterable[int]) -> None: ...
70
+
71
+ async def mark_failed(self, id: int, error: str, *, backoff: timedelta = timedelta(seconds=30)) -> None: ...
72
+
73
+ async def delete_older_than(self, *, before: datetime, status: Optional[OutboxStatus] = None) -> int: ...
@@ -1,24 +1,26 @@
1
1
  from abc import ABC, abstractmethod
2
2
  from typing import (
3
- TypeVar,
3
+ Any,
4
+ Callable,
5
+ ClassVar,
4
6
  Generic,
5
- Optional,
6
7
  Iterable,
7
- Callable,
8
8
  List,
9
- ClassVar,
9
+ Optional,
10
10
  Type,
11
- Any,
11
+ TypeVar,
12
12
  )
13
13
 
14
+ from nlbone.core.domain.base import AggregateRoot
14
15
  from nlbone.interfaces.api.exceptions import NotFoundException
15
16
 
16
17
  ID = TypeVar("ID")
17
- T = TypeVar("T", bound="HasId")
18
+ T = TypeVar("T")
18
19
 
19
20
 
20
21
  class Repository(Generic[T, ID], ABC):
21
22
  model: ClassVar[Type[Any]]
23
+ seen: set[AggregateRoot] = set()
22
24
 
23
25
  @abstractmethod
24
26
  def get(self, id: ID) -> Optional[T]: ...
@@ -68,9 +70,8 @@ class Repository(Generic[T, ID], ABC):
68
70
  # Async Repository (Abstract)
69
71
  # -----------------------------
70
72
  class AsyncRepository(Generic[T, ID], ABC):
71
- @property
72
- @abstractmethod
73
- def model(self) -> type[T]: ...
73
+ model: ClassVar[Type[Any]]
74
+ seen: set[AggregateRoot] = set()
74
75
 
75
76
  @abstractmethod
76
77
  async def get(self, id: ID) -> Optional[T]: ...
nlbone/core/ports/uow.py CHANGED
@@ -1,19 +1,38 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Protocol, runtime_checkable
3
+ from typing import AsyncIterator, Iterator, Protocol, runtime_checkable
4
+
5
+ from nlbone.core.domain.base import DomainEvent
6
+ from nlbone.core.ports.outbox import AsyncOutboxRepository, OutboxRepository
4
7
 
5
8
 
6
9
  @runtime_checkable
7
10
  class UnitOfWork(Protocol):
11
+ outbox: list
12
+ outbox_repo: OutboxRepository
13
+
8
14
  def __enter__(self) -> "UnitOfWork": ...
15
+
9
16
  def __exit__(self, exc_type, exc, tb) -> None: ...
17
+
10
18
  def commit(self) -> None: ...
19
+
11
20
  def rollback(self) -> None: ...
12
21
 
22
+ def collect_new_events(self) -> Iterator[DomainEvent]: ...
23
+
13
24
 
14
25
  @runtime_checkable
15
26
  class AsyncUnitOfWork(Protocol):
27
+ outbox: list
28
+ outbox_repo: AsyncOutboxRepository
29
+
16
30
  async def __aenter__(self) -> "AsyncUnitOfWork": ...
31
+
17
32
  async def __aexit__(self, exc_type, exc, tb) -> None: ...
33
+
18
34
  async def commit(self) -> None: ...
35
+
19
36
  async def rollback(self) -> None: ...
37
+
38
+ async def collect_new_events(self) -> AsyncIterator[DomainEvent]: ...
@@ -11,6 +11,8 @@ Loader = Callable
11
11
  def _schema_fields(schema: Type[BaseModel], by_alias: bool = True) -> Set[str]:
12
12
  names = set()
13
13
  for name, f in schema.model_fields.items():
14
+ if f.json_schema_extra and f.json_schema_extra.get("exclude_none"):
15
+ continue
14
16
  names.add(f.alias or name if by_alias else name)
15
17
  return names
16
18
 
@@ -1,3 +1,7 @@
1
+ import importlib
2
+ import sys
3
+ from pathlib import Path
4
+
1
5
  import typer
2
6
 
3
7
  from nlbone.adapters.db import Base, init_sync_engine, sync_ping
@@ -5,9 +9,42 @@ from nlbone.adapters.db import Base, init_sync_engine, sync_ping
5
9
  init_db_command = typer.Typer(help="Database utilities")
6
10
 
7
11
 
12
+ def _import_target(target: str):
13
+ """Import a module or call a bootstrap function if using 'module:function' syntax."""
14
+ if ":" in target:
15
+ mod_name, attr = target.split(":", 1)
16
+ mod = importlib.import_module(mod_name)
17
+ getattr(mod, attr)()
18
+ else:
19
+ importlib.import_module(target)
20
+
21
+
8
22
  @init_db_command.command("init")
9
- def init_db(drop: bool = typer.Option(False, "--drop", help="Drop all tables before create")):
10
- """Create (and optionally drop) DB schema."""
23
+ def init_db(
24
+ drop: bool = typer.Option(False, "--drop", help="Drop all tables before creating them"),
25
+ models: list[str] = typer.Option(
26
+ None,
27
+ "--models",
28
+ "-m",
29
+ help=(
30
+ "List of modules or bootstrap functions to import before create_all. "
31
+ "For example: app.models or app.bootstrap:register_models"
32
+ ),
33
+ ),
34
+ add_cwd: bool = typer.Option(
35
+ True,
36
+ "--add-cwd/--no-add-cwd",
37
+ help=("Add the current working directory to sys.path so imports work relative to the host project root."),
38
+ ),
39
+ ):
40
+ """Create (and optionally drop) the database schema."""
41
+
42
+ if add_cwd:
43
+ sys.path.insert(0, str(Path.cwd()))
44
+
45
+ for target in models or []:
46
+ _import_target(target)
47
+
11
48
  engine = init_sync_engine()
12
49
  if drop:
13
50
  Base.metadata.drop_all(bind=engine)
@@ -6,11 +6,13 @@ from nlbone.adapters.db import init_sync_engine
6
6
  from nlbone.config.settings import get_settings
7
7
  from nlbone.interfaces.cli.crypto import crypto_command
8
8
  from nlbone.interfaces.cli.init_db import init_db_command
9
+ from nlbone.interfaces.cli.ticket import app as ticket_command
9
10
 
10
11
  app = typer.Typer(help="NLBone CLI")
11
12
 
12
13
  app.add_typer(init_db_command, name="db")
13
14
  app.add_typer(crypto_command, name="crypto")
15
+ app.add_typer(ticket_command, name="ticket")
14
16
 
15
17
 
16
18
  @app.callback()
@@ -0,0 +1,29 @@
1
+ import asyncio
2
+ import typer
3
+
4
+ from nlbone.adapters.ticketing.client import TicketingClient, CreateTicketIn
5
+
6
+ app = typer.Typer(add_completion=False)
7
+
8
+ @app.command("create")
9
+ def send_sample():
10
+ payload = CreateTicketIn(
11
+ assignee_id= "153",
12
+ category_id= 2,
13
+ channel= "site_chat",
14
+ direction= "incoming",
15
+ entity_id= "153",
16
+ entity_type= "user",
17
+ message= "سلام خوبی",
18
+ priority= "medium",
19
+ product_id= 0,
20
+ status= "open",
21
+ title= "پشتیبانی فنی (ثبت نام و لاگین)",
22
+ user_id= 153,
23
+ )
24
+ client = TicketingClient()
25
+ asyncio.run(client.create_ticket(payload, created_by_id=995836))
26
+ print("Ticket message published (or logged if Noop).")
27
+
28
+ if __name__ == "__main__":
29
+ app()
@@ -13,8 +13,8 @@ def run_dispatch_outbox(outbox_repo, publisher: IntegrationPublisher):
13
13
  else:
14
14
  publisher.publish(topic, payload)
15
15
  outbox_repo.mark_sent(rec["id"])
16
- except TemporaryError:
17
- outbox_repo.schedule_retry(rec["id"], rec["retries"])
16
+ # except TemporaryError:
17
+ # outbox_repo.schedule_retry(rec["id"], rec["retries"])
18
18
  except Exception:
19
19
  # mark_failed یا retry policy
20
20
  outbox_repo.schedule_retry(rec["id"], rec["retries"])
nlbone/utils/crypto.py CHANGED
@@ -1,12 +1,13 @@
1
1
  import base64
2
2
  import hashlib
3
+ from functools import lru_cache
3
4
 
4
5
  from cryptography.fernet import Fernet
5
6
 
6
7
  from nlbone.config.settings import get_settings
7
8
 
8
9
 
9
- def _get_fernet_key() -> Fernet:
10
+ def _get_fernet_key() -> bytes:
10
11
  settings = get_settings()
11
12
  fernet_key = settings.FERNET_KEY
12
13
 
@@ -18,12 +19,14 @@ def _get_fernet_key() -> Fernet:
18
19
  return base64.urlsafe_b64encode(digest)
19
20
 
20
21
 
21
- fernet = Fernet(_get_fernet_key())
22
+ @lru_cache(maxsize=1)
23
+ def get_fernet():
24
+ return Fernet(_get_fernet_key())
22
25
 
23
26
 
24
27
  def encrypt_text(plaintext: str) -> str:
25
- return fernet.encrypt(plaintext.encode()).decode()
28
+ return get_fernet().encrypt(plaintext.encode()).decode()
26
29
 
27
30
 
28
31
  def decrypt_text(token: str) -> str:
29
- return fernet.decrypt(token.encode()).decode()
32
+ return get_fernet().decrypt(token.encode()).decode()
@@ -1,11 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nlbone
3
- Version: 0.6.20
3
+ Version: 0.7.0
4
4
  Summary: Backbone package for interfaces and infrastructure in Python projects
5
5
  Author-email: Amir Hosein Kahkbazzadeh <a.khakbazzadeh@gmail.com>
6
6
  License: MIT
7
7
  License-File: LICENSE
8
8
  Requires-Python: >=3.10
9
+ Requires-Dist: aio-pika>=9.5.7
9
10
  Requires-Dist: anyio>=4.0
10
11
  Requires-Dist: cachetools>=6.2.0
11
12
  Requires-Dist: cryptography~=45.0.4
@@ -23,7 +24,7 @@ Requires-Dist: redis~=6.4.0
23
24
  Requires-Dist: sqlalchemy>=2.0
24
25
  Requires-Dist: starlette>=0.47
25
26
  Requires-Dist: typer>=0.17.4
26
- Requires-Dist: uvicorn>=0.35
27
+ Requires-Dist: uvicorn==0.35
27
28
  Description-Content-Type: text/markdown
28
29
 
29
30
  # nlbone
@@ -1,5 +1,5 @@
1
1
  nlbone/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- nlbone/container.py,sha256=rVYzH-jIM8iCcefDOo29mNjvFdf3nJ4EtPNUws9SDnA,3089
2
+ nlbone/container.py,sha256=I3Ev5L-CvfOquR4cyueIiplRriZ-_q_QlH_Xne9lA0k,2698
3
3
  nlbone/types.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  nlbone/adapters/__init__.py,sha256=NzUmk4XPyp3GJOw7VSE86xkQMZLtG3MrOoXLeoB551M,41
5
5
  nlbone/adapters/auth/__init__.py,sha256=hkDHvsFhw_UiOHG9ZSMqjiAhK4wumEforitveSZswVw,42
@@ -11,14 +11,14 @@ nlbone/adapters/cache/memory.py,sha256=y8M4erHQXApiSMAqG6Qk4pxEb60hRdu1szPv6iqvO
11
11
  nlbone/adapters/cache/pubsub_listener.py,sha256=3vfK4O4EzuQQhTsbZ_bweP06o99kDSyHJ5PrfUotUaE,1460
12
12
  nlbone/adapters/cache/redis.py,sha256=2Y1DYHBLCrbHTO6O7pw85u3qY6OnCIFTYJ-HBvBs0FM,4608
13
13
  nlbone/adapters/db/__init__.py,sha256=0CDSySEk4jJsqmwI0eNuaaLJOJDt8_iSiHBsFdC-L3s,212
14
- nlbone/adapters/db/postgres/__init__.py,sha256=6JYJH0xZs3aR-zuyMpRhsdzFugmqz8nprwTQLprqhZc,313
14
+ nlbone/adapters/db/postgres/__init__.py,sha256=tvCpHOdZbpQ57o7k-plq7L0e1uZe5_Frbh7I-LxW7zM,313
15
15
  nlbone/adapters/db/postgres/audit.py,sha256=IuWkPitr70UyQ6-GkAedckp8U-Z4cTgzFbdt_bQv1VQ,4800
16
- nlbone/adapters/db/postgres/base.py,sha256=kha9xmklzhuQAK8QEkNBn-mAHq8dUKbOM-3abaBpWmQ,71
16
+ nlbone/adapters/db/postgres/base.py,sha256=I89PsEeR9ADEScG8D5pVSncPrPRBmf-KQQkjajl7Koo,132
17
17
  nlbone/adapters/db/postgres/engine.py,sha256=UCegauVB1gvo42ThytYnn5VIcQBwR-5xhcXYFApRFNk,3448
18
18
  nlbone/adapters/db/postgres/query_builder.py,sha256=Qv_2oZ5OxZwtN3Ts-jaAX_8sLBzb1mpGBhlNF7aR6Wk,12543
19
- nlbone/adapters/db/postgres/repository.py,sha256=J_DBE73JhHPYCk90c5-O7lQtZbxDgqjjN9OcWy4Omvs,1660
19
+ nlbone/adapters/db/postgres/repository.py,sha256=n01TAzdKd-UbOhirE6KMosuvRdJG2l1cszwVHjTM-Ks,10345
20
20
  nlbone/adapters/db/postgres/schema.py,sha256=NlE7Rr8uXypsw4oWkdZhZwcIBHQEPIpoHLxcUo98i6s,1039
21
- nlbone/adapters/db/postgres/uow.py,sha256=nRxNpY-WoWHpym-XeZ8VHm0MYvtB9wuopOeNdV_ebk8,2088
21
+ nlbone/adapters/db/postgres/uow.py,sha256=2vRp4RBkh9RVniEY6CMXNHt-XXK9W2CDNKR1upT5EJE,3788
22
22
  nlbone/adapters/db/redis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
23
  nlbone/adapters/db/redis/client.py,sha256=5SUnwP2-GrueSFimUbiqDvrQsumvIE2aeozk8l-vOfQ,466
24
24
  nlbone/adapters/http_clients/__init__.py,sha256=w-Yr9CLuXMU71N0Ada5HbvP1DB53wqeP6B-i5rALlTo,150
@@ -27,39 +27,39 @@ nlbone/adapters/http_clients/pricing/pricing_service.py,sha256=fYfMQh3qW_YDNkBW1
27
27
  nlbone/adapters/http_clients/uploadchi/__init__.py,sha256=uBzEOuVtY22teWW2b36Pitkdk5yVdSqa6xbg22JfTNg,105
28
28
  nlbone/adapters/http_clients/uploadchi/uploadchi.py,sha256=erpjOees25FW0nuK1PkYS-oU0h8MeRV9Rhs1cf3gaEs,4881
29
29
  nlbone/adapters/http_clients/uploadchi/uploadchi_async.py,sha256=PQbVNeaYde5CmgT3vcnQoI1PGeSs9AxHlPFuB8biOmU,4717
30
- nlbone/adapters/messaging/__init__.py,sha256=UDAwu3s-JQmOZjWz2Nu0SgHhnkbeOhKDH_zLD75oWMY,40
31
- nlbone/adapters/messaging/event_bus.py,sha256=w-NPwDiPMLFPU_enRQCtfQXOALsXfg31u57R8sG_-1U,781
32
- nlbone/adapters/messaging/redis.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
+ nlbone/adapters/messaging/__init__.py,sha256=o6ZiMihm_MhRXfcEpcjHBB3JGQovQbg3pxe0qS6516c,41
31
+ nlbone/adapters/messaging/event_bus.py,sha256=MSM70JPHoDK17efWlh20ATT1O0KW7xWnwZ5D-gI6U_w,3773
32
+ nlbone/adapters/messaging/rabbitmq.py,sha256=jO58NvsZnAEoS3nvsfdjQgqnzraD8f5Op3PqDAVt0RM,2007
33
+ nlbone/adapters/outbox/__init__.py,sha256=S_5t-rI0e3Gj_IegkuMnvwwqkU8BUqLBazJ-nWlFDAM,117
34
+ nlbone/adapters/outbox/outbox_consumer.py,sha256=Pjc8gAKapR-JznhgLXfsDrk5_W2e7QSCQbKlU2nDU4I,3114
35
+ nlbone/adapters/outbox/outbox_repo.py,sha256=X8YOhbpB8zgxlBw8Na1I9lEfhI4cEhsYZVb2oIiYlGo,6708
33
36
  nlbone/adapters/percolation/__init__.py,sha256=0h1Bw7FzxgkDIHxeoyQXSfegrhP6VbpYV4QC8njYdRE,38
34
37
  nlbone/adapters/percolation/connection.py,sha256=1iJISSwMEh4r_6nJI7mYf_v64Q0eeU1eSI0wLIfOK14,415
35
38
  nlbone/adapters/repositories/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
- nlbone/adapters/repositories/outbox_repo.py,sha256=AgZ5BIL6UXAsXO7BlrId6XKGdsznDWsz1Jg9wK2Klww,404
39
+ nlbone/adapters/ticketing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
+ nlbone/adapters/ticketing/client.py,sha256=V5_u7cxV67eAG4jj4vUD23VWGiMXIXSAU362pNS6hYU,1289
37
41
  nlbone/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
42
  nlbone/config/logging.py,sha256=Ot6Ctf7EQZlW8YNB-uBdleqI6wixn5fH0Eo6QRgNkQk,4358
39
- nlbone/config/settings.py,sha256=jmpMeQ6IG_BXv6onwYIvYEauGIlHbEYaf8k6k_Owc9k,4073
43
+ nlbone/config/settings.py,sha256=Zld9ie7X1v2xPZzNVbsHV-EXo6RICf9GIABHwTKuivQ,4332
40
44
  nlbone/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
45
  nlbone/core/application/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
42
46
  nlbone/core/application/base_worker.py,sha256=5brIToSd-vi6tw0ukhHnUZGZhOLq1SQ-NRRy-kp6D24,1193
43
- nlbone/core/application/bus.py,sha256=i-pcIb28lwtkoDwitmXEXxXaf6FSH_jllid0O9QdhX0,6420
44
- nlbone/core/application/di.py,sha256=95BG1LadZvptXI-kMpwqXpQqkXobVfkzirfBTBirRLs,3603
45
- nlbone/core/application/events.py,sha256=eQGLE0aZHuWJsy9J-qRse4CMXOtweH9-2rQ7AIPRMEQ,614
46
- nlbone/core/application/registry.py,sha256=Kvxozb_Z99q4WqP6xRtKoESeQyV9gJFm2olSGNAar08,4474
47
- nlbone/core/application/services.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
+ nlbone/core/application/bus.py,sha256=bi40pu_-6bBllRxqvBNpf7ByHXPsfrUacs-JxM0d18Q,6432
48
+ nlbone/core/application/di.py,sha256=gfxSawmT7jV6fnvOSgZrNt4yIPUg2FSQsT7euShg774,4117
49
+ nlbone/core/application/registry.py,sha256=dTqV_4bkMsLJ60CesZuEel5xO36cD1qikiaCLJXIGOw,4660
48
50
  nlbone/core/application/use_case.py,sha256=3GMQZ3CFK5cbLoBNBgohPft6GBq2j9_wr8iKRq_osQA,247
49
51
  nlbone/core/application/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
52
  nlbone/core/domain/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
- nlbone/core/domain/base.py,sha256=5oUfbpaI8juJ28Api8J9IXOSm55VI2bp4QNhA0U8h2Y,1251
52
- nlbone/core/domain/events.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
53
- nlbone/core/domain/models.py,sha256=Zn_rwtlzfjOEJZo6HS9M8UsMk-HpMJrHAKn05UA-u2k,1461
54
- nlbone/core/ports/__init__.py,sha256=gx-Ubj7h-1vvnu56sNnRqmer7HHfW3rX2WLl-0AX5U0,214
53
+ nlbone/core/domain/base.py,sha256=6C_wsn4CfFlW7n6ACsyA4r-ZciF4xUv18y0LzhCqMq4,1434
54
+ nlbone/core/domain/models.py,sha256=VEIfzruBXcF5XrDrWEvh9q-Ba9-9x_JG20wZsBF5thc,3270
55
+ nlbone/core/ports/__init__.py,sha256=syJg3fAjQALD5Rjfm9wi9bQpkIvNTWjE9AURBmy587o,132
55
56
  nlbone/core/ports/auth.py,sha256=C-GmUqHNx4bAku6KbW_OTpPXCEfurBWWyDi9KxpTi9M,553
56
57
  nlbone/core/ports/cache.py,sha256=8pP_z4ta7PNNG8UiSrEF4xMZRm2wLPxISZvdPt7QnxQ,2351
57
- nlbone/core/ports/event_bus.py,sha256=_Om1GOOT-F325oV6_LJXtLdx4vu5i7KrpTDD3qPJXU0,325
58
+ nlbone/core/ports/event_bus.py,sha256=7iC8WRBg-EmcKJx7AVPkP-r823SLKGuDxGp9WF4q-_U,824
58
59
  nlbone/core/ports/files.py,sha256=7Ov2ITYRpPwwDTZGCeNVISg8e3A9l08jbOgpTImgfK8,1863
59
- nlbone/core/ports/messaging.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
60
- nlbone/core/ports/repo.py,sha256=zOw8CTMAu5DKKy2wZpT3_6JWWjaJCDt7q4dOiJYrCOQ,651
61
- nlbone/core/ports/repository.py,sha256=2IfyGOERhWQGYkVk3pHswtUQ7_bGxfXZCTu3o29OhWU,2752
62
- nlbone/core/ports/uow.py,sha256=SmBdRf0NvSdIjQ3Le1QGz8kNGBk7jgNHtNguvXRwmgs,557
60
+ nlbone/core/ports/outbox.py,sha256=mjA3uHS_ycE1oD4Ht8uDUf8QbwoC8r7llb6gBoIbAZU,2274
61
+ nlbone/core/ports/repository.py,sha256=Ee8iSt4WxUIt113zLd7hq0HwtHc8r8qRSFBMTiGuJq4,2822
62
+ nlbone/core/ports/uow.py,sha256=VhqSc-Ryt9m-rlNMiXTzD3dPGz6mM_JxND8D0UJGRu4,962
63
63
  nlbone/interfaces/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
64
64
  nlbone/interfaces/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
65
65
  nlbone/interfaces/api/exception_handlers.py,sha256=vxNEBgAaQygLgAz1UNt3wHj0SdCJOwtLOv_BwTfir3o,4050
@@ -68,7 +68,7 @@ nlbone/interfaces/api/routers.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hS
68
68
  nlbone/interfaces/api/schemas.py,sha256=NIEKeTdJtwwIkIxL7WURNZF8g34I4TlRAqs-x1Uq7YI,108
69
69
  nlbone/interfaces/api/additional_filed/__init__.py,sha256=BWemliLSQV9iq1vdUaF733q0FOSipSWBOQk9eYj732Q,318
70
70
  nlbone/interfaces/api/additional_filed/assembler.py,sha256=80sFuNiquqdLPOcx7MoQ_ud9fAJtA327M77Z9V47pIU,1956
71
- nlbone/interfaces/api/additional_filed/field_registry.py,sha256=xrA-2pMqX6JA4vy7LliJv5btQdy-6AKctFxZZCpWVOI,5321
71
+ nlbone/interfaces/api/additional_filed/field_registry.py,sha256=IhIvzHWOMtKv8iTdFu7LzQboi4SFTLOyJqKdYPY8xFE,5418
72
72
  nlbone/interfaces/api/additional_filed/resolver.py,sha256=jv1TIBBHN4LBIMwHGipcy4iq0uP0r6udyaqvhRzb8Bk,4655
73
73
  nlbone/interfaces/api/additional_filed/default_field_rules/__init__.py,sha256=LUSAOO3xRUt5ptlraIx7H-7dSkdr1D-WprmnqXRB16g,48
74
74
  nlbone/interfaces/api/additional_filed/default_field_rules/image_field_rules.py,sha256=ecKqPeXZ-YiF14RK9PmK7ln3PCzpCUc18S5zm5IF3fw,339
@@ -88,23 +88,24 @@ nlbone/interfaces/api/schema/adaptive_schema.py,sha256=bdWBNpP2NfOJ_in4btXn0lrZO
88
88
  nlbone/interfaces/api/schema/base_response_model.py,sha256=lkBs7k0IcQiSQdJ3KvqDQPr_zwqKNbwaQjcwAE_chnU,599
89
89
  nlbone/interfaces/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
90
90
  nlbone/interfaces/cli/crypto.py,sha256=lh2uUbSYKT6XxAt9uP1-VksopqAgdxiSKoKgXwXB0aE,692
91
- nlbone/interfaces/cli/init_db.py,sha256=C67n2MsJ1vzkJxC8zfUYOxFdd6mEB_vT9agxN6jWoG8,790
92
- nlbone/interfaces/cli/main.py,sha256=0SxjiJlEB0xd8gobxSCg8mzsDx_ZIzUvRn9DWYi8Vw8,787
91
+ nlbone/interfaces/cli/init_db.py,sha256=Hk3aZ8w9KdfgQfDWaOnIgNEAegn2uNggkkSgDXQLgyc,1791
92
+ nlbone/interfaces/cli/main.py,sha256=wI6YQMTQ4wxH-5ncFgrKKk2uVoinqO70oaWziOkfsfw,895
93
+ nlbone/interfaces/cli/ticket.py,sha256=7-T-4VTh6X41C2EX_oNvAFCRpQOe9UOfXCmLy-07TqQ,798
93
94
  nlbone/interfaces/jobs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
94
- nlbone/interfaces/jobs/dispatch_outbox.py,sha256=C6KWo17SXSETIrlYcGrNzh0SfI_gzfBcj0xp5mr8iXo,805
95
+ nlbone/interfaces/jobs/dispatch_outbox.py,sha256=yLZSC3nvkgxT2LL4Pq_DYzCyf_tZB-FknrjjgN89GFg,809
95
96
  nlbone/interfaces/jobs/sync_tokens.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
96
97
  nlbone/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
97
98
  nlbone/utils/cache.py,sha256=hVfkR62o5vllDrE_nY4At10wK0It6qpZ45K1xoj10cQ,5931
98
99
  nlbone/utils/cache_keys.py,sha256=Y2YSellHTbUOcoaNbl1jaD4r485VU_e4KXsfBWhYTBo,1075
99
100
  nlbone/utils/cache_registry.py,sha256=w28sEfUQZAhzCCqVH5TflWQY3nyDXyEcFWt8hkuHRHw,823
100
101
  nlbone/utils/context.py,sha256=MmclJ24BG2uvSTg1IK7J-Da9BhVFDQ5ag4Ggs2FF1_w,1600
101
- nlbone/utils/crypto.py,sha256=UOxjjyc1B868_R_k2js83bYRIBoo7c0txD8gXLgavDY,661
102
+ nlbone/utils/crypto.py,sha256=PX0Tlf2nqXcGbuv16J26MoUPzo2c4xcD4sZBXxhBXgQ,746
102
103
  nlbone/utils/http.py,sha256=UXUoXgQdTRNT08ho8zl-C5ekfDsD8uf-JiMQ323ooqw,872
103
104
  nlbone/utils/normalize_mobile.py,sha256=sGH4tV9gX-6eVKozviNWJhm1DN1J28Nj-ERldCYkS_E,732
104
105
  nlbone/utils/redactor.py,sha256=-V4HrHmHwPi3Kez587Ek1uJlgK35qGSrwBOvcbw8Jas,1279
105
106
  nlbone/utils/time.py,sha256=DjjyQ9GLsfXoT6NK8RDW2rOlJg3e6sF04Jw6PBUrSvg,1268
106
- nlbone-0.6.20.dist-info/METADATA,sha256=y5qyXUYRp1IImMd3Y9X4HxrwcFzR6QsBHMu-Q150tho,2264
107
- nlbone-0.6.20.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
108
- nlbone-0.6.20.dist-info/entry_points.txt,sha256=CpIL45t5nbhl1dGQPhfIIDfqqak3teK0SxPGBBr7YCk,59
109
- nlbone-0.6.20.dist-info/licenses/LICENSE,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
110
- nlbone-0.6.20.dist-info/RECORD,,
107
+ nlbone-0.7.0.dist-info/METADATA,sha256=GGuW7XamhW1Bg6v2NX5E09NS5L4W41k6MikQane4Fq8,2294
108
+ nlbone-0.7.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
109
+ nlbone-0.7.0.dist-info/entry_points.txt,sha256=CpIL45t5nbhl1dGQPhfIIDfqqak3teK0SxPGBBr7YCk,59
110
+ nlbone-0.7.0.dist-info/licenses/LICENSE,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
111
+ nlbone-0.7.0.dist-info/RECORD,,
@@ -1,18 +0,0 @@
1
- from typing import List
2
-
3
-
4
- class OutboxRecord(dict):
5
- pass
6
-
7
-
8
- class OutboxRepository:
9
- def __init__(self, engine):
10
- self._engine = engine
11
-
12
- def add(self, msg) -> None: ...
13
-
14
- def fetch_pending(self, limit: int = 100) -> List[OutboxRecord]: ...
15
-
16
- def mark_sent(self, msg_id: int) -> None: ...
17
-
18
- def schedule_retry(self, msg_id: int, retries: int, backoff_base: int = 2) -> None: ...
@@ -1,20 +0,0 @@
1
- from typing import Iterable, Sequence
2
-
3
- from nlbone.core.domain.base import AggregateRoot, DomainEvent
4
- from nlbone.core.ports.event_bus import EventBusPort
5
-
6
-
7
- def collect_events(*aggregates: Iterable[AggregateRoot]) -> list[DomainEvent]:
8
- events: list[DomainEvent] = []
9
- for agg in aggregates:
10
- if isinstance(agg, AggregateRoot):
11
- events.extend(agg.pull_events())
12
- else:
13
- for a in agg:
14
- events.extend(a.pull_events())
15
- return events
16
-
17
-
18
- def publish_events(bus: EventBusPort, events: Sequence[DomainEvent]) -> None:
19
- if events:
20
- bus.publish(events)
File without changes
File without changes
File without changes
nlbone/core/ports/repo.py DELETED
@@ -1,19 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from typing import Iterable, List, Optional, Protocol, TypeVar
4
-
5
- T = TypeVar("T")
6
-
7
-
8
- class Repository(Protocol[T]): # ← نه Protocol, Generic[T]
9
- def get(self, id) -> Optional[T]: ...
10
- def add(self, obj: T) -> None: ...
11
- def remove(self, obj: T) -> None: ...
12
- def list(self, *, limit: int | None = None, offset: int = 0) -> Iterable[T]: ...
13
-
14
-
15
- class AsyncRepository(Protocol[T]):
16
- async def get(self, id) -> Optional[T]: ...
17
- def add(self, obj: T) -> None: ...
18
- async def remove(self, obj: T) -> None: ...
19
- async def list(self, *, limit: int | None = None, offset: int = 0) -> List[T]: ...