samsara-api 0.0.3__py3-none-any.whl → 0.0.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.
- samsara/__init__.py +0 -2
- samsara/auth/__init__.py +3 -2
- samsara/auth/client.py +3 -93
- samsara/auth/raw_client.py +0 -115
- samsara/auth/{types → tokens}/__init__.py +2 -2
- samsara/auth/tokens/client.py +185 -0
- samsara/auth/tokens/raw_client.py +210 -0
- samsara/auth/tokens/types/__init__.py +7 -0
- samsara/auth/{types/get_token_response.py → tokens/types/create_tokens_response.py} +4 -2
- samsara/client.py +2 -2
- samsara/core/client_wrapper.py +2 -2
- samsara/utils/webhooks_helper.py +52 -0
- {samsara_api-0.0.3.dist-info → samsara_api-0.0.4.dist-info}/METADATA +18 -1
- {samsara_api-0.0.3.dist-info → samsara_api-0.0.4.dist-info}/RECORD +16 -12
- {samsara_api-0.0.3.dist-info → samsara_api-0.0.4.dist-info}/LICENSE +0 -0
- {samsara_api-0.0.3.dist-info → samsara_api-0.0.4.dist-info}/WHEEL +0 -0
samsara/__init__.py
CHANGED
|
@@ -2347,7 +2347,6 @@ from .attributes import (
|
|
|
2347
2347
|
UpdateAttributeRequestAttributeValueQuantity,
|
|
2348
2348
|
UpdateAttributeRequestEntityType,
|
|
2349
2349
|
)
|
|
2350
|
-
from .auth import GetTokenResponse
|
|
2351
2350
|
from .client import AsyncSamsara, Samsara
|
|
2352
2351
|
from .documents import DocumentsPostDocumentRequestBodyState
|
|
2353
2352
|
from .driver_vehicle_assignments import (
|
|
@@ -3351,7 +3350,6 @@ __all__ = [
|
|
|
3351
3350
|
"GetDriverTrailerAssignmentsResponseBodyResponseBody",
|
|
3352
3351
|
"GetMediaRetrievalObjectResponseBody",
|
|
3353
3352
|
"GetResponseWorkflowConfigurationObjectResponseBody",
|
|
3354
|
-
"GetTokenResponse",
|
|
3355
3353
|
"GetWorkflowIncidentResponseObjectResponseBody",
|
|
3356
3354
|
"GoaAddressTinyResponseResponseBody",
|
|
3357
3355
|
"GoaAttributeTinyRequestBody",
|
samsara/auth/__init__.py
CHANGED
samsara/auth/client.py
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
# This file was auto-generated by Fern from our API Definition.
|
|
2
2
|
|
|
3
|
-
import typing
|
|
4
|
-
|
|
5
3
|
from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
|
|
6
|
-
from ..core.request_options import RequestOptions
|
|
7
4
|
from .raw_client import AsyncRawAuthClient, RawAuthClient
|
|
8
|
-
from .
|
|
9
|
-
|
|
10
|
-
# this is used as the default value for optional parameters
|
|
11
|
-
OMIT = typing.cast(typing.Any, ...)
|
|
5
|
+
from .tokens.client import AsyncTokensClient, TokensClient
|
|
12
6
|
|
|
13
7
|
|
|
14
8
|
class AuthClient:
|
|
15
9
|
def __init__(self, *, client_wrapper: SyncClientWrapper):
|
|
16
10
|
self._raw_client = RawAuthClient(client_wrapper=client_wrapper)
|
|
11
|
+
self.tokens = TokensClient(client_wrapper=client_wrapper)
|
|
17
12
|
|
|
18
13
|
@property
|
|
19
14
|
def with_raw_response(self) -> RawAuthClient:
|
|
@@ -26,49 +21,11 @@ class AuthClient:
|
|
|
26
21
|
"""
|
|
27
22
|
return self._raw_client
|
|
28
23
|
|
|
29
|
-
def get_token(
|
|
30
|
-
self, *, client_id: str, client_secret: str, request_options: typing.Optional[RequestOptions] = None
|
|
31
|
-
) -> GetTokenResponse:
|
|
32
|
-
"""
|
|
33
|
-
Obtain an OAuth2 access token using client credentials
|
|
34
|
-
|
|
35
|
-
Parameters
|
|
36
|
-
----------
|
|
37
|
-
client_id : str
|
|
38
|
-
The client ID of the application
|
|
39
|
-
|
|
40
|
-
client_secret : str
|
|
41
|
-
The client secret of the application
|
|
42
|
-
|
|
43
|
-
request_options : typing.Optional[RequestOptions]
|
|
44
|
-
Request-specific configuration.
|
|
45
|
-
|
|
46
|
-
Returns
|
|
47
|
-
-------
|
|
48
|
-
GetTokenResponse
|
|
49
|
-
Successful response
|
|
50
|
-
|
|
51
|
-
Examples
|
|
52
|
-
--------
|
|
53
|
-
from samsara import Samsara
|
|
54
|
-
|
|
55
|
-
client = Samsara(
|
|
56
|
-
token="YOUR_TOKEN",
|
|
57
|
-
)
|
|
58
|
-
client.auth.get_token(
|
|
59
|
-
client_id="client_id",
|
|
60
|
-
client_secret="client_secret",
|
|
61
|
-
)
|
|
62
|
-
"""
|
|
63
|
-
_response = self._raw_client.get_token(
|
|
64
|
-
client_id=client_id, client_secret=client_secret, request_options=request_options
|
|
65
|
-
)
|
|
66
|
-
return _response.data
|
|
67
|
-
|
|
68
24
|
|
|
69
25
|
class AsyncAuthClient:
|
|
70
26
|
def __init__(self, *, client_wrapper: AsyncClientWrapper):
|
|
71
27
|
self._raw_client = AsyncRawAuthClient(client_wrapper=client_wrapper)
|
|
28
|
+
self.tokens = AsyncTokensClient(client_wrapper=client_wrapper)
|
|
72
29
|
|
|
73
30
|
@property
|
|
74
31
|
def with_raw_response(self) -> AsyncRawAuthClient:
|
|
@@ -80,50 +37,3 @@ class AsyncAuthClient:
|
|
|
80
37
|
AsyncRawAuthClient
|
|
81
38
|
"""
|
|
82
39
|
return self._raw_client
|
|
83
|
-
|
|
84
|
-
async def get_token(
|
|
85
|
-
self, *, client_id: str, client_secret: str, request_options: typing.Optional[RequestOptions] = None
|
|
86
|
-
) -> GetTokenResponse:
|
|
87
|
-
"""
|
|
88
|
-
Obtain an OAuth2 access token using client credentials
|
|
89
|
-
|
|
90
|
-
Parameters
|
|
91
|
-
----------
|
|
92
|
-
client_id : str
|
|
93
|
-
The client ID of the application
|
|
94
|
-
|
|
95
|
-
client_secret : str
|
|
96
|
-
The client secret of the application
|
|
97
|
-
|
|
98
|
-
request_options : typing.Optional[RequestOptions]
|
|
99
|
-
Request-specific configuration.
|
|
100
|
-
|
|
101
|
-
Returns
|
|
102
|
-
-------
|
|
103
|
-
GetTokenResponse
|
|
104
|
-
Successful response
|
|
105
|
-
|
|
106
|
-
Examples
|
|
107
|
-
--------
|
|
108
|
-
import asyncio
|
|
109
|
-
|
|
110
|
-
from samsara import AsyncSamsara
|
|
111
|
-
|
|
112
|
-
client = AsyncSamsara(
|
|
113
|
-
token="YOUR_TOKEN",
|
|
114
|
-
)
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
async def main() -> None:
|
|
118
|
-
await client.auth.get_token(
|
|
119
|
-
client_id="client_id",
|
|
120
|
-
client_secret="client_secret",
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
asyncio.run(main())
|
|
125
|
-
"""
|
|
126
|
-
_response = await self._raw_client.get_token(
|
|
127
|
-
client_id=client_id, client_secret=client_secret, request_options=request_options
|
|
128
|
-
)
|
|
129
|
-
return _response.data
|
samsara/auth/raw_client.py
CHANGED
|
@@ -1,128 +1,13 @@
|
|
|
1
1
|
# This file was auto-generated by Fern from our API Definition.
|
|
2
2
|
|
|
3
|
-
import typing
|
|
4
|
-
from json.decoder import JSONDecodeError
|
|
5
|
-
|
|
6
|
-
from ..core.api_error import ApiError
|
|
7
3
|
from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
|
|
8
|
-
from ..core.http_response import AsyncHttpResponse, HttpResponse
|
|
9
|
-
from ..core.pydantic_utilities import parse_obj_as
|
|
10
|
-
from ..core.request_options import RequestOptions
|
|
11
|
-
from .types.get_token_response import GetTokenResponse
|
|
12
|
-
|
|
13
|
-
# this is used as the default value for optional parameters
|
|
14
|
-
OMIT = typing.cast(typing.Any, ...)
|
|
15
4
|
|
|
16
5
|
|
|
17
6
|
class RawAuthClient:
|
|
18
7
|
def __init__(self, *, client_wrapper: SyncClientWrapper):
|
|
19
8
|
self._client_wrapper = client_wrapper
|
|
20
9
|
|
|
21
|
-
def get_token(
|
|
22
|
-
self, *, client_id: str, client_secret: str, request_options: typing.Optional[RequestOptions] = None
|
|
23
|
-
) -> HttpResponse[GetTokenResponse]:
|
|
24
|
-
"""
|
|
25
|
-
Obtain an OAuth2 access token using client credentials
|
|
26
|
-
|
|
27
|
-
Parameters
|
|
28
|
-
----------
|
|
29
|
-
client_id : str
|
|
30
|
-
The client ID of the application
|
|
31
|
-
|
|
32
|
-
client_secret : str
|
|
33
|
-
The client secret of the application
|
|
34
|
-
|
|
35
|
-
request_options : typing.Optional[RequestOptions]
|
|
36
|
-
Request-specific configuration.
|
|
37
|
-
|
|
38
|
-
Returns
|
|
39
|
-
-------
|
|
40
|
-
HttpResponse[GetTokenResponse]
|
|
41
|
-
Successful response
|
|
42
|
-
"""
|
|
43
|
-
_response = self._client_wrapper.httpx_client.request(
|
|
44
|
-
"oauth/token",
|
|
45
|
-
method="POST",
|
|
46
|
-
json={
|
|
47
|
-
"client_id": client_id,
|
|
48
|
-
"client_secret": client_secret,
|
|
49
|
-
"audience": "https://api.samsara.com",
|
|
50
|
-
"grant_type": "authorization_code",
|
|
51
|
-
},
|
|
52
|
-
headers={
|
|
53
|
-
"content-type": "application/json",
|
|
54
|
-
},
|
|
55
|
-
request_options=request_options,
|
|
56
|
-
omit=OMIT,
|
|
57
|
-
)
|
|
58
|
-
try:
|
|
59
|
-
if 200 <= _response.status_code < 300:
|
|
60
|
-
_data = typing.cast(
|
|
61
|
-
GetTokenResponse,
|
|
62
|
-
parse_obj_as(
|
|
63
|
-
type_=GetTokenResponse, # type: ignore
|
|
64
|
-
object_=_response.json(),
|
|
65
|
-
),
|
|
66
|
-
)
|
|
67
|
-
return HttpResponse(response=_response, data=_data)
|
|
68
|
-
_response_json = _response.json()
|
|
69
|
-
except JSONDecodeError:
|
|
70
|
-
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
|
|
71
|
-
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
|
|
72
|
-
|
|
73
10
|
|
|
74
11
|
class AsyncRawAuthClient:
|
|
75
12
|
def __init__(self, *, client_wrapper: AsyncClientWrapper):
|
|
76
13
|
self._client_wrapper = client_wrapper
|
|
77
|
-
|
|
78
|
-
async def get_token(
|
|
79
|
-
self, *, client_id: str, client_secret: str, request_options: typing.Optional[RequestOptions] = None
|
|
80
|
-
) -> AsyncHttpResponse[GetTokenResponse]:
|
|
81
|
-
"""
|
|
82
|
-
Obtain an OAuth2 access token using client credentials
|
|
83
|
-
|
|
84
|
-
Parameters
|
|
85
|
-
----------
|
|
86
|
-
client_id : str
|
|
87
|
-
The client ID of the application
|
|
88
|
-
|
|
89
|
-
client_secret : str
|
|
90
|
-
The client secret of the application
|
|
91
|
-
|
|
92
|
-
request_options : typing.Optional[RequestOptions]
|
|
93
|
-
Request-specific configuration.
|
|
94
|
-
|
|
95
|
-
Returns
|
|
96
|
-
-------
|
|
97
|
-
AsyncHttpResponse[GetTokenResponse]
|
|
98
|
-
Successful response
|
|
99
|
-
"""
|
|
100
|
-
_response = await self._client_wrapper.httpx_client.request(
|
|
101
|
-
"oauth/token",
|
|
102
|
-
method="POST",
|
|
103
|
-
json={
|
|
104
|
-
"client_id": client_id,
|
|
105
|
-
"client_secret": client_secret,
|
|
106
|
-
"audience": "https://api.samsara.com",
|
|
107
|
-
"grant_type": "authorization_code",
|
|
108
|
-
},
|
|
109
|
-
headers={
|
|
110
|
-
"content-type": "application/json",
|
|
111
|
-
},
|
|
112
|
-
request_options=request_options,
|
|
113
|
-
omit=OMIT,
|
|
114
|
-
)
|
|
115
|
-
try:
|
|
116
|
-
if 200 <= _response.status_code < 300:
|
|
117
|
-
_data = typing.cast(
|
|
118
|
-
GetTokenResponse,
|
|
119
|
-
parse_obj_as(
|
|
120
|
-
type_=GetTokenResponse, # type: ignore
|
|
121
|
-
object_=_response.json(),
|
|
122
|
-
),
|
|
123
|
-
)
|
|
124
|
-
return AsyncHttpResponse(response=_response, data=_data)
|
|
125
|
-
_response_json = _response.json()
|
|
126
|
-
except JSONDecodeError:
|
|
127
|
-
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
|
|
128
|
-
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
|
2
|
+
|
|
3
|
+
import typing
|
|
4
|
+
|
|
5
|
+
from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
|
|
6
|
+
from ...core.request_options import RequestOptions
|
|
7
|
+
from .raw_client import AsyncRawTokensClient, RawTokensClient
|
|
8
|
+
from .types.create_tokens_response import CreateTokensResponse
|
|
9
|
+
|
|
10
|
+
# this is used as the default value for optional parameters
|
|
11
|
+
OMIT = typing.cast(typing.Any, ...)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TokensClient:
|
|
15
|
+
def __init__(self, *, client_wrapper: SyncClientWrapper):
|
|
16
|
+
self._raw_client = RawTokensClient(client_wrapper=client_wrapper)
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def with_raw_response(self) -> RawTokensClient:
|
|
20
|
+
"""
|
|
21
|
+
Retrieves a raw implementation of this client that returns raw responses.
|
|
22
|
+
|
|
23
|
+
Returns
|
|
24
|
+
-------
|
|
25
|
+
RawTokensClient
|
|
26
|
+
"""
|
|
27
|
+
return self._raw_client
|
|
28
|
+
|
|
29
|
+
def create(
|
|
30
|
+
self, *, code: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None
|
|
31
|
+
) -> CreateTokensResponse:
|
|
32
|
+
"""
|
|
33
|
+
Exchange an authorization code for access and refresh tokens.
|
|
34
|
+
|
|
35
|
+
Parameters
|
|
36
|
+
----------
|
|
37
|
+
code : typing.Optional[str]
|
|
38
|
+
The client secret of the application
|
|
39
|
+
|
|
40
|
+
request_options : typing.Optional[RequestOptions]
|
|
41
|
+
Request-specific configuration.
|
|
42
|
+
|
|
43
|
+
Returns
|
|
44
|
+
-------
|
|
45
|
+
CreateTokensResponse
|
|
46
|
+
Successful response
|
|
47
|
+
|
|
48
|
+
Examples
|
|
49
|
+
--------
|
|
50
|
+
from samsara import Samsara
|
|
51
|
+
|
|
52
|
+
client = Samsara(
|
|
53
|
+
token="YOUR_TOKEN",
|
|
54
|
+
)
|
|
55
|
+
client.auth.tokens.create()
|
|
56
|
+
"""
|
|
57
|
+
_response = self._raw_client.create(code=code, request_options=request_options)
|
|
58
|
+
return _response.data
|
|
59
|
+
|
|
60
|
+
def revoke(self, *, token: str, request_options: typing.Optional[RequestOptions] = None) -> CreateTokensResponse:
|
|
61
|
+
"""
|
|
62
|
+
Invalidates access tokens and refresh tokens for that organization
|
|
63
|
+
|
|
64
|
+
Parameters
|
|
65
|
+
----------
|
|
66
|
+
token : str
|
|
67
|
+
The token to revoke
|
|
68
|
+
|
|
69
|
+
request_options : typing.Optional[RequestOptions]
|
|
70
|
+
Request-specific configuration.
|
|
71
|
+
|
|
72
|
+
Returns
|
|
73
|
+
-------
|
|
74
|
+
CreateTokensResponse
|
|
75
|
+
Successful response
|
|
76
|
+
|
|
77
|
+
Examples
|
|
78
|
+
--------
|
|
79
|
+
from samsara import Samsara
|
|
80
|
+
|
|
81
|
+
client = Samsara(
|
|
82
|
+
token="YOUR_TOKEN",
|
|
83
|
+
)
|
|
84
|
+
client.auth.tokens.revoke(
|
|
85
|
+
token="token",
|
|
86
|
+
)
|
|
87
|
+
"""
|
|
88
|
+
_response = self._raw_client.revoke(token=token, request_options=request_options)
|
|
89
|
+
return _response.data
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class AsyncTokensClient:
|
|
93
|
+
def __init__(self, *, client_wrapper: AsyncClientWrapper):
|
|
94
|
+
self._raw_client = AsyncRawTokensClient(client_wrapper=client_wrapper)
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def with_raw_response(self) -> AsyncRawTokensClient:
|
|
98
|
+
"""
|
|
99
|
+
Retrieves a raw implementation of this client that returns raw responses.
|
|
100
|
+
|
|
101
|
+
Returns
|
|
102
|
+
-------
|
|
103
|
+
AsyncRawTokensClient
|
|
104
|
+
"""
|
|
105
|
+
return self._raw_client
|
|
106
|
+
|
|
107
|
+
async def create(
|
|
108
|
+
self, *, code: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None
|
|
109
|
+
) -> CreateTokensResponse:
|
|
110
|
+
"""
|
|
111
|
+
Exchange an authorization code for access and refresh tokens.
|
|
112
|
+
|
|
113
|
+
Parameters
|
|
114
|
+
----------
|
|
115
|
+
code : typing.Optional[str]
|
|
116
|
+
The client secret of the application
|
|
117
|
+
|
|
118
|
+
request_options : typing.Optional[RequestOptions]
|
|
119
|
+
Request-specific configuration.
|
|
120
|
+
|
|
121
|
+
Returns
|
|
122
|
+
-------
|
|
123
|
+
CreateTokensResponse
|
|
124
|
+
Successful response
|
|
125
|
+
|
|
126
|
+
Examples
|
|
127
|
+
--------
|
|
128
|
+
import asyncio
|
|
129
|
+
|
|
130
|
+
from samsara import AsyncSamsara
|
|
131
|
+
|
|
132
|
+
client = AsyncSamsara(
|
|
133
|
+
token="YOUR_TOKEN",
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
async def main() -> None:
|
|
138
|
+
await client.auth.tokens.create()
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
asyncio.run(main())
|
|
142
|
+
"""
|
|
143
|
+
_response = await self._raw_client.create(code=code, request_options=request_options)
|
|
144
|
+
return _response.data
|
|
145
|
+
|
|
146
|
+
async def revoke(
|
|
147
|
+
self, *, token: str, request_options: typing.Optional[RequestOptions] = None
|
|
148
|
+
) -> CreateTokensResponse:
|
|
149
|
+
"""
|
|
150
|
+
Invalidates access tokens and refresh tokens for that organization
|
|
151
|
+
|
|
152
|
+
Parameters
|
|
153
|
+
----------
|
|
154
|
+
token : str
|
|
155
|
+
The token to revoke
|
|
156
|
+
|
|
157
|
+
request_options : typing.Optional[RequestOptions]
|
|
158
|
+
Request-specific configuration.
|
|
159
|
+
|
|
160
|
+
Returns
|
|
161
|
+
-------
|
|
162
|
+
CreateTokensResponse
|
|
163
|
+
Successful response
|
|
164
|
+
|
|
165
|
+
Examples
|
|
166
|
+
--------
|
|
167
|
+
import asyncio
|
|
168
|
+
|
|
169
|
+
from samsara import AsyncSamsara
|
|
170
|
+
|
|
171
|
+
client = AsyncSamsara(
|
|
172
|
+
token="YOUR_TOKEN",
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
async def main() -> None:
|
|
177
|
+
await client.auth.tokens.revoke(
|
|
178
|
+
token="token",
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
asyncio.run(main())
|
|
183
|
+
"""
|
|
184
|
+
_response = await self._raw_client.revoke(token=token, request_options=request_options)
|
|
185
|
+
return _response.data
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
|
2
|
+
|
|
3
|
+
import typing
|
|
4
|
+
from json.decoder import JSONDecodeError
|
|
5
|
+
|
|
6
|
+
from ...core.api_error import ApiError
|
|
7
|
+
from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
|
|
8
|
+
from ...core.http_response import AsyncHttpResponse, HttpResponse
|
|
9
|
+
from ...core.pydantic_utilities import parse_obj_as
|
|
10
|
+
from ...core.request_options import RequestOptions
|
|
11
|
+
from .types.create_tokens_response import CreateTokensResponse
|
|
12
|
+
|
|
13
|
+
# this is used as the default value for optional parameters
|
|
14
|
+
OMIT = typing.cast(typing.Any, ...)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class RawTokensClient:
|
|
18
|
+
def __init__(self, *, client_wrapper: SyncClientWrapper):
|
|
19
|
+
self._client_wrapper = client_wrapper
|
|
20
|
+
|
|
21
|
+
def create(
|
|
22
|
+
self, *, code: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None
|
|
23
|
+
) -> HttpResponse[CreateTokensResponse]:
|
|
24
|
+
"""
|
|
25
|
+
Exchange an authorization code for access and refresh tokens.
|
|
26
|
+
|
|
27
|
+
Parameters
|
|
28
|
+
----------
|
|
29
|
+
code : typing.Optional[str]
|
|
30
|
+
The client secret of the application
|
|
31
|
+
|
|
32
|
+
request_options : typing.Optional[RequestOptions]
|
|
33
|
+
Request-specific configuration.
|
|
34
|
+
|
|
35
|
+
Returns
|
|
36
|
+
-------
|
|
37
|
+
HttpResponse[CreateTokensResponse]
|
|
38
|
+
Successful response
|
|
39
|
+
"""
|
|
40
|
+
_response = self._client_wrapper.httpx_client.request(
|
|
41
|
+
"oauth2/token",
|
|
42
|
+
method="POST",
|
|
43
|
+
json={
|
|
44
|
+
"code": code,
|
|
45
|
+
"grant_type": "authorization_code",
|
|
46
|
+
},
|
|
47
|
+
headers={
|
|
48
|
+
"content-type": "application/json",
|
|
49
|
+
},
|
|
50
|
+
request_options=request_options,
|
|
51
|
+
omit=OMIT,
|
|
52
|
+
)
|
|
53
|
+
try:
|
|
54
|
+
if 200 <= _response.status_code < 300:
|
|
55
|
+
_data = typing.cast(
|
|
56
|
+
CreateTokensResponse,
|
|
57
|
+
parse_obj_as(
|
|
58
|
+
type_=CreateTokensResponse, # type: ignore
|
|
59
|
+
object_=_response.json(),
|
|
60
|
+
),
|
|
61
|
+
)
|
|
62
|
+
return HttpResponse(response=_response, data=_data)
|
|
63
|
+
_response_json = _response.json()
|
|
64
|
+
except JSONDecodeError:
|
|
65
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
|
|
66
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
|
|
67
|
+
|
|
68
|
+
def revoke(
|
|
69
|
+
self, *, token: str, request_options: typing.Optional[RequestOptions] = None
|
|
70
|
+
) -> HttpResponse[CreateTokensResponse]:
|
|
71
|
+
"""
|
|
72
|
+
Invalidates access tokens and refresh tokens for that organization
|
|
73
|
+
|
|
74
|
+
Parameters
|
|
75
|
+
----------
|
|
76
|
+
token : str
|
|
77
|
+
The token to revoke
|
|
78
|
+
|
|
79
|
+
request_options : typing.Optional[RequestOptions]
|
|
80
|
+
Request-specific configuration.
|
|
81
|
+
|
|
82
|
+
Returns
|
|
83
|
+
-------
|
|
84
|
+
HttpResponse[CreateTokensResponse]
|
|
85
|
+
Successful response
|
|
86
|
+
"""
|
|
87
|
+
_response = self._client_wrapper.httpx_client.request(
|
|
88
|
+
"oauth2/revoke",
|
|
89
|
+
method="POST",
|
|
90
|
+
json={
|
|
91
|
+
"token": token,
|
|
92
|
+
},
|
|
93
|
+
headers={
|
|
94
|
+
"content-type": "application/json",
|
|
95
|
+
},
|
|
96
|
+
request_options=request_options,
|
|
97
|
+
omit=OMIT,
|
|
98
|
+
)
|
|
99
|
+
try:
|
|
100
|
+
if 200 <= _response.status_code < 300:
|
|
101
|
+
_data = typing.cast(
|
|
102
|
+
CreateTokensResponse,
|
|
103
|
+
parse_obj_as(
|
|
104
|
+
type_=CreateTokensResponse, # type: ignore
|
|
105
|
+
object_=_response.json(),
|
|
106
|
+
),
|
|
107
|
+
)
|
|
108
|
+
return HttpResponse(response=_response, data=_data)
|
|
109
|
+
_response_json = _response.json()
|
|
110
|
+
except JSONDecodeError:
|
|
111
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
|
|
112
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class AsyncRawTokensClient:
|
|
116
|
+
def __init__(self, *, client_wrapper: AsyncClientWrapper):
|
|
117
|
+
self._client_wrapper = client_wrapper
|
|
118
|
+
|
|
119
|
+
async def create(
|
|
120
|
+
self, *, code: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None
|
|
121
|
+
) -> AsyncHttpResponse[CreateTokensResponse]:
|
|
122
|
+
"""
|
|
123
|
+
Exchange an authorization code for access and refresh tokens.
|
|
124
|
+
|
|
125
|
+
Parameters
|
|
126
|
+
----------
|
|
127
|
+
code : typing.Optional[str]
|
|
128
|
+
The client secret of the application
|
|
129
|
+
|
|
130
|
+
request_options : typing.Optional[RequestOptions]
|
|
131
|
+
Request-specific configuration.
|
|
132
|
+
|
|
133
|
+
Returns
|
|
134
|
+
-------
|
|
135
|
+
AsyncHttpResponse[CreateTokensResponse]
|
|
136
|
+
Successful response
|
|
137
|
+
"""
|
|
138
|
+
_response = await self._client_wrapper.httpx_client.request(
|
|
139
|
+
"oauth2/token",
|
|
140
|
+
method="POST",
|
|
141
|
+
json={
|
|
142
|
+
"code": code,
|
|
143
|
+
"grant_type": "authorization_code",
|
|
144
|
+
},
|
|
145
|
+
headers={
|
|
146
|
+
"content-type": "application/json",
|
|
147
|
+
},
|
|
148
|
+
request_options=request_options,
|
|
149
|
+
omit=OMIT,
|
|
150
|
+
)
|
|
151
|
+
try:
|
|
152
|
+
if 200 <= _response.status_code < 300:
|
|
153
|
+
_data = typing.cast(
|
|
154
|
+
CreateTokensResponse,
|
|
155
|
+
parse_obj_as(
|
|
156
|
+
type_=CreateTokensResponse, # type: ignore
|
|
157
|
+
object_=_response.json(),
|
|
158
|
+
),
|
|
159
|
+
)
|
|
160
|
+
return AsyncHttpResponse(response=_response, data=_data)
|
|
161
|
+
_response_json = _response.json()
|
|
162
|
+
except JSONDecodeError:
|
|
163
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
|
|
164
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
|
|
165
|
+
|
|
166
|
+
async def revoke(
|
|
167
|
+
self, *, token: str, request_options: typing.Optional[RequestOptions] = None
|
|
168
|
+
) -> AsyncHttpResponse[CreateTokensResponse]:
|
|
169
|
+
"""
|
|
170
|
+
Invalidates access tokens and refresh tokens for that organization
|
|
171
|
+
|
|
172
|
+
Parameters
|
|
173
|
+
----------
|
|
174
|
+
token : str
|
|
175
|
+
The token to revoke
|
|
176
|
+
|
|
177
|
+
request_options : typing.Optional[RequestOptions]
|
|
178
|
+
Request-specific configuration.
|
|
179
|
+
|
|
180
|
+
Returns
|
|
181
|
+
-------
|
|
182
|
+
AsyncHttpResponse[CreateTokensResponse]
|
|
183
|
+
Successful response
|
|
184
|
+
"""
|
|
185
|
+
_response = await self._client_wrapper.httpx_client.request(
|
|
186
|
+
"oauth2/revoke",
|
|
187
|
+
method="POST",
|
|
188
|
+
json={
|
|
189
|
+
"token": token,
|
|
190
|
+
},
|
|
191
|
+
headers={
|
|
192
|
+
"content-type": "application/json",
|
|
193
|
+
},
|
|
194
|
+
request_options=request_options,
|
|
195
|
+
omit=OMIT,
|
|
196
|
+
)
|
|
197
|
+
try:
|
|
198
|
+
if 200 <= _response.status_code < 300:
|
|
199
|
+
_data = typing.cast(
|
|
200
|
+
CreateTokensResponse,
|
|
201
|
+
parse_obj_as(
|
|
202
|
+
type_=CreateTokensResponse, # type: ignore
|
|
203
|
+
object_=_response.json(),
|
|
204
|
+
),
|
|
205
|
+
)
|
|
206
|
+
return AsyncHttpResponse(response=_response, data=_data)
|
|
207
|
+
_response_json = _response.json()
|
|
208
|
+
except JSONDecodeError:
|
|
209
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
|
|
210
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
|
|
@@ -3,13 +3,15 @@
|
|
|
3
3
|
import typing
|
|
4
4
|
|
|
5
5
|
import pydantic
|
|
6
|
-
from
|
|
6
|
+
from ....core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
class
|
|
9
|
+
class CreateTokensResponse(UniversalBaseModel):
|
|
10
10
|
access_token: str
|
|
11
11
|
token_type: str
|
|
12
12
|
expires_in: int
|
|
13
|
+
refresh_token: str
|
|
14
|
+
scope: str
|
|
13
15
|
|
|
14
16
|
if IS_PYDANTIC_V2:
|
|
15
17
|
model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
|
samsara/client.py
CHANGED
|
@@ -160,8 +160,8 @@ class Samsara:
|
|
|
160
160
|
self.users = UsersClient(client_wrapper=self._client_wrapper)
|
|
161
161
|
self.v_1_messages = V1MessagesClient(client_wrapper=self._client_wrapper)
|
|
162
162
|
self.webhooks = WebhooksClient(client_wrapper=self._client_wrapper)
|
|
163
|
-
self.auth = AuthClient(client_wrapper=self._client_wrapper)
|
|
164
163
|
self.alerts = AlertsClient(client_wrapper=self._client_wrapper)
|
|
164
|
+
self.auth = AuthClient(client_wrapper=self._client_wrapper)
|
|
165
165
|
self.cameras = CamerasClient(client_wrapper=self._client_wrapper)
|
|
166
166
|
self.coaching = CoachingClient(client_wrapper=self._client_wrapper)
|
|
167
167
|
self.ifta = IftaClient(client_wrapper=self._client_wrapper)
|
|
@@ -273,8 +273,8 @@ class AsyncSamsara:
|
|
|
273
273
|
self.users = AsyncUsersClient(client_wrapper=self._client_wrapper)
|
|
274
274
|
self.v_1_messages = AsyncV1MessagesClient(client_wrapper=self._client_wrapper)
|
|
275
275
|
self.webhooks = AsyncWebhooksClient(client_wrapper=self._client_wrapper)
|
|
276
|
-
self.auth = AsyncAuthClient(client_wrapper=self._client_wrapper)
|
|
277
276
|
self.alerts = AsyncAlertsClient(client_wrapper=self._client_wrapper)
|
|
277
|
+
self.auth = AsyncAuthClient(client_wrapper=self._client_wrapper)
|
|
278
278
|
self.cameras = AsyncCamerasClient(client_wrapper=self._client_wrapper)
|
|
279
279
|
self.coaching = AsyncCoachingClient(client_wrapper=self._client_wrapper)
|
|
280
280
|
self.ifta = AsyncIftaClient(client_wrapper=self._client_wrapper)
|
samsara/core/client_wrapper.py
CHANGED
|
@@ -20,10 +20,10 @@ class BaseClientWrapper:
|
|
|
20
20
|
|
|
21
21
|
def get_headers(self) -> typing.Dict[str, str]:
|
|
22
22
|
headers: typing.Dict[str, str] = {
|
|
23
|
-
"User-Agent": "samsara-api/0.0.
|
|
23
|
+
"User-Agent": "samsara-api/0.0.4",
|
|
24
24
|
"X-Fern-Language": "Python",
|
|
25
25
|
"X-Fern-SDK-Name": "samsara-api",
|
|
26
|
-
"X-Fern-SDK-Version": "0.0.
|
|
26
|
+
"X-Fern-SDK-Version": "0.0.4",
|
|
27
27
|
}
|
|
28
28
|
headers["Authorization"] = f"Bearer {self._get_token()}"
|
|
29
29
|
return headers
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import hashlib
|
|
3
|
+
import hmac
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def verify_signature(
|
|
7
|
+
*,
|
|
8
|
+
request_body: str,
|
|
9
|
+
signature_header: str,
|
|
10
|
+
signature_key: str,
|
|
11
|
+
notification_url: str,
|
|
12
|
+
) -> bool:
|
|
13
|
+
"""
|
|
14
|
+
Verifies and validates an event notification. See the `documentation`_ for more details.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
request_body: The JSON body of the request.
|
|
18
|
+
signature_header: The value for the `x-samsara-hmacsha256-signature` header.
|
|
19
|
+
signature_key: The signature key from the Samsara Developer portal for the webhook subscription.
|
|
20
|
+
notification_url: The notification endpoint URL as defined in the Samsara Developer portal for the webhook
|
|
21
|
+
subscription.
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
bool: True if the signature is valid, indicating that the event can be trusted as it came from Samsara.
|
|
25
|
+
False if the signature validation fails, indicating that the event did not come from Samsara, so it may
|
|
26
|
+
be malicious and should be discarded.
|
|
27
|
+
|
|
28
|
+
Raises:
|
|
29
|
+
ValueError: if `signature_key` or `notification_url` are empty.
|
|
30
|
+
"""
|
|
31
|
+
if not request_body:
|
|
32
|
+
return False
|
|
33
|
+
if not signature_key:
|
|
34
|
+
raise ValueError("signature_key is empty")
|
|
35
|
+
if not notification_url:
|
|
36
|
+
raise ValueError("notification_url is empty")
|
|
37
|
+
|
|
38
|
+
# Perform UTF-8 encoding to bytes
|
|
39
|
+
payload = notification_url + request_body
|
|
40
|
+
payload_bytes = payload.encode("utf-8")
|
|
41
|
+
signature_header_bytes = signature_header.encode("utf-8")
|
|
42
|
+
signature_key_bytes = signature_key.encode("utf-8")
|
|
43
|
+
|
|
44
|
+
# Compute the hash value
|
|
45
|
+
hashing_obj = hmac.new(
|
|
46
|
+
key=signature_key_bytes, msg=payload_bytes, digestmod=hashlib.sha256
|
|
47
|
+
)
|
|
48
|
+
hash_bytes = hashing_obj.digest()
|
|
49
|
+
|
|
50
|
+
# Compare the computed hash vs the value in the signature header
|
|
51
|
+
hash_base64 = base64.b64encode(hash_bytes)
|
|
52
|
+
return hmac.compare_digest(hash_base64, signature_header_bytes)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: samsara-api
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4
|
|
4
4
|
Summary:
|
|
5
5
|
License: MIT
|
|
6
6
|
Requires-Python: >=3.8,<4.0
|
|
@@ -125,6 +125,23 @@ for page in response.iter_pages():
|
|
|
125
125
|
yield page
|
|
126
126
|
```
|
|
127
127
|
|
|
128
|
+
## Webhook Signature Verification
|
|
129
|
+
|
|
130
|
+
The SDK provides utility methods that allow you to verify webhook signatures and ensure
|
|
131
|
+
that all webhook events originate from Samsara. The `verify_signature` method will verify
|
|
132
|
+
the signature.
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
from samsara.utils.webhooks_helper import verify_signature
|
|
136
|
+
|
|
137
|
+
is_valid = verify_signature(
|
|
138
|
+
request_body=request_body,
|
|
139
|
+
signature_header=request.headers['x-samsara-hmacsha256-signature'],
|
|
140
|
+
signature_key="YOUR_SIGNATURE_KEY",
|
|
141
|
+
notification_url="https://example.com/webhook", # The URL where event notifications are sent.
|
|
142
|
+
)
|
|
143
|
+
```
|
|
144
|
+
|
|
128
145
|
## Advanced
|
|
129
146
|
|
|
130
147
|
### Access Raw Response Data
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
samsara/__init__.py,sha256=
|
|
1
|
+
samsara/__init__.py,sha256=92NvaQpSlOyKeuVpidF-8CqSBNqs-mUz8-ISlOKTWA4,243381
|
|
2
2
|
samsara/addresses/__init__.py,sha256=VwNk87ydCDVCvXs50iVyOtmRChWMryj-qaD37dmXEHE,271
|
|
3
3
|
samsara/addresses/client.py,sha256=NmZDd3Q5xZsNDD-NlBZ6dIxIxHNQUVs9DDZ-3b38qQQ,31432
|
|
4
4
|
samsara/addresses/raw_client.py,sha256=dF0VKXWrRMpZ_FYBwT5Z58StWm1nE7VCQVE4NouRvF0,39437
|
|
@@ -41,11 +41,14 @@ samsara/attributes/types/create_attribute_request_entity_type.py,sha256=YVWNyZIS
|
|
|
41
41
|
samsara/attributes/types/update_attribute_request_attribute_type.py,sha256=nmtbsmoh3lh6NkGW6UVDbrwLSf_Kyp0FmJJyzC60yfY,179
|
|
42
42
|
samsara/attributes/types/update_attribute_request_attribute_value_quantity.py,sha256=UIX4mHT8iNREa_H6CuXcpgIH42KKKQRpnUgxpoYy_P4,187
|
|
43
43
|
samsara/attributes/types/update_attribute_request_entity_type.py,sha256=O3P4cbLmICVFdTzcEUWq4HSpheSpWE-TZfz4HElX9bM,175
|
|
44
|
-
samsara/auth/__init__.py,sha256=
|
|
45
|
-
samsara/auth/client.py,sha256=
|
|
46
|
-
samsara/auth/raw_client.py,sha256=
|
|
47
|
-
samsara/auth/
|
|
48
|
-
samsara/auth/
|
|
44
|
+
samsara/auth/__init__.py,sha256=9yWTBw0ONdi-3tmC4kjbCpApiVniv2aK5csdVnHOI20,193
|
|
45
|
+
samsara/auth/client.py,sha256=iGRrTmTAyBspdf_-HcGqn0Pb0s1HQwco4PoSphDFwEU,1236
|
|
46
|
+
samsara/auth/raw_client.py,sha256=Xjah5juxJ0L8FfHyZBKMoOVHWxzvqTv4qtQixxA3jDc,405
|
|
47
|
+
samsara/auth/tokens/__init__.py,sha256=gbhdUVQ3-j2WiNIQN0-h_5RODBZ4gvJgteMmSdgtscQ,161
|
|
48
|
+
samsara/auth/tokens/client.py,sha256=g6AlGPqOt3gHPDrz2q9Glemm7jEGHFiGFnijUY4a66Q,4959
|
|
49
|
+
samsara/auth/tokens/raw_client.py,sha256=ZEnP5Xi8DkY-SEsiQkNAsB3b06AIoal5_cmRcW_Zuxo,7528
|
|
50
|
+
samsara/auth/tokens/types/__init__.py,sha256=XmB_JdsWYwBG-Tz8M8Qj3rfQJWmQtPXDtsFiqy_VuNs,178
|
|
51
|
+
samsara/auth/tokens/types/create_tokens_response.py,sha256=wcHMN9xNW0DfH4-wXKa1l1mY14BmMxl6UDLJGLwNDsY,615
|
|
49
52
|
samsara/cameras/__init__.py,sha256=6oUbRWZI3I0mSd4P2kGnp-bNVIQoyoR6J4_1OXzluws,361
|
|
50
53
|
samsara/cameras/client.py,sha256=HdYw4W_X5eIuR9zOYL9IyIrIyeYRIicK9RNdsKPnKJg,1259
|
|
51
54
|
samsara/cameras/media/__init__.py,sha256=bXxa72UiJqERML9R4PL4PCNWKFZhTCrly5ZvF7__7rA,634
|
|
@@ -65,7 +68,7 @@ samsara/cameras/raw_client.py,sha256=X7YzaI5nwgwczR-A4OwhSK54TQW6VfCzs00pgNTMuUU
|
|
|
65
68
|
samsara/carrier_proposed_assignments/__init__.py,sha256=_VhToAyIt_5axN6CLJwtxg3-CO7THa_23pbUzqhXJa4,85
|
|
66
69
|
samsara/carrier_proposed_assignments/client.py,sha256=UDeSIJ17UU_TboofUe-Y8uIY1zBNNtt9Ss7msqIiLac,17860
|
|
67
70
|
samsara/carrier_proposed_assignments/raw_client.py,sha256=NW9vhF3XwbYEK5nQDzhGYzxkEx4a_wIqL4gqU-npmn0,22836
|
|
68
|
-
samsara/client.py,sha256=
|
|
71
|
+
samsara/client.py,sha256=852-56uS8ECcrGvhCp-ykxHYJLSuy7VRe0F1iVPk4tw,17115
|
|
69
72
|
samsara/coaching/__init__.py,sha256=LfmwpXue7wsY-q1lfvX-AYcU4JdP1x0zVtofVAh4pAA,186
|
|
70
73
|
samsara/coaching/client.py,sha256=ULolm0GnWQmfOVzY1FE8vBMaLl-m0InJutgkQJ4lfps,1606
|
|
71
74
|
samsara/coaching/driver_coach_assignments/__init__.py,sha256=_VhToAyIt_5axN6CLJwtxg3-CO7THa_23pbUzqhXJa4,85
|
|
@@ -80,7 +83,7 @@ samsara/contacts/client.py,sha256=-DvPNxYQZboAYekVkG22JH8GLN5Pb441W0pD7amZue8,19
|
|
|
80
83
|
samsara/contacts/raw_client.py,sha256=nMFcdeS_I53QS01zxF2yeY6-t6cbQ7ZeZeqUxKcH7yI,27530
|
|
81
84
|
samsara/core/__init__.py,sha256=4POYbbRlgR7TwGFY5nmHpaa7nFgXOX_pYHcN1Ezh2p8,1643
|
|
82
85
|
samsara/core/api_error.py,sha256=44vPoTyWN59gonCIZMdzw7M1uspygiLnr3GNFOoVL2Q,614
|
|
83
|
-
samsara/core/client_wrapper.py,sha256=
|
|
86
|
+
samsara/core/client_wrapper.py,sha256=9ANX-olJY3Lv-BmJeGdRh408Cu9mhWO74esp7VjH7jI,2236
|
|
84
87
|
samsara/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
|
|
85
88
|
samsara/core/file.py,sha256=d4NNbX8XvXP32z8KpK2Xovv33nFfruIrpz0QWxlgpZk,2663
|
|
86
89
|
samsara/core/force_multipart.py,sha256=awxh5MtcRYe74ehY8U76jzv6fYM_w_D3Rur7KQQzSDk,429
|
|
@@ -2610,6 +2613,7 @@ samsara/users/raw_client.py,sha256=aeoDOnJ4dMB4O3WocJXATsCiK-zNHodq09tBBYgaD8w,3
|
|
|
2610
2613
|
samsara/users/types/__init__.py,sha256=yVRLnN-wUYfYcYWwrgJSM8GIRnVdqk207hLlDqal0GM,293
|
|
2611
2614
|
samsara/users/types/create_user_request_auth_type.py,sha256=rdNs3jjJv7IY0koJ6vpgdE79OskOYbA6zUrYMijKmMw,168
|
|
2612
2615
|
samsara/users/types/update_user_request_auth_type.py,sha256=E2r4bzBS0lwPCWrUwC37GfMlt8Hv-YGw_3abv6wNN-Q,168
|
|
2616
|
+
samsara/utils/webhooks_helper.py,sha256=oosLIOouDmGa7a6xj4sI_EfUSvtzfqB6uXXaUKaagP8,1911
|
|
2613
2617
|
samsara/v_1_messages/__init__.py,sha256=_VhToAyIt_5axN6CLJwtxg3-CO7THa_23pbUzqhXJa4,85
|
|
2614
2618
|
samsara/v_1_messages/client.py,sha256=rhUwhh0L3IcgD3sglfNtZMyeLM2j1ogrpMe4902yTos,9734
|
|
2615
2619
|
samsara/v_1_messages/raw_client.py,sha256=3_5CVjrIRu2VREzYtcV7sQBz0K0F_tOwPDNcMSGDBOw,11896
|
|
@@ -2654,7 +2658,7 @@ samsara/webhooks/types/__init__.py,sha256=gZew8TwQaEiQWvSAewo9htvyM3UqVSZc1UJ2Aa
|
|
|
2654
2658
|
samsara/webhooks/types/webhooks_patch_webhook_request_body_version.py,sha256=WaQrAnZGbaz7eQ6fpnX77L5nb8dLwuUkEQdvx5mCGAw,224
|
|
2655
2659
|
samsara/webhooks/types/webhooks_post_webhooks_request_body_event_types_item.py,sha256=-whKIc9UjBEIXZUxwkDULLSxR0Dg_-6KxRUjcfyvTuQ,927
|
|
2656
2660
|
samsara/webhooks/types/webhooks_post_webhooks_request_body_version.py,sha256=1HR1l6_Qc_jS_mf_UkguxgMiiIeAiwaX7jjOTQfG1bw,224
|
|
2657
|
-
samsara_api-0.0.
|
|
2658
|
-
samsara_api-0.0.
|
|
2659
|
-
samsara_api-0.0.
|
|
2660
|
-
samsara_api-0.0.
|
|
2661
|
+
samsara_api-0.0.4.dist-info/LICENSE,sha256=uX-nl5hOEHp4uvQPCcpde-doNbQhV5uRQNwkB474IoQ,1064
|
|
2662
|
+
samsara_api-0.0.4.dist-info/METADATA,sha256=9uB-xryoMS0LeZ1qLICrPttG2gNMHa6AQ_nNQiyyI28,6831
|
|
2663
|
+
samsara_api-0.0.4.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
|
|
2664
|
+
samsara_api-0.0.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|