Skip to content

Commit 011b066

Browse files
authored
release: v0.6.0 (#119)
2 parents 1a6bffb + 847c456 commit 011b066

File tree

13 files changed

+102
-40
lines changed

13 files changed

+102
-40
lines changed

.openapi-generator/FILES

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ configuration.ts
2828
credentials/credentials.ts
2929
credentials/index.ts
3030
credentials/types.ts
31+
docs/opentelemetry.md
3132
errors.ts
3233
example/Makefile
3334
example/README.md
@@ -36,6 +37,7 @@ example/example1/package.json
3637
git_push.sh
3738
index.ts
3839
package.json
40+
telemetry.ts
3941
tests/client.test.ts
4042
tests/helpers/default-config.ts
4143
tests/helpers/index.ts

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Changelog
22

3+
## v0.6.0
4+
5+
### [0.6.0](https://github.com/openfga/js-sdk/compare/v0.5.0...v0.6.0) (2024-06-28)
6+
- feat: add opentelemetry metrics reporting (#117)
7+
38
## v0.5.0
49

510
### [0.5.0](https://github.com/openfga/js-sdk/compare/v0.4.0...v0.5.0) (2024-06-14)

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ This is an autogenerated JavaScript SDK for OpenFGA. It provides a wrapper aroun
4545
- [Retries](#retries)
4646
- [API Endpoints](#api-endpoints)
4747
- [Models](#models)
48+
- [OpenTelemetry](#opentelemetry)
4849
- [Contributing](#contributing)
4950
- [Issues](#issues)
5051
- [Pull Requests](#pull-requests)
@@ -711,6 +712,10 @@ const fgaClient = new OpenFgaClient({
711712
[Models](https://github.com/openfga/js-sdk/blob/main/apiModel.ts)
712713

713714

715+
### OpenTelemetry
716+
717+
This SDK supports producing metrics that can be consumed as part of an [OpenTelemetry](https://opentelemetry.io/) setup. For more information, please see [the documentation]((https://github.com/openfga/js-sdk/blob/main/docs/opentelemetry.md)
718+
714719
## Contributing
715720

716721
### Issues

api.ts

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ import {
2222
createRequestFunction,
2323
RequestArgs,
2424
CallResult,
25-
PromiseResult} from "./common";
25+
PromiseResult
26+
} from "./common";
2627
import { attributeNames } from "./telemetry";
2728
import { Configuration } from "./configuration";
2829
import { Credentials } from "./credentials";
@@ -757,8 +758,8 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials:
757758
async check(storeId: string, body: CheckRequest, options?: any): Promise<(axios?: AxiosInstance) => PromiseResult<CheckResponse>> {
758759
const localVarAxiosArgs = await localVarAxiosParamCreator.check(storeId, body, options);
759760
return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, {
760-
[attributeNames.requestStoreId]: storeId,
761761
[attributeNames.requestMethod]: "check",
762+
[attributeNames.requestStoreId]: storeId,
762763
[attributeNames.user]: body.tuple_key.user
763764
});
764765
},
@@ -771,8 +772,8 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials:
771772
*/
772773
async createStore(body: CreateStoreRequest, options?: any): Promise<(axios?: AxiosInstance) => PromiseResult<CreateStoreResponse>> {
773774
const localVarAxiosArgs = await localVarAxiosParamCreator.createStore(body, options);
774-
return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, {
775-
[attributeNames.requestMethod]: "createStore"
775+
return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, {
776+
[attributeNames.requestMethod]: "createStore",
776777
});
777778
},
778779
/**
@@ -784,7 +785,10 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials:
784785
*/
785786
async deleteStore(storeId: string, options?: any): Promise<(axios?: AxiosInstance) => PromiseResult<void>> {
786787
const localVarAxiosArgs = await localVarAxiosParamCreator.deleteStore(storeId, options);
787-
return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials);
788+
return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, {
789+
[attributeNames.requestMethod]: "deleteStore",
790+
[attributeNames.requestStoreId]: storeId,
791+
});
788792
},
789793
/**
790794
* The Expand API will return all users and usersets that have certain relationship with an object in a certain store. This is different from the `/stores/{store_id}/read` API in that both users and computed usersets are returned. Body parameters `tuple_key.object` and `tuple_key.relation` are all required. The response will return a tree whose leaves are the specific users and usersets. Union, intersection and difference operator are located in the intermediate nodes. ## Example To expand all users that have the `reader` relationship with object `document:2021-budget`, use the Expand API with the following request body ```json { \"tuple_key\": { \"object\": \"document:2021-budget\", \"relation\": \"reader\" }, \"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\" } ``` OpenFGA\'s response will be a userset tree of the users and usersets that have read access to the document. ```json { \"tree\":{ \"root\":{ \"type\":\"document:2021-budget#reader\", \"union\":{ \"nodes\":[ { \"type\":\"document:2021-budget#reader\", \"leaf\":{ \"users\":{ \"users\":[ \"user:bob\" ] } } }, { \"type\":\"document:2021-budget#reader\", \"leaf\":{ \"computed\":{ \"userset\":\"document:2021-budget#writer\" } } } ] } } } } ``` The caller can then call expand API for the `writer` relationship for the `document:2021-budget`.
@@ -797,8 +801,8 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials:
797801
async expand(storeId: string, body: ExpandRequest, options?: any): Promise<(axios?: AxiosInstance) => PromiseResult<ExpandResponse>> {
798802
const localVarAxiosArgs = await localVarAxiosParamCreator.expand(storeId, body, options);
799803
return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, {
804+
[attributeNames.requestMethod]: "expand",
800805
[attributeNames.requestStoreId]: storeId,
801-
[attributeNames.requestMethod]: "expand"
802806
});
803807
},
804808
/**
@@ -811,8 +815,8 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials:
811815
async getStore(storeId: string, options?: any): Promise<(axios?: AxiosInstance) => PromiseResult<GetStoreResponse>> {
812816
const localVarAxiosArgs = await localVarAxiosParamCreator.getStore(storeId, options);
813817
return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, {
814-
[attributeNames.requestStoreId]: storeId,
815-
[attributeNames.requestMethod]: "getStore"
818+
[attributeNames.requestMethod]: "getStore",
819+
[attributeNames.requestStoreId]: storeId,
816820
});
817821
},
818822
/**
@@ -826,8 +830,8 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials:
826830
async listObjects(storeId: string, body: ListObjectsRequest, options?: any): Promise<(axios?: AxiosInstance) => PromiseResult<ListObjectsResponse>> {
827831
const localVarAxiosArgs = await localVarAxiosParamCreator.listObjects(storeId, body, options);
828832
return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, {
829-
[attributeNames.requestStoreId]: storeId,
830833
[attributeNames.requestMethod]: "listObjects",
834+
[attributeNames.requestStoreId]: storeId,
831835
[attributeNames.user]: body.user
832836
});
833837
},
@@ -841,8 +845,8 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials:
841845
*/
842846
async listStores(pageSize?: number, continuationToken?: string, options?: any): Promise<(axios?: AxiosInstance) => PromiseResult<ListStoresResponse>> {
843847
const localVarAxiosArgs = await localVarAxiosParamCreator.listStores(pageSize, continuationToken, options);
844-
return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, {
845-
[attributeNames.requestMethod]: "listStores"
848+
return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, {
849+
[attributeNames.requestMethod]: "listStores",
846850
});
847851
},
848852
/**
@@ -856,8 +860,8 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials:
856860
async listUsers(storeId: string, body: ListUsersRequest, options?: any): Promise<(axios?: AxiosInstance) => PromiseResult<ListUsersResponse>> {
857861
const localVarAxiosArgs = await localVarAxiosParamCreator.listUsers(storeId, body, options);
858862
return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, {
859-
[attributeNames.requestStoreId]: storeId,
860-
[attributeNames.requestMethod]: "listUsers"
863+
[attributeNames.requestMethod]: "listUsers",
864+
[attributeNames.requestStoreId]: storeId,
861865
});
862866
},
863867
/**
@@ -871,8 +875,8 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials:
871875
async read(storeId: string, body: ReadRequest, options?: any): Promise<(axios?: AxiosInstance) => PromiseResult<ReadResponse>> {
872876
const localVarAxiosArgs = await localVarAxiosParamCreator.read(storeId, body, options);
873877
return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, {
874-
[attributeNames.requestStoreId]: storeId,
875-
[attributeNames.requestMethod]: "read"
878+
[attributeNames.requestMethod]: "read",
879+
[attributeNames.requestStoreId]: storeId,
876880
});
877881
},
878882
/**
@@ -886,8 +890,8 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials:
886890
async readAssertions(storeId: string, authorizationModelId: string, options?: any): Promise<(axios?: AxiosInstance) => PromiseResult<ReadAssertionsResponse>> {
887891
const localVarAxiosArgs = await localVarAxiosParamCreator.readAssertions(storeId, authorizationModelId, options);
888892
return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, {
889-
[attributeNames.requestStoreId]: storeId,
890-
[attributeNames.requestMethod]: "readAssertions"
893+
[attributeNames.requestMethod]: "readAssertions",
894+
[attributeNames.requestStoreId]: storeId,
891895
});
892896
},
893897
/**
@@ -901,8 +905,8 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials:
901905
async readAuthorizationModel(storeId: string, id: string, options?: any): Promise<(axios?: AxiosInstance) => PromiseResult<ReadAuthorizationModelResponse>> {
902906
const localVarAxiosArgs = await localVarAxiosParamCreator.readAuthorizationModel(storeId, id, options);
903907
return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, {
904-
[attributeNames.requestStoreId]: storeId,
905-
[attributeNames.requestMethod]: "readAuthorizationModel"
908+
[attributeNames.requestMethod]: "readAuthorizationModel",
909+
[attributeNames.requestStoreId]: storeId,
906910
});
907911
},
908912
/**
@@ -917,8 +921,8 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials:
917921
async readAuthorizationModels(storeId: string, pageSize?: number, continuationToken?: string, options?: any): Promise<(axios?: AxiosInstance) => PromiseResult<ReadAuthorizationModelsResponse>> {
918922
const localVarAxiosArgs = await localVarAxiosParamCreator.readAuthorizationModels(storeId, pageSize, continuationToken, options);
919923
return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, {
920-
[attributeNames.requestStoreId]: storeId,
921-
[attributeNames.requestMethod]: "readAuthorizationModels"
924+
[attributeNames.requestMethod]: "readAuthorizationModels",
925+
[attributeNames.requestStoreId]: storeId,
922926
});
923927
},
924928
/**
@@ -934,8 +938,8 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials:
934938
async readChanges(storeId: string, type?: string, pageSize?: number, continuationToken?: string, options?: any): Promise<(axios?: AxiosInstance) => PromiseResult<ReadChangesResponse>> {
935939
const localVarAxiosArgs = await localVarAxiosParamCreator.readChanges(storeId, type, pageSize, continuationToken, options);
936940
return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, {
937-
[attributeNames.requestStoreId]: storeId,
938-
[attributeNames.requestMethod]: "readChanges"
941+
[attributeNames.requestMethod]: "readChanges",
942+
[attributeNames.requestStoreId]: storeId,
939943
});
940944
},
941945
/**
@@ -949,8 +953,8 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials:
949953
async write(storeId: string, body: WriteRequest, options?: any): Promise<(axios?: AxiosInstance) => PromiseResult<object>> {
950954
const localVarAxiosArgs = await localVarAxiosParamCreator.write(storeId, body, options);
951955
return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, {
952-
[attributeNames.requestStoreId]: storeId,
953-
[attributeNames.requestMethod]: "write"
956+
[attributeNames.requestMethod]: "write",
957+
[attributeNames.requestStoreId]: storeId,
954958
});
955959
},
956960
/**
@@ -965,8 +969,8 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials:
965969
async writeAssertions(storeId: string, authorizationModelId: string, body: WriteAssertionsRequest, options?: any): Promise<(axios?: AxiosInstance) => PromiseResult<void>> {
966970
const localVarAxiosArgs = await localVarAxiosParamCreator.writeAssertions(storeId, authorizationModelId, body, options);
967971
return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, {
968-
[attributeNames.requestStoreId]: storeId,
969-
[attributeNames.requestMethod]: "writeAssertions"
972+
[attributeNames.requestMethod]: "writeAssertions",
973+
[attributeNames.requestStoreId]: storeId,
970974
});
971975
},
972976
/**
@@ -980,8 +984,8 @@ export const OpenFgaApiFp = function(configuration: Configuration, credentials:
980984
async writeAuthorizationModel(storeId: string, body: WriteAuthorizationModelRequest, options?: any): Promise<(axios?: AxiosInstance) => PromiseResult<WriteAuthorizationModelResponse>> {
981985
const localVarAxiosArgs = await localVarAxiosParamCreator.writeAuthorizationModel(storeId, body, options);
982986
return createRequestFunction(localVarAxiosArgs, globalAxios, configuration, credentials, {
983-
[attributeNames.requestStoreId]: storeId,
984-
[attributeNames.requestMethod]: "writeAuthorizationModel"
987+
[attributeNames.requestMethod]: "writeAuthorizationModel",
988+
[attributeNames.requestStoreId]: storeId,
985989
});
986990
},
987991
};

common.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
1515
import { metrics } from "@opentelemetry/api";
1616

17-
1817
import { Configuration } from "./configuration";
1918
import type { Credentials } from "./credentials";
2019
import {
@@ -29,7 +28,7 @@ import {
2928
import { setNotEnumerableProperty } from "./utils";
3029
import { buildAttributes } from "./telemetry";
3130

32-
const meter = metrics.getMeter("@openfga/sdk", "0.5.0");
31+
const meter = metrics.getMeter("@openfga/sdk", "0.6.0");
3332
const durationHist = meter.createHistogram("fga-client.request.duration", {
3433
description: "The duration of requests",
3534
unit: "milliseconds",
@@ -230,4 +229,3 @@ export const createRequestFunction = function (axiosArgs: RequestArgs, axiosInst
230229
return result;
231230
};
232231
};
233-

configuration.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const DEFAULT_MAX_RETRY = 15;
2121
// default minimum wait period in retry - but will backoff exponentially
2222
const DEFAULT_MIN_WAIT_MS = 100;
2323

24-
const DEFAULT_USER_AGENT = "openfga-sdk js/0.5.0";
24+
const DEFAULT_USER_AGENT = "openfga-sdk js/0.6.0";
2525

2626
export interface RetryParams {
2727
maxRetry?: number;
@@ -73,7 +73,7 @@ export class Configuration {
7373
* @type {string}
7474
* @memberof Configuration
7575
*/
76-
private static sdkVersion = "0.5.0";
76+
private static sdkVersion = "0.6.0";
7777

7878
/**
7979
* provide the full api URL (e.g. `https://api.fga.example`)

credentials/credentials.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export class Credentials {
5252
}
5353
break;
5454
case CredentialsMethod.ClientCredentials: {
55-
const meter = metrics.getMeter("@openfga/sdk", "0.5.0");
55+
const meter = metrics.getMeter("@openfga/sdk", "0.6.0");
5656
this.tokenCounter = meter.createCounter("fga-client.credentials.request");
5757
break;
5858
}
@@ -122,6 +122,7 @@ export class Credentials {
122122
if (this.accessToken && (!this.accessTokenExpiryDate || this.accessTokenExpiryDate > new Date())) {
123123
return this.accessToken;
124124
}
125+
125126
return this.refreshAccessToken();
126127
}
127128
}
@@ -132,6 +133,7 @@ export class Credentials {
132133
*/
133134
private async refreshAccessToken() {
134135
const clientCredentials = (this.authConfig as { method: CredentialsMethod.ClientCredentials; config: ClientCredentialsConfig })?.config;
136+
135137
try {
136138
const response = await attemptHttpRequest<{
137139
client_id: string,
@@ -162,7 +164,9 @@ export class Credentials {
162164
this.accessToken = response.data.access_token;
163165
this.accessTokenExpiryDate = new Date(Date.now() + response.data.expires_in * 1000);
164166
}
167+
165168
this.tokenCounter?.add(1, buildAttributes(response, this.authConfig));
169+
166170
return this.accessToken;
167171
} catch (err: unknown) {
168172
if (err instanceof FgaApiError) {

docs/opentelemetry.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# OpenTelemetry
2+
3+
This SDK produces [metrics](https://opentelemetry.io/docs/concepts/signals/metrics/) using [OpenTelemetry](https://opentelemetry.io/) that allow you to view data such as request timings. These metrics also include attributes for the model and store ID, as well as the API called to allow you to build reporting.
4+
5+
When an OpenTelemetry SDK instance is configured, the metrics will be exported and sent to the collector configured as part of your applications configuration. If you are not using OpenTelemetry, the metric functionality is a no-op and the events are never sent.
6+
7+
In cases when metrics events are sent, they will not be viewable outside of infrastructure configured in your application, and are never available to the OpenFGA team or contributors.
8+
9+
## Metrics
10+
11+
### Supported Metrics
12+
13+
| Metric Name | Type | Description |
14+
|---------------------------------|-----------|---------------------------------------------------------------------------------|
15+
| `fga-client.request.duration` | Histogram | The total request time for FGA requests |
16+
| `fga-client.query.duration` | Histogram | The amount of time the FGA server took to process the request |
17+
|` fga-client.credentials.request`| Counter | The total number of times a new token was requested when using ClientCredentials|
18+
19+
### Supported attributes
20+
21+
| Attribute Name | Type | Description |
22+
|--------------------------------|----------|-------------------------------------------------------------------------------------|
23+
| `fga-client.response.model_id` | `string` | The authorization model ID that the FGA server used |
24+
| `fga-client.request.method` | `string` | The FGA method/action that was performed |
25+
| `fga-client.request.store_id` | `string` | The store ID that was sent as part of the request |
26+
| `fga-client.request.model_id` | `string` | The authorization model ID that was sent as part of the request, if any |
27+
| `fga-client.request.client_id` | `string` | The client ID associated with the request, if any |
28+
| `fga-client.user` | `string` | The user that is associated with the action of the request for check and list users |
29+
| `http.status_code ` | `int` | The status code of the response |
30+
| `http.method` | `string` | The HTTP method for the request |
31+
| `http.host` | `string` | Host identifier of the origin the request was sent to |

example/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ Steps
2828
2. In the Example `package.json` change the `@openfga/sdk` dependency from a semver range like below
2929
```json
3030
"dependencies": {
31-
"@openfga/sdk": "^0.5.0"
31+
"@openfga/sdk": "^0.6.0"
3232
}
3333
```
3434
to a `file:` reference like below

0 commit comments

Comments
 (0)