alchemy 0.16.5 → 0.16.6
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/lib/sentry/api.d.ts +50 -0
- package/lib/sentry/api.d.ts.map +1 -0
- package/lib/sentry/api.js +76 -0
- package/lib/sentry/api.js.map +1 -0
- package/lib/sentry/client-key.d.ts +156 -0
- package/lib/sentry/client-key.d.ts.map +1 -0
- package/lib/sentry/client-key.js +126 -0
- package/lib/sentry/client-key.js.map +1 -0
- package/lib/sentry/index.d.ts +5 -0
- package/lib/sentry/index.d.ts.map +1 -0
- package/lib/sentry/index.js +5 -0
- package/lib/sentry/index.js.map +1 -0
- package/lib/sentry/project.d.ts +235 -0
- package/lib/sentry/project.d.ts.map +1 -0
- package/lib/sentry/project.js +146 -0
- package/lib/sentry/project.js.map +1 -0
- package/lib/sentry/team.d.ts +109 -0
- package/lib/sentry/team.d.ts.map +1 -0
- package/lib/sentry/team.js +109 -0
- package/lib/sentry/team.js.map +1 -0
- package/package.json +2 -1
- package/src/sentry/api.ts +106 -0
- package/src/sentry/client-key.ts +295 -0
- package/src/sentry/index.ts +4 -0
- package/src/sentry/project.ts +420 -0
- package/src/sentry/team.ts +235 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import type { Context } from "../context.js";
|
|
2
|
+
import { Resource } from "../resource.js";
|
|
3
|
+
import type { Secret } from "../secret.js";
|
|
4
|
+
import { SentryApi } from "./api.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Properties for creating or updating a Team
|
|
8
|
+
*/
|
|
9
|
+
export interface TeamProps {
|
|
10
|
+
/**
|
|
11
|
+
* The name for the team
|
|
12
|
+
*/
|
|
13
|
+
name: string;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Uniquely identifies a team and is used for the interface
|
|
17
|
+
*/
|
|
18
|
+
slug?: string;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The organization ID or slug that owns the team
|
|
22
|
+
*/
|
|
23
|
+
organization: string;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Auth token to use (overrides environment variable)
|
|
27
|
+
*/
|
|
28
|
+
authToken?: Secret;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Whether to adopt an existing team with the same slug if it exists
|
|
32
|
+
* If true and a team with the same slug exists, it will be adopted rather than creating a new one
|
|
33
|
+
*
|
|
34
|
+
* @default false
|
|
35
|
+
*/
|
|
36
|
+
adopt?: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Output returned after Team creation/update
|
|
41
|
+
*/
|
|
42
|
+
export interface Team extends Resource<"sentry::Team">, TeamProps {
|
|
43
|
+
/**
|
|
44
|
+
* The ID of the team
|
|
45
|
+
*/
|
|
46
|
+
id: string;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Time at which the team was created
|
|
50
|
+
*/
|
|
51
|
+
dateCreated: string;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Whether the current user is a member of the team
|
|
55
|
+
*/
|
|
56
|
+
isMember: boolean;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The role of the current user in the team
|
|
60
|
+
*/
|
|
61
|
+
teamRole: string;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Team flags
|
|
65
|
+
*/
|
|
66
|
+
flags: {
|
|
67
|
+
"idp:provisioned": boolean;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Access permissions for the team
|
|
72
|
+
*/
|
|
73
|
+
access: string[];
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Whether the current user has access to the team
|
|
77
|
+
*/
|
|
78
|
+
hasAccess: boolean;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Whether the team membership is pending
|
|
82
|
+
*/
|
|
83
|
+
isPending: boolean;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Number of members in the team
|
|
87
|
+
*/
|
|
88
|
+
memberCount: number;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Team avatar information
|
|
92
|
+
*/
|
|
93
|
+
avatar: {
|
|
94
|
+
avatarType: string;
|
|
95
|
+
avatarUuid: string | null;
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Create and manage Sentry teams
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* // Create a basic Sentry team:
|
|
104
|
+
* const team = await Team("my-team", {
|
|
105
|
+
* name: "My Team",
|
|
106
|
+
* organization: "my-org"
|
|
107
|
+
* });
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* // Create a team with a custom slug:
|
|
111
|
+
* const team = await Team("custom-team", {
|
|
112
|
+
* name: "Custom Team",
|
|
113
|
+
* organization: "my-org",
|
|
114
|
+
* slug: "custom-team-slug"
|
|
115
|
+
* });
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* // Create or adopt an existing team with the same slug:
|
|
119
|
+
* const team = await Team("existing-team", {
|
|
120
|
+
* name: "Existing Team",
|
|
121
|
+
* organization: "my-org",
|
|
122
|
+
* adopt: true
|
|
123
|
+
* });
|
|
124
|
+
*/
|
|
125
|
+
export const Team = Resource(
|
|
126
|
+
"sentry::Team",
|
|
127
|
+
async function (
|
|
128
|
+
this: Context<Team>,
|
|
129
|
+
id: string,
|
|
130
|
+
props: TeamProps,
|
|
131
|
+
): Promise<Team> {
|
|
132
|
+
const api = new SentryApi({ authToken: props.authToken });
|
|
133
|
+
|
|
134
|
+
if (this.phase === "delete") {
|
|
135
|
+
try {
|
|
136
|
+
if (this.output?.id) {
|
|
137
|
+
const response = await api.delete(
|
|
138
|
+
`/teams/${props.organization}/${this.output.slug || this.output.id}/`,
|
|
139
|
+
);
|
|
140
|
+
if (!response.ok && response.status !== 404) {
|
|
141
|
+
console.error("Error deleting team:", response.statusText);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
} catch (error) {
|
|
145
|
+
console.error("Error deleting team:", error);
|
|
146
|
+
}
|
|
147
|
+
return this.destroy();
|
|
148
|
+
} else {
|
|
149
|
+
try {
|
|
150
|
+
let response;
|
|
151
|
+
|
|
152
|
+
if (this.phase === "update" && this.output?.id) {
|
|
153
|
+
response = await api.put(
|
|
154
|
+
`/teams/${props.organization}/${this.output.slug || this.output.id}/`,
|
|
155
|
+
props,
|
|
156
|
+
);
|
|
157
|
+
} else {
|
|
158
|
+
try {
|
|
159
|
+
response = await api.post(
|
|
160
|
+
`/organizations/${props.organization}/teams/`,
|
|
161
|
+
props,
|
|
162
|
+
);
|
|
163
|
+
} catch (error) {
|
|
164
|
+
// Check if this is a "team already exists" error and adopt is enabled
|
|
165
|
+
if (
|
|
166
|
+
props.adopt &&
|
|
167
|
+
error instanceof Error &&
|
|
168
|
+
error.message.includes("already exists")
|
|
169
|
+
) {
|
|
170
|
+
console.log(
|
|
171
|
+
`Team '${props.slug || props.name}' already exists, adopting it`,
|
|
172
|
+
);
|
|
173
|
+
// Find the existing team by slug
|
|
174
|
+
const existingTeam = await findTeamBySlug(
|
|
175
|
+
api,
|
|
176
|
+
props.organization,
|
|
177
|
+
props.slug || props.name,
|
|
178
|
+
);
|
|
179
|
+
if (!existingTeam) {
|
|
180
|
+
throw new Error(
|
|
181
|
+
`Failed to find existing team '${props.slug || props.name}' for adoption`,
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
response = await api.get(
|
|
185
|
+
`/organizations/${props.organization}/teams/${existingTeam.slug}/`,
|
|
186
|
+
);
|
|
187
|
+
} else {
|
|
188
|
+
throw error;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (!response.ok) {
|
|
194
|
+
throw new Error(`API error: ${response.statusText}`);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const data = (await response.json()) as Omit<Team, keyof TeamProps>;
|
|
198
|
+
return this({
|
|
199
|
+
...props,
|
|
200
|
+
id: data.id,
|
|
201
|
+
dateCreated: data.dateCreated,
|
|
202
|
+
isMember: data.isMember,
|
|
203
|
+
teamRole: data.teamRole,
|
|
204
|
+
flags: data.flags,
|
|
205
|
+
access: data.access,
|
|
206
|
+
hasAccess: data.hasAccess,
|
|
207
|
+
isPending: data.isPending,
|
|
208
|
+
memberCount: data.memberCount,
|
|
209
|
+
avatar: data.avatar,
|
|
210
|
+
});
|
|
211
|
+
} catch (error) {
|
|
212
|
+
console.error("Error creating/updating team:", error);
|
|
213
|
+
throw error;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Find a team by slug
|
|
221
|
+
*/
|
|
222
|
+
async function findTeamBySlug(
|
|
223
|
+
api: SentryApi,
|
|
224
|
+
organization: string,
|
|
225
|
+
slug: string,
|
|
226
|
+
): Promise<{ id: string; slug: string } | null> {
|
|
227
|
+
const response = await api.get(`/teams/${organization}/${slug}/`);
|
|
228
|
+
if (!response.ok) {
|
|
229
|
+
throw new Error(`API error: ${response.statusText}`);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const teams = (await response.json()) as Array<{ id: string; slug: string }>;
|
|
233
|
+
const team = teams.find((t) => t.slug === slug);
|
|
234
|
+
return team ? { id: team.id, slug: team.slug } : null;
|
|
235
|
+
}
|