@hyperframes/studio-server 0.8.72 → 0.8.74

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,6 +3,99 @@ import { RegistryItem } from '@hyperframes/core';
3
3
  import { CanvasResolution } from '@hyperframes/parsers';
4
4
  import { MediaCodecProbeCache, HtmlSourceLike } from './helpers/mediaCodecMap.js';
5
5
 
6
+ interface HistoryWho {
7
+ kind: "person" | "agent" | "outside";
8
+ /** Shown in the History list: "You", the agent's name, "Outside". */
9
+ name: string;
10
+ }
11
+ /** A file's sha256 before and after; null is "did not exist", so a create or delete undoes like any edit. */
12
+ interface HistoryFileChange {
13
+ path: string;
14
+ before: string | null;
15
+ after: string | null;
16
+ }
17
+ interface HistoryEntry {
18
+ id: string;
19
+ who: HistoryWho;
20
+ label: string;
21
+ startedAt: number;
22
+ endedAt: number;
23
+ files: HistoryFileChange[];
24
+ /** Set on an undo: the entry it reverted. Redo is undoing the undo. */
25
+ undoes?: string;
26
+ /** Set on a restore: the point (an entry id, or START) the files were made equal to. */
27
+ restoredTo?: string;
28
+ }
29
+ /** The point before the first kept entry. */
30
+ declare const START = "start";
31
+
32
+ interface ProjectHistoryOptions {
33
+ projectDir: string;
34
+ /** Kept outside the project, so nothing tidying the project can take its history with it. */
35
+ historyRoot: string;
36
+ now?: () => number;
37
+ /** Writes with no window open group into one entry until this long without another (default 2 s)... */
38
+ quietMs?: number;
39
+ /** ...or this long after the first (default 30 s). */
40
+ maxGroupMs?: number;
41
+ /** Past this many stored bytes the oldest unpinned entries are folded away (default 2 GB). */
42
+ budgetBytes?: number;
43
+ /** A sweep or commit that a watcher or timer started failed. */
44
+ onError?: (error: unknown) => void;
45
+ }
46
+ interface HistoryListItem extends HistoryEntry {
47
+ pinned: boolean;
48
+ undone: boolean;
49
+ }
50
+ type HistoryResult = {
51
+ ok: true;
52
+ entry: HistoryEntry | null;
53
+ } | {
54
+ ok: false;
55
+ conflict: {
56
+ files: string[];
57
+ newer: string[];
58
+ };
59
+ };
60
+ interface HistoryWindow {
61
+ readonly id: string;
62
+ /** Records everything written since the window opened as one entry (null when nothing changed); after the window
63
+ * ended by itself or by flush, returns the entry it became. */
64
+ close(): Promise<HistoryEntry | null>;
65
+ }
66
+ interface ProjectHistory {
67
+ readonly projectId: string;
68
+ /**
69
+ * Writes until close() are this writer's, as one entry whose id is the window's. A window with no write for
70
+ * `idleMs` (default maxGroupMs) ends by itself. ponytail: overlapping windows give a write to the newest.
71
+ */
72
+ beginWindow(who: HistoryWho, label: string, options?: {
73
+ idleMs?: number;
74
+ }): Promise<HistoryWindow>;
75
+ /** A watcher saw `path` change (project-relative or absolute). */
76
+ noteChange(path: string): void;
77
+ list(): HistoryListItem[];
78
+ /** Cmd+Z (back) and Cmd+Shift+Z (forward), whoever made the change. */
79
+ step(direction: "back" | "forward", who: HistoryWho): Promise<HistoryResult>;
80
+ /** A conflict (a file changed since) returns the choice; pass `mode` to take one. */
81
+ undo(id: string, options: {
82
+ who: HistoryWho;
83
+ mode?: "just-this" | "back-to-before";
84
+ }): Promise<HistoryResult>;
85
+ /** Makes the files equal what they were right after `point` (an entry id, or START). */
86
+ restore(point: string, who: HistoryWho): Promise<HistoryEntry | null>;
87
+ /** The files at `point` without writing anything: path to hash, read through readBlob. */
88
+ peek(point: string): Record<string, string> | null;
89
+ readBlob(hash: string): Promise<Buffer>;
90
+ pin(id: string, pinned: boolean): void;
91
+ onEntry(listener: (entry: HistoryEntry) => void): () => void;
92
+ /** Takes in every pending write and commits every open window and the outside group. */
93
+ flush(): Promise<void>;
94
+ close(): Promise<void>;
95
+ }
96
+ /** Opens a project's history: every write to its files becomes an entry that can be undone or restored. */
97
+ declare function openProjectHistory(options: ProjectHistoryOptions): Promise<ProjectHistory>;
98
+
6
99
  /** Resolved info about a single project. */
7
100
  interface ResolvedProject {
8
101
  id: string;
@@ -106,6 +199,11 @@ interface StudioApiAdapter {
106
199
  listProjects(): Promise<ResolvedProject[]> | ResolvedProject[];
107
200
  /** Resolve a project ID (or session ID) to its directory. Returns null if not found. */
108
201
  resolveProject(id: string): Promise<ResolvedProject | null> | ResolvedProject | null;
202
+ /**
203
+ * Optional: the project's history (openProjectHistory), one per project for the host's lifetime. Without it
204
+ * the history routes answer 404.
205
+ */
206
+ history?: (project: ResolvedProject) => Promise<ProjectHistory | null> | ProjectHistory | null;
109
207
  /** Bundle a project directory into a single HTML string. Returns null if unavailable. */
110
208
  bundle(projectDir: string): Promise<string | null>;
111
209
  /** Optional: cached signature for project files that should invalidate preview frame caches. */
@@ -283,4 +381,4 @@ declare function injectMediaCodecMapIntoHtml(html: string, projectDir: string, h
283
381
  */
284
382
  declare function injectMediaCodecMap(html: string, adapter: PreviewApiAdapter, projectDir: string, compSrcPath: string, probeCache: MediaCodecProbeCache): Promise<string>;
285
383
 
286
- export { type LintResult as L, type MediaProcessingJobState as M, type PreviewApiAdapter as P, type RenderJobState as R, type StudioApiAdapter as S, type ResolvedProject as a, type StudioSelectionResponse as b, type StudioSelectionSnapshot as c, type StudioSelectionTextField as d, injectMediaCodecMapIntoHtml as e, isAutoProxyEnabled as f, injectMediaCodecMap as i, proxyEtagSalt as p, resolvePreviewMediaCodecProbeCache as r };
384
+ export { type HistoryEntry as H, type LintResult as L, type MediaProcessingJobState as M, type PreviewApiAdapter as P, type RenderJobState as R, type StudioApiAdapter as S, START as a, type HistoryFileChange as b, type HistoryListItem as c, type HistoryResult as d, type HistoryWho as e, type HistoryWindow as f, type ProjectHistory as g, type ProjectHistoryOptions as h, type ResolvedProject as i, type StudioSelectionResponse as j, type StudioSelectionSnapshot as k, type StudioSelectionTextField as l, injectMediaCodecMap as m, injectMediaCodecMapIntoHtml as n, openProjectHistory as o, isAutoProxyEnabled as p, proxyEtagSalt as q, resolvePreviewMediaCodecProbeCache as r };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperframes/studio-server",
3
- "version": "0.8.72",
3
+ "version": "0.8.74",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/heygen-com/hyperframes",
@@ -64,8 +64,8 @@
64
64
  "linkedom": "^0.18.12",
65
65
  "postcss": "^8.5.8",
66
66
  "postcss-selector-parser": "^7.1.2",
67
- "@hyperframes/core": "0.8.72",
68
- "@hyperframes/parsers": "0.8.72"
67
+ "@hyperframes/parsers": "0.8.74",
68
+ "@hyperframes/core": "0.8.74"
69
69
  },
70
70
  "devDependencies": {
71
71
  "@types/node": "^25.0.10",