@servicetitan/docs-uikit 31.5.1 → 32.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/BREAKING_CHANGES.mdx +19 -2
- package/docs/ajax-handlers/ajax-handlers.mdx +12 -0
- package/docs/ajax-handlers/init-ajax-handlers-parse-dates.mdx +74 -0
- package/docs/{ajax-handlers.mdx → ajax-handlers/with-microservice.mdx} +33 -29
- package/docs/datadog-rum.mdx +133 -0
- package/docs/startup/install.mdx +151 -0
- package/docs/startup/review.mdx +42 -0
- package/docs/startup/start.mdx +1 -1
- package/docs/startup/test.mdx +197 -3
- package/package.json +2 -2
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
title: BREAKING CHANGES
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
+
## v32.0.0
|
|
6
|
+
|
|
7
|
+
### [@servicetitan/startup](./startup)
|
|
8
|
+
|
|
9
|
+
:::caution
|
|
10
|
+
This breaking change affects local development, even if you do not update the `@servicetitan/startup` dependency directly. On a clean install, the standard bootstrap script runs the latest version of `startup`, which automatically removes hard-coded tokens from `.npmrc` files.
|
|
11
|
+
:::
|
|
12
|
+
|
|
13
|
+
Removed support for hard-coded npm tokens in `.npmrc` files. The new `startup install` removes hard-coded authentication tokens from project `.npmrc` files and, in development environments, automatically adds a token to npm's per-user configuration that grants access to ServiceTitan's private packages.
|
|
14
|
+
|
|
15
|
+
Projects that previously relied on hard-coded tokens must update their Github and Teamcity workflows to instead use the organization secret as described in the [startup install documentation](./startup/install#configuring-npm-token-in-ci):
|
|
16
|
+
|
|
17
|
+
- Option 1: Inject the organization secret into `.npmrc`.
|
|
18
|
+
- Option 2: Configure `.npmrc` to get the organization secret from an environment variable.
|
|
19
|
+
|
|
20
|
+
**Why this change?**
|
|
21
|
+
Two recent incidents mandated that we revoke the shared token that grants access to ServiceTitan's private packages. By removing hard-coded tokens, ServiceTitan can more easily and seamlessly rotate or revoke tokens, improving security and reducing friction for developers.
|
|
22
|
+
|
|
5
23
|
## v31.0.0
|
|
6
24
|
|
|
7
25
|
### [@servicetitan/startup](./startup)
|
|
@@ -63,14 +81,13 @@ title: BREAKING CHANGES
|
|
|
63
81
|
|
|
64
82
|
### [@servicetitan/ajax-handlers](./ajax-handlers)
|
|
65
83
|
|
|
66
|
-
- Changed [**withMicroservice**](./ajax-handlers#parameters) arguments to a single options object.
|
|
84
|
+
- Changed [**withMicroservice**](./ajax-handlers/with-microservice#parameters) arguments to a single options object.
|
|
67
85
|
|
|
68
86
|
## v24.0.0
|
|
69
87
|
|
|
70
88
|
### [@servicetitan/startup](./startup)
|
|
71
89
|
|
|
72
90
|
- Upgraded **Typescript** from v4 to v5, which adds correctness improvements that will reveal previously undetected ambiguities. In particular,
|
|
73
|
-
|
|
74
91
|
- Type checks for enums are stricter because all **enum** values get their own type
|
|
75
92
|
- **string** and **boolean** values aren't implicitly converted to numbers. Use the `+` operator to explicitly convert values to numbers in mathematical expressions. (e.g., `return +str > 42;`)
|
|
76
93
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: AJAX Handlers
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
#### [CHANGELOG (@servicetitan/ajax-handlers)](https://github.com/servicetitan/uikit/blob/master/packages/ajax-handlers/CHANGELOG.md)
|
|
6
|
+
|
|
7
|
+
`@servicetitan/ajax-handlers` provides utilities for handling AJAX requests, authentication, and response processing in ServiceTitan applications. It includes automatic date parsing, authentication wrappers for protected resources, and comprehensive error handling.
|
|
8
|
+
|
|
9
|
+
## API
|
|
10
|
+
|
|
11
|
+
- [withMicroservice](./with-microservice.mdx) - Use `withMicroservice` to wrap components and authenticate requests to protected resources with support for Bearer and Token Server authentication.
|
|
12
|
+
- [initAjaxHandlersParseDates](./init-ajax-handlers-parse-dates.mdx) - Use `initAjaxHandlersParseDates` to automatically transform date strings in axios responses into JavaScript Date objects.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: initAjaxHandlersParseDates
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
`initAjaxHandlersParseDates` is a function that automatically transforms date strings in axios responses into JavaScript Date objects. This eliminates the need for manual date parsing throughout your application.
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
Call this function once in your application's initialization code, typically before making any axios requests:
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import { initAjaxHandlersParseDates } from '@servicetitan/ajax-handlers';
|
|
13
|
+
|
|
14
|
+
// Initialize date parsing for all axios responses
|
|
15
|
+
initAjaxHandlersParseDates();
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## How It Works
|
|
19
|
+
|
|
20
|
+
The function adds a response transformer to the global axios defaults that:
|
|
21
|
+
|
|
22
|
+
1. Automatically detects and parses date strings in response data
|
|
23
|
+
2. Recursively traverses objects and arrays to find date strings
|
|
24
|
+
3. Preserves other data types unchanged (including Blobs)
|
|
25
|
+
4. Handles parsing errors gracefully by returning the original data
|
|
26
|
+
|
|
27
|
+
## Supported Date Formats
|
|
28
|
+
|
|
29
|
+
The parser recognizes two date formats commonly used in APIs:
|
|
30
|
+
|
|
31
|
+
### ISO 8601 Format
|
|
32
|
+
|
|
33
|
+
Supports standard ISO date strings with optional time zones and milliseconds:
|
|
34
|
+
|
|
35
|
+
- `2024-03-15T10:30:45Z`
|
|
36
|
+
- `2024-03-15T10:30:45.123Z`
|
|
37
|
+
- `2024-03-15T10:30:45+05:00`
|
|
38
|
+
- `2024-03-15T10:30:45.789-08:00`
|
|
39
|
+
|
|
40
|
+
### .NET JSON Date Format
|
|
41
|
+
|
|
42
|
+
Supports the legacy .NET JSON date format:
|
|
43
|
+
|
|
44
|
+
- `/Date(1710504645000)/`
|
|
45
|
+
- `/Date(1710504645000-0800)/`
|
|
46
|
+
- `/Date(-62135596800000)/` (negative timestamps for dates before 1970)
|
|
47
|
+
|
|
48
|
+
## Example
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
import axios from 'axios';
|
|
52
|
+
import { initAjaxHandlersParseDates } from '@servicetitan/ajax-handlers';
|
|
53
|
+
|
|
54
|
+
// Initialize date parsing once
|
|
55
|
+
initAjaxHandlersParseDates();
|
|
56
|
+
|
|
57
|
+
// Now all axios responses will have dates automatically parsed
|
|
58
|
+
const response = await axios.get('/api/users/123');
|
|
59
|
+
|
|
60
|
+
// response.data might look like:
|
|
61
|
+
// {
|
|
62
|
+
// id: 123,
|
|
63
|
+
// name: 'John Doe',
|
|
64
|
+
// createdAt: Date object (not a string!),
|
|
65
|
+
// lastLogin: Date object (not a string!),
|
|
66
|
+
// metadata: {
|
|
67
|
+
// updatedAt: Date object (not a string!)
|
|
68
|
+
// }
|
|
69
|
+
// }
|
|
70
|
+
|
|
71
|
+
// You can immediately use Date methods
|
|
72
|
+
console.log(response.data.createdAt.getFullYear());
|
|
73
|
+
console.log(response.data.lastLogin.toLocaleDateString());
|
|
74
|
+
```
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
---
|
|
2
|
-
title:
|
|
2
|
+
title: withMicroservice
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
#### [CHANGELOG (@servicetitan/ajax-handlers)](https://github.com/servicetitan/uikit/blob/master/packages/ajax-handlers/CHANGELOG.md)
|
|
6
|
-
|
|
7
|
-
## withMicroservice
|
|
8
|
-
|
|
9
5
|
`withMicroservice` is a higher-order function that wraps a component and authenticates
|
|
10
6
|
its requests to protected resources.
|
|
11
7
|
|
|
12
|
-
|
|
8
|
+
## Usage
|
|
13
9
|
|
|
14
10
|
The best way to use `withMicroservice` is to wrap the component in the ES module body. E.g.,
|
|
15
11
|
|
|
@@ -54,7 +50,7 @@ const App = () => {
|
|
|
54
50
|
}
|
|
55
51
|
```
|
|
56
52
|
|
|
57
|
-
|
|
53
|
+
## Parameters
|
|
58
54
|
|
|
59
55
|
`withMicroservice` accepts an object with the following properties:
|
|
60
56
|
|
|
@@ -70,27 +66,27 @@ const App = () => {
|
|
|
70
66
|
| `preAuthenticateCallback` | `(error?: any) => void` | (optional) callback to call after pre-authentication succeeds or fails. If pre-authentication fails, the error is passed to the first parameter of the callback. |
|
|
71
67
|
| `tokens` | `Symbol[]` | (optional) symbols to use to provide `baseURL` to autogenerated API services and child components |
|
|
72
68
|
|
|
73
|
-
|
|
69
|
+
### authAdapter{#auth-adapter}
|
|
74
70
|
|
|
75
71
|
Use `authAdapter` to select the authentication scheme. One of,
|
|
76
72
|
|
|
77
|
-
| Value
|
|
78
|
-
|
|
|
79
|
-
| "bearer"
|
|
80
|
-
| "token"
|
|
73
|
+
| Value | Description |
|
|
74
|
+
| :-------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
75
|
+
| "bearer" | **Bearer** authentication sends the bearer token returned by `authURL` in the **Authorization** header of requests. Uses BearerTokenAuth adapter. |
|
|
76
|
+
| "token" | **Token** authentication uses the Token Server's "silent login" protocol to add secure cookies to requests. Uses TokenServerAuth adapter. |
|
|
81
77
|
| `(context: WithMicroserviceContext) => AuthAdapter` | Custom authentication uses the adapter returned by a function to decorate requests. |
|
|
82
78
|
|
|
83
79
|
See [Authentication Adapters](#authentication-adapters) for more information.
|
|
84
80
|
|
|
85
|
-
|
|
81
|
+
### authUrl
|
|
86
82
|
|
|
87
83
|
The authentication endpoint for protected resources.
|
|
88
84
|
|
|
89
|
-
-
|
|
85
|
+
- For **Bearer** authentication, this is the endpoint that returns the bearer token to send in **Authorization** headers. Defaults to `${baseURL}/auth`.
|
|
90
86
|
|
|
91
|
-
-
|
|
87
|
+
- For **Token server** authentication, this is the "silent login" endpoint. Defaults to `${baseURL}/bff/silent-login`.
|
|
92
88
|
|
|
93
|
-
|
|
89
|
+
### preAuthenticate{#pre-authenticate}
|
|
94
90
|
|
|
95
91
|
Controls when authentication happens:
|
|
96
92
|
|
|
@@ -101,9 +97,9 @@ Controls when authentication happens:
|
|
|
101
97
|
|
|
102
98
|
When using Token Server authentication, authentication is always performed after the component is loaded and this value is ignored.
|
|
103
99
|
|
|
104
|
-
|
|
100
|
+
### tokens
|
|
105
101
|
|
|
106
|
-
The main purpose of `tokens` is to [provide](
|
|
102
|
+
The main purpose of `tokens` is to [provide](../react-ioc#provide) the `baseURL` to autogenerated API services.
|
|
107
103
|
For example,
|
|
108
104
|
|
|
109
105
|
```tsx
|
|
@@ -138,11 +134,11 @@ const Component = () => {
|
|
|
138
134
|
}
|
|
139
135
|
```
|
|
140
136
|
|
|
141
|
-
|
|
137
|
+
## Authentication Adapters{#authentication-adapters}
|
|
142
138
|
|
|
143
139
|
`withMicroservice` uses authentication adapters in order to perform authentication in different ways depending on your needs.
|
|
144
140
|
|
|
145
|
-
|
|
141
|
+
### BearerTokenAuth
|
|
146
142
|
|
|
147
143
|
The default adapter is the `BearerTokenAuth` adapter. When authentication occurs, a request is sent to the `authURL` in order to retrieve a token. Then any requests made using the `baseURL` will add the `Authorization: Bearer ...` header with the stored token.
|
|
148
144
|
|
|
@@ -156,7 +152,7 @@ const App = withMicroservice({
|
|
|
156
152
|
});
|
|
157
153
|
```
|
|
158
154
|
|
|
159
|
-
|
|
155
|
+
### TokenServerAuth{#token-server-auth}
|
|
160
156
|
|
|
161
157
|
The `TokenServerAuth` adapter allows you to authenticate with a backend that is using the `ServiceTitan.Ium.Bff` NuGet package ([see TokenServer documentation for details](/docs/projects/ium/tokenserver-new-app-integration/)).
|
|
162
158
|
|
|
@@ -177,8 +173,8 @@ const App = withMicroservice({
|
|
|
177
173
|
```tsx title="Custom adapter"
|
|
178
174
|
const options: TokenServerAuthOptions = {
|
|
179
175
|
authInfoURL: '/custom/authinfo',
|
|
180
|
-
onError: (defaultErrorHandler) => {
|
|
181
|
-
console.error(
|
|
176
|
+
onError: (defaultErrorHandler, error) => {
|
|
177
|
+
console.error(error, error.data);
|
|
182
178
|
defaultErrorHandler();
|
|
183
179
|
},
|
|
184
180
|
};
|
|
@@ -189,12 +185,20 @@ const App = withMicroservice({
|
|
|
189
185
|
});
|
|
190
186
|
```
|
|
191
187
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
|
195
|
-
|
|
|
196
|
-
| `
|
|
188
|
+
#### TokenServerAuthOptions
|
|
189
|
+
|
|
190
|
+
| Name | Type | Description |
|
|
191
|
+
| :------------ | :--------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- |
|
|
192
|
+
| `authInfoURL` | `string` | (optional) URL to fetch authentication parameters from. Defaults to `'/bff/authinfo'`. |
|
|
193
|
+
| `onError` | `(defaultErrorHandler: () => void, error: Error) => void;` | (optional) Callback to call when an error occurs during authentication. Defaults to reloading the page a maximum of 1 time. |
|
|
194
|
+
|
|
195
|
+
The `onError` callback is passed the following arguments:
|
|
196
|
+
|
|
197
|
+
| Name | Type | Description |
|
|
198
|
+
| :-------------------- | :--------- | :------------------------------------------------------------------------------------------------- |
|
|
199
|
+
| `defaultErrorHandler` | `Function` | The default error handler. |
|
|
200
|
+
| `error` | `Error` | An error object with a `data` property that contains the data associated with the failure, if any. |
|
|
197
201
|
|
|
198
|
-
|
|
202
|
+
## Authorization
|
|
199
203
|
|
|
200
204
|
`withMicroservice` currently only assists with performing authentication for requests of protected resources. There are currently no plans to implement authorization until we see concrete Token Server usage examples by product teams. If you find that having any sort of implementation for authorization would be helpful, especially in regards to Token Server implementation, please bring any ideas or discussions to the Frontend Platform team's attention so that we can create a platform solution.
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: DataDog RUM
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
#### [CHANGELOG (@servicetitan/datadog-rum)](https://github.com/servicetitan/uikit/blob/master/packages/datadog-rum/CHANGELOG.md)
|
|
6
|
+
|
|
7
|
+
[`@servicetitan/datadog-rum`](https://github.com/servicetitan/uikit/tree/master/packages/datadog-rum) helps configure DataDog RUM JS SDK in standalone applications. It enriches RUM events with information useful for application and MFE monitoring, and troubleshooting.
|
|
8
|
+
|
|
9
|
+
## Configuration snippet
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import { beforeSend, DatadogProvider } from '@servicetitan/datadog-rum';
|
|
13
|
+
import { datadogRum } from '@datadog/browser-rum';
|
|
14
|
+
|
|
15
|
+
const isEnabled = /.*go\d*\.servicetitan\.com/.test(window.location.hostname);
|
|
16
|
+
|
|
17
|
+
if (isEnabled) {
|
|
18
|
+
datadogRum.init({
|
|
19
|
+
applicationId: '<APPLICATION_ID>',
|
|
20
|
+
clientToken: '<CLIENT_TOKEN>',
|
|
21
|
+
site: 'datadoghq.com',
|
|
22
|
+
service: '<SERVICE_NAME>',
|
|
23
|
+
env: '<ENV_NAME>',
|
|
24
|
+
version: '<APPLICATION_VERSION>',
|
|
25
|
+
sessionSampleRate: 100,
|
|
26
|
+
sessionReplaySampleRate: 0,
|
|
27
|
+
defaultPrivacyLevel: 'mask-user-input',
|
|
28
|
+
beforeSend: beforeSend(),
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const Root = () => {
|
|
33
|
+
const user = useCurrentUser(); // application-specific hook that identifies the user
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<DatadogProvider isEnabled={isEnabled} user={user}>
|
|
37
|
+
<Application />
|
|
38
|
+
</DatadogProvider>
|
|
39
|
+
);
|
|
40
|
+
};
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## DatadogProvider
|
|
44
|
+
|
|
45
|
+
`DatadogProvider` is a higher-order component that supplies RUM SDK with:
|
|
46
|
+
|
|
47
|
+
- Information about the user session
|
|
48
|
+
- Sanitized view event names (`@view.name`) when hash-based routing is used
|
|
49
|
+
|
|
50
|
+
### Usage
|
|
51
|
+
|
|
52
|
+
Wrap your application with `DatadogProvider` close to the root. E.g.,
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
import { DatadogProvider } from '@servicetitan/datadog-rum';
|
|
56
|
+
|
|
57
|
+
const Root = () =>
|
|
58
|
+
return (
|
|
59
|
+
<DatadogProvider isEnabled={isEnabled} user={user}>
|
|
60
|
+
...
|
|
61
|
+
</DatadogProvider>
|
|
62
|
+
);
|
|
63
|
+
};
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
If your application uses hash-based routing, `DatadogProvider` should be placed inside `HashRouter`. E.g.,
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
import { HashRouter } from 'react-router-dom';
|
|
70
|
+
import { DatadogProvider } from '@servicetitan/datadog-rum';
|
|
71
|
+
|
|
72
|
+
const Root = () => {
|
|
73
|
+
return (
|
|
74
|
+
<HashRouter>
|
|
75
|
+
<DatadogProvider isEnabled={isEnabled} user={user} options={{ hashRouting: true }}>
|
|
76
|
+
...
|
|
77
|
+
</DatadogProvider>
|
|
78
|
+
</HashRouter>
|
|
79
|
+
);
|
|
80
|
+
};
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Parameters
|
|
84
|
+
|
|
85
|
+
| Name | Type | Description |
|
|
86
|
+
| :---------- | :-------- | :------------------------------------------ |
|
|
87
|
+
| `isEnabled` | `boolean` | Enables DD RUM instrumentation |
|
|
88
|
+
| `user` | `User` | (optional) User session information |
|
|
89
|
+
| `options` | `Options` | (optional) Additional configuration options |
|
|
90
|
+
|
|
91
|
+
#### `User`
|
|
92
|
+
|
|
93
|
+
| Name | Type | Description |
|
|
94
|
+
| :-------------- | :----------------------------- | :----------------------------------- |
|
|
95
|
+
| `id` | `string` | User ID |
|
|
96
|
+
| `[key: string]` | `string \| number \| string[]` | (optional) Arbitrary user attributes |
|
|
97
|
+
|
|
98
|
+
#### `Options`
|
|
99
|
+
|
|
100
|
+
| Name | Type | Description |
|
|
101
|
+
| :------------ | :-------- | :------------------------------------------ |
|
|
102
|
+
| `hashRouting` | `boolean` | Sanitizes view names for hash-based routing |
|
|
103
|
+
|
|
104
|
+
## `beforeSend`
|
|
105
|
+
|
|
106
|
+
`beforeSend` is a callback function for enriching RUM events. Supported functionality:
|
|
107
|
+
|
|
108
|
+
- Adds MFE name and version for error and resource events coming from MFEs (`@error.service`, `@resource.service`, `@error.version`, and `@resource.version`)
|
|
109
|
+
- Adds Cloudflare Ray ID for resource events (`@resource.cfRay`)
|
|
110
|
+
|
|
111
|
+
### Usage
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
import { beforeSend } from '@servicetitan/datadog-rum';
|
|
115
|
+
import { datadogRum } from '@datadog/browser-rum';
|
|
116
|
+
|
|
117
|
+
const isEnabled = /.*go\d*\.servicetitan\.com/.test(window.location.hostname);
|
|
118
|
+
|
|
119
|
+
if (isEnabled) {
|
|
120
|
+
datadogRum.init({
|
|
121
|
+
applicationId: '<APPLICATION_ID>',
|
|
122
|
+
clientToken: '<CLIENT_TOKEN>',
|
|
123
|
+
site: 'datadoghq.com',
|
|
124
|
+
service: '<SERVICE_NAME>',
|
|
125
|
+
env: '<ENV_NAME>',
|
|
126
|
+
version: '<APPLICATION_VERSION>',
|
|
127
|
+
sessionSampleRate: 100,
|
|
128
|
+
sessionReplaySampleRate: 0,
|
|
129
|
+
defaultPrivacyLevel: 'mask-user-input',
|
|
130
|
+
beforeSend: beforeSend(), // <--beforeSend() returns handler that enriches events
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
```
|
package/docs/startup/install.mdx
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
title: install
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
+
import Tabs from '@theme/Tabs';
|
|
6
|
+
import TabItem from '@theme/TabItem';
|
|
7
|
+
|
|
5
8
|
Installs project dependencies.
|
|
6
9
|
|
|
7
10
|
Use this command instead of plain `npm install` to guarantee that all packages are installed correctly and any necessary post-install steps are performed.
|
|
@@ -11,3 +14,151 @@ npx --yes @servicetitan/startup install
|
|
|
11
14
|
```
|
|
12
15
|
|
|
13
16
|
See [package.json in the example project](https://github.com/search?q=repo%3Aservicetitan%2Ffrontend-example+path%3A**%2Fpackage.json+%22startup+install%22&type=code) for how to use `install` in an npm script.
|
|
17
|
+
|
|
18
|
+
## Options
|
|
19
|
+
|
|
20
|
+
| Option | Description |
|
|
21
|
+
| :----------- | :-------------------------------------------- |
|
|
22
|
+
| `--no-token` | Disable configuring npm authentication token. |
|
|
23
|
+
|
|
24
|
+
## Configuring NPM Token in Development
|
|
25
|
+
|
|
26
|
+
In development environments, `startup install` automatically configures an npm authentication token that grants access to private ServiceTitan packages. It securely retrieves the token and updates your npm configuration so you can install dependencies without any further setup.
|
|
27
|
+
|
|
28
|
+
:::caution
|
|
29
|
+
`startup install` detects if it is running in development by checking for standard environment variables set by CI systems (e.g.,`CI` and `TEAMCITY_VERSION`). If none of these variables are set, it assumes it is running on a developer machine.
|
|
30
|
+
If it mistakes a CI environment for a developer machine, add a `CI` environment variable (with any value) to the workflow, or [use `--no-token`](#how-to-use---no-token) to disable configuring the npm token.
|
|
31
|
+
:::
|
|
32
|
+
|
|
33
|
+
## Configuring NPM Token in CI
|
|
34
|
+
|
|
35
|
+
In CI environments such as Teamcity and Github, use the `ST_NPM_READONLY_TOKEN` organization secret to grant access to private ServiceTitan packages. You can do this in two ways:
|
|
36
|
+
|
|
37
|
+
### Option 1: Inject into .npmrc (Recommended)
|
|
38
|
+
|
|
39
|
+
The recommended method is to use `npm config set --location=project` to manually inject the organization secret into the project's `.npmrc`. For example,
|
|
40
|
+
|
|
41
|
+
<Tabs
|
|
42
|
+
defaultValue="github"
|
|
43
|
+
values={[{ label: "Github Action", value: "github"}, {label: "Dockerfile", value: "docker"}]}>
|
|
44
|
+
|
|
45
|
+
<TabItem value="github">
|
|
46
|
+
|
|
47
|
+
```yml
|
|
48
|
+
- run: npm config set --location=project "//registry.npmjs.org/:_authToken"="${{ secrets.ST_NPM_READONLY_TOKEN }}"
|
|
49
|
+
- run: npm run build
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Alternatively, in Github actions using `action/setup-node`, you can use `registry-url` and `env.NODE_AUTH_TOKEN` to have it configure the project level `.npmrc`. For example,
|
|
53
|
+
|
|
54
|
+
```yml
|
|
55
|
+
- uses: actions/setup-node@v4
|
|
56
|
+
registry-url: https://registry.npmjs.org
|
|
57
|
+
env:
|
|
58
|
+
NODE_AUTH_TOKEN: ${{ secrets.ST_NPM_READONLY_TOKEN }}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
</TabItem>
|
|
62
|
+
<TabItem value="docker">
|
|
63
|
+
|
|
64
|
+
```dockerfile
|
|
65
|
+
ARG NPM_READONLY_TOKEN
|
|
66
|
+
|
|
67
|
+
RUN npm config set --location=project "//registry.npmjs.org/:_authToken=$NPM_READONLY_TOKEN"
|
|
68
|
+
RUN npm run build
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
</TabItem>
|
|
72
|
+
</Tabs>
|
|
73
|
+
|
|
74
|
+
### Option 2: Use environment variable
|
|
75
|
+
|
|
76
|
+
:::caution
|
|
77
|
+
Using an environment variable is not recommended because it requires [extra steps](#how-to-configure-with-legacy-startup) to rotate the token in projects using `startup` v31 or earlier.
|
|
78
|
+
:::
|
|
79
|
+
|
|
80
|
+
To use an environment variable to configure the npm token, modify `.npmrc` to get the token from an environment variable,
|
|
81
|
+
|
|
82
|
+
```npmrc title=".npmrc"
|
|
83
|
+
//registry.npmjs.org/:_authToken=${NPM_READONLY_TOKEN}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Then, in the CI action, set that environment variable to the organization secret. For example,
|
|
87
|
+
|
|
88
|
+
<Tabs
|
|
89
|
+
defaultValue="github"
|
|
90
|
+
values={[{ label: "Github Action", value: "github"}, {label: "Dockerfile", value: "docker"}]}>
|
|
91
|
+
|
|
92
|
+
<TabItem value="github">
|
|
93
|
+
|
|
94
|
+
```yml
|
|
95
|
+
- run: npm run build
|
|
96
|
+
env:
|
|
97
|
+
NPM_READONLY_TOKEN: ${{ secrets.ST_NPM_READONLY_TOKEN }}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
</TabItem>
|
|
101
|
+
<TabItem value="docker">
|
|
102
|
+
|
|
103
|
+
```dockerfile
|
|
104
|
+
ARG NPM_READONLY_TOKEN
|
|
105
|
+
|
|
106
|
+
ENV NPM_READONLY_TOKEN=${NPM_READONLY_TOKEN}
|
|
107
|
+
|
|
108
|
+
RUN npm run build
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
</TabItem></Tabs>
|
|
112
|
+
|
|
113
|
+
## How to Configure Development Environment When Not Using Startup v32 or Later {#how-to-configure-with-legacy-startup}
|
|
114
|
+
|
|
115
|
+
:::note
|
|
116
|
+
These instructions are only for projects using [Option 2](#option-2-use-environment-variable) with `startup` v31 or earlier (or that are not using `startup` at all);
|
|
117
|
+
`startup` v32 automatically detects and provides environment variables to `npm install`.
|
|
118
|
+
:::
|
|
119
|
+
|
|
120
|
+
If your project is [using an environment variable](#option-2-use-environment-variable), and it isn't using `startup` v32 or later, then developers must also defined the same environment variable manually. And they must repeat these steps each time the token is rotated,
|
|
121
|
+
|
|
122
|
+
1. Run `npx --yes @servicetitan/startup@latest install` to add the token to your per-user configuration.
|
|
123
|
+
2. Run `npm config get userconfig` to get the location of your per-user configuration file.
|
|
124
|
+
3. Find the token in the configuration file, on the line that starts `//registry.npmjs.org/:_authToken=`
|
|
125
|
+
4. Create a local environment variable with the token. Use the same variable name as in project's `.npmrc`.
|
|
126
|
+
|
|
127
|
+
:::tip
|
|
128
|
+
On MacOS you can accomplish steps 2 and 3 with this single command:
|
|
129
|
+
|
|
130
|
+
```sh
|
|
131
|
+
grep registry.npmjs.org < $(npm config get userconfig)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
:::
|
|
135
|
+
|
|
136
|
+
## How to Use --no-token
|
|
137
|
+
|
|
138
|
+
If startup mistakes your CI environment for a development machine and it isn't practical to add a `CI` environment variable to the workflow, use `--no-token` to instruct `startup install` not to attempt to configure the npm token.
|
|
139
|
+
|
|
140
|
+
Create a `build:ci` script and accompanying pre script that runs `bootstrap` with `-- --no-token`:
|
|
141
|
+
|
|
142
|
+
```json title="package.json"
|
|
143
|
+
"scripts": {
|
|
144
|
+
"prebuild:ci": "npm run bootstrap -- --no-token",
|
|
145
|
+
"build:ci": "startup build"
|
|
146
|
+
},
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Then, call `build:ci` instead of `build` in the CI workflow:
|
|
150
|
+
|
|
151
|
+
```sh
|
|
152
|
+
npm run build:ci
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
:::note
|
|
156
|
+
This assumes you're using this recommended `bootstrap` script:
|
|
157
|
+
|
|
158
|
+
```json
|
|
159
|
+
"scripts": {
|
|
160
|
+
"bootstrap": "npx --yes @servicetitan/startup install",
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
:::
|
package/docs/startup/review.mdx
CHANGED
|
@@ -192,6 +192,32 @@ npm pkg set "main"="dist/index.js" -w packages/lib
|
|
|
192
192
|
|
|
193
193
|
---
|
|
194
194
|
|
|
195
|
+
### require-all-react-dependencies
|
|
196
|
+
|
|
197
|
+
Ensures that any package which depends on either `react` or `react-dom` explicitly lists both as dependencies.
|
|
198
|
+
React and ReactDOM are tightly coupled and should always be paired together to avoid runtime issues.
|
|
199
|
+
|
|
200
|
+
#### ✅ Autofix
|
|
201
|
+
|
|
202
|
+
This rule supports autofix.
|
|
203
|
+
It adds the missing `react` or `react-dom` dependency, using the same version that is already present. For example, given:
|
|
204
|
+
|
|
205
|
+
```json title="package.json"
|
|
206
|
+
{
|
|
207
|
+
"dependencies": {
|
|
208
|
+
"react": "^18.3.1"
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
It runs:
|
|
214
|
+
|
|
215
|
+
```sh
|
|
216
|
+
npm pkg set dependencies["react-dom"]="^18.3.1"
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
195
221
|
### require-explicit-side-effects
|
|
196
222
|
|
|
197
223
|
Warns if a package is missing the `sideEffects` property in its `package.json`.
|
|
@@ -290,6 +316,22 @@ It sets the version of each dependency to the [highest](#highest-versions) of th
|
|
|
290
316
|
|
|
291
317
|
---
|
|
292
318
|
|
|
319
|
+
### require-one-react-version
|
|
320
|
+
|
|
321
|
+
Ensures the same version of `react` and `react-dom` is used across the workspace.
|
|
322
|
+
|
|
323
|
+
These two packages are fundamentally designed to work together, with `react-dom` relying heavily on the internal structures and mechanisms exposed by `react`.
|
|
324
|
+
|
|
325
|
+
While React 17 introduced features for gradual upgrades and potentially using multiple React versions in specific scenarios, maintaining synchronized versions of `react` and `react-dom` is the recommended and safest practice to ensure compatibility and avoid unforeseen issues.
|
|
326
|
+
|
|
327
|
+
#### ✅ Autofix
|
|
328
|
+
|
|
329
|
+
This rule supports autofix.
|
|
330
|
+
It sets `react` and `react-dom` to the most common version in the repo.
|
|
331
|
+
If multiple versions tie for the most common, it uses the [highest](#highest-versions) version among the top contenders.
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
293
335
|
### require-one-uikit-version
|
|
294
336
|
|
|
295
337
|
Ensures the same version of related `uikit` packages is installed across the workspace.
|
package/docs/startup/start.mdx
CHANGED
|
@@ -17,4 +17,4 @@ Runs package in the development mode. Applications will be hosted on sequential
|
|
|
17
17
|
|
|
18
18
|
The `start` command executes the same steps as the `build` command, then watches for changes and automatically reruns each step as needed.
|
|
19
19
|
|
|
20
|
-
See [Build Steps](
|
|
20
|
+
See [Build Steps](./build#build-steps).
|
package/docs/startup/test.mdx
CHANGED
|
@@ -2,10 +2,204 @@
|
|
|
2
2
|
title: test
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
Runs
|
|
5
|
+
Runs your project's tests.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
- Supports both Jest and Vitest.
|
|
8
|
+
- Automatically selects the test runner based on your workspace configuration or the `--runner` option.
|
|
9
|
+
- Handles runner-specific arguments and passes them through to the underlying test tool.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
Run all tests with Jest (default):
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
npx startup test
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Run all tests with Vitest:
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
npx startup test --runner vitest
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
:::tip
|
|
26
|
+
Use the double-dash (--) separator to pass arguments to an `npm` script.
|
|
27
|
+
This separator indicates that any arguments following it should be passed directly to the script being executed, rather than being interpreted by `npm` itself.
|
|
28
|
+
For example, given the standard `startup test` script:
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"test": "npx startup test"
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Running,
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
npm run test -- --runner vitest
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Executes,
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
npx startup test --runner vitest
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
:::
|
|
49
|
+
|
|
50
|
+
## Running Specific Tests
|
|
51
|
+
|
|
52
|
+
To run specific tests, pass their file names or paths as additional arguments.
|
|
53
|
+
This works just like running Jest and Vitest directly, simply specify the file(s) you want to test:
|
|
54
|
+
|
|
55
|
+
### Examples
|
|
56
|
+
|
|
57
|
+
Run a specific test with Jest (default):
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
npx startup test app.test.tsx
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Run a specific test with Vitest:
|
|
64
|
+
|
|
65
|
+
```sh
|
|
66
|
+
npx startup test --runner vitest app.test.tsx
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Using Jest
|
|
70
|
+
|
|
71
|
+
The `startup test` command uses the Jest test runner by default.
|
|
72
|
+
|
|
73
|
+
### Configuration
|
|
74
|
+
|
|
75
|
+
The Jest runner provides a default, built-in configuration optimized for ServiceTitan workspaces.
|
|
76
|
+
|
|
77
|
+
You can override the defaults by specifying [Jest options](https://jestjs.io/docs/configuration) in your workspace `package.json` under the `"cli.jest"` key (the `"cli.test"` key also works, for backward compatibility). You can also use a standard Jest config file (such as `jest.config.js`) to override defaults.
|
|
78
|
+
|
|
79
|
+
Any options passed directly via the command line (e.g., `npx startup test --coverage`) take the highest precedence.
|
|
80
|
+
|
|
81
|
+
:::caution
|
|
82
|
+
If your project includes a standard Jest config file and also specifies Jest options in the workspace `package.json`, ensure that the configurations are mutually exclusive.
|
|
83
|
+
To avoid confusing or unexpected behavior, do not specify the same setting in both locations.
|
|
84
|
+
:::
|
|
85
|
+
|
|
86
|
+
### Examples
|
|
87
|
+
|
|
88
|
+
Use the workspace `package.json` to set up code that runs before each test file is executed:
|
|
89
|
+
|
|
90
|
+
```json title="package.json"
|
|
91
|
+
{
|
|
92
|
+
"cli": {
|
|
93
|
+
"jest": {
|
|
94
|
+
"setupFilesAfterEnv": ["<rootDir>/jest.setup.ts"]
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
:::note
|
|
101
|
+
For backward compatibility, you may also use the `ci.test` key:
|
|
102
|
+
:::
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
Use `jest.config.js` to increase Jest's `testTimeout` on Windows:
|
|
107
|
+
|
|
108
|
+
```js title="jest.config.js"
|
|
109
|
+
module.exports = {
|
|
110
|
+
testTimeout: process.platform === 'win32' ? 60 * 1000 : undefined, // increase timeout on Windows
|
|
111
|
+
};
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
Use the command line to collect test coverage:
|
|
117
|
+
|
|
118
|
+
```sh
|
|
119
|
+
npx startup test --coverage
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Use the command line to enable Jest's watch mode:
|
|
123
|
+
|
|
124
|
+
```sh
|
|
125
|
+
npx startup test --watch
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Using Vitest
|
|
129
|
+
|
|
130
|
+
✨ New in **v31.6.0** ✨
|
|
131
|
+
|
|
132
|
+
You can change the default test runner to `vitest` in your workspace's `package.json`:
|
|
133
|
+
|
|
134
|
+
```json title="package.json"
|
|
135
|
+
{
|
|
136
|
+
"cli": {
|
|
137
|
+
"testRunner": "vitest"
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Or override it per invocation with the `--runner` option.
|
|
143
|
+
|
|
144
|
+
### Configuration
|
|
145
|
+
|
|
146
|
+
The Vitest runner uses a layered configuration approach to provide sensible defaults while allowing full customization.
|
|
147
|
+
|
|
148
|
+
- Uses the default, built-in configuration as a base.
|
|
149
|
+
- Applies workspace overrides from `package.json`.
|
|
150
|
+
- Applies overrides from your Vitest config file.
|
|
151
|
+
- Applies command line options last.
|
|
152
|
+
|
|
153
|
+
1. **Default Configuration:**
|
|
154
|
+
The runner starts with a built-in default configuration optimized for ServiceTitan workspaces. This includes sensible coverage settings, the environment (`jsdom`), file exclusions, and more.
|
|
155
|
+
|
|
156
|
+
2. **Workspace Configuration:**
|
|
157
|
+
You can override defaults by specifying [Vitest options](https://vitest.dev/config) in your workspace `package.json` under the `"cli.vitest"` key.
|
|
158
|
+
|
|
159
|
+
3. **Vitest Config File:**
|
|
160
|
+
If your project includes a standard Vitest config file (such as `vitest.config.ts` or `vite.config.ts`), its settings will override both the defaults and workspace configuration.
|
|
161
|
+
|
|
162
|
+
4. **Command Line Arguments:**
|
|
163
|
+
Any options passed directly via the command line (e.g., `npx startup test --runner vitest --coverage`) take highest precedence and override all previous configuration layers.
|
|
164
|
+
|
|
165
|
+
### Examples
|
|
166
|
+
|
|
167
|
+
Use workspace `package.json` to make `vitest` APIs available [globally](https://vitest.dev/config/#globals) like Jest:
|
|
168
|
+
|
|
169
|
+
```json title="package.json"
|
|
170
|
+
{
|
|
171
|
+
"cli": {
|
|
172
|
+
"vitest": {
|
|
173
|
+
"globals": true
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
Use Vitest config file to disable watch mode:
|
|
182
|
+
|
|
183
|
+
```ts title="vitest.config.mts"
|
|
184
|
+
import { defineConfig } from 'vitest/config';
|
|
185
|
+
|
|
186
|
+
export default defineConfig({
|
|
187
|
+
test: {
|
|
188
|
+
watch: false,
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
Use the command line to disable watch mode:
|
|
196
|
+
|
|
197
|
+
```sh
|
|
198
|
+
npx startup test --runner vitest --run
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Use the command line to collect code coverage:
|
|
8
202
|
|
|
9
203
|
```sh
|
|
10
|
-
npx startup test --
|
|
204
|
+
npx startup test --runner vitest --coverage
|
|
11
205
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@servicetitan/docs-uikit",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "32.0.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -16,5 +16,5 @@
|
|
|
16
16
|
"cli": {
|
|
17
17
|
"webpack": false
|
|
18
18
|
},
|
|
19
|
-
"gitHead": "
|
|
19
|
+
"gitHead": "af064114b3ec8c08a4b693a66c4062a52b03504c"
|
|
20
20
|
}
|