Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(types): Add Envelope types #4527

Merged
merged 2 commits into from
Feb 14, 2022
Merged

feat(types): Add Envelope types #4527

merged 2 commits into from
Feb 14, 2022

Conversation

AbhiPrasad
Copy link
Member

@AbhiPrasad AbhiPrasad commented Feb 9, 2022

To prep for the introduction of formal envelopes API, add types
representing envelopes and their items. These are based on the
documentation from the develop docs at the time of this patch.

Envelope items are stored as a tuple of length 2 (item headers and
payload) to reduce bundle size. This is as array access is smaller than
having to access through object properties, and they will stay constant.

Each Envelope is generic over a BaseEnvelope type, which allows for
items and headers to be configured, but sets a CommonEnvelopeHeaders
alongside a default UnknownEnvelopeItem (as per the spec).

Each Envelope item is generic over a BaseEnvelopeItem type, which
establishs CommonEnvelopeItemHeaders over an arbitrary item payload.

Envelope items are defined for events, attachments, user feedback,
sessions, and client reports. Envelopes are defined for events,
sessions, and client reports. This is as attachments and user feedback
(for now) must be in the envelope alongside the event.

As User Feedback and Attachment envelopes are currently not supported in
the SDK, they are not exported, but will be once v7 is introduced.

The next step from the patch is to add the public API around creating
and mutating Envelopes of different natures, as well as mapping from an
Envelope -> SentryRequest.

Addresses https://getsentry.atlassian.net/browse/WEB-590

See: https://develop.sentry.dev/sdk/envelopes/

To prep for the introduction of formal envelopes API, add types
representing envelopes and their items. These are based on the
documentation from the develop docs at the time of this patch.

Envelope items are stored as a tuple of length 2 (item headers and
payload) to reduce bundle size. This is as array access is smaller than
having to access through object properties, and they will stay constant.

Each Envelope is generic over a `BaseEnvelope` type, which allows for
items and headers to be configured, but sets a `CommonEnvelopeHeaders`
alongside a default `UnknownEnvelopeItem` (as per the spec).

Each Envelope item is generic over a `BaseEnvelopeItem` type, which
establishs `CommonEnvelopeItemHeaders` over an arbitrary item payload.

Envelope items are defined for events, attachments, user feedback,
sessions, and client reports. Envelopes are defined for events,
sessions, and client reports. This is as attachments and user feedback
(for now) must be in the envelope alongside the event.

As User Feedback and Attachment envelopes are currently not supported in
the SDK, they are not exported, but will be once v7 is introduced.

The next step from the patch is to add the public API around creating
and mutating Envelopes of different natures, as well as mapping from an
Envelope -> `SentryRequest`.
@AbhiPrasad AbhiPrasad requested review from a team, Lms24 and lobsterkatie and removed request for a team February 9, 2022 16:53
@github-actions
Copy link
Contributor

github-actions bot commented Feb 9, 2022

size-limit report

Path Base Size (a547883) Current Size Change
@sentry/browser - ES5 CDN Bundle (gzipped + minified) 19.77 KB 19.77 KB -0.01% 🔽
@sentry/browser - ES5 CDN Bundle (minified) 63.18 KB 63.18 KB +0.01% 🔺
@sentry/browser - ES6 CDN Bundle (gzipped + minified) 18.52 KB 18.52 KB 0%
@sentry/browser - ES6 CDN Bundle (minified) 56.8 KB 56.8 KB +0.01% 🔺
@sentry/browser - Webpack (gzipped + minified) 22.21 KB 22.21 KB 0%
@sentry/browser - Webpack (minified) 76.02 KB 76.02 KB 0%
@sentry/react - Webpack (gzipped + minified) 22.25 KB 22.25 KB 0%
@sentry/nextjs Client - Webpack (gzipped + minified) 46.32 KB 46.32 KB 0%
@sentry/browser + @sentry/tracing - ES5 CDN Bundle (gzipped + minified) 28.32 KB 28.33 KB +0.01% 🔺

Copy link
Member

@lobsterkatie lobsterkatie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a criticism of you, more like the result of some of TS's pitfalls, but overall this feels complicated and harder to grok than I feel like it ideally would be. I wonder if we could put our heads together IRL to see if it's possible to crate a more straightforward way to wrangle TS into submission.

Separately, two small suggestions below.

Comment on lines 29 to 32
type BaseEnvelope<EnvelopeHeaders extends Record<string, unknown>, EnvelopeItems extends BaseEnvelopeItem<any>> = {
h: CommonEnvelopeHeaders & EnvelopeHeaders;
i: Array<EnvelopeItems | UnknownEnvelopeItem>;
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two things here:

  1. The second generic parameter should be singular, I believe, right? Because it's what's going into the array.

  2. I get that it saves on bundle size to have the properties be single letters, but in this case the loss of readability/ease of use makes it feel not worth it to me. Especially given that envelopes are something an SDK user might have to deal with (i.e., aren't purely for internal use, though, to be fair, I'd be saying this regardless), I really think we should give these real names.

Suggested change
type BaseEnvelope<EnvelopeHeaders extends Record<string, unknown>, EnvelopeItems extends BaseEnvelopeItem<any>> = {
h: CommonEnvelopeHeaders & EnvelopeHeaders;
i: Array<EnvelopeItems | UnknownEnvelopeItem>;
};
type BaseEnvelope<EnvelopeHeaders extends Record<string, unknown>, EnvelopeItem extends BaseEnvelopeItem<any>> = {
headers: CommonEnvelopeHeaders & EnvelopeHeaders;
items: Array<EnvelopeItem | UnknownEnvelopeItem>;
};

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The second generic parameter should be singular, I believe, right? Because it's what's going into the array.

Yeah the 2nd parameter can be singular, I just kept it as this because it can be union typed, so it better fit my mental model as I was laying out the types.

I really think we should give these real names.

This is a good point that I didn't fully consider, I agree with the change

I wonder if we could put our heads together IRL to see if it's possible to crate a more straightforward way to wrangle TS into submission.

IMO I think it's pretty clear from the types what is happening. Is there a particular area that is harder to understand? It's also important to note that I'm sure these types will change a bit once we actually use them in the envelope helper functions. This is just a nice start to model out the domains appropriately.

@AbhiPrasad AbhiPrasad added this to the 7.0.0 milestone Feb 10, 2022
@AbhiPrasad AbhiPrasad merged commit 2a150ee into master Feb 14, 2022
@AbhiPrasad AbhiPrasad deleted the abhi-envelope-types branch February 14, 2022 17:57
items: Array<EnvelopeItem | UnknownEnvelopeItem>;
};

export type EventEnvelopeItem = BaseEnvelopeItem<{ type: 'event' | 'transaction' }, Event>;
Copy link

@HofmannZ HofmannZ Feb 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line causes a type error on node version 14.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh interesting. Could you open a GitHub issue please with your tsconfig, package.json and some details about your setup?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will try to do that tomorrow, we now locked the @sentry/types to 6.17.7 in our package.json and that resolves the issue.

...
"@sentry/types": "6.17.7"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I think it's filed with #4583. Woooops, thats on me. Will fix with #4584

AbhiPrasad added a commit that referenced this pull request Feb 15, 2022
#4527 introduced
Envelope types. In that patch, we included the `Event` DOM type, which
is not declared in all TS environments accidentally - we meant to
include Sentry's `Event` type.

This patch explicitly introduces Sentry's Event type by importing it in,
fixing the build errors that folks were having.
AbhiPrasad added a commit that referenced this pull request Feb 15, 2022
#4527 introduced Envelope types. In that patch, we included the `Event` DOM type, which is not declared in all TS environments - we meant to include Sentry's `Event` type.

This patch explicitly introduces Sentry's Event type by importing it in, fixing the build errors that folks were having.

Also updates the changelog for `6.17.9`
AbhiPrasad added a commit that referenced this pull request Feb 15, 2022
This patch introduces functions that create, mutate and serialize
envelopes. It also adds some basic unit tests that sanity check their
functionality. It builds on top of the work done in
#4527.

Users are expected to not directly interact with the Envelope instance,
but instead use the helper functions to work with them. Essentially, we
can treat the envelope instance as an opaque handle, similar to how void
pointers are used in low-level languages. This was done to minimize the
bundle impact of working with the envelopes, and as the set of possible
envelope operations was fixed (and on the smaller end).

To directly create an envelope, the `createEnvelope()` function was
introduced. Users are encouraged to explicitly provide the generic type
arg to this function so that add headers/items are typed accordingly.

To add headers and items to envelopes, the `addHeaderToEnvelope()` and
`addItemToEnvelope()` functions are exposed respectively. The reason
that these functions are purely additive (or in the case of headers, can
re-write existing ones), instead of allow for headers/items to be
removed, is that removal functionality doesn't seem like it'll be used
at all. In the interest of keeping the API surface small, we settled
with these two functions, but we can come back and adjust this later on.

Finally, there is `serializeEnvelope()`, which is used to serialize an
envelope to a string. It does have some TypeScript complications, which
is explained in detail in a code comment, but otherwise is a pretty
simple implementation. You can notice the power of the tuple based
envelope implementation, where it becomes easy to access headers/items.

```js
const [headers, items] = envelope;
```

To illustrate how these functions will be used, another patch will be
added that adds a `createClientReportEnvelope()` util, and the base
transport in `@sentry/browser` will be updated to use that util.
AbhiPrasad added a commit that referenced this pull request Feb 23, 2022
This patch introduces functions that create, mutate and serialize
envelopes. It also adds some basic unit tests that sanity check their
functionality. It builds on top of the work done in
#4527.

Users are expected to not directly interact with the Envelope instance,
but instead use the helper functions to work with them. Essentially, we
can treat the envelope instance as an opaque handle, similar to how void
pointers are used in low-level languages. This was done to minimize the
bundle impact of working with the envelopes, and as the set of possible
envelope operations was fixed (and on the smaller end).

To directly create an envelope, the `createEnvelope()` function was
introduced. Users are encouraged to explicitly provide the generic type
arg to this function so that add headers/items are typed accordingly.

To add headers and items to envelopes, the `addHeaderToEnvelope()` and
`addItemToEnvelope()` functions are exposed respectively. The reason
that these functions are purely additive (or in the case of headers, can
re-write existing ones), instead of allow for headers/items to be
removed, is that removal functionality doesn't seem like it'll be used
at all. In the interest of keeping the API surface small, we settled
with these two functions, but we can come back and adjust this later on.

Finally, there is `serializeEnvelope()`, which is used to serialize an
envelope to a string. It does have some TypeScript complications, which
is explained in detail in a code comment, but otherwise is a pretty
simple implementation. You can notice the power of the tuple based
envelope implementation, where it becomes easy to access headers/items.

```js
const [headers, items] = envelope;
```

To illustrate how these functions will be used, another patch will be
added that adds a `createClientReportEnvelope()` util, and the base
transport in `@sentry/browser` will be updated to use that util.
@AbhiPrasad AbhiPrasad modified the milestones: 7.0.0, Pre 7.0.0 Work Feb 23, 2022
AbhiPrasad added a commit that referenced this pull request Feb 25, 2022
This patch introduces functions that create, mutate and serialize
envelopes. It also adds some basic unit tests that sanity check their
functionality. It builds on top of the work done in
#4527.

Users are expected to not directly interact with the Envelope instance,
but instead use the helper functions to work with them. Essentially, we
can treat the envelope instance as an opaque handle, similar to how void
pointers are used in low-level languages. This was done to minimize the
bundle impact of working with the envelopes, and as the set of possible
envelope operations was fixed (and on the smaller end).

To directly create an envelope, the `createEnvelope()` function was
introduced. Users are encouraged to explicitly provide the generic type
arg to this function so that headers/items are typed accordingly.

To add items to envelopes, the`addItemToEnvelope()` functions is exposed. 
In the interest of keeping the API surface small, we settled with just this one
function, but we can come back and change it later on.

Finally, there is `serializeEnvelope()`, which is used to serialize an
envelope to a string. It does have some TypeScript complications, which
are explained in detail in a code comment, but otherwise is a pretty
simple implementation. You can notice the power of the tuple based
envelope implementation, where it becomes easy to access headers/items.

```js
const [headers, items] = envelope;
```

To illustrate how these functions will be used, another patch will be
added that adds a `createClientReportEnvelope()` util, and the base
transport in `@sentry/browser` will be updated to use that util.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants