From f9b78790496fabed98c0fa62c88c766981146631 Mon Sep 17 00:00:00 2001 From: Nicklas Lundin Date: Tue, 19 Nov 2024 09:20:04 +0100 Subject: [PATCH 1/6] build: bump ts-proto to 2.3.0 this makes it possible to generate encode methods correctly --- packages/sdk/package.json | 2 +- .../confidence/flags/resolver/v1/api.ts | 23 ++- .../confidence/flags/resolver/v1/types.ts | 15 +- .../confidence/flags/types/v1/types.ts | 27 +++- .../src/generated/google/protobuf/struct.ts | 34 +++- .../generated/google/protobuf/timestamp.ts | 13 +- yarn.lock | 148 +++--------------- 7 files changed, 112 insertions(+), 150 deletions(-) diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 54ffea3c..51554e7b 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -30,7 +30,7 @@ "@microsoft/api-extractor": "7.43.1", "prettier": "*", "rollup": "4.24.0", - "ts-proto": "^1.171.0" + "ts-proto": "^2.3.0" }, "main": "dist/index.cjs.js", "module": "dist/index.esm.js" diff --git a/packages/sdk/src/generated/confidence/flags/resolver/v1/api.ts b/packages/sdk/src/generated/confidence/flags/resolver/v1/api.ts index 87da030b..a21c1ab4 100644 --- a/packages/sdk/src/generated/confidence/flags/resolver/v1/api.ts +++ b/packages/sdk/src/generated/confidence/flags/resolver/v1/api.ts @@ -1,3 +1,9 @@ +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v2.3.0 +// protoc v5.26.1 +// source: confidence/flags/resolver/v1/api.proto + /* eslint-disable */ import { Timestamp } from '../../../../google/protobuf/timestamp'; import { FlagSchema_StructFlagSchema } from '../../types/v1/types'; @@ -99,7 +105,7 @@ export interface ResolvedFlag { reason: ResolveReason; } -export const ResolveFlagsRequest = { +export const ResolveFlagsRequest: MessageFns = { fromJSON(object: any): ResolveFlagsRequest { return { flags: globalThis.Array.isArray(object?.flags) ? object.flags.map((e: any) => globalThis.String(e)) : [], @@ -131,7 +137,7 @@ export const ResolveFlagsRequest = { }, }; -export const ResolveFlagsResponse = { +export const ResolveFlagsResponse: MessageFns = { fromJSON(object: any): ResolveFlagsResponse { return { resolvedFlags: globalThis.Array.isArray(object?.resolvedFlags) @@ -157,7 +163,7 @@ export const ResolveFlagsResponse = { }, }; -export const ApplyFlagsRequest = { +export const ApplyFlagsRequest: MessageFns = { fromJSON(object: any): ApplyFlagsRequest { return { flags: globalThis.Array.isArray(object?.flags) ? object.flags.map((e: any) => AppliedFlag.fromJSON(e)) : [], @@ -189,7 +195,7 @@ export const ApplyFlagsRequest = { }, }; -export const ApplyFlagsResponse = { +export const ApplyFlagsResponse: MessageFns = { fromJSON(_: any): ApplyFlagsResponse { return {}; }, @@ -200,7 +206,7 @@ export const ApplyFlagsResponse = { }, }; -export const AppliedFlag = { +export const AppliedFlag: MessageFns = { fromJSON(object: any): AppliedFlag { return { flag: isSet(object.flag) ? globalThis.String(object.flag) : '', @@ -220,7 +226,7 @@ export const AppliedFlag = { }, }; -export const ResolvedFlag = { +export const ResolvedFlag: MessageFns = { fromJSON(object: any): ResolvedFlag { return { flag: isSet(object.flag) ? globalThis.String(object.flag) : '', @@ -300,3 +306,8 @@ function isObject(value: any): boolean { function isSet(value: any): boolean { return value !== null && value !== undefined; } + +export interface MessageFns { + fromJSON(object: any): T; + toJSON(message: T): unknown; +} diff --git a/packages/sdk/src/generated/confidence/flags/resolver/v1/types.ts b/packages/sdk/src/generated/confidence/flags/resolver/v1/types.ts index 860c9a0d..2f1222d3 100644 --- a/packages/sdk/src/generated/confidence/flags/resolver/v1/types.ts +++ b/packages/sdk/src/generated/confidence/flags/resolver/v1/types.ts @@ -1,3 +1,9 @@ +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v2.3.0 +// protoc v5.26.1 +// source: confidence/flags/resolver/v1/types.proto + /* eslint-disable */ export const protobufPackage = 'confidence.flags.resolver.v1'; @@ -12,6 +18,8 @@ export enum ResolveReason { /** * RESOLVE_REASON_NO_TREATMENT_MATCH - The flag could not be resolved because the matching rule had no variant * that could be assigned. + * + * @deprecated */ RESOLVE_REASON_NO_TREATMENT_MATCH = 3, /** RESOLVE_REASON_FLAG_ARCHIVED - The flag could not be resolved because it was archived. */ @@ -217,7 +225,7 @@ export interface Sdk { version: string; } -export const Sdk = { +export const Sdk: MessageFns = { fromJSON(object: any): Sdk { return { id: isSet(object.id) ? sdkIdFromJSON(object.id) : undefined, @@ -244,3 +252,8 @@ export const Sdk = { function isSet(value: any): boolean { return value !== null && value !== undefined; } + +export interface MessageFns { + fromJSON(object: any): T; + toJSON(message: T): unknown; +} diff --git a/packages/sdk/src/generated/confidence/flags/types/v1/types.ts b/packages/sdk/src/generated/confidence/flags/types/v1/types.ts index 4a6eefbf..7203a6db 100644 --- a/packages/sdk/src/generated/confidence/flags/types/v1/types.ts +++ b/packages/sdk/src/generated/confidence/flags/types/v1/types.ts @@ -1,3 +1,9 @@ +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v2.3.0 +// protoc v5.26.1 +// source: confidence/flags/types/v1/types.proto + /* eslint-disable */ export const protobufPackage = 'confidence.flags.types.v1'; @@ -73,7 +79,7 @@ export interface FlagSchema_ListFlagSchema { elementSchema: FlagSchema | undefined; } -export const FlagSchema = { +export const FlagSchema: MessageFns = { fromJSON(object: any): FlagSchema { return { structSchema: isSet(object.structSchema) ? FlagSchema_StructFlagSchema.fromJSON(object.structSchema) : undefined, @@ -109,7 +115,7 @@ export const FlagSchema = { }, }; -export const FlagSchema_StructFlagSchema = { +export const FlagSchema_StructFlagSchema: MessageFns = { fromJSON(object: any): FlagSchema_StructFlagSchema { return { schema: isObject(object.schema) @@ -136,7 +142,7 @@ export const FlagSchema_StructFlagSchema = { }, }; -export const FlagSchema_StructFlagSchema_SchemaEntry = { +export const FlagSchema_StructFlagSchema_SchemaEntry: MessageFns = { fromJSON(object: any): FlagSchema_StructFlagSchema_SchemaEntry { return { key: isSet(object.key) ? globalThis.String(object.key) : '', @@ -156,7 +162,7 @@ export const FlagSchema_StructFlagSchema_SchemaEntry = { }, }; -export const FlagSchema_DoubleFlagSchema = { +export const FlagSchema_DoubleFlagSchema: MessageFns = { fromJSON(_: any): FlagSchema_DoubleFlagSchema { return {}; }, @@ -167,7 +173,7 @@ export const FlagSchema_DoubleFlagSchema = { }, }; -export const FlagSchema_IntFlagSchema = { +export const FlagSchema_IntFlagSchema: MessageFns = { fromJSON(_: any): FlagSchema_IntFlagSchema { return {}; }, @@ -178,7 +184,7 @@ export const FlagSchema_IntFlagSchema = { }, }; -export const FlagSchema_StringFlagSchema = { +export const FlagSchema_StringFlagSchema: MessageFns = { fromJSON(_: any): FlagSchema_StringFlagSchema { return {}; }, @@ -189,7 +195,7 @@ export const FlagSchema_StringFlagSchema = { }, }; -export const FlagSchema_BoolFlagSchema = { +export const FlagSchema_BoolFlagSchema: MessageFns = { fromJSON(_: any): FlagSchema_BoolFlagSchema { return {}; }, @@ -200,7 +206,7 @@ export const FlagSchema_BoolFlagSchema = { }, }; -export const FlagSchema_ListFlagSchema = { +export const FlagSchema_ListFlagSchema: MessageFns = { fromJSON(object: any): FlagSchema_ListFlagSchema { return { elementSchema: isSet(object.elementSchema) ? FlagSchema.fromJSON(object.elementSchema) : undefined }; }, @@ -221,3 +227,8 @@ function isObject(value: any): boolean { function isSet(value: any): boolean { return value !== null && value !== undefined; } + +export interface MessageFns { + fromJSON(object: any): T; + toJSON(message: T): unknown; +} diff --git a/packages/sdk/src/generated/google/protobuf/struct.ts b/packages/sdk/src/generated/google/protobuf/struct.ts index 4227adb2..193f8438 100644 --- a/packages/sdk/src/generated/google/protobuf/struct.ts +++ b/packages/sdk/src/generated/google/protobuf/struct.ts @@ -1,3 +1,9 @@ +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v2.3.0 +// protoc v5.26.1 +// source: google/protobuf/struct.proto + /* eslint-disable */ export const protobufPackage = 'google.protobuf'; @@ -93,7 +99,7 @@ function createBaseStruct(): Struct { return { fields: {} }; } -export const Struct = { +export const Struct: MessageFns & StructWrapperFns = { fromJSON(object: any): Struct { return { fields: isObject(object.fields) @@ -141,7 +147,7 @@ export const Struct = { }, }; -export const Struct_FieldsEntry = { +export const Struct_FieldsEntry: MessageFns = { fromJSON(object: any): Struct_FieldsEntry { return { key: isSet(object.key) ? globalThis.String(object.key) : '', @@ -172,7 +178,7 @@ function createBaseValue(): Value { }; } -export const Value = { +export const Value: MessageFns & AnyValueWrapperFns = { fromJSON(object: any): Value { return { nullValue: isSet(object.nullValue) ? nullValueFromJSON(object.nullValue) : undefined, @@ -249,7 +255,7 @@ function createBaseListValue(): ListValue { return { values: [] }; } -export const ListValue = { +export const ListValue: MessageFns & ListValueWrapperFns = { fromJSON(object: any): ListValue { return { values: globalThis.Array.isArray(object?.values) ? [...object.values] : [] }; }, @@ -284,3 +290,23 @@ function isObject(value: any): boolean { function isSet(value: any): boolean { return value !== null && value !== undefined; } + +export interface MessageFns { + fromJSON(object: any): T; + toJSON(message: T): unknown; +} + +export interface StructWrapperFns { + wrap(object: { [key: string]: any } | undefined): Struct; + unwrap(message: Struct): { [key: string]: any }; +} + +export interface AnyValueWrapperFns { + wrap(value: any): Value; + unwrap(message: any): string | number | boolean | Object | null | Array | undefined; +} + +export interface ListValueWrapperFns { + wrap(array: Array | undefined): ListValue; + unwrap(message: ListValue): Array; +} diff --git a/packages/sdk/src/generated/google/protobuf/timestamp.ts b/packages/sdk/src/generated/google/protobuf/timestamp.ts index 5b042267..14e7bbba 100644 --- a/packages/sdk/src/generated/google/protobuf/timestamp.ts +++ b/packages/sdk/src/generated/google/protobuf/timestamp.ts @@ -1,3 +1,9 @@ +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v2.3.0 +// protoc v5.26.1 +// source: google/protobuf/timestamp.proto + /* eslint-disable */ export const protobufPackage = 'google.protobuf'; @@ -109,7 +115,7 @@ export interface Timestamp { nanos: number; } -export const Timestamp = { +export const Timestamp: MessageFns = { fromJSON(object: any): Timestamp { return { seconds: isSet(object.seconds) ? globalThis.Number(object.seconds) : 0, @@ -132,3 +138,8 @@ export const Timestamp = { function isSet(value: any): boolean { return value !== null && value !== undefined; } + +export interface MessageFns { + fromJSON(object: any): T; + toJSON(message: T): unknown; +} diff --git a/yarn.lock b/yarn.lock index ec7fde05..38ecfdd4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1986,6 +1986,13 @@ __metadata: languageName: node linkType: hard +"@bufbuild/protobuf@npm:^2.0.0": + version: 2.2.2 + resolution: "@bufbuild/protobuf@npm:2.2.2" + checksum: 10c0/17687c36c85b2e489c7ffd676479c54e12437270eb5a724775cb880b09948cad205b79e5822a4d10cefde0eef433b781350d73bb649d8de9e84d7745871ee719 + languageName: node + linkType: hard + "@commitlint/cli@npm:^17.6.7": version: 17.6.7 resolution: "@commitlint/cli@npm:17.6.7" @@ -3351,79 +3358,6 @@ __metadata: languageName: node linkType: hard -"@protobufjs/aspromise@npm:^1.1.1, @protobufjs/aspromise@npm:^1.1.2": - version: 1.1.2 - resolution: "@protobufjs/aspromise@npm:1.1.2" - checksum: 10c0/a83343a468ff5b5ec6bff36fd788a64c839e48a07ff9f4f813564f58caf44d011cd6504ed2147bf34835bd7a7dd2107052af755961c6b098fd8902b4f6500d0f - languageName: node - linkType: hard - -"@protobufjs/base64@npm:^1.1.2": - version: 1.1.2 - resolution: "@protobufjs/base64@npm:1.1.2" - checksum: 10c0/eec925e681081af190b8ee231f9bad3101e189abbc182ff279da6b531e7dbd2a56f1f306f37a80b1be9e00aa2d271690d08dcc5f326f71c9eed8546675c8caf6 - languageName: node - linkType: hard - -"@protobufjs/codegen@npm:^2.0.4": - version: 2.0.4 - resolution: "@protobufjs/codegen@npm:2.0.4" - checksum: 10c0/26ae337c5659e41f091606d16465bbcc1df1f37cc1ed462438b1f67be0c1e28dfb2ca9f294f39100c52161aef82edf758c95d6d75650a1ddf31f7ddee1440b43 - languageName: node - linkType: hard - -"@protobufjs/eventemitter@npm:^1.1.0": - version: 1.1.0 - resolution: "@protobufjs/eventemitter@npm:1.1.0" - checksum: 10c0/1eb0a75180e5206d1033e4138212a8c7089a3d418c6dfa5a6ce42e593a4ae2e5892c4ef7421f38092badba4040ea6a45f0928869989411001d8c1018ea9a6e70 - languageName: node - linkType: hard - -"@protobufjs/fetch@npm:^1.1.0": - version: 1.1.0 - resolution: "@protobufjs/fetch@npm:1.1.0" - dependencies: - "@protobufjs/aspromise": "npm:^1.1.1" - "@protobufjs/inquire": "npm:^1.1.0" - checksum: 10c0/cda6a3dc2d50a182c5865b160f72077aac197046600091dbb005dd0a66db9cce3c5eaed6d470ac8ed49d7bcbeef6ee5f0bc288db5ff9a70cbd003e5909065233 - languageName: node - linkType: hard - -"@protobufjs/float@npm:^1.0.2": - version: 1.0.2 - resolution: "@protobufjs/float@npm:1.0.2" - checksum: 10c0/18f2bdede76ffcf0170708af15c9c9db6259b771e6b84c51b06df34a9c339dbbeec267d14ce0bddd20acc142b1d980d983d31434398df7f98eb0c94a0eb79069 - languageName: node - linkType: hard - -"@protobufjs/inquire@npm:^1.1.0": - version: 1.1.0 - resolution: "@protobufjs/inquire@npm:1.1.0" - checksum: 10c0/64372482efcba1fb4d166a2664a6395fa978b557803857c9c03500e0ac1013eb4b1aacc9ed851dd5fc22f81583670b4f4431bae186f3373fedcfde863ef5921a - languageName: node - linkType: hard - -"@protobufjs/path@npm:^1.1.2": - version: 1.1.2 - resolution: "@protobufjs/path@npm:1.1.2" - checksum: 10c0/cece0a938e7f5dfd2fa03f8c14f2f1cf8b0d6e13ac7326ff4c96ea311effd5fb7ae0bba754fbf505312af2e38500250c90e68506b97c02360a43793d88a0d8b4 - languageName: node - linkType: hard - -"@protobufjs/pool@npm:^1.1.0": - version: 1.1.0 - resolution: "@protobufjs/pool@npm:1.1.0" - checksum: 10c0/eda2718b7f222ac6e6ad36f758a92ef90d26526026a19f4f17f668f45e0306a5bd734def3f48f51f8134ae0978b6262a5c517c08b115a551756d1a3aadfcf038 - languageName: node - linkType: hard - -"@protobufjs/utf8@npm:^1.1.0": - version: 1.1.0 - resolution: "@protobufjs/utf8@npm:1.1.0" - checksum: 10c0/a3fe31fe3fa29aa3349e2e04ee13dc170cc6af7c23d92ad49e3eeaf79b9766264544d3da824dba93b7855bd6a2982fb40032ef40693da98a136d835752beb487 - languageName: node - linkType: hard - "@rollup/plugin-babel@npm:^5.2.0": version: 5.3.1 resolution: "@rollup/plugin-babel@npm:5.3.1" @@ -3829,7 +3763,7 @@ __metadata: "@microsoft/api-extractor": "npm:7.43.1" prettier: "npm:*" rollup: "npm:4.24.0" - ts-proto: "npm:^1.171.0" + ts-proto: "npm:^2.3.0" web-vitals: "npm:^3.5.2" languageName: unknown linkType: soft @@ -4615,15 +4549,6 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:>=13.7.0": - version: 20.12.12 - resolution: "@types/node@npm:20.12.12" - dependencies: - undici-types: "npm:~5.26.4" - checksum: 10c0/f374b763c744e8f16e4f38cf6e2c0eef31781ec9228c9e43a6f267880fea420fab0a238b59f10a7cb3444e49547c5e3785787e371fc242307310995b21988812 - languageName: node - linkType: hard - "@types/node@npm:^16.7.13": version: 16.18.58 resolution: "@types/node@npm:16.18.58" @@ -12454,13 +12379,6 @@ __metadata: languageName: node linkType: hard -"long@npm:^5.0.0, long@npm:^5.2.3": - version: 5.2.3 - resolution: "long@npm:5.2.3" - checksum: 10c0/6a0da658f5ef683b90330b1af76f06790c623e148222da9d75b60e266bbf88f803232dd21464575681638894a84091616e7f89557aa087fd14116c0f4e0e43d9 - languageName: node - linkType: hard - "longest@npm:^2.0.1": version: 2.0.1 resolution: "longest@npm:2.0.1" @@ -14762,26 +14680,6 @@ __metadata: languageName: node linkType: hard -"protobufjs@npm:^7.2.4": - version: 7.3.0 - resolution: "protobufjs@npm:7.3.0" - dependencies: - "@protobufjs/aspromise": "npm:^1.1.2" - "@protobufjs/base64": "npm:^1.1.2" - "@protobufjs/codegen": "npm:^2.0.4" - "@protobufjs/eventemitter": "npm:^1.1.0" - "@protobufjs/fetch": "npm:^1.1.0" - "@protobufjs/float": "npm:^1.0.2" - "@protobufjs/inquire": "npm:^1.1.0" - "@protobufjs/path": "npm:^1.1.2" - "@protobufjs/pool": "npm:^1.1.0" - "@protobufjs/utf8": "npm:^1.1.0" - "@types/node": "npm:>=13.7.0" - long: "npm:^5.0.0" - checksum: 10c0/fdcd17a783a4d71dd46463419cdfb5a5e3ad07cf4d9460abb5bdeb2547b0fa77c55955ac26c38e5557f5169dc3909456c675a08c56268c0e79b34d348c05dcab - languageName: node - linkType: hard - "proxy-addr@npm:~2.0.7": version: 2.0.7 resolution: "proxy-addr@npm:2.0.7" @@ -17222,27 +17120,26 @@ __metadata: languageName: node linkType: hard -"ts-proto-descriptors@npm:1.16.0": - version: 1.16.0 - resolution: "ts-proto-descriptors@npm:1.16.0" +"ts-proto-descriptors@npm:2.0.0": + version: 2.0.0 + resolution: "ts-proto-descriptors@npm:2.0.0" dependencies: - long: "npm:^5.2.3" - protobufjs: "npm:^7.2.4" - checksum: 10c0/6e943b05ecd1f240ff443719479fe112e198d5bbf2d9ec7c3412511d555f85da485021286b424cedba52392dc23de49d3ea773f865f556c9c173446a948d5484 + "@bufbuild/protobuf": "npm:^2.0.0" + checksum: 10c0/a4f47a6db7de6b328a5b22bb0bed2a0dac929c28002567613db7980e0a8392b9148530e432a602a8c6b2cfda9909be9568a2e5c545f5624bb5d5eba52031c059 languageName: node linkType: hard -"ts-proto@npm:^1.171.0": - version: 1.176.0 - resolution: "ts-proto@npm:1.176.0" +"ts-proto@npm:^2.3.0": + version: 2.3.0 + resolution: "ts-proto@npm:2.3.0" dependencies: + "@bufbuild/protobuf": "npm:^2.0.0" case-anything: "npm:^2.1.13" - protobufjs: "npm:^7.2.4" ts-poet: "npm:^6.7.0" - ts-proto-descriptors: "npm:1.16.0" + ts-proto-descriptors: "npm:2.0.0" bin: protoc-gen-ts_proto: protoc-gen-ts_proto - checksum: 10c0/fa7b0b614d08d94e486a0b9af4414fae86bc90fe677241e595a208fceb2324ee7abad6851ae83ac1a4fc9dc6ba1ed1c9132d9212838272d090f17aac6d2c1ba6 + checksum: 10c0/0571c93c277c44718e364a61b26c3d8db5c44210b150cb0966cecb27bf09996f683355c33c0eec2e4c9c960a9ea27f8197d841777a51e3b34144472449c8066e languageName: node linkType: hard @@ -17502,13 +17399,6 @@ __metadata: languageName: node linkType: hard -"undici-types@npm:~5.26.4": - version: 5.26.5 - resolution: "undici-types@npm:5.26.5" - checksum: 10c0/bb673d7876c2d411b6eb6c560e0c571eef4a01c1c19925175d16e3a30c4c428181fb8d7ae802a261f283e4166a0ac435e2f505743aa9e45d893f9a3df017b501 - languageName: node - linkType: hard - "unicode-canonical-property-names-ecmascript@npm:^2.0.0": version: 2.0.0 resolution: "unicode-canonical-property-names-ecmascript@npm:2.0.0" From cc19f25f9edd65ae14dc29b90b0470360404c091 Mon Sep 17 00:00:00 2001 From: Nicklas Lundin Date: Tue, 19 Nov 2024 11:28:35 +0100 Subject: [PATCH 2/6] build: proto outputEncodeMethods=true --- api/sdk.api.md | 3 + packages/sdk/package.json | 3 +- .../confidence/flags/resolver/v1/api.ts | 374 ++++++++++++++++++ .../confidence/flags/resolver/v1/types.ts | 62 ++- .../confidence/flags/types/v1/types.ts | 315 +++++++++++++++ .../src/generated/google/protobuf/struct.ts | 202 ++++++++++ .../generated/google/protobuf/timestamp.ts | 60 +++ yarn.lock | 1 + 8 files changed, 1018 insertions(+), 2 deletions(-) diff --git a/api/sdk.api.md b/api/sdk.api.md index 8f6b3b96..a520a5e2 100644 --- a/api/sdk.api.md +++ b/api/sdk.api.md @@ -4,6 +4,9 @@ ```ts +import { BinaryReader } from '@bufbuild/protobuf/wire'; +import { BinaryWriter } from '@bufbuild/protobuf/wire'; + // @public export namespace Closer { export function combine(...closers: Closer[]): Closer; diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 51554e7b..227a4ac5 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -8,7 +8,7 @@ "node": ">=18.17.0" }, "scripts": { - "gen:proto": "protoc --plugin=$(yarn bin protoc-gen-ts_proto) --ts_proto_out=src/generated -I proto proto/confidence/flags/resolver/v1/api.proto --ts_proto_opt=outputEncodeMethods=false --ts_proto_opt=outputPartialMethods=false && prettier --config ../../prettier.config.js -w src/generated", + "gen:proto": "protoc --plugin=$(yarn bin protoc-gen-ts_proto) --ts_proto_out=src/generated -I proto proto/confidence/flags/resolver/v1/api.proto --ts_proto_opt=outputEncodeMethods=true --ts_proto_opt=outputPartialMethods=false && prettier --config ../../prettier.config.js -w src/generated", "build": "tsc -b", "bundle": "rollup -c && api-extractor run", "prepack": "yarn build && yarn bundle" @@ -21,6 +21,7 @@ "module": "dist/index.esm.js" }, "dependencies": { + "@bufbuild/protobuf": "^2.0.0", "web-vitals": "^3.5.2" }, "files": [ diff --git a/packages/sdk/src/generated/confidence/flags/resolver/v1/api.ts b/packages/sdk/src/generated/confidence/flags/resolver/v1/api.ts index a21c1ab4..e69649c8 100644 --- a/packages/sdk/src/generated/confidence/flags/resolver/v1/api.ts +++ b/packages/sdk/src/generated/confidence/flags/resolver/v1/api.ts @@ -5,6 +5,8 @@ // source: confidence/flags/resolver/v1/api.proto /* eslint-disable */ +import { BinaryReader, BinaryWriter } from '@bufbuild/protobuf/wire'; +import { Struct } from '../../../../google/protobuf/struct'; import { Timestamp } from '../../../../google/protobuf/timestamp'; import { FlagSchema_StructFlagSchema } from '../../types/v1/types'; import { ResolveReason, resolveReasonFromJSON, resolveReasonToJSON, Sdk } from './types'; @@ -105,7 +107,86 @@ export interface ResolvedFlag { reason: ResolveReason; } +function createBaseResolveFlagsRequest(): ResolveFlagsRequest { + return { flags: [], evaluationContext: undefined, clientSecret: '', apply: false, sdk: undefined }; +} + export const ResolveFlagsRequest: MessageFns = { + encode(message: ResolveFlagsRequest, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + for (const v of message.flags) { + writer.uint32(10).string(v!); + } + if (message.evaluationContext !== undefined) { + Struct.encode(Struct.wrap(message.evaluationContext), writer.uint32(18).fork()).join(); + } + if (message.clientSecret !== '') { + writer.uint32(26).string(message.clientSecret); + } + if (message.apply !== false) { + writer.uint32(32).bool(message.apply); + } + if (message.sdk !== undefined) { + Sdk.encode(message.sdk, writer.uint32(42).fork()).join(); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): ResolveFlagsRequest { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseResolveFlagsRequest(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 10) { + break; + } + + message.flags.push(reader.string()); + continue; + } + case 2: { + if (tag !== 18) { + break; + } + + message.evaluationContext = Struct.unwrap(Struct.decode(reader, reader.uint32())); + continue; + } + case 3: { + if (tag !== 26) { + break; + } + + message.clientSecret = reader.string(); + continue; + } + case 4: { + if (tag !== 32) { + break; + } + + message.apply = reader.bool(); + continue; + } + case 5: { + if (tag !== 42) { + break; + } + + message.sdk = Sdk.decode(reader, reader.uint32()); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + fromJSON(object: any): ResolveFlagsRequest { return { flags: globalThis.Array.isArray(object?.flags) ? object.flags.map((e: any) => globalThis.String(e)) : [], @@ -137,7 +218,64 @@ export const ResolveFlagsRequest: MessageFns = { }, }; +function createBaseResolveFlagsResponse(): ResolveFlagsResponse { + return { resolvedFlags: [], resolveToken: new Uint8Array(0), resolveId: '' }; +} + export const ResolveFlagsResponse: MessageFns = { + encode(message: ResolveFlagsResponse, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + for (const v of message.resolvedFlags) { + ResolvedFlag.encode(v!, writer.uint32(10).fork()).join(); + } + if (message.resolveToken.length !== 0) { + writer.uint32(18).bytes(message.resolveToken); + } + if (message.resolveId !== '') { + writer.uint32(26).string(message.resolveId); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): ResolveFlagsResponse { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseResolveFlagsResponse(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 10) { + break; + } + + message.resolvedFlags.push(ResolvedFlag.decode(reader, reader.uint32())); + continue; + } + case 2: { + if (tag !== 18) { + break; + } + + message.resolveToken = reader.bytes(); + continue; + } + case 3: { + if (tag !== 26) { + break; + } + + message.resolveId = reader.string(); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + fromJSON(object: any): ResolveFlagsResponse { return { resolvedFlags: globalThis.Array.isArray(object?.resolvedFlags) @@ -163,7 +301,86 @@ export const ResolveFlagsResponse: MessageFns = { }, }; +function createBaseApplyFlagsRequest(): ApplyFlagsRequest { + return { flags: [], clientSecret: '', resolveToken: new Uint8Array(0), sendTime: undefined, sdk: undefined }; +} + export const ApplyFlagsRequest: MessageFns = { + encode(message: ApplyFlagsRequest, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + for (const v of message.flags) { + AppliedFlag.encode(v!, writer.uint32(10).fork()).join(); + } + if (message.clientSecret !== '') { + writer.uint32(18).string(message.clientSecret); + } + if (message.resolveToken.length !== 0) { + writer.uint32(26).bytes(message.resolveToken); + } + if (message.sendTime !== undefined) { + Timestamp.encode(toTimestamp(message.sendTime), writer.uint32(34).fork()).join(); + } + if (message.sdk !== undefined) { + Sdk.encode(message.sdk, writer.uint32(42).fork()).join(); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): ApplyFlagsRequest { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseApplyFlagsRequest(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 10) { + break; + } + + message.flags.push(AppliedFlag.decode(reader, reader.uint32())); + continue; + } + case 2: { + if (tag !== 18) { + break; + } + + message.clientSecret = reader.string(); + continue; + } + case 3: { + if (tag !== 26) { + break; + } + + message.resolveToken = reader.bytes(); + continue; + } + case 4: { + if (tag !== 34) { + break; + } + + message.sendTime = fromTimestamp(Timestamp.decode(reader, reader.uint32())); + continue; + } + case 5: { + if (tag !== 42) { + break; + } + + message.sdk = Sdk.decode(reader, reader.uint32()); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + fromJSON(object: any): ApplyFlagsRequest { return { flags: globalThis.Array.isArray(object?.flags) ? object.flags.map((e: any) => AppliedFlag.fromJSON(e)) : [], @@ -195,7 +412,31 @@ export const ApplyFlagsRequest: MessageFns = { }, }; +function createBaseApplyFlagsResponse(): ApplyFlagsResponse { + return {}; +} + export const ApplyFlagsResponse: MessageFns = { + encode(_: ApplyFlagsResponse, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): ApplyFlagsResponse { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseApplyFlagsResponse(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + fromJSON(_: any): ApplyFlagsResponse { return {}; }, @@ -206,7 +447,53 @@ export const ApplyFlagsResponse: MessageFns = { }, }; +function createBaseAppliedFlag(): AppliedFlag { + return { flag: '', applyTime: undefined }; +} + export const AppliedFlag: MessageFns = { + encode(message: AppliedFlag, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + if (message.flag !== '') { + writer.uint32(10).string(message.flag); + } + if (message.applyTime !== undefined) { + Timestamp.encode(toTimestamp(message.applyTime), writer.uint32(18).fork()).join(); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): AppliedFlag { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseAppliedFlag(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 10) { + break; + } + + message.flag = reader.string(); + continue; + } + case 2: { + if (tag !== 18) { + break; + } + + message.applyTime = fromTimestamp(Timestamp.decode(reader, reader.uint32())); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + fromJSON(object: any): AppliedFlag { return { flag: isSet(object.flag) ? globalThis.String(object.flag) : '', @@ -226,7 +513,86 @@ export const AppliedFlag: MessageFns = { }, }; +function createBaseResolvedFlag(): ResolvedFlag { + return { flag: '', variant: '', value: undefined, flagSchema: undefined, reason: 0 }; +} + export const ResolvedFlag: MessageFns = { + encode(message: ResolvedFlag, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + if (message.flag !== '') { + writer.uint32(10).string(message.flag); + } + if (message.variant !== '') { + writer.uint32(18).string(message.variant); + } + if (message.value !== undefined) { + Struct.encode(Struct.wrap(message.value), writer.uint32(26).fork()).join(); + } + if (message.flagSchema !== undefined) { + FlagSchema_StructFlagSchema.encode(message.flagSchema, writer.uint32(34).fork()).join(); + } + if (message.reason !== 0) { + writer.uint32(40).int32(message.reason); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): ResolvedFlag { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseResolvedFlag(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 10) { + break; + } + + message.flag = reader.string(); + continue; + } + case 2: { + if (tag !== 18) { + break; + } + + message.variant = reader.string(); + continue; + } + case 3: { + if (tag !== 26) { + break; + } + + message.value = Struct.unwrap(Struct.decode(reader, reader.uint32())); + continue; + } + case 4: { + if (tag !== 34) { + break; + } + + message.flagSchema = FlagSchema_StructFlagSchema.decode(reader, reader.uint32()); + continue; + } + case 5: { + if (tag !== 40) { + break; + } + + message.reason = reader.int32() as any; + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + fromJSON(object: any): ResolvedFlag { return { flag: isSet(object.flag) ? globalThis.String(object.flag) : '', @@ -283,6 +649,12 @@ function base64FromBytes(arr: Uint8Array): string { } } +function toTimestamp(date: Date): Timestamp { + const seconds = Math.trunc(date.getTime() / 1_000); + const nanos = (date.getTime() % 1_000) * 1_000_000; + return { seconds, nanos }; +} + function fromTimestamp(t: Timestamp): Date { let millis = (t.seconds || 0) * 1_000; millis += (t.nanos || 0) / 1_000_000; @@ -308,6 +680,8 @@ function isSet(value: any): boolean { } export interface MessageFns { + encode(message: T, writer?: BinaryWriter): BinaryWriter; + decode(input: BinaryReader | Uint8Array, length?: number): T; fromJSON(object: any): T; toJSON(message: T): unknown; } diff --git a/packages/sdk/src/generated/confidence/flags/resolver/v1/types.ts b/packages/sdk/src/generated/confidence/flags/resolver/v1/types.ts index 2f1222d3..fc9df893 100644 --- a/packages/sdk/src/generated/confidence/flags/resolver/v1/types.ts +++ b/packages/sdk/src/generated/confidence/flags/resolver/v1/types.ts @@ -5,6 +5,7 @@ // source: confidence/flags/resolver/v1/types.proto /* eslint-disable */ +import { BinaryReader, BinaryWriter } from '@bufbuild/protobuf/wire'; export const protobufPackage = 'confidence.flags.resolver.v1'; @@ -19,7 +20,7 @@ export enum ResolveReason { * RESOLVE_REASON_NO_TREATMENT_MATCH - The flag could not be resolved because the matching rule had no variant * that could be assigned. * - * @deprecated + * @deprecated use RESOLVE_REASON_NO_SEGMENT_MATCH instead */ RESOLVE_REASON_NO_TREATMENT_MATCH = 3, /** RESOLVE_REASON_FLAG_ARCHIVED - The flag could not be resolved because it was archived. */ @@ -225,7 +226,64 @@ export interface Sdk { version: string; } +function createBaseSdk(): Sdk { + return { id: undefined, customId: undefined, version: '' }; +} + export const Sdk: MessageFns = { + encode(message: Sdk, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + if (message.id !== undefined) { + writer.uint32(8).int32(message.id); + } + if (message.customId !== undefined) { + writer.uint32(18).string(message.customId); + } + if (message.version !== '') { + writer.uint32(26).string(message.version); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): Sdk { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseSdk(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 8) { + break; + } + + message.id = reader.int32() as any; + continue; + } + case 2: { + if (tag !== 18) { + break; + } + + message.customId = reader.string(); + continue; + } + case 3: { + if (tag !== 26) { + break; + } + + message.version = reader.string(); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + fromJSON(object: any): Sdk { return { id: isSet(object.id) ? sdkIdFromJSON(object.id) : undefined, @@ -254,6 +312,8 @@ function isSet(value: any): boolean { } export interface MessageFns { + encode(message: T, writer?: BinaryWriter): BinaryWriter; + decode(input: BinaryReader | Uint8Array, length?: number): T; fromJSON(object: any): T; toJSON(message: T): unknown; } diff --git a/packages/sdk/src/generated/confidence/flags/types/v1/types.ts b/packages/sdk/src/generated/confidence/flags/types/v1/types.ts index 7203a6db..5e807efb 100644 --- a/packages/sdk/src/generated/confidence/flags/types/v1/types.ts +++ b/packages/sdk/src/generated/confidence/flags/types/v1/types.ts @@ -5,6 +5,7 @@ // source: confidence/flags/types/v1/types.proto /* eslint-disable */ +import { BinaryReader, BinaryWriter } from '@bufbuild/protobuf/wire'; export const protobufPackage = 'confidence.flags.types.v1'; @@ -79,7 +80,104 @@ export interface FlagSchema_ListFlagSchema { elementSchema: FlagSchema | undefined; } +function createBaseFlagSchema(): FlagSchema { + return { + structSchema: undefined, + listSchema: undefined, + intSchema: undefined, + doubleSchema: undefined, + stringSchema: undefined, + boolSchema: undefined, + }; +} + export const FlagSchema: MessageFns = { + encode(message: FlagSchema, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + if (message.structSchema !== undefined) { + FlagSchema_StructFlagSchema.encode(message.structSchema, writer.uint32(10).fork()).join(); + } + if (message.listSchema !== undefined) { + FlagSchema_ListFlagSchema.encode(message.listSchema, writer.uint32(18).fork()).join(); + } + if (message.intSchema !== undefined) { + FlagSchema_IntFlagSchema.encode(message.intSchema, writer.uint32(26).fork()).join(); + } + if (message.doubleSchema !== undefined) { + FlagSchema_DoubleFlagSchema.encode(message.doubleSchema, writer.uint32(34).fork()).join(); + } + if (message.stringSchema !== undefined) { + FlagSchema_StringFlagSchema.encode(message.stringSchema, writer.uint32(42).fork()).join(); + } + if (message.boolSchema !== undefined) { + FlagSchema_BoolFlagSchema.encode(message.boolSchema, writer.uint32(50).fork()).join(); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): FlagSchema { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseFlagSchema(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 10) { + break; + } + + message.structSchema = FlagSchema_StructFlagSchema.decode(reader, reader.uint32()); + continue; + } + case 2: { + if (tag !== 18) { + break; + } + + message.listSchema = FlagSchema_ListFlagSchema.decode(reader, reader.uint32()); + continue; + } + case 3: { + if (tag !== 26) { + break; + } + + message.intSchema = FlagSchema_IntFlagSchema.decode(reader, reader.uint32()); + continue; + } + case 4: { + if (tag !== 34) { + break; + } + + message.doubleSchema = FlagSchema_DoubleFlagSchema.decode(reader, reader.uint32()); + continue; + } + case 5: { + if (tag !== 42) { + break; + } + + message.stringSchema = FlagSchema_StringFlagSchema.decode(reader, reader.uint32()); + continue; + } + case 6: { + if (tag !== 50) { + break; + } + + message.boolSchema = FlagSchema_BoolFlagSchema.decode(reader, reader.uint32()); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + fromJSON(object: any): FlagSchema { return { structSchema: isSet(object.structSchema) ? FlagSchema_StructFlagSchema.fromJSON(object.structSchema) : undefined, @@ -115,7 +213,45 @@ export const FlagSchema: MessageFns = { }, }; +function createBaseFlagSchema_StructFlagSchema(): FlagSchema_StructFlagSchema { + return { schema: {} }; +} + export const FlagSchema_StructFlagSchema: MessageFns = { + encode(message: FlagSchema_StructFlagSchema, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + Object.entries(message.schema).forEach(([key, value]) => { + FlagSchema_StructFlagSchema_SchemaEntry.encode({ key: key as any, value }, writer.uint32(10).fork()).join(); + }); + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): FlagSchema_StructFlagSchema { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseFlagSchema_StructFlagSchema(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 10) { + break; + } + + const entry1 = FlagSchema_StructFlagSchema_SchemaEntry.decode(reader, reader.uint32()); + if (entry1.value !== undefined) { + message.schema[entry1.key] = entry1.value; + } + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + fromJSON(object: any): FlagSchema_StructFlagSchema { return { schema: isObject(object.schema) @@ -142,7 +278,53 @@ export const FlagSchema_StructFlagSchema: MessageFns = { + encode(message: FlagSchema_StructFlagSchema_SchemaEntry, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + if (message.key !== '') { + writer.uint32(10).string(message.key); + } + if (message.value !== undefined) { + FlagSchema.encode(message.value, writer.uint32(18).fork()).join(); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): FlagSchema_StructFlagSchema_SchemaEntry { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseFlagSchema_StructFlagSchema_SchemaEntry(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 10) { + break; + } + + message.key = reader.string(); + continue; + } + case 2: { + if (tag !== 18) { + break; + } + + message.value = FlagSchema.decode(reader, reader.uint32()); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + fromJSON(object: any): FlagSchema_StructFlagSchema_SchemaEntry { return { key: isSet(object.key) ? globalThis.String(object.key) : '', @@ -162,7 +344,31 @@ export const FlagSchema_StructFlagSchema_SchemaEntry: MessageFns = { + encode(_: FlagSchema_DoubleFlagSchema, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): FlagSchema_DoubleFlagSchema { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseFlagSchema_DoubleFlagSchema(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + fromJSON(_: any): FlagSchema_DoubleFlagSchema { return {}; }, @@ -173,7 +379,31 @@ export const FlagSchema_DoubleFlagSchema: MessageFns = { + encode(_: FlagSchema_IntFlagSchema, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): FlagSchema_IntFlagSchema { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseFlagSchema_IntFlagSchema(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + fromJSON(_: any): FlagSchema_IntFlagSchema { return {}; }, @@ -184,7 +414,31 @@ export const FlagSchema_IntFlagSchema: MessageFns = { }, }; +function createBaseFlagSchema_StringFlagSchema(): FlagSchema_StringFlagSchema { + return {}; +} + export const FlagSchema_StringFlagSchema: MessageFns = { + encode(_: FlagSchema_StringFlagSchema, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): FlagSchema_StringFlagSchema { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseFlagSchema_StringFlagSchema(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + fromJSON(_: any): FlagSchema_StringFlagSchema { return {}; }, @@ -195,7 +449,31 @@ export const FlagSchema_StringFlagSchema: MessageFns = { + encode(_: FlagSchema_BoolFlagSchema, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): FlagSchema_BoolFlagSchema { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseFlagSchema_BoolFlagSchema(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + fromJSON(_: any): FlagSchema_BoolFlagSchema { return {}; }, @@ -206,7 +484,42 @@ export const FlagSchema_BoolFlagSchema: MessageFns = }, }; +function createBaseFlagSchema_ListFlagSchema(): FlagSchema_ListFlagSchema { + return { elementSchema: undefined }; +} + export const FlagSchema_ListFlagSchema: MessageFns = { + encode(message: FlagSchema_ListFlagSchema, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + if (message.elementSchema !== undefined) { + FlagSchema.encode(message.elementSchema, writer.uint32(10).fork()).join(); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): FlagSchema_ListFlagSchema { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseFlagSchema_ListFlagSchema(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 10) { + break; + } + + message.elementSchema = FlagSchema.decode(reader, reader.uint32()); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + fromJSON(object: any): FlagSchema_ListFlagSchema { return { elementSchema: isSet(object.elementSchema) ? FlagSchema.fromJSON(object.elementSchema) : undefined }; }, @@ -229,6 +542,8 @@ function isSet(value: any): boolean { } export interface MessageFns { + encode(message: T, writer?: BinaryWriter): BinaryWriter; + decode(input: BinaryReader | Uint8Array, length?: number): T; fromJSON(object: any): T; toJSON(message: T): unknown; } diff --git a/packages/sdk/src/generated/google/protobuf/struct.ts b/packages/sdk/src/generated/google/protobuf/struct.ts index 193f8438..927ff0d8 100644 --- a/packages/sdk/src/generated/google/protobuf/struct.ts +++ b/packages/sdk/src/generated/google/protobuf/struct.ts @@ -5,6 +5,7 @@ // source: google/protobuf/struct.proto /* eslint-disable */ +import { BinaryReader, BinaryWriter } from '@bufbuild/protobuf/wire'; export const protobufPackage = 'google.protobuf'; @@ -100,6 +101,42 @@ function createBaseStruct(): Struct { } export const Struct: MessageFns & StructWrapperFns = { + encode(message: Struct, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + Object.entries(message.fields).forEach(([key, value]) => { + if (value !== undefined) { + Struct_FieldsEntry.encode({ key: key as any, value }, writer.uint32(10).fork()).join(); + } + }); + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): Struct { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseStruct(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 10) { + break; + } + + const entry1 = Struct_FieldsEntry.decode(reader, reader.uint32()); + if (entry1.value !== undefined) { + message.fields[entry1.key] = entry1.value; + } + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + fromJSON(object: any): Struct { return { fields: isObject(object.fields) @@ -147,7 +184,53 @@ export const Struct: MessageFns & StructWrapperFns = { }, }; +function createBaseStruct_FieldsEntry(): Struct_FieldsEntry { + return { key: '', value: undefined }; +} + export const Struct_FieldsEntry: MessageFns = { + encode(message: Struct_FieldsEntry, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + if (message.key !== '') { + writer.uint32(10).string(message.key); + } + if (message.value !== undefined) { + Value.encode(Value.wrap(message.value), writer.uint32(18).fork()).join(); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): Struct_FieldsEntry { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseStruct_FieldsEntry(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 10) { + break; + } + + message.key = reader.string(); + continue; + } + case 2: { + if (tag !== 18) { + break; + } + + message.value = Value.unwrap(Value.decode(reader, reader.uint32())); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + fromJSON(object: any): Struct_FieldsEntry { return { key: isSet(object.key) ? globalThis.String(object.key) : '', @@ -179,6 +262,92 @@ function createBaseValue(): Value { } export const Value: MessageFns & AnyValueWrapperFns = { + encode(message: Value, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + if (message.nullValue !== undefined) { + writer.uint32(8).int32(message.nullValue); + } + if (message.numberValue !== undefined) { + writer.uint32(17).double(message.numberValue); + } + if (message.stringValue !== undefined) { + writer.uint32(26).string(message.stringValue); + } + if (message.boolValue !== undefined) { + writer.uint32(32).bool(message.boolValue); + } + if (message.structValue !== undefined) { + Struct.encode(Struct.wrap(message.structValue), writer.uint32(42).fork()).join(); + } + if (message.listValue !== undefined) { + ListValue.encode(ListValue.wrap(message.listValue), writer.uint32(50).fork()).join(); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): Value { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseValue(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 8) { + break; + } + + message.nullValue = reader.int32() as any; + continue; + } + case 2: { + if (tag !== 17) { + break; + } + + message.numberValue = reader.double(); + continue; + } + case 3: { + if (tag !== 26) { + break; + } + + message.stringValue = reader.string(); + continue; + } + case 4: { + if (tag !== 32) { + break; + } + + message.boolValue = reader.bool(); + continue; + } + case 5: { + if (tag !== 42) { + break; + } + + message.structValue = Struct.unwrap(Struct.decode(reader, reader.uint32())); + continue; + } + case 6: { + if (tag !== 50) { + break; + } + + message.listValue = ListValue.unwrap(ListValue.decode(reader, reader.uint32())); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + fromJSON(object: any): Value { return { nullValue: isSet(object.nullValue) ? nullValueFromJSON(object.nullValue) : undefined, @@ -256,6 +425,37 @@ function createBaseListValue(): ListValue { } export const ListValue: MessageFns & ListValueWrapperFns = { + encode(message: ListValue, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + for (const v of message.values) { + Value.encode(Value.wrap(v!), writer.uint32(10).fork()).join(); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): ListValue { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseListValue(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 10) { + break; + } + + message.values.push(Value.unwrap(Value.decode(reader, reader.uint32()))); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + fromJSON(object: any): ListValue { return { values: globalThis.Array.isArray(object?.values) ? [...object.values] : [] }; }, @@ -292,6 +492,8 @@ function isSet(value: any): boolean { } export interface MessageFns { + encode(message: T, writer?: BinaryWriter): BinaryWriter; + decode(input: BinaryReader | Uint8Array, length?: number): T; fromJSON(object: any): T; toJSON(message: T): unknown; } diff --git a/packages/sdk/src/generated/google/protobuf/timestamp.ts b/packages/sdk/src/generated/google/protobuf/timestamp.ts index 14e7bbba..7785f9f0 100644 --- a/packages/sdk/src/generated/google/protobuf/timestamp.ts +++ b/packages/sdk/src/generated/google/protobuf/timestamp.ts @@ -5,6 +5,7 @@ // source: google/protobuf/timestamp.proto /* eslint-disable */ +import { BinaryReader, BinaryWriter } from '@bufbuild/protobuf/wire'; export const protobufPackage = 'google.protobuf'; @@ -115,7 +116,53 @@ export interface Timestamp { nanos: number; } +function createBaseTimestamp(): Timestamp { + return { seconds: 0, nanos: 0 }; +} + export const Timestamp: MessageFns = { + encode(message: Timestamp, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + if (message.seconds !== 0) { + writer.uint32(8).int64(message.seconds); + } + if (message.nanos !== 0) { + writer.uint32(16).int32(message.nanos); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): Timestamp { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseTimestamp(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 8) { + break; + } + + message.seconds = longToNumber(reader.int64()); + continue; + } + case 2: { + if (tag !== 16) { + break; + } + + message.nanos = reader.int32(); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + fromJSON(object: any): Timestamp { return { seconds: isSet(object.seconds) ? globalThis.Number(object.seconds) : 0, @@ -135,11 +182,24 @@ export const Timestamp: MessageFns = { }, }; +function longToNumber(int64: { toString(): string }): number { + const num = globalThis.Number(int64.toString()); + if (num > globalThis.Number.MAX_SAFE_INTEGER) { + throw new globalThis.Error('Value is larger than Number.MAX_SAFE_INTEGER'); + } + if (num < globalThis.Number.MIN_SAFE_INTEGER) { + throw new globalThis.Error('Value is smaller than Number.MIN_SAFE_INTEGER'); + } + return num; +} + function isSet(value: any): boolean { return value !== null && value !== undefined; } export interface MessageFns { + encode(message: T, writer?: BinaryWriter): BinaryWriter; + decode(input: BinaryReader | Uint8Array, length?: number): T; fromJSON(object: any): T; toJSON(message: T): unknown; } diff --git a/yarn.lock b/yarn.lock index 38ecfdd4..46402416 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3760,6 +3760,7 @@ __metadata: version: 0.0.0-use.local resolution: "@spotify-confidence/sdk@workspace:packages/sdk" dependencies: + "@bufbuild/protobuf": "npm:^2.0.0" "@microsoft/api-extractor": "npm:7.43.1" prettier: "npm:*" rollup: "npm:4.24.0" From ed4f2814b92b43e4658c8e626e3ecde8727edc7e Mon Sep 17 00:00:00 2001 From: Nicklas Lundin Date: Tue, 19 Nov 2024 16:35:23 +0100 Subject: [PATCH 3/6] feat: wip add telemetry data to header --- packages/sdk/package.json | 2 +- .../confidence/telemetry/v1/telemetry.proto | 34 ++ packages/sdk/src/Confidence.ts | 4 + packages/sdk/src/FlagResolverClient.test.ts | 2 + packages/sdk/src/FlagResolverClient.ts | 51 ++- .../confidence/telemetry/v1/telemetry.ts | 348 ++++++++++++++++++ 6 files changed, 437 insertions(+), 4 deletions(-) create mode 100644 packages/sdk/proto/confidence/telemetry/v1/telemetry.proto create mode 100644 packages/sdk/src/generated/confidence/telemetry/v1/telemetry.ts diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 227a4ac5..dcdd07c8 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -8,7 +8,7 @@ "node": ">=18.17.0" }, "scripts": { - "gen:proto": "protoc --plugin=$(yarn bin protoc-gen-ts_proto) --ts_proto_out=src/generated -I proto proto/confidence/flags/resolver/v1/api.proto --ts_proto_opt=outputEncodeMethods=true --ts_proto_opt=outputPartialMethods=false && prettier --config ../../prettier.config.js -w src/generated", + "gen:proto": "protoc --plugin=$(yarn bin protoc-gen-ts_proto) --ts_proto_out=src/generated -I proto proto/confidence/flags/resolver/v1/api.proto proto/confidence/telemetry/v1/telemetry.proto --ts_proto_opt=outputEncodeMethods=true --ts_proto_opt=outputPartialMethods=false && prettier --config ../../prettier.config.js -w src/generated", "build": "tsc -b", "bundle": "rollup -c && api-extractor run", "prepack": "yarn build && yarn bundle" diff --git a/packages/sdk/proto/confidence/telemetry/v1/telemetry.proto b/packages/sdk/proto/confidence/telemetry/v1/telemetry.proto new file mode 100644 index 00000000..d2bd5559 --- /dev/null +++ b/packages/sdk/proto/confidence/telemetry/v1/telemetry.proto @@ -0,0 +1,34 @@ +syntax = "proto3"; + +package confidence.telemetry.v1; + +message Monitoring { + repeated LibraryTraces library_traces = 1; +} + +message LibraryTraces { + Library library = 1; + string library_version = 2; + repeated Trace traces = 3; + + message Trace { + TraceId id = 1; + // only used for timed events. + optional uint64 millisecond_duration = 2; + } + + enum Library { + LIBRARY_UNSPECIFIED = 0; + LIBRARY_CONFIDENCE = 1; + LIBRARY_OPEN_FEATURE = 2; + LIBRARY_REACT = 3; + } + + enum TraceId { + TRACE_ID_UNSPECIFIED = 0; + TRACE_ID_RESOLVE_LATENCY = 1; + TRACE_ID_STALE_FLAG = 2; + TRACE_ID_FLAG_TYPE_MISMATCH = 3; + TRACE_ID_WITH_CONTEXT = 4; + } +} diff --git a/packages/sdk/src/Confidence.ts b/packages/sdk/src/Confidence.ts index 12c52a49..9da20f24 100644 --- a/packages/sdk/src/Confidence.ts +++ b/packages/sdk/src/Confidence.ts @@ -37,6 +37,8 @@ export interface ConfidenceOptions { logger?: Logger; /** Sets an alternative resolve url */ resolveBaseUrl?: string; + /** Enable telemetry */ + enableTelemetry?: boolean; } /** @@ -333,6 +335,7 @@ export class Confidence implements EventSender, Trackable, FlagResolver { fetchImplementation = defaultFetchImplementation(), logger = defaultLogger(), resolveBaseUrl, + enableTelemetry = true, }: ConfidenceOptions): Confidence { const sdk = { id: SdkId.SDK_ID_JS_CONFIDENCE, @@ -346,6 +349,7 @@ export class Confidence implements EventSender, Trackable, FlagResolver { resolveTimeout: timeout, region, resolveBaseUrl, + enableTelemetry, }); if (environment === 'client') { flagResolverClient = new CachingFlagResolverClient(flagResolverClient, Number.POSITIVE_INFINITY); diff --git a/packages/sdk/src/FlagResolverClient.test.ts b/packages/sdk/src/FlagResolverClient.test.ts index 6115a212..9266ff3c 100644 --- a/packages/sdk/src/FlagResolverClient.test.ts +++ b/packages/sdk/src/FlagResolverClient.test.ts @@ -56,6 +56,7 @@ describe('Client environment Evaluation', () => { }, environment: 'client', resolveTimeout: 10, + enableTelemetry: true, }); describe('apply', () => { @@ -108,6 +109,7 @@ describe('Backend environment Evaluation', () => { }, environment: 'backend', resolveTimeout: 10, + enableTelemetry: true, }); it('should resolve a full flag object', async () => { diff --git a/packages/sdk/src/FlagResolverClient.ts b/packages/sdk/src/FlagResolverClient.ts index f37c5e45..b14cf885 100644 --- a/packages/sdk/src/FlagResolverClient.ts +++ b/packages/sdk/src/FlagResolverClient.ts @@ -11,12 +11,20 @@ import { AppliedFlag, } from './generated/confidence/flags/resolver/v1/api'; import { Sdk } from './generated/confidence/flags/resolver/v1/types'; +import { + LibraryTraces_Library, + LibraryTraces_TraceId, + Monitoring, +} from './generated/confidence/telemetry/v1/telemetry'; import { SimpleFetch } from './types'; const FLAG_PREFIX = 'flags/'; export class ResolveError extends Error { - constructor(public readonly code: FlagEvaluation.ErrorCode, message: string) { + constructor( + public readonly code: FlagEvaluation.ErrorCode, + message: string, + ) { super(message); } } @@ -85,6 +93,7 @@ export type FlagResolverClientOptions = { environment: 'client' | 'backend'; region?: 'eu' | 'us'; resolveBaseUrl?: string; + enableTelemetry: boolean; }; export class FetchingFlagResolverClient implements FlagResolverClient { @@ -105,9 +114,18 @@ export class FetchingFlagResolverClient implements FlagResolverClient { environment, region, resolveBaseUrl, + enableTelemetry, }: FlagResolverClientOptions) { - // TODO think about both resolve and apply request logic for backends - this.fetchImplementation = environment === 'backend' ? fetchImplementation : withRequestLogic(fetchImplementation); + if (!enableTelemetry) { + // TODO think about both resolve and apply request logic for backends + this.fetchImplementation = + environment === 'backend' ? fetchImplementation : withRequestLogic(fetchImplementation); + } else { + this.fetchImplementation = + environment === 'backend' + ? withTelemetryData(fetchImplementation) + : withRequestLogic(withTelemetryData(fetchImplementation)); + } this.clientSecret = clientSecret; this.sdk = sdk; this.applyTimeout = applyTimeout; @@ -275,6 +293,33 @@ export class CachingFlagResolverClient implements FlagResolverClient { } } +export function withTelemetryData(fetchImplementation: (request: Request) => Promise): typeof fetch { + return new FetchBuilder() + .modifyRequest(async request => { + // TODO pull actual telemetry data + const monitoring: Monitoring = { + libraryTraces: [ + { + library: LibraryTraces_Library.LIBRARY_CONFIDENCE, + libraryVersion: '0.1.0', + traces: [ + { + id: LibraryTraces_TraceId.TRACE_ID_RESOLVE_LATENCY, + millisecondDuration: 100, + }, + ], + }, + ], + }; + const headers = new Headers(request.headers); + const base64Message = btoa(String.fromCharCode(...Monitoring.encode(monitoring).finish())); + + headers.set('X-CONFIDENCE-TELEMETRY', base64Message); + return new Request(request, { headers }); + }) + .build(fetchImplementation); +} + export function withRequestLogic(fetchImplementation: (request: Request) => Promise): typeof fetch { const fetchResolve = new FetchBuilder() // infinite retries without delay until aborted by timeout diff --git a/packages/sdk/src/generated/confidence/telemetry/v1/telemetry.ts b/packages/sdk/src/generated/confidence/telemetry/v1/telemetry.ts new file mode 100644 index 00000000..a41c34c5 --- /dev/null +++ b/packages/sdk/src/generated/confidence/telemetry/v1/telemetry.ts @@ -0,0 +1,348 @@ +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v2.3.0 +// protoc v5.26.1 +// source: confidence/telemetry/v1/telemetry.proto + +/* eslint-disable */ +import { BinaryReader, BinaryWriter } from '@bufbuild/protobuf/wire'; + +export const protobufPackage = 'confidence.telemetry.v1'; + +export interface Monitoring { + libraryTraces: LibraryTraces[]; +} + +export interface LibraryTraces { + library: LibraryTraces_Library; + libraryVersion: string; + traces: LibraryTraces_Trace[]; +} + +export enum LibraryTraces_Library { + LIBRARY_UNSPECIFIED = 0, + LIBRARY_CONFIDENCE = 1, + LIBRARY_OPEN_FEATURE = 2, + LIBRARY_REACT = 3, + UNRECOGNIZED = -1, +} + +export function libraryTraces_LibraryFromJSON(object: any): LibraryTraces_Library { + switch (object) { + case 0: + case 'LIBRARY_UNSPECIFIED': + return LibraryTraces_Library.LIBRARY_UNSPECIFIED; + case 1: + case 'LIBRARY_CONFIDENCE': + return LibraryTraces_Library.LIBRARY_CONFIDENCE; + case 2: + case 'LIBRARY_OPEN_FEATURE': + return LibraryTraces_Library.LIBRARY_OPEN_FEATURE; + case 3: + case 'LIBRARY_REACT': + return LibraryTraces_Library.LIBRARY_REACT; + case -1: + case 'UNRECOGNIZED': + default: + return LibraryTraces_Library.UNRECOGNIZED; + } +} + +export function libraryTraces_LibraryToJSON(object: LibraryTraces_Library): string { + switch (object) { + case LibraryTraces_Library.LIBRARY_UNSPECIFIED: + return 'LIBRARY_UNSPECIFIED'; + case LibraryTraces_Library.LIBRARY_CONFIDENCE: + return 'LIBRARY_CONFIDENCE'; + case LibraryTraces_Library.LIBRARY_OPEN_FEATURE: + return 'LIBRARY_OPEN_FEATURE'; + case LibraryTraces_Library.LIBRARY_REACT: + return 'LIBRARY_REACT'; + case LibraryTraces_Library.UNRECOGNIZED: + default: + return 'UNRECOGNIZED'; + } +} + +export enum LibraryTraces_TraceId { + TRACE_ID_UNSPECIFIED = 0, + TRACE_ID_RESOLVE_LATENCY = 1, + TRACE_ID_STALE_FLAG = 2, + TRACE_ID_FLAG_TYPE_MISMATCH = 3, + TRACE_ID_WITH_CONTEXT = 4, + UNRECOGNIZED = -1, +} + +export function libraryTraces_TraceIdFromJSON(object: any): LibraryTraces_TraceId { + switch (object) { + case 0: + case 'TRACE_ID_UNSPECIFIED': + return LibraryTraces_TraceId.TRACE_ID_UNSPECIFIED; + case 1: + case 'TRACE_ID_RESOLVE_LATENCY': + return LibraryTraces_TraceId.TRACE_ID_RESOLVE_LATENCY; + case 2: + case 'TRACE_ID_STALE_FLAG': + return LibraryTraces_TraceId.TRACE_ID_STALE_FLAG; + case 3: + case 'TRACE_ID_FLAG_TYPE_MISMATCH': + return LibraryTraces_TraceId.TRACE_ID_FLAG_TYPE_MISMATCH; + case 4: + case 'TRACE_ID_WITH_CONTEXT': + return LibraryTraces_TraceId.TRACE_ID_WITH_CONTEXT; + case -1: + case 'UNRECOGNIZED': + default: + return LibraryTraces_TraceId.UNRECOGNIZED; + } +} + +export function libraryTraces_TraceIdToJSON(object: LibraryTraces_TraceId): string { + switch (object) { + case LibraryTraces_TraceId.TRACE_ID_UNSPECIFIED: + return 'TRACE_ID_UNSPECIFIED'; + case LibraryTraces_TraceId.TRACE_ID_RESOLVE_LATENCY: + return 'TRACE_ID_RESOLVE_LATENCY'; + case LibraryTraces_TraceId.TRACE_ID_STALE_FLAG: + return 'TRACE_ID_STALE_FLAG'; + case LibraryTraces_TraceId.TRACE_ID_FLAG_TYPE_MISMATCH: + return 'TRACE_ID_FLAG_TYPE_MISMATCH'; + case LibraryTraces_TraceId.TRACE_ID_WITH_CONTEXT: + return 'TRACE_ID_WITH_CONTEXT'; + case LibraryTraces_TraceId.UNRECOGNIZED: + default: + return 'UNRECOGNIZED'; + } +} + +export interface LibraryTraces_Trace { + id: LibraryTraces_TraceId; + /** only used for timed events. */ + millisecondDuration?: number | undefined; +} + +function createBaseMonitoring(): Monitoring { + return { libraryTraces: [] }; +} + +export const Monitoring: MessageFns = { + encode(message: Monitoring, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + for (const v of message.libraryTraces) { + LibraryTraces.encode(v!, writer.uint32(10).fork()).join(); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): Monitoring { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseMonitoring(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 10) { + break; + } + + message.libraryTraces.push(LibraryTraces.decode(reader, reader.uint32())); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): Monitoring { + return { + libraryTraces: globalThis.Array.isArray(object?.libraryTraces) + ? object.libraryTraces.map((e: any) => LibraryTraces.fromJSON(e)) + : [], + }; + }, + + toJSON(message: Monitoring): unknown { + const obj: any = {}; + if (message.libraryTraces?.length) { + obj.libraryTraces = message.libraryTraces.map(e => LibraryTraces.toJSON(e)); + } + return obj; + }, +}; + +function createBaseLibraryTraces(): LibraryTraces { + return { library: 0, libraryVersion: '', traces: [] }; +} + +export const LibraryTraces: MessageFns = { + encode(message: LibraryTraces, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + if (message.library !== 0) { + writer.uint32(8).int32(message.library); + } + if (message.libraryVersion !== '') { + writer.uint32(18).string(message.libraryVersion); + } + for (const v of message.traces) { + LibraryTraces_Trace.encode(v!, writer.uint32(26).fork()).join(); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): LibraryTraces { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseLibraryTraces(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 8) { + break; + } + + message.library = reader.int32() as any; + continue; + } + case 2: { + if (tag !== 18) { + break; + } + + message.libraryVersion = reader.string(); + continue; + } + case 3: { + if (tag !== 26) { + break; + } + + message.traces.push(LibraryTraces_Trace.decode(reader, reader.uint32())); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): LibraryTraces { + return { + library: isSet(object.library) ? libraryTraces_LibraryFromJSON(object.library) : 0, + libraryVersion: isSet(object.libraryVersion) ? globalThis.String(object.libraryVersion) : '', + traces: globalThis.Array.isArray(object?.traces) + ? object.traces.map((e: any) => LibraryTraces_Trace.fromJSON(e)) + : [], + }; + }, + + toJSON(message: LibraryTraces): unknown { + const obj: any = {}; + if (message.library !== 0) { + obj.library = libraryTraces_LibraryToJSON(message.library); + } + if (message.libraryVersion !== '') { + obj.libraryVersion = message.libraryVersion; + } + if (message.traces?.length) { + obj.traces = message.traces.map(e => LibraryTraces_Trace.toJSON(e)); + } + return obj; + }, +}; + +function createBaseLibraryTraces_Trace(): LibraryTraces_Trace { + return { id: 0, millisecondDuration: undefined }; +} + +export const LibraryTraces_Trace: MessageFns = { + encode(message: LibraryTraces_Trace, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + if (message.id !== 0) { + writer.uint32(8).int32(message.id); + } + if (message.millisecondDuration !== undefined) { + writer.uint32(16).uint64(message.millisecondDuration); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): LibraryTraces_Trace { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseLibraryTraces_Trace(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 8) { + break; + } + + message.id = reader.int32() as any; + continue; + } + case 2: { + if (tag !== 16) { + break; + } + + message.millisecondDuration = longToNumber(reader.uint64()); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): LibraryTraces_Trace { + return { + id: isSet(object.id) ? libraryTraces_TraceIdFromJSON(object.id) : 0, + millisecondDuration: isSet(object.millisecondDuration) + ? globalThis.Number(object.millisecondDuration) + : undefined, + }; + }, + + toJSON(message: LibraryTraces_Trace): unknown { + const obj: any = {}; + if (message.id !== 0) { + obj.id = libraryTraces_TraceIdToJSON(message.id); + } + if (message.millisecondDuration !== undefined) { + obj.millisecondDuration = Math.round(message.millisecondDuration); + } + return obj; + }, +}; + +function longToNumber(int64: { toString(): string }): number { + const num = globalThis.Number(int64.toString()); + if (num > globalThis.Number.MAX_SAFE_INTEGER) { + throw new globalThis.Error('Value is larger than Number.MAX_SAFE_INTEGER'); + } + if (num < globalThis.Number.MIN_SAFE_INTEGER) { + throw new globalThis.Error('Value is smaller than Number.MIN_SAFE_INTEGER'); + } + return num; +} + +function isSet(value: any): boolean { + return value !== null && value !== undefined; +} + +export interface MessageFns { + encode(message: T, writer?: BinaryWriter): BinaryWriter; + decode(input: BinaryReader | Uint8Array, length?: number): T; + fromJSON(object: any): T; + toJSON(message: T): unknown; +} From 7892603542da346cea855e2e3cb44b995ee8ed32 Mon Sep 17 00:00:00 2001 From: Nicklas Lundin Date: Wed, 20 Nov 2024 16:50:01 +0100 Subject: [PATCH 4/6] fix: wip telemetry singleton --- api/sdk.api.md | 3 +- packages/sdk/src/Confidence.ts | 8 +-- packages/sdk/src/FlagResolverClient.test.ts | 4 +- packages/sdk/src/FlagResolverClient.ts | 37 ++++-------- packages/sdk/src/Telemetry.ts | 67 +++++++++++++++++++++ 5 files changed, 86 insertions(+), 33 deletions(-) create mode 100644 packages/sdk/src/Telemetry.ts diff --git a/api/sdk.api.md b/api/sdk.api.md index a520a5e2..653cdfa5 100644 --- a/api/sdk.api.md +++ b/api/sdk.api.md @@ -25,7 +25,7 @@ export class Confidence implements EventSender, Trackable, FlagResolver { // // @internal readonly contextChanges: Subscribe; - static create({ clientSecret, region, timeout, environment, fetchImplementation, logger, resolveBaseUrl, }: ConfidenceOptions): Confidence; + static create({ clientSecret, region, timeout, environment, fetchImplementation, logger, resolveBaseUrl, disableTelemetry, }: ConfidenceOptions): Confidence; get environment(): string; evaluateFlag(path: string, defaultValue: string): FlagEvaluation; // (undocumented) @@ -55,6 +55,7 @@ export class Confidence implements EventSender, Trackable, FlagResolver { // @public export interface ConfidenceOptions { clientSecret: string; + disableTelemetry?: boolean; environment: 'client' | 'backend'; // Warning: (ae-forgotten-export) The symbol "SimpleFetch" needs to be exported by the entry point index.d.ts fetchImplementation?: SimpleFetch; diff --git a/packages/sdk/src/Confidence.ts b/packages/sdk/src/Confidence.ts index 9da20f24..8e17982e 100644 --- a/packages/sdk/src/Confidence.ts +++ b/packages/sdk/src/Confidence.ts @@ -37,8 +37,8 @@ export interface ConfidenceOptions { logger?: Logger; /** Sets an alternative resolve url */ resolveBaseUrl?: string; - /** Enable telemetry */ - enableTelemetry?: boolean; + /** Disable telemetry */ + disableTelemetry?: boolean; } /** @@ -335,7 +335,7 @@ export class Confidence implements EventSender, Trackable, FlagResolver { fetchImplementation = defaultFetchImplementation(), logger = defaultLogger(), resolveBaseUrl, - enableTelemetry = true, + disableTelemetry = false, }: ConfidenceOptions): Confidence { const sdk = { id: SdkId.SDK_ID_JS_CONFIDENCE, @@ -349,7 +349,7 @@ export class Confidence implements EventSender, Trackable, FlagResolver { resolveTimeout: timeout, region, resolveBaseUrl, - enableTelemetry, + disableTelemetry, }); if (environment === 'client') { flagResolverClient = new CachingFlagResolverClient(flagResolverClient, Number.POSITIVE_INFINITY); diff --git a/packages/sdk/src/FlagResolverClient.test.ts b/packages/sdk/src/FlagResolverClient.test.ts index 9266ff3c..b679aebe 100644 --- a/packages/sdk/src/FlagResolverClient.test.ts +++ b/packages/sdk/src/FlagResolverClient.test.ts @@ -56,7 +56,7 @@ describe('Client environment Evaluation', () => { }, environment: 'client', resolveTimeout: 10, - enableTelemetry: true, + disableTelemetry: false, }); describe('apply', () => { @@ -109,7 +109,7 @@ describe('Backend environment Evaluation', () => { }, environment: 'backend', resolveTimeout: 10, - enableTelemetry: true, + disableTelemetry: false, }); it('should resolve a full flag object', async () => { diff --git a/packages/sdk/src/FlagResolverClient.ts b/packages/sdk/src/FlagResolverClient.ts index b14cf885..06eabcde 100644 --- a/packages/sdk/src/FlagResolverClient.ts +++ b/packages/sdk/src/FlagResolverClient.ts @@ -1,6 +1,7 @@ import { FlagEvaluation } from '.'; import { AccessiblePromise } from './AccessiblePromise'; import { Applier, FlagResolution } from './FlagResolution'; +import Telemetry from './Telemetry'; import { Value } from './Value'; import { Context } from './context'; import { FetchBuilder, TimeUnit } from './fetch-util'; @@ -11,20 +12,13 @@ import { AppliedFlag, } from './generated/confidence/flags/resolver/v1/api'; import { Sdk } from './generated/confidence/flags/resolver/v1/types'; -import { - LibraryTraces_Library, - LibraryTraces_TraceId, - Monitoring, -} from './generated/confidence/telemetry/v1/telemetry'; +import { Monitoring } from './generated/confidence/telemetry/v1/telemetry'; import { SimpleFetch } from './types'; const FLAG_PREFIX = 'flags/'; export class ResolveError extends Error { - constructor( - public readonly code: FlagEvaluation.ErrorCode, - message: string, - ) { + constructor(public readonly code: FlagEvaluation.ErrorCode, message: string) { super(message); } } @@ -93,7 +87,7 @@ export type FlagResolverClientOptions = { environment: 'client' | 'backend'; region?: 'eu' | 'us'; resolveBaseUrl?: string; - enableTelemetry: boolean; + disableTelemetry: boolean; }; export class FetchingFlagResolverClient implements FlagResolverClient { @@ -114,9 +108,9 @@ export class FetchingFlagResolverClient implements FlagResolverClient { environment, region, resolveBaseUrl, - enableTelemetry, + disableTelemetry, }: FlagResolverClientOptions) { - if (!enableTelemetry) { + if (disableTelemetry) { // TODO think about both resolve and apply request logic for backends this.fetchImplementation = environment === 'backend' ? fetchImplementation : withRequestLogic(fetchImplementation); @@ -152,6 +146,7 @@ export class FetchingFlagResolverClient implements FlagResolverClient { this.resolveTimeout, new ResolveError('TIMEOUT', 'Resolve timeout'), ); + const start = new Date().getTime(); return this.resolveFlagsJson(request, signalWithTimeout) .then(response => FlagResolution.ready(context, response, this.createApplier(response.resolveToken))) .catch(error => { @@ -159,6 +154,9 @@ export class FetchingFlagResolverClient implements FlagResolverClient { return FlagResolution.failed(context, error.code, error.message); } throw error; + }) + .finally(() => { + Telemetry.getInstance().markFlagResolved(new Date().getTime() - start); }); }); } @@ -297,20 +295,7 @@ export function withTelemetryData(fetchImplementation: (request: Request) => Pro return new FetchBuilder() .modifyRequest(async request => { // TODO pull actual telemetry data - const monitoring: Monitoring = { - libraryTraces: [ - { - library: LibraryTraces_Library.LIBRARY_CONFIDENCE, - libraryVersion: '0.1.0', - traces: [ - { - id: LibraryTraces_TraceId.TRACE_ID_RESOLVE_LATENCY, - millisecondDuration: 100, - }, - ], - }, - ], - }; + const monitoring: Monitoring = Telemetry.getInstance().getSnapshot(); const headers = new Headers(request.headers); const base64Message = btoa(String.fromCharCode(...Monitoring.encode(monitoring).finish())); diff --git a/packages/sdk/src/Telemetry.ts b/packages/sdk/src/Telemetry.ts new file mode 100644 index 00000000..242f8944 --- /dev/null +++ b/packages/sdk/src/Telemetry.ts @@ -0,0 +1,67 @@ +import { + LibraryTraces_Library, + LibraryTraces_TraceId, + Monitoring, +} from './generated/confidence/telemetry/v1/telemetry'; + +class Telemetry { + private static instance: Telemetry; + private monitoring: Monitoring = { + libraryTraces: [], + }; + + static getInstance(): Telemetry { + if (!Telemetry.instance) { + Telemetry.instance = new Telemetry(); + } + return Telemetry.instance; + } + + markStaleFlag(): void { + this.pushTrace(LibraryTraces_TraceId.TRACE_ID_STALE_FLAG); + } + + pushTrace(traceId: LibraryTraces_TraceId, latency: number | undefined = undefined): void { + const { library, version } = this.getLibraryAndVersion(); + const existing = this.monitoring.libraryTraces.find(trace => { + return trace.library === library && trace.libraryVersion === version; + }); + if (existing) { + existing.traces.push({ + id: traceId, + millisecondDuration: latency, + }); + } else { + this.monitoring.libraryTraces.push({ + library, + libraryVersion: version, + traces: [ + { + id: traceId, + millisecondDuration: latency, + }, + ], + }); + } + } + + getLibraryAndVersion(): { library: LibraryTraces_Library; version: string } { + // TODO - get the library and version somehow + return { + library: LibraryTraces_Library.LIBRARY_CONFIDENCE, + version: '0.0.0', + }; + } + + markFlagResolved(latency: number): void { + this.pushTrace(LibraryTraces_TraceId.TRACE_ID_RESOLVE_LATENCY, latency); + } + + getSnapshot(): Monitoring { + const snapshot = { ...this.monitoring }; + this.monitoring = { libraryTraces: [] }; // Reset the state + return snapshot; + } +} + +export default Telemetry; From 44f1a010f76ac0fb41050ff362fd950bd6949db3 Mon Sep 17 00:00:00 2001 From: Nicklas Lundin Date: Tue, 26 Nov 2024 17:22:58 +0100 Subject: [PATCH 5/6] refactor: use registerCounter approach --- packages/sdk/src/Confidence.ts | 6 +- packages/sdk/src/FlagResolverClient.test.ts | 5 +- packages/sdk/src/FlagResolverClient.ts | 56 +++++++++------ packages/sdk/src/Telemetry.ts | 77 +++++++++++++-------- 4 files changed, 89 insertions(+), 55 deletions(-) diff --git a/packages/sdk/src/Confidence.ts b/packages/sdk/src/Confidence.ts index 8e17982e..3625b093 100644 --- a/packages/sdk/src/Confidence.ts +++ b/packages/sdk/src/Confidence.ts @@ -17,6 +17,7 @@ import { Subscribe, Observer, subject, changeObserver } from './observing'; import { SimpleFetch } from './types'; import { FlagResolution } from './FlagResolution'; import { AccessiblePromise } from './AccessiblePromise'; +import { Telemetry } from './Telemetry'; /** * Confidence options, to be used for easier initialization of Confidence @@ -341,6 +342,9 @@ export class Confidence implements EventSender, Trackable, FlagResolver { id: SdkId.SDK_ID_JS_CONFIDENCE, version: '0.2.1', // x-release-please-version } as const; + const telemetry = new Telemetry({ + disabled: disableTelemetry, + }); let flagResolverClient: FlagResolverClient = new FetchingFlagResolverClient({ clientSecret, fetchImplementation, @@ -349,7 +353,7 @@ export class Confidence implements EventSender, Trackable, FlagResolver { resolveTimeout: timeout, region, resolveBaseUrl, - disableTelemetry, + telemetry, }); if (environment === 'client') { flagResolverClient = new CachingFlagResolverClient(flagResolverClient, Number.POSITIVE_INFINITY); diff --git a/packages/sdk/src/FlagResolverClient.test.ts b/packages/sdk/src/FlagResolverClient.test.ts index b679aebe..02e091a8 100644 --- a/packages/sdk/src/FlagResolverClient.test.ts +++ b/packages/sdk/src/FlagResolverClient.test.ts @@ -10,6 +10,7 @@ import { SdkId } from './generated/confidence/flags/resolver/v1/types'; import { abortableSleep } from './fetch-util'; import { ApplyFlagsRequest, ResolveFlagsRequest } from './generated/confidence/flags/resolver/v1/api'; import { FlagResolution } from './FlagResolution'; +import { Telemetry } from './Telemetry'; const RESOLVE_ENDPOINT = 'https://resolver.confidence.dev/v1/flags:resolve'; const APPLY_ENDPOINT = 'https://resolver.confidence.dev/v1/flags:apply'; @@ -56,7 +57,7 @@ describe('Client environment Evaluation', () => { }, environment: 'client', resolveTimeout: 10, - disableTelemetry: false, + telemetry: new Telemetry({ disabled: true }), }); describe('apply', () => { @@ -109,7 +110,7 @@ describe('Backend environment Evaluation', () => { }, environment: 'backend', resolveTimeout: 10, - disableTelemetry: false, + telemetry: new Telemetry({ disabled: true }), }); it('should resolve a full flag object', async () => { diff --git a/packages/sdk/src/FlagResolverClient.ts b/packages/sdk/src/FlagResolverClient.ts index 06eabcde..53bbb704 100644 --- a/packages/sdk/src/FlagResolverClient.ts +++ b/packages/sdk/src/FlagResolverClient.ts @@ -1,7 +1,7 @@ import { FlagEvaluation } from '.'; import { AccessiblePromise } from './AccessiblePromise'; import { Applier, FlagResolution } from './FlagResolution'; -import Telemetry from './Telemetry'; +import { Telemetry, Meter } from './Telemetry'; import { Value } from './Value'; import { Context } from './context'; import { FetchBuilder, TimeUnit } from './fetch-util'; @@ -12,7 +12,11 @@ import { AppliedFlag, } from './generated/confidence/flags/resolver/v1/api'; import { Sdk } from './generated/confidence/flags/resolver/v1/types'; -import { Monitoring } from './generated/confidence/telemetry/v1/telemetry'; +import { + LibraryTraces_Library, + LibraryTraces_TraceId, + Monitoring, +} from './generated/confidence/telemetry/v1/telemetry'; import { SimpleFetch } from './types'; const FLAG_PREFIX = 'flags/'; @@ -87,7 +91,7 @@ export type FlagResolverClientOptions = { environment: 'client' | 'backend'; region?: 'eu' | 'us'; resolveBaseUrl?: string; - disableTelemetry: boolean; + telemetry: Telemetry; }; export class FetchingFlagResolverClient implements FlagResolverClient { @@ -97,6 +101,7 @@ export class FetchingFlagResolverClient implements FlagResolverClient { private readonly applyTimeout?: number; private readonly resolveTimeout: number; private readonly baseUrl: string; + private readonly markLatency: Meter; constructor({ fetchImplementation, @@ -108,18 +113,20 @@ export class FetchingFlagResolverClient implements FlagResolverClient { environment, region, resolveBaseUrl, - disableTelemetry, + telemetry, }: FlagResolverClientOptions) { - if (disableTelemetry) { - // TODO think about both resolve and apply request logic for backends - this.fetchImplementation = - environment === 'backend' ? fetchImplementation : withRequestLogic(fetchImplementation); - } else { - this.fetchImplementation = - environment === 'backend' - ? withTelemetryData(fetchImplementation) - : withRequestLogic(withTelemetryData(fetchImplementation)); - } + this.markLatency = telemetry.registerMeter({ + // TODO how to get library name? + library: LibraryTraces_Library.LIBRARY_CONFIDENCE, + version: sdk.version, + id: LibraryTraces_TraceId.TRACE_ID_RESOLVE_LATENCY, + }); + // TODO think about both resolve and apply request logic for backends + this.fetchImplementation = + environment === 'backend' + ? withTelemetryData(fetchImplementation, telemetry) + : withRequestLogic(withTelemetryData(fetchImplementation, telemetry)); + this.clientSecret = clientSecret; this.sdk = sdk; this.applyTimeout = applyTimeout; @@ -156,7 +163,7 @@ export class FetchingFlagResolverClient implements FlagResolverClient { throw error; }) .finally(() => { - Telemetry.getInstance().markFlagResolved(new Date().getTime() - start); + this.markLatency(new Date().getTime() - start); }); }); } @@ -291,16 +298,21 @@ export class CachingFlagResolverClient implements FlagResolverClient { } } -export function withTelemetryData(fetchImplementation: (request: Request) => Promise): typeof fetch { +export function withTelemetryData( + fetchImplementation: (request: Request) => Promise, + telemetry: Telemetry, +): typeof fetch { return new FetchBuilder() .modifyRequest(async request => { - // TODO pull actual telemetry data - const monitoring: Monitoring = Telemetry.getInstance().getSnapshot(); - const headers = new Headers(request.headers); - const base64Message = btoa(String.fromCharCode(...Monitoring.encode(monitoring).finish())); + const monitoring = telemetry.getSnapshot(); + if (monitoring) { + const headers = new Headers(request.headers); + const base64Message = btoa(String.fromCharCode(...Monitoring.encode(monitoring).finish())); - headers.set('X-CONFIDENCE-TELEMETRY', base64Message); - return new Request(request, { headers }); + headers.set('X-CONFIDENCE-TELEMETRY', base64Message); + return new Request(request, { headers }); + } + return request; }) .build(fetchImplementation); } diff --git a/packages/sdk/src/Telemetry.ts b/packages/sdk/src/Telemetry.ts index 242f8944..861ab892 100644 --- a/packages/sdk/src/Telemetry.ts +++ b/packages/sdk/src/Telemetry.ts @@ -4,64 +4,81 @@ import { Monitoring, } from './generated/confidence/telemetry/v1/telemetry'; -class Telemetry { - private static instance: Telemetry; - private monitoring: Monitoring = { - libraryTraces: [], - }; +export type TelemetryOptions = { disabled: boolean }; - static getInstance(): Telemetry { - if (!Telemetry.instance) { - Telemetry.instance = new Telemetry(); - } - return Telemetry.instance; - } +export type Tag = { + library: LibraryTraces_Library; + version: string; + id: LibraryTraces_TraceId; +}; + +export type Counter = () => void; +export type Meter = (value: number) => void; - markStaleFlag(): void { - this.pushTrace(LibraryTraces_TraceId.TRACE_ID_STALE_FLAG); +export class Telemetry { + private disabled: boolean; + constructor(opts: TelemetryOptions) { + this.disabled = opts.disabled; } - pushTrace(traceId: LibraryTraces_TraceId, latency: number | undefined = undefined): void { - const { library, version } = this.getLibraryAndVersion(); + private monitoring: Monitoring = { + libraryTraces: [], + }; + + private pushTrace(tags: Tag, value: number | undefined = undefined): void { + const library = tags.library; + const version = tags.version; const existing = this.monitoring.libraryTraces.find(trace => { return trace.library === library && trace.libraryVersion === version; }); if (existing) { existing.traces.push({ - id: traceId, - millisecondDuration: latency, + id: tags.id, + millisecondDuration: value, }); } else { + // should never happen. remove? this.monitoring.libraryTraces.push({ library, libraryVersion: version, traces: [ { - id: traceId, - millisecondDuration: latency, + id: tags.id, + millisecondDuration: value, }, ], }); } } - getLibraryAndVersion(): { library: LibraryTraces_Library; version: string } { - // TODO - get the library and version somehow - return { - library: LibraryTraces_Library.LIBRARY_CONFIDENCE, - version: '0.0.0', + registerCounter(tag: Tag): Counter { + this.monitoring.libraryTraces.push({ + library: tag.library, + libraryVersion: tag.version, + traces: [], + }); + return () => { + this.pushTrace(tag); }; } - markFlagResolved(latency: number): void { - this.pushTrace(LibraryTraces_TraceId.TRACE_ID_RESOLVE_LATENCY, latency); + registerMeter(tag: Tag): Meter { + this.monitoring.libraryTraces.push({ + library: tag.library, + libraryVersion: tag.version, + traces: [], + }); + return (value: number) => { + this.pushTrace(tag, value); + }; } - getSnapshot(): Monitoring { + getSnapshot(): Monitoring | undefined { + if (this.disabled) { + return undefined; + } const snapshot = { ...this.monitoring }; - this.monitoring = { libraryTraces: [] }; // Reset the state + this.monitoring = { libraryTraces: [] }; //TODO only clear traces! return snapshot; } } - -export default Telemetry; From 02faad3aa5e17064ceca08ce109e1675fe84c5d0 Mon Sep 17 00:00:00 2001 From: Nicklas Lundin Date: Tue, 26 Nov 2024 17:26:45 +0100 Subject: [PATCH 6/6] fixup! refactor: use registerCounter approach --- packages/sdk/src/Telemetry.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/sdk/src/Telemetry.ts b/packages/sdk/src/Telemetry.ts index 861ab892..db573f10 100644 --- a/packages/sdk/src/Telemetry.ts +++ b/packages/sdk/src/Telemetry.ts @@ -78,7 +78,10 @@ export class Telemetry { return undefined; } const snapshot = { ...this.monitoring }; - this.monitoring = { libraryTraces: [] }; //TODO only clear traces! + this.monitoring.libraryTraces.forEach(trace => { + // only clear traces. keep library and version since they are registered. + trace.traces = []; + }); return snapshot; } }