@autofleet/cli 2.28.0 → 2.29.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/dist/claude-marketplace/plugins/autofleet/skills/mobx-usage/SKILL.md +114 -0
- package/dist/claude-marketplace/plugins/autofleet/skills/mobx-usage/examples.md +329 -0
- package/dist/e2e.js +1 -1
- package/dist/git-autofleet.js +1 -1
- package/dist/index.js +1 -1
- package/dist/{utils-DIMkM3Kw.js → utils-BE0PAuyu.js} +2 -2
- package/dist/{utils-DIMkM3Kw.js.map → utils-BE0PAuyu.js.map} +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mobx-usage
|
|
3
|
+
description: >-
|
|
4
|
+
MobX 6 patterns and conventions for Autofleet projects. Invoke when writing
|
|
5
|
+
or reviewing MobX stores, observer components, async actions, reactions, or
|
|
6
|
+
persistence. Applies to all @autofleet/* repos using MobX.
|
|
7
|
+
user-invocable: true
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# MobX Usage — Autofleet Conventions
|
|
11
|
+
|
|
12
|
+
This project uses **MobX 6** with **mobx-react-lite** (functional components only).
|
|
13
|
+
See **examples.md** for all code examples.
|
|
14
|
+
|
|
15
|
+
## Core Rules (never break these)
|
|
16
|
+
|
|
17
|
+
1. **No decorators** — never `@observable`, `@action`, `@computed`
|
|
18
|
+
2. **No `makeObservable`** — always use `makeAutoObservable`
|
|
19
|
+
3. **No `mobx-react`** — only `mobx-react-lite`
|
|
20
|
+
4. **No React Context for stores** — singleton + direct import only
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Store Definition
|
|
25
|
+
|
|
26
|
+
**Default: use plain `makeAutoObservable`** (see **examples.md → Store Definition → Using plain makeAutoObservable**) unless the app's CLAUDE.md explicitly specifies a different factory. Always read the relevant app's CLAUDE.md before writing a store.
|
|
27
|
+
|
|
28
|
+
- **Using `makeAutoObservableAndExpose`** custom wrapper that registers stores globally on `window.__globalMobxStores` for debugging — see **examples.md → Store Definition → Using makeAutoObservableAndExpose**
|
|
29
|
+
- Always declare `readonly [Symbol.toStringTag] = 'StoreName'` (required by the wrapper)
|
|
30
|
+
- Always pass `{ autoBind: true }` as the third argument
|
|
31
|
+
- Export a singleton instance at the bottom of the file
|
|
32
|
+
|
|
33
|
+
- **Excluding / overriding annotations**: pass overrides as the second argument — see **examples.md → Store Definition → Excluding / overriding annotations**
|
|
34
|
+
- `false` to exclude a property entirely
|
|
35
|
+
- `observable.ref` / `observable.shallow` / `computed.struct` to override inference
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Store Provision — Singleton Pattern
|
|
40
|
+
|
|
41
|
+
Stores are never provided via React Context or dependency injection. Always module-level singletons imported directly. Stores reference each other via direct imports too — see **examples.md → Store Provision**.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Observer Components
|
|
46
|
+
|
|
47
|
+
- Always wrap with `observer()` when reading observable values
|
|
48
|
+
- Always set `displayName` on observer components
|
|
49
|
+
- Split into small co-located observer components for granular re-renders
|
|
50
|
+
|
|
51
|
+
See **examples.md → Observer Components**.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Component-Scoped Reactive State
|
|
56
|
+
|
|
57
|
+
- **`useLocalObservable`**: for simple local reactive state that doesn't justify a store class — see **examples.md → Component-Scoped Reactive State → useLocalObservable**
|
|
58
|
+
- **`useLocalStoreWithProps`**: for class-based local stores that receive props; must implement `[setPropsSymbol]` — see **examples.md → Component-Scoped Reactive State → useLocalStoreWithProps**
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Async Patterns
|
|
63
|
+
|
|
64
|
+
- **`runInAction()`**: always wrap state mutations after `await` — both success and error paths — see **examples.md → Async Patterns → runInAction**
|
|
65
|
+
- **`fromPromise`** (mobx-utils): wraps promises to provide observable `.state` and `.case()` for rendering — see **examples.md → Async Patterns → fromPromise**
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Reactions
|
|
70
|
+
|
|
71
|
+
- **`reaction()`**: for side effects on observable changes
|
|
72
|
+
- Safe without disposers in **singleton store** constructors (live for app lifetime)
|
|
73
|
+
- **Local stores** must collect disposers and clean up in a `dispose()` method
|
|
74
|
+
- Supports options: `{ delay, equals: comparer.structural }`
|
|
75
|
+
- **`when()`**: for one-time condition triggers; supports await-style usage
|
|
76
|
+
- **`autorun()`**: for derived state synchronization
|
|
77
|
+
|
|
78
|
+
See **examples.md → Reactions**.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## MobX Utilities
|
|
83
|
+
|
|
84
|
+
- **`computedFn`** (mobx-utils): for computed values that take arguments — see **examples.md → MobX Utilities → computedFn**
|
|
85
|
+
- **`keepAlive`** (mobx-utils): prevents computed GC when unobserved — use sparingly, can cause memory leaks — see **examples.md → MobX Utilities → keepAlive**
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Persistence (`mobx-persist-store`)
|
|
90
|
+
|
|
91
|
+
Check your app's CLAUDE.md for which storage backend to use.
|
|
92
|
+
|
|
93
|
+
- **IndexedDB** (configured globally): use `this[Symbol.toStringTag]` as the store name — see **examples.md → Persistence → IndexedDB persistence**
|
|
94
|
+
- **IndexedDB — custom serialize/deserialize**: pass `{ key, serialize, deserialize }` objects in the `properties` array — see **examples.md → Persistence → IndexedDB — custom serialize/deserialize**
|
|
95
|
+
- **localStorage**: pass `storage: window.localStorage` per store — see **examples.md → Persistence → localStorage persistence**
|
|
96
|
+
- **Hydration check**: expose `isHydrated(this)` as a computed and `await when(() => this.isHydrated)` before reading persisted state — see **examples.md → Persistence → Hydration check**
|
|
97
|
+
|
|
98
|
+
See **examples.md → Persistence**.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Common Mistakes
|
|
103
|
+
|
|
104
|
+
| Wrong | Right |
|
|
105
|
+
|-------|-------|
|
|
106
|
+
| `const { items } = myStore` | `myStore.items` — destructuring breaks reactivity |
|
|
107
|
+
| `@observable field` | `makeAutoObservable(this)` |
|
|
108
|
+
| `makeObservable(this, {...})` | `makeAutoObservable(this)` |
|
|
109
|
+
| Mutating state after `await` directly | Wrap in `runInAction()` — both success and error paths |
|
|
110
|
+
| Component reads store but no `observer()` | Always wrap with `observer()` |
|
|
111
|
+
| `import { Provider }` from mobx-react | Direct singleton import |
|
|
112
|
+
| `import { observer } from 'mobx-react'` | `import { observer } from 'mobx-react-lite'` |
|
|
113
|
+
| Missing `Symbol.toStringTag` in ordering stores | Required for `makeAutoObservableAndExpose` |
|
|
114
|
+
| Passing store methods as callbacks without binding | Use `autoBind: true` (already configured) — never pass unbound method refs |
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
# MobX Usage — Examples
|
|
2
|
+
|
|
3
|
+
## Store Definition
|
|
4
|
+
|
|
5
|
+
### Using `makeAutoObservableAndExpose`
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { makeAutoObservableAndExpose } from '../stores/mobxUtils';
|
|
9
|
+
|
|
10
|
+
class MyStore {
|
|
11
|
+
readonly [Symbol.toStringTag] = 'MyStore'; // required — minification-safe debug name
|
|
12
|
+
|
|
13
|
+
someField = '';
|
|
14
|
+
items: Item[] = [];
|
|
15
|
+
|
|
16
|
+
constructor() {
|
|
17
|
+
makeAutoObservableAndExpose(this, undefined, { autoBind: true });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
get filteredItems() {
|
|
21
|
+
return this.items.filter(item => item.active);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const myStore = new MyStore();
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Using plain `makeAutoObservable`
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { makeAutoObservable } from 'mobx';
|
|
32
|
+
|
|
33
|
+
class SomeStore {
|
|
34
|
+
constructor() {
|
|
35
|
+
makeAutoObservable(this);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const someStore = new SomeStore();
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Excluding / overriding annotations
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
// Exclude non-serializable values
|
|
46
|
+
makeAutoObservableAndExpose<this, 'debounceHandler'>(
|
|
47
|
+
this,
|
|
48
|
+
{ debounceHandler: false },
|
|
49
|
+
{ autoBind: true },
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
// Override specific annotations
|
|
53
|
+
makeAutoObservableAndExpose<this, '_promise'>(
|
|
54
|
+
this,
|
|
55
|
+
{
|
|
56
|
+
someRef: observable.ref,
|
|
57
|
+
shallowList: observable.shallow,
|
|
58
|
+
structComputed: computed.struct,
|
|
59
|
+
_promise: false,
|
|
60
|
+
},
|
|
61
|
+
{ autoBind: true },
|
|
62
|
+
);
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Store Provision — Singleton Pattern
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
// store.ts
|
|
71
|
+
export const catalogStore = new CatalogStore();
|
|
72
|
+
|
|
73
|
+
// component.tsx
|
|
74
|
+
import { catalogStore } from './CatalogStore';
|
|
75
|
+
|
|
76
|
+
export const CatalogPage = observer(() => (
|
|
77
|
+
<div>{catalogStore.items.length}</div>
|
|
78
|
+
));
|
|
79
|
+
CatalogPage.displayName = 'CatalogPage';
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Observer Components
|
|
85
|
+
|
|
86
|
+
### Basic observer
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
import { observer } from 'mobx-react-lite';
|
|
90
|
+
|
|
91
|
+
export const MyComponent = observer(() => {
|
|
92
|
+
return <div>{myStore.someValue}</div>;
|
|
93
|
+
});
|
|
94
|
+
MyComponent.displayName = 'MyComponent';
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Split co-located observers
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
const Header = observer(() => <h1>{store.title}</h1>);
|
|
101
|
+
const ItemList = observer(() => <ul>{store.items.map(...)}</ul>);
|
|
102
|
+
|
|
103
|
+
export const MyPage = observer(() => (
|
|
104
|
+
<div><Header /><ItemList /></div>
|
|
105
|
+
));
|
|
106
|
+
MyPage.displayName = 'MyPage';
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Component-Scoped Reactive State
|
|
112
|
+
|
|
113
|
+
### `useLocalObservable`
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
export const MyComponent = observer(() => {
|
|
117
|
+
const local = useLocalObservable(() => ({
|
|
118
|
+
isOpen: false,
|
|
119
|
+
toggle() { this.isOpen = !this.isOpen; },
|
|
120
|
+
get label() { return this.isOpen ? 'Close' : 'Open'; },
|
|
121
|
+
}));
|
|
122
|
+
|
|
123
|
+
return <button onClick={local.toggle}>{local.label}</button>;
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### `useLocalStoreWithProps`
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
import { useLocalStoreWithProps, setPropsSymbol } from '@autofleet/ui-components/dist/hooks';
|
|
131
|
+
|
|
132
|
+
class MyLocalStore {
|
|
133
|
+
private data!: SomeType;
|
|
134
|
+
|
|
135
|
+
constructor(props: Props) {
|
|
136
|
+
this[setPropsSymbol](props);
|
|
137
|
+
makeAutoObservable(this, undefined, { autoBind: true });
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
public [setPropsSymbol](props: Props): void {
|
|
141
|
+
this.data = props.data;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
get computed() { return transform(this.data); }
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const MyComponent = observer((props: Props) => {
|
|
148
|
+
const store = useLocalStoreWithProps(MyLocalStore, props);
|
|
149
|
+
return <div>{store.computed}</div>;
|
|
150
|
+
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Async Patterns
|
|
156
|
+
|
|
157
|
+
### `runInAction`
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
async loadData() {
|
|
161
|
+
try {
|
|
162
|
+
const result = await fetchData();
|
|
163
|
+
runInAction(() => {
|
|
164
|
+
this.data = result;
|
|
165
|
+
});
|
|
166
|
+
} catch (error) {
|
|
167
|
+
runInAction(() => {
|
|
168
|
+
this.error = error;
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### `fromPromise`
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
import { fromPromise, IPromiseBasedObservable } from 'mobx-utils';
|
|
178
|
+
|
|
179
|
+
class MyStore {
|
|
180
|
+
detailsPromise: IPromiseBasedObservable<Details> | null = null;
|
|
181
|
+
|
|
182
|
+
loadDetails(id: string) {
|
|
183
|
+
this.detailsPromise = fromPromise(fetchDetails(id), this.detailsPromise);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
get details() {
|
|
187
|
+
return this.detailsPromise?.case({ fulfilled: val => val });
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Reactions
|
|
195
|
+
|
|
196
|
+
### `reaction` — singleton store (no cleanup needed)
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
constructor() {
|
|
200
|
+
makeAutoObservableAndExpose(this, undefined, { autoBind: true });
|
|
201
|
+
reaction(
|
|
202
|
+
() => this.searchTerm.trim(),
|
|
203
|
+
(term) => this.debouncedSearch(term),
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
// With options
|
|
207
|
+
reaction(
|
|
208
|
+
() => ({ options: this.selectedOptions, id: this.vehicleId }),
|
|
209
|
+
(data) => this.updateIncentives(data),
|
|
210
|
+
{ delay: 300, equals: comparer.structural },
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### `reaction` — local store (collect disposers)
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
private disposers: (() => void)[] = [];
|
|
219
|
+
|
|
220
|
+
constructor() {
|
|
221
|
+
this.disposers.push(
|
|
222
|
+
reaction(() => this.settings, () => this.saveToStorage()),
|
|
223
|
+
);
|
|
224
|
+
this.disposers.push(
|
|
225
|
+
reaction(() => this.key, (newKey, oldKey) => { /* ... */ }),
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
dispose() {
|
|
230
|
+
this.disposers.forEach(d => d());
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### `when`
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
when(
|
|
238
|
+
() => !!this.reservationNumber && !!this.selectedAccount,
|
|
239
|
+
() => void this.loadReservation(),
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
// Await-style
|
|
243
|
+
await when(() => authStore.isReady);
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### `autorun`
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
autorun(() => {
|
|
250
|
+
this.params.vehicleIds = this.selectedVehicle ? [this.selectedVehicle.id] : null;
|
|
251
|
+
});
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## MobX Utilities
|
|
257
|
+
|
|
258
|
+
### `computedFn`
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
import { computedFn } from 'mobx-utils';
|
|
262
|
+
|
|
263
|
+
class MyStore {
|
|
264
|
+
isItemSelected = computedFn(
|
|
265
|
+
(itemId: string) => this.selectedIds.includes(itemId),
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
optionIncludedIn = computedFn(
|
|
269
|
+
(optionCode: string) => this.parentOptionByCode[optionCode] ?? [],
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### `keepAlive`
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
import { keepAlive } from 'mobx-utils';
|
|
278
|
+
|
|
279
|
+
constructor() {
|
|
280
|
+
makeAutoObservableAndExpose(this, undefined, { autoBind: true });
|
|
281
|
+
keepAlive(this, 'expensiveComputed');
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## Persistence (`mobx-persist-store`)
|
|
288
|
+
|
|
289
|
+
### IndexedDB persistence
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
constructor() {
|
|
293
|
+
makeAutoObservableAndExpose(this, undefined, { autoBind: true });
|
|
294
|
+
void makePersistable(this, {
|
|
295
|
+
name: this[Symbol.toStringTag],
|
|
296
|
+
properties: ['field1', 'field2'],
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### IndexedDB — custom serialize/deserialize
|
|
302
|
+
|
|
303
|
+
```typescript
|
|
304
|
+
void makePersistable(this, {
|
|
305
|
+
name: this[Symbol.toStringTag],
|
|
306
|
+
properties: [
|
|
307
|
+
{ key: '_flags', serialize: encode, deserialize: decode },
|
|
308
|
+
],
|
|
309
|
+
});
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### Hydration check
|
|
313
|
+
|
|
314
|
+
```typescript
|
|
315
|
+
get isHydrated() { return isHydrated(this); }
|
|
316
|
+
|
|
317
|
+
// Wait for hydration before proceeding
|
|
318
|
+
await when(() => this.isHydrated);
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### localStorage persistence
|
|
322
|
+
|
|
323
|
+
```typescript
|
|
324
|
+
void makePersistable(this, {
|
|
325
|
+
name: 'storeName',
|
|
326
|
+
properties: ['field1'],
|
|
327
|
+
storage: window.localStorage,
|
|
328
|
+
});
|
|
329
|
+
```
|
package/dist/e2e.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{C as e,c as t,i as n,l as r,n as i,x as a}from"./utils-
|
|
2
|
+
import{C as e,c as t,i as n,l as r,n as i,x as a}from"./utils-BE0PAuyu.js";import o from"node:path";import s from"p-retry";const c=[`identity-ms`,`vehicle-ms`,`ride-ms`,`vehicle-live-data-ms`,`pricing-ms`,`payment-ms`,`route-plan-ms`,`task-ms`,`audit-ms`,`pgweb`,`placement-ms`,`demand-prediction-ms`,`control-center-ms`,`setting-ms`,`api-gateway-ms`],l={start:`--e2eBranch=<branchName> --branches="{\\"ride-ms\\": \\"AUT-7070\\"}"`,getIpsForEnv:`--variationId=<yourVariationUuid> --cluster=<dev1/e2eManager>`},u=e=>Object.keys(l).includes(e),{positionals:d,values:f,help:p}=e({strict:!0,binName:`autofleet-e2e`,allowPositionals:!0,options:{e2eBranch:{type:`string`,default:`master`,description:`Name of e2e branch`},branches:{type:`string`,default:``,description:`"ride-ms": "AUT-7070"`},cluster:{type:`string`,short:`c`,description:`The cluster name. One of dev1, e2eManager, expManager`},variationId:{type:`string`,short:`i`,description:`The variation id`}},commands:l});d.length||(console.log(p),process.exit(0));const[m]=d;if(u(m)||n(Error(`Command ${m} does not exist`),p),m===`start`){let e=(f.branches?.replace(`{`,` `)||``).replace(/[^a-z0-9]/gi,``),t=`${o.resolve()}/bin/utils/e2e.sh`,n=`${o.resolve()}/e2e.sh`;r({newFilePath:n,filePath:t,linesToReplace:[{find:`$E2E_BRANCH_PLACE_HOLDER$`,replace:f.e2eBranch},{find:`$BRANCHES_PLACE_HOLDER$`,replace:f.branches},{find:`$NAME_PLACE_HOLDER$`,replace:e}]}),await a(`chmod`,[`+x ${n} && ${n}`]),console.log(`finished e2e`)}const{cluster:h,variationId:g}=f;h||n(Error(`cluster required`),p),g||n(Error(`variationId required`),p);let _;try{_=await i({clusterName:h,variationId:g})}catch(e){n(e)}m===`getIpsForEnv`&&(await Promise.all(c.map(e=>a(`kubectl`,[`annotate`,_,`service`,e,`cloud.google.com/load-balancer-type-`],{print:!1}))),await Promise.all(c.map(e=>a(`kubectl`,[`patch`,`svc`,_,e,`-p`,`{"spec": {"type": "LoadBalancer"}}`],{print:!1}))),console.log(`exposed services successfully. the services are now creating public ips.`),await s(async()=>{let{stdout:e}=await a(`kubectl`,[_,`get`,`services`],{print:!1}),n=t(e);if(n.some(e=>e.includes(`<pending>`)))throw Error(`Some services are still pending`);n.forEach(e=>console.log(e))},{retries:10,factor:1,maxTimeout:5e3,randomize:!0}),process.exit(0));export{};
|
|
3
3
|
//# sourceMappingURL=e2e.js.map
|
package/dist/git-autofleet.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{C as e,_ as t,g as n,h as r,i,m as a,v as o,x as s,y as c}from"./utils-
|
|
2
|
+
import{C as e,_ as t,g as n,h as r,i,m as a,v as o,x as s,y as c}from"./utils-BE0PAuyu.js";import{basename as l,sep as u}from"node:path";import{readdir as d}from"node:fs/promises";import{randomUUID as f}from"node:crypto";const p=[`premajor`,`preminor`,`prepatch`,`prerelease`],m=[`major`,`minor`,`patch`,...p],h={bumpVersion:`[${m.join(`|`)}]`,openPR:`Opens github UI for creating a PR from the current branch.`,releaseBeta:`Bumps version if needed, and publishes a beta release to NPM registry.`},g=e=>Object.keys(h).includes(e),_=async({versionType:e,packageName:t,preReleaseId:n=``})=>{let{stdout:r}=await s(`npm`,[`version`,e,`--no-git-tag-version`,`--preid`,n],{print:!1,cwd:t?`.${u}packages${u}${t}`:void 0});return await s(`git`,[`add`,`package*`],{print:!1}),await s(`git`,[`commit`,`-m`,`${e} version: ${r}`],{print:!1}),console.log(`Created commit for version bump: ${e}. Version is now ${r}`),r},v=async e=>{let t=await c(),{default:{version:n}}=await import(`${e?`${t}${u}packages${u}${e}`:t}${u}package.json`,{assert:{type:`json`},with:{type:`json`}});return n.replace(/\d+\.\d+\.\d+(?:-beta-([\w]+)?\.\d+)?/,`$1`)},{positionals:y,help:b}=e({strict:!0,binName:`git autofleet`,allowPositionals:!0,options:{},commands:h});y.length||(console.log(b),process.exit(0));const[x,S,C]=y;if(g(x)||i(Error(`Command ${x} does not exist`),b),x===`openPR`){let[e,t]=await Promise.all([c(),o()]);await s(`open`,[`https://github.com/Autofleet/${l(e)}/compare/${t}?expand=1`],{print:!1}),process.exit(0)}async function w(){let e=await c();return e.split(u).pop()===`autorepo`?e:!1}async function T({message:e,pathIfAutorepo:t}){t??=await w();let r=C;if(t){let a=(await d(`${t}${u}packages`)).filter(e=>!e.startsWith(`.`));r?a.includes(r)||i(Error(`Package name ${r} does not exist in autorepo packages`),b):r=await n({message:e,choices:a.map(e=>({name:e,value:e}))}),r||i(Error(`No package name provided, exiting...`),b)}return r}if(x===`bumpVersion`){let e=await T({message:`Which package do you want to bump?`}),t=S||await n({message:`Which version type do you want to bump?`,choices:(x===`bumpVersion`?m:p).map(e=>({name:e,value:e}))});t||i(Error(`Must explicitly define version type.\n\tVersion type can be one of: ${m.join(`, `)}`),b);let r=await o();[`main`,`master`].includes(r)&&(await a(`Are you sure you want to bump version on main branch?`)||process.exit(0)),await _({versionType:t,packageName:e}),process.exit(0)}if(x===`releaseBeta`){let e=await w(),n=await T({message:`Which package do you want to release?`,pathIfAutorepo:e});S&&!p.includes(S)&&i(Error(`Invalid version type: ${S}\n\tVersion must be a prerelease type. (${p.join(`, `)})`),b);let c=await o();[`main`,`master`].includes(c)&&i(Error(`Cannot release beta from main branch`),b);let l=n?`.${u}packages${u}${n}`:void 0,d=!(await t(n?`.${u}packages${u}${n}${u}package.json`:`package.json`)).split(`
|
|
3
3
|
`).some(e=>/^\+\s*"version":\s*"\d+\.\d+\.\d+(?:-(?:[\w-]+\.)?\d+)?",/.test(e))||await a(`Version already bumped on branch. Should version be re-bumped?`),m=d&&await v(n),h=d&&await _({versionType:S||`prerelease`,preReleaseId:`beta-${m||f().split(`-`)[0]}`,packageName:n}),g=e?`pnpm`:`npm`;await s(g,[`run`,`build`],{cwd:l});let y=await r({message:`In case your token requires an OTP, please enter it:`});try{await s(g,[`publish`,`--tag`,`beta`,`--@autofleet:registry=https://registry.npmjs.org`,...y?[`--otp`,y]:[],...e?[`--no-git-checks`]:[]],{cwd:l})}catch(e){console.error(e),i(`Failed to publish beta version`)}if(h)console.log(`Published beta version with new version: ${h}`);else{let{stdout:e}=await s(g,[`info`,`.`,`version`],{print:!1,cwd:l});console.log(`Published beta version with existing version: ${e}`)}process.exit(0)}export{};
|
|
4
4
|
//# sourceMappingURL=git-autofleet.js.map
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{C as e,S as t,a as n,b as r,c as i,d as a,f as o,g as s,i as c,m as l,n as u,o as d,p as f,r as p,s as m,t as h,u as g,v as ee,w as te,x as _,y as v}from"./utils-
|
|
2
|
+
import{C as e,S as t,a as n,b as r,c as i,d as a,f as o,g as s,i as c,m as l,n as u,o as d,p as f,r as p,s as m,t as h,u as g,v as ee,w as te,x as _,y as v}from"./utils-BE0PAuyu.js";import{styleText as y}from"node:util";import*as ne from"node:fs";import b from"node:fs";import{execFile as re,execSync as x,spawn as ie}from"node:child_process";import{confirm as S}from"@inquirer/prompts";import*as C from"node:path";import w,{basename as T,join as E,resolve as D,sep as ae}from"node:path";import{mkdir as oe,readFile as O,writeFile as k}from"node:fs/promises";import*as se from"node:os";import ce,{EOL as A}from"node:os";import{randomUUID as le}from"node:crypto";import{setTimeout as ue}from"node:timers/promises";import{cwd as j}from"node:process";function M(e){return e.replace(/^[\^~]/,``)}function N(e){let t=M(e),n=/^(\d+)/.exec(t);return n?parseInt(n[1],10):0}function de(e,t){return N(t)>N(e)}function fe(e,t){if(e.includes(`-`)||t.includes(`-`))return!1;let n=e=>e.split(`.`).map(Number),[r,i,a]=n(e),[o,s,c]=n(t);return r===o?i===s?a>c:i>s:r>o}const P=w.join(ce.homedir(),`.autofleet`,`update-check.json`);function pe(){try{return JSON.parse(b.readFileSync(P,`utf-8`))}catch{return null}}function me(e){try{b.mkdirSync(w.dirname(P),{recursive:!0}),b.writeFileSync(P,JSON.stringify(e))}catch{}}function he(e,t){try{return x(`${e} ${t.join(` `)}`,{encoding:`utf-8`,stdio:[`ignore`,`pipe`,`ignore`]}).trim()||null}catch{return null}}function ge(){let e=process.argv[1]??``;for(let{pm:t,args:n}of[{pm:`pnpm`,args:[`root`,`-g`]},{pm:`yarn`,args:[`global`,`dir`]},{pm:`npm`,args:[`root`,`-g`]}]){let r=he(t,n);if(r&&e.startsWith(r))return t}return`npm`}function _e(e){return e===`pnpm`?`pnpm add -g @autofleet/cli@latest`:e===`yarn`?`yarn global add @autofleet/cli@latest`:`${w.join(w.dirname(process.execPath),`npm`)} install -g @autofleet/cli@latest`}function ve(){re(`npm`,[`view`,`@autofleet/cli@latest`,`version`],{encoding:`utf-8`,timeout:15e3},(e,t)=>{if(e||!t.trim())return;let n=t.trim();n&&me({latestVersion:n,checkedAt:Date.now()})}).unref()}async function ye(e=!1){if(e)return;let t=pe();if(t&&fe(t.latestVersion,te)&&await l(`New @autofleet/cli version available (${te} → ${t.latestVersion}). Update now?`)){let e=_e(ge());console.log(`Updating @autofleet/cli...`),x(e,{stdio:`inherit`}),console.log(`✓ Updated! Please re-run your command.`),process.exit(0)}(t?Date.now()-t.checkedAt:1/0)>864e5&&ve()}const F=`.mirrord`;async function I({makeDir:e=!1}={}){let t=E(await v(),F);return e&&await oe(t,{recursive:!0}),E(t,`mirrord.json`)}async function be(e=le()){let t=await I({makeDir:!0}),n={feature:{network:{incoming:{mode:`steal`,http_filter:{ports:[8080],path_filter:`^(?!/alive|/ready)`}},outgoing:!0},fs:`read`,env:!0},target:{namespace:e},agent:{ephemeral:!0,startup_timeout:600,communication_timeout:120,namespace:e}};return await k(t,JSON.stringify(n,null,2)),{mirrordConfigData:n,mirrordPath:t}}async function xe(){try{let e=await O(await I(),{encoding:`utf-8`});return JSON.parse(e||`{}`)?.target?.namespace??``}catch{return``}}function Se(e){process.once(`exit`,e),process.once(`SIGTERM`,e),process.once(`SIGINT`,e)}function L(e){return e&&=e.trim(),e&&(e.startsWith(`'`)&&e.endsWith(`'`)&&(e=e.slice(1,-1)),e)}const R=`livenessProbe`,z=`readinessProbe`,B=e=>`jsonpath='{.spec.template.spec.containers[?(@.name=="worker")].${e}}'`,V=(...e)=>`{"spec": {"template": {"spec": {"containers": [{"name": "worker",${e.map(([e,t])=>`"${e}": ${t}`).join(`,`)}}]}}}}`;var Ce=async(e,t,n)=>{console.log(`Will now disable health check to allow debugging.`);let[{stdout:r},{stdout:i}]=await Promise.all([_(`kubectl`,[`get`,`deployment/${n}`,e,`-o`,B(R)],{print:!1}),_(`kubectl`,[`get`,`deployment/${n}`,e,`-o`,B(z)],{print:!1})]);r&&=L(r),i&&=L(i),(r||i)&&(await _(`kubectl`,[`patch`,`deployment/${n}`,e,`--patch`,V([R,`null`],[z,`null`])],{print:!1}),console.log(`Health check disabled, will now start mirrord and run "npm run dev". Make sure to attach a debugger!`));let a=new AbortController;Se(async()=>{globalThis.executedExitHooks||(globalThis.executedExitHooks=!0,a.abort(),(r||i)&&(console.log(`Re-enabling health check.`),await _(`kubectl`,[`patch`,`deployment/${n}`,e,`--patch`,`'${V([R,r],[z,i])}'`],{print:!1,shell:!0}),console.log(`health check enabled.`)),process.exit(0))});try{let e=await I();await _(`mirrord`,[`exec`,`-t`,`deployment/${n}`,`-n`,t,`-f`,e,`--steal`,`npm`,`run`,`dev`],{signal:a.signal})}catch(e){if(e&&typeof e==`object`&&`code`in e&&e.code===`ABORT_ERR`)return;c(e)}},we=async(e,t)=>{if(await p(e),e===`expManager`||e===`dev1`){let{variationId:e}=await g({variationId:t},[`variationId`]);e!==``&&(await n()===e&&(console.log(`Already connected to simulation with uuid: ${e}, skipping namespace switch...`),process.exit(0)),await _(`kubectl`,[`config`,`set-context`,`--current`,`--namespace=${e}`],{print:!1}),console.log(`Switched to simulation with uuid: ${e} successfully`))}process.exit(0)};async function Te(){try{await _(`telepresence`,[`version`],{print:!1})}catch{c(`Telepresence is not installed. Please install it from:
|
|
3
3
|
https://www.telepresence.io/docs/latest/quick-start/`)}}function Ee(){return s({message:`Do you want to leave the connection or create a new one?`,choices:[{name:`Leave the current connection`,value:`leave`},{name:`Create a new connection`,value:`connect`}],default:`connect`})}async function De(e){await Te();let{cluster:t=``,service:n=``}=e;await p(t);let r=await Ee();if([`leave`,`connect`].includes(r)||c(`Invalid action, how did you get here? 🤔`),r===`leave`){await _(`telepresence`,[`leave`,n]),console.log(`Disconnected! 👋`);return}let i=e.variationId||await f(),a=e[`local-port`]&&Number.parseInt(e[`local-port`],10)||Number.parseInt(await o()||``,10);await _(`telepresence`,[`connect`,`--namespace=${i}`]),await _(`telepresence`,[`intercept`,n,`--port`,a.toString(),`--env-file=./.env`]),console.log(`Everything is set up! 🚀`),console.log(`You can now access the service at localhost:${a}`),console.log(`You can only have one connection at a time. If you want to connect to a different service, you need to leave the current connection first.`),process.exit(0)}var Oe=async(e,t,n)=>{n||c(Error(`service is required for exposeService`),t),await _(`kubectl`,[`patch`,`svc`,e,n,`-p`,`{"spec": {"type": "LoadBalancer"}}`]),console.log(`exposed ${n} successfully. the service is now creating an internal load balancer ip to use with vpn`),process.exit(0)},ke=async(e,t,n,r,i)=>{let a=Number.parseInt(e[`local-port`]??`5432`,10);Number.isNaN(a)&&c(Error(`if defined, local-port must be a number`),r);let o=`afpass_${n}`,s=`postgres`,l=n.replaceAll(`-`,`_`),u=i?`${i.replaceAll(`-`,`_`)||``}_${l}`:`postgres`,d=`postgres://${s}:${o}@localhost:${a}/${u}?&nickname=var_${n}`;console.log(`Forwarding db to local port ${a}.\naccess the DB at ${d}\nPress ctrl+c to stop.`);let f=` DB_USERNAME=${s}
|
|
4
4
|
DB_PASSWORD=${o}
|
|
5
5
|
DB_NAME=${i?u:`<service_name>_${l}`}`;console.log(`Generated database environment for local development:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{parseArgs as e}from"node:util";import t from"node:fs";import{spawn as n}from"node:child_process";import{confirm as r,input as i,select as a}from"@inquirer/prompts";import{sep as o}from"node:path";import{readdir as s}from"node:fs/promises";var c=`2.
|
|
1
|
+
import{parseArgs as e}from"node:util";import t from"node:fs";import{spawn as n}from"node:child_process";import{confirm as r,input as i,select as a}from"@inquirer/prompts";import{sep as o}from"node:path";import{readdir as s}from"node:fs/promises";var c=`2.29.0`;const l={help:{type:`boolean`,short:`h`,default:!1,description:`Show help (prints this message)`},version:{type:`boolean`,short:`v`,default:!1,description:`Show version number`},quiet:{type:`boolean`,short:`q`,default:!1,description:`Skip interactive prompts (e.g. version update check)`}};function u(t){t.options={...l,...t.options};let n=e(t),{values:r}=n;r.version&&(console.log(c),process.exit(0));let i=t.commands?`
|
|
2
2
|
|
|
3
3
|
Commands:
|
|
4
4
|
${Object.entries(t.commands).map(([e,t])=>`${e.padEnd(30,` `)} ${t}`).join(`
|
|
@@ -10,4 +10,4 @@ Options:
|
|
|
10
10
|
`)}
|
|
11
11
|
`;return r.help&&(console.log(o),process.exit(0)),{...n,help:o}}const d=()=>{if(Promise.withResolvers)return Promise.withResolvers();let e,t;return{promise:new Promise((n,r)=>{e=r,t=n}),reject:e,resolve:t}};var f=async(e,t,{print:r=!0,env:i={},signal:a,shell:o,cwd:s}={})=>{typeof t==`boolean`&&(r=t,t=void 0);let c=Error(),l=c.stack?c.stack.replace(/^.*/,` ...`):null,{promise:u,reject:f,resolve:p}=d(),m=n(e,t,{env:Object.assign(i,process.env),signal:a,shell:o,cwd:s});r&&(m.stdout.pipe(process.stdout),m.stderr.pipe(process.stderr));let h=``,g=``;m.stdout?.on(`data`,e=>{h+=e}),m.stderr?.on(`data`,e=>{g+=e});let _=r?`exit`:`close`;function v(e){m.removeListener(_,y),Object.assign(e,{pid:m.pid,stdout:h,stderr:g,status:null,signal:null}),f(e)}function y(n,r){m.removeListener(`error`,v);let i={pid:m.pid,stdout:h,stderr:g,status:n,signal:r};if(n!==0){let a=typeof t!=`boolean`&&` ${t?.join(` `)}`||``,o=r?Error(`${e}${a} exited with signal: ${r}`):Error(`${e}${a} exited with non-zero code: ${n}`);o.stack&&l&&(o.stack+=`\n${l}`),Object.assign(o,i),f(o)}else p(i)}return m.once(_,y),m.once(`error`,v),u};const p=async()=>{let{stdout:e}=await f(`git`,[`branch`,`--show-current`],{print:!1});return e.trim()},m=async()=>{let{stdout:e}=await f(`git`,[`rev-parse`,`--show-toplevel`],{print:!1});return e.trim()},h=async e=>{let{stdout:t}=await f(`git`,[`diff`,`origin/master..`,e],{print:!1});return t},g=async e=>{try{return await f(`git`,[`check-ignore`,e],{print:!1}),!0}catch{return!1}};function _(){var e=typeof SuppressedError==`function`?SuppressedError:function(e,t){var n=Error();return n.name=`SuppressedError`,n.error=e,n.suppressed=t,n},t={},n=[];function r(e,t){if(t!=null){if(Object(t)!==t)throw TypeError(`using declarations can only be used with objects, functions, null, or undefined.`);if(e)var r=t[Symbol.asyncDispose||Symbol.for(`Symbol.asyncDispose`)];if(r===void 0&&(r=t[Symbol.dispose||Symbol.for(`Symbol.dispose`)],e))var i=r;if(typeof r!=`function`)throw TypeError(`Object is not disposable.`);i&&(r=function(){try{i.call(t)}catch(e){return Promise.reject(e)}}),n.push({v:t,d:r,a:e})}else e&&n.push({d:t,a:e});return t}return{e:t,u:r.bind(null,!1),a:r.bind(null,!0),d:function(){var r,i=this.e,a=0;function o(){for(;r=n.pop();)try{if(!r.a&&a===1)return a=0,n.push(r),Promise.resolve().then(o);if(r.d){var e=r.d.call(r.v);if(r.a)return a|=2,Promise.resolve(e).then(o,s)}else a|=1}catch(e){return s(e)}if(a===1)return i===t?Promise.resolve():Promise.reject(i);if(i!==t)throw i}function s(n){return i=i===t?n:new e(n,i),o()}return o()}}}Symbol.dispose??=Symbol.for(`nodejs.dispose`),Symbol.asyncDispose??=Symbol.for(`nodejs.asyncDispose`);let v;const y=()=>v?.();function b(){return process.once(`beforeExit`,y),{[Symbol.dispose](){process.off(`beforeExit`,y),v=void 0}}}async function x(e,...t){try{try{var n=_();n.u(b());let r=e(...t);return v=r.cancel,await r}catch(e){n.e=e}finally{n.d()}}catch(e){e instanceof Error&&[`CancelPromptError`,`ExitPromptError`].includes(e.constructor.name)&&J(`Cancelled! 👋`),J(e);return}}function S(...e){return x(a,...e)}function C(...e){return x(i,...e)}const w=e=>e.charAt(0).toUpperCase()+e.slice(1).split(/(?=[A-Z])/).join(` `);function T(){return S({message:`Which environment do you want to use?`,choices:B.map(e=>({name:w(e),value:e})),default:`expManager`})}async function E(e){return S({message:`Using from autorepo, Which app do you want to use?`,choices:(await s(`${e}${o}apps`)).filter(e=>!e.startsWith(`.`)&&!e.endsWith(`-e2e`)).map(e=>({name:e,value:e}))})}async function D(){let e=await m(),t=e.split(o).pop();return t===`autorepo`?E(e):C({message:`Enter the service name:`,default:t})}function O(e=`default`){return C({message:`Enter your simulator id (Press enter to pass):`,default:e})}async function k(e=`8080`,t=!1){return C({message:`Enter the ${t?`local `:``}port:`,default:e,validate(e){return/^([1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$/.test(e)?!0:`Please enter a valid port number`}})}async function A(e=`5432`){return k(e,!0)}const j={cluster:T,variationId:O,service:D,port:(e=`8080`)=>k(e),"local-port":A};async function M(e,t){for(let n of t){let t=typeof n==`object`?n.option:n,r=typeof n==`object`?n.defaultVal:void 0;if(typeof t!=`string`)throw Error(`Invalid option ${String(t)}`);let i=j[t];if(!i)throw Error(`No value getter for ${String(t)}`);e[t]??=await i(r)}return e}async function N(e,t=!0){return x(r,{message:e,default:t})}const P={prodUs:[`us-autofleet-production`,`us-central1`,`autofleet-production`],prodEu:[`eu-prod-autofleet`,`europe-west1`,`autofleetprod`],prodJp:[`jp-autofleet`,`asia-northeast1`,`autofleet-japan`]},F={dev1:[`dev-cluster-2`,`europe-west1`,`dev1-experiment-manager`],e2eManager:[`e2e-cluster-2`,`europe-west1`,`e2e-project-1`],expManager:[`af-experiment-manager`,`europe-west1`]},I={staging:[`stg-autofleet`,`europe-west1`,`autofleet-staging`],loadTest:[`lt-autofleet-production`,`asia-northeast1`,`load-testing-428806`]},L={osrmProd:[`maps-prod`,`europe-west1`,`af-mapping`]},R={...P,...F,...I,...L},z={staging:`europe-west1`},B=Object.keys(R),V=async e=>{let t=R[e];if(!t)throw Error(`Cluster name ${e} does not exist!`);let[n,r,i]=t;return P[e]&&!await N(`❌❌ Are you sure you want to run this command on ${e}? ❌❌`,!1)?(console.log(`Aborting...`),process.exit(1)):{name:n,region:r,project:i}},H=({newFilePath:e,filePath:n,linesToReplace:r})=>{let i=t.readFileSync(n,`utf8`);for(let{find:e,replace:t}of r)i=i.replace(e,t);t.writeFileSync(e,i)};async function U(){try{let{stdout:e}=await f(`kubectl`,[`config`,`current-context`],{print:!1});return e.trim()}catch{return null}}const W=async e=>{let{name:t,region:n,project:r}=await V(e),i=`gke_${r||t}_${n}_${t}`;return await U()===i?(console.log(`Already connected to ${e}, skipping connection to cluster...`),{name:t,region:n,project:r}):(await f(`gcloud`,[`container`,`clusters`,`get-credentials`,t,`--region`,n,`--project`,r||t],{print:!1}),console.log(`Switched to ${e} successfully`),{name:t,region:n,project:r})};async function G(){try{let{stdout:e}=await f(`kubectl`,[`config`,`view`,`--minify`,`--output`,`jsonpath={..namespace}`],{print:!1});return e.trim()}catch{return`default`}}const K=async({clusterName:e,variationId:t})=>(await W(e),`--namespace=${t}`),q=e=>{let t=e.split(`
|
|
12
12
|
`).filter(Boolean);t.shift();let n=t.map(e=>{let[t,n,r,i,a,o]=e.split(/(\s+)/).map(e=>e.trim()).filter(Boolean);return`${t.replace(/-/g,`_`).toUpperCase()}_SERVICE_HOST=${i}`});return n=n.filter(e=>!e.includes(`none`)&&!e.includes(`undefined`)),n};function J(e,t){return e instanceof Error||(e=Error(e)),console.error(e),t&&console.log(t),process.exit(1)}const Y=e=>Object.keys(F).includes(e),X=e=>z[e]||R[e][1];export{u as C,d as S,h as _,G as a,g as b,q as c,E as d,A as f,S as g,C as h,J as i,H as l,N as m,K as n,X as o,O as p,W as r,Y as s,B as t,M as u,p as v,c as w,f as x,m as y};
|
|
13
|
-
//# sourceMappingURL=utils-
|
|
13
|
+
//# sourceMappingURL=utils-BE0PAuyu.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils-DIMkM3Kw.js","names":["parseArgs","nativeParseArgs","packageJson.version","reject!: PromiseWithResolvers<T>['reject']","resolve!: PromiseWithResolvers<T>['resolve']","result: SpawnResult","signal","asyncSpawn","path","cancelFn: (() => void) | undefined","asyncSpawn"],"sources":["../package.json","../bin/utils/parser.ts","../bin/utils/promise.ts","../bin/utils/asyncSpawn.ts","../bin/utils/git.ts","../bin/utils/inquirer.ts","../bin/utils/index.ts"],"sourcesContent":["","import { parseArgs as nativeParseArgs, type ParseArgsConfig } from 'node:util';\nimport packageJson from '../../package.json' with { type: 'json' };\n\ntype ParseArgsOptionConfig = NonNullable<ParseArgsConfig['options']>[string] & { description: string; };\ntype ParseArgsParams = Omit<ParseArgsConfig, 'options'> & { binName: string; options: Record<string, ParseArgsOptionConfig>; commands?: Record<string, string>; };\n\nconst GLOBAL_OPTIONS = {\n help: {\n type: 'boolean',\n short: 'h',\n default: false,\n description: 'Show help (prints this message)',\n },\n version: {\n type: 'boolean',\n short: 'v',\n default: false,\n description: 'Show version number',\n },\n quiet: {\n type: 'boolean',\n short: 'q',\n default: false,\n description: 'Skip interactive prompts (e.g. version update check)',\n },\n} satisfies ParseArgsParams['options'];\n\ntype Expanded<T extends ParseArgsParams> = T & { options: T['options'] & typeof GLOBAL_OPTIONS; };\ntype Parsed<T extends ParseArgsParams> = ReturnType<typeof nativeParseArgs<Expanded<T>>> & { help: string; };\n\nexport default function parseArgs<T extends ParseArgsParams = ParseArgsParams>(params: T): Parsed<T> {\n params.options = { ...GLOBAL_OPTIONS, ...params.options };\n const data = nativeParseArgs(params as Expanded<T>);\n const { values } = data;\n if ((values as { version: boolean; }).version) {\n console.log(packageJson.version);\n process.exit(0);\n }\n\n const commands = !params.commands ? '' : `\n\nCommands:\n ${Object.entries(params.commands).map(([command, example]) => `${command.padEnd(30, ' ')} ${example}`).join('\\n ')}\n`;\n\n const longestDescriptionLength = Math.max.apply(null, Object.values(params.options).map(({ description }) => description.length));\n\n const help = `\n${params.binName} ${commands ? '[command] ' : ''}<options>${commands}\nOptions:\n ${Object.entries(params.options).map(([option, { description, type, short }]) => {\n const key = short ? `--${option}, -${short}` : `--${option}`;\n return `${key.padEnd(30, ' ')} ${description.padEnd(longestDescriptionLength + 10, ' ')} [${type}]`;\n }).join('\\n ')}\n`;\n\n if ((values as { help: boolean; }).help) {\n console.log(help);\n process.exit(0);\n }\n\n return { ...data, help };\n}\n","declare global {\n interface PromiseWithResolvers<T> {\n promise: Promise<T>;\n resolve: (value: T | PromiseLike<T>) => void;\n reject: (reason?: any) => void; // eslint-disable-line @typescript-eslint/no-explicit-any\n }\n interface PromiseConstructor {\n /**\n * Creates a new Promise and returns it in an object, along with its resolve and reject functions.\n * @returns An object with the properties `promise`, `resolve`, and `reject`.\n *\n * ```ts\n * const { promise, resolve, reject } = Promise.withResolvers<T>();\n * ```\n */\n withResolvers<T>(): PromiseWithResolvers<T>;\n }\n}\n\nexport const createDeferredPromise = <T>() => {\n if (Promise.withResolvers) {\n return Promise.withResolvers<T>();\n }\n let reject!: PromiseWithResolvers<T>['reject'];\n let resolve!: PromiseWithResolvers<T>['resolve'];\n const promise = new Promise<T>((res, rej) => {\n reject = rej;\n resolve = res;\n });\n return { promise, reject, resolve };\n};\n","import { spawn } from 'node:child_process';\nimport { createDeferredPromise } from './promise.js';\n\ninterface SpawnResult {\n pid?: number;\n stdout: string;\n stderr: string;\n status: number | null;\n signal: string | null;\n}\n\nexport default async (\n command: string,\n args?: boolean | readonly string[],\n {\n print = true,\n env = {},\n signal,\n shell,\n cwd,\n }: { print?: boolean; env?: NodeJS.ProcessEnv; signal?: AbortSignal; shell?: string | boolean; cwd?: string; } = {},\n) => {\n if (typeof args === 'boolean') {\n print = args;\n args = undefined;\n }\n const stubError = new Error();\n const callerStack = stubError.stack ? stubError.stack.replace(/^.*/, ' ...') : null;\n const { promise, reject, resolve } = createDeferredPromise<SpawnResult>();\n const child = spawn(command, args, { env: Object.assign(env, process.env), signal, shell, cwd });\n if (print) {\n child.stdout.pipe(process.stdout);\n child.stderr.pipe(process.stderr);\n }\n let stdout = '';\n let stderr = '';\n child.stdout?.on('data', (data) => {\n stdout += data;\n });\n child.stderr?.on('data', (data) => {\n stderr += data;\n });\n const completionEventName = print ? 'exit' : 'close';\n function errorListener(error: Error) {\n child.removeListener(completionEventName, completionListener);\n Object.assign(error, {\n pid: child.pid,\n stdout,\n stderr,\n status: null,\n signal: null,\n });\n reject(error);\n }\n function completionListener(code: number | null, signal: string | null) {\n child.removeListener('error', errorListener);\n const result: SpawnResult = {\n pid: child.pid,\n stdout,\n stderr,\n status: code,\n signal,\n };\n if (code !== 0) {\n const argumentString = (typeof args !== 'boolean' && ` ${args?.join(' ')}`) || '';\n const error = signal\n ? new Error(`${command}${argumentString} exited with signal: ${signal}`)\n : new Error(`${command}${argumentString} exited with non-zero code: ${code}`);\n if (error.stack && callerStack) {\n error.stack += `\\n${callerStack}`;\n }\n Object.assign(error, result);\n reject(error);\n } else {\n resolve(result);\n }\n }\n\n child.once(completionEventName, completionListener);\n child.once('error', errorListener);\n return promise;\n};\n","import asyncSpawn from './asyncSpawn.js';\n\nexport const getCurrentBranch = async () => {\n const { stdout: currentBranch } = await asyncSpawn('git', ['branch', '--show-current'], { print: false });\n return currentBranch.trim();\n};\n\nexport const getGitPath = async () => {\n const { stdout: gitPath } = await asyncSpawn('git', ['rev-parse', '--show-toplevel'], { print: false });\n return gitPath.trim();\n};\n\nexport const getChangesOfFile = async (filePath: string) => {\n const { stdout: changes } = await asyncSpawn('git', ['diff', 'origin/master..', filePath], { print: false });\n return changes;\n};\n\nexport const isPathIgnored = async (path: string) => {\n try {\n await asyncSpawn('git', ['check-ignore', path], { print: false });\n return true;\n } catch {\n return false;\n }\n};\n","import { confirm, input, select } from '@inquirer/prompts';\nimport type { Prompt } from '@inquirer/type';\nimport { getGitPath } from './git.js';\nimport { SUPPORTED_CLUSTERS, endWithError } from './index.js';\nimport { sep } from 'node:path';\nimport { readdir } from 'node:fs/promises';\n\ndeclare global {\n interface SymbolConstructor {\n /** A method that is used to release resources held by an object. Called by the semantics of the `using` statement. */\n readonly dispose: unique symbol;\n /** A method that is used to asynchronously release resources held by an object. Called by the semantics of the `await using` statement. */\n readonly asyncDispose: unique symbol;\n }\n}\n// @ts-expect-error polyfill for node < 18.18\nSymbol.dispose ??= Symbol.for('nodejs.dispose');\n// @ts-expect-error polyfill for node < 18.18\nSymbol.asyncDispose ??= Symbol.for('nodejs.asyncDispose');\nlet cancelFn: (() => void) | undefined;\nconst handler = () => cancelFn?.();\nfunction addExitListener() {\n process.once('beforeExit', handler);\n return {\n [Symbol.dispose]() {\n process.off('beforeExit', handler);\n cancelFn = undefined;\n },\n };\n}\n\nasync function inquirerWrapper<Value, Config>(fn: Prompt<Value, Config>, ...params: Parameters<Prompt<Value, Config>>) {\n try {\n using _ = addExitListener();\n const result = fn(...params);\n cancelFn = result.cancel;\n return await result;\n } catch (error) {\n if (error instanceof Error && ['CancelPromptError', 'ExitPromptError'].includes(error.constructor.name)) {\n endWithError('Cancelled! 👋');\n }\n endWithError(error as Error);\n return undefined;\n }\n}\n\nexport function safeSelect<Value = string>(...params: Parameters<typeof select<Value>>) {\n return inquirerWrapper(select, ...params);\n}\n\nexport function safeInput(...params: Parameters<typeof input>) {\n return inquirerWrapper(input, ...params);\n}\n\nconst splitWordAtCapital = (str: string) => str.charAt(0).toUpperCase() + str.slice(1).split(/(?=[A-Z])/).join(' ');\n\nfunction getEnvironment() {\n return safeSelect({\n message: 'Which environment do you want to use?',\n choices: SUPPORTED_CLUSTERS.map(cluster => ({ name: splitWordAtCapital(cluster), value: cluster })),\n default: 'expManager',\n });\n}\n\nexport async function getAutorepoAppName(currentServicePath: string) {\n const appNames = (await readdir(`${currentServicePath}${sep}apps`)).filter(name => !name.startsWith('.') && !name.endsWith('-e2e'));\n return safeSelect({\n message: 'Using from autorepo, Which app do you want to use?',\n choices: appNames.map(app => ({ name: app, value: app })),\n });\n}\n\nasync function getServiceName() {\n const gitPath = await getGitPath();\n const defaultValue = gitPath.split(sep).pop();\n if (defaultValue === 'autorepo') {\n return getAutorepoAppName(gitPath);\n }\n return safeInput({ message: 'Enter the service name:', default: defaultValue });\n}\n\nexport function getVariationId(defaultVal = 'default') {\n return safeInput({ message: 'Enter your simulator id (Press enter to pass):', default: defaultVal });\n}\n\nasync function getPort(defaultVal = '8080', isLocal = false) {\n return safeInput({\n message: `Enter the ${isLocal ? 'local ' : ''}port:`,\n default: defaultVal,\n validate(value) {\n // Regex source: https://stackoverflow.com/a/12968117\n if (!/^([1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$/.test(value)) {\n return 'Please enter a valid port number';\n }\n return true;\n },\n });\n}\n\nexport async function getLocalPort(defaultVal = '5432') {\n return getPort(defaultVal, true);\n}\n\nconst VALUE_GETTER_MAP = {\n cluster: getEnvironment,\n variationId: getVariationId,\n service: getServiceName,\n port: (defaultVal = '8080') => getPort(defaultVal),\n 'local-port': getLocalPort,\n} as const;\n\nexport async function fillMissingRequiredValues<T extends { [key in keyof typeof VALUE_GETTER_MAP]?: string }>(values: T, requiredValues: (keyof T | { option: keyof T; defaultVal: string; })[]) {\n for (const value of requiredValues) {\n const option = typeof value === 'object' ? value.option : value;\n const defaultVal = typeof value === 'object' ? value.defaultVal : undefined;\n if (typeof option !== 'string') {\n throw new Error(`Invalid option ${String(option)}`);\n }\n const getter = VALUE_GETTER_MAP[option as keyof typeof VALUE_GETTER_MAP];\n if (!getter) {\n throw new Error(`No value getter for ${String(option)}`);\n }\n\n values[option] ??= await getter(defaultVal) as T[keyof T & string];\n }\n return values;\n}\n\nexport async function promptForConfirmation(message: string, defaultVal = true) {\n return inquirerWrapper(confirm, { message, default: defaultVal });\n}\n","#!/usr/bin/env node\nimport fs from 'node:fs';\nimport asyncSpawn from './asyncSpawn.js';\nimport { promptForConfirmation } from './inquirer.js';\n\nconst IP_LINE_SUFFIX = 'SERVICE_HOST';\nconst PROD_CLUSTER_TO_CMD_MAP = {\n prodUs: ['us-autofleet-production', 'us-central1', 'autofleet-production'],\n prodEu: ['eu-prod-autofleet', 'europe-west1', 'autofleetprod'],\n prodJp: ['jp-autofleet', 'asia-northeast1', 'autofleet-japan'],\n};\nconst SIMULATION_CLUSTER_TO_CMD_MAP = {\n dev1: ['dev-cluster-2', 'europe-west1', 'dev1-experiment-manager'],\n e2eManager: ['e2e-cluster-2', 'europe-west1', 'e2e-project-1'],\n expManager: ['af-experiment-manager', 'europe-west1'],\n};\nconst STAGING_CLUSTER_TO_CMD_MAP = {\n staging: ['stg-autofleet', 'europe-west1', 'autofleet-staging'],\n loadTest: ['lt-autofleet-production', 'asia-northeast1', 'load-testing-428806'],\n};\nconst MAPPING_CLUSTER_TO_CMD_MAP = {\n osrmProd: ['maps-prod', 'europe-west1', 'af-mapping'],\n};\nconst CLUSTER_TO_CMD_MAP = {\n ...PROD_CLUSTER_TO_CMD_MAP,\n ...SIMULATION_CLUSTER_TO_CMD_MAP,\n ...STAGING_CLUSTER_TO_CMD_MAP,\n ...MAPPING_CLUSTER_TO_CMD_MAP,\n};\n\nconst CLUSTER_TO_REDIS_REGION = {\n staging: 'europe-west1',\n};\n\nexport const SUPPORTED_CLUSTERS = Object.keys(CLUSTER_TO_CMD_MAP) as (keyof typeof CLUSTER_TO_CMD_MAP)[];\n\nconst getClusterDetails = async (clusterName: string) => {\n const command = CLUSTER_TO_CMD_MAP[clusterName as keyof typeof CLUSTER_TO_CMD_MAP];\n if (!command) {\n throw new Error(`Cluster name ${clusterName} does not exist!`);\n }\n const [name, region, project] = command;\n\n if (\n PROD_CLUSTER_TO_CMD_MAP[clusterName as keyof typeof PROD_CLUSTER_TO_CMD_MAP]\n && !(await promptForConfirmation(`❌❌ Are you sure you want to run this command on ${clusterName}? ❌❌`, false))) {\n console.log('Aborting...');\n return process.exit(1);\n }\n\n return { name, region, project };\n};\n\nexport const replaceInFile = ({ newFilePath, filePath, linesToReplace }: { newFilePath: string; filePath: string; linesToReplace: { find: string; replace: string; }[]; }) => {\n let fileAsString = fs.readFileSync(filePath, 'utf8');\n for (const { find, replace } of linesToReplace) {\n fileAsString = fileAsString.replace(find, replace);\n }\n fs.writeFileSync(newFilePath, fileAsString);\n};\n\nexport async function getCurrentCluster() {\n try {\n const { stdout } = await asyncSpawn('kubectl', ['config', 'current-context'], { print: false });\n return stdout.trim();\n } catch {\n return null;\n }\n}\n\nexport const connectToCluster = async (clusterName: string) => {\n const { name, region, project } = await getClusterDetails(clusterName);\n\n const expectedContext = `gke_${project || name}_${region}_${name}`;\n const currentContext = await getCurrentCluster();\n if (currentContext === expectedContext) {\n console.log(`Already connected to ${clusterName}, skipping connection to cluster...`);\n return { name, region, project };\n }\n\n await asyncSpawn('gcloud', ['container', 'clusters', 'get-credentials', name, '--region', region, '--project', project || name], { print: false });\n\n console.log(`Switched to ${clusterName} successfully`);\n\n return { name, region, project };\n};\n\nexport async function getCurrentNamespace() {\n try {\n const { stdout } = await asyncSpawn('kubectl', ['config', 'view', '--minify', '--output', 'jsonpath={..namespace}'], { print: false });\n return stdout.trim();\n } catch {\n return 'default'; // If no namespace is set, it defaults to 'default'\n }\n}\n\nexport const connectAndGetPrefix = async ({ clusterName, variationId }: { clusterName: string; variationId: string; }) => {\n await connectToCluster(clusterName);\n return `--namespace=${variationId}`;\n};\n\nexport const parseIps = (ips: string) => {\n const ipLines = ips.split('\\n').filter(Boolean);\n ipLines.shift();\n\n let formattedIps = ipLines.map((ipLine) => {\n const [name, _type, _clusterIp, externalIp, _port, _age] = ipLine.split(/(\\s+)/).map(s => s.trim()).filter(Boolean);\n const serviceName = name.replace(/-/g, '_').toUpperCase();\n const formattedLine = `${serviceName}_${IP_LINE_SUFFIX}=${externalIp}`;\n return formattedLine;\n });\n formattedIps = formattedIps.filter(formattedIp => !formattedIp.includes('none') && !formattedIp.includes('undefined'));\n return formattedIps;\n};\n\nexport function endWithError(error: string | Error, helpText?: string): never {\n if (!(error instanceof Error)) {\n error = new Error(error);\n }\n console.error(error);\n if (helpText) {\n console.log(helpText);\n }\n return process.exit(1);\n}\n\nexport const isSimulationCluster = (clusterName: string) => Object.keys(SIMULATION_CLUSTER_TO_CMD_MAP).includes(clusterName);\n\nexport const getRedisRegion = (clusterName: string) => CLUSTER_TO_REDIS_REGION[clusterName as keyof typeof CLUSTER_TO_REDIS_REGION]\n || CLUSTER_TO_CMD_MAP[clusterName as keyof typeof CLUSTER_TO_CMD_MAP][1];\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utils-BE0PAuyu.js","names":["parseArgs","nativeParseArgs","packageJson.version","reject!: PromiseWithResolvers<T>['reject']","resolve!: PromiseWithResolvers<T>['resolve']","result: SpawnResult","signal","asyncSpawn","path","cancelFn: (() => void) | undefined","asyncSpawn"],"sources":["../package.json","../bin/utils/parser.ts","../bin/utils/promise.ts","../bin/utils/asyncSpawn.ts","../bin/utils/git.ts","../bin/utils/inquirer.ts","../bin/utils/index.ts"],"sourcesContent":["","import { parseArgs as nativeParseArgs, type ParseArgsConfig } from 'node:util';\nimport packageJson from '../../package.json' with { type: 'json' };\n\ntype ParseArgsOptionConfig = NonNullable<ParseArgsConfig['options']>[string] & { description: string; };\ntype ParseArgsParams = Omit<ParseArgsConfig, 'options'> & { binName: string; options: Record<string, ParseArgsOptionConfig>; commands?: Record<string, string>; };\n\nconst GLOBAL_OPTIONS = {\n help: {\n type: 'boolean',\n short: 'h',\n default: false,\n description: 'Show help (prints this message)',\n },\n version: {\n type: 'boolean',\n short: 'v',\n default: false,\n description: 'Show version number',\n },\n quiet: {\n type: 'boolean',\n short: 'q',\n default: false,\n description: 'Skip interactive prompts (e.g. version update check)',\n },\n} satisfies ParseArgsParams['options'];\n\ntype Expanded<T extends ParseArgsParams> = T & { options: T['options'] & typeof GLOBAL_OPTIONS; };\ntype Parsed<T extends ParseArgsParams> = ReturnType<typeof nativeParseArgs<Expanded<T>>> & { help: string; };\n\nexport default function parseArgs<T extends ParseArgsParams = ParseArgsParams>(params: T): Parsed<T> {\n params.options = { ...GLOBAL_OPTIONS, ...params.options };\n const data = nativeParseArgs(params as Expanded<T>);\n const { values } = data;\n if ((values as { version: boolean; }).version) {\n console.log(packageJson.version);\n process.exit(0);\n }\n\n const commands = !params.commands ? '' : `\n\nCommands:\n ${Object.entries(params.commands).map(([command, example]) => `${command.padEnd(30, ' ')} ${example}`).join('\\n ')}\n`;\n\n const longestDescriptionLength = Math.max.apply(null, Object.values(params.options).map(({ description }) => description.length));\n\n const help = `\n${params.binName} ${commands ? '[command] ' : ''}<options>${commands}\nOptions:\n ${Object.entries(params.options).map(([option, { description, type, short }]) => {\n const key = short ? `--${option}, -${short}` : `--${option}`;\n return `${key.padEnd(30, ' ')} ${description.padEnd(longestDescriptionLength + 10, ' ')} [${type}]`;\n }).join('\\n ')}\n`;\n\n if ((values as { help: boolean; }).help) {\n console.log(help);\n process.exit(0);\n }\n\n return { ...data, help };\n}\n","declare global {\n interface PromiseWithResolvers<T> {\n promise: Promise<T>;\n resolve: (value: T | PromiseLike<T>) => void;\n reject: (reason?: any) => void; // eslint-disable-line @typescript-eslint/no-explicit-any\n }\n interface PromiseConstructor {\n /**\n * Creates a new Promise and returns it in an object, along with its resolve and reject functions.\n * @returns An object with the properties `promise`, `resolve`, and `reject`.\n *\n * ```ts\n * const { promise, resolve, reject } = Promise.withResolvers<T>();\n * ```\n */\n withResolvers<T>(): PromiseWithResolvers<T>;\n }\n}\n\nexport const createDeferredPromise = <T>() => {\n if (Promise.withResolvers) {\n return Promise.withResolvers<T>();\n }\n let reject!: PromiseWithResolvers<T>['reject'];\n let resolve!: PromiseWithResolvers<T>['resolve'];\n const promise = new Promise<T>((res, rej) => {\n reject = rej;\n resolve = res;\n });\n return { promise, reject, resolve };\n};\n","import { spawn } from 'node:child_process';\nimport { createDeferredPromise } from './promise.js';\n\ninterface SpawnResult {\n pid?: number;\n stdout: string;\n stderr: string;\n status: number | null;\n signal: string | null;\n}\n\nexport default async (\n command: string,\n args?: boolean | readonly string[],\n {\n print = true,\n env = {},\n signal,\n shell,\n cwd,\n }: { print?: boolean; env?: NodeJS.ProcessEnv; signal?: AbortSignal; shell?: string | boolean; cwd?: string; } = {},\n) => {\n if (typeof args === 'boolean') {\n print = args;\n args = undefined;\n }\n const stubError = new Error();\n const callerStack = stubError.stack ? stubError.stack.replace(/^.*/, ' ...') : null;\n const { promise, reject, resolve } = createDeferredPromise<SpawnResult>();\n const child = spawn(command, args, { env: Object.assign(env, process.env), signal, shell, cwd });\n if (print) {\n child.stdout.pipe(process.stdout);\n child.stderr.pipe(process.stderr);\n }\n let stdout = '';\n let stderr = '';\n child.stdout?.on('data', (data) => {\n stdout += data;\n });\n child.stderr?.on('data', (data) => {\n stderr += data;\n });\n const completionEventName = print ? 'exit' : 'close';\n function errorListener(error: Error) {\n child.removeListener(completionEventName, completionListener);\n Object.assign(error, {\n pid: child.pid,\n stdout,\n stderr,\n status: null,\n signal: null,\n });\n reject(error);\n }\n function completionListener(code: number | null, signal: string | null) {\n child.removeListener('error', errorListener);\n const result: SpawnResult = {\n pid: child.pid,\n stdout,\n stderr,\n status: code,\n signal,\n };\n if (code !== 0) {\n const argumentString = (typeof args !== 'boolean' && ` ${args?.join(' ')}`) || '';\n const error = signal\n ? new Error(`${command}${argumentString} exited with signal: ${signal}`)\n : new Error(`${command}${argumentString} exited with non-zero code: ${code}`);\n if (error.stack && callerStack) {\n error.stack += `\\n${callerStack}`;\n }\n Object.assign(error, result);\n reject(error);\n } else {\n resolve(result);\n }\n }\n\n child.once(completionEventName, completionListener);\n child.once('error', errorListener);\n return promise;\n};\n","import asyncSpawn from './asyncSpawn.js';\n\nexport const getCurrentBranch = async () => {\n const { stdout: currentBranch } = await asyncSpawn('git', ['branch', '--show-current'], { print: false });\n return currentBranch.trim();\n};\n\nexport const getGitPath = async () => {\n const { stdout: gitPath } = await asyncSpawn('git', ['rev-parse', '--show-toplevel'], { print: false });\n return gitPath.trim();\n};\n\nexport const getChangesOfFile = async (filePath: string) => {\n const { stdout: changes } = await asyncSpawn('git', ['diff', 'origin/master..', filePath], { print: false });\n return changes;\n};\n\nexport const isPathIgnored = async (path: string) => {\n try {\n await asyncSpawn('git', ['check-ignore', path], { print: false });\n return true;\n } catch {\n return false;\n }\n};\n","import { confirm, input, select } from '@inquirer/prompts';\nimport type { Prompt } from '@inquirer/type';\nimport { getGitPath } from './git.js';\nimport { SUPPORTED_CLUSTERS, endWithError } from './index.js';\nimport { sep } from 'node:path';\nimport { readdir } from 'node:fs/promises';\n\ndeclare global {\n interface SymbolConstructor {\n /** A method that is used to release resources held by an object. Called by the semantics of the `using` statement. */\n readonly dispose: unique symbol;\n /** A method that is used to asynchronously release resources held by an object. Called by the semantics of the `await using` statement. */\n readonly asyncDispose: unique symbol;\n }\n}\n// @ts-expect-error polyfill for node < 18.18\nSymbol.dispose ??= Symbol.for('nodejs.dispose');\n// @ts-expect-error polyfill for node < 18.18\nSymbol.asyncDispose ??= Symbol.for('nodejs.asyncDispose');\nlet cancelFn: (() => void) | undefined;\nconst handler = () => cancelFn?.();\nfunction addExitListener() {\n process.once('beforeExit', handler);\n return {\n [Symbol.dispose]() {\n process.off('beforeExit', handler);\n cancelFn = undefined;\n },\n };\n}\n\nasync function inquirerWrapper<Value, Config>(fn: Prompt<Value, Config>, ...params: Parameters<Prompt<Value, Config>>) {\n try {\n using _ = addExitListener();\n const result = fn(...params);\n cancelFn = result.cancel;\n return await result;\n } catch (error) {\n if (error instanceof Error && ['CancelPromptError', 'ExitPromptError'].includes(error.constructor.name)) {\n endWithError('Cancelled! 👋');\n }\n endWithError(error as Error);\n return undefined;\n }\n}\n\nexport function safeSelect<Value = string>(...params: Parameters<typeof select<Value>>) {\n return inquirerWrapper(select, ...params);\n}\n\nexport function safeInput(...params: Parameters<typeof input>) {\n return inquirerWrapper(input, ...params);\n}\n\nconst splitWordAtCapital = (str: string) => str.charAt(0).toUpperCase() + str.slice(1).split(/(?=[A-Z])/).join(' ');\n\nfunction getEnvironment() {\n return safeSelect({\n message: 'Which environment do you want to use?',\n choices: SUPPORTED_CLUSTERS.map(cluster => ({ name: splitWordAtCapital(cluster), value: cluster })),\n default: 'expManager',\n });\n}\n\nexport async function getAutorepoAppName(currentServicePath: string) {\n const appNames = (await readdir(`${currentServicePath}${sep}apps`)).filter(name => !name.startsWith('.') && !name.endsWith('-e2e'));\n return safeSelect({\n message: 'Using from autorepo, Which app do you want to use?',\n choices: appNames.map(app => ({ name: app, value: app })),\n });\n}\n\nasync function getServiceName() {\n const gitPath = await getGitPath();\n const defaultValue = gitPath.split(sep).pop();\n if (defaultValue === 'autorepo') {\n return getAutorepoAppName(gitPath);\n }\n return safeInput({ message: 'Enter the service name:', default: defaultValue });\n}\n\nexport function getVariationId(defaultVal = 'default') {\n return safeInput({ message: 'Enter your simulator id (Press enter to pass):', default: defaultVal });\n}\n\nasync function getPort(defaultVal = '8080', isLocal = false) {\n return safeInput({\n message: `Enter the ${isLocal ? 'local ' : ''}port:`,\n default: defaultVal,\n validate(value) {\n // Regex source: https://stackoverflow.com/a/12968117\n if (!/^([1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$/.test(value)) {\n return 'Please enter a valid port number';\n }\n return true;\n },\n });\n}\n\nexport async function getLocalPort(defaultVal = '5432') {\n return getPort(defaultVal, true);\n}\n\nconst VALUE_GETTER_MAP = {\n cluster: getEnvironment,\n variationId: getVariationId,\n service: getServiceName,\n port: (defaultVal = '8080') => getPort(defaultVal),\n 'local-port': getLocalPort,\n} as const;\n\nexport async function fillMissingRequiredValues<T extends { [key in keyof typeof VALUE_GETTER_MAP]?: string }>(values: T, requiredValues: (keyof T | { option: keyof T; defaultVal: string; })[]) {\n for (const value of requiredValues) {\n const option = typeof value === 'object' ? value.option : value;\n const defaultVal = typeof value === 'object' ? value.defaultVal : undefined;\n if (typeof option !== 'string') {\n throw new Error(`Invalid option ${String(option)}`);\n }\n const getter = VALUE_GETTER_MAP[option as keyof typeof VALUE_GETTER_MAP];\n if (!getter) {\n throw new Error(`No value getter for ${String(option)}`);\n }\n\n values[option] ??= await getter(defaultVal) as T[keyof T & string];\n }\n return values;\n}\n\nexport async function promptForConfirmation(message: string, defaultVal = true) {\n return inquirerWrapper(confirm, { message, default: defaultVal });\n}\n","#!/usr/bin/env node\nimport fs from 'node:fs';\nimport asyncSpawn from './asyncSpawn.js';\nimport { promptForConfirmation } from './inquirer.js';\n\nconst IP_LINE_SUFFIX = 'SERVICE_HOST';\nconst PROD_CLUSTER_TO_CMD_MAP = {\n prodUs: ['us-autofleet-production', 'us-central1', 'autofleet-production'],\n prodEu: ['eu-prod-autofleet', 'europe-west1', 'autofleetprod'],\n prodJp: ['jp-autofleet', 'asia-northeast1', 'autofleet-japan'],\n};\nconst SIMULATION_CLUSTER_TO_CMD_MAP = {\n dev1: ['dev-cluster-2', 'europe-west1', 'dev1-experiment-manager'],\n e2eManager: ['e2e-cluster-2', 'europe-west1', 'e2e-project-1'],\n expManager: ['af-experiment-manager', 'europe-west1'],\n};\nconst STAGING_CLUSTER_TO_CMD_MAP = {\n staging: ['stg-autofleet', 'europe-west1', 'autofleet-staging'],\n loadTest: ['lt-autofleet-production', 'asia-northeast1', 'load-testing-428806'],\n};\nconst MAPPING_CLUSTER_TO_CMD_MAP = {\n osrmProd: ['maps-prod', 'europe-west1', 'af-mapping'],\n};\nconst CLUSTER_TO_CMD_MAP = {\n ...PROD_CLUSTER_TO_CMD_MAP,\n ...SIMULATION_CLUSTER_TO_CMD_MAP,\n ...STAGING_CLUSTER_TO_CMD_MAP,\n ...MAPPING_CLUSTER_TO_CMD_MAP,\n};\n\nconst CLUSTER_TO_REDIS_REGION = {\n staging: 'europe-west1',\n};\n\nexport const SUPPORTED_CLUSTERS = Object.keys(CLUSTER_TO_CMD_MAP) as (keyof typeof CLUSTER_TO_CMD_MAP)[];\n\nconst getClusterDetails = async (clusterName: string) => {\n const command = CLUSTER_TO_CMD_MAP[clusterName as keyof typeof CLUSTER_TO_CMD_MAP];\n if (!command) {\n throw new Error(`Cluster name ${clusterName} does not exist!`);\n }\n const [name, region, project] = command;\n\n if (\n PROD_CLUSTER_TO_CMD_MAP[clusterName as keyof typeof PROD_CLUSTER_TO_CMD_MAP]\n && !(await promptForConfirmation(`❌❌ Are you sure you want to run this command on ${clusterName}? ❌❌`, false))) {\n console.log('Aborting...');\n return process.exit(1);\n }\n\n return { name, region, project };\n};\n\nexport const replaceInFile = ({ newFilePath, filePath, linesToReplace }: { newFilePath: string; filePath: string; linesToReplace: { find: string; replace: string; }[]; }) => {\n let fileAsString = fs.readFileSync(filePath, 'utf8');\n for (const { find, replace } of linesToReplace) {\n fileAsString = fileAsString.replace(find, replace);\n }\n fs.writeFileSync(newFilePath, fileAsString);\n};\n\nexport async function getCurrentCluster() {\n try {\n const { stdout } = await asyncSpawn('kubectl', ['config', 'current-context'], { print: false });\n return stdout.trim();\n } catch {\n return null;\n }\n}\n\nexport const connectToCluster = async (clusterName: string) => {\n const { name, region, project } = await getClusterDetails(clusterName);\n\n const expectedContext = `gke_${project || name}_${region}_${name}`;\n const currentContext = await getCurrentCluster();\n if (currentContext === expectedContext) {\n console.log(`Already connected to ${clusterName}, skipping connection to cluster...`);\n return { name, region, project };\n }\n\n await asyncSpawn('gcloud', ['container', 'clusters', 'get-credentials', name, '--region', region, '--project', project || name], { print: false });\n\n console.log(`Switched to ${clusterName} successfully`);\n\n return { name, region, project };\n};\n\nexport async function getCurrentNamespace() {\n try {\n const { stdout } = await asyncSpawn('kubectl', ['config', 'view', '--minify', '--output', 'jsonpath={..namespace}'], { print: false });\n return stdout.trim();\n } catch {\n return 'default'; // If no namespace is set, it defaults to 'default'\n }\n}\n\nexport const connectAndGetPrefix = async ({ clusterName, variationId }: { clusterName: string; variationId: string; }) => {\n await connectToCluster(clusterName);\n return `--namespace=${variationId}`;\n};\n\nexport const parseIps = (ips: string) => {\n const ipLines = ips.split('\\n').filter(Boolean);\n ipLines.shift();\n\n let formattedIps = ipLines.map((ipLine) => {\n const [name, _type, _clusterIp, externalIp, _port, _age] = ipLine.split(/(\\s+)/).map(s => s.trim()).filter(Boolean);\n const serviceName = name.replace(/-/g, '_').toUpperCase();\n const formattedLine = `${serviceName}_${IP_LINE_SUFFIX}=${externalIp}`;\n return formattedLine;\n });\n formattedIps = formattedIps.filter(formattedIp => !formattedIp.includes('none') && !formattedIp.includes('undefined'));\n return formattedIps;\n};\n\nexport function endWithError(error: string | Error, helpText?: string): never {\n if (!(error instanceof Error)) {\n error = new Error(error);\n }\n console.error(error);\n if (helpText) {\n console.log(helpText);\n }\n return process.exit(1);\n}\n\nexport const isSimulationCluster = (clusterName: string) => Object.keys(SIMULATION_CLUSTER_TO_CMD_MAP).includes(clusterName);\n\nexport const getRedisRegion = (clusterName: string) => CLUSTER_TO_REDIS_REGION[clusterName as keyof typeof CLUSTER_TO_REDIS_REGION]\n || CLUSTER_TO_CMD_MAP[clusterName as keyof typeof CLUSTER_TO_CMD_MAP][1];\n"],"mappings":"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"}
|