You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
vescape-app/vescape-server#29 adds Hosted Asset storage, normalization, public reads, resizing, deletion, and caller-supplied Asset IDs.
vescape-app/vescape-server#33 adds the Account-authenticated map-points group and ownership rules.
What to build
Add one reusable native photo pipeline for Map Point photos. It accepts picker and camera files in modern phone formats, writes a normalized app-owned photo, uploads exactly one image through the existing authenticated API boundary, and durably tracks transfer and deletion across process death, offline periods, background work, sign-out, and retry.
Native owns normalized files, the Asset job queue, remote identity, retry policy, and long-lived work. JS receives stable state and sends intents. This slice exposes only the finite map-points group. Future features may extend the pipeline without adding another codec, multipart client, queue, or retry loop.
Use the existing Device Token API boundary, Account generation and reset guards, App Status gating, connectivity policy, background ride window, cold-launch resume, diagnostics, and stale-response protection already present on dev.
Normalization contract
Decode JPEG, PNG, WebP, HEIC or HEIF, and AVIF inputs where the platform supplies a decoder.
Apply encoded orientation before sizing.
Remove EXIF and other metadata, including GPS.
Preserve aspect ratio, never upscale, and limit the long edge to 4096px.
Prefer WebP where platform encoding is reliable. Otherwise use JPEG. AVIF is never required on the wire.
Use one parity-linked quality policy with deterministic MIME type, extension, width, height, byte count, and SHA-256 over normalized bytes.
Publish through temp file, final file, then durable row. Failed normalization or publication leaves no visible partial state or orphan temp file.
Callers use the normalized result and never retain the full original.
Wire contract
Mint and persist a UUIDv4 Asset ID before the first attempt.
Upload multipart fields id and file to POST /assets/map-points. file contains exactly one normalized image.
Retrying the same ID after an ambiguous response addresses the same immutable Asset. A 200 response means the existing Asset was found, and 201 means it was created.
Use the existing VescapeApi Device Token credential during native and background work. Never send Internal API keys or caller-selected group fields.
Stream multipart bytes from disk. Do not send image bytes through the JS bridge or build a possible 50 MiB body in one memory buffer.
Strictly parse the server response fields id, url, width, height, and bytes.
Persist group and Asset ID as durable remote identity. Treat the URL as display data, never as an object-store identity.
Treat upload 409 asset-owner-conflict as permanent for that job. It means the generated ID belongs to another Account and must not be retried under a new ID automatically.
Treat delete 204 and every delete 404 as converged. The server deliberately hides wrong ownership behind 404.
Treat delete 409 asset-in-use as blocked on detachment. Keep the delete job and retry only after the feature has removed the live reference.
Durable state
Use an additive native table or manifest with states equivalent to:
Keep local owner identity, normalized file identity, group, Asset ID, attempt metadata, last classified failure, remote response data, and the Account generation needed to reject stale responses.
Network, timeout, server-unavailable, and future 429 results back off without dropping the normalized file.
Authentication and App Status failures use the shared API policy and diagnostics.
Cold launch, foreground, connectivity regain, sign-in, and the existing background ride window resume eligible work.
Sign-out stops transfer without discarding queued media. Signing back into the same Account resumes it.
Account reset invalidates old work before replacing local data. An old response cannot publish into a new Account's database.
Keep the normalized file until the owning feature confirms its remote reference is durable. The pipeline may then release it when that feature has no local-storage requirement.
Likely files
modules/vescape-core/ios/api/VescapeApi.swift - add streamed multipart support to the shared Device Token boundary.
Parent
vescape-app/vescape-server#29adds Hosted Asset storage, normalization, public reads, resizing, deletion, and caller-supplied Asset IDs.vescape-app/vescape-server#33adds the Account-authenticatedmap-pointsgroup and ownership rules.What to build
Add one reusable native photo pipeline for Map Point photos. It accepts picker and camera files in modern phone formats, writes a normalized app-owned photo, uploads exactly one image through the existing authenticated API boundary, and durably tracks transfer and deletion across process death, offline periods, background work, sign-out, and retry.
Native owns normalized files, the Asset job queue, remote identity, retry policy, and long-lived work. JS receives stable state and sends intents. This slice exposes only the finite
map-pointsgroup. Future features may extend the pipeline without adding another codec, multipart client, queue, or retry loop.Use the existing Device Token API boundary, Account generation and reset guards, App Status gating, connectivity policy, background ride window, cold-launch resume, diagnostics, and stale-response protection already present on
dev.Normalization contract
Wire contract
idandfiletoPOST /assets/map-points.filecontains exactly one normalized image.200response means the existing Asset was found, and201means it was created.VescapeApiDevice Token credential during native and background work. Never send Internal API keys or caller-selected group fields.id,url,width,height, andbytes.409 asset-owner-conflictas permanent for that job. It means the generated ID belongs to another Account and must not be retried under a new ID automatically.204and every delete404as converged. The server deliberately hides wrong ownership behind404.409 asset-in-useas blocked on detachment. Keep the delete job and retry only after the feature has removed the live reference.Durable state
Use an additive native table or manifest with states equivalent to:
Keep local owner identity, normalized file identity, group, Asset ID, attempt metadata, last classified failure, remote response data, and the Account generation needed to reject stale responses.
429results back off without dropping the normalized file.Likely files
modules/vescape-core/ios/api/VescapeApi.swift- add streamed multipart support to the shared Device Token boundary.modules/vescape-core/android/src/main/java/expo/modules/vescapecore/api/VescapeApi.kt- Android parity peer.modules/vescape-core/ios/assets/- new normalization, manifest, transfer engine, and focused tests.modules/vescape-core/android/src/main/java/expo/modules/vescapecore/assets/- Android parity package.modules/vescape-core/ios/telemetry/TelemetryDatabase.swift- additive durable Asset-job schema.modules/vescape-core/android/src/main/java/expo/modules/vescapecore/telemetry/TelemetryDatabase.kt- Room migration peer.modules/vescape-core/src/index.ts- parity-linked photo, Asset reference, and job-state contracts exposed to JS.Acceptance criteria
idwith one streamedfile.200or creation201response.204and404converge, while409 asset-in-usewaits for detachment.@parity.Blocked by
vescape-app/vescape-server#33.Related
Explicit exclusions
WorkManagerorBGTaskSchedulerbehavior beyond existing lifecycle windows.