@dimo-network/data-sdk 1.2.3 → 1.2.4
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.
- package/README.md +57 -46
- package/dist/api/functions/{getToken.d.ts → getDeveloperJwt.d.ts} +1 -1
- package/dist/api/functions/{getToken.js → getDeveloperJwt.js} +1 -1
- package/dist/api/functions/getVehicleJwt.d.ts +7 -0
- package/dist/api/functions/getVehicleJwt.js +23 -0
- package/dist/api/functions/index.d.ts +3 -2
- package/dist/api/functions/index.js +3 -2
- package/dist/api/resources/Auth/index.js +2 -2
- package/dist/api/resources/TokenExchange/index.js +4 -0
- package/dist/constants.d.ts +4 -1
- package/dist/constants.js +3 -0
- package/dist/dimo.js +1 -1
- package/dist/environments/index.d.ts +0 -6
- package/dist/environments/index.js +0 -6
- package/dist/graphql/Query.js +7 -8
- package/dist/graphql/functions/getVehiclePrivileges.d.ts +6 -0
- package/dist/graphql/functions/getVehiclePrivileges.js +46 -0
- package/dist/graphql/functions/index.d.ts +2 -1
- package/dist/graphql/functions/index.js +2 -1
- package/dist/graphql/resources/Identity/index.d.ts +0 -1
- package/dist/graphql/resources/Identity/index.js +53 -78
- package/dist/graphql/util/paginate.d.ts +9 -0
- package/dist/graphql/util/paginate.js +37 -0
- package/dist/index.cjs +1624 -293
- package/dist/util/decodeJwt.d.ts +1 -0
- package/dist/util/decodeJwt.js +11 -0
- package/dist/util/decodePermissions.d.ts +1 -0
- package/dist/util/decodePermissions.js +12 -0
- package/dist/util/index.d.ts +8 -0
- package/dist/util/index.js +7 -0
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -37,7 +37,7 @@ import { DIMO } from '@dimo-network/data-sdk';
|
|
|
37
37
|
|
|
38
38
|
(CommonJS)
|
|
39
39
|
```js
|
|
40
|
-
const { DIMO } = require('@dimo-network/data-sdk
|
|
40
|
+
const { DIMO } = require('@dimo-network/data-sdk')
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
Initiate the SDK:
|
|
@@ -55,33 +55,28 @@ As part of the authentication process, you will need to obtain a Developer Licen
|
|
|
55
55
|
|
|
56
56
|
### Authentication
|
|
57
57
|
|
|
58
|
-
The SDK provides you with all the steps needed in the [Authentication Flow](https://docs.dimo.org/developer-platform/getting-started/developer-guide/authentication) to obtain a Developer JWT.
|
|
58
|
+
The SDK provides you with all the steps needed in the [Authentication Flow](https://docs.dimo.org/developer-platform/getting-started/developer-guide/authentication) to obtain a Developer JWT & to get Vehicle JWT for each vehicle shared with your app.
|
|
59
59
|
|
|
60
|
-
#### Prerequisites for Authentication
|
|
61
|
-
1. A valid Developer License with a `client_id`
|
|
62
|
-
2. A valid API key, generated via the Developer Console
|
|
63
60
|
3. A proper [project set up with TypeScript](https://www.digitalocean.com/community/tutorials/setting-up-a-node-project-with-typescript).
|
|
64
61
|
|
|
65
|
-
####
|
|
62
|
+
#### Developer JWT
|
|
63
|
+
To get a Developer JWT, you will need a valid Developer License with a `client_id`, a generated `api_key`, and a `domain`/`redirect_uri` you configured on the Developer Console.
|
|
66
64
|
|
|
67
|
-
##### (Option 1 - PREFERRED)
|
|
65
|
+
##### (Option 1 - PREFERRED) getDeveloperJwt Function
|
|
68
66
|
This is a utility function call to get a Developer JWT in one step:
|
|
69
67
|
|
|
70
68
|
```ts
|
|
71
|
-
const developerJwt = await dimo.auth.
|
|
69
|
+
const developerJwt = await dimo.auth.getDeveloperJwt({
|
|
72
70
|
client_id: '<client_id>',
|
|
73
|
-
domain: '<domain>',
|
|
71
|
+
domain: '<domain/redirect_uri>',
|
|
74
72
|
private_key: '<api_key>',
|
|
75
73
|
});
|
|
76
74
|
```
|
|
77
75
|
|
|
78
|
-
Once you have the `developerJwt`, you'll have access to the DIMO API
|
|
76
|
+
Once you have the `developerJwt`, you'll have access to the DIMO API as a verified developer. For endpoints that require the authorization headers, you can simply pass the results.
|
|
79
77
|
|
|
80
78
|
```ts
|
|
81
79
|
// Pass the developerJwt object to a protected endpoint
|
|
82
|
-
await dimo.user.get(developerJwt);
|
|
83
|
-
|
|
84
|
-
// Pass the developerJwt object to a protected endpoint with body parameters
|
|
85
80
|
await dimo.tokenexchange.exchange({
|
|
86
81
|
...developerJwt,
|
|
87
82
|
privileges: [4],
|
|
@@ -101,6 +96,54 @@ const developerJwt = await dimo.authenticate();
|
|
|
101
96
|
// The rest would be the same as option 1
|
|
102
97
|
```
|
|
103
98
|
|
|
99
|
+
#### Vehicle JWT
|
|
100
|
+
|
|
101
|
+
To get vehicle data from an end user, your application will need to exchange for a short-lived [Vehicle JWT](https://docs.dimo.org/developer-platform/getting-started/developer-guide/authentication#getting-a-jwt) for vehicles that have granted permissions to your app.
|
|
102
|
+
|
|
103
|
+
For the end users of your application, they will need to have already shared their vehicle permissions via the DIMO Mobile App or via your implementation of [Login with DIMO](https://docs.dimo.org/developer-platform/getting-started/developer-guide/login-with-dimo) before you can fetch for their vehicle data.
|
|
104
|
+
|
|
105
|
+
##### (Option 1 - PREFERRED) getVehicleJwt Function
|
|
106
|
+
This is a utility function call to get a Vehicle JWT in one step by inputting your developer JWT obtained earlier with the vehicle's identifier (`tokenId`):
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
const vehicleJwt = await dimo.tokenexchange.getVehicleJwt({
|
|
110
|
+
...developerJwt,
|
|
111
|
+
tokenId: 117315
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
##### (Option 2) Manually exchanging for Vehicle JWT
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
const vehicle_jwt = await dimo.tokenexchange.exchange({
|
|
119
|
+
...auth,
|
|
120
|
+
privileges: [1, 5],
|
|
121
|
+
tokenId: <vehicle_token_id>
|
|
122
|
+
});
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Once you have the `vehicleJwt`, you'll have access to the vehicle data for a specific vehicle. For endpoints that require the authorization headers, you can pass the results.
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
// Vehicle Status uses privId 1
|
|
129
|
+
await dimo.devicedata.getVehicleStatus({
|
|
130
|
+
...vehicle_jwt,
|
|
131
|
+
tokenId: <vehicle_token_id>
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Proof of Movement Verifiable Credentials uses privId 4
|
|
135
|
+
await dimo.attestation.createPomVC({
|
|
136
|
+
...vehicle_jwt,
|
|
137
|
+
tokenId: <vehicle_token_id>
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
// VIN Verifiable Credentials uses privId 5
|
|
141
|
+
await dimo.attestation.createVinVC({
|
|
142
|
+
...vehicle_jwt,
|
|
143
|
+
tokenId: <vehicle_token_id>
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
104
147
|
### Querying the DIMO REST API
|
|
105
148
|
The SDK supports async await and your typical JS Promises. HTTP operations can be utilized in either ways:
|
|
106
149
|
|
|
@@ -146,41 +189,9 @@ dimo.attestation.createVinVC({
|
|
|
146
189
|
})
|
|
147
190
|
```
|
|
148
191
|
|
|
149
|
-
#### Vehicle JWT
|
|
150
|
-
|
|
151
|
-
As the 2nd leg of the API authentication, applications may exchange for short-lived [Vehicle JWT](https://docs.dimo.org/developer-platform/getting-started/developer-guide/authentication#getting-a-jwt) for specific vehicles that granted permissions to the app. This uses the [DIMO Token Exchange API](https://docs.dimo.org/developer-platform/api-references/dimo-protocol/token-exchange-api/token-exchange-api-endpoints).
|
|
152
|
-
|
|
153
|
-
For the end users of your application, they will need to share their vehicle permissions via the DIMO Mobile App or via your implementation of [Login with DIMO](https://docs.dimo.org/developer-platform/getting-started/developer-guide/login-with-dimo) or even by sharing on the Vehicle NFT directly. Once vehicles are shared, you will be able to get a Vehicle JWT.
|
|
154
|
-
|
|
155
|
-
```ts
|
|
156
|
-
const vehicle_jwt = await dimo.tokenexchange.exchange({
|
|
157
|
-
...auth,
|
|
158
|
-
privileges: [1, 5],
|
|
159
|
-
tokenId: <vehicle_token_id>
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
// Vehicle Status uses privId 1
|
|
163
|
-
await dimo.devicedata.getVehicleStatus({
|
|
164
|
-
...vehicle_jwt,
|
|
165
|
-
tokenId: <vehicle_token_id>
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
// Proof of Movement Verifiable Credentials uses privId 4
|
|
169
|
-
await dimo.attestation.createPomVC({
|
|
170
|
-
...vehicle_jwt,
|
|
171
|
-
tokenId: <vehicle_token_id>
|
|
172
|
-
})
|
|
173
|
-
|
|
174
|
-
// VIN Verifiable Credentials uses privId 5
|
|
175
|
-
await dimo.attestation.createVinVC({
|
|
176
|
-
...vehicle_jwt,
|
|
177
|
-
tokenId: <vehicle_token_id>
|
|
178
|
-
});
|
|
179
|
-
```
|
|
180
|
-
|
|
181
192
|
### Querying the DIMO GraphQL API
|
|
182
193
|
|
|
183
|
-
The SDK accepts any type of valid custom GraphQL queries, but we've also included a few sample queries to help you understand the DIMO GraphQL APIs.
|
|
194
|
+
The SDK accepts any type of valid custom GraphQL queries, but we've also included a few sample queries to help you understand the DIMO GraphQL APIs. There's also a helper function called `paginate` that you can use to paginate through the GraphQL pages, see `getVehiclePrivileges.ts` on how it's being used.
|
|
184
195
|
|
|
185
196
|
#### Authentication for GraphQL API
|
|
186
197
|
The GraphQL entry points are designed almost identical to the REST API entry points. For any GraphQL API that requires auth headers (Telemetry API for example), you can use the same pattern as you would in the REST protected endpoints.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { DIMO } from '../../dimo';
|
|
2
|
+
import { decodeJwt, decodePermissions } from '../../util';
|
|
3
|
+
export const getVehicleJwt = async (input, env) => {
|
|
4
|
+
const sdk = new DIMO(env);
|
|
5
|
+
const developerJwt = input.headers.Authorization;
|
|
6
|
+
if (!developerJwt || !developerJwt.startsWith('Bearer ')) {
|
|
7
|
+
throw new Error('Invalid Authorization header format');
|
|
8
|
+
}
|
|
9
|
+
// Remove "Bearer " prefix
|
|
10
|
+
const decodedToken = decodeJwt(developerJwt.slice(7));
|
|
11
|
+
const clientId = decodedToken.ethereum_address;
|
|
12
|
+
const privileges = await sdk.identity.getVehiclePrivileges({
|
|
13
|
+
tokenId: input.tokenId,
|
|
14
|
+
clientId: clientId // We want to pass in the clientId
|
|
15
|
+
});
|
|
16
|
+
const decodedPrivileges = decodePermissions(privileges[0].permissions);
|
|
17
|
+
const vehicleJwt = await sdk.tokenexchange.exchange({
|
|
18
|
+
...input,
|
|
19
|
+
privileges: decodedPrivileges,
|
|
20
|
+
tokenId: input.tokenId
|
|
21
|
+
});
|
|
22
|
+
return vehicleJwt;
|
|
23
|
+
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getDeveloperJwt } from "./getDeveloperJwt";
|
|
2
|
+
import { getVehicleJwt } from "./getVehicleJwt";
|
|
2
3
|
import { signChallenge } from "./signChallenge";
|
|
3
|
-
export {
|
|
4
|
+
export { getDeveloperJwt, getVehicleJwt, signChallenge };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getDeveloperJwt } from "./getDeveloperJwt";
|
|
2
|
+
import { getVehicleJwt } from "./getVehicleJwt";
|
|
2
3
|
import { signChallenge } from "./signChallenge";
|
|
3
|
-
export {
|
|
4
|
+
export { getDeveloperJwt, getVehicleJwt, signChallenge };
|
package/dist/constants.d.ts
CHANGED
|
@@ -7,5 +7,8 @@ export declare const DimoConstants: {
|
|
|
7
7
|
readonly NFT_address: "0x45fbCD3ef7361d156e8b16F5538AE36DEdf61Da8";
|
|
8
8
|
readonly RPC_provider: "https://eth.llamarpc.com";
|
|
9
9
|
};
|
|
10
|
+
readonly Query: {
|
|
11
|
+
readonly PAGE_SIZE: 100;
|
|
12
|
+
};
|
|
10
13
|
};
|
|
11
|
-
export type DimoConstants = typeof DimoConstants.Production | typeof DimoConstants.Dev;
|
|
14
|
+
export type DimoConstants = typeof DimoConstants.Production | typeof DimoConstants.Dev | typeof DimoConstants.Query;
|
package/dist/constants.js
CHANGED
package/dist/dimo.js
CHANGED
|
@@ -47,7 +47,7 @@ export class DIMO {
|
|
|
47
47
|
}
|
|
48
48
|
const data = fs.readFileSync('.credentials.json', 'utf8');
|
|
49
49
|
const credentials = JSON.parse(data);
|
|
50
|
-
const authHeader = await this.auth.
|
|
50
|
+
const authHeader = await this.auth.getDeveloperJwt({
|
|
51
51
|
client_id: credentials.client_id,
|
|
52
52
|
domain: credentials.redirect_uri,
|
|
53
53
|
private_key: credentials.private_key,
|
|
@@ -4,13 +4,10 @@ export declare const DimoEnvironment: {
|
|
|
4
4
|
readonly Auth: "https://auth.dimo.zone";
|
|
5
5
|
readonly Identity: "https://identity-api.dimo.zone/query";
|
|
6
6
|
readonly Devices: "https://devices-api.dimo.zone";
|
|
7
|
-
readonly DeviceData: "https://device-data-api.dimo.zone";
|
|
8
7
|
readonly DeviceDefinitions: "https://device-definitions-api.dimo.zone";
|
|
9
|
-
readonly Events: "https://events-api.dimo.zone";
|
|
10
8
|
readonly Telemetry: "https://telemetry-api.dimo.zone/query";
|
|
11
9
|
readonly TokenExchange: "https://token-exchange-api.dimo.zone";
|
|
12
10
|
readonly Trips: "https://trips-api.dimo.zone";
|
|
13
|
-
readonly User: "https://users-api.dimo.zone";
|
|
14
11
|
readonly Valuations: "https://valuations-api.dimo.zone";
|
|
15
12
|
readonly VehicleSignalDecoding: "https://vehicle-signal-decoding.dimo.zone";
|
|
16
13
|
};
|
|
@@ -19,13 +16,10 @@ export declare const DimoEnvironment: {
|
|
|
19
16
|
readonly Auth: "https://auth.dev.dimo.zone";
|
|
20
17
|
readonly Identity: "https://identity-api.dev.dimo.zone/query";
|
|
21
18
|
readonly Devices: "https://devices-api.dev.dimo.zone";
|
|
22
|
-
readonly DeviceData: "https://device-data-api.dev.dimo.zone";
|
|
23
19
|
readonly DeviceDefinitions: "https://device-definitions-api.dev.dimo.zone";
|
|
24
|
-
readonly Events: "https://events-api.dev.dimo.zone";
|
|
25
20
|
readonly Telemetry: "https://telemetry-api.dev.dimo.zone/query";
|
|
26
21
|
readonly TokenExchange: "https://token-exchange-api.dev.dimo.zone";
|
|
27
22
|
readonly Trips: "https://trips-api.dev.dimo.zone";
|
|
28
|
-
readonly User: "https://users-api.dev.dimo.zone";
|
|
29
23
|
readonly Valuations: "https://valuations-api.dev.dimo.zone";
|
|
30
24
|
readonly VehicleSignalDecoding: "https://vehicle-signal-decoding.dev.dimo.zone";
|
|
31
25
|
};
|
|
@@ -4,13 +4,10 @@ export const DimoEnvironment = {
|
|
|
4
4
|
'Auth': 'https://auth.dimo.zone',
|
|
5
5
|
'Identity': 'https://identity-api.dimo.zone/query',
|
|
6
6
|
'Devices': 'https://devices-api.dimo.zone',
|
|
7
|
-
'DeviceData': 'https://device-data-api.dimo.zone',
|
|
8
7
|
'DeviceDefinitions': 'https://device-definitions-api.dimo.zone',
|
|
9
|
-
'Events': 'https://events-api.dimo.zone',
|
|
10
8
|
'Telemetry': 'https://telemetry-api.dimo.zone/query',
|
|
11
9
|
'TokenExchange': 'https://token-exchange-api.dimo.zone',
|
|
12
10
|
'Trips': 'https://trips-api.dimo.zone',
|
|
13
|
-
'User': 'https://users-api.dimo.zone',
|
|
14
11
|
'Valuations': 'https://valuations-api.dimo.zone',
|
|
15
12
|
'VehicleSignalDecoding': 'https://vehicle-signal-decoding.dimo.zone'
|
|
16
13
|
},
|
|
@@ -19,13 +16,10 @@ export const DimoEnvironment = {
|
|
|
19
16
|
'Auth': 'https://auth.dev.dimo.zone',
|
|
20
17
|
'Identity': 'https://identity-api.dev.dimo.zone/query',
|
|
21
18
|
'Devices': 'https://devices-api.dev.dimo.zone',
|
|
22
|
-
'DeviceData': 'https://device-data-api.dev.dimo.zone',
|
|
23
19
|
'DeviceDefinitions': 'https://device-definitions-api.dev.dimo.zone',
|
|
24
|
-
'Events': 'https://events-api.dev.dimo.zone',
|
|
25
20
|
'Telemetry': 'https://telemetry-api.dev.dimo.zone/query',
|
|
26
21
|
'TokenExchange': 'https://token-exchange-api.dev.dimo.zone',
|
|
27
22
|
'Trips': 'https://trips-api.dev.dimo.zone',
|
|
28
|
-
'User': 'https://users-api.dev.dimo.zone',
|
|
29
23
|
'Valuations': 'https://valuations-api.dev.dimo.zone',
|
|
30
24
|
'VehicleSignalDecoding': 'https://vehicle-signal-decoding.dev.dimo.zone'
|
|
31
25
|
}
|
package/dist/graphql/Query.js
CHANGED
|
@@ -45,15 +45,14 @@ export const Query = async (resource, baseUrl, params = {}, env) => {
|
|
|
45
45
|
for (const key in variables) {
|
|
46
46
|
const placeholder = new RegExp(`\\$${key}\\b`, 'g');
|
|
47
47
|
if (variables[key] === true) {
|
|
48
|
-
if (
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
48
|
+
if (params[key] === undefined || params[key] === null) {
|
|
49
|
+
// ACC-303: Replace the placeholder with null string to handle pagination
|
|
50
|
+
query = query.replace(placeholder, "null");
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
const value = typeof params[key] === 'string' ? `"${params[key]}"` : params[key];
|
|
54
|
+
query = query.replace(placeholder, value);
|
|
54
55
|
}
|
|
55
|
-
const value = typeof params[key] === 'string' ? `"${params[key]}"` : params[key];
|
|
56
|
-
query = query.replace(placeholder, value);
|
|
57
56
|
}
|
|
58
57
|
}
|
|
59
58
|
try {
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { DIMO } from '../../dimo';
|
|
2
|
+
import { DimoError } from '../../errors';
|
|
3
|
+
import { paginate } from '../util/paginate';
|
|
4
|
+
export const getVehiclePrivileges = async (input, env) => {
|
|
5
|
+
const sdk = new DIMO(env);
|
|
6
|
+
try {
|
|
7
|
+
const getSacds = async (after) => {
|
|
8
|
+
const response = await sdk.identity.listSacdPerVehicleTokenId({
|
|
9
|
+
tokenId: input.tokenId,
|
|
10
|
+
after
|
|
11
|
+
});
|
|
12
|
+
const sacds = response.data?.vehicle?.sacds || [];
|
|
13
|
+
const pageInfo = response.data?.vehicle?.sacds.pageInfo || { endCursor: null };
|
|
14
|
+
const totalCount = response.data?.vehicle?.sacds?.totalCount || null;
|
|
15
|
+
if (input.clientId) {
|
|
16
|
+
const matchingSacd = sacds.nodes.find((sacd) => sacd.grantee === input.clientId);
|
|
17
|
+
if (matchingSacd) {
|
|
18
|
+
return {
|
|
19
|
+
nodes: [matchingSacd],
|
|
20
|
+
pageInfo: { endCursor: null },
|
|
21
|
+
totalCount: 1
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
nodes: sacds,
|
|
27
|
+
pageInfo,
|
|
28
|
+
totalCount
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
if (input.clientId) {
|
|
32
|
+
const { nodes } = await getSacds(undefined);
|
|
33
|
+
if (nodes.length > 0) {
|
|
34
|
+
return nodes;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return await paginate(getSacds);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
console.error(error);
|
|
41
|
+
throw new DimoError({
|
|
42
|
+
message: `Error getting vehicle privileges: ${error.message || error}`,
|
|
43
|
+
statusCode: 400
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Resource } from '../../Resource';
|
|
2
|
+
import { DimoConstants } from '../../../constants';
|
|
2
3
|
export class Identity extends Resource {
|
|
3
4
|
constructor(api, env) {
|
|
4
5
|
super(api, 'Identity', env);
|
|
@@ -6,14 +7,41 @@ export class Identity extends Resource {
|
|
|
6
7
|
query: true
|
|
7
8
|
}),
|
|
8
9
|
this.setQueries({
|
|
9
|
-
|
|
10
|
+
getVehiclePrivileges: {
|
|
11
|
+
method: 'FUNCTION',
|
|
12
|
+
path: 'getVehiclePrivileges',
|
|
13
|
+
},
|
|
14
|
+
listSacdPerVehicleTokenId: {
|
|
15
|
+
params: {
|
|
16
|
+
tokenId: true,
|
|
17
|
+
after: true
|
|
18
|
+
},
|
|
10
19
|
query: `
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
20
|
+
{
|
|
21
|
+
vehicle(tokenId: $tokenId) {
|
|
22
|
+
sacds(first: ${DimoConstants.Query.PAGE_SIZE}, after: $after) {
|
|
23
|
+
nodes {
|
|
24
|
+
permissions
|
|
25
|
+
grantee
|
|
26
|
+
}
|
|
27
|
+
totalCount
|
|
28
|
+
pageInfo {
|
|
29
|
+
startCursor
|
|
30
|
+
endCursor
|
|
31
|
+
}
|
|
15
32
|
}
|
|
16
|
-
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
`
|
|
36
|
+
},
|
|
37
|
+
countDimoVehicles: {
|
|
38
|
+
query: `
|
|
39
|
+
{
|
|
40
|
+
vehicles (first: ${DimoConstants.Query.PAGE_SIZE}) {
|
|
41
|
+
totalCount,
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
`
|
|
17
45
|
},
|
|
18
46
|
listVehicleDefinitionsPerAddress: {
|
|
19
47
|
params: {
|
|
@@ -21,80 +49,27 @@ export class Identity extends Resource {
|
|
|
21
49
|
limit: true
|
|
22
50
|
},
|
|
23
51
|
query: `
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
definition {
|
|
36
|
-
make
|
|
37
|
-
model
|
|
38
|
-
year
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
52
|
+
{
|
|
53
|
+
vehicles(filterBy: {owner: $address}, first: $limit) {
|
|
54
|
+
nodes {
|
|
55
|
+
aftermarketDevice {
|
|
56
|
+
tokenId
|
|
57
|
+
address
|
|
58
|
+
}
|
|
59
|
+
syntheticDevice {
|
|
60
|
+
address
|
|
61
|
+
tokenId
|
|
42
62
|
}
|
|
43
|
-
|
|
63
|
+
definition {
|
|
64
|
+
make
|
|
65
|
+
model
|
|
66
|
+
year
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
`
|
|
44
72
|
}
|
|
45
73
|
});
|
|
46
74
|
}
|
|
47
75
|
}
|
|
48
|
-
export const listVehicleDefinitionsPerAddress = (address, limit) => `
|
|
49
|
-
{
|
|
50
|
-
vehicles(filterBy: {owner: "${address}"}, first: ${limit}) {
|
|
51
|
-
nodes {
|
|
52
|
-
aftermarketDevice {
|
|
53
|
-
tokenId
|
|
54
|
-
address
|
|
55
|
-
}
|
|
56
|
-
syntheticDevice {
|
|
57
|
-
address
|
|
58
|
-
tokenId
|
|
59
|
-
}
|
|
60
|
-
definition {
|
|
61
|
-
make
|
|
62
|
-
model
|
|
63
|
-
year
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
`;
|
|
69
|
-
// export const getVehicleDetailsByTokenId = (tokenId: number) => `
|
|
70
|
-
// {
|
|
71
|
-
// vehicle (tokenId: ${tokenId}) {
|
|
72
|
-
// aftermarketDevice {
|
|
73
|
-
// tokenId
|
|
74
|
-
// address
|
|
75
|
-
// }
|
|
76
|
-
// syntheticDevice {
|
|
77
|
-
// address
|
|
78
|
-
// tokenId
|
|
79
|
-
// }
|
|
80
|
-
// definition {
|
|
81
|
-
// make
|
|
82
|
-
// model
|
|
83
|
-
// year
|
|
84
|
-
// }
|
|
85
|
-
// }
|
|
86
|
-
// }
|
|
87
|
-
// `;
|
|
88
|
-
// export const test = () => `
|
|
89
|
-
// {
|
|
90
|
-
// vehicles(filterBy: {owner: "0xf9D26323Ab49179A6d57C26515B01De018553787"}, first: 10) {
|
|
91
|
-
// nodes {
|
|
92
|
-
// definition {
|
|
93
|
-
// make
|
|
94
|
-
// model
|
|
95
|
-
// year
|
|
96
|
-
// }
|
|
97
|
-
// }
|
|
98
|
-
// }
|
|
99
|
-
// }
|
|
100
|
-
// `;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { DimoConstants } from '../../constants';
|
|
2
|
+
const pageSize = DimoConstants.Query.PAGE_SIZE;
|
|
3
|
+
export const paginate = async (fetchPage) => {
|
|
4
|
+
let after = null;
|
|
5
|
+
let result = [];
|
|
6
|
+
let totalCount = null;
|
|
7
|
+
let page = 0;
|
|
8
|
+
while (true) {
|
|
9
|
+
const response = await fetchPage(after ?? undefined);
|
|
10
|
+
const { nodes, pageInfo, totalCount: responseTotalCount } = response;
|
|
11
|
+
if (!nodes || !nodes.nodes) {
|
|
12
|
+
console.error('Invalid response: nodes is undefined or null', response);
|
|
13
|
+
throw new Error('Unexpected API response format');
|
|
14
|
+
}
|
|
15
|
+
// Capture totalCount from the first request
|
|
16
|
+
if (totalCount === null) {
|
|
17
|
+
totalCount = responseTotalCount ?? null; // Ensure fallback if totalCount is missing
|
|
18
|
+
if (totalCount === null) {
|
|
19
|
+
console.warn('Warning: totalCount is null. Defaulting to single page execution.');
|
|
20
|
+
totalCount = pageSize; // Assume at least one page if totalCount is unknown
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
result.push(...nodes.nodes);
|
|
24
|
+
page++;
|
|
25
|
+
const totalPages = Math.ceil(totalCount / pageSize);
|
|
26
|
+
if (page >= totalPages || nodes.nodes.length < pageSize) {
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
// Update the cursor
|
|
30
|
+
after = pageInfo.endCursor ?? null;
|
|
31
|
+
if (after === null && page < totalPages) {
|
|
32
|
+
console.warn(`Expected more pages (${page}/${totalPages}), but endCursor is null. Stopping pagination.`);
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
};
|