deio-scroll 1.0.0

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.
Files changed (205) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +21 -0
  3. package/dist/api/server.d.ts +3 -0
  4. package/dist/api/server.d.ts.map +1 -0
  5. package/dist/api/server.js +393 -0
  6. package/dist/api/server.js.map +1 -0
  7. package/dist/artifacts/store.d.ts +24 -0
  8. package/dist/artifacts/store.d.ts.map +1 -0
  9. package/dist/artifacts/store.js +43 -0
  10. package/dist/artifacts/store.js.map +1 -0
  11. package/dist/browser/componentInteraction.d.ts +24 -0
  12. package/dist/browser/componentInteraction.d.ts.map +1 -0
  13. package/dist/browser/componentInteraction.js +328 -0
  14. package/dist/browser/componentInteraction.js.map +1 -0
  15. package/dist/browser/composition.d.ts +42 -0
  16. package/dist/browser/composition.d.ts.map +1 -0
  17. package/dist/browser/composition.js +132 -0
  18. package/dist/browser/composition.js.map +1 -0
  19. package/dist/browser/cookies.d.ts +3 -0
  20. package/dist/browser/cookies.d.ts.map +1 -0
  21. package/dist/browser/cookies.js +20 -0
  22. package/dist/browser/cookies.js.map +1 -0
  23. package/dist/browser/curves.d.ts +4 -0
  24. package/dist/browser/curves.d.ts.map +1 -0
  25. package/dist/browser/curves.js +35 -0
  26. package/dist/browser/curves.js.map +1 -0
  27. package/dist/browser/detectScrollMode.d.ts +5 -0
  28. package/dist/browser/detectScrollMode.d.ts.map +1 -0
  29. package/dist/browser/detectScrollMode.js +61 -0
  30. package/dist/browser/detectScrollMode.js.map +1 -0
  31. package/dist/browser/directionGuardrails.d.ts +22 -0
  32. package/dist/browser/directionGuardrails.d.ts.map +1 -0
  33. package/dist/browser/directionGuardrails.js +99 -0
  34. package/dist/browser/directionGuardrails.js.map +1 -0
  35. package/dist/browser/goto.d.ts +9 -0
  36. package/dist/browser/goto.d.ts.map +1 -0
  37. package/dist/browser/goto.js +62 -0
  38. package/dist/browser/goto.js.map +1 -0
  39. package/dist/browser/hydrate.d.ts +8 -0
  40. package/dist/browser/hydrate.d.ts.map +1 -0
  41. package/dist/browser/hydrate.js +73 -0
  42. package/dist/browser/hydrate.js.map +1 -0
  43. package/dist/browser/mediaClock.d.ts +9 -0
  44. package/dist/browser/mediaClock.d.ts.map +1 -0
  45. package/dist/browser/mediaClock.js +86 -0
  46. package/dist/browser/mediaClock.js.map +1 -0
  47. package/dist/browser/motion.d.ts +21 -0
  48. package/dist/browser/motion.d.ts.map +1 -0
  49. package/dist/browser/motion.js +42 -0
  50. package/dist/browser/motion.js.map +1 -0
  51. package/dist/browser/networkPolicy.d.ts +11 -0
  52. package/dist/browser/networkPolicy.d.ts.map +1 -0
  53. package/dist/browser/networkPolicy.js +119 -0
  54. package/dist/browser/networkPolicy.js.map +1 -0
  55. package/dist/browser/prime.d.ts +3 -0
  56. package/dist/browser/prime.d.ts.map +1 -0
  57. package/dist/browser/prime.js +13 -0
  58. package/dist/browser/prime.js.map +1 -0
  59. package/dist/browser/sanitize.d.ts +3 -0
  60. package/dist/browser/sanitize.d.ts.map +1 -0
  61. package/dist/browser/sanitize.js +37 -0
  62. package/dist/browser/sanitize.js.map +1 -0
  63. package/dist/browser/scroll.d.ts +29 -0
  64. package/dist/browser/scroll.d.ts.map +1 -0
  65. package/dist/browser/scroll.js +420 -0
  66. package/dist/browser/scroll.js.map +1 -0
  67. package/dist/browser/scrollEasing.d.ts +5 -0
  68. package/dist/browser/scrollEasing.d.ts.map +1 -0
  69. package/dist/browser/scrollEasing.js +40 -0
  70. package/dist/browser/scrollEasing.js.map +1 -0
  71. package/dist/browser/scrollReadiness.d.ts +25 -0
  72. package/dist/browser/scrollReadiness.d.ts.map +1 -0
  73. package/dist/browser/scrollReadiness.js +105 -0
  74. package/dist/browser/scrollReadiness.js.map +1 -0
  75. package/dist/browser/urlGuard.d.ts +4 -0
  76. package/dist/browser/urlGuard.d.ts.map +1 -0
  77. package/dist/browser/urlGuard.js +22 -0
  78. package/dist/browser/urlGuard.js.map +1 -0
  79. package/dist/browser/virtualScroll.d.ts +19 -0
  80. package/dist/browser/virtualScroll.d.ts.map +1 -0
  81. package/dist/browser/virtualScroll.js +50 -0
  82. package/dist/browser/virtualScroll.js.map +1 -0
  83. package/dist/capture/detectMargins.d.ts +6 -0
  84. package/dist/capture/detectMargins.d.ts.map +1 -0
  85. package/dist/capture/detectMargins.js +145 -0
  86. package/dist/capture/detectMargins.js.map +1 -0
  87. package/dist/capture/frameRecorder.d.ts +29 -0
  88. package/dist/capture/frameRecorder.d.ts.map +1 -0
  89. package/dist/capture/frameRecorder.js +74 -0
  90. package/dist/capture/frameRecorder.js.map +1 -0
  91. package/dist/capture/stitchFrames.d.ts +9 -0
  92. package/dist/capture/stitchFrames.d.ts.map +1 -0
  93. package/dist/capture/stitchFrames.js +62 -0
  94. package/dist/capture/stitchFrames.js.map +1 -0
  95. package/dist/cli.d.ts +3 -0
  96. package/dist/cli.d.ts.map +1 -0
  97. package/dist/cli.js +329 -0
  98. package/dist/cli.js.map +1 -0
  99. package/dist/config/browserLaunch.d.ts +13 -0
  100. package/dist/config/browserLaunch.d.ts.map +1 -0
  101. package/dist/config/browserLaunch.js +63 -0
  102. package/dist/config/browserLaunch.js.map +1 -0
  103. package/dist/config/recordingProfile.d.ts +10 -0
  104. package/dist/config/recordingProfile.d.ts.map +1 -0
  105. package/dist/config/recordingProfile.js +25 -0
  106. package/dist/config/recordingProfile.js.map +1 -0
  107. package/dist/config/runtimeMode.d.ts +2 -0
  108. package/dist/config/runtimeMode.d.ts.map +1 -0
  109. package/dist/config/runtimeMode.js +4 -0
  110. package/dist/config/runtimeMode.js.map +1 -0
  111. package/dist/config/virtualScroll.d.ts +8 -0
  112. package/dist/config/virtualScroll.d.ts.map +1 -0
  113. package/dist/config/virtualScroll.js +19 -0
  114. package/dist/config/virtualScroll.js.map +1 -0
  115. package/dist/contracts.d.ts +157 -0
  116. package/dist/contracts.d.ts.map +1 -0
  117. package/dist/contracts.js +136 -0
  118. package/dist/contracts.js.map +1 -0
  119. package/dist/editor/compileVideo.d.ts +21 -0
  120. package/dist/editor/compileVideo.d.ts.map +1 -0
  121. package/dist/editor/compileVideo.js +104 -0
  122. package/dist/editor/compileVideo.js.map +1 -0
  123. package/dist/editor/composeComparison.d.ts +30 -0
  124. package/dist/editor/composeComparison.d.ts.map +1 -0
  125. package/dist/editor/composeComparison.js +315 -0
  126. package/dist/editor/composeComparison.js.map +1 -0
  127. package/dist/editor/composeResponsiveness.d.ts +19 -0
  128. package/dist/editor/composeResponsiveness.d.ts.map +1 -0
  129. package/dist/editor/composeResponsiveness.js +198 -0
  130. package/dist/editor/composeResponsiveness.js.map +1 -0
  131. package/dist/editor/frameVideo.d.ts +11 -0
  132. package/dist/editor/frameVideo.d.ts.map +1 -0
  133. package/dist/editor/frameVideo.js +181 -0
  134. package/dist/editor/frameVideo.js.map +1 -0
  135. package/dist/index.d.ts +3 -0
  136. package/dist/index.d.ts.map +1 -0
  137. package/dist/index.js +2 -0
  138. package/dist/index.js.map +1 -0
  139. package/dist/inspection/inspectWebsite.d.ts +21 -0
  140. package/dist/inspection/inspectWebsite.d.ts.map +1 -0
  141. package/dist/inspection/inspectWebsite.js +412 -0
  142. package/dist/inspection/inspectWebsite.js.map +1 -0
  143. package/dist/jobs/manager.d.ts +123 -0
  144. package/dist/jobs/manager.d.ts.map +1 -0
  145. package/dist/jobs/manager.js +378 -0
  146. package/dist/jobs/manager.js.map +1 -0
  147. package/dist/jobs/store.d.ts +150 -0
  148. package/dist/jobs/store.d.ts.map +1 -0
  149. package/dist/jobs/store.js +446 -0
  150. package/dist/jobs/store.js.map +1 -0
  151. package/dist/jobs/thumbnail.d.ts +2 -0
  152. package/dist/jobs/thumbnail.d.ts.map +1 -0
  153. package/dist/jobs/thumbnail.js +36 -0
  154. package/dist/jobs/thumbnail.js.map +1 -0
  155. package/dist/pipeline/processRecordingRequest.d.ts +4 -0
  156. package/dist/pipeline/processRecordingRequest.d.ts.map +1 -0
  157. package/dist/pipeline/processRecordingRequest.js +17 -0
  158. package/dist/pipeline/processRecordingRequest.js.map +1 -0
  159. package/dist/pipeline/recordComparison.d.ts +4 -0
  160. package/dist/pipeline/recordComparison.d.ts.map +1 -0
  161. package/dist/pipeline/recordComparison.js +99 -0
  162. package/dist/pipeline/recordComparison.js.map +1 -0
  163. package/dist/pipeline/recordResponsiveness.d.ts +4 -0
  164. package/dist/pipeline/recordResponsiveness.d.ts.map +1 -0
  165. package/dist/pipeline/recordResponsiveness.js +122 -0
  166. package/dist/pipeline/recordResponsiveness.js.map +1 -0
  167. package/dist/pipeline/recordWebsite.d.ts +11 -0
  168. package/dist/pipeline/recordWebsite.d.ts.map +1 -0
  169. package/dist/pipeline/recordWebsite.js +446 -0
  170. package/dist/pipeline/recordWebsite.js.map +1 -0
  171. package/dist/pipeline/styleRecording.d.ts +12 -0
  172. package/dist/pipeline/styleRecording.d.ts.map +1 -0
  173. package/dist/pipeline/styleRecording.js +59 -0
  174. package/dist/pipeline/styleRecording.js.map +1 -0
  175. package/dist/transcode/ffmpeg.d.ts +4 -0
  176. package/dist/transcode/ffmpeg.d.ts.map +1 -0
  177. package/dist/transcode/ffmpeg.js +62 -0
  178. package/dist/transcode/ffmpeg.js.map +1 -0
  179. package/dist/transcode/probe.d.ts +7 -0
  180. package/dist/transcode/probe.d.ts.map +1 -0
  181. package/dist/transcode/probe.js +91 -0
  182. package/dist/transcode/probe.js.map +1 -0
  183. package/dist/transcode/quality.d.ts +8 -0
  184. package/dist/transcode/quality.d.ts.map +1 -0
  185. package/dist/transcode/quality.js +13 -0
  186. package/dist/transcode/quality.js.map +1 -0
  187. package/dist/types.d.ts +302 -0
  188. package/dist/types.d.ts.map +1 -0
  189. package/dist/types.js +2 -0
  190. package/dist/types.js.map +1 -0
  191. package/dist/worker.d.ts +3 -0
  192. package/dist/worker.d.ts.map +1 -0
  193. package/dist/worker.js +22 -0
  194. package/dist/worker.js.map +1 -0
  195. package/package.json +63 -0
  196. package/public/assets/index-C63t4P1L.css +1 -0
  197. package/public/assets/index-Sfgf7dSH.js +9 -0
  198. package/public/background_presets/gray_noise_gradient.png +0 -0
  199. package/public/background_presets/paper_blue.png +0 -0
  200. package/public/background_presets/red_blocks_gradient.png +0 -0
  201. package/public/deio-scroll-mark.svg +12 -0
  202. package/public/favicon.svg +1 -0
  203. package/public/icons.svg +24 -0
  204. package/public/index.html +16 -0
  205. package/public/scrollizard-mark.png +0 -0
@@ -0,0 +1,150 @@
1
+ import type { RecordRequest, RecordingJobManifest, RecordingJobProgress } from "../types.js";
2
+ export declare const JOB_MANIFEST_FILENAME = "job.json";
3
+ export declare const LOCAL_WORKSPACE_ID = "local";
4
+ export declare const LOCAL_PROJECT_ID = "default";
5
+ type RecoveryMode = "interrupt" | "requeue";
6
+ export interface ArtifactRecord {
7
+ kind: "output" | "source" | "thumbnail";
8
+ path: string;
9
+ sizeBytes: number;
10
+ createdAt?: string;
11
+ }
12
+ export declare class WorkerLeaseLostError extends Error {
13
+ constructor(jobId: string);
14
+ }
15
+ export declare class JobStore {
16
+ readonly outputRoot: string;
17
+ private database;
18
+ constructor(outputRoot: string);
19
+ initialize(): Promise<void>;
20
+ close(): void;
21
+ createJobId(targetUrl: string): string;
22
+ create(request: RecordRequest, options?: {
23
+ parentJobId?: string;
24
+ attempt?: number;
25
+ }): Promise<{
26
+ workspaceId: string;
27
+ projectId: string;
28
+ updatedAt: string;
29
+ schemaVersion: 1;
30
+ jobId: string;
31
+ targetUrl: string;
32
+ title?: string;
33
+ createdAt: string;
34
+ status: import("../types.js").RecordingJobStatus;
35
+ progress: RecordingJobProgress;
36
+ request?: RecordRequest;
37
+ result?: import("../types.js").RecordingJobResult;
38
+ error?: {
39
+ stage: import("../types.js").RecordingJobStage;
40
+ message: string;
41
+ };
42
+ attempt: number;
43
+ parentJobId?: string;
44
+ legacy?: boolean;
45
+ }>;
46
+ list(): Promise<RecordingJobManifest[]>;
47
+ read(jobId: string): Promise<RecordingJobManifest>;
48
+ write(manifest: RecordingJobManifest): Promise<{
49
+ workspaceId: string;
50
+ projectId: string;
51
+ updatedAt: string;
52
+ schemaVersion: 1;
53
+ jobId: string;
54
+ targetUrl: string;
55
+ title?: string;
56
+ createdAt: string;
57
+ status: import("../types.js").RecordingJobStatus;
58
+ progress: RecordingJobProgress;
59
+ request?: RecordRequest;
60
+ result?: import("../types.js").RecordingJobResult;
61
+ error?: {
62
+ stage: import("../types.js").RecordingJobStage;
63
+ message: string;
64
+ };
65
+ attempt: number;
66
+ parentJobId?: string;
67
+ legacy?: boolean;
68
+ }>;
69
+ patch(jobId: string, update: Partial<RecordingJobManifest>): Promise<{
70
+ workspaceId: string;
71
+ projectId: string;
72
+ updatedAt: string;
73
+ schemaVersion: 1;
74
+ jobId: string;
75
+ targetUrl: string;
76
+ title?: string;
77
+ createdAt: string;
78
+ status: import("../types.js").RecordingJobStatus;
79
+ progress: RecordingJobProgress;
80
+ request?: RecordRequest;
81
+ result?: import("../types.js").RecordingJobResult;
82
+ error?: {
83
+ stage: import("../types.js").RecordingJobStage;
84
+ message: string;
85
+ };
86
+ attempt: number;
87
+ parentJobId?: string;
88
+ legacy?: boolean;
89
+ }>;
90
+ patchLeased(jobId: string, workerId: string, update: Partial<RecordingJobManifest>): Promise<{
91
+ jobId: string;
92
+ schemaVersion: 1;
93
+ workspaceId: string;
94
+ projectId: string;
95
+ updatedAt: string;
96
+ targetUrl: string;
97
+ title?: string;
98
+ createdAt: string;
99
+ status: import("../types.js").RecordingJobStatus;
100
+ progress: RecordingJobProgress;
101
+ request?: RecordRequest;
102
+ result?: import("../types.js").RecordingJobResult;
103
+ error?: {
104
+ stage: import("../types.js").RecordingJobStage;
105
+ message: string;
106
+ };
107
+ attempt: number;
108
+ parentJobId?: string;
109
+ legacy?: boolean;
110
+ }>;
111
+ remove(jobId: string): Promise<void>;
112
+ claimNextQueued(workerId: string, leaseMs: number): Promise<RecordingJobManifest | null>;
113
+ heartbeat(jobId: string, workerId: string, leaseMs: number): Promise<boolean>;
114
+ releaseLease(jobId: string, workerId: string): Promise<void>;
115
+ recoverExpiredRunningJobs(mode: RecoveryMode): Promise<number>;
116
+ requestCancellation(jobId: string): Promise<{
117
+ workspaceId: string;
118
+ projectId: string;
119
+ updatedAt: string;
120
+ schemaVersion: 1;
121
+ jobId: string;
122
+ targetUrl: string;
123
+ title?: string;
124
+ createdAt: string;
125
+ status: import("../types.js").RecordingJobStatus;
126
+ progress: RecordingJobProgress;
127
+ request?: RecordRequest;
128
+ result?: import("../types.js").RecordingJobResult;
129
+ error?: {
130
+ stage: import("../types.js").RecordingJobStage;
131
+ message: string;
132
+ };
133
+ attempt: number;
134
+ parentJobId?: string;
135
+ legacy?: boolean;
136
+ }>;
137
+ isCancellationRequested(jobId: string): Promise<boolean>;
138
+ replaceArtifacts(jobId: string, artifacts: ArtifactRecord[]): Promise<void>;
139
+ recordUsage(jobId: string, eventType: string, quantity: number, unit: string): Promise<void>;
140
+ jobDir(jobId: string): string;
141
+ private db;
142
+ private createSchema;
143
+ private exists;
144
+ private writeCompatibilityManifest;
145
+ private importFilesystemJobs;
146
+ }
147
+ export declare function progress(stage: RecordingJobProgress["stage"], percent: number, message: string): RecordingJobProgress;
148
+ export declare function validateJobId(jobId: string): void;
149
+ export {};
150
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/jobs/store.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,aAAa,EACb,oBAAoB,EACpB,oBAAoB,EACrB,MAAM,aAAa,CAAC;AAErB,eAAO,MAAM,qBAAqB,aAAa,CAAC;AAChD,eAAO,MAAM,kBAAkB,UAAU,CAAC;AAC1C,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAE1C,KAAK,YAAY,GAAG,WAAW,GAAG,SAAS,CAAC;AAU5C,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,WAAW,CAAC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,oBAAqB,SAAQ,KAAK;gBACjC,KAAK,EAAE,MAAM;CAI1B;AAED,qBAAa,QAAQ;IAGP,QAAQ,CAAC,UAAU,EAAE,MAAM;IAFvC,OAAO,CAAC,QAAQ,CAAkC;gBAE7B,UAAU,EAAE,MAAM;IAEjC,UAAU;IAahB,KAAK;IAKL,WAAW,CAAC,SAAS,EAAE,MAAM;IAMvB,MAAM,CACV,OAAO,EAAE,aAAa,EACtB,OAAO,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE;;;;;;;;;;;;;;;;;;;;;IA4BhD,IAAI;IAOJ,IAAI,CAAC,KAAK,EAAE,MAAM;IASlB,KAAK,CAAC,QAAQ,EAAE,oBAAoB;;;;;;;;;;;;;;;;;;;;;IAuCpC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,oBAAoB,CAAC;;;;;;;;;;;;;;;;;;;;;IAK1D,WAAW,CACf,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,OAAO,CAAC,oBAAoB,CAAC;;;;;;;;;;;;;;;;;;;;;IAyCjC,MAAM,CAAC,KAAK,EAAE,MAAM;IAKpB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAyBjD,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAU1D,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;IAQ5C,yBAAyB,CAAC,IAAI,EAAE,YAAY;IAmC5C,mBAAmB,CAAC,KAAK,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;IAmBjC,uBAAuB,CAAC,KAAK,EAAE,MAAM;IAOrC,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE;IAqB3D,WAAW,CACf,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM;IAiBd,MAAM,CAAC,KAAK,EAAE,MAAM;IAKpB,OAAO,CAAC,EAAE;IAKV,OAAO,CAAC,YAAY;YAyDN,MAAM;YAKN,0BAA0B;YAQ1B,oBAAoB;CA8DnC;AAED,wBAAgB,QAAQ,CACtB,KAAK,EAAE,oBAAoB,CAAC,OAAO,CAAC,EACpC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,oBAAoB,CAEtB;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,QAE1C"}
@@ -0,0 +1,446 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import Database from "better-sqlite3";
4
+ import { probeVideoDurationMs, probeVideoSize } from "../transcode/probe.js";
5
+ export const JOB_MANIFEST_FILENAME = "job.json";
6
+ export const LOCAL_WORKSPACE_ID = "local";
7
+ export const LOCAL_PROJECT_ID = "default";
8
+ export class WorkerLeaseLostError extends Error {
9
+ constructor(jobId) {
10
+ super(`Worker lease lost for ${jobId}`);
11
+ this.name = "WorkerLeaseLostError";
12
+ }
13
+ }
14
+ export class JobStore {
15
+ outputRoot;
16
+ database = null;
17
+ constructor(outputRoot) {
18
+ this.outputRoot = outputRoot;
19
+ }
20
+ async initialize() {
21
+ await fs.mkdir(this.outputRoot, { recursive: true });
22
+ if (!this.database) {
23
+ this.database = new Database(path.join(this.outputRoot, "scrollizard.sqlite3"));
24
+ this.database.pragma("journal_mode = WAL");
25
+ this.database.pragma("foreign_keys = ON");
26
+ this.database.pragma("busy_timeout = 5000");
27
+ this.createSchema();
28
+ this.database.pragma("user_version = 1");
29
+ }
30
+ await this.importFilesystemJobs();
31
+ }
32
+ close() {
33
+ this.database?.close();
34
+ this.database = null;
35
+ }
36
+ createJobId(targetUrl) {
37
+ const host = new URL(targetUrl).hostname.replace(/^www\./, "");
38
+ const stamp = new Date().toISOString().replace(/[:.]/g, "-");
39
+ return `${host}-${stamp}`;
40
+ }
41
+ async create(request, options) {
42
+ const now = new Date().toISOString();
43
+ let jobId = this.createJobId(request.targetUrl);
44
+ let suffix = 1;
45
+ while (await this.exists(jobId))
46
+ jobId = `${this.createJobId(request.targetUrl)}-${suffix++}`;
47
+ const manifest = {
48
+ schemaVersion: 1,
49
+ jobId,
50
+ workspaceId: LOCAL_WORKSPACE_ID,
51
+ projectId: LOCAL_PROJECT_ID,
52
+ targetUrl: request.targetUrl,
53
+ title: new URL(request.targetUrl).hostname.replace(/^www\./, ""),
54
+ createdAt: now,
55
+ updatedAt: now,
56
+ status: "queued",
57
+ progress: progress("queued", 0, "Waiting for a capture worker"),
58
+ request,
59
+ attempt: options?.attempt ?? 1,
60
+ parentJobId: options?.parentJobId,
61
+ };
62
+ if (request.comparison) {
63
+ manifest.title = `${request.comparison.primaryLabel} vs ${request.comparison.secondaryLabel}`;
64
+ }
65
+ await fs.mkdir(this.jobDir(jobId), { recursive: true });
66
+ return this.write(manifest);
67
+ }
68
+ async list() {
69
+ const rows = this.db()
70
+ .prepare("SELECT manifest_json FROM jobs ORDER BY created_at DESC")
71
+ .all();
72
+ return rows.map(parseManifest);
73
+ }
74
+ async read(jobId) {
75
+ validateJobId(jobId);
76
+ const row = this.db()
77
+ .prepare("SELECT manifest_json FROM jobs WHERE job_id = ?")
78
+ .get(jobId);
79
+ if (!row)
80
+ throw new Error("Recording job not found");
81
+ return parseManifest(row);
82
+ }
83
+ async write(manifest) {
84
+ validateJobId(manifest.jobId);
85
+ const next = {
86
+ ...manifest,
87
+ workspaceId: manifest.workspaceId ?? LOCAL_WORKSPACE_ID,
88
+ projectId: manifest.projectId ?? LOCAL_PROJECT_ID,
89
+ updatedAt: new Date().toISOString(),
90
+ };
91
+ this.db()
92
+ .prepare(`
93
+ INSERT INTO jobs (
94
+ job_id, workspace_id, project_id, target_url, status,
95
+ created_at, updated_at, manifest_json
96
+ ) VALUES (
97
+ @jobId, @workspaceId, @projectId, @targetUrl, @status,
98
+ @createdAt, @updatedAt, @manifest
99
+ )
100
+ ON CONFLICT(job_id) DO UPDATE SET
101
+ workspace_id = excluded.workspace_id,
102
+ project_id = excluded.project_id,
103
+ target_url = excluded.target_url,
104
+ status = excluded.status,
105
+ updated_at = excluded.updated_at,
106
+ manifest_json = excluded.manifest_json
107
+ `)
108
+ .run({
109
+ jobId: next.jobId,
110
+ workspaceId: next.workspaceId,
111
+ projectId: next.projectId,
112
+ targetUrl: next.targetUrl,
113
+ status: next.status,
114
+ createdAt: next.createdAt,
115
+ updatedAt: next.updatedAt,
116
+ manifest: JSON.stringify(next),
117
+ });
118
+ await this.writeCompatibilityManifest(next);
119
+ return next;
120
+ }
121
+ async patch(jobId, update) {
122
+ const current = await this.read(jobId);
123
+ return this.write({ ...current, ...update, jobId: current.jobId, schemaVersion: 1 });
124
+ }
125
+ async patchLeased(jobId, workerId, update) {
126
+ validateJobId(jobId);
127
+ const row = this.db().prepare(`
128
+ SELECT manifest_json FROM jobs WHERE job_id = ? AND lease_owner = ?
129
+ `).get(jobId, workerId);
130
+ if (!row)
131
+ throw new WorkerLeaseLostError(jobId);
132
+ const current = parseManifest(row);
133
+ const next = {
134
+ ...current,
135
+ ...update,
136
+ jobId: current.jobId,
137
+ schemaVersion: 1,
138
+ workspaceId: current.workspaceId ?? LOCAL_WORKSPACE_ID,
139
+ projectId: current.projectId ?? LOCAL_PROJECT_ID,
140
+ updatedAt: new Date().toISOString(),
141
+ };
142
+ const result = this.db().prepare(`
143
+ UPDATE jobs SET
144
+ workspace_id = @workspaceId,
145
+ project_id = @projectId,
146
+ target_url = @targetUrl,
147
+ status = @status,
148
+ updated_at = @updatedAt,
149
+ manifest_json = @manifest
150
+ WHERE job_id = @jobId AND lease_owner = @workerId
151
+ `).run({
152
+ jobId,
153
+ workerId,
154
+ workspaceId: next.workspaceId,
155
+ projectId: next.projectId,
156
+ targetUrl: next.targetUrl,
157
+ status: next.status,
158
+ updatedAt: next.updatedAt,
159
+ manifest: JSON.stringify(next),
160
+ });
161
+ if (result.changes !== 1)
162
+ throw new WorkerLeaseLostError(jobId);
163
+ await this.writeCompatibilityManifest(next);
164
+ return next;
165
+ }
166
+ async remove(jobId) {
167
+ validateJobId(jobId);
168
+ this.db().prepare("DELETE FROM jobs WHERE job_id = ?").run(jobId);
169
+ }
170
+ async claimNextQueued(workerId, leaseMs) {
171
+ const database = this.db();
172
+ const claim = database.transaction(() => {
173
+ const now = Date.now();
174
+ const row = database.prepare(`
175
+ SELECT job_id, manifest_json
176
+ FROM jobs
177
+ WHERE status = 'queued'
178
+ AND (lease_owner IS NULL OR lease_expires_at < ?)
179
+ ORDER BY created_at ASC
180
+ LIMIT 1
181
+ `).get(now);
182
+ if (!row)
183
+ return null;
184
+ const result = database.prepare(`
185
+ UPDATE jobs
186
+ SET lease_owner = ?, lease_expires_at = ?, heartbeat_at = ?
187
+ WHERE job_id = ?
188
+ AND status = 'queued'
189
+ AND (lease_owner IS NULL OR lease_expires_at < ?)
190
+ `).run(workerId, now + leaseMs, now, row.job_id, now);
191
+ return result.changes === 1 ? parseManifest(row) : null;
192
+ });
193
+ return claim.immediate();
194
+ }
195
+ async heartbeat(jobId, workerId, leaseMs) {
196
+ const now = Date.now();
197
+ const result = this.db().prepare(`
198
+ UPDATE jobs
199
+ SET heartbeat_at = ?, lease_expires_at = ?
200
+ WHERE job_id = ? AND lease_owner = ?
201
+ `).run(now, now + leaseMs, jobId, workerId);
202
+ return result.changes === 1;
203
+ }
204
+ async releaseLease(jobId, workerId) {
205
+ this.db().prepare(`
206
+ UPDATE jobs
207
+ SET lease_owner = NULL, lease_expires_at = NULL, heartbeat_at = NULL
208
+ WHERE job_id = ? AND lease_owner = ?
209
+ `).run(jobId, workerId);
210
+ }
211
+ async recoverExpiredRunningJobs(mode) {
212
+ const now = Date.now();
213
+ const rows = this.db().prepare(`
214
+ SELECT manifest_json
215
+ FROM jobs
216
+ WHERE status = 'running'
217
+ AND (lease_owner IS NULL OR lease_expires_at < ?)
218
+ `).all(now);
219
+ for (const row of rows) {
220
+ const job = parseManifest(row);
221
+ const status = mode === "requeue" ? "queued" : "interrupted";
222
+ await this.patch(job.jobId, {
223
+ status,
224
+ progress: progress(status, mode === "requeue" ? 0 : job.progress.percent, mode === "requeue"
225
+ ? "Recovered after worker restart"
226
+ : "Capture interrupted by application restart"),
227
+ error: mode === "requeue"
228
+ ? undefined
229
+ : { stage: job.progress.stage, message: "Capture interrupted by application restart" },
230
+ });
231
+ this.db().prepare(`
232
+ UPDATE jobs
233
+ SET lease_owner = NULL, lease_expires_at = NULL, heartbeat_at = NULL,
234
+ cancel_requested = 0
235
+ WHERE job_id = ?
236
+ `).run(job.jobId);
237
+ }
238
+ return rows.length;
239
+ }
240
+ async requestCancellation(jobId) {
241
+ const job = await this.read(jobId);
242
+ if (job.status === "queued") {
243
+ const cancelled = await this.patch(jobId, {
244
+ status: "cancelled",
245
+ progress: progress("cancelled", job.progress.percent, "Capture cancelled"),
246
+ });
247
+ this.db().prepare("UPDATE jobs SET cancel_requested = 0 WHERE job_id = ?").run(jobId);
248
+ return cancelled;
249
+ }
250
+ if (job.status !== "running") {
251
+ throw new Error("Only queued or running jobs can be cancelled");
252
+ }
253
+ this.db().prepare("UPDATE jobs SET cancel_requested = 1 WHERE job_id = ?").run(jobId);
254
+ return this.patch(jobId, {
255
+ progress: progress(job.progress.stage, job.progress.percent, "Cancellation requested"),
256
+ });
257
+ }
258
+ async isCancellationRequested(jobId) {
259
+ const row = this.db()
260
+ .prepare("SELECT cancel_requested AS requested FROM jobs WHERE job_id = ?")
261
+ .get(jobId);
262
+ return row?.requested === 1;
263
+ }
264
+ async replaceArtifacts(jobId, artifacts) {
265
+ validateJobId(jobId);
266
+ const database = this.db();
267
+ database.transaction(() => {
268
+ database.prepare("DELETE FROM artifacts WHERE job_id = ?").run(jobId);
269
+ const insert = database.prepare(`
270
+ INSERT INTO artifacts (job_id, kind, path, size_bytes, created_at)
271
+ VALUES (?, ?, ?, ?, ?)
272
+ `);
273
+ for (const artifact of artifacts) {
274
+ insert.run(jobId, artifact.kind, artifact.path, artifact.sizeBytes, artifact.createdAt ?? new Date().toISOString());
275
+ }
276
+ })();
277
+ }
278
+ async recordUsage(jobId, eventType, quantity, unit) {
279
+ this.db().prepare(`
280
+ INSERT INTO usage_events (
281
+ workspace_id, project_id, job_id, event_type, quantity, unit, created_at
282
+ ) VALUES (?, ?, ?, ?, ?, ?, ?)
283
+ `).run(LOCAL_WORKSPACE_ID, LOCAL_PROJECT_ID, jobId, eventType, quantity, unit, new Date().toISOString());
284
+ }
285
+ jobDir(jobId) {
286
+ validateJobId(jobId);
287
+ return path.join(this.outputRoot, jobId);
288
+ }
289
+ db() {
290
+ if (!this.database)
291
+ throw new Error("JobStore has not been initialized");
292
+ return this.database;
293
+ }
294
+ createSchema() {
295
+ this.db().exec(`
296
+ CREATE TABLE IF NOT EXISTS workspaces (
297
+ id TEXT PRIMARY KEY,
298
+ name TEXT NOT NULL,
299
+ created_at TEXT NOT NULL
300
+ );
301
+ CREATE TABLE IF NOT EXISTS projects (
302
+ id TEXT PRIMARY KEY,
303
+ workspace_id TEXT NOT NULL REFERENCES workspaces(id),
304
+ name TEXT NOT NULL,
305
+ created_at TEXT NOT NULL
306
+ );
307
+ CREATE TABLE IF NOT EXISTS jobs (
308
+ job_id TEXT PRIMARY KEY,
309
+ workspace_id TEXT NOT NULL REFERENCES workspaces(id),
310
+ project_id TEXT NOT NULL REFERENCES projects(id),
311
+ target_url TEXT NOT NULL,
312
+ status TEXT NOT NULL,
313
+ created_at TEXT NOT NULL,
314
+ updated_at TEXT NOT NULL,
315
+ manifest_json TEXT NOT NULL,
316
+ lease_owner TEXT,
317
+ lease_expires_at INTEGER,
318
+ heartbeat_at INTEGER,
319
+ cancel_requested INTEGER NOT NULL DEFAULT 0
320
+ );
321
+ CREATE INDEX IF NOT EXISTS jobs_queue_idx
322
+ ON jobs(status, created_at, lease_expires_at);
323
+ CREATE TABLE IF NOT EXISTS artifacts (
324
+ job_id TEXT NOT NULL REFERENCES jobs(job_id) ON DELETE CASCADE,
325
+ kind TEXT NOT NULL,
326
+ path TEXT NOT NULL,
327
+ size_bytes INTEGER NOT NULL,
328
+ created_at TEXT NOT NULL,
329
+ PRIMARY KEY(job_id, kind)
330
+ );
331
+ CREATE TABLE IF NOT EXISTS usage_events (
332
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
333
+ workspace_id TEXT NOT NULL REFERENCES workspaces(id),
334
+ project_id TEXT NOT NULL REFERENCES projects(id),
335
+ job_id TEXT REFERENCES jobs(job_id) ON DELETE SET NULL,
336
+ event_type TEXT NOT NULL,
337
+ quantity REAL NOT NULL,
338
+ unit TEXT NOT NULL,
339
+ created_at TEXT NOT NULL
340
+ );
341
+ `);
342
+ const now = new Date().toISOString();
343
+ this.db()
344
+ .prepare("INSERT OR IGNORE INTO workspaces (id, name, created_at) VALUES (?, ?, ?)")
345
+ .run(LOCAL_WORKSPACE_ID, "Local workspace", now);
346
+ this.db()
347
+ .prepare("INSERT OR IGNORE INTO projects (id, workspace_id, name, created_at) VALUES (?, ?, ?, ?)")
348
+ .run(LOCAL_PROJECT_ID, LOCAL_WORKSPACE_ID, "Default project", now);
349
+ }
350
+ async exists(jobId) {
351
+ const row = this.db().prepare("SELECT 1 AS found FROM jobs WHERE job_id = ?").get(jobId);
352
+ return Boolean(row);
353
+ }
354
+ async writeCompatibilityManifest(manifest) {
355
+ const target = path.join(this.jobDir(manifest.jobId), JOB_MANIFEST_FILENAME);
356
+ const temporary = `${target}.${process.pid}.next`;
357
+ await fs.mkdir(this.jobDir(manifest.jobId), { recursive: true });
358
+ await fs.writeFile(temporary, JSON.stringify(manifest, null, 2));
359
+ await fs.rename(temporary, target);
360
+ }
361
+ async importFilesystemJobs() {
362
+ const entries = await fs.readdir(this.outputRoot, { withFileTypes: true }).catch(() => []);
363
+ for (const entry of entries) {
364
+ if (!entry.isDirectory() || entry.name.startsWith("."))
365
+ continue;
366
+ const jobId = entry.name;
367
+ try {
368
+ validateJobId(jobId);
369
+ }
370
+ catch {
371
+ continue;
372
+ }
373
+ if (await this.exists(jobId))
374
+ continue;
375
+ const manifestPath = path.join(this.jobDir(jobId), JOB_MANIFEST_FILENAME);
376
+ const storedManifest = await fs.readFile(manifestPath, "utf8").catch(() => null);
377
+ if (storedManifest) {
378
+ try {
379
+ await this.write(JSON.parse(storedManifest));
380
+ continue;
381
+ }
382
+ catch {
383
+ // Fall through to importing the completed MP4 as a legacy job.
384
+ }
385
+ }
386
+ const outputPath = path.join(this.jobDir(jobId), "output.mp4");
387
+ const details = await fs.stat(outputPath).catch(() => null);
388
+ if (!details?.isFile())
389
+ continue;
390
+ const [durationMs, viewport, source] = await Promise.all([
391
+ probeVideoDurationMs(outputPath),
392
+ probeVideoSize(outputPath),
393
+ fs.stat(path.join(this.jobDir(jobId), "source.mp4")).catch(() => null),
394
+ ]);
395
+ const parsed = parseLegacyJobName(jobId);
396
+ const createdAt = parsed.createdAt ?? details.birthtime.toISOString();
397
+ await this.write({
398
+ schemaVersion: 1,
399
+ jobId,
400
+ workspaceId: LOCAL_WORKSPACE_ID,
401
+ projectId: LOCAL_PROJECT_ID,
402
+ targetUrl: parsed.host ? `https://${parsed.host}` : "",
403
+ createdAt,
404
+ updatedAt: new Date().toISOString(),
405
+ status: "completed",
406
+ progress: progress("completed", 100, "Legacy recording imported"),
407
+ result: {
408
+ videoUrl: `/outputs/${jobId}/output.mp4`,
409
+ sourceVideoUrl: source?.isFile() ? `/outputs/${jobId}/source.mp4` : undefined,
410
+ durationMs: durationMs ?? 0,
411
+ renderTimeMs: 0,
412
+ sizeBytes: details.size,
413
+ viewport: {
414
+ width: viewport?.width ?? 0,
415
+ height: viewport?.height ?? 0,
416
+ deviceScaleFactor: 1,
417
+ },
418
+ scrollStrategy: "document",
419
+ canRestyle: Boolean(source?.isFile()),
420
+ },
421
+ attempt: 1,
422
+ legacy: true,
423
+ });
424
+ }
425
+ }
426
+ }
427
+ export function progress(stage, percent, message) {
428
+ return { stage, percent: Math.max(0, Math.min(100, Math.round(percent))), message };
429
+ }
430
+ export function validateJobId(jobId) {
431
+ if (!/^[a-zA-Z0-9._-]+$/.test(jobId))
432
+ throw new Error("Invalid jobId");
433
+ }
434
+ function parseManifest(row) {
435
+ return JSON.parse(row.manifest_json);
436
+ }
437
+ function parseLegacyJobName(jobId) {
438
+ const match = jobId.match(/^(.*)-(\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}-\d{3}Z)(?:-\d+)?$/);
439
+ if (!match)
440
+ return { host: jobId || undefined, createdAt: undefined };
441
+ return {
442
+ host: match[1],
443
+ createdAt: new Date(match[2].replace(/T(\d{2})-(\d{2})-(\d{2})-(\d{3})Z$/, "T$1:$2:$3.$4Z")).toISOString(),
444
+ };
445
+ }
446
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/jobs/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function createVideoThumbnail(inputPath: string, outputPath: string, signal?: AbortSignal): Promise<void>;
2
+ //# sourceMappingURL=thumbnail.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thumbnail.d.ts","sourceRoot":"","sources":["../../src/jobs/thumbnail.ts"],"names":[],"mappings":"AAEA,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,WAAW,iBA+BrB"}
@@ -0,0 +1,36 @@
1
+ import { spawn } from "node:child_process";
2
+ export async function createVideoThumbnail(inputPath, outputPath, signal) {
3
+ await new Promise((resolve, reject) => {
4
+ const child = spawn("ffmpeg", [
5
+ "-y",
6
+ "-ss",
7
+ "0",
8
+ "-i",
9
+ inputPath,
10
+ "-frames:v",
11
+ "1",
12
+ "-vf",
13
+ "scale=640:-2",
14
+ "-q:v",
15
+ "3",
16
+ outputPath,
17
+ ], { stdio: ["ignore", "ignore", "pipe"] });
18
+ let stderr = "";
19
+ const abort = () => child.kill("SIGTERM");
20
+ signal?.addEventListener("abort", abort, { once: true });
21
+ child.stderr.on("data", (chunk) => {
22
+ stderr += chunk.toString();
23
+ });
24
+ child.on("error", reject);
25
+ child.on("close", (code) => {
26
+ signal?.removeEventListener("abort", abort);
27
+ if (signal?.aborted)
28
+ reject(signal.reason ?? new Error("Cancelled"));
29
+ else if (code === 0)
30
+ resolve();
31
+ else
32
+ reject(new Error(`Thumbnail generation failed: ${stderr.slice(-1000)}`));
33
+ });
34
+ });
35
+ }
36
+ //# sourceMappingURL=thumbnail.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thumbnail.js","sourceRoot":"","sources":["../../src/jobs/thumbnail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,SAAiB,EACjB,UAAkB,EAClB,MAAoB;IAEpB,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,EAAE;YAC5B,IAAI;YACJ,KAAK;YACL,GAAG;YACH,IAAI;YACJ,SAAS;YACT,WAAW;YACX,GAAG;YACH,KAAK;YACL,cAAc;YACd,MAAM;YACN,GAAG;YACH,UAAU;SACX,EAAE,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QAC5C,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,MAAM,KAAK,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC1C,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACzD,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YACxC,MAAM,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC7B,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC1B,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACzB,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YAC5C,IAAI,MAAM,EAAE,OAAO;gBAAE,MAAM,CAAC,MAAM,CAAC,MAAM,IAAI,IAAI,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;iBAChE,IAAI,IAAI,KAAK,CAAC;gBAAE,OAAO,EAAE,CAAC;;gBAC1B,MAAM,CAAC,IAAI,KAAK,CAAC,gCAAgC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QAChF,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}