PranitInitial commit439f83c3 months agoHistory
1217 lines · 48.7 KB · Zig
RawDownload
const std = @import("std");const config_runtime = @import("../config/config_runtime.zig");const debug_trace = @import("../shared/debug_trace.zig");const host = @import("../hosts/host.zig");const runtime_profile = @import("../hosts/runtime_profile.zig");const io_mod = @import("../shared/io.zig");const credentials = @import("../auth/credentials.zig");const auth_runtime = @import("../auth/auth_runtime.zig");const login_flow = @import("../auth/login_flow.zig");const types = @import("../shared/types.zig"); fn oauthAuthEnabled(comptime App: type) bool {    return runtime_profile.allows(App, .native_auth) or        runtime_profile.allows(App, .js_host_auth);} pub fn Runtime(comptime App: type) type {    return struct {        fn ensurePromptCredential(app: *App) !bool {            if (app.auth.credentialSource() != null) return true;             const auth_view = app.auth.view();            if (auth_view.onboarding_skipped) {                try app.writeDomainNotice(.{                    .topic = "auth",                    .tone = .@"error",                    .body = credentials.missing_interactive_credential_message,                }, true);            } else if (!app.auth.pickerView().active) {                try app.auth.refreshSourceInventory(app.alloc);                app.auth.openOnboardingPicker(app.alloc);            }            app.shell.render_requests.request(.footer);            return false;        }         pub fn runLoginCommand(app: *App) !void {            if (comptime !oauthAuthEnabled(App)) {                try app.writeDomainNotice(.{                    .topic = "auth",                    .tone = .warning,                    .body = "Set FX_API_KEY through createFxTerminal() to authenticate this WASM session.",                }, true);                return;            }            try beginSignIn(app, false);        }         pub fn runLogoutCommand(app: *App) !void {            if (comptime !oauthAuthEnabled(App)) {                try app.writeDomainNotice(.{                    .topic = "auth",                    .tone = .warning,                    .body = "Authentication is owned by the embedding SDK for this WASM session.",                }, true);                return;            }            try app.flushBeforeBlockingExternalWork();            const result = login_flow.logout(app.alloc, app.auth.oauthTransport()) catch |err| switch (err) {                error.SessionDeleteFailed => {                    try writeAuthNotice(app, .{                        .topic = "auth",                        .tone = .@"error",                        .body = "Could not complete fx logout. The current source is unchanged.",                    });                    return;                },            };            try applyLogoutResult(app, result);        }         pub fn openSetupHub(app: *App) !void {            if (comptime !runtime_profile.allows(App, .native_auth)) {                try app.writeDomainNotice(.{                    .topic = "auth",                    .tone = .warning,                    .body = "API key setup is unavailable in this WASM session.",                }, true);                return;            }            try app.auth.refreshSourceInventory(app.alloc);            app.auth.openPicker(app.alloc);            app.shell.render_requests.request(.footer);        }         fn applyLogoutResult(app: *App, result: login_flow.LogoutResult) !void {            // Logging out is an explicit rejection of that credential, so a            // remembered pointer to it would silently reactivate on next login.            // A remembered source always wins resolution, so an active fx login            // is the only way one can be remembered; clearing otherwise is a            // no-op against a store that holds nothing.            if (app.auth.credentialSource() == .fx_login) forgetCredentialSource(app);            applyCredentialChange(app, try app.auth.reconcileAfterFxLoginLogout(app.alloc));            try writeAuthNotice(app, if (result.local_durability_failed)                .{                    .topic = "auth",                    .tone = .warning,                    .body = "Could not confirm durable fx logout. The active source was recalculated.",                }            else if (result.session_deleted)                .{                    .topic = "auth",                    .tone = .neutral,                    .body = "Signed out of fx.",                }            else                .{                    .topic = "auth",                    .tone = .neutral,                    .body = "No fx login session found.",                });            if (result.remote_revocation_failed) {                try writeAuthNotice(app, .{                    .topic = "auth",                    .tone = .warning,                    .body = login_flow.remote_revocation_warning,                });            }        }         pub fn applyPickerChoice(app: *App, choice: auth_runtime.Choice) !void {            if (comptime !oauthAuthEnabled(App)) {                try app.writeDomainNotice(.{                    .topic = "auth",                    .tone = .warning,                    .body = "Browser authentication is supplied by the embedding SDK.",                }, true);                return;            }            switch (choice) {                .source => |source| try applySourceChoice(app, source),                .action => |action| switch (action) {                    .login => try beginSignIn(app, true),                    .setup => {                        if (comptime !runtime_profile.allows(App, .native_auth)) {                            try app.writeDomainNotice(.{                                .topic = "auth",                                .tone = .warning,                                .body = "API key setup is unavailable in this WASM session.",                            }, true);                            return;                        }                        prepareApiKeyInputBoundary(app);                        app.auth.openApiKeyPickerFromRoot(app.alloc);                    },                    .change_team => try beginTeamPicker(app),                    .switch_credential => app.auth.openSwitchCredentialPicker(app.alloc),                    .automatic => try applyAutomaticCredential(app),                },                .team => |index| try applyTeamChoice(app, index),            }        }         pub fn routeAuthPickerByte(app: *App, byte: u8) !bool {            if (app.auth.signInEntryActive()) {                switch (byte) {                    3, 4 => _ = app.auth.popPickerStage(app.alloc),                    '\r', '\n' => try openSignInBrowser(app),                    else => {},                }                app.shell.render_requests.request(.footer);                return true;            }            if (app.auth.teamPickerActive()) {                const consumed = switch (byte) {                    8, 127 => app.auth.deleteTeamQueryByte(),                    else => try app.auth.appendTeamQueryByte(app.alloc, byte),                };                if (consumed) {                    app.shell.render_requests.request(.footer);                    return true;                }            }            if (!app.auth.apiKeyEntryActive()) return false;            switch (byte) {                3, 4 => _ = app.auth.popPickerStage(app.alloc),                '\r', '\n' => try submitApiKeyEntry(app),                8, 127 => _ = app.auth.deleteApiKeyByte(),                else => _ = try app.auth.appendApiKeyByte(app.alloc, byte),            }            app.shell.render_requests.request(.footer);            return true;        }         pub fn routeAuthPickerEscapeAction(app: *App, action: anytype) bool {            if (!app.auth.signInEntryActive() and !app.auth.apiKeyEntryActive()) return false;            return switch (action) {                .escape, .remapped_byte => false,                else => true,            };        }         pub fn collectSignInFacts(app: *App) !void {            if (comptime !oauthAuthEnabled(App)) return;            app.auth.pulseSignIn(app.alloc);            switch (app.auth.pollSignInTransition(app.alloc)) {                .none => {},                .cancelled => app.shell.render_requests.request(.footer),                .failed => |err| {                    debug_trace.logf("auth", "login failed err={s}", .{@errorName(err)});                    _ = app.auth.popPickerStage(app.alloc);                    try writeLoginError(app, err);                },                .succeeded => |completed| {                    var selection = completed;                    defer selection.deinit(app.alloc);                     if (!try selectCredentialSource(app, .fx_login)) {                        _ = app.auth.popPickerStage(app.alloc);                        try writeAuthNotice(app, .{                            .topic = "auth",                            .tone = .@"error",                            .body = "Signed in, but the fx login credential could not be loaded.",                        });                        return;                    }                    rememberCredentialSource(app, .fx_login);                     if (selection.teams.items.len > 0) {                        app.auth.openTeamPicker(app.alloc, &selection);                    } else {                        _ = app.auth.popPickerStage(app.alloc);                    }                    try writeAuthNotice(app, .{                        .topic = "auth",                        .tone = .neutral,                        .body = "Signed in to Vercel.",                    });                },            }        }         fn prepareApiKeyInputBoundary(app: *App) void {            if (comptime @hasDecl(App, "prepareApiKeyInputBoundary")) {                app.prepareApiKeyInputBoundary();            }        }         fn submitApiKeyEntry(app: *App) !void {            if (app.auth.pickerView().api_key_mask_count == 0) return;            switch (app.auth.beginApiKeySave(app.alloc)) {                .started => app.shell.render_requests.request(.footer),                .empty => {},                .busy => try app.writeDomainNotice(.{                    .topic = "auth",                    .tone = .warning,                    .body = "Still saving the previous API key. Nothing was stored for this one; try again in a moment.",                }, true),            }        }         /// Polled from the event loop so a save that blocks on a locked key store        /// or a slow gateway never stalls rendering.        pub fn collectApiKeySaveFacts(app: *App) !void {            const result = app.auth.takeApiKeySaveResult(app.alloc) orelse return;            try applyApiKeySaveResult(app, result);        }         fn applyApiKeySaveResult(app: *App, result: auth_runtime.ApiKeySaveResult) !void {            switch (result) {                .empty => return,                .saved => |changed| {                    applyCredentialChange(app, changed);                    rememberCredentialSource(app, .stored_key);                    const body = try std.fmt.allocPrint(                        app.alloc,                        "Saved the API key to {s} and made it active.",                        .{credentials.stored_key_backend_label},                    );                    defer app.alloc.free(body);                    try app.writeDomainNotice(.{                        .topic = "auth",                        .tone = .neutral,                        .body = body,                    }, true);                },                .gateway_refused => try app.writeDomainNotice(.{                    .topic = "auth",                    .tone = .@"error",                    .body = "The AI Gateway refused that API key. Nothing was stored.",                }, true),                .gateway_unavailable => try app.writeDomainNotice(.{                    .topic = "auth",                    .tone = .@"error",                    .body = "Could not verify that API key with AI Gateway. Nothing was stored.",                }, true),                .store_failed => {                    const body = try std.fmt.allocPrint(                        app.alloc,                        "Could not save the API key to {s}. Nothing was stored.",                        .{credentials.stored_key_backend_label},                    );                    defer app.alloc.free(body);                    try app.writeDomainNotice(.{                        .topic = "auth",                        .tone = .@"error",                        .body = body,                    }, true);                },                .reload_failed => {                    const body = try std.fmt.allocPrint(                        app.alloc,                        "Saved the API key to {s}, but could not make it active.",                        .{credentials.stored_key_backend_label},                    );                    defer app.alloc.free(body);                    try app.writeDomainNotice(.{                        .topic = "auth",                        .tone = .warning,                        .body = body,                    }, true);                },            }        }         /// Clearing the remembered choice must also re-resolve, otherwise the        /// session would keep running on a source precedence no longer selects.        fn applyAutomaticCredential(app: *App) !void {            forgetCredentialSource(app);            app.auth.closePicker(app.alloc);            applyCredentialChange(app, try app.auth.reselectByPrecedence(app.alloc));            try app.writeDomainNotice(.{                .topic = "auth",                .tone = .neutral,                .body = "Using automatic credential precedence again.",            }, true);        }         fn forgetCredentialSource(app: *App) void {            var attempt = config_runtime.attemptUserPreferences(                app.alloc,                .{ .clear_credential_source = true },            );            defer attempt.deinit(app.alloc);            switch (attempt) {                .outcome => debug_trace.logf("auth", "credential choice cleared", .{}),                .failure => |failure| debug_trace.logf(                    "auth",                    "credential choice not cleared err={s}",                    .{@errorName(failure.err)},                ),            }        }         fn applySourceChoice(app: *App, source: credentials.Source) !void {            const body = try std.fmt.allocPrint(                app.alloc,                "Switched credential to {s}.",                .{credentials.sourceLabel(source)},            );            defer app.alloc.free(body);             if (!try selectCredentialSource(app, source)) {                try app.writeDomainNotice(.{                    .topic = "auth",                    .tone = .warning,                    .body = "That credential is no longer available. The current source is unchanged.",                }, true);                return;            }             rememberCredentialSource(app, source);            try app.writeDomainNotice(.{                .topic = "auth",                .tone = .neutral,                .body = body,            }, true);        }         /// An explicit source choice outlives the session. Failing to persist        /// leaves the source active for this run rather than refusing a working        /// credential the user already selected.        fn rememberCredentialSource(app: *App, source: credentials.Source) void {            if (comptime @hasDecl(App, "persistCredentialSourcePreference")) {                app.persistCredentialSourcePreference(source);                return;            }             var attempt = config_runtime.attemptUserPreferences(                app.alloc,                .{ .credential_source = source },            );            defer attempt.deinit(app.alloc);            switch (attempt) {                .outcome => debug_trace.logf("auth", "credential choice persisted source={t}", .{source}),                .failure => |failure| debug_trace.logf(                    "auth",                    "credential choice not persisted source={t} err={s}",                    .{ source, @errorName(failure.err) },                ),            }        }         fn beginTeamPicker(app: *App) !void {            if (!app.auth.pickerView().fx_login_session_available) return;            try app.flushBeforeBlockingExternalWork();             var selection = login_flow.loadTeamSelection(app.alloc, app.auth.oauthTransport()) catch |err| {                debug_trace.logf("auth", "team picker load failed err={s}", .{@errorName(err)});                try app.writeDomainNotice(.{                    .topic = "auth",                    .tone = .@"error",                    .body = switch (err) {                        error.NoSession => "The fx login session is no longer available. Sign in to change teams.",                        error.NoTeams => "No Vercel teams are available for this account.",                        else => "Could not load Vercel teams. The current team is unchanged.",                    },                }, true);                return;            };            defer selection.deinit(app.alloc);            app.auth.openTeamPicker(app.alloc, &selection);            app.shell.render_requests.request(.footer);        }         fn applyTeamChoice(app: *App, index: usize) !void {            const selection = app.auth.teamSelection() orelse return;            if (index >= selection.teams.items.len) return;            const team = selection.teams.items[index];            const body = try std.fmt.allocPrint(                app.alloc,                "Changed Vercel team to {s} ({s}).",                .{ team.name, team.slug },            );            defer app.alloc.free(body);             var selected_team = selection.select(app.alloc, index) catch |err| {                debug_trace.logf("auth", "team change failed err={s}", .{@errorName(err)});                app.auth.closePicker(app.alloc);                try app.writeDomainNotice(.{                    .topic = "auth",                    .tone = .@"error",                    .body = switch (err) {                        error.SessionChanged, error.NoSession => "The fx login session changed before the team could be saved.",                        else => "Could not change the Vercel team. The current team is unchanged.",                    },                }, true);                return;            };            defer selected_team.deinit(app.alloc);             if (app.auth.credentialSource() == .fx_login) {                applyCredentialChange(app, app.auth.adoptSelectedTeam(app.alloc, &selected_team));            } else if (!try selectCredentialSource(app, .fx_login)) {                app.auth.closePicker(app.alloc);                try app.writeDomainNotice(.{                    .topic = "auth",                    .tone = .@"error",                    .body = "Changed the Vercel team, but the fx login credential could not be loaded.",                }, true);                return;            }            rememberCredentialSource(app, .fx_login);            app.auth.closePicker(app.alloc);            try app.writeDomainNotice(.{                .topic = "auth",                .tone = .neutral,                .body = body,            }, true);        }         fn beginSignIn(app: *App, from_root: bool) !void {            try app.flushBeforeBlockingExternalWork();             const started = if (from_root)                app.auth.openSignInPickerFromRoot(app.alloc)            else                app.auth.openSignInPicker(app.alloc);            if (started catch |err| {                debug_trace.logf("auth", "login failed err={s}", .{@errorName(err)});                try writeLoginError(app, err);                return;            }) {                app.shell.render_requests.request(.footer);                // Open the browser as soon as the device code is ready instead of                // waiting for Enter; Enter stays as a manual re-open, and                // FX_NO_OPEN_BROWSER opts out for headless/SSH sessions.                if (io_mod.getenv("FX_NO_OPEN_BROWSER") == null) try openSignInBrowser(app);            }        }         fn openSignInBrowser(app: *App) !void {            const url = (try app.auth.signInBrowserUrlAlloc(app.alloc)) orelse return;            defer app.alloc.free(url);            if (!try app.urlOpener().open(app.alloc, url)) {                debug_trace.logf("auth", "login browser launcher failed", .{});            }        }         pub fn selectCredentialSource(app: *App, source: credentials.Source) !bool {            const changed = (try app.auth.selectSource(app.alloc, source)) orelse return false;            applyCredentialChange(app, changed);            return true;        }         fn refreshFxLoginCredentialIfNeeded(app: *App) !void {            if (!try app.auth.refreshFxLoginIfNeeded(app.alloc)) return;            reconcileGatewayCredential(app);            if (app.auth.modelCatalogAccess().authorizationCredential() == null) return;            app.model_cache.reset();

Lines 1–500 of 1217.