nornweave 0.1.2__py3-none-any.whl → 0.1.4__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.
@@ -13,9 +13,11 @@ from nornweave.core.config import Settings, get_settings
13
13
  from nornweave.core.interfaces import (
14
14
  StorageInterface, # noqa: TC001 - needed at runtime for FastAPI
15
15
  )
16
+ from nornweave.core.storage import AttachmentMetadata, create_attachment_storage
16
17
  from nornweave.models.message import Message, MessageDirection
17
18
  from nornweave.models.thread import Thread
18
19
  from nornweave.verdandi.parser import html_to_markdown
20
+ from nornweave.verdandi.summarize import generate_thread_summary
19
21
  from nornweave.yggdrasil.dependencies import get_storage
20
22
 
21
23
  router = APIRouter()
@@ -112,7 +114,7 @@ async def resend_webhook(
112
114
 
113
115
  # Route based on event type
114
116
  if event_type == "email.received":
115
- return await _handle_inbound_email(adapter, payload, storage)
117
+ return await _handle_inbound_email(adapter, payload, storage, settings)
116
118
  elif event_type in DELIVERY_EVENT_TYPES:
117
119
  return _handle_delivery_event(event_type, payload)
118
120
  else:
@@ -124,10 +126,12 @@ async def _handle_inbound_email(
124
126
  adapter: ResendAdapter,
125
127
  payload: dict[str, Any],
126
128
  storage: StorageInterface,
129
+ settings: Settings,
127
130
  ) -> dict[str, str]:
128
131
  """Handle email.received event.
129
132
 
130
133
  Fetches full email content from Resend API and stores the message.
134
+ Stores attachments using the configured storage backend.
131
135
  """
132
136
  data = payload.get("data", {})
133
137
  email_id = data.get("email_id", "unknown")
@@ -187,6 +191,22 @@ async def _handle_inbound_email(
187
191
 
188
192
  logger.info("Found inbox %s for recipient %s", inbox.id, inbound.to_address)
189
193
 
194
+ # Check for duplicate webhook delivery (idempotency)
195
+ if inbound.message_id:
196
+ existing_msg = await storage.get_message_by_provider_id(inbox.id, inbound.message_id)
197
+ if existing_msg:
198
+ logger.info(
199
+ "Duplicate webhook detected: message %s already exists for provider_message_id %s",
200
+ existing_msg.id,
201
+ inbound.message_id,
202
+ )
203
+ return {
204
+ "status": "duplicate",
205
+ "message_id": existing_msg.id,
206
+ "thread_id": existing_msg.thread_id,
207
+ "email_id": email_id,
208
+ }
209
+
190
210
  # Try to find existing thread by Message-ID references (for replies)
191
211
  thread_id: str | None = None
192
212
 
@@ -256,21 +276,57 @@ async def _handle_inbound_email(
256
276
  created_message = await storage.create_message(message)
257
277
  logger.info("Created message %s in thread %s", created_message.id, thread_id)
258
278
 
259
- # Store attachments if present
260
- for att in inbound.attachments:
261
- if att.content and att.size_bytes > 0:
262
- try:
263
- await storage.create_attachment(
264
- message_id=created_message.id,
265
- filename=att.filename,
266
- content_type=att.content_type,
267
- size_bytes=att.size_bytes,
268
- disposition=att.disposition.value,
269
- content_id=att.content_id,
270
- )
271
- logger.debug("Created attachment record for %s", att.filename)
272
- except (ValueError, RuntimeError) as e:
273
- logger.warning("Failed to create attachment record: %s", e)
279
+ # Store attachments if present - using the configured storage backend
280
+ if inbound.attachments:
281
+ # Create storage backend for attachments
282
+ storage_backend = create_attachment_storage(settings)
283
+
284
+ for att in inbound.attachments:
285
+ if att.content and att.size_bytes > 0:
286
+ try:
287
+ # Generate attachment ID
288
+ attachment_id = str(uuid.uuid4())
289
+
290
+ # Create metadata for storage backend
291
+ metadata = AttachmentMetadata(
292
+ attachment_id=attachment_id,
293
+ message_id=created_message.id,
294
+ filename=att.filename,
295
+ content_type=att.content_type,
296
+ content_disposition=att.disposition.value,
297
+ content_id=att.content_id,
298
+ )
299
+
300
+ # Store in configured backend (local, s3, gcs, or database)
301
+ storage_result = await storage_backend.store(
302
+ attachment_id=attachment_id,
303
+ content=att.content,
304
+ metadata=metadata,
305
+ )
306
+
307
+ # Create database record with storage info
308
+ await storage.create_attachment(
309
+ message_id=created_message.id,
310
+ filename=att.filename,
311
+ content_type=att.content_type,
312
+ size_bytes=storage_result.size_bytes,
313
+ disposition=att.disposition.value,
314
+ content_id=att.content_id,
315
+ storage_path=storage_result.storage_key,
316
+ storage_backend=storage_result.backend,
317
+ content_hash=storage_result.content_hash,
318
+ # For database backend, also store the content
319
+ content=att.content if storage_result.backend == "database" else None,
320
+ )
321
+ logger.info(
322
+ "Stored attachment %s (%s, %d bytes) via %s backend",
323
+ att.filename,
324
+ att.content_type,
325
+ storage_result.size_bytes,
326
+ storage_result.backend,
327
+ )
328
+ except (ValueError, RuntimeError) as e:
329
+ logger.warning("Failed to store attachment %s: %s", att.filename, e)
274
330
 
275
331
  # Update thread's last_message_at
276
332
  if thread:
@@ -278,6 +334,10 @@ async def _handle_inbound_email(
278
334
  thread.received_timestamp = created_message.created_at
279
335
  await storage.update_thread(thread)
280
336
 
337
+ # Fire-and-forget thread summarization
338
+ if thread_id:
339
+ await generate_thread_summary(storage, thread_id)
340
+
281
341
  result = {
282
342
  "status": "received",
283
343
  "message_id": created_message.id,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nornweave
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: Open-source, self-hosted Inbox-as-a-Service API for AI Agents
5
5
  Project-URL: Homepage, https://github.com/DataCovey/nornweave
6
6
  Project-URL: Documentation, https://nornweave.datacovey.com/docs/
@@ -38,8 +38,12 @@ Requires-Dist: sqlalchemy[asyncio]>=2.0.36
38
38
  Requires-Dist: svix>=1.24.0
39
39
  Requires-Dist: uvicorn[standard]>=0.32.0
40
40
  Provides-Extra: all
41
+ Requires-Dist: anthropic>=0.42.0; extra == 'all'
41
42
  Requires-Dist: asyncpg>=0.30.0; extra == 'all'
43
+ Requires-Dist: boto3>=1.35.0; extra == 'all'
42
44
  Requires-Dist: fastmcp>=2.0.0; extra == 'all'
45
+ Requires-Dist: google-cloud-storage>=2.18.0; extra == 'all'
46
+ Requires-Dist: google-genai>=1.0.0; extra == 'all'
43
47
  Requires-Dist: mcp>=1.0.0; extra == 'all'
44
48
  Requires-Dist: openai>=1.57.0; extra == 'all'
45
49
  Requires-Dist: pgvector>=0.3.6; extra == 'all'
@@ -47,6 +51,8 @@ Requires-Dist: psycopg2-binary>=2.9.0; extra == 'all'
47
51
  Requires-Dist: pypdf>=5.1.0; extra == 'all'
48
52
  Requires-Dist: python-magic>=0.4.27; extra == 'all'
49
53
  Requires-Dist: redis>=5.2.0; extra == 'all'
54
+ Provides-Extra: anthropic
55
+ Requires-Dist: anthropic>=0.42.0; extra == 'anthropic'
50
56
  Provides-Extra: attachments
51
57
  Requires-Dist: pypdf>=5.1.0; extra == 'attachments'
52
58
  Requires-Dist: python-magic>=0.4.27; extra == 'attachments'
@@ -59,14 +65,26 @@ Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
59
65
  Requires-Dist: pytest-cov>=6.0.0; extra == 'dev'
60
66
  Requires-Dist: pytest>=8.3.0; extra == 'dev'
61
67
  Requires-Dist: ruff>=0.8.0; extra == 'dev'
68
+ Provides-Extra: gcs
69
+ Requires-Dist: google-cloud-storage>=2.18.0; extra == 'gcs'
70
+ Provides-Extra: gemini
71
+ Requires-Dist: google-genai>=1.0.0; extra == 'gemini'
72
+ Provides-Extra: llm
73
+ Requires-Dist: anthropic>=0.42.0; extra == 'llm'
74
+ Requires-Dist: google-genai>=1.0.0; extra == 'llm'
75
+ Requires-Dist: openai>=1.57.0; extra == 'llm'
62
76
  Provides-Extra: mcp
63
77
  Requires-Dist: fastmcp>=2.0.0; extra == 'mcp'
64
78
  Requires-Dist: mcp>=1.0.0; extra == 'mcp'
79
+ Provides-Extra: openai
80
+ Requires-Dist: openai>=1.57.0; extra == 'openai'
65
81
  Provides-Extra: postgres
66
82
  Requires-Dist: asyncpg>=0.30.0; extra == 'postgres'
67
83
  Requires-Dist: psycopg2-binary>=2.9.0; extra == 'postgres'
68
84
  Provides-Extra: ratelimit
69
85
  Requires-Dist: redis>=5.2.0; extra == 'ratelimit'
86
+ Provides-Extra: s3
87
+ Requires-Dist: boto3>=1.35.0; extra == 's3'
70
88
  Provides-Extra: search
71
89
  Requires-Dist: openai>=1.57.0; extra == 'search'
72
90
  Requires-Dist: pgvector>=0.3.6; extra == 'search'
@@ -3,28 +3,28 @@ nornweave/cli.py,sha256=zFrIjmruvh1YTthYbUsMfkjMb0Tk9cmUR-vYQ9naAK0,4231
3
3
  nornweave/adapters/__init__.py,sha256=eBMqa9HmAuMZreZ0cca-xkxCS0yes247NQ8363pAkkc,38
4
4
  nornweave/adapters/base.py,sha256=Dq68F1IZsUa87lY0J2goEh1Vog14w1XxmBzWPe6XOis,164
5
5
  nornweave/adapters/mailgun.py,sha256=3YdKI7l-bdaF3HF_kJuGmKQQiraFUHTbmq4HL44W_fw,6756
6
- nornweave/adapters/resend.py,sha256=ngDnf4SUHLAkPKLZzi1ANA4XJ6fsApMUnrS6aFVRC7s,17878
6
+ nornweave/adapters/resend.py,sha256=7GCN7ShXjPOO52c_qrr71ecHtpdfqRe5Yyur2-_rh18,19942
7
7
  nornweave/adapters/sendgrid.py,sha256=dF_hmLAkEh1VQ8_O5OhcfCDhMAI-pEDF441im4DC9P4,17855
8
8
  nornweave/adapters/ses.py,sha256=-6_ej9tILPkLjO5ujKEVQF8vHI0WhsiGY345FU7PN74,29683
9
9
  nornweave/core/__init__.py,sha256=q-EsoqN07mZL67qbDEyBVxpAitvMVxiyVwkSxGZx868,533
10
- nornweave/core/config.py,sha256=TaZYTDqywcenpzQCFvWtouVQB5fb-4SLbDA6cysYjNo,6214
10
+ nornweave/core/config.py,sha256=CutIB4UiL5RwUEhkTYpTzc0bEs9MF5s2BTQJurJKb-M,8305
11
11
  nornweave/core/exceptions.py,sha256=Du1NKDpNxOLb75XUavI_Cc7IDOU3WdPnacqwG_8h14U,425
12
- nornweave/core/interfaces.py,sha256=GQUIJ_ANBT5SW1DDHFz4NXch8OY3BMpTB0NXqXpskSA,12352
12
+ nornweave/core/interfaces.py,sha256=IMmGAuU7-J3Zs44lUx3GveVBitPi2uywKGucHCTud0o,14258
13
13
  nornweave/core/storage.py,sha256=MGxTyudFAYmPl7O2O_X68x3mkGu_lnUixRBdKYqiv0E,5234
14
14
  nornweave/core/utils.py,sha256=FTiXmwf7iWIWSyo6DMUeu4MFfvGW-FnFNnqWrkiRlrs,696
15
15
  nornweave/huginn/__init__.py,sha256=4mC_VL1ERiSoZXHpWD26efzqKwN20ED4GTHljJ8AGbs,338
16
- nornweave/huginn/client.py,sha256=OZnWfiPpagQ913vs1FvPkkOP2b_DtxYXTILEFlVCxoo,9191
16
+ nornweave/huginn/client.py,sha256=EjWSRQQMx8PM1q2tWp8qgfi9jvP6DFX9lOo5C2l-vzc,13688
17
17
  nornweave/huginn/config.py,sha256=G1VE9bFtTaJAf-iipqxGkYnviq_yeHKOHySyc_w5tt4,1413
18
- nornweave/huginn/resources.py,sha256=-UwMD9faNuhF7N68BU03ahn3AA5ChV7liPbNsxjq_bE,4960
19
- nornweave/huginn/server.py,sha256=5lKiAQHMG6UbtBg3u-1LtV7DIaNlwK24nBaiFyD55rU,6278
18
+ nornweave/huginn/resources.py,sha256=WsBntF9L2uDHwgL98ij0AjEkQK7NFf6XEosCL3ZSshA,5217
19
+ nornweave/huginn/server.py,sha256=8wbibOjuclQNAycRIOJJRnH77LobVkjnxlDPWFyOwVc,10084
20
20
  nornweave/models/__init__.py,sha256=qHHVmAIstLJFQzZlYjp4k-KDz6Fs_YqvOl9BWOaejYY,2616
21
21
  nornweave/models/attachment.py,sha256=TeeN3Fe42bo0DAyqBmOgAVOesVytKFJN6i45lz7C-7I,4021
22
22
  nornweave/models/event.py,sha256=JmndUxsEJvoqMyBYJMNLh8ZDaIORcyDCHzo5vYNzjig,6772
23
23
  nornweave/models/inbox.py,sha256=Vwpr2JZKep6BcBpWZNR9Ne_rHnIOvlOv97_GgyhV6U8,905
24
24
  nornweave/models/message.py,sha256=m5rUc7TeKwLU7I7UZbCC2Wuk0u5yE95o943eL-SIPDI,10676
25
- nornweave/models/thread.py,sha256=uu2ngc17FaTsXaKgJOymuQ7evJ_kvTR47nTt5wQhSrI,7135
25
+ nornweave/models/thread.py,sha256=ke_0b4_NHzYEMe7dHvNHyh-gyWchh0XkOyTYKv4L4qk,7299
26
26
  nornweave/muninn/__init__.py,sha256=IoRWFRDDH8SesVsBbARQs1xGTQsqnQ-YDyTog8HnmyY,322
27
- nornweave/muninn/tools.py,sha256=qK36MECzPht3_ulvM95KlkLm1iVitl4qrmEmonnjUGE,6057
27
+ nornweave/muninn/tools.py,sha256=VysbtgBbJ4ensmMCqJiCGCginkdczUEiY_OZdUrnBqg,14870
28
28
  nornweave/search/__init__.py,sha256=qjj7B9j7oB3wKOtQa9qa8Z5XAAGVc1lMINFaxeP2ji0,33
29
29
  nornweave/search/embeddings.py,sha256=BoHKqNGzgIztQ_dzoIxMtw43xJU3p2ALrG6rXreAHeA,57
30
30
  nornweave/search/vector_store.py,sha256=xz2p0Tx7XIRIKEK-c3bE9Kv_II3XRbuWNjtWzfqTkrs,50
@@ -34,14 +34,14 @@ nornweave/skuld/scheduler.py,sha256=1PKSlfOCIEg6-J1Gy18eWkxHCrpV0UdL87foceVMUxE,
34
34
  nornweave/skuld/sender.py,sha256=TFANid5iUasXZeHNjYgBG0qeG7hrdhKH8qguUgQ1H6w,585
35
35
  nornweave/skuld/webhooks.py,sha256=i9FSTMyQfvGeNkFaaDwTfoBF1SnIlSMKjegBYuWvhq0,55
36
36
  nornweave/storage/__init__.py,sha256=grAAxi_YamDxYOghqVS4DI6LTtaVfxd8lwPWhYhPzWA,623
37
- nornweave/storage/database.py,sha256=OZN0OKzl4hbQVIrUcgsHlktGc3txAq5YkoxMtPMP5hQ,5289
37
+ nornweave/storage/database.py,sha256=_QLTVRgrfZbGvPq-CS8Y9snaeDVUi9Kc0m--yRZwWcI,5328
38
38
  nornweave/storage/gcs.py,sha256=tWIA6fbh-RTlIjP8XDQ5QHCXRXLrzpg7xv-F3Z1spWU,4471
39
39
  nornweave/storage/local.py,sha256=mWfAa7tJxC9BxM35o4HnF9kQ4VxUjIs9s0FwdR7IQcI,4698
40
40
  nornweave/storage/s3.py,sha256=5Fp9PO7lAPVD2kt1X6LtZ_7WJ5p11V4nfKRVx3amSUA,5126
41
41
  nornweave/urdr/__init__.py,sha256=l6_ktIdR38XprrJysxNgt8nPeGwkjKhto40AdmlVs5g,363
42
- nornweave/urdr/orm.py,sha256=_N4_e7usdUS25B5iUAbnG_zA5xiHLBmjHPt5n5rDZUo,20081
42
+ nornweave/urdr/orm.py,sha256=k48YvuJXAl5pdTwWZoTU1OBPjyMnQ7XUc9OcyhR7a3g,20725
43
43
  nornweave/urdr/adapters/__init__.py,sha256=PxF3WsKO4P1PxUtQ0IBRt4Ie_QVgUs8Yp7GBBJKdzeE,461
44
- nornweave/urdr/adapters/base.py,sha256=mhKoUnEhabz4h2Yx6mPwHs_-9bTljm2FJTmL9iea-s8,14527
44
+ nornweave/urdr/adapters/base.py,sha256=drQcVVE9yd4EKh4WzCcVPV6ont67EntdkjPKId0_Pmo,20736
45
45
  nornweave/urdr/adapters/postgres.py,sha256=2gk52Dz2Ah6nxUOC44ucL5PHT6xViIbbuhbyBOVI3S4,1502
46
46
  nornweave/urdr/adapters/sqlite.py,sha256=DopxiBZ-JMJrxxkzrjk3saYfkvcJwfXHbYNjpsn7rc4,1626
47
47
  nornweave/urdr/migrations/env.py,sha256=NbmCO-73mj5gsNdTNgkXx0IveS3BKJFcLDRqt09BJMw,2596
@@ -49,32 +49,40 @@ nornweave/urdr/migrations/script.py.mako,sha256=MEqL-2qATlST9TAOeYgscMn1uy6HUS9N
49
49
  nornweave/urdr/migrations/versions/.gitkeep,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
50
  nornweave/urdr/migrations/versions/20260131_0001_initial_schema.py,sha256=0QLxVEhDlEX-zMFd2XqYvwj-L78dzq8bkQOXYxaDqMw,6004
51
51
  nornweave/urdr/migrations/versions/20260131_0002_extended_schema.py,sha256=KaYoK5XjASYbhq8wxaA7D1dhw9xahLBI7-vjF6W8fFg,9502
52
+ nornweave/urdr/migrations/versions/20260205_0003_llm_thread_summary.py,sha256=z_cV2mfEkBWBRb1OpBQID3F5mxtETXHl7tiL_IkP7ME,1658
52
53
  nornweave/verdandi/__init__.py,sha256=TegCxwFoPZgwXZxzilXi2n9aA9huF0Vnta3tahvdVvw,1033
53
54
  nornweave/verdandi/attachments.py,sha256=oYytlfktR0WOzshx3xxmJrr3vnIVd5UeKjSGHcfvAxA,12659
54
55
  nornweave/verdandi/content.py,sha256=C_S7IFJ_9WMcLlKmz5uiQ3x0DlKS8pVOsumvYZcMNME,11644
55
56
  nornweave/verdandi/headers.py,sha256=Jb_3OGWa0oZj15qstl2qpLjW1qUPCS7dlWJ5Zw8gk0Q,10706
56
- nornweave/verdandi/parser.py,sha256=Kksn2yFPrPKhuj_SY3hYiLSI5hPWhixBeFwq8SA1nac,661
57
+ nornweave/verdandi/parser.py,sha256=TDWyzm2lUY6CCA4M5rKDJUnozFon4NArXgvnrjb31Wk,686
57
58
  nornweave/verdandi/sanitizer.py,sha256=aLDiuslCkuBDgAhPKDDTaHtG51MWIRAbjDEzpN1cNQo,296
59
+ nornweave/verdandi/summarize.py,sha256=hrxCcyxGe3l2z_ZaOQqPzct1Lg76vfep9XI5HvAd1Ys,7504
58
60
  nornweave/verdandi/threading.py,sha256=8XWVphAFDAPEMQZ-EzJPZiYcRhnkUuRwyb9-_oNdsmQ,10543
61
+ nornweave/verdandi/llm/__init__.py,sha256=JDtH2gQxWbLcs-y7FJZdtdUmbJDpYKCOhWMEe2ZDXEc,1680
62
+ nornweave/verdandi/llm/anthropic.py,sha256=9r8B5NhXgGyeSgQ94U6jfwfy6VJGsikrNYc-AI2U6vM,1936
63
+ nornweave/verdandi/llm/base.py,sha256=dqXwPP6sfcByfJjeeoKyGkMelX-mK3H7am1k4Kd7iOs,827
64
+ nornweave/verdandi/llm/gemini.py,sha256=NOJZ1hn5b9LXDurHtutDYULJrAbtegnIOUnZ6VO3CA0,2758
65
+ nornweave/verdandi/llm/openai.py,sha256=r7IGf2O-zRmkNzZUi6htHwTjCro7OeFwlSZAyoMAviA,1949
59
66
  nornweave/yggdrasil/__init__.py,sha256=AmtQ0PBXOqLWnaEXN4c4it0JzsbhPR4ACdTgsTZ0_Ak,41
60
- nornweave/yggdrasil/app.py,sha256=w3m6EOtJTeQKh2uGSVqBF8VkI6XBbl_INcyRKxzumho,2596
61
- nornweave/yggdrasil/dependencies.py,sha256=qbdPtN57SvXvcskGi7MEt7ne-t6TJQXK6rps3FVmaM4,6426
67
+ nornweave/yggdrasil/app.py,sha256=UzWFTd2HlQ1AhN3wVosar7dUemI3PyFada82pXSaa0w,2688
68
+ nornweave/yggdrasil/dependencies.py,sha256=TgrJXYEdBPCNkVmwbvgm36_Tdvkvtpr2g4M2avz4Vxw,6579
62
69
  nornweave/yggdrasil/middleware/__init__.py,sha256=epGY0eVYG4p8CSN2HrDVr3D34E_Vj_ZhKhHtSvZfuBo,33
63
70
  nornweave/yggdrasil/middleware/auth.py,sha256=v-JDrb3jIicrjg_QchHeiYgfnpIIiM31SHGdioBFaEk,54
64
71
  nornweave/yggdrasil/middleware/logging.py,sha256=AxAWfVLorrR6OWRfNHm6RP3QgG0UhIOsNyYKkaKLWTw,56
65
72
  nornweave/yggdrasil/routes/__init__.py,sha256=B_IMQ-HRZVaz2X6OonhdX1ksEtIi2xOmtBA7Dsm3wlU,18
66
73
  nornweave/yggdrasil/routes/v1/__init__.py,sha256=DLf9PHY_O_gzj4lXg-Gq_Qh_i4b0DQ27z3_6S-FjyAw,26
74
+ nornweave/yggdrasil/routes/v1/attachments.py,sha256=JKh56GFXiHsnDM0S5GRZR4uCSwN1VgQOBCMwHufOWQQ,11052
67
75
  nornweave/yggdrasil/routes/v1/inboxes.py,sha256=8R8bmbwmM4V25iAhwKL7ZphRjqvJYN9KQhRq-3FiIH0,3506
68
- nornweave/yggdrasil/routes/v1/messages.py,sha256=YzzfxWNR72CDja5UFfWwu7orQjUKgARqHnvZAwJPq1w,6021
76
+ nornweave/yggdrasil/routes/v1/messages.py,sha256=E_TBatWen77bf4Xn4noUqcRfNqx_gU7t_hCeAEBKes4,12493
69
77
  nornweave/yggdrasil/routes/v1/search.py,sha256=5rMC99H8YNDK9gYzsg2gc_fLnWHiogXTTByXh05_0ek,2293
70
- nornweave/yggdrasil/routes/v1/threads.py,sha256=uIg7vxp8KK8QnBJwwwSuY69ioCCuci2hAnMuesnmtGw,4083
78
+ nornweave/yggdrasil/routes/v1/threads.py,sha256=N9PRhKsD7C-AeUAVKOj21URkn_4bFr8PRPR8HzbtXlo,4212
71
79
  nornweave/yggdrasil/routes/webhooks/__init__.py,sha256=Kt9atFe_bmd0784Ug7QDI04VnLcKJ4vEAynjYdVWWuM,47
72
- nornweave/yggdrasil/routes/webhooks/mailgun.py,sha256=G6c5Mr24uHyxft5U2wo7itHpkzTS1LqeWCez6tMnP0I,5050
73
- nornweave/yggdrasil/routes/webhooks/resend.py,sha256=OExdLbNN9hwbUDMG-YH_Lw5NhV-bfZ6TXE7yOISzQfw,12332
80
+ nornweave/yggdrasil/routes/webhooks/mailgun.py,sha256=ccxcp-_TrBkK05Lne4Sg5iZ-nvzNHs0a-GpzJV4qUt8,5213
81
+ nornweave/yggdrasil/routes/webhooks/resend.py,sha256=gaHbmCsfxkeeIK9xGCUcBwo3a80wHcmdsQfE3IgJGsY,15095
74
82
  nornweave/yggdrasil/routes/webhooks/sendgrid.py,sha256=ABcpjRTJ8QE2h9_vzhfXtCwOyL_UEVObrghWwQoPyvc,465
75
83
  nornweave/yggdrasil/routes/webhooks/ses.py,sha256=c0cUs_DLjHGTXW26Dp20xQ76-SKZ9uzLTRNQlp6G06M,472
76
- nornweave-0.1.2.dist-info/METADATA,sha256=Z1ysC3qqqm25c31zXCuy1ngflEpy-AHDrMVURPjNeO8,10353
77
- nornweave-0.1.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
78
- nornweave-0.1.2.dist-info/entry_points.txt,sha256=0FFL4MJSIBy8S2YJ5fUpAQbTyH5D5c30rEM6KTc93yk,112
79
- nornweave-0.1.2.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
80
- nornweave-0.1.2.dist-info/RECORD,,
84
+ nornweave-0.1.4.dist-info/METADATA,sha256=SyA_dLtgN2raDaQgpbZ7umriLrvP5wgRxVj7YhWgMeI,11097
85
+ nornweave-0.1.4.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
86
+ nornweave-0.1.4.dist-info/entry_points.txt,sha256=0FFL4MJSIBy8S2YJ5fUpAQbTyH5D5c30rEM6KTc93yk,112
87
+ nornweave-0.1.4.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
88
+ nornweave-0.1.4.dist-info/RECORD,,