@vercel/sandbox 2.0.0-beta.2 → 2.0.0-beta.20

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.
Files changed (208) hide show
  1. package/README.md +48 -1
  2. package/dist/_virtual/rolldown_runtime.cjs +29 -0
  3. package/dist/api-client/api-client.cjs +445 -0
  4. package/dist/api-client/api-client.cjs.map +1 -0
  5. package/dist/api-client/api-client.d.cts +6235 -0
  6. package/dist/api-client/api-client.d.ts +6229 -706
  7. package/dist/api-client/api-client.js +436 -472
  8. package/dist/api-client/api-client.js.map +1 -1
  9. package/dist/api-client/api-error.cjs +32 -0
  10. package/dist/api-client/api-error.cjs.map +1 -0
  11. package/dist/api-client/api-error.d.cts +29 -0
  12. package/dist/api-client/api-error.d.ts +21 -16
  13. package/dist/api-client/api-error.js +28 -32
  14. package/dist/api-client/api-error.js.map +1 -1
  15. package/dist/api-client/base-client.cjs +126 -0
  16. package/dist/api-client/base-client.cjs.map +1 -0
  17. package/dist/api-client/base-client.d.cts +38 -0
  18. package/dist/api-client/base-client.d.ts +31 -36
  19. package/dist/api-client/base-client.js +114 -118
  20. package/dist/api-client/base-client.js.map +1 -1
  21. package/dist/api-client/file-writer.cjs +62 -0
  22. package/dist/api-client/file-writer.cjs.map +1 -0
  23. package/dist/api-client/file-writer.d.cts +66 -0
  24. package/dist/api-client/file-writer.d.ts +56 -42
  25. package/dist/api-client/file-writer.js +57 -61
  26. package/dist/api-client/file-writer.js.map +1 -1
  27. package/dist/api-client/index.cjs +2 -0
  28. package/dist/api-client/index.d.ts +2 -2
  29. package/dist/api-client/index.js +4 -21
  30. package/dist/api-client/validators.cjs +229 -0
  31. package/dist/api-client/validators.cjs.map +1 -0
  32. package/dist/api-client/validators.d.cts +26885 -0
  33. package/dist/api-client/validators.d.ts +26732 -3706
  34. package/dist/api-client/validators.js +198 -191
  35. package/dist/api-client/validators.js.map +1 -1
  36. package/dist/api-client/with-retry.cjs +89 -0
  37. package/dist/api-client/with-retry.cjs.map +1 -0
  38. package/dist/api-client/with-retry.d.cts +10 -0
  39. package/dist/api-client/with-retry.d.ts +9 -13
  40. package/dist/api-client/with-retry.js +81 -102
  41. package/dist/api-client/with-retry.js.map +1 -1
  42. package/dist/auth/api.cjs +29 -0
  43. package/dist/auth/api.cjs.map +1 -0
  44. package/dist/auth/api.js +26 -25
  45. package/dist/auth/api.js.map +1 -1
  46. package/dist/auth/error.cjs +13 -0
  47. package/dist/auth/error.cjs.map +1 -0
  48. package/dist/auth/error.js +11 -11
  49. package/dist/auth/error.js.map +1 -1
  50. package/dist/auth/file.cjs +64 -0
  51. package/dist/auth/file.cjs.map +1 -0
  52. package/dist/auth/file.d.cts +26 -0
  53. package/dist/auth/file.d.ts +19 -15
  54. package/dist/auth/file.js +49 -64
  55. package/dist/auth/file.js.map +1 -1
  56. package/dist/auth/index.cjs +11 -0
  57. package/dist/auth/index.d.cts +5 -0
  58. package/dist/auth/index.d.ts +5 -6
  59. package/dist/auth/index.js +6 -27
  60. package/dist/auth/linked-project.cjs +38 -0
  61. package/dist/auth/linked-project.cjs.map +1 -0
  62. package/dist/auth/linked-project.js +30 -64
  63. package/dist/auth/linked-project.js.map +1 -1
  64. package/dist/auth/oauth.cjs +205 -0
  65. package/dist/auth/oauth.cjs.map +1 -0
  66. package/dist/auth/oauth.d.cts +135 -0
  67. package/dist/auth/oauth.d.ts +113 -109
  68. package/dist/auth/oauth.js +185 -252
  69. package/dist/auth/oauth.js.map +1 -1
  70. package/dist/auth/poll-for-token.cjs +82 -0
  71. package/dist/auth/poll-for-token.cjs.map +1 -0
  72. package/dist/auth/poll-for-token.d.cts +28 -0
  73. package/dist/auth/poll-for-token.d.ts +23 -15
  74. package/dist/auth/poll-for-token.js +79 -64
  75. package/dist/auth/poll-for-token.js.map +1 -1
  76. package/dist/auth/project.cjs +178 -0
  77. package/dist/auth/project.cjs.map +1 -0
  78. package/dist/auth/project.d.cts +40 -0
  79. package/dist/auth/project.d.ts +19 -19
  80. package/dist/auth/project.js +169 -72
  81. package/dist/auth/project.js.map +1 -1
  82. package/dist/auth/zod.cjs +22 -0
  83. package/dist/auth/zod.cjs.map +1 -0
  84. package/dist/auth/zod.js +18 -17
  85. package/dist/auth/zod.js.map +1 -1
  86. package/dist/command.cjs +328 -0
  87. package/dist/command.cjs.map +1 -0
  88. package/dist/command.d.cts +289 -0
  89. package/dist/command.d.ts +265 -171
  90. package/dist/command.js +323 -226
  91. package/dist/command.js.map +1 -1
  92. package/dist/constants.d.cts +5 -0
  93. package/dist/constants.d.ts +5 -1
  94. package/dist/filesystem.cjs +499 -0
  95. package/dist/filesystem.cjs.map +1 -0
  96. package/dist/filesystem.d.cts +258 -0
  97. package/dist/filesystem.d.ts +258 -0
  98. package/dist/filesystem.js +497 -0
  99. package/dist/filesystem.js.map +1 -0
  100. package/dist/index.cjs +15 -0
  101. package/dist/index.d.cts +8 -0
  102. package/dist/index.d.ts +8 -6
  103. package/dist/index.js +8 -17
  104. package/dist/network-policy.d.cts +156 -0
  105. package/dist/network-policy.d.ts +88 -28
  106. package/dist/sandbox.cjs +816 -0
  107. package/dist/sandbox.cjs.map +1 -0
  108. package/dist/sandbox.d.cts +2847 -0
  109. package/dist/sandbox.d.ts +2834 -628
  110. package/dist/sandbox.js +808 -557
  111. package/dist/sandbox.js.map +1 -1
  112. package/dist/session.cjs +527 -0
  113. package/dist/session.cjs.map +1 -0
  114. package/dist/session.d.cts +410 -0
  115. package/dist/session.d.ts +403 -368
  116. package/dist/session.js +524 -489
  117. package/dist/session.js.map +1 -1
  118. package/dist/snapshot.cjs +204 -0
  119. package/dist/snapshot.cjs.map +1 -0
  120. package/dist/snapshot.d.cts +161 -0
  121. package/dist/snapshot.d.ts +152 -92
  122. package/dist/snapshot.js +201 -114
  123. package/dist/snapshot.js.map +1 -1
  124. package/dist/utils/array.cjs +17 -0
  125. package/dist/utils/array.cjs.map +1 -0
  126. package/dist/utils/array.js +12 -15
  127. package/dist/utils/array.js.map +1 -1
  128. package/dist/utils/consume-readable.cjs +18 -0
  129. package/dist/utils/consume-readable.cjs.map +1 -0
  130. package/dist/utils/consume-readable.js +13 -12
  131. package/dist/utils/consume-readable.js.map +1 -1
  132. package/dist/utils/decode-base64-url.cjs +15 -0
  133. package/dist/utils/decode-base64-url.cjs.map +1 -0
  134. package/dist/utils/decode-base64-url.js +10 -9
  135. package/dist/utils/decode-base64-url.js.map +1 -1
  136. package/dist/utils/dev-credentials.cjs +142 -0
  137. package/dist/utils/dev-credentials.cjs.map +1 -0
  138. package/dist/utils/dev-credentials.js +126 -184
  139. package/dist/utils/dev-credentials.js.map +1 -1
  140. package/dist/utils/get-credentials.cjs +123 -0
  141. package/dist/utils/get-credentials.cjs.map +1 -0
  142. package/dist/utils/get-credentials.d.cts +21 -0
  143. package/dist/utils/get-credentials.d.ts +19 -61
  144. package/dist/utils/get-credentials.js +106 -140
  145. package/dist/utils/get-credentials.js.map +1 -1
  146. package/dist/utils/log.cjs +25 -0
  147. package/dist/utils/log.cjs.map +1 -0
  148. package/dist/utils/log.js +15 -17
  149. package/dist/utils/log.js.map +1 -1
  150. package/dist/utils/network-policy.cjs +49 -0
  151. package/dist/utils/network-policy.cjs.map +1 -0
  152. package/dist/utils/network-policy.js +42 -77
  153. package/dist/utils/network-policy.js.map +1 -1
  154. package/dist/utils/normalizePath.cjs +27 -0
  155. package/dist/utils/normalizePath.cjs.map +1 -0
  156. package/dist/utils/normalizePath.js +21 -28
  157. package/dist/utils/normalizePath.js.map +1 -1
  158. package/dist/utils/paginator.cjs +41 -0
  159. package/dist/utils/paginator.cjs.map +1 -0
  160. package/dist/utils/paginator.d.cts +16 -0
  161. package/dist/utils/paginator.d.ts +16 -0
  162. package/dist/utils/paginator.js +40 -0
  163. package/dist/utils/paginator.js.map +1 -0
  164. package/dist/utils/resolveSignal.cjs +20 -0
  165. package/dist/utils/resolveSignal.cjs.map +1 -0
  166. package/dist/utils/resolveSignal.d.cts +15 -0
  167. package/dist/utils/resolveSignal.d.ts +12 -10
  168. package/dist/utils/resolveSignal.js +14 -17
  169. package/dist/utils/resolveSignal.js.map +1 -1
  170. package/dist/utils/sandbox-snapshot.cjs +14 -0
  171. package/dist/utils/sandbox-snapshot.cjs.map +1 -0
  172. package/dist/utils/sandbox-snapshot.d.cts +10 -0
  173. package/dist/utils/sandbox-snapshot.d.ts +11 -0
  174. package/dist/utils/sandbox-snapshot.js +14 -0
  175. package/dist/utils/sandbox-snapshot.js.map +1 -0
  176. package/dist/utils/types.cjs +13 -0
  177. package/dist/utils/types.cjs.map +1 -0
  178. package/dist/utils/types.d.cts +11 -0
  179. package/dist/utils/types.d.ts +5 -7
  180. package/dist/utils/types.js +8 -8
  181. package/dist/utils/types.js.map +1 -1
  182. package/dist/version.cjs +7 -0
  183. package/dist/version.cjs.map +1 -0
  184. package/dist/version.js +5 -5
  185. package/dist/version.js.map +1 -1
  186. package/package.json +23 -3
  187. package/dist/api-client/index.js.map +0 -1
  188. package/dist/auth/api.d.ts +0 -6
  189. package/dist/auth/error.d.ts +0 -11
  190. package/dist/auth/index.js.map +0 -1
  191. package/dist/auth/linked-project.d.ts +0 -10
  192. package/dist/auth/zod.d.ts +0 -5
  193. package/dist/constants.js +0 -3
  194. package/dist/constants.js.map +0 -1
  195. package/dist/index.js.map +0 -1
  196. package/dist/network-policy.js +0 -3
  197. package/dist/network-policy.js.map +0 -1
  198. package/dist/utils/array.d.ts +0 -9
  199. package/dist/utils/consume-readable.d.ts +0 -5
  200. package/dist/utils/convert-sandbox.d.ts +0 -6
  201. package/dist/utils/convert-sandbox.js +0 -14
  202. package/dist/utils/convert-sandbox.js.map +0 -1
  203. package/dist/utils/decode-base64-url.d.ts +0 -7
  204. package/dist/utils/dev-credentials.d.ts +0 -37
  205. package/dist/utils/log.d.ts +0 -2
  206. package/dist/utils/network-policy.d.ts +0 -7
  207. package/dist/utils/normalizePath.d.ts +0 -17
  208. package/dist/version.d.ts +0 -1
@@ -1,80 +1,177 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.inferScope = inferScope;
4
- exports.selectTeam = selectTeam;
5
- const zod_1 = require("zod");
6
- const api_1 = require("./api");
7
- const error_1 = require("./error");
8
- const linked_project_1 = require("./linked-project");
9
- const TeamsSchema = zod_1.z.object({
10
- teams: zod_1.z
11
- .array(zod_1.z.object({
12
- slug: zod_1.z.string(),
13
- }))
14
- .min(1, `No teams found. Please create a team first.`),
1
+ import { NotOk } from "./error.js";
2
+ import { fetchApi } from "./api.js";
3
+ import { readLinkedProject } from "./linked-project.js";
4
+ import { z } from "zod";
5
+
6
+ //#region src/auth/project.ts
7
+ const UserSchema = z.object({ user: z.object({
8
+ defaultTeamId: z.string().nullable(),
9
+ username: z.string()
10
+ }) });
11
+ const TeamSchema = z.object({
12
+ id: z.string(),
13
+ slug: z.string(),
14
+ updatedAt: z.number(),
15
+ membership: z.object({ role: z.string() }),
16
+ billing: z.object({ plan: z.string() })
17
+ });
18
+ const TeamsSchema = z.object({
19
+ teams: z.array(TeamSchema),
20
+ pagination: z.object({
21
+ count: z.number(),
22
+ next: z.number().nullable()
23
+ })
15
24
  });
16
25
  const DEFAULT_PROJECT_NAME = "vercel-sandbox-default-project";
26
+ /** Status codes that mean "this team can't be used, try the next one". */
27
+ function isSkippableTeamError(e) {
28
+ return e instanceof NotOk && (e.response.statusCode === 402 || e.response.statusCode === 403);
29
+ }
17
30
  /**
18
- * Resolves the team and project scope for sandbox operations.
19
- *
20
- * First checks for a locally linked project in `.vercel/project.json`.
21
- * If found, uses the `projectId` and `orgId` from there.
22
- *
23
- * Otherwise, if `teamId` is not provided, selects the first available team for the account.
24
- * Ensures a default project exists within the team, creating it if necessary.
25
- *
26
- * @param opts.token - Vercel API authentication token.
27
- * @param opts.teamId - Optional team slug. If omitted, the first team is selected.
28
- * @param opts.cwd - Optional directory to search for `.vercel/project.json`. Defaults to `process.cwd()`.
29
- * @returns The resolved scope with `projectId`, `teamId`, and whether the project was `created`.
30
- *
31
- * @throws {NotOk} If the API returns an error other than 404 when checking the project.
32
- * @throws {ZodError} If no teams exist for the account.
33
- *
34
- * @example
35
- * ```ts
36
- * const scope = await inferScope({ token: "vercel_..." });
37
- * // => { projectId: "vercel-sandbox-default-project", teamId: "my-team", created: false }
38
- * ```
39
- */
31
+ * Resolves the team and project scope for sandbox operations.
32
+ *
33
+ * First checks for a locally linked project in `.vercel/project.json`.
34
+ * If found, uses the `projectId` and `orgId` from there.
35
+ *
36
+ * Otherwise, if `teamId` is not provided, builds an ordered list of candidate
37
+ * teams to try: the user's `defaultTeamId` first (if set), then hobby-plan
38
+ * teams where the user has an OWNER role (preferring the personal team matching
39
+ * the username, then the most recently updated). Tries each candidate until one
40
+ * succeeds.
41
+ *
42
+ * @param opts.token - Vercel API authentication token.
43
+ * @param opts.teamId - Optional team slug. If omitted, candidate teams are resolved automatically.
44
+ * @param opts.cwd - Optional directory to search for `.vercel/project.json`. Defaults to `process.cwd()`.
45
+ * @returns The resolved scope with `projectId`, `teamId`, and whether the project was `created`.
46
+ *
47
+ * @throws {NotOk} If the API returns an error other than 404 when checking the project.
48
+ *
49
+ * @example
50
+ * ```ts
51
+ * const scope = await inferScope({ token: "vercel_..." });
52
+ * // => { projectId: "vercel-sandbox-default-project", teamId: "my-team", created: false }
53
+ * ```
54
+ */
40
55
  async function inferScope(opts) {
41
- const linkedProject = await (0, linked_project_1.readLinkedProject)(opts.cwd ?? process.cwd());
42
- if (linkedProject) {
43
- return { ...linkedProject, created: false };
44
- }
45
- const teamId = opts.teamId ?? (await selectTeam(opts.token));
46
- let created = false;
47
- try {
48
- await (0, api_1.fetchApi)({
49
- token: opts.token,
50
- endpoint: `/v2/projects/${encodeURIComponent(DEFAULT_PROJECT_NAME)}?slug=${encodeURIComponent(teamId)}`,
51
- });
52
- }
53
- catch (e) {
54
- if (!(e instanceof error_1.NotOk) || e.response.statusCode !== 404) {
55
- throw e;
56
- }
57
- await (0, api_1.fetchApi)({
58
- token: opts.token,
59
- endpoint: `/v11/projects?slug=${encodeURIComponent(teamId)}`,
60
- method: "POST",
61
- body: JSON.stringify({
62
- name: DEFAULT_PROJECT_NAME,
63
- }),
64
- });
65
- created = true;
66
- }
67
- return { projectId: DEFAULT_PROJECT_NAME, teamId, created };
56
+ const linkedProject = await readLinkedProject(opts.cwd ?? process.cwd());
57
+ if (linkedProject) {
58
+ const slugs = await resolveLinkedProjectSlugs(opts.token, linkedProject.teamId, linkedProject.projectId);
59
+ return {
60
+ ...linkedProject,
61
+ created: false,
62
+ ...slugs
63
+ };
64
+ }
65
+ if (opts.teamId) return tryTeam(opts.token, opts.teamId);
66
+ const { defaultTeamId, username } = (await fetchApi({
67
+ token: opts.token,
68
+ endpoint: "/v2/user"
69
+ }).then(UserSchema.parse)).user;
70
+ if (defaultTeamId) try {
71
+ const result = await tryTeam(opts.token, defaultTeamId);
72
+ try {
73
+ const team = await fetchApi({
74
+ token: opts.token,
75
+ endpoint: `/v2/teams/${encodeURIComponent(defaultTeamId)}`
76
+ }).then(z.object({ slug: z.string() }).parse);
77
+ return {
78
+ ...result,
79
+ teamSlug: team.slug
80
+ };
81
+ } catch {
82
+ return result;
83
+ }
84
+ } catch (e) {
85
+ if (!isSkippableTeamError(e)) throw e;
86
+ }
87
+ let next = null;
88
+ do {
89
+ const endpoint = next === null ? "/v2/teams?limit=20" : `/v2/teams?limit=20&until=${next}`;
90
+ const page = await fetchApi({
91
+ token: opts.token,
92
+ endpoint
93
+ }).then(TeamsSchema.parse);
94
+ next = page.pagination.next;
95
+ const hobbyOwnerTeams = page.teams.filter((t) => t.membership.role === "OWNER" && t.billing.plan === "hobby");
96
+ if (hobbyOwnerTeams.length === 0) continue;
97
+ const bestHobbyTeam = hobbyOwnerTeams.find((t) => t.slug === username) ?? hobbyOwnerTeams.sort((a, b) => b.updatedAt - a.updatedAt)[0];
98
+ if (bestHobbyTeam && bestHobbyTeam.id !== defaultTeamId) try {
99
+ return {
100
+ ...await tryTeam(opts.token, bestHobbyTeam.id),
101
+ teamSlug: bestHobbyTeam.slug
102
+ };
103
+ } catch (e) {
104
+ if (!isSkippableTeamError(e)) throw e;
105
+ }
106
+ } while (next !== null);
107
+ try {
108
+ return {
109
+ ...await tryTeam(opts.token, username),
110
+ teamSlug: username
111
+ };
112
+ } catch (e) {
113
+ if (!isSkippableTeamError(e)) throw e;
114
+ }
115
+ throw new NotOk({
116
+ statusCode: 403,
117
+ responseText: `Authenticated as "${username}" but none of the available teams allow sandbox creation. Specify a team explicitly with --scope <team-id-or-slug>.`
118
+ });
119
+ }
120
+ /**
121
+ * Attempts to use a specific team for sandbox operations by checking for
122
+ * (or creating) the default project within that team.
123
+ *
124
+ * @returns The resolved scope if the team is usable.
125
+ * @throws {NotOk} On authorization or other API errors.
126
+ */
127
+ async function tryTeam(token, teamId) {
128
+ const teamParam = teamId.startsWith("team_") ? `teamId=${encodeURIComponent(teamId)}` : `slug=${encodeURIComponent(teamId)}`;
129
+ let created = false;
130
+ try {
131
+ await fetchApi({
132
+ token,
133
+ endpoint: `/v2/projects/${encodeURIComponent(DEFAULT_PROJECT_NAME)}?${teamParam}`
134
+ });
135
+ } catch (e) {
136
+ if (!(e instanceof NotOk) || e.response.statusCode !== 404) throw e;
137
+ await fetchApi({
138
+ token,
139
+ endpoint: `/v11/projects?${teamParam}`,
140
+ method: "POST",
141
+ body: JSON.stringify({ name: DEFAULT_PROJECT_NAME })
142
+ });
143
+ created = true;
144
+ }
145
+ return {
146
+ projectId: DEFAULT_PROJECT_NAME,
147
+ teamId,
148
+ created
149
+ };
68
150
  }
69
151
  /**
70
- * Selects a team for the current token by querying the Teams API and
71
- * returning the slug of the first team in the result set.
72
- *
73
- * @param token - Authentication token used to call the Vercel API.
74
- * @returns A promise that resolves to the first team's slug.
75
- */
76
- async function selectTeam(token) {
77
- const { teams: [team], } = await (0, api_1.fetchApi)({ token, endpoint: "/v2/teams?limit=1" }).then(TeamsSchema.parse);
78
- return team.slug;
152
+ * Best-effort resolution of team slug and project name for a linked project.
153
+ * Both IDs may be opaque (e.g. `team_xxx`, `prj_xxx`), so we fetch the
154
+ * human-readable names from the API in parallel.
155
+ */
156
+ async function resolveLinkedProjectSlugs(token, teamId, projectId) {
157
+ try {
158
+ const teamParam = teamId.startsWith("team_") ? `teamId=${encodeURIComponent(teamId)}` : `slug=${encodeURIComponent(teamId)}`;
159
+ const [teamData, projectData] = await Promise.all([fetchApi({
160
+ token,
161
+ endpoint: `/v2/teams/${encodeURIComponent(teamId)}`
162
+ }).then(z.object({ slug: z.string() }).parse), fetchApi({
163
+ token,
164
+ endpoint: `/v2/projects/${encodeURIComponent(projectId)}?${teamParam}`
165
+ }).then(z.object({ name: z.string() }).parse)]);
166
+ return {
167
+ teamSlug: teamData.slug,
168
+ projectSlug: projectData.name
169
+ };
170
+ } catch {
171
+ return {};
172
+ }
79
173
  }
174
+
175
+ //#endregion
176
+ export { inferScope };
80
177
  //# sourceMappingURL=project.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/auth/project.ts"],"names":[],"mappings":";;AAwCA,gCAmCC;AASD,gCAOC;AA3FD,6BAAwB;AACxB,+BAAiC;AACjC,mCAAgC;AAChC,qDAAqD;AAErD,MAAM,WAAW,GAAG,OAAC,CAAC,MAAM,CAAC;IAC3B,KAAK,EAAE,OAAC;SACL,KAAK,CACJ,OAAC,CAAC,MAAM,CAAC;QACP,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE;KACjB,CAAC,CACH;SACA,GAAG,CAAC,CAAC,EAAE,6CAA6C,CAAC;CACzD,CAAC,CAAC;AAEH,MAAM,oBAAoB,GAAG,gCAAgC,CAAC;AAE9D;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACI,KAAK,UAAU,UAAU,CAAC,IAIhC;IACC,MAAM,aAAa,GAAG,MAAM,IAAA,kCAAiB,EAAC,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACzE,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO,EAAE,GAAG,aAAa,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC9C,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IAE7D,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,IAAA,cAAQ,EAAC;YACb,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,QAAQ,EAAE,gBAAgB,kBAAkB,CAAC,oBAAoB,CAAC,SAAS,kBAAkB,CAAC,MAAM,CAAC,EAAE;SACxG,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,CAAC,CAAC,YAAY,aAAK,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,UAAU,KAAK,GAAG,EAAE,CAAC;YAC3D,MAAM,CAAC,CAAC;QACV,CAAC;QAED,MAAM,IAAA,cAAQ,EAAC;YACb,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,QAAQ,EAAE,sBAAsB,kBAAkB,CAAC,MAAM,CAAC,EAAE;YAC5D,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,IAAI,EAAE,oBAAoB;aAC3B,CAAC;SACH,CAAC,CAAC;QACH,OAAO,GAAG,IAAI,CAAC;IACjB,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AAC9D,CAAC;AAED;;;;;;GAMG;AACI,KAAK,UAAU,UAAU,CAAC,KAAa;IAC5C,MAAM,EACJ,KAAK,EAAE,CAAC,IAAI,CAAC,GACd,GAAG,MAAM,IAAA,cAAQ,EAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,mBAAmB,EAAE,CAAC,CAAC,IAAI,CAC/D,WAAW,CAAC,KAAK,CAClB,CAAC;IACF,OAAO,IAAI,CAAC,IAAI,CAAC;AACnB,CAAC"}
1
+ {"version":3,"file":"project.js","names":["next: number | null","endpoint: string"],"sources":["../../src/auth/project.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { fetchApi } from \"./api.js\";\nimport { NotOk } from \"./error.js\";\nimport { readLinkedProject } from \"./linked-project.js\";\n\nconst UserSchema = z.object({\n user: z.object({\n defaultTeamId: z.string().nullable(),\n username: z.string(),\n }),\n});\n\nconst TeamSchema = z.object({\n id: z.string(),\n slug: z.string(),\n updatedAt: z.number(),\n membership: z.object({\n role: z.string(),\n }),\n billing: z.object({\n plan: z.string(),\n }),\n});\n\nconst TeamsSchema = z.object({\n teams: z.array(TeamSchema),\n pagination: z.object({\n count: z.number(),\n next: z.number().nullable(),\n }),\n});\n\nconst DEFAULT_PROJECT_NAME = \"vercel-sandbox-default-project\";\n\n/** Status codes that mean \"this team can't be used, try the next one\". */\nfunction isSkippableTeamError(e: unknown): boolean {\n return e instanceof NotOk && (e.response.statusCode === 402 || e.response.statusCode === 403);\n}\n\n/**\n * Resolves the team and project scope for sandbox operations.\n *\n * First checks for a locally linked project in `.vercel/project.json`.\n * If found, uses the `projectId` and `orgId` from there.\n *\n * Otherwise, if `teamId` is not provided, builds an ordered list of candidate\n * teams to try: the user's `defaultTeamId` first (if set), then hobby-plan\n * teams where the user has an OWNER role (preferring the personal team matching\n * the username, then the most recently updated). Tries each candidate until one\n * succeeds.\n *\n * @param opts.token - Vercel API authentication token.\n * @param opts.teamId - Optional team slug. If omitted, candidate teams are resolved automatically.\n * @param opts.cwd - Optional directory to search for `.vercel/project.json`. Defaults to `process.cwd()`.\n * @returns The resolved scope with `projectId`, `teamId`, and whether the project was `created`.\n *\n * @throws {NotOk} If the API returns an error other than 404 when checking the project.\n *\n * @example\n * ```ts\n * const scope = await inferScope({ token: \"vercel_...\" });\n * // => { projectId: \"vercel-sandbox-default-project\", teamId: \"my-team\", created: false }\n * ```\n */\nexport async function inferScope(opts: {\n token: string;\n teamId?: string;\n cwd?: string;\n}): Promise<{\n projectId: string;\n teamId: string;\n created: boolean;\n teamSlug?: string;\n projectSlug?: string;\n}> {\n const linkedProject = await readLinkedProject(opts.cwd ?? process.cwd());\n if (linkedProject) {\n const slugs = await resolveLinkedProjectSlugs(\n opts.token,\n linkedProject.teamId,\n linkedProject.projectId,\n );\n return { ...linkedProject, created: false, ...slugs };\n }\n\n if (opts.teamId) {\n return tryTeam(opts.token, opts.teamId);\n }\n\n const userData = await fetchApi({\n token: opts.token,\n endpoint: \"/v2/user\",\n }).then(UserSchema.parse);\n const { defaultTeamId, username } = userData.user;\n\n // 1. Try defaultTeamId first\n if (defaultTeamId) {\n try {\n const result = await tryTeam(opts.token, defaultTeamId);\n // Resolve team slug (best-effort)\n try {\n const team = await fetchApi({\n token: opts.token,\n endpoint: `/v2/teams/${encodeURIComponent(defaultTeamId)}`,\n }).then(z.object({ slug: z.string() }).parse);\n return { ...result, teamSlug: team.slug };\n } catch {\n return result;\n }\n } catch (e) {\n if (!isSkippableTeamError(e)) throw e;\n }\n }\n\n // 2. Paginate teams in pages of 20, try best hobby team per page\n let next: number | null = null;\n do {\n const endpoint: string =\n next === null\n ? \"/v2/teams?limit=20\"\n : `/v2/teams?limit=20&until=${next}`;\n const page = await fetchApi({ token: opts.token, endpoint }).then(\n TeamsSchema.parse,\n );\n\n next = page.pagination.next;\n\n const hobbyOwnerTeams = page.teams.filter(\n (t) => t.membership.role === \"OWNER\" && t.billing.plan === \"hobby\",\n );\n if (hobbyOwnerTeams.length === 0) {\n continue;\n }\n\n const bestHobbyTeam =\n hobbyOwnerTeams.find((t) => t.slug === username) ??\n hobbyOwnerTeams.sort((a, b) => b.updatedAt - a.updatedAt)[0];\n\n if (bestHobbyTeam && bestHobbyTeam.id !== defaultTeamId) {\n try {\n const result = await tryTeam(opts.token, bestHobbyTeam.id);\n return { ...result, teamSlug: bestHobbyTeam.slug };\n } catch (e) {\n if (!isSkippableTeamError(e)) throw e;\n }\n }\n } while (next !== null);\n\n // 3. Fall back to username as personal team\n try {\n const result = await tryTeam(opts.token, username);\n return { ...result, teamSlug: username };\n } catch (e) {\n if (!isSkippableTeamError(e)) throw e;\n }\n\n throw new NotOk({\n statusCode: 403,\n responseText: `Authenticated as \"${username}\" but none of the available teams allow sandbox creation. Specify a team explicitly with --scope <team-id-or-slug>.`,\n });\n}\n\n/**\n * Attempts to use a specific team for sandbox operations by checking for\n * (or creating) the default project within that team.\n *\n * @returns The resolved scope if the team is usable.\n * @throws {NotOk} On authorization or other API errors.\n */\nasync function tryTeam(\n token: string,\n teamId: string,\n): Promise<{ projectId: string; teamId: string; created: boolean }> {\n const teamParam = teamId.startsWith(\"team_\")\n ? `teamId=${encodeURIComponent(teamId)}`\n : `slug=${encodeURIComponent(teamId)}`;\n\n let created = false;\n try {\n await fetchApi({\n token,\n endpoint: `/v2/projects/${encodeURIComponent(DEFAULT_PROJECT_NAME)}?${teamParam}`,\n });\n } catch (e) {\n if (!(e instanceof NotOk) || e.response.statusCode !== 404) {\n throw e;\n }\n\n await fetchApi({\n token,\n endpoint: `/v11/projects?${teamParam}`,\n method: \"POST\",\n body: JSON.stringify({\n name: DEFAULT_PROJECT_NAME,\n }),\n });\n created = true;\n }\n\n return { projectId: DEFAULT_PROJECT_NAME, teamId, created };\n}\n\n/**\n * Best-effort resolution of team slug and project name for a linked project.\n * Both IDs may be opaque (e.g. `team_xxx`, `prj_xxx`), so we fetch the\n * human-readable names from the API in parallel.\n */\nasync function resolveLinkedProjectSlugs(\n token: string,\n teamId: string,\n projectId: string,\n): Promise<{ teamSlug?: string; projectSlug?: string }> {\n try {\n const teamParam = teamId.startsWith(\"team_\")\n ? `teamId=${encodeURIComponent(teamId)}`\n : `slug=${encodeURIComponent(teamId)}`;\n const [teamData, projectData] = await Promise.all([\n fetchApi({\n token,\n endpoint: `/v2/teams/${encodeURIComponent(teamId)}`,\n }).then(z.object({ slug: z.string() }).parse),\n fetchApi({\n token,\n endpoint: `/v2/projects/${encodeURIComponent(projectId)}?${teamParam}`,\n }).then(z.object({ name: z.string() }).parse),\n ]);\n return { teamSlug: teamData.slug, projectSlug: projectData.name };\n } catch {\n return {};\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
2
+ let zod = require("zod");
3
+
4
+ //#region src/auth/zod.ts
5
+ /**
6
+ * A Zod codec that serializes and deserializes JSON strings.
7
+ */
8
+ const json = zod.z.string().transform((jsonString, ctx) => {
9
+ try {
10
+ return JSON.parse(jsonString);
11
+ } catch (err) {
12
+ ctx.addIssue({
13
+ code: zod.z.ZodIssueCode.custom,
14
+ message: `Invalid JSON: ${err.message}`
15
+ });
16
+ return zod.z.NEVER;
17
+ }
18
+ });
19
+
20
+ //#endregion
21
+ exports.json = json;
22
+ //# sourceMappingURL=zod.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zod.cjs","names":["z","err: any"],"sources":["../../src/auth/zod.ts"],"sourcesContent":["import { z } from \"zod\";\n\n/**\n * A Zod codec that serializes and deserializes JSON strings.\n */\nexport const json = z.string().transform((jsonString: string, ctx): unknown => {\n try {\n return JSON.parse(jsonString);\n } catch (err: any) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `Invalid JSON: ${err.message}`,\n });\n return z.NEVER;\n }\n});\n"],"mappings":";;;;;;;AAKA,MAAa,OAAOA,MAAE,QAAQ,CAAC,WAAW,YAAoB,QAAiB;AAC7E,KAAI;AACF,SAAO,KAAK,MAAM,WAAW;UACtBC,KAAU;AACjB,MAAI,SAAS;GACX,MAAMD,MAAE,aAAa;GACrB,SAAS,iBAAiB,IAAI;GAC/B,CAAC;AACF,SAAOA,MAAE;;EAEX"}
package/dist/auth/zod.js CHANGED
@@ -1,20 +1,21 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.json = void 0;
4
- const zod_1 = require("zod");
1
+ import { z } from "zod";
2
+
3
+ //#region src/auth/zod.ts
5
4
  /**
6
- * A Zod codec that serializes and deserializes JSON strings.
7
- */
8
- exports.json = zod_1.z.string().transform((jsonString, ctx) => {
9
- try {
10
- return JSON.parse(jsonString);
11
- }
12
- catch (err) {
13
- ctx.addIssue({
14
- code: zod_1.z.ZodIssueCode.custom,
15
- message: `Invalid JSON: ${err.message}`,
16
- });
17
- return zod_1.z.NEVER;
18
- }
5
+ * A Zod codec that serializes and deserializes JSON strings.
6
+ */
7
+ const json = z.string().transform((jsonString, ctx) => {
8
+ try {
9
+ return JSON.parse(jsonString);
10
+ } catch (err) {
11
+ ctx.addIssue({
12
+ code: z.ZodIssueCode.custom,
13
+ message: `Invalid JSON: ${err.message}`
14
+ });
15
+ return z.NEVER;
16
+ }
19
17
  });
18
+
19
+ //#endregion
20
+ export { json };
20
21
  //# sourceMappingURL=zod.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"zod.js","sourceRoot":"","sources":["../../src/auth/zod.ts"],"names":[],"mappings":";;;AAAA,6BAAwB;AAExB;;GAEG;AACU,QAAA,IAAI,GAAG,OAAC,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,CAAC,UAAkB,EAAE,GAAG,EAAW,EAAE;IAC5E,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAChC,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,GAAG,CAAC,QAAQ,CAAC;YACX,IAAI,EAAE,OAAC,CAAC,YAAY,CAAC,MAAM;YAC3B,OAAO,EAAE,iBAAiB,GAAG,CAAC,OAAO,EAAE;SACxC,CAAC,CAAC;QACH,OAAO,OAAC,CAAC,KAAK,CAAC;IACjB,CAAC;AACH,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"zod.js","names":["err: any"],"sources":["../../src/auth/zod.ts"],"sourcesContent":["import { z } from \"zod\";\n\n/**\n * A Zod codec that serializes and deserializes JSON strings.\n */\nexport const json = z.string().transform((jsonString: string, ctx): unknown => {\n try {\n return JSON.parse(jsonString);\n } catch (err: any) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `Invalid JSON: ${err.message}`,\n });\n return z.NEVER;\n }\n});\n"],"mappings":";;;;;;AAKA,MAAa,OAAO,EAAE,QAAQ,CAAC,WAAW,YAAoB,QAAiB;AAC7E,KAAI;AACF,SAAO,KAAK,MAAM,WAAW;UACtBA,KAAU;AACjB,MAAI,SAAS;GACX,MAAM,EAAE,aAAa;GACrB,SAAS,iBAAiB,IAAI;GAC/B,CAAC;AACF,SAAO,EAAE;;EAEX"}