karrio-server 2025.5rc31__py3-none-any.whl → 2025.5rc33__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.
karrio/server/VERSION CHANGED
@@ -1 +1 @@
1
- 2025.5rc31
1
+ 2025.5rc33
@@ -164,7 +164,7 @@ if OTEL_ENABLED and OTEL_EXPORTER_OTLP_ENDPOINT:
164
164
  pass # Psycopg2 might not be installed
165
165
 
166
166
  # Instrument Redis if configured
167
- if config("REDIS_HOST", default=None):
167
+ if config("REDIS_URL", default=None) or config("REDIS_HOST", default=None):
168
168
  try:
169
169
  RedisInstrumentor().instrument()
170
170
  except Exception:
@@ -31,9 +31,11 @@ config = decouple.AutoConfig(search_path=Path().resolve())
31
31
 
32
32
  if not config("SECRET_KEY", default=None):
33
33
  try:
34
+ # Note: Using print here intentionally as logging isn't configured yet
34
35
  print("> fallback .env.sample...")
35
36
  config = decouple.Config(decouple.RepositoryEnv(".env.sample"))
36
37
  except Exception as e:
38
+ # Note: Using print here intentionally as logging isn't configured yet
37
39
  print(f"> error: {e}")
38
40
 
39
41
 
@@ -58,6 +60,8 @@ CORS_ALLOW_CREDENTIALS = True
58
60
  CORS_ALLOW_HEADERS = list(default_headers) + [
59
61
  "x-test-mode",
60
62
  "x-org-id",
63
+ "x-tenant-id",
64
+ "x-request-id",
61
65
  ]
62
66
 
63
67
  # HTTPS configuration
@@ -353,7 +357,7 @@ if config("DATABASE_URL", default=None):
353
357
  DATABASES["default"].update(db_from_env)
354
358
 
355
359
  # Configure workers database for SQLite storage when Redis is not available
356
- if not config("REDIS_HOST", default=None):
360
+ if not config("REDIS_URL", default=None) and not config("REDIS_HOST", default=None):
357
361
  _WORKER_DB_DIR = config("WORKER_DB_DIR", default=WORK_DIR)
358
362
  _WORKER_DB_FILE_NAME = os.path.join(_WORKER_DB_DIR, "tasks.sqlite3")
359
363
  DATABASES["workers"] = {
@@ -581,54 +585,91 @@ LOG_FILE_DIR = config("LOG_DIR", default=WORK_DIR)
581
585
  LOG_FILE_NAME = os.path.join(LOG_FILE_DIR, "debug.log")
582
586
  DRF_TRACKING_ADMIN_LOG_READONLY = True
583
587
 
584
- LOGGING = {
585
- "version": 1,
586
- "disable_existing_loggers": False,
587
- "formatters": {
588
- "verbose": {
589
- "format": "{levelname} {asctime} {module} {process:d} {thread:d} {message}",
590
- "style": "{",
588
+ # Option to use Loguru (default: True)
589
+ USE_LOGURU = config("USE_LOGURU", default=True, cast=bool)
590
+
591
+ if USE_LOGURU:
592
+ # Minimal LOGGING config - will be intercepted by Loguru
593
+ LOGGING = {
594
+ "version": 1,
595
+ "disable_existing_loggers": False,
596
+ "handlers": {
597
+ "console": {
598
+ "class": "logging.StreamHandler",
599
+ },
591
600
  },
592
- "simple": {
593
- "format": "{levelname} {filename} {lineno} {message}",
594
- "style": "{",
595
- },
596
- },
597
- "handlers": {
598
- "file": {
599
- "level": "DEBUG",
600
- "class": "logging.handlers.TimedRotatingFileHandler",
601
- "formatter": "verbose",
602
- "filename": LOG_FILE_NAME,
603
- "when": "D",
604
- "interval": 1,
605
- "backupCount": 20,
606
- },
607
- "console": {
608
- "class": "logging.StreamHandler",
609
- "formatter": "simple",
610
- },
611
- },
612
- "loggers": {
613
- "oauth2_provider": {
614
- "level": "DEBUG",
601
+ "root": {
615
602
  "handlers": ["console"],
616
- "propagate": True,
603
+ "level": "INFO",
617
604
  },
618
- "django": {
619
- "handlers": ["file", "console"],
620
- "level": DJANGO_LOG_LEVEL,
621
- "propagate": False,
605
+ }
606
+ else:
607
+ # Traditional Django logging configuration
608
+ LOGGING = {
609
+ "version": 1,
610
+ "disable_existing_loggers": False,
611
+ "formatters": {
612
+ "verbose": {
613
+ "format": "{levelname} {asctime} {module} {process:d} {thread:d} {message}",
614
+ "style": "{",
615
+ },
616
+ "simple": {
617
+ "format": "{levelname} {filename} {lineno} {message}",
618
+ "style": "{",
619
+ },
622
620
  },
623
- "karrio": {
624
- "handlers": ["file", "console"],
625
- "level": LOG_LEVEL,
626
- "propagate": False,
621
+ "handlers": {
622
+ "file": {
623
+ "level": "DEBUG",
624
+ "class": "logging.handlers.TimedRotatingFileHandler",
625
+ "formatter": "verbose",
626
+ "filename": LOG_FILE_NAME,
627
+ "when": "D",
628
+ "interval": 1,
629
+ "backupCount": 20,
630
+ },
631
+ "console": {
632
+ "class": "logging.StreamHandler",
633
+ "formatter": "simple",
634
+ },
627
635
  },
628
- "karrio.server.core.exceptions": {
629
- "handlers": ["file", "console"],
630
- "level": "DEBUG",
631
- "propagate": False,
636
+ "loggers": {
637
+ "oauth2_provider": {
638
+ "level": "DEBUG",
639
+ "handlers": ["console"],
640
+ "propagate": True,
641
+ },
642
+ "django": {
643
+ "handlers": ["file", "console"],
644
+ "level": DJANGO_LOG_LEVEL,
645
+ "propagate": False,
646
+ },
647
+ "karrio": {
648
+ "handlers": ["file", "console"],
649
+ "level": LOG_LEVEL,
650
+ "propagate": False,
651
+ },
652
+ "karrio.server.core.exceptions": {
653
+ "handlers": ["file", "console"],
654
+ "level": "DEBUG",
655
+ "propagate": False,
656
+ },
632
657
  },
633
- },
634
- }
658
+ }
659
+
660
+ # Initialize Loguru if enabled
661
+ if USE_LOGURU:
662
+ try:
663
+ from karrio.server.core.logging import setup_django_loguru, logger
664
+
665
+ setup_django_loguru(
666
+ level=LOG_LEVEL,
667
+ log_file=LOG_FILE_NAME,
668
+ intercept_django=True,
669
+ enqueue=True, # Thread-safe async logging
670
+ )
671
+ except ImportError as e:
672
+ # Note: Using print here as Loguru failed to load
673
+ print(f"Warning: Failed to initialize Loguru: {e}")
674
+ print("Falling back to standard Django logging")
675
+ USE_LOGURU = False
@@ -1,29 +1,85 @@
1
1
  # type: ignore
2
+ import sys
2
3
  from decouple import config
3
4
  from karrio.server.settings.base import *
4
5
  from karrio.server.settings.apm import HEALTH_CHECK_APPS
6
+ from karrio.server.core.logging import logger
5
7
 
6
8
 
7
9
  CACHE_TTL = 60 * 15
8
- REDIS_HOST = config("REDIS_HOST", default=None)
9
- REDIS_PORT = config("REDIS_PORT", default=None)
10
- REDIS_PASSWORD = config("REDIS_PASSWORD", default=None)
11
- REDIS_USERNAME = config("REDIS_USERNAME", default="default")
10
+
11
+ # Check if worker is running in detached mode (separate from API server)
12
+ DETACHED_WORKER = config("DETACHED_WORKER", default=False, cast=bool)
13
+
14
+ # Detect if running as a worker process (via run_huey command)
15
+ IS_WORKER_PROCESS = any("run_huey" in arg for arg in sys.argv)
16
+
17
+ # Skip default Redis cache configuration if in worker mode
18
+ # Workers only need HUEY Redis, not the default Django cache
19
+ SKIP_DEFAULT_CACHE = DETACHED_WORKER or IS_WORKER_PROCESS
20
+
21
+ # Redis configuration - REDIS_URL takes precedence and supersedes granular env vars
22
+ REDIS_URL = config("REDIS_URL", default=None)
12
23
  REDIS_PREFIX = config("REDIS_PREFIX", default="karrio")
24
+ REDIS_SSL = config("REDIS_SSL", default=False, cast=bool)
25
+
26
+ # Parse REDIS_URL or construct from individual parameters
27
+ if REDIS_URL is not None:
28
+ from urllib.parse import urlparse, urlunparse
29
+ import re
30
+
31
+ parsed = urlparse(REDIS_URL)
32
+
33
+ # Extract values from REDIS_URL (these supersede granular env vars)
34
+ REDIS_HOST = parsed.hostname
35
+ REDIS_PORT = parsed.port or 6379
36
+ REDIS_USERNAME = parsed.username or "default"
37
+ REDIS_PASSWORD = parsed.password
13
38
 
14
- # karrio server caching setup
15
- if REDIS_HOST is not None:
39
+ # Determine SSL from URL scheme (rediss:// means SSL is enabled)
40
+ REDIS_SCHEME = parsed.scheme if parsed.scheme in ("redis", "rediss") else "redis"
41
+ REDIS_SSL = REDIS_SCHEME == "rediss"
42
+
43
+ # Build connection URL with database 1 for cache
44
+ REDIS_AUTH = f"{REDIS_USERNAME}:{REDIS_PASSWORD}@" if REDIS_PASSWORD else ""
45
+ REDIS_CONNECTION_URL = f"{REDIS_SCHEME}://{REDIS_AUTH}{REDIS_HOST}:{REDIS_PORT}/1"
46
+
47
+ else:
48
+ # Fall back to individual parameters
49
+ REDIS_HOST = config("REDIS_HOST", default=None)
50
+ REDIS_PORT = config("REDIS_PORT", default=None)
51
+ REDIS_PASSWORD = config("REDIS_PASSWORD", default=None)
52
+ REDIS_USERNAME = config("REDIS_USERNAME", default="default")
53
+
54
+ if REDIS_HOST is not None:
55
+ REDIS_AUTH = f"{REDIS_USERNAME}:{REDIS_PASSWORD}@" if REDIS_PASSWORD else ""
56
+ REDIS_SCHEME = "rediss" if REDIS_SSL else "redis"
57
+ REDIS_CONNECTION_URL = (
58
+ f'{REDIS_SCHEME}://{REDIS_AUTH}{REDIS_HOST}:{REDIS_PORT or "6379"}/1'
59
+ )
60
+
61
+ # Configure Django cache if Redis is available and not in worker mode
62
+ if REDIS_HOST is not None and not SKIP_DEFAULT_CACHE:
16
63
  HEALTH_CHECK_APPS += ["health_check.contrib.redis"]
17
64
  INSTALLED_APPS += ["health_check.contrib.redis"]
18
- REDIS_AUTH = f"{REDIS_USERNAME}:{REDIS_PASSWORD}@" if REDIS_PASSWORD else ""
19
65
 
20
- REDIS_CONNECTION_URL = f'redis://{REDIS_AUTH}{REDIS_HOST}:{REDIS_PORT or "6379"}/1'
21
66
  CACHES = {
22
67
  "default": {
23
68
  "BACKEND": "django_redis.cache.RedisCache",
24
69
  "LOCATION": REDIS_CONNECTION_URL,
25
- "OPTIONS": {"CLIENT_CLASS": "django_redis.client.DefaultClient"},
70
+ "OPTIONS": {
71
+ "CLIENT_CLASS": "django_redis.client.DefaultClient",
72
+ **(
73
+ {"CONNECTION_POOL_KWARGS": {"ssl_cert_reqs": None}}
74
+ if REDIS_SSL
75
+ else {}
76
+ ),
77
+ },
26
78
  "KEY_PREFIX": REDIS_PREFIX,
27
79
  }
28
80
  }
29
- print(f"Redis connection initialized at: {REDIS_CONNECTION_URL}")
81
+ print(f"Redis cache connection initialized")
82
+ elif SKIP_DEFAULT_CACHE:
83
+ print(
84
+ "Skipping default Redis cache configuration (worker mode - only HUEY Redis needed)"
85
+ )
@@ -1,5 +1,7 @@
1
1
  # type: ignore
2
2
  import os
3
+ import sys
4
+ import socket
3
5
  import huey
4
6
  import redis
5
7
  import decouple
@@ -12,42 +14,125 @@ DEFAULT_TRACKERS_UPDATE_INTERVAL = decouple.config(
12
14
  "TRACKING_PULSE", default=7200, cast=int
13
15
  ) # value is seconds. so 10800 seconds = 3 Hours
14
16
 
17
+ # Check if worker is running in detached mode (separate from API server)
18
+ DETACHED_WORKER = decouple.config("DETACHED_WORKER", default=False, cast=bool)
19
+
15
20
  WORKER_IMMEDIATE_MODE = decouple.config(
16
21
  "WORKER_IMMEDIATE_MODE", default=False, cast=bool
17
22
  )
18
23
 
19
- REDIS_HOST = decouple.config("REDIS_HOST", default=None)
20
- REDIS_PORT = decouple.config("REDIS_PORT", default=None)
21
- REDIS_PASSWORD = decouple.config("REDIS_PASSWORD", default=None)
22
- REDIS_USERNAME = decouple.config("REDIS_USERNAME", default="default")
23
-
24
-
25
- # Use redis if available
26
- if REDIS_HOST is not None:
27
- pool = redis.ConnectionPool(
28
- host=REDIS_HOST,
29
- port=REDIS_PORT or "6379",
30
- max_connections=20,
31
- **({"password": REDIS_PASSWORD} if REDIS_PASSWORD else {}),
32
- **({"username": REDIS_USERNAME} if REDIS_USERNAME else {}),
33
- )
34
- HUEY = huey.RedisHuey(
35
- "default",
36
- connection_pool=pool,
37
- **({"immediate": WORKER_IMMEDIATE_MODE} if WORKER_IMMEDIATE_MODE else {}),
38
- )
24
+ # Detect if running as a worker process (via run_huey command)
25
+ # Workers always need Huey configured regardless of DETACHED_WORKER setting
26
+ IS_WORKER_PROCESS = any("run_huey" in arg for arg in sys.argv)
39
27
 
28
+ # Skip Huey configuration only if:
29
+ # 1. Running in detached worker mode (DETACHED_WORKER=True)
30
+ # 2. AND not running as a worker process (IS_WORKER_PROCESS=False)
31
+ # This ensures workers always get Huey configured, but API servers don't when detached
32
+ if DETACHED_WORKER and not IS_WORKER_PROCESS:
33
+ # API server in detached mode - skip Huey configuration
34
+ HUEY = None
40
35
  else:
41
- WORKER_DB_DIR = decouple.config("WORKER_DB_DIR", default=settings.WORK_DIR)
42
- WORKER_DB_FILE_NAME = os.path.join(WORKER_DB_DIR, "tasks.sqlite3")
43
-
44
- settings.DATABASES["workers"] = {
45
- "NAME": WORKER_DB_FILE_NAME,
46
- "ENGINE": "django.db.backends.sqlite3",
47
- }
48
-
49
- HUEY = huey.SqliteHuey(
50
- name="default",
51
- filename=WORKER_DB_FILE_NAME,
52
- **({"immediate": WORKER_IMMEDIATE_MODE} if WORKER_IMMEDIATE_MODE else {}),
53
- )
36
+ # Either: worker process, or API server with embedded workers
37
+ # Redis configuration - REDIS_URL takes precedence and supersedes granular env vars
38
+ REDIS_URL = decouple.config("REDIS_URL", default=None)
39
+
40
+ # Parse REDIS_URL or construct from individual parameters
41
+ if REDIS_URL is not None:
42
+ from urllib.parse import urlparse
43
+
44
+ parsed = urlparse(REDIS_URL)
45
+
46
+ # Extract values from REDIS_URL (these supersede granular env vars)
47
+ REDIS_HOST = parsed.hostname
48
+ REDIS_PORT = parsed.port or 6379
49
+ REDIS_USERNAME = parsed.username or "default"
50
+ REDIS_PASSWORD = parsed.password
51
+
52
+ # Determine SSL from URL scheme (rediss:// means SSL is enabled)
53
+ REDIS_SCHEME = (
54
+ parsed.scheme if parsed.scheme in ("redis", "rediss") else "redis"
55
+ )
56
+ REDIS_SSL = REDIS_SCHEME == "rediss"
57
+
58
+ else:
59
+ # Fall back to individual parameters
60
+ REDIS_HOST = decouple.config("REDIS_HOST", default=None)
61
+ REDIS_PORT = decouple.config("REDIS_PORT", default=None)
62
+ REDIS_PASSWORD = decouple.config("REDIS_PASSWORD", default=None)
63
+ REDIS_USERNAME = decouple.config("REDIS_USERNAME", default="default")
64
+ REDIS_SSL = decouple.config("REDIS_SSL", default=False, cast=bool)
65
+
66
+ # Configure HUEY based on available Redis configuration
67
+ if REDIS_HOST is not None:
68
+ # Calculate max connections based on environment
69
+ # Each worker replica needs: (workers_per_replica + 1 scheduler) connections
70
+ # Formula: (worker_replicas * (threads_per_worker + 1)) + api_connections + buffer
71
+ # Example: 100 connections = (5 replicas * (8 workers + 1 scheduler)) + 40 API + 15 buffer
72
+ REDIS_MAX_CONNECTIONS = decouple.config(
73
+ "REDIS_MAX_CONNECTIONS", default=100, cast=int
74
+ )
75
+
76
+ # Connection pool configuration with timeouts
77
+ # Use BlockingConnectionPool to wait for available connections instead of failing immediately
78
+ pool_kwargs = {
79
+ "host": REDIS_HOST,
80
+ "port": REDIS_PORT,
81
+ "max_connections": REDIS_MAX_CONNECTIONS,
82
+ "timeout": 20, # Wait up to 20 seconds for an available connection
83
+ # Timeout settings to prevent hung connections
84
+ "socket_timeout": 10, # Command execution timeout (seconds)
85
+ "socket_connect_timeout": 10, # Connection establishment timeout (seconds)
86
+ # Keep connections alive to prevent closure by firewalls/load balancers
87
+ "socket_keepalive": True,
88
+ # Retry on transient failures
89
+ "retry_on_timeout": True,
90
+ }
91
+
92
+ # Add TCP keepalive options if available (Linux/Unix only)
93
+ try:
94
+ pool_kwargs["socket_keepalive_options"] = {
95
+ socket.TCP_KEEPIDLE: 60, # Start keepalive after 60s idle
96
+ socket.TCP_KEEPINTVL: 10, # Keepalive interval
97
+ socket.TCP_KEEPCNT: 3, # Keepalive probes before timeout
98
+ }
99
+ except AttributeError:
100
+ # TCP keepalive constants not available on this platform
101
+ pass
102
+
103
+ # Add authentication if provided
104
+ if REDIS_PASSWORD:
105
+ pool_kwargs["password"] = REDIS_PASSWORD
106
+ if REDIS_USERNAME:
107
+ pool_kwargs["username"] = REDIS_USERNAME
108
+
109
+ # Add SSL/TLS configuration if enabled
110
+ if REDIS_SSL:
111
+ # Use SSLConnection class for SSL/TLS connections
112
+ pool_kwargs["connection_class"] = redis.SSLConnection
113
+ pool_kwargs["ssl_cert_reqs"] = None # For Azure Redis compatibility
114
+
115
+ # Use BlockingConnectionPool to wait for connections instead of raising errors immediately
116
+ pool = redis.BlockingConnectionPool(**pool_kwargs)
117
+
118
+ HUEY = huey.RedisHuey(
119
+ "default",
120
+ connection_pool=pool,
121
+ **({"immediate": WORKER_IMMEDIATE_MODE} if WORKER_IMMEDIATE_MODE else {}),
122
+ )
123
+
124
+ else:
125
+ # No Redis configured, use SQLite
126
+ WORKER_DB_DIR = decouple.config("WORKER_DB_DIR", default=settings.WORK_DIR)
127
+ WORKER_DB_FILE_NAME = os.path.join(WORKER_DB_DIR, "tasks.sqlite3")
128
+
129
+ settings.DATABASES["workers"] = {
130
+ "NAME": WORKER_DB_FILE_NAME,
131
+ "ENGINE": "django.db.backends.sqlite3",
132
+ }
133
+
134
+ HUEY = huey.SqliteHuey(
135
+ name="default",
136
+ filename=WORKER_DB_FILE_NAME,
137
+ **({"immediate": WORKER_IMMEDIATE_MODE} if WORKER_IMMEDIATE_MODE else {}),
138
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: karrio_server
3
- Version: 2025.5rc31
3
+ Version: 2025.5rc33
4
4
  Summary: Multi-carrier shipping API
5
5
  Author-email: karrio <hello@karrio.io>
6
6
  License-Expression: Apache-2.0
@@ -42,6 +42,7 @@ Requires-Dist: opentelemetry-instrumentation-logging
42
42
  Requires-Dist: opentelemetry-instrumentation-psycopg2
43
43
  Requires-Dist: opentelemetry-instrumentation-redis
44
44
  Requires-Dist: opentelemetry-semantic-conventions
45
+ Requires-Dist: loguru
45
46
 
46
47
  # <a href="https://karrio.io" target="_blank"><img alt="Karrio" src="https://docs.karrio.io/img/logo.svg" height="50px" /></a>
47
48
 
@@ -1,4 +1,4 @@
1
- karrio/server/VERSION,sha256=mbeRK4sJZA26Mqme_nviTrhpkJlUXIywotpDUr5EmG8,10
1
+ karrio/server/VERSION,sha256=Jmh7RfdYs16oKOK2DMy-Yo-5r45YiB1puxKA3AUCuGc,10
2
2
  karrio/server/__init__.py,sha256=iOEMwnlORWezdO8-2vxBIPSR37D7JGjluZ8f55vzxls,81
3
3
  karrio/server/__main__.py,sha256=hy2-Zb2wSVe_Pu6zWZ-BhiM4rBaGZ3D16HSuhudygqg,632
4
4
  karrio/server/asgi.py,sha256=LsZYMWo8U9zURVPdHnvUsziOhMjdCdQoD2-gMJbS2U0,462
@@ -6,13 +6,13 @@ karrio/server/workers.py,sha256=wOlWmXC7zRJV86IfbQnfUZsnCIvvWtXzFHH_EIkg1J0,179
6
6
  karrio/server/wsgi.py,sha256=SpWqkEYlMsj89_znZ8p8IjH3EgTVRWRq_9eS8t64dMw,403
7
7
  karrio/server/lib/otel_huey.py,sha256=6MP6vX6b6x6RPF2K1m8B8L8S9GK1Q3vANmLidsxh65k,5428
8
8
  karrio/server/settings/__init__.py,sha256=iw-NBcReOnDYpnvSEBdYDfV7jC0040jYdupnmSdElec,866
9
- karrio/server/settings/apm.py,sha256=PfILlN71p38pNHeV3AysAdnyErnsIvh_8buPVt6ASfw,7378
10
- karrio/server/settings/base.py,sha256=c_rNOlOsE5qFEHjIo1yE5FtPfQwkzUhs5e7T9h9cfoA,20752
11
- karrio/server/settings/cache.py,sha256=BCFIjbLKBgYs34i099Z_i8EC55lRF39oJfsPHoXq3vc,1112
9
+ karrio/server/settings/apm.py,sha256=fp9_CVzNfQ8MvNp1-WQbCILzLU3RSJeeu1vYAtdrgfs,7415
10
+ karrio/server/settings/base.py,sha256=UbZ4pEBEKG0mJSlNED1iU9KEpNmrZjjmwdujwnQ30fI,22285
11
+ karrio/server/settings/cache.py,sha256=nAHLgqynNtohxCJSMYP2RzcnBGC0ZC30KH6LlKdxgo4,3218
12
12
  karrio/server/settings/constance.py,sha256=wKi7u-NORAPjIJMIbl3k5kPRkUA6jJJWe9kxsV3aoeA,7113
13
13
  karrio/server/settings/debug.py,sha256=fFyK2XX47UGeK0eRNSV-9ZLaComay5QvJW0692vaH98,527
14
14
  karrio/server/settings/email.py,sha256=bHBLKM_v3HTkmjrz_Msdj_Z7_kMzAb7i6pvJCZuzu1E,1403
15
- karrio/server/settings/workers.py,sha256=s3km5UZcultq4O1adWZWso7jvRyfhc4jk3T1Jx0EoCA,1697
15
+ karrio/server/settings/workers.py,sha256=Ey59-TQ2odW-e15Mf2OZjQSLzX3jNCnWMC7dy-T2A3o,5755
16
16
  karrio/server/static/extra/branding/android-chrome-192x192.png,sha256=qSwEKKBtk4udSHb0OWGC5-jfkP5cVpULDD1Cdkuk8PU,7005
17
17
  karrio/server/static/extra/branding/android-chrome-512x512.png,sha256=YFwVPnPChO30tTuyrwSc_z548H7C6OFXh4CCu2krvHA,21062
18
18
  karrio/server/static/extra/branding/favicon-16x16.png,sha256=wkELpij29bIvvKr5sDcjfNeYvj7i0yk-__bJbZckEK8,1085
@@ -73,8 +73,8 @@ karrio/server/templates/admin/base_site.html,sha256=kbcdvehXZ1EHaw07JL7fSZmjrnVM
73
73
  karrio/server/templates/openapi/openapi.html,sha256=3ApCZ5pE6Wjv7CJllVbqD2WiDQuLy-BFS-IIHurXhBY,1133
74
74
  karrio/server/urls/__init__.py,sha256=Ah-XqaqRsfecQgCGRHjxmXe8O7a0avq5ocU90tkVwQI,1998
75
75
  karrio/server/urls/jwt.py,sha256=QN2L-EpUEQCF2UGYPu_VVlA49Fc0BtcY7Ov3-xpp7_U,6772
76
- karrio_server-2025.5rc31.dist-info/METADATA,sha256=QnPfGK8HPEUkpXjpugdxXmoydJNSTqLY3TcPT4vHR9Q,4283
77
- karrio_server-2025.5rc31.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
78
- karrio_server-2025.5rc31.dist-info/entry_points.txt,sha256=c2eftt6MpJjyp0OFv1OmO9nUYSDemt9fGq_RDdvpGLw,55
79
- karrio_server-2025.5rc31.dist-info/top_level.txt,sha256=D1D7x8R3cTfjF_15mfiO7wCQ5QMtuM4x8GaPr7z5i78,12
80
- karrio_server-2025.5rc31.dist-info/RECORD,,
76
+ karrio_server-2025.5rc33.dist-info/METADATA,sha256=dCp9nxE9T_UWaj-PjNugMeqMiHG_7Udgr8PvKnfPioA,4305
77
+ karrio_server-2025.5rc33.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
78
+ karrio_server-2025.5rc33.dist-info/entry_points.txt,sha256=c2eftt6MpJjyp0OFv1OmO9nUYSDemt9fGq_RDdvpGLw,55
79
+ karrio_server-2025.5rc33.dist-info/top_level.txt,sha256=D1D7x8R3cTfjF_15mfiO7wCQ5QMtuM4x8GaPr7z5i78,12
80
+ karrio_server-2025.5rc33.dist-info/RECORD,,