Skip to content

Add in app video creation example - #14

Open
musab123-afk wants to merge 3 commits into
masterfrom
add-in-app-video-creation-example
Open

Add in app video creation example#14
musab123-afk wants to merge 3 commits into
masterfrom
add-in-app-video-creation-example

Conversation

@musab123-afk

Copy link
Copy Markdown
Collaborator

Companion code for Add video creation to your app without building an editor (https://shotstack.io/learn/add-video-creation-to-your-app/): an embedded Studio SDK editor, a quick form, and a one-click headless render, all through one render proxy that keeps the API key server-side, records render ownership, validates asset URLs on both render paths, and rate limits per user.

Gated live on the sandbox: all three paths render to done (the editor verified mounting in headless Chrome), missing and wrong keys fail with one line and a non-zero exit, non-HTTPS and private-address asset URLs are rejected on both render paths, and the ownership record keeps one user's renders invisible to another. Second commit addresses code review: the webhook receiver re-fetches the render from the API instead of trusting the unauthenticated payload, the private-address check covers IPv4-mapped and link-local IPv6, the gallery seeds from the user's own renders on load, and the headless path gained the audio track the other two paths already had. Prettier passes with the root config.

Companion code for the "Add video creation to your app without
building an editor" guide: an embedded Studio SDK editor, a quick
form, and a one-click headless render, all through one render proxy
that keeps the API key server-side, records render ownership,
validates asset URLs on both render paths, and rate limits per user.
Server: re-fetch the render from the API in the webhook receiver instead of
trusting the unauthenticated payload's url, widen the private-address check to
IPv4-mapped, unique-local and link-local IPv6, match leading whitespace in the
asset-URL collector so " https://..." can't skip validation, and cap the
request body.

Client: register the form, headless and reset handlers without waiting on the
editor mount so they work while it loads, seed the gallery from the user's own
renders on load, add the missing audio track to the headless edit so all three
paths produce the same video, and report a missing render proxy clearly instead
of a JSON parse error.
@vercel

vercel Bot commented Sep 1, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
reelestate Ignored Ignored Preview Sep 9, 2026 11:44am UTC

@dazzatronus dazzatronus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review — STANDARDS.md must be followed

Public cookbook code is copy-paste for customers. Blocking on STANDARDS.md gaps (and one security teaching hole). Align with examples/_template/ and root Prettier — not Studio SDK formatting.

Blockers (STANDARDS)

  1. .env.example incomplete — STANDARDS: empty value + comment with URL above each variable. This example also reads SHOTSTACK_ENV, SHOTSTACK_TEMPLATE_ID, RATE_LIMIT, PORT. Document each (empty) or drop undocumented knobs from the README/server contract.
  2. README vs template / STE — Use the five-section shape from _template (Related guide: line). Shorten Requirements / intro to STE limits (≤20 words/instruction, ≤25/description).
  3. Asset URL validation + redirects (server.js) — DNS checks the hostname, then fetch(..., { redirect: 'follow' }) can land on a private address. For an example that teaches URL validation, refuse redirects, re-validate the final URL, or document this next to the DNS-TOCTOU note.

Already good

  • package.json name / engines / format script
  • Key held server-side; ownership; rate-limit honesty in comments
  • Second commit webhook re-fetch / IPv6 private ranges / gallery seed / headless audio

Please re-run the STANDARDS “before you make a PR” checklist (no key / wrong key / README sequence / prettier) after fixes.

@@ -0,0 +1,2 @@
# https://dashboard.shotstack.io/register
SHOTSTACK_API_KEY=

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

STANDARDS — API keys: document every env var this example reads (SHOTSTACK_ENV, SHOTSTACK_TEMPLATE_ID, optional RATE_LIMIT / PORT) with an empty value and a comment+URL above each line. A missing key must fail with your one-line message, not a late API error.


let head;
try {
head = await fetch(url, { method: 'HEAD', redirect: 'follow' });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness / teaching: after the DNS private-address check, redirect: "follow" can 302 onto link-local / RFC1918. Harden (no follow, or re-check final URL host) or spell this out beside the DNS-TOCTOU comment — STANDARDS expects examples to be safe to copy.

proxy. The proxy holds the API key, records which user owns each render, validates user-supplied
asset URLs, and rate limits each user.

Companion code for [Add video creation to your app without building an editor](https://shotstack.io/learn/add-video-creation-to-your-app/).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

STANDARDS — README: match examples/_template (Related guide: …) and STE (short sentences, active voice). Trim the Requirements sandbox-key sentence — it currently runs long for a description.

@dazzatronus dazzatronus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up from a STANDARDS / public-polish pass (beyond the first review):

  1. Pin Studio SDK exactlypackage.json has ^2.15.1 while the lockfile resolves 2.18.0. Public demos should pin an exact version (and keep lockfile in sync) so fresh clones don’t silently drift.
  2. Timeline CSS — on [data-shotstack-timeline], SDK expects a fixed height and overflow: hidden. Add overflow: hidden so the timeline doesn’t paint outside the box.
  3. Outbound fetch timeouts — add AbortSignal.timeout(...) (or equivalent) on Shotstack/HEAD fetches so a hung network fails with one line instead of hanging the proxy (see examples/first-render).

Still blocked on the earlier STANDARDS items (.env.example, README/STE, redirect-after-DNS).

"node": ">=20"
},
"dependencies": {
"@shotstack/shotstack-studio": "^2.15.1"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pin an exact @shotstack/shotstack-studio version (lockfile currently resolves 2.18.0). Caret ranges make public cookbook clones non-reproducible.

.env.example documents every variable the proxy reads (SHOTSTACK_ENV,
SHOTSTACK_TEMPLATE_ID, RATE_LIMIT, PORT) with an empty value and a comment
above each. server.js uses || so an empty value in .env falls back to the
default, and a bad PORT, RATE_LIMIT or SHOTSTACK_ENV exits with one line.

README follows the _template shape (Related guide line, five sections) and
STE sentence limits, and says the x-demo-user header is a stand-in for auth.

Asset URL validation refuses redirects: the HEAD check uses redirect manual
and rejects any 3xx, so a public host cannot 302 onto a private address after
the DNS check. The comment beside the DNS note explains the alternative.

Studio SDK pinned to 2.18.0 to match the lockfile. The timeline container
has overflow hidden. Every Shotstack fetch goes through an api() helper with
a 30 s AbortSignal.timeout, the HEAD check has 10 s, and timeouts and network
failures return one actionable line instead of hanging the proxy.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants