Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ vi.mock('../../../services/api', () => ({
PORTOS_APP_ID: 'portos-default',
getAppRepositorySources: vi.fn(),
syncAppRepositoryFork: vi.fn(),
pullAndUpdateApp: vi.fn(),
getPreferredSelfRestartOrigin: vi.fn(),
handleSelfRestart: vi.fn(),
}));
vi.mock('../../../hooks/useAppOperation', () => ({
Expand Down Expand Up @@ -90,7 +88,6 @@ beforeEach(() => {
});
api.getAppRepositorySources.mockResolvedValue(canonicalStatus());
api.syncAppRepositoryFork.mockResolvedValue({ synced: true, alreadyUpToDate: false });
api.pullAndUpdateApp.mockResolvedValue({ success: true });
});

afterEach(() => cleanup());
Expand Down Expand Up @@ -147,7 +144,7 @@ describe('managed app repository sources', () => {

fireEvent.click(screen.getByRole('button', { name: 'Sync fork' }));
await waitFor(() => expect(api.syncAppRepositoryFork).toHaveBeenCalledWith('app-example', { silent: true }));
expect(api.pullAndUpdateApp).not.toHaveBeenCalled();
expect(useAppOperation.mock.results[0].value.startUpdate).not.toHaveBeenCalled();
});

it('confirms that one managed update syncs the fork and updates every checkout', async () => {
Expand Down
17 changes: 0 additions & 17 deletions client/src/services/apiApps.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import toast from '../components/ui/Toast';
import { request, API_BASE } from './apiCore.js';
import { getNetworkExposure } from './apiSystem.js';

// Apps
export const getApps = (options) => request('/apps', options);
Expand Down Expand Up @@ -163,22 +162,6 @@ export const openAppFolder = (id) => request(`/apps/${id}/open-folder`, { method
// comes back as a real error instead of a silent `xcode://` no-op.
export const openAppInXcode = (id) => request(`/apps/${id}/open-xcode`, { method: 'POST' });
export const refreshAppConfig = (id) => request(`/apps/${id}/refresh-config`, { method: 'POST' });
// Capture the server's currently trusted origin before a PortOS restart. A
// Vite dev UI on :5554 must not be reused after the server comes back when a
// Tailscale HTTPS origin is available. The read is best-effort so an instance
// without trusted HTTPS keeps the existing same-origin recovery behavior.
export const getPreferredSelfRestartOrigin = async () => {
const exposure = await getNetworkExposure({ silent: true }).catch(() => null);
const trustedUrl = exposure?.setup?.trustedUrl;
return typeof trustedUrl === 'string' && trustedUrl.startsWith('https://')
? trustedUrl
: null;
};
export const pullAndUpdateApp = (id, body = {}, options = {}) => request(`/apps/${id}/update`, {
method: 'POST',
body: JSON.stringify(body),
...options,
});
// `options` lets a caller suppress request()'s auto-toast with `{ silent: true }`
// when it already renders its own error UI.
export const buildApp = (id, options = {}) => request(`/apps/${id}/build`, { method: 'POST', ...options });
Expand Down
27 changes: 1 addition & 26 deletions client/src/services/apiApps.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,12 @@ vi.mock('../components/ui/Toast', () => ({
default: { loading: vi.fn(), success: vi.fn(), error: vi.fn() },
}));

const mockNetwork = vi.hoisted(() => ({ getNetworkExposure: vi.fn() }));
vi.mock('./apiSystem.js', () => mockNetwork);

import toast from '../components/ui/Toast';
import { getPreferredSelfRestartOrigin, handleSelfRestart } from './apiApps';
import { handleSelfRestart } from './apiApps';

beforeEach(() => {
vi.useFakeTimers();
vi.clearAllMocks();
mockNetwork.getNetworkExposure.mockResolvedValue({ setup: { trustedUrl: null } });
});

afterEach(() => {
Expand Down Expand Up @@ -58,24 +54,3 @@ describe('handleSelfRestart', () => {
);
});
});

describe('getPreferredSelfRestartOrigin', () => {
it('returns the active trusted origin supplied by network exposure', async () => {
mockNetwork.getNetworkExposure.mockResolvedValueOnce({
setup: { trustedUrl: 'https://host-alpha.example-tailnet.ts.net:5555' },
});

await expect(getPreferredSelfRestartOrigin()).resolves.toBe(
'https://host-alpha.example-tailnet.ts.net:5555',
);
expect(mockNetwork.getNetworkExposure).toHaveBeenCalledWith({ silent: true });
});

it('does not turn an unavailable or non-HTTPS setup value into a restart target', async () => {
mockNetwork.getNetworkExposure.mockResolvedValueOnce({
setup: { pendingTrustedUrl: 'https://host-alpha.example-tailnet.ts.net:5555', trustedUrl: null },
});

await expect(getPreferredSelfRestartOrigin()).resolves.toBeNull();
});
});