1
>
/*---------------------------------------------------------------------------------------------
browserHistory.ts
2
>
* Copyright (c) Microsoft Corporation. All rights reserved.
3
>
* Licensed under the MIT License. See License.txt in the project root for license information.
4
>
*--------------------------------------------------------------------------------------------*/
5
>
6
>
import { Emitter, Event } from '../../../base/common/event.js';
7
>
import { StringSHA1 } from '../../../base/common/hash.js';
8
>
import { Disposable } from '../../../base/common/lifecycle.js';
9
>
10
>
/**
11
>
* On-disk shape of a single history entry.
12
>
* BACKWARDS COMPATIBILE. When evolving this interface, ensure older versions can still be handled gracefully.
13
>
*/
14
>
export interface ISerializedBrowserHistoryEntry {
15
>
readonly id: number;
16
>
readonly url: string;
17
>
/** Epoch ms when the entry was most recently visited. */
18
>
readonly time: number;
19
>
readonly title: string;
20
>
/** Content hash key into the sibling favicons map. */
21
>
readonly icon?: string;
22
>
/**
23
>
* Set when the navigation was initiated by the user (typing in the URL
24
>
* bar, picking a suggestion, opening a new tab with a URL) rather than by
25
>
* page script or link clicks. Always omitted when false to keep entries
26
>
* small.
27
>
*/
28
>
readonly explicit?: true;
29
>
}
30
>
31
>
/**
32
>
* In-memory representation of a history entry. Currently identical to the
33
>
* on-disk shape; the split exists so future in-memory-only fields can be
34
>
* added here without changing the wire format.
35
>
*/
36
>
export interface IBrowserHistoryEntry extends ISerializedBrowserHistoryEntry { }
37
>
38
>
export interface IBrowserHistoryUpdate {
39
>
/** URL may be updated e.g. during a redirect or in-page navigation. */
40
>
readonly url?: string;
41
>
readonly title?: string;
42
>
/** Favicon data URI; hashed and deduped against the sibling favicons store. Pass `null` to explicitly clear. */
43
>
readonly favicon?: string | null;
44
>
}
45
>
46
>
/**
47
>
* Handle returned by {@link BrowserHistoryStore.add}. `update` and `delete`
48
>
* are no-ops once the underlying entry has been evicted.
49
>
*/
50
>
export interface IBrowserHistoryItemHandle {
51
>
readonly id: number;
52
>
update(patch: IBrowserHistoryUpdate): void;
53
>
delete(): void;
54
>
}
55
>
56
>
/** Returned by {@link BrowserHistoryStore.add} when the store is disabled (max entries = 0). */
57
>
const NOOP_HANDLE: IBrowserHistoryItemHandle = Object.freeze({
58
>
id: -1,
59
>
update: () => { },
60
>
delete: () => { },
61
>
});
62
>
63
>
/**
64
>
* On-disk shape of an entries snapshot. See {@link ISerializedBrowserHistoryEntry}
65
>
* for the backwards-compatibility rules; the same constraints apply here.
66
>
*/
67
>
export interface ISerializedBrowserHistoryEntriesSnapshot {
68
>
readonly items: readonly ISerializedBrowserHistoryEntry[];
69
>
}
70
>
71
>
/**
72
>
* On-disk shape of a favicons snapshot. See {@link ISerializedBrowserHistoryEntry}
73
>
* for the backwards-compatibility rules; the same constraints apply here.
74
>
*/
75
>
export interface ISerializedBrowserFaviconsSnapshot {
76
>
/** Map from content hash to data URI. */
77
>
readonly map: Readonly<Record<string, string>>;
78
>
}
79
>
80
>
const DEFAULT_MAX_ENTRIES = 200;
81
>
82
>
export class BrowserHistoryEntriesStore extends Disposable {
83
>
84
>
private _nextId: number = 1;
85
>
private _items: IBrowserHistoryEntry[] = [];
86
>
private _maxEntries: number;
87
>
88
>
private readonly _onDidChange = this._register(new Emitter<void>());
89
>
readonly onDidChange: Event<void> = this._onDidChange.event;
90
>
91
>
constructor(maxEntries: number = DEFAULT_MAX_ENTRIES) {
92
super();
93
this._maxEntries = maxEntries;
94
}
96
>
get items(): readonly IBrowserHistoryEntry[] {
97
return this._items;
98
}
100
>
get maxEntries(): number {
101
return this._maxEntries;
102
}
104
>
setMaxEntries(max: number): void {
105
if (max < 0 || max === this._maxEntries) {
106
return;