@vfrey/vfrey 0.0.1 → 1.0.0-beta.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.
Files changed (610) hide show
  1. package/LICENSE +33 -0
  2. package/README.md +78 -3
  3. package/accounts.example.json +61 -0
  4. package/accounts.first-run.json +41 -0
  5. package/bin/vfrey.mjs +36 -0
  6. package/integration-tools/README.md +43 -0
  7. package/integration-tools/image/pillow.md +32 -0
  8. package/integration-tools/image/playwright.md +33 -0
  9. package/integration-tools/image/resvg.md +36 -0
  10. package/integration-tools/image/satori.md +36 -0
  11. package/integration-tools/image/sharp.md +38 -0
  12. package/integration-tools/video/blender.md +34 -0
  13. package/integration-tools/video/ffmpeg.md +41 -0
  14. package/integration-tools/video/manim.md +37 -0
  15. package/integration-tools/video/motion-canvas.md +37 -0
  16. package/integration-tools/video/remotion.md +50 -0
  17. package/integration-tools/video/revideo.md +32 -0
  18. package/package.json +74 -6
  19. package/skills/vfrey-orchestrator/SKILL.md +15 -0
  20. package/skills/vfrey-orchestrator/channel-video/SKILL.md +41 -0
  21. package/skills/vfrey-product/SKILL.md +63 -0
  22. package/skills/vfrey-product/examples/concurrency-vs-parallelism/framey/cook-one.svg +14 -0
  23. package/skills/vfrey-product/examples/concurrency-vs-parallelism/framey/cook-two.svg +22 -0
  24. package/skills/vfrey-product/examples/concurrency-vs-parallelism/framey/index.html +70 -0
  25. package/skills/vfrey-product/examples/concurrency-vs-parallelism/remotion/cook-one.svg +14 -0
  26. package/skills/vfrey-product/examples/concurrency-vs-parallelism/remotion/cook-two.svg +22 -0
  27. package/skills/vfrey-product/examples/concurrency-vs-parallelism/remotion/index.tsx +49 -0
  28. package/skills/vfrey-product/examples/concurrency-vs-parallelism/script.json +15 -0
  29. package/skills/vfrey-product/examples/octopus-facts/index.html +60 -0
  30. package/skills/vfrey-product/examples/octopus-facts/octopus.svg +8 -0
  31. package/skills/vfrey-product/examples/octopus-facts/script.json +14 -0
  32. package/skills/vfrey-product/push/SKILL.md +15 -0
  33. package/skills/vfrey-product/scenes/NOTICE +5 -0
  34. package/skills/vfrey-product/scenes/blocks.md +57 -0
  35. package/skills/vfrey-product/scenes/craft.md +118 -0
  36. package/skills/vfrey-product/scenes/motion.md +88 -0
  37. package/src/analytics/dashboard.ts +109 -0
  38. package/src/analytics/index.ts +260 -0
  39. package/src/api/client.ts +361 -0
  40. package/src/api/cloud-files.ts +197 -0
  41. package/src/api/cloud-runs.ts +75 -0
  42. package/src/api/cloud.ts +413 -0
  43. package/src/api/commands.ts +330 -0
  44. package/src/api/config.ts +34 -0
  45. package/src/api/creators.ts +463 -0
  46. package/src/api/credentials.ts +152 -0
  47. package/src/api/mail.ts +333 -0
  48. package/src/api/topics.ts +207 -0
  49. package/src/api/types.ts +273 -0
  50. package/src/cli.ts +468 -0
  51. package/src/cloud/bundle.ts +70 -0
  52. package/src/cloud/cloudrun-executor.ts +237 -0
  53. package/src/cloud/executor.ts +281 -0
  54. package/src/cloud/gcs-sign.ts +76 -0
  55. package/src/cloud/job.ts +106 -0
  56. package/src/cloud/remote-job.ts +67 -0
  57. package/src/cloud/render-job.ts +191 -0
  58. package/src/config.ts +309 -0
  59. package/src/dashboard-link.ts +180 -0
  60. package/src/dashboard-start.ts +103 -0
  61. package/src/desk/channel.ts +64 -0
  62. package/src/desk/cli.ts +216 -0
  63. package/src/desk/creators-route.ts +129 -0
  64. package/src/desk/fonts/JetBrainsMono-OFL.txt +93 -0
  65. package/src/desk/fonts/google-sans-flex-latin.woff2 +0 -0
  66. package/src/desk/fonts/jetbrains-mono-medium.woff2 +0 -0
  67. package/src/desk/http.ts +460 -0
  68. package/src/desk/mail-route.ts +103 -0
  69. package/src/desk/overlay.ts +112 -0
  70. package/src/desk/preview.ts +422 -0
  71. package/src/desk/screens.ts +149 -0
  72. package/src/desk/secrets.ts +143 -0
  73. package/src/desk/series.ts +127 -0
  74. package/src/desk/state.ts +77 -0
  75. package/src/desk/studio-route.ts +119 -0
  76. package/src/desk/tick-runner.ts +66 -0
  77. package/src/desk/tick.ts +56 -0
  78. package/src/desk/topics-route.ts +41 -0
  79. package/src/desk/ui/app.css +505 -0
  80. package/src/desk/ui/app.js +185 -0
  81. package/src/desk/ui/apple-icon.png +0 -0
  82. package/src/desk/ui/components.js +79 -0
  83. package/src/desk/ui/core.js +156 -0
  84. package/src/desk/ui/favicon.ico +0 -0
  85. package/src/desk/ui/icon.svg +1 -0
  86. package/src/desk/ui/icons.js +49 -0
  87. package/src/desk/ui/index.html +41 -0
  88. package/src/desk/ui/metrics-math.d.ts +22 -0
  89. package/src/desk/ui/metrics-math.js +135 -0
  90. package/src/desk/ui/theme.js +5 -0
  91. package/src/desk/ui/views-creators.js +209 -0
  92. package/src/desk/ui/views-keys.js +114 -0
  93. package/src/desk/ui/views-mail.js +188 -0
  94. package/src/desk/ui/views-misc.js +123 -0
  95. package/src/desk/ui/views-review.js +119 -0
  96. package/src/desk/ui/views-runs.js +350 -0
  97. package/src/desk/ui/views-screens.js +163 -0
  98. package/src/desk/ui/views-series.js +318 -0
  99. package/src/desk/ui/views-topics.js +87 -0
  100. package/src/desk/verbs.ts +361 -0
  101. package/src/doctor.ts +212 -0
  102. package/src/drain.ts +14 -0
  103. package/src/engage/index.ts +217 -0
  104. package/src/generate/index.ts +110 -0
  105. package/src/generate/script.ts +152 -0
  106. package/src/generate/title.ts +78 -0
  107. package/src/help.ts +252 -0
  108. package/src/home.ts +45 -0
  109. package/src/llm/client.ts +177 -0
  110. package/src/log.ts +7 -0
  111. package/src/oauth/tokens.ts +189 -0
  112. package/src/oauth/vault.ts +72 -0
  113. package/src/pipeline/review.ts +642 -0
  114. package/src/pipeline/run.ts +443 -0
  115. package/src/pipeline/series-guard.ts +26 -0
  116. package/src/pipeline/source-fetch.ts +69 -0
  117. package/src/pipeline/stages.ts +728 -0
  118. package/src/pipeline/topics-source.ts +90 -0
  119. package/src/product/commands.ts +296 -0
  120. package/src/product/config-file.ts +38 -0
  121. package/src/product/engine-choice.ts +89 -0
  122. package/src/product/engines.ts +103 -0
  123. package/src/product/insights.ts +50 -0
  124. package/src/product/keys.ts +67 -0
  125. package/src/product/paths.ts +18 -0
  126. package/src/product/probes.ts +88 -0
  127. package/src/product/push-flow.ts +90 -0
  128. package/src/product/render-video.ts +21 -0
  129. package/src/product/short.ts +62 -0
  130. package/src/product/update.ts +32 -0
  131. package/src/project/canonical.ts +14 -0
  132. package/src/project/commands.ts +177 -0
  133. package/src/project/dashboard-status.ts +28 -0
  134. package/src/project/discover.ts +19 -0
  135. package/src/project/index-file.ts +73 -0
  136. package/src/project/marker.ts +92 -0
  137. package/src/project/migrate.ts +201 -0
  138. package/src/project/names.ts +27 -0
  139. package/src/project/notice.ts +16 -0
  140. package/src/project/open.ts +88 -0
  141. package/src/project/scaffold.ts +112 -0
  142. package/src/project/templates.ts +42 -0
  143. package/src/project/videos.ts +64 -0
  144. package/src/publish/facebook.ts +91 -0
  145. package/src/publish/index.ts +12 -0
  146. package/src/publish/instagram.ts +97 -0
  147. package/src/publish/rate.ts +62 -0
  148. package/src/publish/session.ts +242 -0
  149. package/src/publish/tiktok.ts +202 -0
  150. package/src/publish/youtube.ts +177 -0
  151. package/src/queue/desk-ops.ts +1170 -0
  152. package/src/queue/seal.ts +3 -0
  153. package/src/queue/store.ts +1006 -0
  154. package/src/remotion/AiLabel.tsx +26 -0
  155. package/src/remotion/Root.tsx +73 -0
  156. package/src/remotion/defaults.ts +26 -0
  157. package/src/remotion/films/claude/ClaudeFilm.tsx +1014 -0
  158. package/src/remotion/films/engine/EngineMark.tsx +17 -0
  159. package/src/remotion/films/rea/ReaShort.tsx +552 -0
  160. package/src/remotion/films/rea/drawings.tsx +907 -0
  161. package/src/remotion/films/rea/timing.ts +144 -0
  162. package/src/remotion/index.ts +4 -0
  163. package/src/remotion/templates/EditorialSplit.tsx +39 -0
  164. package/src/remotion/templates/KineticType.tsx +39 -0
  165. package/src/remotion/templates/SignalBoard.tsx +50 -0
  166. package/src/remotion/timing.ts +22 -0
  167. package/src/render/chrome.ts +78 -0
  168. package/src/render/engine-mark.ts +29 -0
  169. package/src/render/framey-template.ts +130 -0
  170. package/src/render/html-engine.ts +149 -0
  171. package/src/render/node-crypto-stub.ts +11 -0
  172. package/src/render/probe.ts +29 -0
  173. package/src/render/props.ts +17 -0
  174. package/src/render/vertical-short.ts +35 -0
  175. package/src/render/webpack.ts +33 -0
  176. package/src/render/worker.ts +65 -0
  177. package/src/scene/assets/fonts/TitanOne-OFL.txt +94 -0
  178. package/src/scene/assets/fonts/titan-one.woff2 +0 -0
  179. package/src/scene/assets/gsap/LICENSE.txt +8 -0
  180. package/src/scene/assets/gsap/gsap.min.js +11 -0
  181. package/src/scene/audio.ts +54 -0
  182. package/src/scene/blocks/LICENSE +190 -0
  183. package/src/scene/blocks/NOTICE +5 -0
  184. package/src/scene/blocks/bar-chart-race/bar-chart-race.html +585 -0
  185. package/src/scene/blocks/beat-freeze-cut/beat-freeze-cut.html +874 -0
  186. package/src/scene/blocks/camcorder-hud/camcorder-hud.html +164 -0
  187. package/src/scene/blocks/camera-dolly-zoom/camera-dolly-zoom.html +355 -0
  188. package/src/scene/blocks/code-diff/code-diff.html +817 -0
  189. package/src/scene/blocks/code-snippet-apple-terminal-pro/code-snippet-apple-terminal-pro.html +248 -0
  190. package/src/scene/blocks/code-typing/code-typing.html +764 -0
  191. package/src/scene/blocks/data-chart/data-chart.html +452 -0
  192. package/src/scene/blocks/flowchart-vertical/flowchart-vertical.html +454 -0
  193. package/src/scene/blocks/hw-scribble-transition/hw-scribble-transition.html +153 -0
  194. package/src/scene/blocks/index.json +824 -0
  195. package/src/scene/blocks/lt-accent-underline/lt-accent-underline.html +107 -0
  196. package/src/scene/blocks/lt-bold-block/lt-bold-block.html +109 -0
  197. package/src/scene/blocks/lt-clean-bar/lt-clean-bar.html +112 -0
  198. package/src/scene/blocks/lt-dark-card/lt-dark-card.html +111 -0
  199. package/src/scene/blocks/lt-kicker-name/lt-kicker-name.html +114 -0
  200. package/src/scene/blocks/lt-mask-reveal/lt-mask-reveal.html +120 -0
  201. package/src/scene/blocks/lt-neon-border/lt-neon-border.html +391 -0
  202. package/src/scene/blocks/lt-stack-bars/lt-stack-bars.html +109 -0
  203. package/src/scene/blocks/macos-notification/macos-notification.html +194 -0
  204. package/src/scene/blocks/mk-background/mk-background.html +236 -0
  205. package/src/scene/blocks/mk-callout-highlight/mk-callout-highlight.html +183 -0
  206. package/src/scene/blocks/mk-clone-wall-transition/mk-clone-wall-transition.html +226 -0
  207. package/src/scene/blocks/mk-line-graph/mk-line-graph.html +293 -0
  208. package/src/scene/blocks/mk-progress-stat/mk-progress-stat.html +186 -0
  209. package/src/scene/blocks/mk-specs-list/mk-specs-list.html +223 -0
  210. package/src/scene/blocks/news-ticker/news-ticker.html +409 -0
  211. package/src/scene/blocks/organic-light-leak-overlay/organic-light-leak-overlay.html +126 -0
  212. package/src/scene/blocks/oscilloscope-trace/oscilloscope-trace.html +519 -0
  213. package/src/scene/blocks/snow/snow.html +205 -0
  214. package/src/scene/blocks/split-flap-board/split-flap-board.html +347 -0
  215. package/src/scene/blocks/spotify-card/spotify-card.html +294 -0
  216. package/src/scene/blocks/starfield/starfield.html +188 -0
  217. package/src/scene/blocks/thread-message-stack/thread-message-stack.html +239 -0
  218. package/src/scene/blocks/week-in-merges/week-in-merges.html +470 -0
  219. package/src/scene/blocks/x-post/x-post.html +437 -0
  220. package/src/scene/blocks/yt-comment-card/yt-comment-card.html +319 -0
  221. package/src/scene/blocks/yt-lcd-background/yt-lcd-background.html +307 -0
  222. package/src/scene/blocks/yt-prism-title/yt-prism-title.html +205 -0
  223. package/src/scene/blocks.ts +229 -0
  224. package/src/scene/command.ts +272 -0
  225. package/src/scene/figure.ts +181 -0
  226. package/src/scene/glyphs.ts +107 -0
  227. package/src/scene/init.ts +86 -0
  228. package/src/scene/inspect/css-tree.d.ts +6 -0
  229. package/src/scene/inspect/page-scripts.ts +272 -0
  230. package/src/scene/inspect/report.ts +405 -0
  231. package/src/scene/inspect/run.ts +200 -0
  232. package/src/scene/inspect/source.ts +236 -0
  233. package/src/scene/label.ts +131 -0
  234. package/src/scene/net-guard.ts +74 -0
  235. package/src/scene/render.ts +292 -0
  236. package/src/scene/runtime/browser.ts +199 -0
  237. package/src/scene/runtime/core.ts +181 -0
  238. package/src/scene/runtime/react.tsx +115 -0
  239. package/src/scene/runtime/transitions.ts +133 -0
  240. package/src/scene/sanitize.ts +181 -0
  241. package/src/scene/scene.ts +152 -0
  242. package/src/scene/studio-command.ts +48 -0
  243. package/src/scene/studio-skin.ts +59 -0
  244. package/src/scene/studio.ts +337 -0
  245. package/src/scene/supply.ts +111 -0
  246. package/src/scene/timing.ts +288 -0
  247. package/src/scene/transitions/LICENSE +190 -0
  248. package/src/scene/transitions/NOTICE +5 -0
  249. package/src/scene/transitions/SOURCE.json +24 -0
  250. package/src/scene/transitions/transitions.global.js +38 -0
  251. package/src/scene/transitions.ts +26 -0
  252. package/src/service/all-projects.ts +153 -0
  253. package/src/service/commands.ts +256 -0
  254. package/src/service/due.ts +82 -0
  255. package/src/service/lock.ts +101 -0
  256. package/src/service/log-file.ts +56 -0
  257. package/src/service/state.ts +41 -0
  258. package/src/service/units.ts +90 -0
  259. package/src/service/worker.ts +51 -0
  260. package/src/skill-agents.ts +74 -0
  261. package/src/skill-install.ts +334 -0
  262. package/src/sync-write.ts +21 -0
  263. package/src/tick-report.ts +205 -0
  264. package/src/tts.ts +124 -0
  265. package/vendor/@vfrey/contracts/dist/account.d.ts +97 -0
  266. package/vendor/@vfrey/contracts/dist/account.js +27 -0
  267. package/vendor/@vfrey/contracts/dist/checks.d.ts +8 -0
  268. package/vendor/@vfrey/contracts/dist/checks.js +1 -0
  269. package/vendor/@vfrey/contracts/dist/credentials/crypto.d.ts +4 -0
  270. package/vendor/@vfrey/contracts/dist/credentials/crypto.js +38 -0
  271. package/vendor/@vfrey/contracts/dist/domain/advice-persona.d.ts +10 -0
  272. package/vendor/@vfrey/contracts/dist/domain/advice-persona.js +24 -0
  273. package/vendor/@vfrey/contracts/dist/domain/backoff.d.ts +13 -0
  274. package/vendor/@vfrey/contracts/dist/domain/backoff.js +27 -0
  275. package/vendor/@vfrey/contracts/dist/domain/cadence.d.ts +29 -0
  276. package/vendor/@vfrey/contracts/dist/domain/cadence.js +95 -0
  277. package/vendor/@vfrey/contracts/dist/domain/creators.d.ts +146 -0
  278. package/vendor/@vfrey/contracts/dist/domain/creators.js +2 -0
  279. package/vendor/@vfrey/contracts/dist/domain/disclosure.d.ts +127 -0
  280. package/vendor/@vfrey/contracts/dist/domain/disclosure.js +250 -0
  281. package/vendor/@vfrey/contracts/dist/domain/errors.d.ts +34 -0
  282. package/vendor/@vfrey/contracts/dist/domain/errors.js +68 -0
  283. package/vendor/@vfrey/contracts/dist/domain/redact.d.ts +1 -0
  284. package/vendor/@vfrey/contracts/dist/domain/redact.js +21 -0
  285. package/vendor/@vfrey/contracts/dist/domain/revenue.d.ts +13 -0
  286. package/vendor/@vfrey/contracts/dist/domain/revenue.js +16 -0
  287. package/vendor/@vfrey/contracts/dist/domain/safety.d.ts +20 -0
  288. package/vendor/@vfrey/contracts/dist/domain/safety.js +61 -0
  289. package/vendor/@vfrey/contracts/dist/domain/similarity.d.ts +13 -0
  290. package/vendor/@vfrey/contracts/dist/domain/similarity.js +100 -0
  291. package/vendor/@vfrey/contracts/dist/domain/templates.d.ts +18 -0
  292. package/vendor/@vfrey/contracts/dist/domain/templates.js +67 -0
  293. package/vendor/@vfrey/contracts/dist/domain/tiktok-chunks.d.ts +19 -0
  294. package/vendor/@vfrey/contracts/dist/domain/tiktok-chunks.js +52 -0
  295. package/vendor/@vfrey/contracts/dist/domain/topics.d.ts +78 -0
  296. package/vendor/@vfrey/contracts/dist/domain/topics.js +4 -0
  297. package/vendor/@vfrey/contracts/dist/domain/types.d.ts +216 -0
  298. package/vendor/@vfrey/contracts/dist/domain/types.js +1 -0
  299. package/vendor/@vfrey/contracts/dist/domain/variation.d.ts +57 -0
  300. package/vendor/@vfrey/contracts/dist/domain/variation.js +278 -0
  301. package/vendor/@vfrey/contracts/dist/events.d.ts +20 -0
  302. package/vendor/@vfrey/contracts/dist/events.js +1 -0
  303. package/vendor/@vfrey/contracts/dist/http.d.ts +11 -0
  304. package/vendor/@vfrey/contracts/dist/http.js +37 -0
  305. package/vendor/@vfrey/contracts/dist/index.d.ts +22 -0
  306. package/vendor/@vfrey/contracts/dist/index.js +22 -0
  307. package/vendor/@vfrey/contracts/dist/log.d.ts +2 -0
  308. package/vendor/@vfrey/contracts/dist/log.js +10 -0
  309. package/vendor/@vfrey/contracts/dist/mail.d.ts +55 -0
  310. package/vendor/@vfrey/contracts/dist/mail.js +1 -0
  311. package/vendor/@vfrey/contracts/package.json +18 -0
  312. package/vendor/@vfrey/ingest/dist/index.d.ts +41 -0
  313. package/vendor/@vfrey/ingest/dist/index.js +221 -0
  314. package/vendor/@vfrey/ingest/dist/parse.d.ts +5 -0
  315. package/vendor/@vfrey/ingest/dist/parse.js +165 -0
  316. package/vendor/@vfrey/ingest/package.json +21 -0
  317. package/vendor/framey/LICENSE +190 -0
  318. package/vendor/framey/NOTICE +15 -0
  319. package/vendor/framey/SOURCE.json +24 -0
  320. package/vendor/framey/STUDIO-SOURCE.json +9 -0
  321. package/vendor/framey/bin/framey-localize-fonts.mjs +12 -0
  322. package/vendor/framey/bin/framey.mjs +16 -0
  323. package/vendor/framey/dist/add-VMJD5KBS.js +75 -0
  324. package/vendor/framey/dist/animatedGifPrep-QPKGJ6PM.js +43 -0
  325. package/vendor/framey/dist/api.d.ts +211 -0
  326. package/vendor/framey/dist/api.js +76 -0
  327. package/vendor/framey/dist/appHistory-WW56FZTT.js +31 -0
  328. package/vendor/framey/dist/asset-WQKGOELE.js +26 -0
  329. package/vendor/framey/dist/audio-RSJWVWRA.js +1936 -0
  330. package/vendor/framey/dist/batchRender-3HPICDCT.js +366 -0
  331. package/vendor/framey/dist/beats-HL2BDUZI.js +273 -0
  332. package/vendor/framey/dist/benchmark-RWCWHI5Z.js +230 -0
  333. package/vendor/framey/dist/browser-ECYET3Q2.js +206 -0
  334. package/vendor/framey/dist/bundleWithLocalizedFonts-ALYBQEQT.js +52 -0
  335. package/vendor/framey/dist/captureCompositionFrame-4DA6SEH2.js +94 -0
  336. package/vendor/framey/dist/catalog-5JVDEUWK.js +979 -0
  337. package/vendor/framey/dist/catch-up-NEBCL5NO.js +106 -0
  338. package/vendor/framey/dist/check-F5N544ML.js +111 -0
  339. package/vendor/framey/dist/checkBrowser-LZ66CMJG.js +110 -0
  340. package/vendor/framey/dist/chunk-2K7Z2HVP.js +372 -0
  341. package/vendor/framey/dist/chunk-2UZQHDM7.js +323 -0
  342. package/vendor/framey/dist/chunk-2X4PQEYM.js +34 -0
  343. package/vendor/framey/dist/chunk-3422KMTD.js +168 -0
  344. package/vendor/framey/dist/chunk-3FYD4YEK.js +72 -0
  345. package/vendor/framey/dist/chunk-3GXQPCJC.js +682 -0
  346. package/vendor/framey/dist/chunk-3LM6YPBR.js +179 -0
  347. package/vendor/framey/dist/chunk-442JNXRM.js +20 -0
  348. package/vendor/framey/dist/chunk-4BNN5FGX.js +182 -0
  349. package/vendor/framey/dist/chunk-4P7NX5BM.js +11532 -0
  350. package/vendor/framey/dist/chunk-4UMPIPCQ.js +88 -0
  351. package/vendor/framey/dist/chunk-4YYJOFKS.js +28 -0
  352. package/vendor/framey/dist/chunk-54HJ63Q2.js +29 -0
  353. package/vendor/framey/dist/chunk-5ETJX6WM.js +89 -0
  354. package/vendor/framey/dist/chunk-5SG54JRS.js +68 -0
  355. package/vendor/framey/dist/chunk-634HSJ3J.js +58 -0
  356. package/vendor/framey/dist/chunk-66LREXGS.js +48 -0
  357. package/vendor/framey/dist/chunk-6BEFEWFB.js +25 -0
  358. package/vendor/framey/dist/chunk-6BNTGNGD.js +286 -0
  359. package/vendor/framey/dist/chunk-6DDPOHMK.js +140 -0
  360. package/vendor/framey/dist/chunk-6GV5XSOR.js +214 -0
  361. package/vendor/framey/dist/chunk-6JR2XUEE.js +127 -0
  362. package/vendor/framey/dist/chunk-73QVATIM.js +362 -0
  363. package/vendor/framey/dist/chunk-7FMUTGOH.js +279 -0
  364. package/vendor/framey/dist/chunk-7JQFJ6JJ.js +291 -0
  365. package/vendor/framey/dist/chunk-AHPGAESX.js +113 -0
  366. package/vendor/framey/dist/chunk-AHX34EFP.js +15 -0
  367. package/vendor/framey/dist/chunk-AJ5CSAEZ.js +487 -0
  368. package/vendor/framey/dist/chunk-B7RJV74O.js +5047 -0
  369. package/vendor/framey/dist/chunk-BL4U6U52.js +254 -0
  370. package/vendor/framey/dist/chunk-BSQ7XANM.js +210 -0
  371. package/vendor/framey/dist/chunk-BZ56MTDX.js +6 -0
  372. package/vendor/framey/dist/chunk-C5BO7PMT.js +282 -0
  373. package/vendor/framey/dist/chunk-CFUCHO4T.js +358 -0
  374. package/vendor/framey/dist/chunk-CZGHFATT.js +31 -0
  375. package/vendor/framey/dist/chunk-DLA44CMS.js +5649 -0
  376. package/vendor/framey/dist/chunk-DPVXBVLL.js +31292 -0
  377. package/vendor/framey/dist/chunk-DQBY7FRR.js +397 -0
  378. package/vendor/framey/dist/chunk-EAMLBAHA.js +154 -0
  379. package/vendor/framey/dist/chunk-EOVYQ3IG.js +143 -0
  380. package/vendor/framey/dist/chunk-EVMY7IPL.js +612 -0
  381. package/vendor/framey/dist/chunk-FG4BBFZI.js +122 -0
  382. package/vendor/framey/dist/chunk-FI4I7CME.js +56 -0
  383. package/vendor/framey/dist/chunk-FLREUEHW.js +2081 -0
  384. package/vendor/framey/dist/chunk-FUFP7A7S.js +1126 -0
  385. package/vendor/framey/dist/chunk-FV3PIKGH.js +56 -0
  386. package/vendor/framey/dist/chunk-FXMKHHPO.js +123 -0
  387. package/vendor/framey/dist/chunk-GGZAM5VH.js +1187 -0
  388. package/vendor/framey/dist/chunk-GKZEVJIB.js +39 -0
  389. package/vendor/framey/dist/chunk-GMECXFAN.js +57 -0
  390. package/vendor/framey/dist/chunk-GNEFDLFB.js +621 -0
  391. package/vendor/framey/dist/chunk-GPMLSOEG.js +19274 -0
  392. package/vendor/framey/dist/chunk-GPYVT5EE.js +59 -0
  393. package/vendor/framey/dist/chunk-H6IEMZEV.js +40 -0
  394. package/vendor/framey/dist/chunk-HEFQCIXR.js +170 -0
  395. package/vendor/framey/dist/chunk-HFQ4CWHA.js +118 -0
  396. package/vendor/framey/dist/chunk-HPDTCOKE.js +304 -0
  397. package/vendor/framey/dist/chunk-HTUHQKDB.js +548 -0
  398. package/vendor/framey/dist/chunk-HU2SPFNG.js +103 -0
  399. package/vendor/framey/dist/chunk-HVW7ABXD.js +19 -0
  400. package/vendor/framey/dist/chunk-IG7NDKXO.js +26 -0
  401. package/vendor/framey/dist/chunk-II3J3WXK.js +246 -0
  402. package/vendor/framey/dist/chunk-IR35BCLK.js +13 -0
  403. package/vendor/framey/dist/chunk-ISN5GRYI.js +20 -0
  404. package/vendor/framey/dist/chunk-IUONB55J.js +669 -0
  405. package/vendor/framey/dist/chunk-IVSUQR2B.js +161 -0
  406. package/vendor/framey/dist/chunk-IXU6PQSW.js +259 -0
  407. package/vendor/framey/dist/chunk-IZCW2NKT.js +29 -0
  408. package/vendor/framey/dist/chunk-JGXJU5PF.js +68 -0
  409. package/vendor/framey/dist/chunk-JHOCK3DG.js +27 -0
  410. package/vendor/framey/dist/chunk-JVBRJMOP.js +121 -0
  411. package/vendor/framey/dist/chunk-K4MJX7SR.js +17 -0
  412. package/vendor/framey/dist/chunk-K4WKGXRC.js +18 -0
  413. package/vendor/framey/dist/chunk-KGPLIH7B.js +127 -0
  414. package/vendor/framey/dist/chunk-KLIKCX6Q.js +63 -0
  415. package/vendor/framey/dist/chunk-KXTKKBOC.js +61 -0
  416. package/vendor/framey/dist/chunk-KZI44OPA.js +185 -0
  417. package/vendor/framey/dist/chunk-LEKZNRKI.js +45 -0
  418. package/vendor/framey/dist/chunk-LFGJWOVA.js +61 -0
  419. package/vendor/framey/dist/chunk-LLMSX6V6.js +17 -0
  420. package/vendor/framey/dist/chunk-LTGTN2TH.js +195 -0
  421. package/vendor/framey/dist/chunk-M2WBOQ2Q.js +54 -0
  422. package/vendor/framey/dist/chunk-MI5FTLYK.js +399 -0
  423. package/vendor/framey/dist/chunk-MLQP2QUF.js +1809 -0
  424. package/vendor/framey/dist/chunk-MMQ52NIZ.js +956 -0
  425. package/vendor/framey/dist/chunk-ND46XKK3.js +742 -0
  426. package/vendor/framey/dist/chunk-NYEXNSHM.js +504 -0
  427. package/vendor/framey/dist/chunk-O4YRB27L.js +57 -0
  428. package/vendor/framey/dist/chunk-O7BGSQ5F.js +92 -0
  429. package/vendor/framey/dist/chunk-OFQWTKPW.js +117 -0
  430. package/vendor/framey/dist/chunk-P5ZBLXJ6.js +91 -0
  431. package/vendor/framey/dist/chunk-P6LJ4Y32.js +4662 -0
  432. package/vendor/framey/dist/chunk-PKZ7RK5N.js +281 -0
  433. package/vendor/framey/dist/chunk-PURHAXFL.js +15 -0
  434. package/vendor/framey/dist/chunk-Q5X2B5WT.js +29 -0
  435. package/vendor/framey/dist/chunk-QAMKOG67.js +248 -0
  436. package/vendor/framey/dist/chunk-R6YBK4XX.js +514 -0
  437. package/vendor/framey/dist/chunk-RGLQURIX.js +2997 -0
  438. package/vendor/framey/dist/chunk-RNV3DM4S.js +3573 -0
  439. package/vendor/framey/dist/chunk-ROEW726S.js +4638 -0
  440. package/vendor/framey/dist/chunk-RQVDTPGD.js +6 -0
  441. package/vendor/framey/dist/chunk-RVZHGOGR.js +26 -0
  442. package/vendor/framey/dist/chunk-RXATE6FZ.js +385 -0
  443. package/vendor/framey/dist/chunk-S3S4TGEH.js +424 -0
  444. package/vendor/framey/dist/chunk-SDYDNHEE.js +11202 -0
  445. package/vendor/framey/dist/chunk-SSWBU67I.js +173 -0
  446. package/vendor/framey/dist/chunk-ST35C4K6.js +28 -0
  447. package/vendor/framey/dist/chunk-SZNTYTIV.js +990 -0
  448. package/vendor/framey/dist/chunk-T2EUWCJE.js +29 -0
  449. package/vendor/framey/dist/chunk-T6AGUTZJ.js +444 -0
  450. package/vendor/framey/dist/chunk-THJALHFJ.js +11131 -0
  451. package/vendor/framey/dist/chunk-TIQB63MX.js +18128 -0
  452. package/vendor/framey/dist/chunk-U242RTCT.js +134 -0
  453. package/vendor/framey/dist/chunk-UJZREAV6.js +3901 -0
  454. package/vendor/framey/dist/chunk-UMD3V7CU.js +264 -0
  455. package/vendor/framey/dist/chunk-UOFAE5RF.js +42 -0
  456. package/vendor/framey/dist/chunk-UTEIUGAZ.js +29 -0
  457. package/vendor/framey/dist/chunk-VAS6HQX3.js +138 -0
  458. package/vendor/framey/dist/chunk-VC76R6W2.js +27 -0
  459. package/vendor/framey/dist/chunk-VFZ7W5W7.js +226 -0
  460. package/vendor/framey/dist/chunk-VHNLZAE2.js +348 -0
  461. package/vendor/framey/dist/chunk-VMC4WSH5.js +278 -0
  462. package/vendor/framey/dist/chunk-VORQIH64.js +108 -0
  463. package/vendor/framey/dist/chunk-VTXFRIHO.js +186 -0
  464. package/vendor/framey/dist/chunk-W2LGJSEN.js +182 -0
  465. package/vendor/framey/dist/chunk-WKBM7NDG.js +32 -0
  466. package/vendor/framey/dist/chunk-WMQNIQDJ.js +2057 -0
  467. package/vendor/framey/dist/chunk-WN4XZC5F.js +504 -0
  468. package/vendor/framey/dist/chunk-WQ6ZXHFQ.js +133 -0
  469. package/vendor/framey/dist/chunk-X7HBSTCZ.js +53 -0
  470. package/vendor/framey/dist/chunk-X7MTZ4T2.js +6 -0
  471. package/vendor/framey/dist/chunk-XPTOJZJF.js +308 -0
  472. package/vendor/framey/dist/chunk-XT6MXC7A.js +6 -0
  473. package/vendor/framey/dist/chunk-XT7X6QCP.js +6 -0
  474. package/vendor/framey/dist/chunk-XTMDWNEC.js +2820 -0
  475. package/vendor/framey/dist/chunk-XUHOIDKG.js +6 -0
  476. package/vendor/framey/dist/chunk-XX7LTW5Y.js +138 -0
  477. package/vendor/framey/dist/chunk-Y3YGTZEG.js +382 -0
  478. package/vendor/framey/dist/chunk-Y5SBSGN7.js +346 -0
  479. package/vendor/framey/dist/chunk-YCMVI4MZ.js +625 -0
  480. package/vendor/framey/dist/chunk-YOR4CTCE.js +261 -0
  481. package/vendor/framey/dist/chunk-YPRBGITP.js +2748 -0
  482. package/vendor/framey/dist/chunk-ZKDMAOFU.js +32 -0
  483. package/vendor/framey/dist/chunk-ZW6DURPF.js +1318 -0
  484. package/vendor/framey/dist/clean-ZJOGDKDM.js +336 -0
  485. package/vendor/framey/dist/cli.js +439 -0
  486. package/vendor/framey/dist/cloudrun-HGJ3B6ZV.js +767 -0
  487. package/vendor/framey/dist/commands/contrast-audit.browser.js +643 -0
  488. package/vendor/framey/dist/commands/layout-audit.browser.js +2914 -0
  489. package/vendor/framey/dist/commands/motion-sample.browser.js +74 -0
  490. package/vendor/framey/dist/commands/motion-signature.browser.js +475 -0
  491. package/vendor/framey/dist/compare-W7UY3BAZ.js +463 -0
  492. package/vendor/framey/dist/compiler-TM3W6GYF.js +136 -0
  493. package/vendor/framey/dist/component-QF5VGYMU.js +176 -0
  494. package/vendor/framey/dist/compositions-XT3PMNDF.js +238 -0
  495. package/vendor/framey/dist/contactSheet-7W6GYHBQ.js +24 -0
  496. package/vendor/framey/dist/deploy-6FJPWKF2.js +299 -0
  497. package/vendor/framey/dist/destroy-HE2RIPKZ.js +57 -0
  498. package/vendor/framey/dist/deterministicFonts-RADD3BSX.js +50 -0
  499. package/vendor/framey/dist/dist-4S2FGGVY.js +422 -0
  500. package/vendor/framey/dist/dist-BE4B2EZE.js +32 -0
  501. package/vendor/framey/dist/dist-EWXJGN63.js +129 -0
  502. package/vendor/framey/dist/docs-VKIRFEEX.js +131 -0
  503. package/vendor/framey/dist/doctor-2UNJ2G7U.js +74 -0
  504. package/vendor/framey/dist/dom-37K6YOH4.js +14 -0
  505. package/vendor/framey/dist/dotEnv-7PZQTVIM.js +54 -0
  506. package/vendor/framey/dist/events-ACY3P2PA.js +76 -0
  507. package/vendor/framey/dist/events-IHB3B2MK.js +69 -0
  508. package/vendor/framey/dist/ffmpeg-DR5LGGSK.js +63 -0
  509. package/vendor/framey/dist/figma-BODVUPHB.js +63 -0
  510. package/vendor/framey/dist/fontData.generated-NXAOI4GH.js +13 -0
  511. package/vendor/framey/dist/fontLocalizeCli.js +142 -0
  512. package/vendor/framey/dist/gpuPolicy-XLEXORZY.js +49 -0
  513. package/vendor/framey/dist/grade-compare-GAXFQ74C.js +661 -0
  514. package/vendor/framey/dist/gsapParser-IEUSLYDJ.js +2885 -0
  515. package/vendor/framey/dist/gsapParserAcorn-LZJKCFQI.js +30 -0
  516. package/vendor/framey/dist/help-VCB5X2HS.js +184 -0
  517. package/vendor/framey/dist/history-ENGZEVFT.js +471 -0
  518. package/vendor/framey/dist/hyperframe.manifest.json +22 -0
  519. package/vendor/framey/dist/hyperframe.runtime.iife.js +1132 -0
  520. package/vendor/framey/dist/hyperframes-player.global.js +478 -0
  521. package/vendor/framey/dist/hyperframes-slideshow.global.js +148 -0
  522. package/vendor/framey/dist/info-WPCJHBMU.js +182 -0
  523. package/vendor/framey/dist/init-G4WGLYGD.js +1176 -0
  524. package/vendor/framey/dist/inspect-5IQ6CNEQ.js +106 -0
  525. package/vendor/framey/dist/installer-ML4HWUV7.js +40 -0
  526. package/vendor/framey/dist/keyframes-Q6XJO7VW.js +2755 -0
  527. package/vendor/framey/dist/lambda-A7JC74JF.js +468 -0
  528. package/vendor/framey/dist/layout-YET6XNXA.js +95 -0
  529. package/vendor/framey/dist/lint-I7FZN2VJ.js +162 -0
  530. package/vendor/framey/dist/lintProject-PDB3UN72.js +30 -0
  531. package/vendor/framey/dist/manager-CD6LJ7ZN.js +45 -0
  532. package/vendor/framey/dist/manager-WA4F2GST.js +67 -0
  533. package/vendor/framey/dist/media-treatment-BXYS4WVA.js +1030 -0
  534. package/vendor/framey/dist/media-use-LWH3MANK.js +113 -0
  535. package/vendor/framey/dist/models-K363FYM4.js +195 -0
  536. package/vendor/framey/dist/motionShot-GPAVWXLH.js +640 -0
  537. package/vendor/framey/dist/normalize-FASIPBUM.js +24 -0
  538. package/vendor/framey/dist/normalize-audio-VDWYRHN6.js +268 -0
  539. package/vendor/framey/dist/open-E3TB6P6J.js +128 -0
  540. package/vendor/framey/dist/parakeetRunner-UP34UOI2.js +58 -0
  541. package/vendor/framey/dist/pipeline-VXIUYEBU.js +64 -0
  542. package/vendor/framey/dist/play-BUTDQ4DV.js +353 -0
  543. package/vendor/framey/dist/policies-OLDYGFK5.js +309 -0
  544. package/vendor/framey/dist/preflight-2KZ2GWAZ.js +55 -0
  545. package/vendor/framey/dist/present-GXYSM7NX.js +353 -0
  546. package/vendor/framey/dist/preview-EKZ33JOJ.js +1910 -0
  547. package/vendor/framey/dist/producer-SKU5EV3J.js +13 -0
  548. package/vendor/framey/dist/progress-ZWB4Z4ET.js +76 -0
  549. package/vendor/framey/dist/projectConfig-3MZAYVTS.js +60 -0
  550. package/vendor/framey/dist/publication-DTKWNF74.js +33 -0
  551. package/vendor/framey/dist/remove-background-OY5L7XN2.js +265 -0
  552. package/vendor/framey/dist/render-CDV4GDFX.js +187 -0
  553. package/vendor/framey/dist/render-YE5YAMOD.js +2620 -0
  554. package/vendor/framey/dist/render-batch-ZAMFPCLL.js +274 -0
  555. package/vendor/framey/dist/renderSetupWorker.js +120 -0
  556. package/vendor/framey/dist/resolver-D5BIPSEW.js +42 -0
  557. package/vendor/framey/dist/runtimeVersion.js +18 -0
  558. package/vendor/framey/dist/sam-WFZXI4F7.js +23 -0
  559. package/vendor/framey/dist/shaderTransitionWorker.js +44 -0
  560. package/vendor/framey/dist/sherpa-RQWLV7I3.js +79 -0
  561. package/vendor/framey/dist/sherpaWorker.js +84 -0
  562. package/vendor/framey/dist/sites-AMOVABTK.js +54 -0
  563. package/vendor/framey/dist/skill-ZHVLH7KX.js +15 -0
  564. package/vendor/framey/dist/slideshow-SJGK4RQS.js +24 -0
  565. package/vendor/framey/dist/snapshot-TUXL6LBQ.js +1515 -0
  566. package/vendor/framey/dist/src-JHQGB2S6.js +215 -0
  567. package/vendor/framey/dist/src-Z5PGEMXB.js +532 -0
  568. package/vendor/framey/dist/state-B6H3WHCF.js +28 -0
  569. package/vendor/framey/dist/staticProjectServer-DFVZOUGI.js +63 -0
  570. package/vendor/framey/dist/studio/assets/hyperframes-player-DLaKjw0L.js +478 -0
  571. package/vendor/framey/dist/studio/assets/index-BX3KHhGX.js +71 -0
  572. package/vendor/framey/dist/studio/assets/index-CYbvOVp-.css +1 -0
  573. package/vendor/framey/dist/studio/assets/index-Dp3QEUGL.js +402 -0
  574. package/vendor/framey/dist/studio/assets/index-qrTAXbqc.js +531 -0
  575. package/vendor/framey/dist/studio/favicon.svg +14 -0
  576. package/vendor/framey/dist/studio/icons/timeline/audio.svg +7 -0
  577. package/vendor/framey/dist/studio/icons/timeline/captions.svg +5 -0
  578. package/vendor/framey/dist/studio/icons/timeline/composition.svg +12 -0
  579. package/vendor/framey/dist/studio/icons/timeline/image.svg +18 -0
  580. package/vendor/framey/dist/studio/icons/timeline/music.svg +10 -0
  581. package/vendor/framey/dist/studio/icons/timeline/text.svg +3 -0
  582. package/vendor/framey/dist/studio/index.html +23 -0
  583. package/vendor/framey/dist/studio-api-2NECGRMB.js +179 -0
  584. package/vendor/framey/dist/studioSelectionClient-IUUPKUHZ.js +25 -0
  585. package/vendor/framey/dist/studioServer-N2OPUMOQ.js +1569 -0
  586. package/vendor/framey/dist/synthesize-PKTB5ATG.js +183 -0
  587. package/vendor/framey/dist/system-7F3UEHQT.js +27 -0
  588. package/vendor/framey/dist/telemetry-DQGPEKM6.js +145 -0
  589. package/vendor/framey/dist/telemetry-UN55N6U6.js +77 -0
  590. package/vendor/framey/dist/timeline-LHUUMK63.js +1295 -0
  591. package/vendor/framey/dist/tokens-OLECWDFK.js +92 -0
  592. package/vendor/framey/dist/transcribe-O7HQKMIV.js +331 -0
  593. package/vendor/framey/dist/transcribe-UJESPBT5.js +76 -0
  594. package/vendor/framey/dist/tts-YCCQHZD4.js +234 -0
  595. package/vendor/framey/dist/urlDownloader-H2LXLG4U.js +48 -0
  596. package/vendor/framey/dist/usage-HG4WMM7A.js +2167 -0
  597. package/vendor/framey/dist/validate-F2XMN6EV.js +87 -0
  598. package/vendor/framey/dist/vendor/npm/gsap@3.15.0/GSAP-LICENSE.txt +8 -0
  599. package/vendor/framey/dist/vendor/npm/gsap@3.15.0/dist/CustomEase.min.js +11 -0
  600. package/vendor/framey/dist/vendor/npm/gsap@3.15.0/dist/MotionPathPlugin.min.js +11 -0
  601. package/vendor/framey/dist/vendor/npm/gsap@3.15.0/dist/gsap.min.js +11 -0
  602. package/vendor/framey/dist/warmCheck.js +220 -0
  603. package/vendor/framey/dist/warmCheckClient.js +139 -0
  604. package/vendor/framey/dist/workspaceBuildCheck-XYD2YTFW.js +133 -0
  605. package/vendor/framey-player/LICENSE +190 -0
  606. package/vendor/framey-player/NOTICE +16 -0
  607. package/vendor/framey-player/SOURCE.json +6 -0
  608. package/vendor/framey-player/hyperframes-player.global.js +478 -0
  609. package/vendor/framey.pin +1 -0
  610. package/bin/index.js +0 -3
@@ -0,0 +1,95 @@
1
+ import { ConfigError } from "./errors.js";
2
+ export function zonedParts(date, timeZone) {
3
+ const fmt = new Intl.DateTimeFormat("en-US", {
4
+ timeZone,
5
+ hourCycle: "h23",
6
+ year: "numeric",
7
+ month: "2-digit",
8
+ day: "2-digit",
9
+ hour: "2-digit",
10
+ minute: "2-digit",
11
+ });
12
+ const map = {};
13
+ for (const part of fmt.formatToParts(date)) {
14
+ if (part.type !== "literal")
15
+ map[part.type] = part.value;
16
+ }
17
+ return {
18
+ year: Number(map.year),
19
+ month: Number(map.month),
20
+ day: Number(map.day),
21
+ hour: Number(map.hour === "24" ? "0" : map.hour),
22
+ minute: Number(map.minute),
23
+ };
24
+ }
25
+ export function localDayKey(date, timeZone) {
26
+ const parts = zonedParts(date, timeZone);
27
+ const month = String(parts.month).padStart(2, "0");
28
+ const day = String(parts.day).padStart(2, "0");
29
+ return `${parts.year}-${month}-${day}`;
30
+ }
31
+ function minutes(hour, minute) {
32
+ return hour * 60 + minute;
33
+ }
34
+ function parseWindow(value) {
35
+ const match = /^(\d{2}):(\d{2})-(\d{2}):(\d{2})$/.exec(value.trim());
36
+ if (!match)
37
+ throw new ConfigError("cadence_window", `Cadence window must look like 09:00-11:30, received ${value}`);
38
+ const [, h1, m1, h2, m2] = match.map(Number);
39
+ if (h1 > 23 || h2 > 24 || m1 > 59 || m2 > 59 || (h2 === 24 && m2 !== 0)) {
40
+ throw new ConfigError("cadence_window", `Cadence window ${value} has an hour or minute out of range`);
41
+ }
42
+ const start = minutes(h1, m1);
43
+ const end = minutes(h2, m2);
44
+ if (start >= end) {
45
+ throw new ConfigError("cadence_window", `Cadence window ${value} must end after it starts on the same day`);
46
+ }
47
+ return { start, end };
48
+ }
49
+ /** Throws ConfigError for a timezone Intl rejects, malformed windows, or non-sensible limits. */
50
+ export function validateCadence(cadence) {
51
+ try {
52
+ new Intl.DateTimeFormat("en-US", { timeZone: cadence.timezone });
53
+ }
54
+ catch {
55
+ throw new ConfigError("cadence_timezone", `Cadence timezone ${JSON.stringify(cadence.timezone)} is not a valid IANA timezone`);
56
+ }
57
+ if (!Array.isArray(cadence.windows)) {
58
+ throw new ConfigError("cadence_window", "Cadence windows must be a list of HH:MM-HH:MM strings");
59
+ }
60
+ for (const windowValue of cadence.windows) {
61
+ if (typeof windowValue !== "string") {
62
+ throw new ConfigError("cadence_window", "Cadence windows must be a list of HH:MM-HH:MM strings");
63
+ }
64
+ parseWindow(windowValue);
65
+ }
66
+ if (!Number.isFinite(cadence.minHoursBetweenPosts) || cadence.minHoursBetweenPosts < 0) {
67
+ throw new ConfigError("cadence_limit", "minHoursBetweenPosts must be a number of hours, zero or more");
68
+ }
69
+ if (!Number.isInteger(cadence.maxPostsPerDay) || cadence.maxPostsPerDay < 1) {
70
+ throw new ConfigError("cadence_limit", "maxPostsPerDay must be a whole number, one or more");
71
+ }
72
+ }
73
+ export function cadenceDecision(input) {
74
+ const { cadence, now } = input;
75
+ if (input.postsOnLocalDay >= cadence.maxPostsPerDay) {
76
+ return { due: false, reason: "daily_cap" };
77
+ }
78
+ if (input.lastPublishedAt) {
79
+ const elapsedMs = now.getTime() - input.lastPublishedAt.getTime();
80
+ const minMs = cadence.minHoursBetweenPosts * 60 * 60 * 1000;
81
+ if (elapsedMs < minMs)
82
+ return { due: false, reason: "min_interval" };
83
+ }
84
+ if (cadence.windows.length > 0) {
85
+ const parts = zonedParts(now, cadence.timezone);
86
+ const nowMinutes = minutes(parts.hour, parts.minute);
87
+ const open = cadence.windows.some((windowValue) => {
88
+ const window = parseWindow(windowValue);
89
+ return nowMinutes >= window.start && nowMinutes < window.end;
90
+ });
91
+ if (!open)
92
+ return { due: false, reason: "outside_window" };
93
+ }
94
+ return { due: true, reason: "due" };
95
+ }
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Spec 017 (Creators). Types only, plus one constant. No media URL (avatar, cover, video) lives
3
+ * in any of these. An unknown value is undefined, never 0. Phone numbers are never stored.
4
+ */
5
+ import type { PostMetrics, SourceId } from "./topics.js";
6
+ import type { Platform } from "./types.js";
7
+ /** Platforms with creator profiles. Facebook has no provider yet. */
8
+ export declare const CREATOR_PLATFORMS: readonly Platform[];
9
+ /**
10
+ * A contact the creator's own bio presents as a business contact ("business:", "collab",
11
+ * "contact", "inquiries"). Nothing else is extracted. Never a phone number.
12
+ */
13
+ export interface BusinessContact {
14
+ kind: "email" | "link";
15
+ value: string;
16
+ /** Always true: the value was read from the public bio. */
17
+ fromBio: true;
18
+ }
19
+ /** One observation of a creator's public profile. */
20
+ export interface CreatorProfile {
21
+ platform: Platform;
22
+ /** The platform's own id (TikTok uid, Instagram id, YouTube channel id). */
23
+ id: string;
24
+ /** Public handle without the leading @. */
25
+ handle: string;
26
+ displayName?: string;
27
+ followers?: number;
28
+ following?: number;
29
+ totalLikes?: number;
30
+ postCount?: number;
31
+ verified?: boolean;
32
+ bio?: string;
33
+ businessContact?: BusinessContact;
34
+ /** ISO 8601. */
35
+ observedAt: string;
36
+ source: SourceId;
37
+ /** YouTube data must be refreshed or deleted by this time (observedAt + 30 days). */
38
+ refreshBy?: string;
39
+ }
40
+ /** Followers at a point in time, from stored CreatorProfile observations. */
41
+ export interface FollowerSnapshot {
42
+ /** ISO 8601. */
43
+ observedAt: string;
44
+ followers?: number;
45
+ }
46
+ export interface FollowerGrowth {
47
+ /** Followers gained (negative when lost) over the window. */
48
+ abs: number;
49
+ /** abs / starting followers. Undefined when the start was 0. */
50
+ pct?: number;
51
+ }
52
+ /** What the engagement rate was divided by. Never mix the two when comparing creators. */
53
+ export type EngagementBasis = "views" | "followers";
54
+ export interface CreatorTopPost {
55
+ postId: string;
56
+ url: string;
57
+ caption: string;
58
+ postedAt: string;
59
+ metrics: PostMetrics;
60
+ durationSec?: number;
61
+ }
62
+ export interface CreatorFormat {
63
+ /** The top cluster terms. No LLM. */
64
+ name: string;
65
+ terms: string[];
66
+ postCount: number;
67
+ examplePostIds: string[];
68
+ }
69
+ export interface CreatorHook {
70
+ postId: string;
71
+ /** The first sentence of the caption. */
72
+ text: string;
73
+ }
74
+ export interface PostingTimes {
75
+ /** "creator-local" when a time zone was known, else "utc". */
76
+ basis: "creator-local" | "utc";
77
+ /** IANA zone name, or "UTC". */
78
+ timeZone: string;
79
+ /** Posts per hour of day, index 0 to 23. */
80
+ hours: number[];
81
+ /** Posts per weekday, index 0 (Sunday) to 6. */
82
+ weekdays: number[];
83
+ /** Hours with the highest median views, best first. Empty when views are unknown. */
84
+ bestHours: number[];
85
+ /** Weekdays with the highest median views, best first. Empty when views are unknown. */
86
+ bestWeekdays: number[];
87
+ }
88
+ export interface CreatorStats {
89
+ platform: Platform;
90
+ handle: string;
91
+ /** ISO 8601. */
92
+ computedAt: string;
93
+ /** Recent posts the numbers come from. */
94
+ sampleSize: number;
95
+ medianViews?: number;
96
+ /** (likes + comments + shares) / basis, as a fraction (0.05 is 5%). */
97
+ engagementRate?: number;
98
+ engagementBasis?: EngagementBasis;
99
+ /**
100
+ * Posts per week. "30d" means counted over the last 30 days. "sample" means the recent posts
101
+ * did not reach back 30 days, so the rate is over the span the sample covers (at least 7 days).
102
+ */
103
+ postsPerWeek?: number;
104
+ postsPerWeekBasis?: "30d" | "sample";
105
+ growth7d?: FollowerGrowth;
106
+ growth30d?: FollowerGrowth;
107
+ postingTimes?: PostingTimes;
108
+ medianLengthSec?: number;
109
+ topPosts: CreatorTopPost[];
110
+ formats: CreatorFormat[];
111
+ hooks: CreatorHook[];
112
+ }
113
+ /** One row of a creator search: enough to rank and pick, nothing more. */
114
+ export interface CreatorSummary {
115
+ platform: Platform;
116
+ handle: string;
117
+ displayName?: string;
118
+ followers?: number;
119
+ verified?: boolean;
120
+ niche?: string;
121
+ postsPerWeek?: number;
122
+ engagementRate?: number;
123
+ engagementBasis?: EngagementBasis;
124
+ medianViews?: number;
125
+ growth30dPct?: number;
126
+ /** ISO 8601. */
127
+ observedAt: string;
128
+ source: SourceId;
129
+ }
130
+ export interface WatchlistItem {
131
+ id: string;
132
+ watchlistId: string;
133
+ platform: Platform;
134
+ handle: string;
135
+ note?: string;
136
+ /** ISO 8601. */
137
+ addedAt: string;
138
+ }
139
+ export interface Watchlist {
140
+ id: string;
141
+ orgId: string;
142
+ name: string;
143
+ /** ISO 8601. */
144
+ createdAt: string;
145
+ items?: WatchlistItem[];
146
+ }
@@ -0,0 +1,2 @@
1
+ /** Platforms with creator profiles. Facebook has no provider yet. */
2
+ export const CREATOR_PLATFORMS = ["youtube", "tiktok", "instagram"];
@@ -0,0 +1,127 @@
1
+ import type { DisclosureProof } from "./types.js";
2
+ /**
3
+ * Compliance checklist. These are platform rules, not creative preferences.
4
+ * A video can be original and still fail here. A video can pass here and
5
+ * still fail the quality variation gates.
6
+ */
7
+ export declare const COMPLIANCE_CHECKLIST: ({
8
+ id: string;
9
+ platform: "youtube";
10
+ field: string;
11
+ location: string;
12
+ rule: string;
13
+ } | {
14
+ id: string;
15
+ platform: "tiktok";
16
+ field: string;
17
+ location: string;
18
+ rule: string;
19
+ } | {
20
+ id: string;
21
+ platform: "instagram";
22
+ field: string;
23
+ location: string;
24
+ rule: string;
25
+ } | {
26
+ id: string;
27
+ platform: "facebook";
28
+ field: string;
29
+ location: string;
30
+ rule: string;
31
+ } | {
32
+ id: string;
33
+ platform: "all";
34
+ field: string;
35
+ location: string;
36
+ rule: string;
37
+ })[];
38
+ export declare function assertNotVerbatim(script: string, sourceText: string): void;
39
+ export declare function assertNoAdvicePersona(script: string): void;
40
+ export interface YouTubeMetadata {
41
+ snippet: {
42
+ title: string;
43
+ description: string;
44
+ tags: string[];
45
+ categoryId: string;
46
+ defaultLanguage: string;
47
+ };
48
+ status: {
49
+ privacyStatus: "public" | "private" | "unlisted";
50
+ selfDeclaredMadeForKids: boolean;
51
+ containsSyntheticMedia: true;
52
+ embeddable: boolean;
53
+ };
54
+ }
55
+ /** YouTube: title up to 100 characters, description up to 5000 bytes (UTF-8). */
56
+ export declare const YOUTUBE_TITLE_CHARS = 100;
57
+ export declare const YOUTUBE_DESCRIPTION_BYTES = 5000;
58
+ /** YouTube rejects "<" and ">" in titles and descriptions. */
59
+ export declare function stripAngleBrackets(value: string): string;
60
+ export declare function buildYouTubeMetadata(input: {
61
+ title: string;
62
+ description: string;
63
+ tags: string[];
64
+ categoryId: string;
65
+ privacyStatus: "public" | "private" | "unlisted";
66
+ madeForKids: boolean;
67
+ language: string;
68
+ }): {
69
+ body: YouTubeMetadata;
70
+ proof: DisclosureProof;
71
+ };
72
+ export interface TikTokInitBody {
73
+ post_info: {
74
+ title: string;
75
+ privacy_level: string;
76
+ disable_duet: boolean;
77
+ disable_comment: boolean;
78
+ disable_stitch: boolean;
79
+ video_cover_timestamp_ms: number;
80
+ brand_content_toggle: boolean;
81
+ brand_organic_toggle: boolean;
82
+ is_aigc: true;
83
+ };
84
+ source_info: {
85
+ source: "FILE_UPLOAD";
86
+ video_size: number;
87
+ chunk_size: number;
88
+ total_chunk_count: number;
89
+ };
90
+ }
91
+ export declare function buildTikTokInit(input: {
92
+ caption: string;
93
+ privacyLevel: string;
94
+ disableComment: boolean;
95
+ coverTimestampMs: number;
96
+ brandContent: boolean;
97
+ brandOrganic: boolean;
98
+ videoSize: number;
99
+ chunkSize: number;
100
+ totalChunkCount: number;
101
+ audited: boolean;
102
+ privacyOptions: string[];
103
+ }): {
104
+ body: TikTokInitBody;
105
+ proof: DisclosureProof;
106
+ };
107
+ export declare function buildInstagramContainer(input: {
108
+ caption: string;
109
+ shareToFeed: boolean;
110
+ }): {
111
+ form: Record<string, string>;
112
+ proof: DisclosureProof;
113
+ };
114
+ export declare function buildFacebookFinish(input: {
115
+ videoId: string;
116
+ title: string;
117
+ description: string;
118
+ }): {
119
+ form: Record<string, string>;
120
+ proof: DisclosureProof;
121
+ };
122
+ export declare function clip(value: string, max: number): string;
123
+ export declare function utf8Bytes(value: string): number;
124
+ /** Clip to a UTF-8 byte budget without splitting a code point or surrogate pair. */
125
+ export declare function clipBytes(value: string, maxBytes: number): string;
126
+ export declare function utf16Length(value: string): number;
127
+ export declare function clipUtf16(value: string, maxUnits: number): string;
@@ -0,0 +1,250 @@
1
+ import { ComplianceError } from "./errors.js";
2
+ import { claimsAdvicePersona } from "./advice-persona.js";
3
+ import { longestSharedWordRun } from "./similarity.js";
4
+ /**
5
+ * Compliance checklist. These are platform rules, not creative preferences.
6
+ * A video can be original and still fail here. A video can pass here and
7
+ * still fail the quality variation gates.
8
+ */
9
+ export const COMPLIANCE_CHECKLIST = [
10
+ {
11
+ id: "youtube-synthetic",
12
+ platform: "youtube",
13
+ field: "status.containsSyntheticMedia",
14
+ location: "videos.insert body status.containsSyntheticMedia (part=snippet,status)",
15
+ rule: "Always true. YouTube Data API, videos.insert, documented on the video resource status.",
16
+ },
17
+ {
18
+ id: "tiktok-aigc",
19
+ platform: "tiktok",
20
+ field: "post_info.is_aigc",
21
+ location: "POST /v2/post/publish/video/init/ post_info.is_aigc",
22
+ rule: "Always true. TikTok labels the post with the creator-labeled AI-generated tag.",
23
+ },
24
+ {
25
+ id: "instagram-ai",
26
+ platform: "instagram",
27
+ field: "is_ai_generated",
28
+ location: "POST /{ig-user-id}/media is_ai_generated=true, before media_publish",
29
+ rule: "Always true on the media container. Instagram changelog, June 22, 2026. Carousels would set it on the container only. This pipeline publishes Reels.",
30
+ },
31
+ {
32
+ id: "facebook-ai",
33
+ platform: "facebook",
34
+ field: "is_ai_generated",
35
+ location: "POST /{page-id}/video_reels upload_phase=finish is_ai_generated=true",
36
+ rule: "Always true on the finish call. Page Video Reels documents is_ai_generated as the self-claim flag. If the platform rejects the field, the job blocks and does not publish without it.",
37
+ },
38
+ {
39
+ id: "verbatim-source",
40
+ platform: "all",
41
+ field: "script",
42
+ location: "generate stage, before render",
43
+ rule: "A 12-word run shared with the source excerpt is a compliance block (reused content and copyright), not a style nit.",
44
+ },
45
+ {
46
+ id: "advice-persona",
47
+ platform: "all",
48
+ field: "source score",
49
+ location: "source stage",
50
+ rule: "AI personas giving medical, legal, or financial advice are blocked. YouTube's monetization policy treats that category as ineligible.",
51
+ },
52
+ ];
53
+ export function assertNotVerbatim(script, sourceText) {
54
+ const run = longestSharedWordRun(script, sourceText);
55
+ if (run >= 12) {
56
+ throw new ComplianceError("verbatim_source_overlap", `Script shares a ${run}-word run with the source. That is reused content, not a variation miss.`);
57
+ }
58
+ }
59
+ export function assertNoAdvicePersona(script) {
60
+ if (claimsAdvicePersona(script)) {
61
+ throw new ComplianceError("advice_persona", "Script presents an AI persona as a doctor, lawyer, or financial adviser.");
62
+ }
63
+ }
64
+ /** YouTube: title up to 100 characters, description up to 5000 bytes (UTF-8). */
65
+ export const YOUTUBE_TITLE_CHARS = 100;
66
+ export const YOUTUBE_DESCRIPTION_BYTES = 5000;
67
+ /** YouTube rejects "<" and ">" in titles and descriptions. */
68
+ export function stripAngleBrackets(value) {
69
+ return value.replace(/</g, "\u2039").replace(/>/g, "\u203a");
70
+ }
71
+ export function buildYouTubeMetadata(input) {
72
+ const body = {
73
+ snippet: {
74
+ title: clip(stripAngleBrackets(input.title), YOUTUBE_TITLE_CHARS),
75
+ description: clipBytes(stripAngleBrackets(input.description), YOUTUBE_DESCRIPTION_BYTES),
76
+ tags: clipTags(input.tags),
77
+ categoryId: input.categoryId,
78
+ defaultLanguage: input.language,
79
+ },
80
+ status: {
81
+ privacyStatus: input.privacyStatus,
82
+ selfDeclaredMadeForKids: input.madeForKids,
83
+ containsSyntheticMedia: true,
84
+ embeddable: true,
85
+ },
86
+ };
87
+ assertDisclosure("youtube", body.status.containsSyntheticMedia);
88
+ return {
89
+ body,
90
+ proof: {
91
+ platform: "youtube",
92
+ field: "status.containsSyntheticMedia",
93
+ value: true,
94
+ location: "videos.insert JSON body, part=snippet,status",
95
+ },
96
+ };
97
+ }
98
+ export function buildTikTokInit(input) {
99
+ if (!input.audited && input.privacyLevel !== "SELF_ONLY") {
100
+ throw new ComplianceError("tiktok_unaudited_public", "Unaudited TikTok clients can only post privately. Set privacyLevel to SELF_ONLY, or finish TikTok's Content Posting audit. The worker will not silently downgrade a public request.");
101
+ }
102
+ if (!input.privacyOptions.includes(input.privacyLevel)) {
103
+ throw new ComplianceError("tiktok_privacy_mismatch", `privacy_level ${input.privacyLevel} is not in creator options [${input.privacyOptions.join(", ")}]. Query creator info is mandatory, and the worker will not substitute a different level.`);
104
+ }
105
+ const body = {
106
+ post_info: {
107
+ title: clipUtf16(input.caption, 2200),
108
+ privacy_level: input.privacyLevel,
109
+ disable_duet: false,
110
+ disable_comment: input.disableComment,
111
+ disable_stitch: false,
112
+ video_cover_timestamp_ms: input.coverTimestampMs,
113
+ brand_content_toggle: input.brandContent,
114
+ brand_organic_toggle: input.brandOrganic,
115
+ is_aigc: true,
116
+ },
117
+ source_info: {
118
+ source: "FILE_UPLOAD",
119
+ video_size: input.videoSize,
120
+ chunk_size: input.chunkSize,
121
+ total_chunk_count: input.totalChunkCount,
122
+ },
123
+ };
124
+ assertDisclosure("tiktok", body.post_info.is_aigc);
125
+ return {
126
+ body,
127
+ proof: {
128
+ platform: "tiktok",
129
+ field: "post_info.is_aigc",
130
+ value: true,
131
+ location: "POST https://open.tiktokapis.com/v2/post/publish/video/init/",
132
+ },
133
+ };
134
+ }
135
+ export function buildInstagramContainer(input) {
136
+ const form = {
137
+ media_type: "REELS",
138
+ upload_type: "resumable",
139
+ caption: clip(input.caption, 2200),
140
+ share_to_feed: input.shareToFeed ? "true" : "false",
141
+ is_ai_generated: "true",
142
+ };
143
+ if (form.is_ai_generated !== "true") {
144
+ throw new ComplianceError("instagram_disclosure", "Instagram container lost is_ai_generated.");
145
+ }
146
+ return {
147
+ form,
148
+ proof: {
149
+ platform: "instagram",
150
+ field: "is_ai_generated",
151
+ value: true,
152
+ location: "POST /{ig-user-id}/media (container). media_publish does not carry the flag.",
153
+ },
154
+ };
155
+ }
156
+ export function buildFacebookFinish(input) {
157
+ const form = {
158
+ upload_phase: "finish",
159
+ video_id: input.videoId,
160
+ video_state: "PUBLISHED",
161
+ title: clip(input.title, 255),
162
+ description: clip(input.description, 5000),
163
+ is_ai_generated: "true",
164
+ };
165
+ if (form.is_ai_generated !== "true" || form.upload_phase !== "finish") {
166
+ throw new ComplianceError("facebook_disclosure", "Facebook finish call lost is_ai_generated.");
167
+ }
168
+ return {
169
+ form,
170
+ proof: {
171
+ platform: "facebook",
172
+ field: "is_ai_generated",
173
+ value: true,
174
+ location: "POST /{page-id}/video_reels upload_phase=finish",
175
+ },
176
+ };
177
+ }
178
+ function assertDisclosure(platform, value) {
179
+ if (value !== true) {
180
+ throw new ComplianceError(`${platform}_disclosure`, `${platform} synthetic-media flag was not true. Publish is refused.`);
181
+ }
182
+ }
183
+ export function clip(value, max) {
184
+ const trimmed = value.trim();
185
+ if (trimmed.length <= max)
186
+ return trimmed;
187
+ let end = Math.max(0, max - 1);
188
+ const last = trimmed.charCodeAt(end - 1);
189
+ if (end > 0 && last >= 0xd800 && last <= 0xdbff)
190
+ end -= 1;
191
+ return trimmed.slice(0, end).trimEnd() + "…";
192
+ }
193
+ export function utf8Bytes(value) {
194
+ return new TextEncoder().encode(value).length;
195
+ }
196
+ /** Clip to a UTF-8 byte budget without splitting a code point or surrogate pair. */
197
+ export function clipBytes(value, maxBytes) {
198
+ const trimmed = value.trim();
199
+ if (utf8Bytes(trimmed) <= maxBytes)
200
+ return trimmed;
201
+ const ellipsis = "…";
202
+ const budget = maxBytes - utf8Bytes(ellipsis);
203
+ let used = 0;
204
+ let out = "";
205
+ for (const char of trimmed) {
206
+ const size = utf8Bytes(char);
207
+ if (used + size > budget)
208
+ break;
209
+ out += char;
210
+ used += size;
211
+ }
212
+ return out.trimEnd() + ellipsis;
213
+ }
214
+ export function utf16Length(value) {
215
+ let length = 0;
216
+ for (const char of value) {
217
+ const point = char.codePointAt(0) ?? 0;
218
+ length += point > 0xffff ? 2 : 1;
219
+ }
220
+ return length;
221
+ }
222
+ export function clipUtf16(value, maxUnits) {
223
+ let length = 0;
224
+ let out = "";
225
+ for (const char of value.trim()) {
226
+ const point = char.codePointAt(0) ?? 0;
227
+ const units = point > 0xffff ? 2 : 1;
228
+ if (length + units > maxUnits)
229
+ break;
230
+ out += char;
231
+ length += units;
232
+ }
233
+ return out;
234
+ }
235
+ function clipTags(tags) {
236
+ const cleaned = [];
237
+ let used = 0;
238
+ for (const tag of tags) {
239
+ const value = tag.replace(/^#/, "").trim();
240
+ if (!value)
241
+ continue;
242
+ if (used + value.length + 1 > 480)
243
+ break;
244
+ cleaned.push(value);
245
+ used += value.length + 1;
246
+ if (cleaned.length >= 15)
247
+ break;
248
+ }
249
+ return cleaned;
250
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Quality failures and compliance failures are different stops.
3
+ *
4
+ * Quality: the video would be thin, generic, or too similar to the last one.
5
+ * These gates exist so a channel does not ship interchangeable templated videos.
6
+ * YouTube's inauthentic-content monetization policy is why the gates are strict.
7
+ * A quality rejection is not an API policy verdict, and passing is not a
8
+ * promise that YouTube will monetize the channel.
9
+ *
10
+ * Compliance: the platform requires a disclosure flag, an audit posture,
11
+ * a privacy choice the creator options allow, or the draft copies a source
12
+ * or presents an AI persona as a professional adviser. These do not retry.
13
+ */
14
+ export type RiskClass = "quality" | "compliance" | "transport" | "config";
15
+ export declare class AppError extends Error {
16
+ readonly code: string;
17
+ readonly retryable: boolean;
18
+ readonly risk: RiskClass;
19
+ constructor(message: string, code: string, retryable: boolean, risk: RiskClass);
20
+ }
21
+ export declare class QualityError extends AppError {
22
+ constructor(code: string, message: string);
23
+ }
24
+ export declare class ComplianceError extends AppError {
25
+ constructor(code: string, message: string);
26
+ }
27
+ export declare class RetryableError extends AppError {
28
+ readonly retryAfterMs: number | undefined;
29
+ constructor(code: string, message: string, retryAfterMs?: number);
30
+ }
31
+ export declare class ConfigError extends AppError {
32
+ constructor(code: string, message: string);
33
+ }
34
+ export declare function asAppError(error: unknown): AppError;