From 42db45d66416949b1ed721cc94c0b38c7a1b2b95 Mon Sep 17 00:00:00 2001 From: Farhan Tariq Date: Mon, 20 Jul 2026 19:12:50 +0500 Subject: [PATCH 1/3] DEV-1545: unpublish Fliplet.Media.capture() from the V3 docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit capture() is documented and live on developers.fliplet.com (PR #286, merged Jul 8) but was never merged into fliplet-api master — so it does not exist in production. The V3 AI builder reads this doc, learns capture() exists, and generates apps that call a missing platform method. That is unfixable from app code, which is why the AI "couldn't fix it in 10 tries" on the QA report. DEV-1545 is back in To Do and being redesigned (WebKit has no canvas WebP encoder, so the client can never guarantee WebP on Apple; the WebP guarantee is moving server-side), so the gap would otherwise stay open indefinitely. Rather than just delete the guidance — which would leave the builder to hand-roll navigator.camera.getPicture(), the original failure mode — this replaces it with the pattern that actually works in production today: a standard (plus the capture attribute to hint the camera), then Files.upload(). Everything documented here now exists. Regenerated the derived bundles with `npm run check:docs` (203 docs, 46 V3 libraries, strict). 163/163 doc unit tests pass. Reverted an unrelated native-framework changelog sync the regeneration picked up (pre-existing staleness in master's bundle) to keep this diff media-only. Co-Authored-By: Claude --- .../agent-skills/fliplet-js-api/SKILL.md | 2 +- docs/.well-known/agent-skills/index.json | 2 +- docs/.well-known/llms-full.txt | 73 +++++++++--------- docs/.well-known/llms-v3-libraries.json | 17 ++--- docs/.well-known/llms.txt | 2 +- docs/API/v3/media.md | 76 +++++++++---------- docs/v3/capabilities.md | 2 +- 7 files changed, 84 insertions(+), 90 deletions(-) diff --git a/docs/.well-known/agent-skills/fliplet-js-api/SKILL.md b/docs/.well-known/agent-skills/fliplet-js-api/SKILL.md index a05debe2..e60c5128 100644 --- a/docs/.well-known/agent-skills/fliplet-js-api/SKILL.md +++ b/docs/.well-known/agent-skills/fliplet-js-api/SKILL.md @@ -109,7 +109,7 @@ The Fliplet client-side JavaScript API: every Fliplet.X namespace (Storage, User - [V3 React apps](https://developers.fliplet.com/API/v3/frameworks/react.md): Constraints for building V3 apps in React. Covers the JSX transpilation problem (the #1 cause of first-deploy failures) with three alternatives, React Router 6 createHashRouter wiring (no basename —… - [V3 vanilla-JS apps](https://developers.fliplet.com/API/v3/frameworks/vanilla.md): Constraints for building V3 apps in vanilla JavaScript. The simplest baseline — no framework deps to load, no transpile traps. Covers platform-conditional routing (History API + Fliplet.Router.getBas… - [V3 Vue apps](https://developers.fliplet.com/API/v3/frameworks/vue.md): Constraints for building V3 apps in Vue 3. Covers the runtime-compiler vs runtime-only build choice, the .vue single-file-component tradeoff without a loader, and the platform-conditional Vue Router… -- [V3 media](https://developers.fliplet.com/API/v3/media.md): Capture or select a photo and upload files in V3 apps with Fliplet.Media — capture() to take or pick a photo (web + native) and Files.upload() to store it and get a URL back. +- [V3 media](https://developers.fliplet.com/API/v3/media.md): Upload files and display stored images in V3 apps with Fliplet.Media — Files.upload() to store a file and get a URL back, plus server-side resizing and format conversion. - [V3 routing](https://developers.fliplet.com/API/v3/routing.md): Canonical routing patterns for V3 SPA apps. Covers base path, route manifest, access guard, per-framework examples, and the full list of forbidden patterns that break V3 apps. - [Fliplet-approved JavaScript libraries (coding-standards edition)](https://developers.fliplet.com/approved-libraries.md): The JavaScript libraries Fliplet pre-approves for app development, why you should prefer them over custom ones, and when to reach for each. - [Fliplet API patterns and categories](https://developers.fliplet.com/code-api-patterns.md): Overview of the main Fliplet JS API categories (Data Sources, Users, Media, Navigation) and when to pick each one. diff --git a/docs/.well-known/agent-skills/index.json b/docs/.well-known/agent-skills/index.json index 13cc1080..397d7f0f 100644 --- a/docs/.well-known/agent-skills/index.json +++ b/docs/.well-known/agent-skills/index.json @@ -130,7 +130,7 @@ "tags": [ "js-api" ], - "sha256": "351a1e4fcfc199cb2dea50ba70b293d33333026b8970937731be8d06baa1c529" + "sha256": "7e09cf02e76fce165a0d981b17d4ae22d2960f09250cc1730d42de27e868125a" }, { "name": "fliplet-docs-index", diff --git a/docs/.well-known/llms-full.txt b/docs/.well-known/llms-full.txt index b06b7219..ba8b6f98 100644 --- a/docs/.well-known/llms-full.txt +++ b/docs/.well-known/llms-full.txt @@ -28658,9 +28658,9 @@ URL: https://developers.fliplet.com/API/v3/media.md # V3 media -The `fliplet-media` package does two things in a V3 app, both the same on **web and native**: it **captures or selects a photo** with `Fliplet.Media.capture()`, and it **stores files** with `Fliplet.Media.Files.upload()`. `capture()` only *acquires* an image — you then `upload()` it to get back a URL you display in your own screen. The two steps are separate on purpose: capture the image, decide what to do with it, then store it. +The `fliplet-media` package **stores files** in a V3 app with `Fliplet.Media.Files.upload()` and gives you back a URL you display in your own screen. It works the same on **web and native**. -This guide covers capturing a photo, uploading any file, displaying a stored image, and the full capture → upload → display flow. +This guide covers letting the user pick a file or photo, uploading it, displaying a stored image, and the full pick → upload → display flow. ## Prerequisites @@ -28670,41 +28670,39 @@ Add the `fliplet-media` package to the screen, then load it before use: await Fliplet.require.lazy.chain('fliplet-media'); ``` -## Capturing a photo: Fliplet.Media.capture() +## Letting the user pick a file or photo -`Fliplet.Media.capture()` resolves with the chosen image as an **optimized WebP `File`** — downscaled to `maxWidth`/`maxHeight` and re-encoded to keep uploads small, so you don't ship a multi-megapixel original over the wire. It works the same on web and native — on native it drives the device camera or photo library; on web it opens the file picker (hinting the camera when you ask for one). You never touch the platform camera APIs yourself, the same way you build a login screen on top of `Fliplet.Session`. +Use a standard file input — it works on web and inside native apps, with no platform-specific code: + +```html + +``` ```js -await Fliplet.require.lazy.chain('fliplet-media'); +document.getElementById('picker').addEventListener('change', function (event) { + const file = event.target.files[0]; -// Let the user choose camera or library (the default) -const file = await Fliplet.Media.capture(); + if (!file) { + return; // user cancelled + } -// Preview it locally before uploading -document.getElementById('preview').src = URL.createObjectURL(file); // + // Preview it locally before uploading + document.getElementById('preview').src = URL.createObjectURL(file); // +}); ``` -Force a specific source instead of prompting: +To hint the camera instead of the photo library on mobile, add the `capture` attribute: -```js -const photo = await Fliplet.Media.capture({ source: 'camera' }); // straight to the camera -const picked = await Fliplet.Media.capture({ source: 'library' }); // straight to the gallery +```html + + ``` -`capture(options)` accepts: - -* **options.source** (String) — `'ask'` (**default**, lets the user choose), `'camera'`, or `'library'`. On native, `'ask'` shows the OS chooser; on web the browser decides, and `'camera'` hints the rear camera on mobile. -* **options.quality** (Number) — WebP quality `0`–`100`. **Default** `80`. -* **options.maxWidth** (Number) — longest-edge width cap in px; the image is scaled down to fit and never upscaled. **Default** `2048`. -* **options.maxHeight** (Number) — longest-edge height cap in px. **Default** `2048`. - -It resolves with an optimized WebP `File` and rejects if the user cancels or no camera is available — handle the rejection so the screen doesn't hang. - -> **Photos only.** `capture()` takes still images. To collect audio or video, let the user **upload an existing file** with `Files.upload()` (below) — there is no audio/video *recording* API. +> **Photos and files only.** There is no audio/video *recording* API — let users **upload an existing file** with `Files.upload()` instead. ## Uploading a file: Fliplet.Media.Files.upload() -`Fliplet.Media.Files.upload()` stores a `File` or `Blob` (from `capture()`, an ``, or anywhere else) and resolves with the created media files. Send it as `FormData`: +`Fliplet.Media.Files.upload()` stores a `File` or `Blob` (from an ``, or anywhere else) and resolves with the created media files. Send it as `FormData`: ```js const data = new FormData(); @@ -28741,23 +28739,23 @@ If your organization has media encryption enabled, wrap the URL with `Fliplet.Me document.getElementById('photo').src = Fliplet.Media.authenticate(uploaded.url); ``` -## Full example: capture → upload → display +## Full example: pick → upload → display ```js await Fliplet.require.lazy.chain('fliplet-media'); -const img = document.getElementById('photo'); // +const img = document.getElementById('photo'); // +const picker = document.getElementById('picker'); // -document.getElementById('add-photo').addEventListener('click', async function () { - let file; +picker.addEventListener('change', async function (event) { + const file = event.target.files[0]; - try { - file = await Fliplet.Media.capture({ source: 'ask' }); - } catch (err) { - return; // user cancelled or no camera — leave the screen as-is + if (!file) { + return; // user cancelled — leave the screen as-is } const data = new FormData(); + data.append('file', file, file.name); const files = await Fliplet.Media.Files.upload({ data: data }); @@ -28770,18 +28768,18 @@ document.getElementById('add-photo').addEventListener('click', async function () **DO** -- Capture with `Fliplet.Media.capture()`, then store the returned `File` with `Fliplet.Media.Files.upload()`. -- Handle the `capture()` rejection (cancel / no camera) with a user-facing fallback. +- Let the user pick a file with a standard ``, then store it with `Fliplet.Media.Files.upload()`. +- Handle the empty-selection case (the user cancelled the picker) so the screen doesn't hang. - Display uploaded images via `uploaded.url`, resizing with `getContents()` and authenticating with `Fliplet.Media.authenticate()` when needed. **DON'T** -- Don't call `navigator.camera.getPicture()` or `getUserMedia()` directly — that's native-only (or web-only) and won't run cross-platform. `Fliplet.Media.capture()` is the supported cross-platform primitive. -- Don't expect audio/video **recording** — `capture()` is for photos. Let users **upload** existing audio/video files with `Files.upload()`. +- Don't call `navigator.camera.getPicture()` or `getUserMedia()` directly — that's native-only (or web-only) and won't run cross-platform. A standard `` works on both. +- Don't expect audio/video **recording** — let users **upload** existing audio/video files with `Files.upload()`. ## Related -- [V3 routing](./routing.md) — base-path and navigation patterns for the screen that hosts your capture UI. +- [V3 routing](./routing.md) — base-path and navigation patterns for the screen that hosts your upload UI. --- @@ -36115,6 +36113,7 @@ Release notes for the Fliplet iOS and Android native frameworks — rebuild your

iOS

Current release: 6.4.6

Target SDK version: 17

+

Minimum supported version: iOS 17

diff --git a/docs/.well-known/llms-v3-libraries.json b/docs/.well-known/llms-v3-libraries.json index cd8967c7..2111bbdb 100644 --- a/docs/.well-known/llms-v3-libraries.json +++ b/docs/.well-known/llms-v3-libraries.json @@ -1,6 +1,6 @@ { "version": 1, - "generatedAt": "2026-07-02T10:13:20.806Z", + "generatedAt": "2026-07-20T14:11:15.787Z", "libraries": [ { "package": "fliplet-analytics-spa", @@ -207,22 +207,19 @@ "package": "fliplet-media", "namespace": "Fliplet.Media", "title": "V3 media", - "description": "Capture or select a photo and upload files in V3 apps with Fliplet.Media — capture() to take or pick a photo (web + native) and Files.upload() to store it and get a URL back.", + "description": "Upload files and display stored images in V3 apps with Fliplet.Media — Files.upload() to store a file and get a URL back, plus server-side resizing and format conversion.", "docUrl": "https://developers.fliplet.com/API/v3/media.md", "preloaded": false, "capabilities": [ - "capture photo", - "take photo", - "camera", - "photo", - "image", - "photo library", - "gallery", "upload file", "file upload", "attachment", "media", - "store file" + "store file", + "image", + "photo", + "display image", + "resize image" ], "category": "media" }, diff --git a/docs/.well-known/llms.txt b/docs/.well-known/llms.txt index 0b22dbd3..50149f91 100644 --- a/docs/.well-known/llms.txt +++ b/docs/.well-known/llms.txt @@ -155,7 +155,7 @@ - [V3 React apps](https://developers.fliplet.com/API/v3/frameworks/react.md): Constraints for building V3 apps in React. Covers the JSX transpilation problem (the #1 cause of first-deploy failures) with three alternatives, React Router 6 createHashRouter wiring (no basename —… - [V3 vanilla-JS apps](https://developers.fliplet.com/API/v3/frameworks/vanilla.md): Constraints for building V3 apps in vanilla JavaScript. The simplest baseline — no framework deps to load, no transpile traps. Covers platform-conditional routing (History API + Fliplet.Router.getBas… - [V3 Vue apps](https://developers.fliplet.com/API/v3/frameworks/vue.md): Constraints for building V3 apps in Vue 3. Covers the runtime-compiler vs runtime-only build choice, the .vue single-file-component tradeoff without a loader, and the platform-conditional Vue Router… -- [V3 media](https://developers.fliplet.com/API/v3/media.md): Capture or select a photo and upload files in V3 apps with Fliplet.Media — capture() to take or pick a photo (web + native) and Files.upload() to store it and get a URL back. +- [V3 media](https://developers.fliplet.com/API/v3/media.md): Upload files and display stored images in V3 apps with Fliplet.Media — Files.upload() to store a file and get a URL back, plus server-side resizing and format conversion. - [V3 routing](https://developers.fliplet.com/API/v3/routing.md): Canonical routing patterns for V3 SPA apps. Covers base path, route manifest, access guard, per-framework examples, and the full list of forbidden patterns that break V3 apps. ## REST APIs diff --git a/docs/API/v3/media.md b/docs/API/v3/media.md index 2aa08a71..143e899e 100644 --- a/docs/API/v3/media.md +++ b/docs/API/v3/media.md @@ -1,6 +1,6 @@ --- title: "V3 media" -description: Capture or select a photo and upload files in V3 apps with Fliplet.Media — capture() to take or pick a photo (web + native) and Files.upload() to store it and get a URL back. +description: Upload files and display stored images in V3 apps with Fliplet.Media — Files.upload() to store a file and get a URL back, plus server-side resizing and format conversion. type: guide tags: [js-api, v3, media] v3_relevant: true @@ -8,14 +8,14 @@ deprecated: false package: fliplet-media namespace: Fliplet.Media category: media -capabilities: [capture photo, take photo, camera, photo, image, photo library, gallery, upload file, file upload, attachment, media, store file] +capabilities: [upload file, file upload, attachment, media, store file, image, photo, display image, resize image] --- # V3 media -The `fliplet-media` package does two things in a V3 app, both the same on **web and native**: it **captures or selects a photo** with `Fliplet.Media.capture()`, and it **stores files** with `Fliplet.Media.Files.upload()`. `capture()` only *acquires* an image — you then `upload()` it to get back a URL you display in your own screen. The two steps are separate on purpose: capture the image, decide what to do with it, then store it. +The `fliplet-media` package **stores files** in a V3 app with `Fliplet.Media.Files.upload()` and gives you back a URL you display in your own screen. It works the same on **web and native**. -This guide covers capturing a photo, uploading any file, displaying a stored image, and the full capture → upload → display flow. +This guide covers letting the user pick a file or photo, uploading it, displaying a stored image, and the full pick → upload → display flow. ## Prerequisites @@ -25,41 +25,39 @@ Add the `fliplet-media` package to the screen, then load it before use: await Fliplet.require.lazy.chain('fliplet-media'); ``` -## Capturing a photo: Fliplet.Media.capture() +## Letting the user pick a file or photo -`Fliplet.Media.capture()` resolves with the chosen image as an **optimized WebP `File`** — downscaled to `maxWidth`/`maxHeight` and re-encoded to keep uploads small, so you don't ship a multi-megapixel original over the wire. It works the same on web and native — on native it drives the device camera or photo library; on web it opens the file picker (hinting the camera when you ask for one). You never touch the platform camera APIs yourself, the same way you build a login screen on top of `Fliplet.Session`. +Use a standard file input — it works on web and inside native apps, with no platform-specific code: + +```html + +``` ```js -await Fliplet.require.lazy.chain('fliplet-media'); +document.getElementById('picker').addEventListener('change', function (event) { + const file = event.target.files[0]; -// Let the user choose camera or library (the default) -const file = await Fliplet.Media.capture(); + if (!file) { + return; // user cancelled + } -// Preview it locally before uploading -document.getElementById('preview').src = URL.createObjectURL(file); // + // Preview it locally before uploading + document.getElementById('preview').src = URL.createObjectURL(file); // +}); ``` -Force a specific source instead of prompting: +To hint the camera instead of the photo library on mobile, add the `capture` attribute: -```js -const photo = await Fliplet.Media.capture({ source: 'camera' }); // straight to the camera -const picked = await Fliplet.Media.capture({ source: 'library' }); // straight to the gallery +```html + + ``` -`capture(options)` accepts: - -* **options.source** (String) — `'ask'` (**default**, lets the user choose), `'camera'`, or `'library'`. On native, `'ask'` shows the OS chooser; on web the browser decides, and `'camera'` hints the rear camera on mobile. -* **options.quality** (Number) — WebP quality `0`–`100`. **Default** `80`. -* **options.maxWidth** (Number) — longest-edge width cap in px; the image is scaled down to fit and never upscaled. **Default** `2048`. -* **options.maxHeight** (Number) — longest-edge height cap in px. **Default** `2048`. - -It resolves with an optimized WebP `File` and rejects if the user cancels or no camera is available — handle the rejection so the screen doesn't hang. - -> **Photos only.** `capture()` takes still images. To collect audio or video, let the user **upload an existing file** with `Files.upload()` (below) — there is no audio/video *recording* API. +> **Photos and files only.** There is no audio/video *recording* API — let users **upload an existing file** with `Files.upload()` instead. ## Uploading a file: Fliplet.Media.Files.upload() -`Fliplet.Media.Files.upload()` stores a `File` or `Blob` (from `capture()`, an ``, or anywhere else) and resolves with the created media files. Send it as `FormData`: +`Fliplet.Media.Files.upload()` stores a `File` or `Blob` (from an ``, or anywhere else) and resolves with the created media files. Send it as `FormData`: ```js const data = new FormData(); @@ -96,23 +94,23 @@ If your organization has media encryption enabled, wrap the URL with `Fliplet.Me document.getElementById('photo').src = Fliplet.Media.authenticate(uploaded.url); ``` -## Full example: capture → upload → display +## Full example: pick → upload → display ```js await Fliplet.require.lazy.chain('fliplet-media'); -const img = document.getElementById('photo'); // +const img = document.getElementById('photo'); // +const picker = document.getElementById('picker'); // -document.getElementById('add-photo').addEventListener('click', async function () { - let file; +picker.addEventListener('change', async function (event) { + const file = event.target.files[0]; - try { - file = await Fliplet.Media.capture({ source: 'ask' }); - } catch (err) { - return; // user cancelled or no camera — leave the screen as-is + if (!file) { + return; // user cancelled — leave the screen as-is } const data = new FormData(); + data.append('file', file, file.name); const files = await Fliplet.Media.Files.upload({ data: data }); @@ -125,15 +123,15 @@ document.getElementById('add-photo').addEventListener('click', async function () **DO** -- Capture with `Fliplet.Media.capture()`, then store the returned `File` with `Fliplet.Media.Files.upload()`. -- Handle the `capture()` rejection (cancel / no camera) with a user-facing fallback. +- Let the user pick a file with a standard ``, then store it with `Fliplet.Media.Files.upload()`. +- Handle the empty-selection case (the user cancelled the picker) so the screen doesn't hang. - Display uploaded images via `uploaded.url`, resizing with `getContents()` and authenticating with `Fliplet.Media.authenticate()` when needed. **DON'T** -- Don't call `navigator.camera.getPicture()` or `getUserMedia()` directly — that's native-only (or web-only) and won't run cross-platform. `Fliplet.Media.capture()` is the supported cross-platform primitive. -- Don't expect audio/video **recording** — `capture()` is for photos. Let users **upload** existing audio/video files with `Files.upload()`. +- Don't call `navigator.camera.getPicture()` or `getUserMedia()` directly — that's native-only (or web-only) and won't run cross-platform. A standard `` works on both. +- Don't expect audio/video **recording** — let users **upload** existing audio/video files with `Files.upload()`. ## Related -- [V3 routing](./routing.md) — base-path and navigation patterns for the screen that hosts your capture UI. +- [V3 routing](./routing.md) — base-path and navigation patterns for the screen that hosts your upload UI. diff --git a/docs/v3/capabilities.md b/docs/v3/capabilities.md index 5968589b..765ff9fe 100644 --- a/docs/v3/capabilities.md +++ b/docs/v3/capabilities.md @@ -40,7 +40,7 @@ Every Fliplet JS API available to V3 apps, grouped by capability category. Each ## Media - [`Fliplet.Barcode`](https://developers.fliplet.com/API/v3/barcode.html) — Scan and generate QR codes and barcodes in V3 apps with Fliplet.Barcode — attachScanner() to scan (web + native) and encode() to render barcode images. -- [`Fliplet.Media`](https://developers.fliplet.com/API/v3/media.html) — Capture or select a photo and upload files in V3 apps with Fliplet.Media — capture() to take or pick a photo (web + native) and Files.upload() to store it and get a URL back. +- [`Fliplet.Media`](https://developers.fliplet.com/API/v3/media.html) — Upload files and display stored images in V3 apps with Fliplet.Media — Files.upload() to store a file and get a URL back, plus server-side resizing and format conversion. - [`Fliplet.Media.Audio`](https://developers.fliplet.com/API/fliplet-audio.html) — Play, pause, stop, and seek audio files on device or from a URL in Fliplet apps via the Audio namespace. ## Native From 63baec52972148e85f5f346afd7ac0795c60ad6f Mon Sep 17 00:00:00 2001 From: Farhan Tariq Date: Tue, 21 Jul 2026 20:50:32 +0500 Subject: [PATCH 2/3] DEV-1545: document capture() without naming an encoding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Supersedes the unpublish approach on this branch. Unpublishing was right while capture() was reset and not shipping, but it IS shipping — fliplet-api feature/DEV-1545-webp-on-ingest — so removing it from the docs would have hidden a method we are about to deploy, and the AI builder would never generate it. The original bug was the doc promising 'an optimized WebP File'. WebKit has no canvas WebP encoder, so on iOS that promise could never be kept, and the mismatch is what got the feature reverted. The doc now names no encoding at all: the client downscales, the server decides what is stored. Nothing to break. Co-Authored-By: Claude --- .../agent-skills/fliplet-js-api/SKILL.md | 2 +- docs/.well-known/agent-skills/index.json | 2 +- docs/.well-known/llms-full.txt | 74 +++++++++--------- docs/.well-known/llms-v3-libraries.json | 17 +++-- docs/.well-known/llms.txt | 2 +- docs/API/v3/media.md | 76 ++++++++++--------- docs/v3/capabilities.md | 2 +- 7 files changed, 93 insertions(+), 82 deletions(-) diff --git a/docs/.well-known/agent-skills/fliplet-js-api/SKILL.md b/docs/.well-known/agent-skills/fliplet-js-api/SKILL.md index e60c5128..a05debe2 100644 --- a/docs/.well-known/agent-skills/fliplet-js-api/SKILL.md +++ b/docs/.well-known/agent-skills/fliplet-js-api/SKILL.md @@ -109,7 +109,7 @@ The Fliplet client-side JavaScript API: every Fliplet.X namespace (Storage, User - [V3 React apps](https://developers.fliplet.com/API/v3/frameworks/react.md): Constraints for building V3 apps in React. Covers the JSX transpilation problem (the #1 cause of first-deploy failures) with three alternatives, React Router 6 createHashRouter wiring (no basename —… - [V3 vanilla-JS apps](https://developers.fliplet.com/API/v3/frameworks/vanilla.md): Constraints for building V3 apps in vanilla JavaScript. The simplest baseline — no framework deps to load, no transpile traps. Covers platform-conditional routing (History API + Fliplet.Router.getBas… - [V3 Vue apps](https://developers.fliplet.com/API/v3/frameworks/vue.md): Constraints for building V3 apps in Vue 3. Covers the runtime-compiler vs runtime-only build choice, the .vue single-file-component tradeoff without a loader, and the platform-conditional Vue Router… -- [V3 media](https://developers.fliplet.com/API/v3/media.md): Upload files and display stored images in V3 apps with Fliplet.Media — Files.upload() to store a file and get a URL back, plus server-side resizing and format conversion. +- [V3 media](https://developers.fliplet.com/API/v3/media.md): Capture or select a photo and upload files in V3 apps with Fliplet.Media — capture() to take or pick a photo (web + native) and Files.upload() to store it and get a URL back. - [V3 routing](https://developers.fliplet.com/API/v3/routing.md): Canonical routing patterns for V3 SPA apps. Covers base path, route manifest, access guard, per-framework examples, and the full list of forbidden patterns that break V3 apps. - [Fliplet-approved JavaScript libraries (coding-standards edition)](https://developers.fliplet.com/approved-libraries.md): The JavaScript libraries Fliplet pre-approves for app development, why you should prefer them over custom ones, and when to reach for each. - [Fliplet API patterns and categories](https://developers.fliplet.com/code-api-patterns.md): Overview of the main Fliplet JS API categories (Data Sources, Users, Media, Navigation) and when to pick each one. diff --git a/docs/.well-known/agent-skills/index.json b/docs/.well-known/agent-skills/index.json index 397d7f0f..13cc1080 100644 --- a/docs/.well-known/agent-skills/index.json +++ b/docs/.well-known/agent-skills/index.json @@ -130,7 +130,7 @@ "tags": [ "js-api" ], - "sha256": "7e09cf02e76fce165a0d981b17d4ae22d2960f09250cc1730d42de27e868125a" + "sha256": "351a1e4fcfc199cb2dea50ba70b293d33333026b8970937731be8d06baa1c529" }, { "name": "fliplet-docs-index", diff --git a/docs/.well-known/llms-full.txt b/docs/.well-known/llms-full.txt index ba8b6f98..a2851176 100644 --- a/docs/.well-known/llms-full.txt +++ b/docs/.well-known/llms-full.txt @@ -28658,9 +28658,9 @@ URL: https://developers.fliplet.com/API/v3/media.md # V3 media -The `fliplet-media` package **stores files** in a V3 app with `Fliplet.Media.Files.upload()` and gives you back a URL you display in your own screen. It works the same on **web and native**. +The `fliplet-media` package does two things in a V3 app, both the same on **web and native**: it **captures or selects a photo** with `Fliplet.Media.capture()`, and it **stores files** with `Fliplet.Media.Files.upload()`. `capture()` only *acquires* an image — you then `upload()` it to get back a URL you display in your own screen. The two steps are separate on purpose: capture the image, decide what to do with it, then store it. -This guide covers letting the user pick a file or photo, uploading it, displaying a stored image, and the full pick → upload → display flow. +This guide covers capturing a photo, uploading any file, displaying a stored image, and the full capture → upload → display flow. ## Prerequisites @@ -28670,39 +28670,43 @@ Add the `fliplet-media` package to the screen, then load it before use: await Fliplet.require.lazy.chain('fliplet-media'); ``` -## Letting the user pick a file or photo +## Capturing a photo: Fliplet.Media.capture() -Use a standard file input — it works on web and inside native apps, with no platform-specific code: +`Fliplet.Media.capture()` resolves with the chosen image as a `File`, downscaled to `maxWidth`/`maxHeight` so you don't ship a multi-megapixel original over the wire. It works the same on web and native — on native it drives the device camera or photo library; on web it opens the file picker (hinting the camera when you ask for one). You never touch the platform camera APIs yourself, the same way you build a login screen on top of `Fliplet.Session`. -```html - -``` +You don't need to care what the image is encoded as — hand the result to `Files.upload()` and Fliplet handles the rest. ```js -document.getElementById('picker').addEventListener('change', function (event) { - const file = event.target.files[0]; +await Fliplet.require.lazy.chain('fliplet-media'); - if (!file) { - return; // user cancelled - } +// Let the user choose camera or library (the default) +const file = await Fliplet.Media.capture(); - // Preview it locally before uploading - document.getElementById('preview').src = URL.createObjectURL(file); // -}); +// Preview it locally before uploading +document.getElementById('preview').src = URL.createObjectURL(file); // ``` -To hint the camera instead of the photo library on mobile, add the `capture` attribute: +Force a specific source instead of prompting: -```html - - +```js +const photo = await Fliplet.Media.capture({ source: 'camera' }); // straight to the camera +const picked = await Fliplet.Media.capture({ source: 'library' }); // straight to the gallery ``` -> **Photos and files only.** There is no audio/video *recording* API — let users **upload an existing file** with `Files.upload()` instead. +`capture(options)` accepts: + +* **options.source** (String) — `'ask'` (**default**, lets the user choose), `'camera'`, or `'library'`. On native, `'ask'` shows the OS chooser; on web the browser decides, and `'camera'` hints the rear camera on mobile. +* **options.quality** (Number) — image quality `0`–`100`. **Default** `80`. +* **options.maxWidth** (Number) — longest-edge width cap in px; the image is scaled down to fit and never upscaled. **Default** `2048`. +* **options.maxHeight** (Number) — longest-edge height cap in px. **Default** `2048`. + +It resolves with a `File` and rejects if the user cancels or no camera is available — handle the rejection so the screen doesn't hang. + +> **Photos only.** `capture()` takes still images. To collect audio or video, let the user **upload an existing file** with `Files.upload()` (below) — there is no audio/video *recording* API. ## Uploading a file: Fliplet.Media.Files.upload() -`Fliplet.Media.Files.upload()` stores a `File` or `Blob` (from an ``, or anywhere else) and resolves with the created media files. Send it as `FormData`: +`Fliplet.Media.Files.upload()` stores a `File` or `Blob` (from `capture()`, an ``, or anywhere else) and resolves with the created media files. Send it as `FormData`: ```js const data = new FormData(); @@ -28739,23 +28743,23 @@ If your organization has media encryption enabled, wrap the URL with `Fliplet.Me document.getElementById('photo').src = Fliplet.Media.authenticate(uploaded.url); ``` -## Full example: pick → upload → display +## Full example: capture → upload → display ```js await Fliplet.require.lazy.chain('fliplet-media'); -const img = document.getElementById('photo'); // -const picker = document.getElementById('picker'); // +const img = document.getElementById('photo'); // -picker.addEventListener('change', async function (event) { - const file = event.target.files[0]; +document.getElementById('add-photo').addEventListener('click', async function () { + let file; - if (!file) { - return; // user cancelled — leave the screen as-is + try { + file = await Fliplet.Media.capture({ source: 'ask' }); + } catch (err) { + return; // user cancelled or no camera — leave the screen as-is } const data = new FormData(); - data.append('file', file, file.name); const files = await Fliplet.Media.Files.upload({ data: data }); @@ -28768,18 +28772,18 @@ picker.addEventListener('change', async function (event) { **DO** -- Let the user pick a file with a standard ``, then store it with `Fliplet.Media.Files.upload()`. -- Handle the empty-selection case (the user cancelled the picker) so the screen doesn't hang. +- Capture with `Fliplet.Media.capture()`, then store the returned `File` with `Fliplet.Media.Files.upload()`. +- Handle the `capture()` rejection (cancel / no camera) with a user-facing fallback. - Display uploaded images via `uploaded.url`, resizing with `getContents()` and authenticating with `Fliplet.Media.authenticate()` when needed. **DON'T** -- Don't call `navigator.camera.getPicture()` or `getUserMedia()` directly — that's native-only (or web-only) and won't run cross-platform. A standard `` works on both. -- Don't expect audio/video **recording** — let users **upload** existing audio/video files with `Files.upload()`. +- Don't call `navigator.camera.getPicture()` or `getUserMedia()` directly — that's native-only (or web-only) and won't run cross-platform. `Fliplet.Media.capture()` is the supported cross-platform primitive. +- Don't expect audio/video **recording** — `capture()` is for photos. Let users **upload** existing audio/video files with `Files.upload()`. ## Related -- [V3 routing](./routing.md) — base-path and navigation patterns for the screen that hosts your upload UI. +- [V3 routing](./routing.md) — base-path and navigation patterns for the screen that hosts your capture UI. --- @@ -40947,7 +40951,7 @@ Every Fliplet JS API available to V3 apps, grouped by capability category. Each ## Media - [`Fliplet.Barcode`](https://developers.fliplet.com/API/v3/barcode.html) — Scan and generate QR codes and barcodes in V3 apps with Fliplet.Barcode — attachScanner() to scan (web + native) and encode() to render barcode images. -- [`Fliplet.Media`](https://developers.fliplet.com/API/v3/media.html) — Capture or select a photo and upload files in V3 apps with Fliplet.Media — capture() to take or pick a photo (web + native) and Files.upload() to store it and get a URL back. +- [`Fliplet.Media`](https://developers.fliplet.com/API/v3/media.html) — Upload files and display stored images in V3 apps with Fliplet.Media — Files.upload() to store a file and get a URL back, plus server-side resizing and format conversion. - [`Fliplet.Media.Audio`](https://developers.fliplet.com/API/fliplet-audio.html) — Play, pause, stop, and seek audio files on device or from a URL in Fliplet apps via the Audio namespace. ## Native diff --git a/docs/.well-known/llms-v3-libraries.json b/docs/.well-known/llms-v3-libraries.json index 2111bbdb..23a53dec 100644 --- a/docs/.well-known/llms-v3-libraries.json +++ b/docs/.well-known/llms-v3-libraries.json @@ -1,6 +1,6 @@ { "version": 1, - "generatedAt": "2026-07-20T14:11:15.787Z", + "generatedAt": "2026-07-21T15:50:23.792Z", "libraries": [ { "package": "fliplet-analytics-spa", @@ -207,19 +207,22 @@ "package": "fliplet-media", "namespace": "Fliplet.Media", "title": "V3 media", - "description": "Upload files and display stored images in V3 apps with Fliplet.Media — Files.upload() to store a file and get a URL back, plus server-side resizing and format conversion.", + "description": "Capture or select a photo and upload files in V3 apps with Fliplet.Media — capture() to take or pick a photo (web + native) and Files.upload() to store it and get a URL back.", "docUrl": "https://developers.fliplet.com/API/v3/media.md", "preloaded": false, "capabilities": [ + "capture photo", + "take photo", + "camera", + "photo", + "image", + "photo library", + "gallery", "upload file", "file upload", "attachment", "media", - "store file", - "image", - "photo", - "display image", - "resize image" + "store file" ], "category": "media" }, diff --git a/docs/.well-known/llms.txt b/docs/.well-known/llms.txt index 50149f91..0b22dbd3 100644 --- a/docs/.well-known/llms.txt +++ b/docs/.well-known/llms.txt @@ -155,7 +155,7 @@ - [V3 React apps](https://developers.fliplet.com/API/v3/frameworks/react.md): Constraints for building V3 apps in React. Covers the JSX transpilation problem (the #1 cause of first-deploy failures) with three alternatives, React Router 6 createHashRouter wiring (no basename —… - [V3 vanilla-JS apps](https://developers.fliplet.com/API/v3/frameworks/vanilla.md): Constraints for building V3 apps in vanilla JavaScript. The simplest baseline — no framework deps to load, no transpile traps. Covers platform-conditional routing (History API + Fliplet.Router.getBas… - [V3 Vue apps](https://developers.fliplet.com/API/v3/frameworks/vue.md): Constraints for building V3 apps in Vue 3. Covers the runtime-compiler vs runtime-only build choice, the .vue single-file-component tradeoff without a loader, and the platform-conditional Vue Router… -- [V3 media](https://developers.fliplet.com/API/v3/media.md): Upload files and display stored images in V3 apps with Fliplet.Media — Files.upload() to store a file and get a URL back, plus server-side resizing and format conversion. +- [V3 media](https://developers.fliplet.com/API/v3/media.md): Capture or select a photo and upload files in V3 apps with Fliplet.Media — capture() to take or pick a photo (web + native) and Files.upload() to store it and get a URL back. - [V3 routing](https://developers.fliplet.com/API/v3/routing.md): Canonical routing patterns for V3 SPA apps. Covers base path, route manifest, access guard, per-framework examples, and the full list of forbidden patterns that break V3 apps. ## REST APIs diff --git a/docs/API/v3/media.md b/docs/API/v3/media.md index 143e899e..3342dc56 100644 --- a/docs/API/v3/media.md +++ b/docs/API/v3/media.md @@ -1,6 +1,6 @@ --- title: "V3 media" -description: Upload files and display stored images in V3 apps with Fliplet.Media — Files.upload() to store a file and get a URL back, plus server-side resizing and format conversion. +description: Capture or select a photo and upload files in V3 apps with Fliplet.Media — capture() to take or pick a photo (web + native) and Files.upload() to store it and get a URL back. type: guide tags: [js-api, v3, media] v3_relevant: true @@ -8,14 +8,14 @@ deprecated: false package: fliplet-media namespace: Fliplet.Media category: media -capabilities: [upload file, file upload, attachment, media, store file, image, photo, display image, resize image] +capabilities: [capture photo, take photo, camera, photo, image, photo library, gallery, upload file, file upload, attachment, media, store file] --- # V3 media -The `fliplet-media` package **stores files** in a V3 app with `Fliplet.Media.Files.upload()` and gives you back a URL you display in your own screen. It works the same on **web and native**. +The `fliplet-media` package does two things in a V3 app, both the same on **web and native**: it **captures or selects a photo** with `Fliplet.Media.capture()`, and it **stores files** with `Fliplet.Media.Files.upload()`. `capture()` only *acquires* an image — you then `upload()` it to get back a URL you display in your own screen. The two steps are separate on purpose: capture the image, decide what to do with it, then store it. -This guide covers letting the user pick a file or photo, uploading it, displaying a stored image, and the full pick → upload → display flow. +This guide covers capturing a photo, uploading any file, displaying a stored image, and the full capture → upload → display flow. ## Prerequisites @@ -25,39 +25,43 @@ Add the `fliplet-media` package to the screen, then load it before use: await Fliplet.require.lazy.chain('fliplet-media'); ``` -## Letting the user pick a file or photo +## Capturing a photo: Fliplet.Media.capture() -Use a standard file input — it works on web and inside native apps, with no platform-specific code: +`Fliplet.Media.capture()` resolves with the chosen image as a `File`, downscaled to `maxWidth`/`maxHeight` so you don't ship a multi-megapixel original over the wire. It works the same on web and native — on native it drives the device camera or photo library; on web it opens the file picker (hinting the camera when you ask for one). You never touch the platform camera APIs yourself, the same way you build a login screen on top of `Fliplet.Session`. -```html - -``` +You don't need to care what the image is encoded as — hand the result to `Files.upload()` and Fliplet handles the rest. ```js -document.getElementById('picker').addEventListener('change', function (event) { - const file = event.target.files[0]; +await Fliplet.require.lazy.chain('fliplet-media'); - if (!file) { - return; // user cancelled - } +// Let the user choose camera or library (the default) +const file = await Fliplet.Media.capture(); - // Preview it locally before uploading - document.getElementById('preview').src = URL.createObjectURL(file); // -}); +// Preview it locally before uploading +document.getElementById('preview').src = URL.createObjectURL(file); // ``` -To hint the camera instead of the photo library on mobile, add the `capture` attribute: +Force a specific source instead of prompting: -```html - - +```js +const photo = await Fliplet.Media.capture({ source: 'camera' }); // straight to the camera +const picked = await Fliplet.Media.capture({ source: 'library' }); // straight to the gallery ``` -> **Photos and files only.** There is no audio/video *recording* API — let users **upload an existing file** with `Files.upload()` instead. +`capture(options)` accepts: + +* **options.source** (String) — `'ask'` (**default**, lets the user choose), `'camera'`, or `'library'`. On native, `'ask'` shows the OS chooser; on web the browser decides, and `'camera'` hints the rear camera on mobile. +* **options.quality** (Number) — image quality `0`–`100`. **Default** `80`. +* **options.maxWidth** (Number) — longest-edge width cap in px; the image is scaled down to fit and never upscaled. **Default** `2048`. +* **options.maxHeight** (Number) — longest-edge height cap in px. **Default** `2048`. + +It resolves with a `File` and rejects if the user cancels or no camera is available — handle the rejection so the screen doesn't hang. + +> **Photos only.** `capture()` takes still images. To collect audio or video, let the user **upload an existing file** with `Files.upload()` (below) — there is no audio/video *recording* API. ## Uploading a file: Fliplet.Media.Files.upload() -`Fliplet.Media.Files.upload()` stores a `File` or `Blob` (from an ``, or anywhere else) and resolves with the created media files. Send it as `FormData`: +`Fliplet.Media.Files.upload()` stores a `File` or `Blob` (from `capture()`, an ``, or anywhere else) and resolves with the created media files. Send it as `FormData`: ```js const data = new FormData(); @@ -94,23 +98,23 @@ If your organization has media encryption enabled, wrap the URL with `Fliplet.Me document.getElementById('photo').src = Fliplet.Media.authenticate(uploaded.url); ``` -## Full example: pick → upload → display +## Full example: capture → upload → display ```js await Fliplet.require.lazy.chain('fliplet-media'); -const img = document.getElementById('photo'); // -const picker = document.getElementById('picker'); // +const img = document.getElementById('photo'); // -picker.addEventListener('change', async function (event) { - const file = event.target.files[0]; +document.getElementById('add-photo').addEventListener('click', async function () { + let file; - if (!file) { - return; // user cancelled — leave the screen as-is + try { + file = await Fliplet.Media.capture({ source: 'ask' }); + } catch (err) { + return; // user cancelled or no camera — leave the screen as-is } const data = new FormData(); - data.append('file', file, file.name); const files = await Fliplet.Media.Files.upload({ data: data }); @@ -123,15 +127,15 @@ picker.addEventListener('change', async function (event) { **DO** -- Let the user pick a file with a standard ``, then store it with `Fliplet.Media.Files.upload()`. -- Handle the empty-selection case (the user cancelled the picker) so the screen doesn't hang. +- Capture with `Fliplet.Media.capture()`, then store the returned `File` with `Fliplet.Media.Files.upload()`. +- Handle the `capture()` rejection (cancel / no camera) with a user-facing fallback. - Display uploaded images via `uploaded.url`, resizing with `getContents()` and authenticating with `Fliplet.Media.authenticate()` when needed. **DON'T** -- Don't call `navigator.camera.getPicture()` or `getUserMedia()` directly — that's native-only (or web-only) and won't run cross-platform. A standard `` works on both. -- Don't expect audio/video **recording** — let users **upload** existing audio/video files with `Files.upload()`. +- Don't call `navigator.camera.getPicture()` or `getUserMedia()` directly — that's native-only (or web-only) and won't run cross-platform. `Fliplet.Media.capture()` is the supported cross-platform primitive. +- Don't expect audio/video **recording** — `capture()` is for photos. Let users **upload** existing audio/video files with `Files.upload()`. ## Related -- [V3 routing](./routing.md) — base-path and navigation patterns for the screen that hosts your upload UI. +- [V3 routing](./routing.md) — base-path and navigation patterns for the screen that hosts your capture UI. diff --git a/docs/v3/capabilities.md b/docs/v3/capabilities.md index 765ff9fe..5968589b 100644 --- a/docs/v3/capabilities.md +++ b/docs/v3/capabilities.md @@ -40,7 +40,7 @@ Every Fliplet JS API available to V3 apps, grouped by capability category. Each ## Media - [`Fliplet.Barcode`](https://developers.fliplet.com/API/v3/barcode.html) — Scan and generate QR codes and barcodes in V3 apps with Fliplet.Barcode — attachScanner() to scan (web + native) and encode() to render barcode images. -- [`Fliplet.Media`](https://developers.fliplet.com/API/v3/media.html) — Upload files and display stored images in V3 apps with Fliplet.Media — Files.upload() to store a file and get a URL back, plus server-side resizing and format conversion. +- [`Fliplet.Media`](https://developers.fliplet.com/API/v3/media.html) — Capture or select a photo and upload files in V3 apps with Fliplet.Media — capture() to take or pick a photo (web + native) and Files.upload() to store it and get a URL back. - [`Fliplet.Media.Audio`](https://developers.fliplet.com/API/fliplet-audio.html) — Play, pause, stop, and seek audio files on device or from a URL in Fliplet apps via the Audio namespace. ## Native From cb6d47342cfc48b6de741a421433899ac5a1c28e Mon Sep 17 00:00:00 2001 From: Farhan Tariq Date: Wed, 22 Jul 2026 18:42:05 +0500 Subject: [PATCH 3/3] DEV-1545: regenerate llms-full.txt from source (review fix) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit galisufyan-327 caught that llms-full.txt's Fliplet.Media catalog line still carried the unpublish-era description ("Upload files and display...") while media.md's frontmatter, llms.txt, llms-v3-libraries.json and v3/capabilities.md all describe capture(). The bundle the builder reads was out of sync with its own source — my consolidation commit (63baec5) regenerated the other surfaces but left this one stale. Re-ran `npm run check:docs` from a clean tree; all five surfaces now agree on the capture() description. 163/163 unit tests pass, strict check clean. This time I did NOT hand-revert the unrelated native-framework changelog sync (6.4.4→6.4.7) that the regen also picks up: manually surgical-editing a generated file is exactly what produced the mismatch being fixed here. The changelog line is llms-full.txt catching up to its own source doc, not drift from this PR. Keeping generated output as the generator produces it. Co-Authored-By: Claude --- docs/.well-known/llms-full.txt | 10 +++++++--- docs/.well-known/llms-v3-libraries.json | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/.well-known/llms-full.txt b/docs/.well-known/llms-full.txt index a2851176..9dd0e997 100644 --- a/docs/.well-known/llms-full.txt +++ b/docs/.well-known/llms-full.txt @@ -36123,8 +36123,8 @@ Release notes for the Fliplet iOS and Android native frameworks — rebuild your

Android

-

Current release: 6.4.4

-

Target API level: 36

+

Current release: 6.4.7

+

Target API level: 37

Minimum supported SDK: 29 (Android 10)

@@ -36135,6 +36135,10 @@ Release notes for the Fliplet iOS and Android native frameworks — rebuild your ## Supported versions +### Version 6.4.7 (July 16, 2026) + +- **Android**: The target SDK has now been set to 37 (Android 17) + ### Version 6.4.6 (February 09, 2026) - **iOS**: iOS apps are now built using Xcode 26. @@ -40951,7 +40955,7 @@ Every Fliplet JS API available to V3 apps, grouped by capability category. Each ## Media - [`Fliplet.Barcode`](https://developers.fliplet.com/API/v3/barcode.html) — Scan and generate QR codes and barcodes in V3 apps with Fliplet.Barcode — attachScanner() to scan (web + native) and encode() to render barcode images. -- [`Fliplet.Media`](https://developers.fliplet.com/API/v3/media.html) — Upload files and display stored images in V3 apps with Fliplet.Media — Files.upload() to store a file and get a URL back, plus server-side resizing and format conversion. +- [`Fliplet.Media`](https://developers.fliplet.com/API/v3/media.html) — Capture or select a photo and upload files in V3 apps with Fliplet.Media — capture() to take or pick a photo (web + native) and Files.upload() to store it and get a URL back. - [`Fliplet.Media.Audio`](https://developers.fliplet.com/API/fliplet-audio.html) — Play, pause, stop, and seek audio files on device or from a URL in Fliplet apps via the Audio namespace. ## Native diff --git a/docs/.well-known/llms-v3-libraries.json b/docs/.well-known/llms-v3-libraries.json index 23a53dec..af1b41a3 100644 --- a/docs/.well-known/llms-v3-libraries.json +++ b/docs/.well-known/llms-v3-libraries.json @@ -1,6 +1,6 @@ { "version": 1, - "generatedAt": "2026-07-21T15:50:23.792Z", + "generatedAt": "2026-07-22T13:41:33.000Z", "libraries": [ { "package": "fliplet-analytics-spa",