memorysync 1.1.0__tar.gz → 1.1.1__tar.gz
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.
- {memorysync-1.1.0 → memorysync-1.1.1}/PKG-INFO +1 -1
- {memorysync-1.1.0 → memorysync-1.1.1}/pyproject.toml +1 -1
- memorysync-1.1.1/src/memorysync/_version.py +1 -0
- {memorysync-1.1.0 → memorysync-1.1.1}/src/memorysync/control_plane.py +61 -42
- memorysync-1.1.0/src/memorysync/_version.py +0 -1
- {memorysync-1.1.0 → memorysync-1.1.1}/.gitignore +0 -0
- {memorysync-1.1.0 → memorysync-1.1.1}/LICENSE +0 -0
- {memorysync-1.1.0 → memorysync-1.1.1}/README.md +0 -0
- {memorysync-1.1.0 → memorysync-1.1.1}/src/memorysync/__init__.py +0 -0
- {memorysync-1.1.0 → memorysync-1.1.1}/src/memorysync/client.py +0 -0
- {memorysync-1.1.0 → memorysync-1.1.1}/src/memorysync/control_plane_types.py +0 -0
- {memorysync-1.1.0 → memorysync-1.1.1}/src/memorysync/errors.py +0 -0
- {memorysync-1.1.0 → memorysync-1.1.1}/src/memorysync/types.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.1.1"
|
|
@@ -60,14 +60,45 @@ def _snake_key(key: str) -> str:
|
|
|
60
60
|
return re.sub(r"(?<!^)(?=[A-Z])", "_", key).lower()
|
|
61
61
|
|
|
62
62
|
|
|
63
|
+
_OPAQUE_RESPONSE_KEYS = {"payload", "metadata", "geo", "configuration"}
|
|
64
|
+
|
|
65
|
+
|
|
63
66
|
def _snake(value: Any) -> Any:
|
|
64
67
|
if isinstance(value, dict):
|
|
65
|
-
|
|
68
|
+
normalized: Dict[str, Any] = {}
|
|
69
|
+
for key, item in value.items():
|
|
70
|
+
snake_key = _snake_key(str(key))
|
|
71
|
+
normalized[snake_key] = item if snake_key in _OPAQUE_RESPONSE_KEYS else _snake(item)
|
|
72
|
+
return normalized
|
|
66
73
|
if isinstance(value, list):
|
|
67
74
|
return [_snake(item) for item in value]
|
|
68
75
|
return value
|
|
69
76
|
|
|
70
77
|
|
|
78
|
+
def _project_override(value: Optional[str]) -> object:
|
|
79
|
+
if value is None:
|
|
80
|
+
return _UNSET
|
|
81
|
+
return cast(str, _project(value))
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _webhook_url(value: str) -> None:
|
|
85
|
+
_required_text(value, "url")
|
|
86
|
+
parsed = urlparse(value)
|
|
87
|
+
if parsed.scheme not in ("http", "https") or not parsed.netloc:
|
|
88
|
+
raise ValidationError("url must be an absolute HTTP or HTTPS URL")
|
|
89
|
+
if parsed.username or parsed.password:
|
|
90
|
+
raise ValidationError("url must not contain credentials")
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _string_sequence(values: Sequence[str], name: str) -> None:
|
|
94
|
+
if (
|
|
95
|
+
isinstance(values, (str, bytes))
|
|
96
|
+
or not values
|
|
97
|
+
or any(not isinstance(value, str) or not value.strip() for value in values)
|
|
98
|
+
):
|
|
99
|
+
raise ValidationError(f"{name} must contain at least one non-empty string")
|
|
100
|
+
|
|
101
|
+
|
|
71
102
|
def _detail(body: Any) -> Optional[str]:
|
|
72
103
|
if not isinstance(body, dict):
|
|
73
104
|
return None
|
|
@@ -156,7 +187,7 @@ class _ControlPlaneBase:
|
|
|
156
187
|
raw: Any = response.json()
|
|
157
188
|
except ValueError:
|
|
158
189
|
raw = response.text or None
|
|
159
|
-
if response.status_code
|
|
190
|
+
if not 200 <= response.status_code < 300:
|
|
160
191
|
_raise_response(response, raw)
|
|
161
192
|
return _snake(raw)
|
|
162
193
|
|
|
@@ -165,12 +196,8 @@ def _validate_webhook(name: str, url: str, events: Sequence[str]) -> None:
|
|
|
165
196
|
_required_text(name, "name")
|
|
166
197
|
if len(name) > 128:
|
|
167
198
|
raise ValidationError("name may contain at most 128 characters")
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
if parsed.scheme not in ("http", "https") or not parsed.netloc:
|
|
171
|
-
raise ValidationError("url must be an absolute HTTP or HTTPS URL")
|
|
172
|
-
if not events or any(not isinstance(event, str) or not event.strip() for event in events):
|
|
173
|
-
raise ValidationError("events must contain at least one non-empty string")
|
|
199
|
+
_webhook_url(url)
|
|
200
|
+
_string_sequence(events, "events")
|
|
174
201
|
|
|
175
202
|
|
|
176
203
|
class ControlPlaneClient(_ControlPlaneBase):
|
|
@@ -218,11 +245,11 @@ class ControlPlaneClient(_ControlPlaneBase):
|
|
|
218
245
|
raise ValidationError("key_ids must contain between 1 and 100 entries")
|
|
219
246
|
for key_id in ids:
|
|
220
247
|
_positive_id(key_id, "key_id")
|
|
221
|
-
raw = self._request("POST", "/org/api-keys/bulk-revoke", json={"key_ids": ids}, project_id=project_id
|
|
248
|
+
raw = self._request("POST", "/org/api-keys/bulk-revoke", json={"key_ids": ids}, project_id=_project_override(project_id))
|
|
222
249
|
return cast(BulkRevokeResponse, raw)
|
|
223
250
|
|
|
224
251
|
def test_api_key(self, key_id: int, *, project_id: Optional[str] = None) -> ApiKeyTestResponse:
|
|
225
|
-
raw = self._request("POST", f"/org/api-keys/{_positive_id(key_id, 'key_id')}/test", project_id=project_id
|
|
252
|
+
raw = self._request("POST", f"/org/api-keys/{_positive_id(key_id, 'key_id')}/test", project_id=_project_override(project_id))
|
|
226
253
|
return cast(ApiKeyTestResponse, raw)
|
|
227
254
|
|
|
228
255
|
def login(self, email: str, password: str) -> LoginResponse:
|
|
@@ -322,14 +349,13 @@ class ControlPlaneClient(_ControlPlaneBase):
|
|
|
322
349
|
_validate_webhook(name, url, events)
|
|
323
350
|
if description is not None and len(description) > 500:
|
|
324
351
|
raise ValidationError("description may contain at most 500 characters")
|
|
325
|
-
selected = project_id or self._project_id
|
|
326
352
|
data = _body(name=name, url=url, events=list(events), description=description,
|
|
327
353
|
retry_config=retry_config, signature_config=signature_config,
|
|
328
354
|
project_id=project_id)
|
|
329
|
-
return cast(Webhook, self._request("POST", "/org/webhooks", json=data, project_id=
|
|
355
|
+
return cast(Webhook, self._request("POST", "/org/webhooks", json=data, project_id=_project_override(project_id)))
|
|
330
356
|
|
|
331
357
|
def list_webhooks(self, *, project_id: Optional[str] = None) -> WebhooksResponse:
|
|
332
|
-
return cast(WebhooksResponse, self._request("GET", "/org/webhooks", project_id=project_id
|
|
358
|
+
return cast(WebhooksResponse, self._request("GET", "/org/webhooks", project_id=_project_override(project_id)))
|
|
333
359
|
|
|
334
360
|
|
|
335
361
|
def update_webhook(
|
|
@@ -345,24 +371,22 @@ class ControlPlaneClient(_ControlPlaneBase):
|
|
|
345
371
|
if len(name) > 128:
|
|
346
372
|
raise ValidationError("name may contain at most 128 characters")
|
|
347
373
|
if url is not None:
|
|
348
|
-
|
|
349
|
-
if parsed.scheme not in ("http", "https") or not parsed.netloc:
|
|
350
|
-
raise ValidationError("url must be an absolute HTTP or HTTPS URL")
|
|
374
|
+
_webhook_url(url)
|
|
351
375
|
if description is not None and len(description) > 500:
|
|
352
376
|
raise ValidationError("description may contain at most 500 characters")
|
|
353
|
-
if events is not None
|
|
354
|
-
|
|
377
|
+
if events is not None:
|
|
378
|
+
_string_sequence(events, "events")
|
|
355
379
|
data = _body(name=name, url=url, description=description,
|
|
356
380
|
events=list(events) if events is not None else None,
|
|
357
381
|
retry_config=retry_config, signature_config=signature_config)
|
|
358
382
|
if not data:
|
|
359
383
|
raise ValidationError("update_webhook requires at least one editable field")
|
|
360
384
|
path = f"/org/webhooks/{_positive_id(endpoint_id, 'endpoint_id')}"
|
|
361
|
-
return cast(Webhook, self._request("PATCH", path, json=data, project_id=project_id
|
|
385
|
+
return cast(Webhook, self._request("PATCH", path, json=data, project_id=_project_override(project_id)))
|
|
362
386
|
|
|
363
387
|
def delete_webhook(self, endpoint_id: int, *, project_id: Optional[str] = None) -> None:
|
|
364
388
|
path = f"/org/webhooks/{_positive_id(endpoint_id, 'endpoint_id')}"
|
|
365
|
-
self._request("DELETE", path, project_id=project_id
|
|
389
|
+
self._request("DELETE", path, project_id=_project_override(project_id))
|
|
366
390
|
|
|
367
391
|
def test_webhook(
|
|
368
392
|
self, endpoint_id: int, *, event_type: str = "memory.created",
|
|
@@ -370,7 +394,7 @@ class ControlPlaneClient(_ControlPlaneBase):
|
|
|
370
394
|
) -> WebhookTestResponse:
|
|
371
395
|
_required_text(event_type, "event_type")
|
|
372
396
|
path = f"/org/webhooks/{_positive_id(endpoint_id, 'endpoint_id')}/test"
|
|
373
|
-
return cast(WebhookTestResponse, self._request("POST", path, json={"event_type": event_type}, project_id=project_id
|
|
397
|
+
return cast(WebhookTestResponse, self._request("POST", path, json={"event_type": event_type}, project_id=_project_override(project_id)))
|
|
374
398
|
|
|
375
399
|
def replay_webhook_deliveries(
|
|
376
400
|
self, endpoint_id: int, *, since_minutes: int = 60,
|
|
@@ -379,11 +403,10 @@ class ControlPlaneClient(_ControlPlaneBase):
|
|
|
379
403
|
) -> WebhookReplayResponse:
|
|
380
404
|
_bounded(since_minutes, "since_minutes", 1, 10080)
|
|
381
405
|
_bounded(limit, "limit", 1, 1000)
|
|
382
|
-
|
|
383
|
-
raise ValidationError("statuses must contain at least one non-empty string")
|
|
406
|
+
_string_sequence(statuses, "statuses")
|
|
384
407
|
path = f"/org/webhooks/{_positive_id(endpoint_id, 'endpoint_id')}/replay"
|
|
385
408
|
data = {"since_minutes": since_minutes, "statuses": list(statuses), "limit": limit}
|
|
386
|
-
return cast(WebhookReplayResponse, self._request("POST", path, json=data, project_id=project_id
|
|
409
|
+
return cast(WebhookReplayResponse, self._request("POST", path, json=data, project_id=_project_override(project_id)))
|
|
387
410
|
|
|
388
411
|
def list_webhook_deliveries(
|
|
389
412
|
self, endpoint_id: int, *, page: int = 1, page_size: int = 25,
|
|
@@ -395,7 +418,7 @@ class ControlPlaneClient(_ControlPlaneBase):
|
|
|
395
418
|
_required_text(status, "status")
|
|
396
419
|
path = f"/org/webhooks/{_positive_id(endpoint_id, 'endpoint_id')}/deliveries"
|
|
397
420
|
params = _body(page=page, page_size=page_size, status_filter=status)
|
|
398
|
-
return cast(WebhookDeliveriesResponse, self._request("GET", path, params=params, project_id=project_id
|
|
421
|
+
return cast(WebhookDeliveriesResponse, self._request("GET", path, params=params, project_id=_project_override(project_id)))
|
|
399
422
|
|
|
400
423
|
|
|
401
424
|
class AsyncControlPlaneClient(_ControlPlaneBase):
|
|
@@ -441,11 +464,11 @@ class AsyncControlPlaneClient(_ControlPlaneBase):
|
|
|
441
464
|
raise ValidationError("key_ids must contain between 1 and 100 entries")
|
|
442
465
|
for key_id in ids:
|
|
443
466
|
_positive_id(key_id, "key_id")
|
|
444
|
-
raw = await self._request("POST", "/org/api-keys/bulk-revoke", json={"key_ids": ids}, project_id=project_id
|
|
467
|
+
raw = await self._request("POST", "/org/api-keys/bulk-revoke", json={"key_ids": ids}, project_id=_project_override(project_id))
|
|
445
468
|
return cast(BulkRevokeResponse, raw)
|
|
446
469
|
|
|
447
470
|
async def test_api_key(self, key_id: int, *, project_id: Optional[str] = None) -> ApiKeyTestResponse:
|
|
448
|
-
raw = await self._request("POST", f"/org/api-keys/{_positive_id(key_id, 'key_id')}/test", project_id=project_id
|
|
471
|
+
raw = await self._request("POST", f"/org/api-keys/{_positive_id(key_id, 'key_id')}/test", project_id=_project_override(project_id))
|
|
449
472
|
return cast(ApiKeyTestResponse, raw)
|
|
450
473
|
|
|
451
474
|
async def login(self, email: str, password: str) -> LoginResponse:
|
|
@@ -548,15 +571,14 @@ class AsyncControlPlaneClient(_ControlPlaneBase):
|
|
|
548
571
|
_validate_webhook(name, url, events)
|
|
549
572
|
if description is not None and len(description) > 500:
|
|
550
573
|
raise ValidationError("description may contain at most 500 characters")
|
|
551
|
-
selected = project_id or self._project_id
|
|
552
574
|
data = _body(name=name, url=url, events=list(events), description=description,
|
|
553
575
|
retry_config=retry_config, signature_config=signature_config,
|
|
554
576
|
project_id=project_id)
|
|
555
|
-
raw = await self._request("POST", "/org/webhooks", json=data, project_id=
|
|
577
|
+
raw = await self._request("POST", "/org/webhooks", json=data, project_id=_project_override(project_id))
|
|
556
578
|
return cast(Webhook, raw)
|
|
557
579
|
|
|
558
580
|
async def list_webhooks(self, *, project_id: Optional[str] = None) -> WebhooksResponse:
|
|
559
|
-
return cast(WebhooksResponse, await self._request("GET", "/org/webhooks", project_id=project_id
|
|
581
|
+
return cast(WebhooksResponse, await self._request("GET", "/org/webhooks", project_id=_project_override(project_id)))
|
|
560
582
|
|
|
561
583
|
|
|
562
584
|
async def update_webhook(
|
|
@@ -572,25 +594,23 @@ class AsyncControlPlaneClient(_ControlPlaneBase):
|
|
|
572
594
|
if len(name) > 128:
|
|
573
595
|
raise ValidationError("name may contain at most 128 characters")
|
|
574
596
|
if url is not None:
|
|
575
|
-
|
|
576
|
-
if parsed.scheme not in ("http", "https") or not parsed.netloc:
|
|
577
|
-
raise ValidationError("url must be an absolute HTTP or HTTPS URL")
|
|
597
|
+
_webhook_url(url)
|
|
578
598
|
if description is not None and len(description) > 500:
|
|
579
599
|
raise ValidationError("description may contain at most 500 characters")
|
|
580
|
-
if events is not None
|
|
581
|
-
|
|
600
|
+
if events is not None:
|
|
601
|
+
_string_sequence(events, "events")
|
|
582
602
|
data = _body(name=name, url=url, description=description,
|
|
583
603
|
events=list(events) if events is not None else None,
|
|
584
604
|
retry_config=retry_config, signature_config=signature_config)
|
|
585
605
|
if not data:
|
|
586
606
|
raise ValidationError("update_webhook requires at least one editable field")
|
|
587
607
|
path = f"/org/webhooks/{_positive_id(endpoint_id, 'endpoint_id')}"
|
|
588
|
-
raw = await self._request("PATCH", path, json=data, project_id=project_id
|
|
608
|
+
raw = await self._request("PATCH", path, json=data, project_id=_project_override(project_id))
|
|
589
609
|
return cast(Webhook, raw)
|
|
590
610
|
|
|
591
611
|
async def delete_webhook(self, endpoint_id: int, *, project_id: Optional[str] = None) -> None:
|
|
592
612
|
path = f"/org/webhooks/{_positive_id(endpoint_id, 'endpoint_id')}"
|
|
593
|
-
await self._request("DELETE", path, project_id=project_id
|
|
613
|
+
await self._request("DELETE", path, project_id=_project_override(project_id))
|
|
594
614
|
|
|
595
615
|
async def test_webhook(
|
|
596
616
|
self, endpoint_id: int, *, event_type: str = "memory.created",
|
|
@@ -598,7 +618,7 @@ class AsyncControlPlaneClient(_ControlPlaneBase):
|
|
|
598
618
|
) -> WebhookTestResponse:
|
|
599
619
|
_required_text(event_type, "event_type")
|
|
600
620
|
path = f"/org/webhooks/{_positive_id(endpoint_id, 'endpoint_id')}/test"
|
|
601
|
-
raw = await self._request("POST", path, json={"event_type": event_type}, project_id=project_id
|
|
621
|
+
raw = await self._request("POST", path, json={"event_type": event_type}, project_id=_project_override(project_id))
|
|
602
622
|
return cast(WebhookTestResponse, raw)
|
|
603
623
|
|
|
604
624
|
async def replay_webhook_deliveries(
|
|
@@ -608,11 +628,10 @@ class AsyncControlPlaneClient(_ControlPlaneBase):
|
|
|
608
628
|
) -> WebhookReplayResponse:
|
|
609
629
|
_bounded(since_minutes, "since_minutes", 1, 10080)
|
|
610
630
|
_bounded(limit, "limit", 1, 1000)
|
|
611
|
-
|
|
612
|
-
raise ValidationError("statuses must contain at least one non-empty string")
|
|
631
|
+
_string_sequence(statuses, "statuses")
|
|
613
632
|
path = f"/org/webhooks/{_positive_id(endpoint_id, 'endpoint_id')}/replay"
|
|
614
633
|
data = {"since_minutes": since_minutes, "statuses": list(statuses), "limit": limit}
|
|
615
|
-
raw = await self._request("POST", path, json=data, project_id=project_id
|
|
634
|
+
raw = await self._request("POST", path, json=data, project_id=_project_override(project_id))
|
|
616
635
|
return cast(WebhookReplayResponse, raw)
|
|
617
636
|
|
|
618
637
|
async def list_webhook_deliveries(
|
|
@@ -625,5 +644,5 @@ class AsyncControlPlaneClient(_ControlPlaneBase):
|
|
|
625
644
|
_required_text(status, "status")
|
|
626
645
|
path = f"/org/webhooks/{_positive_id(endpoint_id, 'endpoint_id')}/deliveries"
|
|
627
646
|
params = _body(page=page, page_size=page_size, status_filter=status)
|
|
628
|
-
raw = await self._request("GET", path, params=params, project_id=project_id
|
|
647
|
+
raw = await self._request("GET", path, params=params, project_id=_project_override(project_id))
|
|
629
648
|
return cast(WebhookDeliveriesResponse, raw)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.1.0"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|