@spark-apps/quickpeek 1.1.3 → 1.2.1

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.
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Configuration types and defaults for QuickPeek
3
3
  */
4
- declare const VERSION = "1.1.1";
4
+ declare const VERSION = "1.2.1";
5
5
  declare const CONFIG_FILE = "quickpeek.config.json";
6
6
  type UserTier = 'free' | 'pro';
7
7
  interface Config {
@@ -65,8 +65,13 @@ declare const DEFAULT_CAPTIONS: CaptionStyle;
65
65
  * AI API client — Spark AI communication
66
66
  * Handles token management, rate limiting, and retries
67
67
  *
68
- * The API key is embedded at build time via tsup `define`.
69
- * Per-user rate limiting is handled server-side via email.
68
+ * Two transports:
69
+ * - Relay (default for the published CLI): quickpeek-web mints a short-lived
70
+ * per-user token from a registered email and proxies the chat server-side.
71
+ * No credential ships in the npm bundle.
72
+ * - Direct (dev/server only): when SPARK_AI_KEY is present in the runtime
73
+ * environment (never baked at build time), call Spark AI directly. This is
74
+ * the path quickpeek-web itself uses server-side.
70
75
  */
71
76
 
72
77
  interface RateLimitInfo {
@@ -89,9 +94,15 @@ interface AIError {
89
94
  }
90
95
  type AIResult = AIResponse | AIError;
91
96
  /**
92
- * Call Spark AI chat endpoint. Automatically retries on rate limit using Retry-After header.
97
+ * Direct Spark AI call using the runtime SPARK_AI_KEY (dev + server-side use).
93
98
  */
94
99
  declare function callAI(systemPrompt: string, userPrompt: string, tier?: UserTier): Promise<AIResult>;
100
+ /**
101
+ * Relayed Spark AI call for the published CLI: authenticates with the user's
102
+ * registered email via quickpeek-web, which holds the real key server-side
103
+ * and enforces per-user daily limits.
104
+ */
105
+ declare function callAIViaRelay(systemPrompt: string, userPrompt: string, email: string, tier?: UserTier): Promise<AIResult>;
95
106
  /**
96
107
  * Parse AI-generated plan JSON from response text
97
108
  */
@@ -170,14 +181,19 @@ interface Plan {
170
181
 
171
182
  /**
172
183
  * Crawl a page and extract interactive elements with smart selectors
184
+ * Results are cached in-memory for a few minutes to avoid duplicate browser launches
173
185
  * @param url - URL to crawl
174
186
  * @param task - Optional progress reporter (CLI uses ora spinners, web can omit)
175
187
  */
176
188
  declare function crawlPage(url: string, task?: (text: string) => {
177
189
  succeed: (text?: string) => void;
190
+ }, storageStatePath?: string, viewport?: {
191
+ width: number;
192
+ height: number;
178
193
  }): Promise<{
179
194
  title: string;
180
195
  elements: ElementInfo[];
196
+ scrollable: number;
181
197
  }>;
182
198
 
183
199
  /**
@@ -187,19 +203,12 @@ declare function crawlPage(url: string, task?: (text: string) => {
187
203
  * Get full language name from ISO code
188
204
  */
189
205
  declare function getLanguageName(lang?: string): string | null;
190
- /**
191
- * Convert hex color (#RRGGBB) to ASS subtitle format (&HAABBGGRR)
192
- */
193
- declare function hexToASS(hex: string, alpha?: number): string;
206
+
194
207
  /**
195
208
  * Convert rgba() or rgb() color string to hex
196
209
  */
197
210
  declare function rgbaToHex(color: string): string;
198
- /**
199
- * Convert a Windows absolute path (D:\...) to WSL mount format (/mnt/d/...).
200
- * Returns null if the path is not a Windows drive-letter path.
201
- */
202
- declare function windowsPathToWSL(path: string): string | null;
211
+
203
212
  /**
204
213
  * Parse partial field "start-end" into trim values
205
214
  * e.g., "0-3.5" -> { trimStart: 0, trimEnd: 3.5 }
@@ -224,19 +233,7 @@ declare function toTitleCase(text: string): string;
224
233
  */
225
234
 
226
235
  declare function buildSystemPrompt(maxSteps: number): string;
227
- declare function buildUserPrompt(url: string, title: string, elements: ElementInfo[], langName: string | null, description: string | undefined, maxSteps: number): string;
228
-
229
- /**
230
- * Shared constants for page scraping and element filtering
231
- * Used by both CLI and web versions
232
- */
233
- declare const EXCLUDED_LINK_PATTERNS: string[];
234
- /** CSS selectors for interactive page elements */
235
- declare const INTERACTIVE_SELECTORS: string[];
236
- /** Check if link text or href matches an excluded pattern */
237
- declare function isExcludedLink(text: string, href?: string): boolean;
238
- /** Check if a link should be skipped during crawling */
239
- declare function shouldSkipLink(text: string, href: string, currentPath: string): boolean;
236
+ declare function buildUserPrompt(url: string, title: string, elements: ElementInfo[], langName: string | null, description: string | undefined, maxSteps: number, scrollable?: number): string;
240
237
 
241
238
  type Tier = 'free' | 'pro';
242
239
  declare const FEATURES: Record<string, string[]>;
@@ -282,6 +279,16 @@ declare function pricingUrl(opts?: {
282
279
  returnUrl?: string;
283
280
  }): string;
284
281
 
285
- declare const LANGUAGE_VOICES: Record<string, string>;
282
+ /**
283
+ * Shared constants for page scraping and element filtering
284
+ * Used by both CLI and web versions
285
+ */
286
+ declare const EXCLUDED_LINK_PATTERNS: string[];
287
+ /** CSS selectors for interactive page elements */
288
+ declare const INTERACTIVE_SELECTORS: string[];
289
+ /** Check if link text or href matches an excluded pattern */
290
+ declare function isExcludedLink(text: string, href?: string): boolean;
291
+ /** Check if a link should be skipped during crawling */
292
+ declare function shouldSkipLink(text: string, href: string, currentPath: string): boolean;
286
293
 
287
- export { type AIError as A, isPaid as B, type Config as C, DEFAULT_CAPTIONS as D, EXCLUDED_LINK_PATTERNS as E, FEATURES as F, isVerified as G, type HighlightMode as H, INTERACTIVE_SELECTORS as I, normalizeUrl as J, parseAIPlanResponse as K, LANGUAGE_VOICES as L, parsePartial as M, pricingUrl as N, rgbaToHex as O, type Plan as P, shouldSkipLink as Q, type RateLimitInfo as R, type SparkStatus as S, type Tier as T, type UserTier as U, VERSION as V, showPaywall as W, toTitleCase as X, windowsPathToWSL as Y, getTier as Z, type AIResponse as a, type AIResult as b, CONFIG_FILE as c, type CaptionStyle as d, type CaptionWordStyle as e, DEFAULT_CONFIG as f, type ElementInfo as g, type ElementType as h, type SparkSubscription as i, type SparkTrial as j, type Step as k, type SuggestedAction as l, buildSystemPrompt as m, buildUserPrompt as n, callAI as o, crawlPage as p, getErrorMessage as q, getLanguageName as r, getStatus as s, getStatusCached as t, getTierByEmail as u, hasAccess as v, hasTrialRemaining as w, hexToASS as x, isCanceling as y, isExcludedLink as z };
294
+ export { type AIError as A, isPaid as B, type Config as C, DEFAULT_CAPTIONS as D, EXCLUDED_LINK_PATTERNS as E, FEATURES as F, isVerified as G, type HighlightMode as H, INTERACTIVE_SELECTORS as I, normalizeUrl as J, parseAIPlanResponse as K, parsePartial as L, pricingUrl as M, rgbaToHex as N, shouldSkipLink as O, type Plan as P, showPaywall as Q, type RateLimitInfo as R, type SparkStatus as S, type Tier as T, type UserTier as U, VERSION as V, toTitleCase as W, getTier as X, type AIResponse as a, type AIResult as b, CONFIG_FILE as c, type CaptionStyle as d, type CaptionWordStyle as e, DEFAULT_CONFIG as f, type ElementInfo as g, type ElementType as h, type SparkSubscription as i, type SparkTrial as j, type Step as k, type SuggestedAction as l, buildSystemPrompt as m, buildUserPrompt as n, callAI as o, callAIViaRelay as p, crawlPage as q, getErrorMessage as r, getLanguageName as s, getStatus as t, getStatusCached as u, getTierByEmail as v, hasAccess as w, hasTrialRemaining as x, isCanceling as y, isExcludedLink as z };
package/dist/web.d.mts CHANGED
@@ -1,4 +1,45 @@
1
- export { A as AIError, a as AIResponse, b as AIResult, E as EXCLUDED_LINK_PATTERNS, g as ElementInfo, h as ElementType, F as FEATURES, H as HighlightMode, I as INTERACTIVE_SELECTORS, L as LANGUAGE_VOICES, P as Plan, R as RateLimitInfo, S as SparkStatus, i as SparkSubscription, j as SparkTrial, k as Step, l as SuggestedAction, T as Tier, m as buildSystemPrompt, n as buildUserPrompt, o as callAI, p as crawlPage, q as getErrorMessage, r as getLanguageName, s as getStatus, t as getStatusCached, Z as getTier, u as getTierByEmail, v as hasAccess, w as hasTrialRemaining, x as hexToASS, y as isCanceling, z as isExcludedLink, B as isPaid, G as isVerified, J as normalizeUrl, K as parseAIPlanResponse, M as parsePartial, N as pricingUrl, O as rgbaToHex, Q as shouldSkipLink, W as showPaywall, X as toTitleCase, Y as windowsPathToWSL } from './voices-BtYZey4Y.mjs';
1
+ import { P as Plan } from './scraping-CHN4ClyT.mjs';
2
+ export { A as AIError, a as AIResponse, b as AIResult, E as EXCLUDED_LINK_PATTERNS, g as ElementInfo, h as ElementType, F as FEATURES, H as HighlightMode, I as INTERACTIVE_SELECTORS, R as RateLimitInfo, S as SparkStatus, i as SparkSubscription, j as SparkTrial, k as Step, l as SuggestedAction, T as Tier, m as buildSystemPrompt, n as buildUserPrompt, o as callAI, q as crawlPage, r as getErrorMessage, s as getLanguageName, t as getStatus, u as getStatusCached, X as getTier, v as getTierByEmail, w as hasAccess, x as hasTrialRemaining, y as isCanceling, z as isExcludedLink, B as isPaid, G as isVerified, J as normalizeUrl, K as parseAIPlanResponse, L as parsePartial, M as pricingUrl, N as rgbaToHex, O as shouldSkipLink, Q as showPaywall, W as toTitleCase } from './scraping-CHN4ClyT.mjs';
3
+ export { WIDE_VOICES as LANGUAGE_VOICES, hexToAss as hexToASS, windowsDrivePathToWsl as windowsPathToWSL } from '@spark-apps/video-kit';
4
+
5
+ /**
6
+ * The plan file, and handing it to the browser editor.
7
+ *
8
+ * The JSON on disk is the source of truth: the CLI records from it, and the
9
+ * editor is a view onto it. The handover travels in a URL fragment, which no
10
+ * browser sends to a server — so editing a demo costs no upload, no account,
11
+ * and leaves no stored copy that can drift from the file being recorded.
12
+ *
13
+ * Mirrors VidLet's lib/project validate + file-io split, so whoever maintains
14
+ * both codebases finds the same shape in each.
15
+ */
16
+
17
+ type ParseResult = {
18
+ ok: true;
19
+ plan: Plan;
20
+ } | {
21
+ ok: false;
22
+ error: string;
23
+ };
24
+ /**
25
+ * Browsers accept far longer URLs than this, but shells, terminals and the
26
+ * `open` handlers in between are the weak link. Past it, the editor is opened
27
+ * empty and the user picks the file by hand.
28
+ */
29
+ declare const MAX_HANDOFF_URL_CHARS = 32000;
30
+ /** Canonical on-disk form: 2-space JSON with a trailing newline. */
31
+ declare function serializePlan(plan: Plan): string;
32
+ /**
33
+ * Parse plan JSON, rejecting anything the recorder could not act on. Steps
34
+ * missing an id are numbered rather than refused: the editor drops ids when
35
+ * a user adds a step by hand, and renumbering is what the CLI would do too.
36
+ */
37
+ declare function parsePlanText(text: string): ParseResult;
38
+ declare function encodePlan(plan: Plan): string;
39
+ /** Decode a `#plan=` fragment. Same validation as reading the file. */
40
+ declare function decodePlan(encoded: string): ParseResult;
41
+ /** The editor URL carrying a plan, or null when it is too long to hand over. */
42
+ declare function planEditorUrl(baseUrl: string, plan: Plan): string | null;
2
43
 
3
44
  /**
4
45
  * Plan Validation - Shared between CLI and Web
@@ -99,4 +140,4 @@ declare function restorePreservedValues<T extends BaseStep & {
99
140
  mediaIdx: number;
100
141
  };
101
142
 
102
- export { ACTIONS_REQUIRING_TARGET, type BaseStep, type CLIPlan, type CLIStep, FIX_PLAN_SYSTEM_PROMPT, INVALID_TARGETS, type PreservedValues, REFINE_PLAN_SYSTEM_PROMPT, type StepAction, type StepFailure, collectPreservedValues, filterValidSteps, isInvalidTarget, isValidStep, restorePreservedValues, validateStep };
143
+ export { ACTIONS_REQUIRING_TARGET, type BaseStep, type CLIPlan, type CLIStep, FIX_PLAN_SYSTEM_PROMPT, INVALID_TARGETS, MAX_HANDOFF_URL_CHARS, type ParseResult, Plan, type PreservedValues, REFINE_PLAN_SYSTEM_PROMPT, type StepAction, type StepFailure, collectPreservedValues, decodePlan, encodePlan, filterValidSteps, isInvalidTarget, isValidStep, parsePlanText, planEditorUrl, restorePreservedValues, serializePlan, validateStep };