diff --git a/cmd/browsers.go b/cmd/browsers.go index 6d39958..7457d51 100644 --- a/cmd/browsers.go +++ b/cmd/browsers.go @@ -35,7 +35,6 @@ type BrowsersService interface { List(ctx context.Context, query kernel.BrowserListParams, opts ...option.RequestOption) (res *pagination.OffsetPagination[kernel.BrowserListResponse], err error) New(ctx context.Context, body kernel.BrowserNewParams, opts ...option.RequestOption) (res *kernel.BrowserNewResponse, err error) Update(ctx context.Context, id string, body kernel.BrowserUpdateParams, opts ...option.RequestOption) (res *kernel.BrowserUpdateResponse, err error) - Delete(ctx context.Context, body kernel.BrowserDeleteParams, opts ...option.RequestOption) (err error) DeleteByID(ctx context.Context, id string, opts ...option.RequestOption) (err error) HTTPClient(id string, opts ...option.RequestOption) (*http.Client, error) LoadExtensions(ctx context.Context, id string, body kernel.BrowserLoadExtensionsParams, opts ...option.RequestOption) (err error) @@ -175,7 +174,6 @@ func parseViewport(viewport string) (width, height, refreshRate int64, err error // Inputs for each command type BrowsersCreateInput struct { - PersistenceID string TimeoutSeconds int Stealth BoolFlag Headless BoolFlag @@ -291,7 +289,7 @@ func (b BrowsersCmd) List(ctx context.Context, in BrowsersListInput) error { } // Prepare table data - headers := []string{"Browser ID", "Created At", "Persistent ID", "Profile", "Pool", "CDP WS URL", "Live View URL"} + headers := []string{"Browser ID", "Created At", "Profile", "Pool", "CDP WS URL", "Live View URL"} showDeletedAt := in.IncludeDeleted || in.Status == "deleted" || in.Status == "all" if showDeletedAt { headers = append(headers, "Deleted At") @@ -299,11 +297,6 @@ func (b BrowsersCmd) List(ctx context.Context, in BrowsersListInput) error { tableData := pterm.TableData{headers} for _, browser := range browsers { - persistentID := "-" - if browser.Persistence.ID != "" { - persistentID = browser.Persistence.ID - } - profile := "-" if browser.Profile.Name != "" { profile = browser.Profile.Name @@ -321,7 +314,6 @@ func (b BrowsersCmd) List(ctx context.Context, in BrowsersListInput) error { row := []string{ browser.SessionID, util.FormatLocal(browser.CreatedAt), - persistentID, profile, pool, truncateURL(browser.CdpWsURL, 50), @@ -355,9 +347,6 @@ func (b BrowsersCmd) Create(ctx context.Context, in BrowsersCreateInput) error { pterm.Info.Println("Creating browser session...") } params := kernel.BrowserNewParams{} - if in.PersistenceID != "" { - params.Persistence = kernel.BrowserPersistenceParam{ID: in.PersistenceID} - } if in.TimeoutSeconds > 0 { params.TimeoutSeconds = kernel.Opt(int64(in.TimeoutSeconds)) } @@ -442,17 +431,17 @@ func (b BrowsersCmd) Create(ctx context.Context, in BrowsersCreateInput) error { return util.PrintPrettyJSON(browser) } - printBrowserSessionResult(browser.SessionID, browser.CdpWsURL, browser.BrowserLiveViewURL, browser.Persistence, browser.Profile, browser.StartURL) + printBrowserSessionResult(browser.SessionID, browser.CdpWsURL, browser.BrowserLiveViewURL, browser.Profile, browser.StartURL) return nil } -func printBrowserSessionResult(sessionID, cdpURL, liveViewURL string, persistence kernel.BrowserPersistence, profile kernel.Profile, startURL string) { - tableData := buildBrowserTableData(sessionID, cdpURL, liveViewURL, persistence, profile, startURL) +func printBrowserSessionResult(sessionID, cdpURL, liveViewURL string, profile kernel.Profile, startURL string) { + tableData := buildBrowserTableData(sessionID, cdpURL, liveViewURL, profile, startURL) PrintTableNoPad(tableData, true) } // buildBrowserTableData creates a base table with common browser session fields. -func buildBrowserTableData(sessionID, cdpURL, liveViewURL string, persistence kernel.BrowserPersistence, profile kernel.Profile, startURL string) pterm.TableData { +func buildBrowserTableData(sessionID, cdpURL, liveViewURL string, profile kernel.Profile, startURL string) pterm.TableData { tableData := pterm.TableData{ {"Property", "Value"}, {"Session ID", sessionID}, @@ -461,9 +450,6 @@ func buildBrowserTableData(sessionID, cdpURL, liveViewURL string, persistence ke if liveViewURL != "" { tableData = append(tableData, []string{"Live View URL", liveViewURL}) } - if persistence.ID != "" { - tableData = append(tableData, []string{"Persistent ID", persistence.ID}) - } if profile.ID != "" || profile.Name != "" { profVal := profile.Name if profVal == "" { @@ -478,29 +464,10 @@ func buildBrowserTableData(sessionID, cdpURL, liveViewURL string, persistence ke } func (b BrowsersCmd) Delete(ctx context.Context, in BrowsersDeleteInput) error { - // Try both deletion modes without confirmation // Treat not found as a success (idempotent delete) - var nonNotFoundErrors []error - - // Attempt by session ID - if err := b.browsers.DeleteByID(ctx, in.Identifier); err != nil { - if !util.IsNotFound(err) { - nonNotFoundErrors = append(nonNotFoundErrors, err) - } - } - - // Attempt by persistent ID (backward compatibility) - if err := b.browsers.Delete(ctx, kernel.BrowserDeleteParams{PersistentID: in.Identifier}); err != nil { - if !util.IsNotFound(err) { - nonNotFoundErrors = append(nonNotFoundErrors, err) - } - } - - if len(nonNotFoundErrors) >= 2 { - // Both failed with meaningful errors; report one - return util.CleanedUpSdkError{Err: nonNotFoundErrors[0]} + if err := b.browsers.DeleteByID(ctx, in.Identifier); err != nil && !util.IsNotFound(err) { + return util.CleanedUpSdkError{Err: err} } - pterm.Success.Printf("Successfully deleted (or already absent) browser: %s\n", in.Identifier) return nil } @@ -562,7 +529,6 @@ func (b BrowsersCmd) Get(ctx context.Context, in BrowsersGetInput) error { browser.SessionID, browser.CdpWsURL, browser.BrowserLiveViewURL, - browser.Persistence, browser.Profile, browser.StartURL, ) @@ -2524,8 +2490,6 @@ func init() { // Add flags for create command browsersCreateCmd.Flags().StringP("output", "o", "", "Output format: json for raw API response") - browsersCreateCmd.Flags().StringP("persistent-id", "p", "", "[DEPRECATED] Use --timeout and profiles instead. Unique identifier for browser session persistence") - _ = browsersCreateCmd.Flags().MarkDeprecated("persistent-id", "use --timeout (up to 72 hours) and profiles instead") browsersCreateCmd.Flags().BoolP("stealth", "s", false, "Launch browser in stealth mode to avoid detection") browsersCreateCmd.Flags().BoolP("headless", "H", false, "Launch browser without GUI access") browsersCreateCmd.Flags().Bool("gpu", false, "Launch browser with hardware-accelerated GPU rendering") @@ -2595,10 +2559,6 @@ func runBrowsersCreate(cmd *cobra.Command, args []string) error { client := getKernelClient(cmd) // Get flag values - persistenceID, _ := cmd.Flags().GetString("persistent-id") - if persistenceID != "" { - pterm.Warning.Println("--persistent-id is deprecated. Use --timeout (up to 72 hours) and profiles instead.") - } stealthVal, _ := cmd.Flags().GetBool("stealth") headlessVal, _ := cmd.Flags().GetBool("headless") gpuVal, _ := cmd.Flags().GetBool("gpu") @@ -2689,7 +2649,7 @@ func runBrowsersCreate(cmd *cobra.Command, args []string) error { if output == "json" { return util.PrintPrettyJSON(resp) } - printBrowserSessionResult(resp.SessionID, resp.CdpWsURL, resp.BrowserLiveViewURL, resp.Persistence, resp.Profile, resp.StartURL) + printBrowserSessionResult(resp.SessionID, resp.CdpWsURL, resp.BrowserLiveViewURL, resp.Profile, resp.StartURL) return nil } @@ -2711,7 +2671,6 @@ func runBrowsersCreate(cmd *cobra.Command, args []string) error { } in := BrowsersCreateInput{ - PersistenceID: persistenceID, TimeoutSeconds: timeout, Stealth: BoolFlag{Set: cmd.Flags().Changed("stealth"), Value: stealthVal}, Headless: BoolFlag{Set: cmd.Flags().Changed("headless"), Value: headlessVal}, diff --git a/cmd/browsers_test.go b/cmd/browsers_test.go index da4ba05..36190f4 100644 --- a/cmd/browsers_test.go +++ b/cmd/browsers_test.go @@ -60,7 +60,6 @@ type FakeBrowsersService struct { ListFunc func(ctx context.Context, query kernel.BrowserListParams, opts ...option.RequestOption) (*pagination.OffsetPagination[kernel.BrowserListResponse], error) NewFunc func(ctx context.Context, body kernel.BrowserNewParams, opts ...option.RequestOption) (*kernel.BrowserNewResponse, error) UpdateFunc func(ctx context.Context, id string, body kernel.BrowserUpdateParams, opts ...option.RequestOption) (*kernel.BrowserUpdateResponse, error) - DeleteFunc func(ctx context.Context, body kernel.BrowserDeleteParams, opts ...option.RequestOption) error DeleteByIDFunc func(ctx context.Context, id string, opts ...option.RequestOption) error HTTPClientFunc func(id string, opts ...option.RequestOption) (*http.Client, error) LoadExtensionsFunc func(ctx context.Context, id string, body kernel.BrowserLoadExtensionsParams, opts ...option.RequestOption) error @@ -94,13 +93,6 @@ func (f *FakeBrowsersService) Update(ctx context.Context, id string, body kernel return &kernel.BrowserUpdateResponse{}, nil } -func (f *FakeBrowsersService) Delete(ctx context.Context, body kernel.BrowserDeleteParams, opts ...option.RequestOption) error { - if f.DeleteFunc != nil { - return f.DeleteFunc(ctx, body, opts...) - } - return nil -} - func (f *FakeBrowsersService) DeleteByID(ctx context.Context, id string, opts ...option.RequestOption) error { if f.DeleteByIDFunc != nil { return f.DeleteByIDFunc(ctx, id, opts...) @@ -400,14 +392,12 @@ func TestBrowsersList_PrintsTableWithRows(t *testing.T) { CdpWsURL: "ws://cdp-1", BrowserLiveViewURL: "http://view-1", CreatedAt: created, - Persistence: kernel.BrowserPersistence{ID: "pid-1"}, }, { SessionID: "sess-2", CdpWsURL: "ws://cdp-2", BrowserLiveViewURL: "", CreatedAt: created, - Persistence: kernel.BrowserPersistence{ID: ""}, }, } @@ -422,7 +412,6 @@ func TestBrowsersList_PrintsTableWithRows(t *testing.T) { out := outBuf.String() assert.Contains(t, out, "sess-1") assert.Contains(t, out, "sess-2") - assert.Contains(t, out, "pid-1") } func TestBrowsersList_PrintsErrorOnFailure(t *testing.T) { @@ -469,7 +458,6 @@ func TestBrowsersCreate_PrintsResponse(t *testing.T) { SessionID: "sess-new", CdpWsURL: "ws://cdp-new", BrowserLiveViewURL: "http://view-new", - Persistence: kernel.BrowserPersistence{ID: "pid-new"}, } return resp, nil }, @@ -477,7 +465,6 @@ func TestBrowsersCreate_PrintsResponse(t *testing.T) { b := BrowsersCmd{browsers: fake} in := BrowsersCreateInput{ - PersistenceID: "pid-new", TimeoutSeconds: 120, Stealth: BoolFlag{Set: true, Value: true}, Headless: BoolFlag{Set: true, Value: false}, @@ -491,8 +478,6 @@ func TestBrowsersCreate_PrintsResponse(t *testing.T) { assert.Contains(t, out, "ws://cdp-new") assert.Contains(t, out, "Live View URL") assert.Contains(t, out, "http://view-new") - assert.Contains(t, out, "Persistent ID") - assert.Contains(t, out, "pid-new") } func TestBrowsersCreate_WithInvocationID(t *testing.T) { @@ -533,9 +518,6 @@ func TestBrowsersDelete_Success(t *testing.T) { setupStdoutCapture(t) fake := &FakeBrowsersService{ - DeleteFunc: func(ctx context.Context, body kernel.BrowserDeleteParams, opts ...option.RequestOption) error { - return nil - }, DeleteByIDFunc: func(ctx context.Context, id string, opts ...option.RequestOption) error { return nil }, @@ -551,19 +533,15 @@ func TestBrowsersDelete_Failure(t *testing.T) { setupStdoutCapture(t) fake := &FakeBrowsersService{ - DeleteFunc: func(ctx context.Context, body kernel.BrowserDeleteParams, opts ...option.RequestOption) error { - return errors.New("left failed") - }, DeleteByIDFunc: func(ctx context.Context, id string, opts ...option.RequestOption) error { - return errors.New("right failed") + return errors.New("delete failed") }, } b := BrowsersCmd{browsers: fake} err := b.Delete(context.Background(), BrowsersDeleteInput{Identifier: "any"}) assert.Error(t, err) - errMsg := err.Error() - assert.True(t, strings.Contains(errMsg, "right failed") || strings.Contains(errMsg, "left failed"), "expected error message to contain either 'right failed' or 'left failed', got: %s", errMsg) + assert.Contains(t, err.Error(), "delete failed") } func TestBrowsersView_ByID_PrintsURL(t *testing.T) { @@ -656,7 +634,6 @@ func TestBrowsersGet_PrintsDetails(t *testing.T) { Stealth: true, KioskMode: false, Viewport: shared.BrowserViewport{Width: 1920, Height: 1080, RefreshRate: 25}, - Persistence: kernel.BrowserPersistence{ID: "persist-id"}, Profile: kernel.Profile{ID: "prof-id", Name: "my-profile"}, ProxyID: "proxy-123", }, nil @@ -673,7 +650,6 @@ func TestBrowsersGet_PrintsDetails(t *testing.T) { assert.Contains(t, out, "false") // Headless assert.Contains(t, out, "true") // Stealth assert.Contains(t, out, "1920x1080@25") - assert.Contains(t, out, "persist-id") assert.Contains(t, out, "my-profile") assert.Contains(t, out, "proxy-123") } diff --git a/cmd/projects.go b/cmd/projects.go index 327cf81..a223165 100644 --- a/cmd/projects.go +++ b/cmd/projects.go @@ -57,7 +57,6 @@ type ProjectsLimitsGetInput struct { type ProjectsLimitsSetInput struct { Identifier string MaxConcurrentSessions Int64Flag - MaxPersistentSessions Int64Flag MaxConcurrentInvocations Int64Flag MaxPooledSessions Int64Flag Output string @@ -193,12 +192,6 @@ func (c ProjectsCmd) LimitsSet(ctx context.Context, in ProjectsLimitsSetInput) e } inner.MaxConcurrentSessions = param.NewOpt(in.MaxConcurrentSessions.Value) } - if in.MaxPersistentSessions.Set { - if in.MaxPersistentSessions.Value < 0 { - return fmt.Errorf("--max-persistent-sessions must be non-negative (got %d); use 0 to remove the cap", in.MaxPersistentSessions.Value) - } - inner.MaxPersistentSessions = param.NewOpt(in.MaxPersistentSessions.Value) - } if in.MaxConcurrentInvocations.Set { if in.MaxConcurrentInvocations.Value < 0 { return fmt.Errorf("--max-concurrent-invocations must be non-negative (got %d); use 0 to remove the cap", in.MaxConcurrentInvocations.Value) @@ -243,7 +236,6 @@ func renderProjectLimits(limits *kernel.ProjectLimits) { rows := pterm.TableData{ {"Limit", "Value"}, {"Max Concurrent Sessions", formatProjectLimitValue(limits.MaxConcurrentSessions, limits.JSON.MaxConcurrentSessions)}, - {"Max Persistent Sessions", formatProjectLimitValue(limits.MaxPersistentSessions, limits.JSON.MaxPersistentSessions)}, {"Max Concurrent Invocations", formatProjectLimitValue(limits.MaxConcurrentInvocations, limits.JSON.MaxConcurrentInvocations)}, {"Max Pooled Sessions", formatProjectLimitValue(limits.MaxPooledSessions, limits.JSON.MaxPooledSessions)}, } @@ -297,7 +289,6 @@ func runProjectsLimitsGet(cmd *cobra.Command, args []string) error { func runProjectsLimitsSet(cmd *cobra.Command, args []string) error { c := getProjectsHandler(cmd) maxConcurrentSessions, _ := cmd.Flags().GetInt64("max-concurrent-sessions") - maxPersistentSessions, _ := cmd.Flags().GetInt64("max-persistent-sessions") maxConcurrentInvocations, _ := cmd.Flags().GetInt64("max-concurrent-invocations") maxPooledSessions, _ := cmd.Flags().GetInt64("max-pooled-sessions") output, _ := cmd.Flags().GetString("output") @@ -308,10 +299,6 @@ func runProjectsLimitsSet(cmd *cobra.Command, args []string) error { Set: cmd.Flags().Changed("max-concurrent-sessions"), Value: maxConcurrentSessions, }, - MaxPersistentSessions: Int64Flag{ - Set: cmd.Flags().Changed("max-persistent-sessions"), - Value: maxPersistentSessions, - }, MaxConcurrentInvocations: Int64Flag{ Set: cmd.Flags().Changed("max-concurrent-invocations"), Value: maxConcurrentInvocations, @@ -330,7 +317,6 @@ func addProjectsLimitsOutputFlag(cmd *cobra.Command) { func addProjectsLimitsSetFlags(cmd *cobra.Command) { cmd.Flags().Int64("max-concurrent-sessions", 0, "Maximum concurrent browser sessions (0 to remove cap)") - cmd.Flags().Int64("max-persistent-sessions", 0, "Maximum persistent browser sessions (0 to remove cap)") cmd.Flags().Int64("max-concurrent-invocations", 0, "Maximum concurrent app invocations (0 to remove cap)") cmd.Flags().Int64("max-pooled-sessions", 0, "Maximum pooled sessions capacity (0 to remove cap)") addProjectsLimitsOutputFlag(cmd) diff --git a/cmd/projects_test.go b/cmd/projects_test.go index 7ae7347..33ae60d 100644 --- a/cmd/projects_test.go +++ b/cmd/projects_test.go @@ -100,7 +100,6 @@ func TestProjectsLimitsGet_DefaultOutput(t *testing.T) { } limits.JSON.MaxConcurrentSessions = respjson.NewField("10") limits.JSON.MaxConcurrentInvocations = respjson.NewField("5") - limits.JSON.MaxPersistentSessions = respjson.NewField(respjson.Null) fakeProjects := &FakeProjectsService{} fakeLimits := &FakeProjectLimitsService{