getreadystack's picture
Upload index.html with huggingface_hub
c08442b verified
Raw History Blame Contribute Delete
31.6 kB
<!doctype html><html lang="en"><meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Target API 36 & Xcode 26 Store Deadline Lint</title>
<meta name="description" content="Finds the targetSdk, NDK, Gradle plugin and Xcode versions in your repo that Google Play and App Store Connect already refuse, with the date each one stopped being accepted.">
<style>
:root{color-scheme:light dark}
body{margin:0;font:16px/1.6 system-ui,-apple-system,"Segoe UI",sans-serif;
background:#fbfbfa;color:#16161d}
@media(prefers-color-scheme:dark){body{background:#14141a;color:#e8e8ea}}
.wrap{max-width:880px;margin:0 auto;padding:28px 20px 64px}
h1{font-size:1.7rem;line-height:1.25;margin:.2em 0 .3em}
p.sub{margin:0 0 1.4em;opacity:.8}
textarea{width:100%;min-height:230px;font:13px/1.5 ui-monospace,Menlo,Consolas,monospace;
padding:12px;border:1px solid #c9c9d1;border-radius:10px;background:transparent;color:inherit;
box-sizing:border-box}
button{font:600 15px/1 inherit;padding:12px 22px;border:0;border-radius:10px;
background:#1d4ed8;color:#fff;cursor:pointer;margin:12px 0}
button:hover{background:#1a43bd}
table{border-collapse:collapse;width:100%;margin-top:14px;font-size:14px}
th,td{border-bottom:1px solid #d8d8e0;padding:8px 6px;text-align:left;vertical-align:top}
th{font-weight:600;opacity:.75}
td.n{width:64px;font:13px ui-monospace,monospace;opacity:.7}
.ok{padding:14px;border-radius:10px;background:#e8f5ec;color:#14532d;margin-top:14px}
@media(prefers-color-scheme:dark){.ok{background:#15321f;color:#bbf7d0}}
.next{margin-top:30px;padding:18px;border:1px solid #d8d8e0;border-radius:12px}
.next h2{font-size:1.05rem;margin:0 0 .5em}
.next ul{margin:.3em 0 1em 1.1em;padding:0}
</style>
<div class="wrap">
<h1>Target API 36 & Xcode 26 Store Deadline Lint</h1>
<p class="sub">Finds the targetSdk, NDK, Gradle plugin and Xcode versions in your repo that Google Play and App Store Connect already refuse, with the date each one stopped being accepted.</p>
<textarea id="src" placeholder="Paste your build.gradle, package.json, Podfile or CI workflow">// android/app/build.gradle - shipped last release, untouched since March
android {
namespace "com.acme.fieldapp"
compileSdk 35
buildToolsVersion "35.0.0"
ndkVersion "27.0.12077973"
defaultConfig {
applicationId "com.acme.fieldapp"
minSdkVersion 24
targetSdkVersion 35
versionCode 812
}
}
dependencies {
classpath "com.android.tools.build:gradle:8.4.2"
}
</textarea>
<button id="go">Check this file</button>
<div id="out"></div>
<div class="next"><h2>In the full version</h2><ul><li>Scan every build file in the repository</li><li>Fail the build in CI</li><li>Export a dated release-readiness report</li><li>Re-check on every save</li><li><a href="https://getreadystack.com">Get the full version - $29</a></li></ul></div>
</div>
<script>
var RULES=[{"pattern": "targetSdk(?:Version)?\\s*(?:=|:|\\s)\\s*[\"']?(?:1[4-9]|2[0-9]|3[0-4])\\b", "flags": "", "sev": "error", "message": "targetSdk below 35. Google Play stopped accepting updates without API 36 on 2026-08-31, and at this level your listing is already hidden from new users whose device runs a newer Android than you target. Extension requests close 2026-11-01.", "fix": "targetSdk 36"}, {"pattern": "targetSdk(?:Version)?\\s*(?:=|:|\\s)\\s*[\"']?35\\b", "flags": "", "sev": "error", "message": "targetSdk 35 (Android 15). Google Play has rejected updates without API 36 since 2026-08-31. You can request an extension in Play Console until 2026-11-01; after that no update ships at all.", "fix": "targetSdk 36"}, {"pattern": "compileSdk(?:Version)?\\s*(?:=|:|\\s)\\s*[\"']?(?:2[0-9]|3[0-5])\\b", "flags": "", "sev": "error", "message": "compileSdk below 36. You cannot compile against Android 16, and Gradle refuses a compileSdk lower than targetSdk.", "fix": "compileSdk 36"}, {"pattern": "buildToolsVersion\\s*(?:=|:|\\s)\\s*[\"'](?:2[0-9]|3[0-5])\\.", "flags": "", "sev": "warn", "message": "Build tools below 36.0.0 cannot build API 36 sources.", "fix": "buildToolsVersion \"36.0.0\""}, {"pattern": "flutter\\.(?:target|compile)SdkVersion", "flags": "", "sev": "warn", "message": "This level is inherited from whichever Flutter SDK the build machine has, not from this file, so it can differ between your laptop and CI. Pin it here.", "fix": "targetSdk = 36"}, {"pattern": "ndkVersion\\s*(?:=|:|\\s)\\s*[\"'](?:1[0-9]|2[0-7])\\.", "flags": "", "sev": "error", "message": "NDK below r28 does not align native libraries to 16 KB. Google Play has blocked releases containing native code that target Android 15 or higher since 2025-11-01.", "fix": "NDK r28 or newer"}, {"pattern": "com\\.android\\.tools\\.build:gradle:(?:[0-7]\\.|8\\.[0-4]\\b)", "flags": "", "sev": "error", "message": "Android Gradle Plugin below 8.5.1 does not produce 16 KB-aligned native libraries, which Google Play has required since 2025-11-01.", "fix": "com.android.tools.build:gradle:8.5.1 or newer"}, {"pattern": "windowOptOutEdgeToEdgeEnforcement", "flags": "", "sev": "warn", "message": "Android 16 removes this opt-out. At targetSdk 36 the flag is ignored and the app draws edge-to-edge, so content can sit under the system bars.", "fix": "Handle window insets instead of opting out"}, {"pattern": "\"react-native\"\\s*:\\s*\"[^\"]*0\\.(?:[0-6][0-9]|7[0-9]|80)\\b", "flags": "", "sev": "warn", "message": "React Native below 0.81 defaults to targetSdk 35. Android 16 support landed in 0.81.", "fix": "react-native 0.81 or newer"}, {"pattern": "\"expo\"\\s*:\\s*\"[^\"]*(?:4[0-9]|5[0-3])\\.", "flags": "", "sev": "warn", "message": "Expo SDK below 54 defaults to targetSdk 35. Either upgrade, or set compileSdkVersion and targetSdkVersion to 36 through expo-build-properties.", "fix": "expo 54 or newer"}, {"pattern": "android\\.hardware\\.type\\.(?:watch|television|automotive)", "flags": "", "sev": "info", "message": "Wear OS, Android TV and Automotive run on their own target-level timetable, so the 2026-08-31 API 36 requirement does not apply to this form factor the same way. Confirm this track in Play Console.", "fix": "Check the form-factor track in Play Console"}, {"pattern": "xcode[-_]?version\\s*:\\s*[\"']?(?:1[0-6]|[0-9])\\b", "flags": "i", "sev": "error", "message": "CI is pinned to an Xcode below 26. App Store Connect has rejected uploads not built with the iOS 26 SDK since 2026-04-28 (ITMS-90725).", "fix": "xcode-version: '26.0'"}, {"pattern": "runs-on\\s*:\\s*.*macos-(?:11|12|13|14)\\b", "flags": "i", "sev": "error", "message": "This runner image does not ship Xcode 26, so the archive it produces cannot be uploaded to App Store Connect after 2026-04-28.", "fix": "A runner image that ships Xcode 26"}, {"pattern": "Xcode_?(?:1[0-6]|[0-9])(?:\\.[0-9]+)*\\.app", "flags": "", "sev": "error", "message": "The build points at an Xcode below 26. Uploads built with an older SDK have been rejected since 2026-04-28.", "fix": "/Applications/Xcode_26.app"}, {"pattern": "xc(?:odes|version)\\s*\\(\\s*version\\s*:\\s*[\"'](?:1[0-6]|[0-9])", "flags": "", "sev": "error", "message": "Fastlane selects an Xcode below 26, so the resulting build cannot be uploaded to App Store Connect since 2026-04-28.", "fix": "version: '26.0'"}, {"pattern": "platform\\s*:ios\\s*,\\s*[\"'](?:[89]|1[0-4])(?:\\.[0-9]+)?[\"']", "flags": "", "sev": "warn", "message": "Deployment target below iOS 15. Not a store block by itself, but confirm the project still builds under the iOS 26 SDK that uploads have required since 2026-04-28.", "fix": "Confirm the build under Xcode 26"}];
function scan(t){var L=String(t).split(/\r?\n/),h=[],i,r,re;
for(i=0;i<L.length;i++){for(var k=0;k<RULES.length;k++){r=RULES[k];
try{re=new RegExp(r.pattern,r.flags||'')}catch(e){continue}
if(re.test(L[i]))h.push({line:i+1,msg:r.message})}}
return h}
document.getElementById('go').onclick=function(){
var t=document.getElementById('src').value,o=document.getElementById('out');
if(!t.trim()){o.innerHTML='';return}
var h=scan(t);
if(!h.length){o.innerHTML='<div class="ok">Nothing in this file is blocked by a store requirement.</div>';return}
var s='<table><tr><th>Line</th><th>Finding</th></tr>';
for(var i=0;i<h.length;i++){s+='<tr><td class="n">'+h[i].line+'</td><td>'+
String(h[i].msg).replace(/&/g,'&amp;').replace(/</g,'&lt;')+'</td></tr>'}
o.innerHTML=s+'</table>'};
document.getElementById('go').click();
</script>
</html>
<section data-yj-install="free" style="margin:2rem auto 1rem;max-width:46rem;padding:1.25rem 1.25rem;border:1px solid #cfe3d6;border-radius:12px;background:#f6fbf8;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .4rem;font-size:1.2rem">Install free</h2><p style="margin:0 0 .8rem;color:#41505f">Free for the file open in your editor - no key, no limit. The workspace sweep and the report ask for a key.</p><a href="https://marketplace.visualstudio.com/items?itemName=ReadyStack.target-api-36-store-deadline-lint" rel="noopener" data-yj-install-door="mp" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'target-api-36-store-deadline-lint',src:'mp',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">VS Code Marketplace</a><a href="https://open-vsx.org/extension/readystack/target-api-36-store-deadline-lint" rel="noopener" data-yj-install-door="ovsx" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'target-api-36-store-deadline-lint',src:'ovsx',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Open VSX (Cursor, VSCodium)</a><a href="https://www.npmjs.com/package/@readystack/target-api-36-store-deadline-lint" rel="noopener" data-yj-install-door="npm" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'target-api-36-store-deadline-lint',src:'npm',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">npm</a><a href="https://hub.docker.com/r/getreadystack/target-api-36-store-deadline-lint" rel="noopener" data-yj-install-door="docker" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'target-api-36-store-deadline-lint',src:'docker',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Docker Hub</a><pre style="margin:.5rem 0 0;padding:.6rem .8rem;background:#f3f5f8;border-radius:8px;font-size:.9rem;overflow:auto">ext install ReadyStack.target-api-36-store-deadline-lint
npx @readystack/target-api-36-store-deadline-lint &lt;file&gt;
docker run --rm -v &quot;$PWD:/w&quot; getreadystack/target-api-36-store-deadline-lint /w</pre><p style="margin:.6rem 0 0;font-size:.92rem;color:#41505f"><a href="https://getreadystack.com/api/buy/cl/polar_cl_l6iN1uWt0FwWu7tBsczD0jWpP2vxFM54Wdwqb3KPi1G" rel="nofollow" style="color:#0f7b3f;text-decoration:underline">Team? One key for every ReadyStack linter, 5 seats, $149 once</a></p></section>
<section data-yj-alert="rule" style="margin:1rem auto 1.5rem;max-width:46rem;padding:1.1rem 1.25rem;border:1px solid #d9dee6;border-radius:12px;background:#fbfcfd;font:15px/1.55 system-ui,-apple-system,Segoe UI,sans-serif"><b style="font-size:1.05rem">Get one email when this rule changes</b><div style="opacity:.78;margin:.35rem 0 .8rem">We watch the regulation and vendor sources behind Target API 36 &amp; Xcode 26 Store Deadline Lint every day. When a rule changes, you get a single email with what changed and the updated check. No newsletter.</div><div style="display:flex;gap:8px;flex-wrap:wrap"><input id="yjae" type="email" placeholder="you@example.com" style="flex:1;min-width:210px;padding:11px 13px;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:#fff;color:inherit"><button id="yjab" style="padding:11px 18px;border-radius:8px;border:0;cursor:pointer;background:#0f7b3f;color:#fff;font:600 15px system-ui,sans-serif">Notify me</button></div><div id="yjao" hidden style="margin-top:.6rem;color:#0f7b3f">You're on the list. One email when it changes.</div><script>(function(){var b=document.getElementById("yjab"),e=document.getElementById("yjae");if(!b||!e)return;b.addEventListener("click",function(){var v=e.value.trim();if(!/.+@.+\..+/.test(v))return;try{localStorage.setItem("yj_em","1");}catch(_){}fetch(location.origin+"/api/subscribe",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:v,slug:"target-api-36-store-deadline-lint",lang:"en",source:"rule_alert"+((b.closest&&b.closest("section")&&b.closest("section").getAttribute("data-yj-moved"))?"_at_result":"")})}).then(function(r){var o=document.getElementById("yjao");o.hidden=false;if(!r.ok){o.textContent="Could not save - please try again.";}}).catch(function(){var o=document.getElementById("yjao");o.hidden=false;o.textContent="Could not save - please try again.";});});})();</script><script>(function(){var e=document.getElementById("yjae"),s=e&&e.closest?e.closest("section"):null,o=document.getElementById("out");if(!s||!o)return;var d=false;function mv(ev){if(d)return;if(ev&&ev.target&&s.contains(ev.target))return;d=true;var b=o;while(b.parentNode&&b.parentNode!==document.body&&b.parentNode.tagName!=="MAIN"&&b.parentNode.tagName!=="ARTICLE")b=b.parentNode;if(!b.parentNode||b===s||b.contains(s))return;try{b.parentNode.insertBefore(s,b.nextSibling);s.setAttribute("data-yj-moved","1");}catch(_){}}document.addEventListener("input",mv,true);document.addEventListener("change",mv,true);})();</script></section>
<section data-yj-cta="paid" style="margin:3rem auto;max-width:46rem;padding:1.5rem 1.25rem;border:1px solid #d8dee9;border-radius:12px;background:#fbfcfe;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .5rem;font-size:1.25rem">Get the complete version <span class="yj-price">$29</span></h2><p style="margin:.25rem 0 1rem;color:#41505f">This page is the working piece. The full pack has everything below.</p><p style="margin:0 0 1rem;color:#41505f">Finds the targetSdk, NDK, Gradle plugin and Xcode versions in your repo that Google Play and App Store Connect already refuse, with the date each one stopped being accepted.</p><p style="margin:0 0 1rem;color:#5b6b7c;font-size:.94rem">Google Play's extension window for the API 36 requirement closes 2026-11-01; freelance market rates put a senior Android developer near $128 an hour.</p><a href="https://getreadystack.com/api/buy/cl/polar_cl_vq5XThHMGTzYpT8dmUA38JFX8y3rRSnEzoY8U3wn2Hx" rel="nofollow" style="display:inline-block;padding:.7rem 1.3rem;border-radius:8px;background:#1b64f2;color:#fff;text-decoration:none;font-weight:600">Buy the full version — $29</a></section>
<section data-yj="yj-facts-v1" style="max-width:920px;margin:48px auto 0;padding:0 20px;font-family:system-ui,sans-serif"><style>.yj-article p{font:400 15.5px/1.7 system-ui,sans-serif;color:#26313b;margin:0 0 12px;max-width:72ch}.yj-article h2,.yj-article h3,.yj-article h4{font:600 17px/1.35 system-ui,sans-serif;color:#1b1f24;margin:22px 0 8px}.yj-article table{border-collapse:collapse;margin:10px 0 16px;font:14px/1.45 system-ui,sans-serif}.yj-article th,.yj-article td{border:1px solid #e2e6ea;padding:6px 10px;text-align:left}.yj-article th{background:#f4f6f8}.yj-article pre{background:#0f1720;color:#e6edf3;padding:12px 14px;border-radius:8px;overflow:auto;font:13px/1.5 ui-monospace,Menlo,monospace}.yj-article code{font:13px ui-monospace,Menlo,monospace;background:#f1f3f5;padding:1px 4px;border-radius:3px}.yj-article pre code{background:none;padding:0}.yj-article ul,.yj-article ol{font:15px/1.6 system-ui,sans-serif;color:#26313b}</style><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:34px 0 6px;color:#1b1f24">Questions people ask</h2><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What does Target API 36 &amp; Xcode 26 Store Deadline Lint actually do?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">It reads the build file you have open and flags every version Google Play or App Store Connect already refuses. Each finding gives the line number, the date the store stopped accepting it, and the version to move to. Sixteen rules cover targetSdk, compileSdk, build tools, NDK, the Android Gradle Plugin, React Native, Expo and the Xcode your CI selects.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Who is this for?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">React Native, Expo, Flutter and Capacitor teams who ship to Google Play and the App Store from VS Code. It is aimed at whoever owns the release train on the day Play Console rejects a bundle - usually the mobile lead or the engineer who maintains the CI workflow rather than a dedicated release manager.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Why can I not just ask a chatbot which target API level Google Play requires?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Because the answer changes every August and the model answers with the number it was trained on. Ask today and you will often get 34 or 35, the level Play rejected on 31 August 2026. Play Console does tell you the truth, but only after you build and upload a bundle, which is the most expensive place to find out.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What is free and what needs a licence key?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Checking the file you have open is free and complete: all sixteen rules run, every finding shows its date and its fix, and nothing is hidden, watermarked or time-limited. The licence covers a different job - scanning every build file in the repository, re-checking on save, failing a CI build, and exporting a dated report.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What does this cost compared with the alternative?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">The extension is 29 US dollars once. The alternative is a release blocked at upload, which costs the release window plus the upgrade you had to do anyway, done under pressure. Freelance market rates put a senior Android developer near 128 dollars an hour.</p></details><script type="application/ld+json" data-yj="yj-faq-ld">{"@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [{"@type": "Question", "name": "What does Target API 36 & Xcode 26 Store Deadline Lint actually do?", "acceptedAnswer": {"@type": "Answer", "text": "It reads the build file you have open and flags every version Google Play or App Store Connect already refuses. Each finding gives the line number, the date the store stopped accepting it, and the version to move to. Sixteen rules cover targetSdk, compileSdk, build tools, NDK, the Android Gradle Plugin, React Native, Expo and the Xcode your CI selects."}}, {"@type": "Question", "name": "Who is this for?", "acceptedAnswer": {"@type": "Answer", "text": "React Native, Expo, Flutter and Capacitor teams who ship to Google Play and the App Store from VS Code. It is aimed at whoever owns the release train on the day Play Console rejects a bundle - usually the mobile lead or the engineer who maintains the CI workflow rather than a dedicated release manager."}}, {"@type": "Question", "name": "Why can I not just ask a chatbot which target API level Google Play requires?", "acceptedAnswer": {"@type": "Answer", "text": "Because the answer changes every August and the model answers with the number it was trained on. Ask today and you will often get 34 or 35, the level Play rejected on 31 August 2026. Play Console does tell you the truth, but only after you build and upload a bundle, which is the most expensive place to find out."}}, {"@type": "Question", "name": "What is free and what needs a licence key?", "acceptedAnswer": {"@type": "Answer", "text": "Checking the file you have open is free and complete: all sixteen rules run, every finding shows its date and its fix, and nothing is hidden, watermarked or time-limited. The licence covers a different job - scanning every build file in the repository, re-checking on save, failing a CI build, and exporting a dated report."}}, {"@type": "Question", "name": "What does this cost compared with the alternative?", "acceptedAnswer": {"@type": "Answer", "text": "The extension is 29 US dollars once. The alternative is a release blocked at upload, which costs the release window plus the upgrade you had to do anyway, done under pressure. Freelance market rates put a senior Android developer near 128 dollars an hour."}}]}</script><div id="yj-ask" style="margin:36px 0 0;padding:18px 18px 16px;border:1px solid #e2e6ea;border-radius:10px;background:#fbfbfc"><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:0 0 4px;color:#1b1f24">Ask about this tool</h2><p style="font:400 13.5px/1.5 system-ui,sans-serif;margin:0 0 12px;color:#5b6570">One question, answered by the person who built it. Your email only if you want the answer sent.</p><form onsubmit="return yjAsk(event)" style="display:grid;gap:8px"><textarea name="question" required minlength="10" maxlength="2000" rows="3" placeholder="Your question" style="font:14px/1.5 system-ui,sans-serif;padding:10px;border:1px solid #cfd6dd;border-radius:6px"></textarea><div style="display:flex;gap:8px;flex-wrap:wrap"><input type="email" name="email" placeholder="Email (optional)" style="flex:1;min-width:200px;font:14px system-ui,sans-serif;padding:9px 10px;border:1px solid #cfd6dd;border-radius:6px"><button type="submit" style="font:600 14px system-ui,sans-serif;padding:9px 18px;border:0;border-radius:6px;background:#1b1f24;color:#fff;cursor:pointer">Send</button></div><p id="yj-ask-msg" style="font:13px system-ui,sans-serif;margin:2px 0 0;color:#0a6238;min-height:1em"></p></form><script>function yjAsk(e){e.preventDefault();var f=e.target,m=document.getElementById("yj-ask-msg");m.style.color="#0a6238";fetch(location.origin+"/api/ask",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sku:0,slug:"target-api-36-store-deadline-lint",lang:"en",question:f.question.value,email:f.email.value,page:location.pathname})}).then(function(r){if(!r.ok)throw 0;m.textContent="Thanks \u2014 noted. Answers land on this page and, if you left an email, in your inbox.";f.question.value="";}).catch(function(){m.style.color="#a8551f";m.textContent="Could not send. Please try again in a minute.";});return false;}</script></div></section><section class="yj-related" style="max-width:920px;margin:56px auto 40px;padding:0 20px"><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Same job, next tool</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 20px;color:#5b6570">Free in the browser. The full version is a one-time licence.</p><div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:14px"><a class="yj-rel-c" href="https://getreadystack.com/tools/content-calendar-template"><span class="yj-rel-t">Content Calendar Template with Capacity &amp; Cost Calculator for Small Content Te</span><span class="yj-rel-p">$90</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/ada-title-ii-deadline-lint"><span class="yj-rel-t">ADA Title II Deadline Lint (WCAG 2.1 AA)</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/autohotkey-toml-devicetree-snippets"><span class="yj-rel-t">AutoHotkey v2, TOML and DeviceTree checks for VS Code</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/consent-mode-v2-lint"><span class="yj-rel-t">Consent Mode v2 Lint for GA4 &amp; Google Ads</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/cloud-manifest-audit-kit"><span class="yj-rel-t">Manifest Snippets + Removed-API Audit (8 Sets)</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/sfdx-retirement-lint"><span class="yj-rel-t">Salesforce API Version &amp; CLI Retirement Lint</span><span class="yj-rel-p">$29</span></a></div><style>.yj-rel-c{display:flex;flex-direction:column;gap:8px;padding:15px 16px;border:1px solid #e2e6ea;border-radius:6px;text-decoration:none;background:#fff}.yj-rel-c:hover{border-color:#b9c2cb;background:#fafbfc}.yj-rel-t{font:500 14.5px/1.42 system-ui,sans-serif;color:#1b1f24}.yj-rel-p{font:600 13px system-ui,sans-serif;color:#0a6238}</style></section><!--yj-share-s101--><div style="margin:28px 0 8px;text-align:center"><button id="yjcp" type="button" style="font:inherit;padding:10px 18px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Copy link</button><button id="yjimg" type="button" style="font:inherit;padding:10px 18px;margin-left:8px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Save result as image</button></div><script>(function(){var b=document.getElementById("yjimg");if(!b)return;b.addEventListener("click",function(){var o=document.getElementById("out");var txt=(o&&(o.innerText||o.textContent)||"").trim();if(!txt){b.textContent="(no result yet)";setTimeout(function(){b.textContent="Save result as image";},1500);return;}var lines=txt.split(String.fromCharCode(10)).filter(function(x){return x.trim();}).slice(0,10);var W=1200,P=56,c=document.createElement("canvas");c.width=W;var lh=38,H=P*2+70+lines.length*lh+60;c.height=H;var x=c.getContext("2d");x.fillStyle="#1a1512";x.fillRect(0,0,W,H);x.fillStyle="#f3e9d2";x.font="600 34px system-ui,Segoe UI,Arial";var t=(document.title||"").split("|")[0].trim();x.fillText(t.slice(0,54),P,P+34);x.font="22px ui-monospace,Menlo,Consolas,monospace";x.fillStyle="#e8dcc4";for(var i=0;i<lines.length;i++){x.fillText(lines[i].slice(0,88),P,P+70+i*lh+22);}x.font="600 22px system-ui,Segoe UI,Arial";x.fillStyle="#c9a227";var d=location.hostname.replace("www.","");x.fillText(d,W-P-x.measureText(d).width,H-P+6);c.toBlob(function(bl){var u=URL.createObjectURL(bl),a=document.createElement("a");a.href=u;a.download=(t||"result").replace(/[^a-z0-9]+/gi,"-").toLowerCase()+"-"+d+".png";document.body.appendChild(a);a.click();setTimeout(function(){URL.revokeObjectURL(u);a.remove();},2000);},"image/png");});})();</script><script>(function(){var b=document.getElementById("yjcp");if(!b)return;var t=b.textContent;b.addEventListener("click",function(){var u=location.href.split("#")[0];function d(){b.textContent="Link copied";setTimeout(function(){b.textContent=t;},1800);}if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(u).then(d,function(){prompt("",u);});}else{prompt("",u);}});})();</script><div class="yj-home-find"><div class="yj-lgbar"><a href="/" class="yj-lg on">EN</a><a href="/de/" class="yj-lg">DE</a><a href="/ja/" class="yj-lg">JA</a><a href="/es/" class="yj-lg">ES</a><a href="/pt/" class="yj-lg">PT</a></div><section class="yj-find"><h2>Find a tool</h2><input id="yjq" type="search" autocomplete="off" placeholder="Type a product name, format or task"><div id="yjr"></div></section><style>.yj-lgbar{position:absolute;top:14px;right:18px;display:flex;gap:6px;z-index:60}.yj-lg{font:600 12px/1 system-ui,sans-serif;padding:6px 9px;border-radius:4px;text-decoration:none;color:#8b96a3;border:1px solid rgba(140,150,165,.28)}.yj-lg:hover{color:#e8eaed;border-color:rgba(160,175,195,.6)}.yj-lg.on{color:#0e1116;background:#cfd6de;border-color:#cfd6de}.yj-find{max-width:760px;margin:34px auto 8px;padding:0 20px}.yj-find h2{font:600 20px/1.3 system-ui,sans-serif;margin:0 0 10px}#yjq{width:100%;box-sizing:border-box;padding:13px 15px;font:400 15.5px system-ui,sans-serif;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:rgba(255,255,255,.04);color:inherit}#yjq:focus{outline:none;border-color:#7FD1C4}#yjr{margin-top:10px;display:flex;flex-direction:column;gap:6px}#yjr a{display:flex;justify-content:space-between;gap:12px;padding:11px 14px;border:1px solid rgba(140,150,165,.22);border-radius:6px;text-decoration:none;font:400 14.5px/1.4 system-ui,sans-serif;color:inherit}#yjr a:hover{border-color:#7FD1C4}#yjr .pr{font:600 13px system-ui,sans-serif;color:#5fbf9a;white-space:nowrap}</style><script>(function(){var q=document.getElementById("yjq"),r=document.getElementById("yjr"),D=null;function load(){if(D)return Promise.resolve(D);return fetch("/search-index.json").then(function(x){return x.json();}).then(function(j){D=j;return j;}).catch(function(){D=[];return D;});}function esc(t){return String(t).replace(/[&<>"]/g,function(c){return {"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"}[c];});}function run(){var v=q.value.trim().toLowerCase();if(v.length<2){r.innerHTML="";return;}load().then(function(j){var w=v.split(/\s+/),o=[];for(var i=0;i<j.length&&o.length<12;i++){var t=j[i].t.toLowerCase();var ok=true;for(var k=0;k<w.length;k++){if(t.indexOf(w[k])<0){ok=false;break;}}if(ok)o.push(j[i]);}r.innerHTML=o.length?o.map(function(x){return "<a href=\""+esc(x.u)+"\">"+"<span>"+esc(x.t)+"</span>"+(x.p?"<span class=\"pr\">$"+x.p+"</span>":"")+"</a>";}).join(""):"";});}q.addEventListener("input",run);q.addEventListener("focus",load);})();</script></div>
<script data-yj="yj-view-beacon">(function(){try{var p=location.pathname;var k='yjv:'+p;if(sessionStorage.getItem(k))return;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",ref:(document.referrer||''),src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}catch(e){}})();</script>
<script data-yj="yj-use-beacon">(function(){try{var o=document.getElementById('out');if(!o)return;var p=location.pathname,k='yju:'+p,sent=false;function fire(){if(sent||sessionStorage.getItem(k))return;if(!(o.textContent||'').replace(/\s+/g,'').length)return;sent=true;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",t:'use',src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}var mo=new MutationObserver(function(){fire();if(sent)mo.disconnect();});mo.observe(o,{childList:true,characterData:true,subtree:true});}catch(e){}})();</script>