autokap 1.0.7 → 1.0.8

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 (278) hide show
  1. package/assets/cursors/macos.svg +4 -0
  2. package/assets/cursors/windows.svg +15 -0
  3. package/assets/skill/OPCODE-REFERENCE.md +607 -0
  4. package/assets/skill/README.md +39 -0
  5. package/assets/skill/SKILL.md +453 -468
  6. package/assets/skill/STUDIO-SKILL.md +476 -0
  7. package/assets/skill/references/examples.md +104 -0
  8. package/assets/skill/references/interactive-demo.md +225 -0
  9. package/assets/skill/references/mock-data.md +178 -0
  10. package/dist/action-verifier.d.ts +29 -0
  11. package/dist/action-verifier.js +133 -0
  12. package/dist/agent-action-recovery.d.ts +45 -0
  13. package/dist/agent-action-recovery.js +370 -0
  14. package/dist/agent-message-utils.d.ts +21 -0
  15. package/dist/agent-message-utils.js +77 -0
  16. package/dist/agent-url-utils.d.ts +30 -0
  17. package/dist/agent-url-utils.js +138 -0
  18. package/dist/agent.d.ts +92 -8
  19. package/dist/agent.js +2936 -781
  20. package/dist/ak-tree.d.ts +39 -0
  21. package/dist/ak-tree.js +368 -0
  22. package/dist/alt-text.d.ts +26 -0
  23. package/dist/alt-text.js +55 -0
  24. package/dist/auth-capture.d.ts +17 -0
  25. package/dist/auth-capture.js +164 -0
  26. package/dist/benchmark.d.ts +59 -0
  27. package/dist/benchmark.js +135 -0
  28. package/dist/browser-bar.d.ts +14 -6
  29. package/dist/browser-bar.js +145 -8
  30. package/dist/browser-pool.d.ts +7 -0
  31. package/dist/browser-pool.js +15 -5
  32. package/dist/browser-utils.d.ts +31 -0
  33. package/dist/browser-utils.js +97 -0
  34. package/dist/browser.d.ts +51 -1
  35. package/dist/browser.js +1481 -31
  36. package/dist/capture-alt-text.js +2 -1
  37. package/dist/capture-language-preflight.js +14 -0
  38. package/dist/capture-llm-page-identity.js +22 -10
  39. package/dist/capture-page-identity.d.ts +5 -7
  40. package/dist/capture-page-identity.js +211 -78
  41. package/dist/capture-preset-credentials.d.ts +50 -0
  42. package/dist/capture-preset-credentials.js +127 -0
  43. package/dist/capture-request-plan.d.ts +2 -2
  44. package/dist/capture-request-plan.js +64 -16
  45. package/dist/capture-run-optimizer.js +48 -33
  46. package/dist/capture-selector-memory.d.ts +5 -0
  47. package/dist/capture-selector-memory.js +18 -0
  48. package/dist/capture-strategy.d.ts +36 -0
  49. package/dist/capture-strategy.js +95 -0
  50. package/dist/capture-studio-sync.d.ts +1 -0
  51. package/dist/capture-studio-sync.js +9 -3
  52. package/dist/capture-surface-contract.d.ts +36 -0
  53. package/dist/capture-surface-contract.js +299 -0
  54. package/dist/capture-transition-engine.d.ts +28 -0
  55. package/dist/capture-transition-engine.js +292 -0
  56. package/dist/capture-variant-state.d.ts +2 -0
  57. package/dist/capture-variant-state.js +26 -0
  58. package/dist/capture-verification.d.ts +35 -0
  59. package/dist/capture-verification.js +95 -0
  60. package/dist/capture-viewport-lock.d.ts +48 -0
  61. package/dist/capture-viewport-lock.js +74 -0
  62. package/dist/circuit-breaker.d.ts +42 -0
  63. package/dist/circuit-breaker.js +119 -0
  64. package/dist/cli-config.d.ts +8 -1
  65. package/dist/cli-config.js +62 -6
  66. package/dist/cli-contract.d.ts +15 -0
  67. package/dist/cli-contract.js +167 -0
  68. package/dist/cli-runner-local.d.ts +12 -0
  69. package/dist/cli-runner-local.js +102 -0
  70. package/dist/cli-runner.d.ts +34 -0
  71. package/dist/cli-runner.js +433 -0
  72. package/dist/cli-utils.d.ts +0 -1
  73. package/dist/cli-utils.js +2 -5
  74. package/dist/cli.js +1005 -267
  75. package/dist/clip-orchestrator.js +9 -2
  76. package/dist/clip-postprocess.js +25 -16
  77. package/dist/cookie-dismiss.d.ts +2 -0
  78. package/dist/cookie-dismiss.js +48 -13
  79. package/dist/cost-logging.d.ts +8 -0
  80. package/dist/cost-logging.js +160 -46
  81. package/dist/cost-resolution-monitor.d.ts +16 -0
  82. package/dist/cost-resolution-monitor.js +34 -0
  83. package/dist/credential-templates.js +2 -2
  84. package/dist/cursor-overlay-script.d.ts +6 -0
  85. package/dist/cursor-overlay-script.js +169 -0
  86. package/dist/dom-css-purger.d.ts +65 -0
  87. package/dist/dom-css-purger.js +333 -0
  88. package/dist/dom-font-inliner.d.ts +45 -0
  89. package/dist/dom-font-inliner.js +148 -0
  90. package/dist/dom-patch-resolver.d.ts +52 -0
  91. package/dist/dom-patch-resolver.js +242 -0
  92. package/dist/dom-serializer.d.ts +82 -0
  93. package/dist/dom-serializer.js +378 -0
  94. package/dist/element-capture.d.ts +1 -41
  95. package/dist/element-capture.js +202 -446
  96. package/dist/env-validation.d.ts +5 -0
  97. package/dist/env-validation.js +29 -0
  98. package/dist/execution-schema.d.ts +4423 -0
  99. package/dist/execution-schema.js +507 -0
  100. package/dist/execution-types.d.ts +886 -0
  101. package/dist/execution-types.js +65 -0
  102. package/dist/fonts-loader.d.ts +14 -0
  103. package/dist/fonts-loader.js +55 -0
  104. package/dist/hybrid-navigator.js +12 -12
  105. package/dist/index.d.ts +9 -6
  106. package/dist/index.js +10 -4
  107. package/dist/legacy/agent-action-recovery.d.ts +45 -0
  108. package/dist/legacy/agent-action-recovery.js +370 -0
  109. package/dist/legacy/agent-message-utils.d.ts +21 -0
  110. package/dist/legacy/agent-message-utils.js +77 -0
  111. package/dist/legacy/agent-url-utils.d.ts +30 -0
  112. package/dist/legacy/agent-url-utils.js +138 -0
  113. package/dist/legacy/agent.d.ts +226 -0
  114. package/dist/legacy/agent.js +6666 -0
  115. package/dist/legacy/clip-orchestrator.d.ts +148 -0
  116. package/dist/legacy/clip-orchestrator.js +957 -0
  117. package/dist/legacy/credential-templates.d.ts +5 -0
  118. package/dist/legacy/credential-templates.js +60 -0
  119. package/dist/legacy/hybrid-navigator.d.ts +138 -0
  120. package/dist/legacy/hybrid-navigator.js +468 -0
  121. package/dist/legacy/llm-usage.d.ts +17 -0
  122. package/dist/legacy/llm-usage.js +45 -0
  123. package/dist/legacy/prompt-cache.d.ts +10 -0
  124. package/dist/legacy/prompt-cache.js +24 -0
  125. package/dist/legacy/prompts.d.ts +175 -0
  126. package/dist/legacy/prompts.js +1038 -0
  127. package/dist/legacy/tools.d.ts +4 -0
  128. package/dist/legacy/tools.js +216 -0
  129. package/dist/legacy/video-agent.d.ts +143 -0
  130. package/dist/legacy/video-agent.js +4788 -0
  131. package/dist/legacy/video-observation.d.ts +36 -0
  132. package/dist/legacy/video-observation.js +192 -0
  133. package/dist/legacy/video-planner.d.ts +12 -0
  134. package/dist/legacy/video-planner.js +501 -0
  135. package/dist/legacy/video-prompts.d.ts +37 -0
  136. package/dist/legacy/video-prompts.js +569 -0
  137. package/dist/legacy/video-tools.d.ts +3 -0
  138. package/dist/legacy/video-tools.js +59 -0
  139. package/dist/legacy/video-variant-state.d.ts +29 -0
  140. package/dist/legacy/video-variant-state.js +80 -0
  141. package/dist/legacy/vision-model.d.ts +17 -0
  142. package/dist/legacy/vision-model.js +74 -0
  143. package/dist/llm-healer.d.ts +63 -0
  144. package/dist/llm-healer.js +166 -0
  145. package/dist/llm-provider.d.ts +29 -0
  146. package/dist/llm-provider.js +80 -0
  147. package/dist/logger.d.ts +6 -2
  148. package/dist/logger.js +15 -1
  149. package/dist/mockup-html.js +35 -25
  150. package/dist/mockup.d.ts +95 -2
  151. package/dist/mockup.js +427 -166
  152. package/dist/mouse-animation.d.ts +2 -2
  153. package/dist/mouse-animation.js +34 -20
  154. package/dist/opcode-actions.d.ts +42 -0
  155. package/dist/opcode-actions.js +511 -0
  156. package/dist/opcode-runner.d.ts +51 -0
  157. package/dist/opcode-runner.js +770 -0
  158. package/dist/openrouter-client.d.ts +40 -0
  159. package/dist/openrouter-client.js +16 -0
  160. package/dist/overlay-engine.d.ts +24 -0
  161. package/dist/overlay-engine.js +176 -0
  162. package/dist/postcondition.d.ts +16 -0
  163. package/dist/postcondition.js +269 -0
  164. package/dist/program-patcher.d.ts +25 -0
  165. package/dist/program-patcher.js +44 -0
  166. package/dist/prompts.d.ts +13 -5
  167. package/dist/prompts.js +224 -351
  168. package/dist/provider-config.d.ts +12 -0
  169. package/dist/provider-config.js +15 -0
  170. package/dist/recovery-chain.d.ts +37 -0
  171. package/dist/recovery-chain.js +350 -0
  172. package/dist/remote-browser.d.ts +28 -4
  173. package/dist/remote-browser.js +60 -5
  174. package/dist/safari-browser-bar.d.ts +15 -0
  175. package/dist/safari-browser-bar.js +95 -0
  176. package/dist/safari-toolbar-asset.d.ts +15 -0
  177. package/dist/safari-toolbar-asset.js +12 -0
  178. package/dist/security.d.ts +2 -1
  179. package/dist/security.js +49 -10
  180. package/dist/selector-resolver.d.ts +34 -0
  181. package/dist/selector-resolver.js +181 -0
  182. package/dist/semantic-resolver.d.ts +35 -0
  183. package/dist/semantic-resolver.js +161 -0
  184. package/dist/server-capture-runtime.d.ts +5 -3
  185. package/dist/server-capture-runtime.js +42 -95
  186. package/dist/server-credit-usage.d.ts +2 -2
  187. package/dist/server-project-webhooks.d.ts +15 -1
  188. package/dist/server-project-webhooks.js +34 -8
  189. package/dist/server-screenshot-watermark.js +27 -5
  190. package/dist/session-profile.js +164 -1
  191. package/dist/sf-pro-symbols.d.ts +1 -0
  192. package/dist/sf-pro-symbols.js +55 -0
  193. package/dist/skill-packaging.d.ts +28 -0
  194. package/dist/skill-packaging.js +169 -0
  195. package/dist/smart-wait.d.ts +27 -0
  196. package/dist/smart-wait.js +81 -0
  197. package/dist/status-bar-render.d.ts +20 -0
  198. package/dist/status-bar-render.js +410 -0
  199. package/dist/status-bar.d.ts +9 -0
  200. package/dist/status-bar.js +298 -14
  201. package/dist/svg-browser-bar.d.ts +33 -0
  202. package/dist/svg-browser-bar.js +206 -0
  203. package/dist/svg-status-bar.d.ts +36 -0
  204. package/dist/svg-status-bar.js +597 -0
  205. package/dist/svg-text.d.ts +61 -0
  206. package/dist/svg-text.js +118 -0
  207. package/dist/tools.js +89 -451
  208. package/dist/types.d.ts +240 -5
  209. package/dist/types.js +23 -1
  210. package/dist/v2/action-verifier.d.ts +29 -0
  211. package/dist/v2/action-verifier.js +133 -0
  212. package/dist/v2/alt-text.d.ts +26 -0
  213. package/dist/v2/alt-text.js +55 -0
  214. package/dist/v2/benchmark.d.ts +59 -0
  215. package/dist/v2/benchmark.js +135 -0
  216. package/dist/v2/capture-strategy.d.ts +30 -0
  217. package/dist/v2/capture-strategy.js +67 -0
  218. package/dist/v2/capture-verification.d.ts +35 -0
  219. package/dist/v2/capture-verification.js +95 -0
  220. package/dist/v2/circuit-breaker.d.ts +42 -0
  221. package/dist/v2/circuit-breaker.js +119 -0
  222. package/dist/v2/cli-runner-local.d.ts +11 -0
  223. package/dist/v2/cli-runner-local.js +91 -0
  224. package/dist/v2/cli-runner.d.ts +34 -0
  225. package/dist/v2/cli-runner.js +300 -0
  226. package/dist/v2/compiler-prompts.d.ts +27 -0
  227. package/dist/v2/compiler-prompts.js +123 -0
  228. package/dist/v2/compiler.d.ts +37 -0
  229. package/dist/v2/compiler.js +147 -0
  230. package/dist/v2/explorer.d.ts +41 -0
  231. package/dist/v2/explorer.js +56 -0
  232. package/dist/v2/index.d.ts +37 -0
  233. package/dist/v2/index.js +31 -0
  234. package/dist/v2/llm-healer.d.ts +62 -0
  235. package/dist/v2/llm-healer.js +166 -0
  236. package/dist/v2/llm-provider.d.ts +29 -0
  237. package/dist/v2/llm-provider.js +80 -0
  238. package/dist/v2/opcode-runner.d.ts +47 -0
  239. package/dist/v2/opcode-runner.js +634 -0
  240. package/dist/v2/overlay-engine.d.ts +24 -0
  241. package/dist/v2/overlay-engine.js +150 -0
  242. package/dist/v2/postcondition.d.ts +16 -0
  243. package/dist/v2/postcondition.js +249 -0
  244. package/dist/v2/program-patcher.d.ts +25 -0
  245. package/dist/v2/program-patcher.js +44 -0
  246. package/dist/v2/recovery-chain.d.ts +30 -0
  247. package/dist/v2/recovery-chain.js +368 -0
  248. package/dist/v2/schema.d.ts +2580 -0
  249. package/dist/v2/schema.js +295 -0
  250. package/dist/v2/selector-resolver.d.ts +34 -0
  251. package/dist/v2/selector-resolver.js +181 -0
  252. package/dist/v2/semantic-resolver.d.ts +35 -0
  253. package/dist/v2/semantic-resolver.js +161 -0
  254. package/dist/v2/smart-wait.d.ts +27 -0
  255. package/dist/v2/smart-wait.js +81 -0
  256. package/dist/v2/types.d.ts +444 -0
  257. package/dist/v2/types.js +19 -0
  258. package/dist/v2/web-playwright-local.d.ts +69 -0
  259. package/dist/v2/web-playwright-local.js +392 -0
  260. package/dist/version.d.ts +1 -0
  261. package/dist/version.js +5 -0
  262. package/dist/video-agent.js +18 -13
  263. package/dist/video-planner.js +2 -1
  264. package/dist/video-prompts.js +3 -3
  265. package/dist/web-playwright-local.d.ts +126 -0
  266. package/dist/web-playwright-local.js +819 -0
  267. package/dist/ws-auth.js +4 -1
  268. package/dist/ws-broadcast.d.ts +34 -0
  269. package/dist/ws-broadcast.js +85 -0
  270. package/dist/ws-connection-limits.d.ts +12 -0
  271. package/dist/ws-connection-limits.js +44 -0
  272. package/dist/ws-handler-utils.d.ts +32 -0
  273. package/dist/ws-handler-utils.js +139 -0
  274. package/dist/ws-handler.js +294 -164
  275. package/dist/ws-metrics-server.d.ts +9 -0
  276. package/dist/ws-metrics-server.js +31 -0
  277. package/dist/ws-server.js +41 -1
  278. package/package.json +51 -34
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Capture Agent — Semantic Target Resolver
3
+ *
4
+ * Resolves a SemanticTarget to a concrete Playwright locator.
5
+ * This is the core mechanism that allows opcodes to work WITHOUT CSS selectors.
6
+ *
7
+ * Resolution cascade:
8
+ * 1. CSS selector (if provided, fast path)
9
+ * 2. Playwright semantic locators (getByRole, getByText, getByLabel, getByPlaceholder)
10
+ * 3. Selector alternates
11
+ * 4. Composite: role + name + near (for disambiguation)
12
+ *
13
+ * All resolution happens via Playwright's built-in locator API — no AKTree needed.
14
+ */
15
+ /**
16
+ * Resolves an element on the page using the best available method.
17
+ * Returns the first visible locator found, or null if nothing matches.
18
+ */
19
+ export async function resolveTarget(page, options) {
20
+ const timeout = options.timeoutMs ?? 3000;
21
+ // 1. Primary CSS selector
22
+ if (options.selector) {
23
+ const locator = page.locator(options.selector).first();
24
+ if (await isVisible(locator, timeout)) {
25
+ return { locator, method: 'selector' };
26
+ }
27
+ }
28
+ // 2. Semantic locators from target
29
+ if (options.target) {
30
+ const resolved = await resolveSemanticTarget(page, options.target, timeout);
31
+ if (resolved)
32
+ return resolved;
33
+ }
34
+ // 3. Alternate selectors
35
+ if (options.selectorAlternates) {
36
+ for (const alt of options.selectorAlternates) {
37
+ const locator = page.locator(alt).first();
38
+ if (await isVisible(locator, timeout)) {
39
+ return { locator, method: 'alternate' };
40
+ }
41
+ }
42
+ }
43
+ return null;
44
+ }
45
+ /**
46
+ * Resolves a SemanticTarget using Playwright's semantic locator API.
47
+ */
48
+ async function resolveSemanticTarget(page, target, timeout) {
49
+ const exact = target.exact ?? false;
50
+ // Strategy A: getByRole with name (most precise)
51
+ if (target.role && (target.text || target.label)) {
52
+ const name = target.label || target.text;
53
+ try {
54
+ let locator = page.getByRole(target.role, {
55
+ name: name,
56
+ exact,
57
+ });
58
+ if (target.near) {
59
+ locator = narrowByNear(page, locator, target.near);
60
+ }
61
+ locator = locator.first();
62
+ if (await isVisible(locator, timeout)) {
63
+ return { locator, method: 'role' };
64
+ }
65
+ }
66
+ catch {
67
+ // Invalid role or no match
68
+ }
69
+ }
70
+ // Strategy B: getByRole without name
71
+ if (target.role && !target.text && !target.label) {
72
+ try {
73
+ let locator = page.getByRole(target.role);
74
+ if (target.near) {
75
+ locator = narrowByNear(page, locator, target.near);
76
+ }
77
+ locator = locator.first();
78
+ if (await isVisible(locator, timeout)) {
79
+ return { locator, method: 'role' };
80
+ }
81
+ }
82
+ catch {
83
+ // Invalid role
84
+ }
85
+ }
86
+ // Strategy C: getByText
87
+ if (target.text) {
88
+ let locator = page.getByText(target.text, { exact });
89
+ if (target.near) {
90
+ locator = narrowByNear(page, locator, target.near);
91
+ }
92
+ locator = locator.first();
93
+ if (await isVisible(locator, timeout)) {
94
+ return { locator, method: 'text' };
95
+ }
96
+ }
97
+ // Strategy D: getByLabel
98
+ if (target.label) {
99
+ let locator = page.getByLabel(target.label, { exact });
100
+ if (target.near) {
101
+ locator = narrowByNear(page, locator, target.near);
102
+ }
103
+ locator = locator.first();
104
+ if (await isVisible(locator, timeout)) {
105
+ return { locator, method: 'label' };
106
+ }
107
+ }
108
+ // Strategy E: getByPlaceholder (for inputs)
109
+ if (target.placeholder) {
110
+ let locator = page.getByPlaceholder(target.placeholder, { exact });
111
+ if (target.near) {
112
+ locator = narrowByNear(page, locator, target.near);
113
+ }
114
+ locator = locator.first();
115
+ if (await isVisible(locator, timeout)) {
116
+ return { locator, method: 'placeholder' };
117
+ }
118
+ }
119
+ // Strategy F: Composite — try role-based with looser matching
120
+ if (target.role) {
121
+ try {
122
+ const allByRole = page.getByRole(target.role);
123
+ const count = await allByRole.count();
124
+ for (let i = 0; i < Math.min(count, 10); i++) {
125
+ const candidate = allByRole.nth(i);
126
+ if (await isVisible(candidate, 500)) {
127
+ const text = await candidate.textContent().catch(() => null);
128
+ if (text && target.text && text.toLowerCase().includes(target.text.toLowerCase())) {
129
+ return { locator: candidate, method: 'composite' };
130
+ }
131
+ }
132
+ }
133
+ }
134
+ catch {
135
+ // No match
136
+ }
137
+ }
138
+ return null;
139
+ }
140
+ /**
141
+ * Narrows a locator to one near a specific text/heading on the page.
142
+ * Uses Playwright's `.filter()` with a parent locator containing the near text.
143
+ */
144
+ function narrowByNear(page, locator, nearText) {
145
+ // Find a section/container that contains the near text
146
+ const container = page.locator(`section:has-text("${escapeForSelector(nearText)}"), div:has-text("${escapeForSelector(nearText)}"), [role="region"]:has-text("${escapeForSelector(nearText)}")`).first();
147
+ return container.locator(locator);
148
+ }
149
+ async function isVisible(locator, timeout) {
150
+ try {
151
+ await locator.waitFor({ state: 'visible', timeout });
152
+ return true;
153
+ }
154
+ catch {
155
+ return false;
156
+ }
157
+ }
158
+ function escapeForSelector(text) {
159
+ return text.replace(/"/g, '\\"').replace(/\n/g, ' ');
160
+ }
161
+ //# sourceMappingURL=semantic-resolver.js.map
@@ -1,5 +1,5 @@
1
1
  import type { SupabaseClient } from '@supabase/supabase-js';
2
- export type BillingPlanId = 'free' | 'starter' | 'pro' | 'business';
2
+ export type BillingPlanId = 'free' | 'maker' | 'team';
3
3
  export interface BillingPlanEntitlements {
4
4
  creditsPerMonth: number;
5
5
  maxProjects: number | null;
@@ -16,13 +16,15 @@ export interface BillingPlanEntitlements {
16
16
  maxParallelCaptures: number;
17
17
  teamMembers: boolean;
18
18
  aiDailyCostLimitUsd: number;
19
- maxApiKeys: number;
20
19
  apiRateLimitRpm: number;
20
+ maxDevLinks: number | null;
21
+ maxCompositions: number | null;
22
+ maxTeamMembersPerProject: number | null;
21
23
  }
22
24
  export interface BillingPlan {
23
25
  id: BillingPlanId;
24
26
  nameKey: BillingPlanId;
25
- descriptionKey: 'forEvaluation' | 'forSoloOperators' | 'forProductTeams' | 'forOperationsHeavyTeams';
27
+ descriptionKey: 'forEvaluation' | 'forMakers' | 'forTeams';
26
28
  monthlyPriceEur: number;
27
29
  yearlyPriceEur: number;
28
30
  highlighted?: boolean;
@@ -11,9 +11,8 @@ export class PlanLimitError extends Error {
11
11
  export const SCREENSHOT_CREDIT_COST = 1;
12
12
  const CREDIT_OVERAGE_CENTS = {
13
13
  free: 0,
14
- starter: 6,
15
- pro: 5,
16
- business: 4,
14
+ maker: 6,
15
+ team: 5,
17
16
  };
18
17
  const STRIPE_ACTIVE_STATUSES = new Set(['active', 'trialing', 'past_due']);
19
18
  const BILLING_PLANS = [
@@ -24,11 +23,11 @@ const BILLING_PLANS = [
24
23
  monthlyPriceEur: 0,
25
24
  yearlyPriceEur: 0,
26
25
  previewCurrent: true,
27
- highlights: ['credits', 'projects', 'presets', 'captureMode', 'retention'],
26
+ highlights: ['credits', 'projects', 'devLinks', 'retention', 'support'],
28
27
  entitlements: {
29
- creditsPerMonth: 10,
28
+ creditsPerMonth: 25,
30
29
  maxProjects: 1,
31
- maxPresetsPerProject: 3,
30
+ maxPresetsPerProject: 2,
32
31
  allowFullPageCapture: true,
33
32
  allowElementCapture: true,
34
33
  retentionDays: 7,
@@ -41,22 +40,24 @@ const BILLING_PLANS = [
41
40
  maxParallelCaptures: 1,
42
41
  teamMembers: false,
43
42
  aiDailyCostLimitUsd: 0.05,
44
- maxApiKeys: 2,
45
43
  apiRateLimitRpm: 10,
44
+ maxDevLinks: 1,
45
+ maxCompositions: 2,
46
+ maxTeamMembersPerProject: null,
46
47
  },
47
48
  },
48
49
  {
49
- id: 'starter',
50
- nameKey: 'starter',
51
- descriptionKey: 'forSoloOperators',
52
- monthlyPriceEur: 19,
53
- yearlyPriceEur: 190,
50
+ id: 'maker',
51
+ nameKey: 'maker',
52
+ descriptionKey: 'forMakers',
53
+ monthlyPriceEur: 15,
54
+ yearlyPriceEur: 144,
54
55
  highlighted: true,
55
- highlights: ['credits', 'projects', 'presets', 'captureMode', 'retention'],
56
+ highlights: ['credits', 'projects', 'devLinks', 'retention', 'parallelCaptures', 'captureCompleteWebhook', 'support'],
56
57
  entitlements: {
57
- creditsPerMonth: 300,
58
+ creditsPerMonth: 100,
58
59
  maxProjects: 3,
59
- maxPresetsPerProject: 10,
60
+ maxPresetsPerProject: 5,
60
61
  allowFullPageCapture: true,
61
62
  allowElementCapture: true,
62
63
  retentionDays: 30,
@@ -64,24 +65,26 @@ const BILLING_PLANS = [
64
65
  maxLanguages: null,
65
66
  maxThemes: null,
66
67
  apiAccess: true,
67
- captureCompleteWebhook: false,
68
+ captureCompleteWebhook: true,
68
69
  priorityQueue: false,
69
- maxParallelCaptures: 1,
70
+ maxParallelCaptures: 2,
70
71
  teamMembers: false,
71
- aiDailyCostLimitUsd: 0.1,
72
- maxApiKeys: 5,
72
+ aiDailyCostLimitUsd: 0.10,
73
73
  apiRateLimitRpm: 60,
74
+ maxDevLinks: 10,
75
+ maxCompositions: 10,
76
+ maxTeamMembersPerProject: null,
74
77
  },
75
78
  },
76
79
  {
77
- id: 'pro',
78
- nameKey: 'pro',
79
- descriptionKey: 'forProductTeams',
80
- monthlyPriceEur: 59,
81
- yearlyPriceEur: 590,
82
- highlights: ['credits', 'projects', 'presets', 'retention', 'captureCompleteWebhook'],
80
+ id: 'team',
81
+ nameKey: 'team',
82
+ descriptionKey: 'forTeams',
83
+ monthlyPriceEur: 49,
84
+ yearlyPriceEur: 468,
85
+ highlights: ['credits', 'projects', 'devLinks', 'retention', 'parallelCaptures', 'teamMembers', 'priorityQueue', 'support'],
83
86
  entitlements: {
84
- creditsPerMonth: 1000,
87
+ creditsPerMonth: 500,
85
88
  maxProjects: null,
86
89
  maxPresetsPerProject: null,
87
90
  allowFullPageCapture: true,
@@ -92,48 +95,14 @@ const BILLING_PLANS = [
92
95
  maxThemes: null,
93
96
  apiAccess: true,
94
97
  captureCompleteWebhook: true,
95
- priorityQueue: false,
96
- maxParallelCaptures: 1,
97
- teamMembers: false,
98
- aiDailyCostLimitUsd: 0.15,
99
- maxApiKeys: 10,
100
- apiRateLimitRpm: 120,
101
- },
102
- },
103
- {
104
- id: 'business',
105
- nameKey: 'business',
106
- descriptionKey: 'forOperationsHeavyTeams',
107
- monthlyPriceEur: 149,
108
- yearlyPriceEur: 1490,
109
- highlights: [
110
- 'credits',
111
- 'projects',
112
- 'presets',
113
- 'retention',
114
- 'captureCompleteWebhook',
115
- 'priorityQueue',
116
- 'parallelCaptures',
117
- 'teamMembers',
118
- ],
119
- entitlements: {
120
- creditsPerMonth: 2500,
121
- maxProjects: null,
122
- maxPresetsPerProject: null,
123
- allowFullPageCapture: true,
124
- allowElementCapture: true,
125
- retentionDays: 365,
126
- watermarkScreenshots: false,
127
- maxLanguages: null,
128
- maxThemes: null,
129
- apiAccess: true,
130
- captureCompleteWebhook: true,
131
98
  priorityQueue: true,
132
- maxParallelCaptures: 4,
99
+ maxParallelCaptures: 5,
133
100
  teamMembers: true,
134
101
  aiDailyCostLimitUsd: 0.15,
135
- maxApiKeys: 25,
136
- apiRateLimitRpm: 300,
102
+ apiRateLimitRpm: 200,
103
+ maxDevLinks: null,
104
+ maxCompositions: null,
105
+ maxTeamMembersPerProject: 5,
137
106
  },
138
107
  },
139
108
  ];
@@ -145,31 +114,19 @@ export function coerceBillingPlanId(value) {
145
114
  return null;
146
115
  switch (value) {
147
116
  case 'free':
148
- case 'starter':
149
- case 'pro':
150
- case 'business':
117
+ case 'maker':
118
+ case 'team':
151
119
  return value;
152
120
  default:
153
121
  return null;
154
122
  }
155
123
  }
156
- function getMetadataBillingPlanId(user) {
157
- const metadata = user?.user_metadata;
158
- if (!metadata)
159
- return null;
160
- for (const key of ['billingPlan', 'billing_plan', 'plan']) {
161
- const planId = coerceBillingPlanId(metadata[key]);
162
- if (planId)
163
- return planId;
164
- }
165
- return null;
166
- }
167
124
  function getServerDefaultBillingPlanId() {
168
125
  return (coerceBillingPlanId(process.env.DEFAULT_BILLING_PLAN)
169
126
  ?? coerceBillingPlanId(process.env.NEXT_PUBLIC_DEFAULT_BILLING_PLAN)
170
127
  ?? 'free');
171
128
  }
172
- function resolvePlanFromBillingAccount(account, metadataPlanId, defaultPlanId) {
129
+ function resolvePlanFromBillingAccount(account, defaultPlanId) {
173
130
  const adminPlanId = coerceBillingPlanId(account?.admin_override_plan_id);
174
131
  if (adminPlanId) {
175
132
  return { planId: adminPlanId, source: 'admin_override' };
@@ -178,9 +135,6 @@ function resolvePlanFromBillingAccount(account, metadataPlanId, defaultPlanId) {
178
135
  if (stripePlanId && shouldUseStripePlan(account?.stripe_subscription_status)) {
179
136
  return { planId: stripePlanId, source: 'stripe' };
180
137
  }
181
- if (metadataPlanId) {
182
- return { planId: metadataPlanId, source: 'metadata' };
183
- }
184
138
  return { planId: defaultPlanId, source: 'default' };
185
139
  }
186
140
  export async function getBillingAccountForUser(supabase, userId) {
@@ -198,13 +152,8 @@ export async function getBillingAccountForUser(supabase, userId) {
198
152
  return data ?? null;
199
153
  }
200
154
  async function getResolvedBillingPlanForUserId(supabase, userId) {
201
- const { data, error } = await supabase.auth.admin.getUserById(userId);
202
- if (error) {
203
- throw new Error(`Failed to load user billing plan: ${error.message}`);
204
- }
205
- const metadataPlanId = getMetadataBillingPlanId(data.user);
206
155
  const account = await getBillingAccountForUser(supabase, userId);
207
- const resolved = resolvePlanFromBillingAccount(account, metadataPlanId, getServerDefaultBillingPlanId());
156
+ const resolved = resolvePlanFromBillingAccount(account, getServerDefaultBillingPlanId());
208
157
  return getBillingPlan(resolved.planId);
209
158
  }
210
159
  export async function getProjectOwnerBillingContext(supabase, projectId) {
@@ -234,12 +183,10 @@ export function isYearlySubscription(account) {
234
183
  }
235
184
  export function getStripeOveragePriceIdForPlan(planId) {
236
185
  switch (planId) {
237
- case 'starter':
238
- return process.env.STRIPE_PRICE_ID_STARTER_OVERAGE ?? null;
239
- case 'pro':
240
- return process.env.STRIPE_PRICE_ID_PRO_OVERAGE ?? null;
241
- case 'business':
242
- return process.env.STRIPE_PRICE_ID_BUSINESS_OVERAGE ?? null;
186
+ case 'maker':
187
+ return process.env.STRIPE_PRICE_ID_MAKER_OVERAGE ?? null;
188
+ case 'team':
189
+ return process.env.STRIPE_PRICE_ID_TEAM_OVERAGE ?? null;
243
190
  case 'free':
244
191
  return null;
245
192
  }
@@ -1,8 +1,8 @@
1
1
  import type { SupabaseClient } from '@supabase/supabase-js';
2
- export type CreditUsageType = 'screenshot' | 'clip' | 'video' | 'preset_analysis' | 'ai_chat';
2
+ export type CreditUsageType = 'screenshot' | 'clip' | 'video' | 'preset_analysis' | 'ai_chat' | 'interactive_demo_state';
3
3
  export declare function recordCreditUsage(supabase: SupabaseClient, params: {
4
4
  userId: string;
5
- projectId: string;
5
+ projectId: string | null;
6
6
  presetId?: string | null;
7
7
  type: CreditUsageType;
8
8
  credits: number;
@@ -29,7 +29,20 @@ export interface CaptureWebhookPayload {
29
29
  total_captures: number;
30
30
  success_count: number;
31
31
  results: CaptureWebhookPayloadResult[];
32
+ /** IDs of screenshot_endpoints affected by this capture run (for proxy cache invalidation). */
33
+ affected_endpoint_ids: string[];
32
34
  }
35
+ export interface EndpointChangedWebhookPayload {
36
+ event: 'endpoint.changed';
37
+ project_id: string;
38
+ preset_id: string | null;
39
+ timestamp: string;
40
+ created_endpoint_ids: string[];
41
+ deleted_endpoint_ids: string[];
42
+ /** Full list of currently active endpoint IDs for the project. */
43
+ current_endpoint_ids: string[];
44
+ }
45
+ export type WebhookPayload = CaptureWebhookPayload | EndpointChangedWebhookPayload;
33
46
  export declare function getProjectWebhookConfig(supabase: SupabaseClient, projectId: string): Promise<ProjectWebhookConfig | null>;
34
47
  export declare function buildCaptureWebhookPayload(params: {
35
48
  runId: string;
@@ -37,9 +50,10 @@ export declare function buildCaptureWebhookPayload(params: {
37
50
  presetId?: string | null;
38
51
  completedAt?: string;
39
52
  results: CaptureWebhookPayloadResult[];
53
+ affectedEndpointIds?: string[];
40
54
  }): CaptureWebhookPayload;
41
55
  export declare function dispatchProjectCaptureWebhook(params: {
42
56
  config: ProjectWebhookConfig;
43
- payload: CaptureWebhookPayload;
57
+ payload: WebhookPayload;
44
58
  }): Promise<void>;
45
59
  export declare function encryptProjectWebhookSigningSecret(plaintext: string): string;
@@ -64,8 +64,11 @@ export function buildCaptureWebhookPayload(params) {
64
64
  iterations: result.iterations,
65
65
  finalScreenshotUrl: result.finalScreenshotUrl,
66
66
  })),
67
+ affected_endpoint_ids: params.affectedEndpointIds ?? [],
67
68
  };
68
69
  }
70
+ const WEBHOOK_RETRY_DELAYS = [0, 1_000, 3_000, 9_000];
71
+ const WEBHOOK_TIMEOUT_MS = 10_000;
69
72
  export async function dispatchProjectCaptureWebhook(params) {
70
73
  const body = JSON.stringify(params.payload);
71
74
  const timestamp = Math.floor(Date.now() / 1000).toString();
@@ -81,15 +84,38 @@ export async function dispatchProjectCaptureWebhook(params) {
81
84
  .digest('hex');
82
85
  headers['X-AutoKap-Signature'] = signature;
83
86
  }
84
- const response = await fetch(params.config.url, {
85
- method: 'POST',
86
- headers,
87
- body,
88
- });
89
- if (!response.ok) {
90
- const responseText = await response.text().catch(() => '');
91
- throw new Error(`Webhook responded with ${response.status}${responseText ? `: ${responseText.slice(0, 300)}` : ''}`);
87
+ let lastError = null;
88
+ for (let attempt = 0; attempt < WEBHOOK_RETRY_DELAYS.length; attempt++) {
89
+ if (attempt > 0) {
90
+ await new Promise((resolve) => setTimeout(resolve, WEBHOOK_RETRY_DELAYS[attempt]));
91
+ }
92
+ try {
93
+ const response = await fetch(params.config.url, {
94
+ method: 'POST',
95
+ headers,
96
+ body,
97
+ signal: AbortSignal.timeout(WEBHOOK_TIMEOUT_MS),
98
+ });
99
+ if (response.ok)
100
+ return;
101
+ // Don't retry on 4xx client errors (except 429 rate limiting)
102
+ if (response.status >= 400 && response.status < 500 && response.status !== 429) {
103
+ const responseText = await response.text().catch(() => '');
104
+ throw new Error(`Webhook responded with ${response.status}${responseText ? `: ${responseText.slice(0, 300)}` : ''}`);
105
+ }
106
+ // 5xx or 429 — retry
107
+ const responseText = await response.text().catch(() => '');
108
+ lastError = new Error(`Webhook responded with ${response.status}${responseText ? `: ${responseText.slice(0, 300)}` : ''}`);
109
+ }
110
+ catch (error) {
111
+ lastError = error;
112
+ // Network errors and timeouts are retryable
113
+ if (error.name === 'AbortError') {
114
+ lastError = new Error(`Webhook timed out after ${WEBHOOK_TIMEOUT_MS}ms`);
115
+ }
116
+ }
92
117
  }
118
+ throw lastError ?? new Error('Webhook delivery failed after retries');
93
119
  }
94
120
  export function encryptProjectWebhookSigningSecret(plaintext) {
95
121
  return JSON.stringify(encrypt(plaintext, getWebhookEncryptionSecret()));
@@ -7,11 +7,18 @@ function escapeXml(value) {
7
7
  .replaceAll('"', '&quot;')
8
8
  .replaceAll('\'', '&apos;');
9
9
  }
10
- export async function applyScreenshotWatermark(buffer, label = 'AutoKap Free') {
11
- const image = sharp(buffer);
12
- const metadata = await image.metadata();
13
- const width = metadata.width ?? 1440;
14
- const height = metadata.height ?? 900;
10
+ /** LRU cache for watermark SVG overlays avoids regenerating tiles for repeated dimensions. */
11
+ const SVG_CACHE_MAX = 20;
12
+ const svgOverlayCache = new Map();
13
+ function getOrBuildSvgOverlay(width, height, label) {
14
+ const cacheKey = `${width}:${height}:${label}`;
15
+ const cached = svgOverlayCache.get(cacheKey);
16
+ if (cached) {
17
+ // Move to end (LRU refresh)
18
+ svgOverlayCache.delete(cacheKey);
19
+ svgOverlayCache.set(cacheKey, cached);
20
+ return cached;
21
+ }
15
22
  const fontSize = Math.max(18, Math.round(Math.min(width, height) * 0.035));
16
23
  const tileGap = fontSize * 4;
17
24
  const safeLabel = escapeXml(label);
@@ -27,6 +34,21 @@ export async function applyScreenshotWatermark(buffer, label = 'AutoKap Free') {
27
34
  ${tiles.join('')}
28
35
  </g>
29
36
  </svg>`);
37
+ // Evict oldest entry if cache is full
38
+ if (svgOverlayCache.size >= SVG_CACHE_MAX) {
39
+ const firstKey = svgOverlayCache.keys().next().value;
40
+ if (firstKey !== undefined)
41
+ svgOverlayCache.delete(firstKey);
42
+ }
43
+ svgOverlayCache.set(cacheKey, overlay);
44
+ return overlay;
45
+ }
46
+ export async function applyScreenshotWatermark(buffer, label = 'AutoKap Free') {
47
+ const image = sharp(buffer);
48
+ const metadata = await image.metadata();
49
+ const width = metadata.width ?? 1440;
50
+ const height = metadata.height ?? 900;
51
+ const overlay = getOrBuildSvgOverlay(width, height, label);
30
52
  return image.composite([{ input: overlay }]).png().toBuffer();
31
53
  }
32
54
  export async function applyPlanScreenshotWatermark(plan, buffer) {