@base44-preview/cli 0.0.1-pr.10.0e28f2b → 0.0.1-pr.10.1d6afbb

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 (2) hide show
  1. package/dist/cli/index.js +47 -140
  2. package/package.json +1 -1
package/dist/cli/index.js CHANGED
@@ -108,6 +108,51 @@ const authClient = ky.create({
108
108
  });
109
109
  var authClient_default = authClient;
110
110
 
111
+ //#endregion
112
+ //#region src/core/auth/api.ts
113
+ async function generateDeviceCode() {
114
+ const response = await authClient_default.post("oauth/device/code", {
115
+ json: {
116
+ client_id: AUTH_CLIENT_ID,
117
+ scope: "apps:read apps:write"
118
+ },
119
+ throwHttpErrors: false
120
+ });
121
+ if (!response.ok) throw new AuthApiError(`Failed to generate device code: ${response.status} ${response.statusText}`);
122
+ const result = DeviceCodeResponseSchema.safeParse(await response.json());
123
+ if (!result.success) throw new AuthValidationError(`Invalid device code response from server: ${result.error.message}`);
124
+ return result.data;
125
+ }
126
+ async function getTokenFromDeviceCode(deviceCode) {
127
+ const searchParams = new URLSearchParams();
128
+ searchParams.set("grant_type", "urn:ietf:params:oauth:grant-type:device_code");
129
+ searchParams.set("device_code", deviceCode);
130
+ searchParams.set("client_id", AUTH_CLIENT_ID);
131
+ const response = await authClient_default.post("oauth/token", {
132
+ body: searchParams.toString(),
133
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
134
+ throwHttpErrors: false
135
+ });
136
+ const json = await response.json();
137
+ if (!response.ok) {
138
+ const errorResult = OAuthErrorSchema.safeParse(json);
139
+ if (!errorResult.success) throw new AuthValidationError(`Token request failed: ${errorResult.error.message}`);
140
+ const { error, error_description } = errorResult.data;
141
+ if (error === "authorization_pending" || error === "slow_down") return null;
142
+ throw new AuthApiError(error_description ?? `OAuth error: ${error}`);
143
+ }
144
+ const result = TokenResponseSchema.safeParse(json);
145
+ if (!result.success) throw new AuthValidationError(`Invalid token response from server: ${result.error.message}`);
146
+ return result.data;
147
+ }
148
+ async function getUserInfo(accessToken) {
149
+ const response = await authClient_default.get("oauth/userinfo", { headers: { Authorization: `Bearer ${accessToken}` } });
150
+ if (!response.ok) throw new AuthApiError(`Failed to fetch user info: ${response.status}`);
151
+ const result = UserInfoSchema.safeParse(await response.json());
152
+ if (!result.success) throw new AuthValidationError(`Invalid UserInfo response from server: ${result.error.message}`);
153
+ return result.data;
154
+ }
155
+
111
156
  //#endregion
112
157
  //#region src/core/utils/fs.ts
113
158
  function pathExists(path) {
@@ -150,7 +195,6 @@ async function deleteFile(filePath) {
150
195
  //#endregion
151
196
  //#region src/core/auth/config.ts
152
197
  const TOKEN_REFRESH_BUFFER_MS = 60 * 1e3;
153
- let refreshPromise = null;
154
198
  async function readAuth() {
155
199
  try {
156
200
  const parsed = await readJsonFile(getAuthFilePath());
@@ -179,143 +223,6 @@ async function deleteAuth() {
179
223
  throw new Error(`Failed to delete authentication file: ${error instanceof Error ? error.message : "Unknown error"}`);
180
224
  }
181
225
  }
182
- /**
183
- * Checks if the access token is expired or about to expire.
184
- */
185
- function isTokenExpired(auth) {
186
- return Date.now() >= auth.expiresAt - TOKEN_REFRESH_BUFFER_MS;
187
- }
188
- /**
189
- * Refreshes the access token and saves the new tokens.
190
- * Returns the new access token, or null if refresh failed.
191
- * Uses a lock to prevent concurrent refresh requests.
192
- */
193
- async function refreshAndSaveTokens() {
194
- if (refreshPromise) return refreshPromise;
195
- refreshPromise = (async () => {
196
- try {
197
- const auth = await readAuth();
198
- const tokenResponse = await renewAccessToken(auth.refreshToken);
199
- await writeAuth({
200
- ...auth,
201
- accessToken: tokenResponse.accessToken,
202
- refreshToken: tokenResponse.refreshToken,
203
- expiresAt: Date.now() + tokenResponse.expiresIn * 1e3
204
- });
205
- return tokenResponse.accessToken;
206
- } catch {
207
- await deleteAuth();
208
- return null;
209
- } finally {
210
- refreshPromise = null;
211
- }
212
- })();
213
- return refreshPromise;
214
- }
215
-
216
- //#endregion
217
- //#region src/core/utils/httpClient.ts
218
- const retriedRequests = /* @__PURE__ */ new WeakSet();
219
- /**
220
- * Handles 401 responses by refreshing the token and retrying the request.
221
- * Only retries once per request to prevent infinite loops.
222
- */
223
- async function handleUnauthorized(request, _options, response) {
224
- if (response.status !== 401) return;
225
- if (retriedRequests.has(request)) return;
226
- const newAccessToken = await refreshAndSaveTokens();
227
- if (!newAccessToken) return;
228
- retriedRequests.add(request);
229
- request.headers.set("Authorization", `Bearer ${newAccessToken}`);
230
- return ky(request);
231
- }
232
- const httpClient = ky.create({
233
- prefixUrl: getBase44ApiUrl(),
234
- headers: { "User-Agent": "Base44 CLI" },
235
- hooks: {
236
- beforeRequest: [async (request) => {
237
- try {
238
- const auth = await readAuth();
239
- if (isTokenExpired(auth)) {
240
- const newAccessToken = await refreshAndSaveTokens();
241
- if (newAccessToken) {
242
- request.headers.set("Authorization", `Bearer ${newAccessToken}`);
243
- return;
244
- }
245
- }
246
- request.headers.set("Authorization", `Bearer ${auth.accessToken}`);
247
- } catch {}
248
- }],
249
- afterResponse: [handleUnauthorized]
250
- }
251
- });
252
- var httpClient_default = httpClient;
253
-
254
- //#endregion
255
- //#region src/core/auth/api.ts
256
- async function generateDeviceCode() {
257
- const response = await authClient_default.post("oauth/device/code", {
258
- json: {
259
- client_id: AUTH_CLIENT_ID,
260
- scope: "apps:read apps:write"
261
- },
262
- throwHttpErrors: false
263
- });
264
- if (!response.ok) throw new AuthApiError(`Failed to generate device code: ${response.status} ${response.statusText}`);
265
- const result = DeviceCodeResponseSchema.safeParse(await response.json());
266
- if (!result.success) throw new AuthValidationError(`Invalid device code response from server: ${result.error.message}`);
267
- return result.data;
268
- }
269
- async function getTokenFromDeviceCode(deviceCode) {
270
- const searchParams = new URLSearchParams();
271
- searchParams.set("grant_type", "urn:ietf:params:oauth:grant-type:device_code");
272
- searchParams.set("device_code", deviceCode);
273
- searchParams.set("client_id", AUTH_CLIENT_ID);
274
- const response = await authClient_default.post("oauth/token", {
275
- body: searchParams.toString(),
276
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
277
- throwHttpErrors: false
278
- });
279
- const json = await response.json();
280
- if (!response.ok) {
281
- const errorResult = OAuthErrorSchema.safeParse(json);
282
- if (!errorResult.success) throw new AuthValidationError(`Token request failed: ${errorResult.error.message}`);
283
- const { error, error_description } = errorResult.data;
284
- if (error === "authorization_pending" || error === "slow_down") return null;
285
- throw new AuthApiError(error_description ?? `OAuth error: ${error}`);
286
- }
287
- const result = TokenResponseSchema.safeParse(json);
288
- if (!result.success) throw new AuthValidationError(`Invalid token response from server: ${result.error.message}`);
289
- return result.data;
290
- }
291
- async function renewAccessToken(refreshToken) {
292
- const searchParams = new URLSearchParams();
293
- searchParams.set("grant_type", "refresh_token");
294
- searchParams.set("refresh_token", refreshToken);
295
- searchParams.set("client_id", AUTH_CLIENT_ID);
296
- const response = await authClient_default.post("oauth/token", {
297
- body: searchParams.toString(),
298
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
299
- throwHttpErrors: false
300
- });
301
- const json = await response.json();
302
- if (!response.ok) {
303
- const errorResult = OAuthErrorSchema.safeParse(json);
304
- if (!errorResult.success) throw new AuthApiError(`Token refresh failed: ${response.statusText}`);
305
- const { error, error_description } = errorResult.data;
306
- throw new AuthApiError(error_description ?? `OAuth error: ${error}`);
307
- }
308
- const result = TokenResponseSchema.safeParse(json);
309
- if (!result.success) throw new AuthValidationError(`Invalid token response from server: ${result.error.message}`);
310
- return result.data;
311
- }
312
- async function getUserInfo() {
313
- const response = await httpClient_default.get("oauth/userinfo");
314
- if (!response.ok) throw new AuthApiError(`Failed to fetch user info: ${response.status}`);
315
- const result = UserInfoSchema.safeParse(await response.json());
316
- if (!result.success) throw new AuthValidationError(`Invalid UserInfo response from server: ${result.error.message}`);
317
- return result.data;
318
- }
319
226
 
320
227
  //#endregion
321
228
  //#region src/cli/utils/runCommand.ts
@@ -412,9 +319,9 @@ async function saveAuthData(response, userInfo) {
412
319
  async function login() {
413
320
  const deviceCodeResponse = await generateAndDisplayDeviceCode();
414
321
  const token = await waitForAuthentication(deviceCodeResponse.deviceCode, deviceCodeResponse.expiresIn, deviceCodeResponse.interval);
415
- const userInfo = await getUserInfo();
322
+ const userInfo = await getUserInfo(token.accessToken);
416
323
  await saveAuthData(token, userInfo);
417
- log.success(`Successfully logged as ${chalk.bold(userInfo.email)}`);
324
+ log.success(`Successfully logged in as ${chalk.bold(userInfo.email)}`);
418
325
  }
419
326
  const loginCommand = new Command("login").description("Authenticate with Base44").action(async () => {
420
327
  await runCommand(login);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base44-preview/cli",
3
- "version": "0.0.1-pr.10.0e28f2b",
3
+ "version": "0.0.1-pr.10.1d6afbb",
4
4
  "description": "Base44 CLI - Unified interface for managing Base44 applications",
5
5
  "type": "module",
6
6
  "main": "./dist/cli/index.js",