experiments in a post-browser web
1# Peek Core API Reference
2
3The `window.app` API is automatically injected into all `peek://` pages. This API provides access to window management, data storage, messaging, and shortcuts.
4
5## Context Detection
6
7```javascript
8// Check if running in peek:// context
9if (window.app) {
10 // API available
11}
12
13// Source address of current page
14const source = window.location.toString();
15
16// Context types:
17// - peek://app/... Core application pages
18// - peek://ext/{id}/... Extension pages
19```
20
21## Window Management
22
23### `window.app.window.open(url, options)`
24
25Open a new window.
26
27```javascript
28const result = await window.app.window.open('peek://app/settings/settings.html', {
29 key: 'settings', // Reuse window with same key
30 width: 900, // Window width
31 height: 650, // Window height
32 x: 100, // X position
33 y: 100, // Y position
34 title: 'Settings', // Window title
35 modal: true, // Modal behavior
36 transparent: false, // Transparent background
37 decorations: true, // Window decorations
38 alwaysOnTop: false, // Stay on top
39 visible: true, // Initially visible
40 resizable: true, // Allow resize
41 keepLive: false // Keep window alive when closed
42});
43// Returns: { success: true, id: 'window_label' }
44```
45
46### `window.app.window.close(id?)`
47
48Close a window. If no id, closes current window.
49
50```javascript
51await window.app.window.close(); // Close current
52await window.app.window.close('settings'); // Close by id
53await window.app.window.close({ id: 'settings' }); // Object form
54```
55
56### `window.app.window.hide(id?)` / `window.app.window.show(id?)`
57
58Toggle window visibility.
59
60```javascript
61await window.app.window.hide('main');
62await window.app.window.show('main');
63```
64
65### `window.app.window.focus(id?)`
66
67Bring window to front and focus it.
68
69```javascript
70await window.app.window.focus('settings');
71```
72
73### `window.app.window.list()`
74
75List all open windows.
76
77```javascript
78const result = await window.app.window.list();
79// Returns: {
80// success: true,
81// data: [{
82// id: 'main',
83// label: 'main',
84// url: 'peek://app/background.html',
85// source: 'peek://app/background.html',
86// visible: false,
87// focused: false
88// }, ...]
89// }
90```
91
92### `window.app.window.exists(id)`
93
94Check if a window exists.
95
96```javascript
97const result = await window.app.window.exists('settings');
98// Returns: { success: true, data: true }
99```
100
101## Datastore
102
103All datastore methods return `{ success: boolean, data?: any, error?: string }`.
104
105### Addresses
106
107```javascript
108// Add a new address
109const result = await window.app.datastore.addAddress('https://example.com', {
110 title: 'Example',
111 favicon: 'https://example.com/favicon.ico'
112});
113// Returns: { success: true, data: { id: 'addr_123', ... } }
114
115// Get address by ID
116const addr = await window.app.datastore.getAddress('addr_123');
117
118// Update address
119await window.app.datastore.updateAddress('addr_123', {
120 title: 'New Title'
121});
122
123// Query addresses
124const results = await window.app.datastore.queryAddresses({
125 uri: 'example.com', // Partial match
126 limit: 10,
127 offset: 0
128});
129```
130
131### Visits
132
133```javascript
134// Add a visit
135await window.app.datastore.addVisit('addr_123', {
136 referrer: 'addr_456'
137});
138
139// Query visits
140const visits = await window.app.datastore.queryVisits({
141 addressId: 'addr_123',
142 limit: 50
143});
144```
145
146### Tags
147
148```javascript
149// Get or create a tag
150const tag = await window.app.datastore.getOrCreateTag('important');
151// Returns: { success: true, data: { id: 'tag_123', name: 'important' } }
152
153// Tag an address
154await window.app.datastore.tagAddress('addr_123', 'tag_123');
155
156// Untag an address
157await window.app.datastore.untagAddress('addr_123', 'tag_123');
158
159// Get tags for an address
160const tags = await window.app.datastore.getAddressTags('addr_123');
161```
162
163### Generic Table Access
164
165```javascript
166// Get all rows from a table
167const table = await window.app.datastore.getTable('extensions');
168// Returns: { success: true, data: { row_id: { ... }, ... } }
169
170// Set a row
171await window.app.datastore.setRow('extensions', 'my-ext', {
172 name: 'My Extension',
173 enabled: true
174});
175```
176
177### Statistics
178
179```javascript
180const stats = await window.app.datastore.getStats();
181// Returns: { success: true, data: {
182// addresses: 150,
183// visits: 1200,
184// tags: 25
185// }}
186```
187
188## PubSub Messaging
189
190Cross-window communication via publish/subscribe.
191
192### Scopes
193
194```javascript
195window.app.scopes = {
196 SYSTEM: 1, // System messages
197 SELF: 2, // Same source only
198 GLOBAL: 3 // All windows
199};
200```
201
202### `window.app.publish(topic, message, scope)`
203
204Publish a message.
205
206```javascript
207window.app.publish('settings:changed', { theme: 'dark' }, window.app.scopes.GLOBAL);
208```
209
210### `window.app.subscribe(topic, callback, scope)`
211
212Subscribe to messages.
213
214```javascript
215window.app.subscribe('settings:changed', (msg) => {
216 console.log('Settings changed:', msg.data);
217}, window.app.scopes.GLOBAL);
218```
219
220## Keyboard Shortcuts
221
222### `window.app.shortcuts.register(shortcut, callback, options)`
223
224Register a keyboard shortcut.
225
226```javascript
227// Local shortcut (only when app focused)
228window.app.shortcuts.register('Command+K', () => {
229 console.log('Command+K pressed');
230});
231
232// Global shortcut (works even when app not focused)
233window.app.shortcuts.register('Option+Space', () => {
234 console.log('Global shortcut triggered');
235}, { global: true });
236```
237
238**Shortcut format:**
239- Modifiers: `Command`, `Control`, `Alt`, `Option`, `Shift`, `CommandOrControl`
240- Keys: `A-Z`, `0-9`, `F1-F12`, `Space`, `Enter`, `Escape`, `ArrowUp`, etc.
241- Examples: `Command+Shift+P`, `Alt+1`, `Option+ArrowDown`
242
243### `window.app.shortcuts.unregister(shortcut, options)`
244
245Unregister a shortcut.
246
247```javascript
248window.app.shortcuts.unregister('Command+K');
249window.app.shortcuts.unregister('Option+Space', { global: true });
250```
251
252## Commands (Command Palette)
253
254Register commands that appear in the command palette.
255
256### `window.app.commands.register(command)`
257
258```javascript
259window.app.commands.register({
260 name: 'my-extension:do-thing',
261 description: 'Do the thing',
262 execute: () => {
263 console.log('Doing the thing');
264 }
265});
266```
267
268### `window.app.commands.unregister(name)`
269
270```javascript
271window.app.commands.unregister('my-extension:do-thing');
272```
273
274### `window.app.commands.getAll()`
275
276```javascript
277const commands = await window.app.commands.getAll();
278```
279
280## Escape Handling
281
282Handle the ESC key to prevent window from closing.
283
284```javascript
285window.app.escape.onEscape(() => {
286 if (hasUnsavedChanges) {
287 showConfirmDialog();
288 return { handled: true }; // Prevent close
289 }
290 return { handled: false }; // Allow close
291});
292```
293
294## Logging
295
296Log messages to the backend console.
297
298```javascript
299window.app.log('Something happened', { detail: 'value' });
300// Output in terminal: [peek://app/mypage.html] Something happened { detail: 'value' }
301```
302
303## Debug Mode
304
305```javascript
306if (window.app.debug) {
307 console.log('Debug mode enabled');
308}
309
310// Debug levels
311window.app.debugLevels = { BASIC: 1, FIRST_RUN: 2 };
312window.app.debugLevel; // Current level
313```
314
315## Extensions API
316
317Only available in core app pages (`peek://app/...`).
318
319```javascript
320// Check permission
321if (window.app.extensions._hasPermission()) {
322 const exts = await window.app.extensions.list();
323}
324```
325
326## Settings API
327
328Only available in extension pages (`peek://ext/{id}/...`).
329
330```javascript
331// Get all settings
332const settings = await window.app.settings.get();
333
334// Set all settings
335await window.app.settings.set({ theme: 'dark' });
336
337// Get/set individual keys
338const theme = await window.app.settings.getKey('theme');
339await window.app.settings.setKey('theme', 'light');
340```
341
342## Response Format
343
344All async API methods return a consistent response format:
345
346```javascript
347{
348 success: true, // Operation succeeded
349 data: any, // Result data (if applicable)
350 error: string // Error message (if success: false)
351}
352```
353
354Always check `success` before using `data`:
355
356```javascript
357const result = await window.app.datastore.getAddress(id);
358if (result.success) {
359 console.log(result.data);
360} else {
361 console.error(result.error);
362}
363```