migrate stage build to native elc; chat restores from localStorage on return

Build pipeline
- build-stage.sh replaces the old in-Dockerfile bootstrap.py path. Host
  pre-compiles src/*.el into dist/main.c via the canonical native elc at
  foundation/el/dist/platform/elc and applies the stub-decl sed before
  docker buildx runs.
- Dockerfile.stage drops bootstrap.py + python3 from the builder stage
  and just runs cc on the host-supplied dist/main.c.
- Pre-rendered HTML shells under /srv/landing/ are now chowned to the
  landing user so the El page-builder's fs_write at startup can rewrite
  them — without that, post-COPY edits never reach the served HTML and
  the served page stays as the stale build-time fallback.

Chat restore
- session.verified + session.verifiedAt persist through localStorage so
  a return visit within 24h skips the Turnstile gate and lands directly
  in the restored conversation.
- restoreOrGreet() is the single source of truth for what shows up in
  the message pane after the gate clears: replays prior messages with
  skipSave, else drops the canned hello once and remembers it.
- applyVerifiedDom() hides the gate / reveals the chat row, called both
  from the verified-on-load path (DOMContentLoaded if loading, else
  immediate) and from the Turnstile callback.
- neuronDemoReset clears verified + verifiedAt so the gate returns next
  open.

Extracted JS assets (src/assets/js/*.js + manifest.json) and the
extract-js.py helper land here too — they match what the new build-stage
flow produces and removes the inline <script> blobs from the served HTML.
This commit is contained in:
Will Anderson
2026-05-02 11:15:09 -05:00
parent cae5028130
commit 640813e42e
27 changed files with 906 additions and 1461 deletions
+2 -404
View File
@@ -485,410 +485,8 @@ fn checkout_page(plan: String, pub_key: String) -> String {
.checkout-auth-badge strong { color: var(--navy); font-weight: 500; }
</style>
<script>
// ── Supabase auth ─────────────────────────────────────────────────────────────
(function() {
var supabase;
<script src=\"/assets/js/db455e1671dd.js\" defer></script>
function initSupabase(cb) {
if (supabase) { cb(); return; }
fetch('/api/supabase-config')
.then(function(r) { return r.json(); })
.then(function(cfg) {
supabase = window.supabase.createClient(cfg.url, cfg.anon_key, {
auth: { flowType: 'implicit' }
});
cb();
})
.catch(function(err) {
console.error('Supabase init failed', err);
});
}
function showAuthMessage(msg, isError) {
var el = document.getElementById('auth-message');
el.textContent = msg;
el.style.display = 'block';
el.style.color = isError ? '#c0392b' : '#2ecc71';
}
function revealPaymentForm(user) {
// Capture Supabase user id so /api/link-customer can stamp the Stripe
// customer with metadata[supabase_user_id]. Used by /account to find
// the buyer's plan via the canonical cross-reference.
if (user && user.id) { window._neuronSupaId = user.id; }
// Hide optional auth section if it was shown
var auth = document.getElementById('auth-section');
if (auth) auth.style.display = 'none';
var payment = document.getElementById('payment-section');
if (payment) payment.style.display = '';
// Show auth badge if we have a user, hide the inline 'sign in' prompt
if (user) {
var badge = document.getElementById('auth-badge');
var name = user.user_metadata && user.user_metadata.full_name
? user.user_metadata.full_name
: user.email || '';
badge.innerHTML = '<div class=\"checkout-auth-badge\">'
+ '<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M20 6L9 17l-5-5\" stroke=\"#0052A0\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>'
+ 'Signed in as <strong>' + name + '</strong>'
+ '</div>';
badge.style.display = '';
var prompt = document.getElementById('signin-prompt');
if (prompt) prompt.style.display = 'none';
}
// Pre-fill email only (not name - let user enter their own)
if (user && user.email) {
var emailEl = document.getElementById('buyer-email');
if (emailEl) { emailEl.value = user.email; }
}
// Initialize Stripe Elements with this user's email (or empty if guest)
var userEmail = user ? (user.email || '') : '';
var userName = user ? ((user.user_metadata && user.user_metadata.full_name) || '') : '';
if (typeof initStripe === 'function') initStripe(userEmail, userName);
}
// Check if already signed in on load
function checkExistingSession() {
initSupabase(function() {
supabase.auth.getUser().then(function(res) {
if (res.data && res.data.user) {
revealPaymentForm(res.data.user);
}
});
});
}
// Handle OAuth redirect callback
function handleAuthRedirect() {
initSupabase(function() {
supabase.auth.onAuthStateChange(function(event, session) {
if ((event === 'SIGNED_IN' || event === 'INITIAL_SESSION') && session && session.user) {
revealPaymentForm(session.user);
}
});
});
}
// Social sign-in
window.signInWith = function(provider) {
var btns = document.querySelectorAll('.checkout-social-btn');
btns.forEach(function(b) { b.disabled = true; });
initSupabase(function() {
supabase.auth.signInWithOAuth({
provider: provider,
options: {
redirectTo: window.location.href
}
}).then(function(result) {
if (result.error) {
showAuthMessage(result.error.message || 'Sign-in failed. Please try again.', true);
btns.forEach(function(b) { b.disabled = false; });
}
// On success, browser redirects to OAuth provider - no further action needed here.
});
});
};
// Email signup
window.signUpWithEmail = function() {
var email = document.getElementById('auth-email').value.trim();
var password = document.getElementById('auth-password').value;
if (!email || !password) { showAuthMessage('Please enter your email and a password.', true); return; }
if (password.length < 8) { showAuthMessage('Password must be at least 8 characters.', true); return; }
initSupabase(function() {
supabase.auth.signUp({ email: email, password: password }).then(function(result) {
if (result.error) { showAuthMessage(result.error.message, true); return; }
if (result.data && result.data.session) {
revealPaymentForm(result.data.session.user);
} else {
showAuthMessage('Check your email to confirm your account, then come back to complete your purchase.', false);
}
});
});
};
// Email sign-in (existing account)
window.showSignIn = function() {
var form = document.getElementById('email-auth-form');
var btn = form.querySelector('.checkout-email-btn');
var hint = form.querySelector('.checkout-auth-hint');
btn.textContent = 'Sign in →';
btn.onclick = signInWithEmail;
/* hint replaced with DOM manipulation below */
};
window.showSignUp = function() {
var form = document.getElementById('email-auth-form');
var btn = form.querySelector('.checkout-email-btn');
var hint = form.querySelector('.checkout-auth-hint');
btn.textContent = 'Create account →';
btn.onclick = signUpWithEmail;
/* hint replaced with DOM manipulation below */
};
window.signInWithEmail = function() {
var email = document.getElementById('auth-email').value.trim();
var password = document.getElementById('auth-password').value;
if (!email || !password) { showAuthMessage('Please enter your email and password.', true); return; }
initSupabase(function() {
supabase.auth.signInWithPassword({ email: email, password: password }).then(function(result) {
if (result.error) { showAuthMessage(result.error.message, true); return; }
revealPaymentForm(result.data.session.user);
});
});
};
window.resetPassword = function() {
var email = document.getElementById('auth-email').value.trim();
if (!email) { showAuthMessage('Enter your email address above first.', true); return; }
initSupabase(function() {
supabase.auth.resetPasswordForEmail(email, {
redirectTo: window.location.origin + '/checkout?plan=' + (new URLSearchParams(window.location.search).get('plan') || 'professional')
}).then(function(result) {
if (result.error) { showAuthMessage(result.error.message, true); }
else { showAuthMessage('Password reset email sent. Check your inbox.', false); }
});
});
};
// Init
handleAuthRedirect();
checkExistingSession();
})();
</script>
<script>
(function() {
var PLAN = '" + plan + "';
var STRIPE_PK = '" + pub_key + "';
var stripe, elements;
// Wait for Stripe.js to load
function waitForStripe(cb) {
if (window.Stripe) { cb(); return; }
setTimeout(function() { waitForStripe(cb); }, 50);
}
function showMessage(msg) {
var el = document.getElementById('payment-message');
el.textContent = msg;
el.style.display = 'block';
}
function setLoading(loading) {
var btn = document.getElementById('submit-btn');
var label = document.getElementById('submit-label');
var spinner = document.getElementById('submit-spinner');
btn.disabled = loading;
label.style.display = loading ? 'none' : '';
spinner.style.display = loading ? '' : 'none';
}
// Mode flag: 'payment' (charge now) or 'setup' (save card, charge later).
// The submit handler reads this to choose stripe.confirmPayment vs
// stripe.confirmSetup. SOURCE OF TRUTH for whether the buyer is going to
// be charged at submit time. If the radio toggles, we re-fetch a new
// client_secret of the right type and re-mount the Element.
window._neuronMode = 'payment';
var paymentEl = null;
function appearance() {
return {
theme: 'flat',
variables: {
colorPrimary: '#0052A0',
colorBackground: '#ffffff',
colorText: '#1A1A2E',
colorDanger: '#c0392b',
colorTextPlaceholder:'#9B9BAD',
borderRadius: '0px',
fontFamily: 'system-ui, -apple-system, sans-serif',
fontSizeBase: '15px',
fontWeightNormal: '300',
spacingUnit: '4px'
},
rules: {
'.Input': { border: '1px solid rgba(0,82,160,.22)', boxShadow: 'none', padding: '10px 14px' },
'.Input:focus': { border: '1px solid rgba(0,82,160,.6)', boxShadow: '0 0 0 3px rgba(0,82,160,.08)', outline: 'none' },
'.Label': { fontSize: '11px', fontWeight: '500', letterSpacing: '.06em', textTransform: 'uppercase', color: '#6B6B7E', marginBottom: '6px' },
'.Tab': { border: '1px solid rgba(0,82,160,.18)', boxShadow: 'none' },
'.Tab--selected': { border: '1px solid rgba(0,82,160,.5)', boxShadow: '0 0 0 2px rgba(0,82,160,.12)' },
'.Error': { color: '#c0392b' }
}
};
}
function currentTiming() {
var later = document.getElementById('timing-later');
return (later && later.checked) ? 'later' : 'now';
}
function fetchAndMount() {
var submitBtn = document.getElementById('submit-btn');
if (submitBtn) { submitBtn.disabled = true; }
if (paymentEl) {
try { paymentEl.unmount(); } catch(e) {}
paymentEl = null;
}
var loadEl = document.querySelector('.checkout-element-loading');
if (!loadEl) {
var hostEl = document.getElementById('payment-element');
if (hostEl) {
var d = document.createElement('div');
d.className = 'checkout-element-loading';
d.textContent = 'Loading payment form…';
hostEl.appendChild(d);
}
}
var timing = currentTiming();
return fetch('/api/payment-intent', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ plan: PLAN, timing: timing })
})
.then(function(r) { return r.json(); })
.then(function(data) {
if (data.error === 'sold_out') {
showMessage('All 1,000 Founding Member spots have been claimed. Thank you for your interest - please consider the Professional plan.');
if (submitBtn) { submitBtn.disabled = true; submitBtn.textContent = 'Sold out'; }
return;
}
if (!data.client_secret) {
showMessage('Unable to initialise payment. Please try again.');
return;
}
window._neuronMode = data.setup_mode ? 'setup' : 'payment';
window._neuronPiId = data.id || (data.client_secret ? data.client_secret.split('_secret_')[0] : '');
// Update the submit button label so users know what will happen.
var submitLabel = document.getElementById('submit-label');
if (submitLabel) {
submitLabel.textContent = window._neuronMode === 'setup'
? 'Save my card - no charge today →'
: 'Complete purchase →';
}
waitForStripe(function() {
if (!stripe) { stripe = Stripe(STRIPE_PK); }
elements = stripe.elements({ clientSecret: data.client_secret, appearance: appearance() });
paymentEl = elements.create('payment', {
fields: { billingDetails: { name: 'never', email: 'never' } }
});
paymentEl.mount('#payment-element');
paymentEl.on('ready', function() {
var ld = document.querySelector('.checkout-element-loading');
if (ld) ld.remove();
if (submitBtn) submitBtn.disabled = false;
});
});
})
.catch(function() {
showMessage('Unable to connect. Please check your connection and try again.');
});
}
// Initial mount. PLAN==professional shows a timing radio; toggling it
// re-fetches the right Intent so the buyer's choice is honored.
fetchAndMount();
var tNow = document.getElementById('timing-now');
var tLater = document.getElementById('timing-later');
if (tNow) tNow.addEventListener('change', fetchAndMount);
if (tLater) tLater.addEventListener('change', fetchAndMount);
// Submit
document.getElementById('payment-form').addEventListener('submit', async function(e) {
e.preventDefault();
if (!stripe || !elements) return;
// Founding Member attestation gate
var attestCb = document.getElementById('founding-attest-cb');
if (attestCb && !attestCb.checked) {
var warn = document.getElementById('attest-warn');
if (warn) warn.style.display = 'block';
attestCb.closest('label').scrollIntoView({ behavior: 'smooth', block: 'center' });
return;
}
var name = document.getElementById('buyer-name').value.trim();
var email = document.getElementById('buyer-email').value.trim();
if (!name || !email) {
showMessage('Please enter your name and email.');
return;
}
// Save founding member attestation before charging - independent audit record
if (attestCb) {
try {
await fetch('/api/attest', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
plan: PLAN,
name: name,
email: email,
timestamp: new Date().toISOString(),
attestation: 'I am joining as a genuine early user, not to extract proprietary information about Neuron technology, architecture, or roadmap. I will engage in good faith. I understand that if this is not my intent, a different plan is a better fit.',
user_agent: navigator.userAgent
})
});
} catch(e) {
// Non-blocking - attestation log failure does not stop payment
console.warn('attestation log failed', e);
}
}
setLoading(true);
document.getElementById('payment-message').style.display = 'none';
if (window._neuronPiId) {
try {
await fetch('/api/link-customer', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
pi_id: window._neuronPiId,
email: email,
name: name,
plan: PLAN,
timing: currentTiming(),
mode: window._neuronMode || 'payment',
supabase_user_id: window._neuronSupaId || ''
})
});
} catch(e) { /* non-blocking */ }
}
// Setup mode: save card, do not charge. Use stripe.confirmSetup.
// Payment mode: charge now via stripe.confirmPayment.
var confirmParams = {
return_url: window.location.origin + '/account?welcome=1',
payment_method_data: { billing_details: { name: name, email: email } }
};
var result;
if (window._neuronMode === 'setup') {
result = await stripe.confirmSetup({
elements: elements,
confirmParams: confirmParams
});
} else {
confirmParams.receipt_email = email;
result = await stripe.confirmPayment({
elements: elements,
confirmParams: confirmParams
});
}
if (result.error) {
showMessage(result.error.message || (window._neuronMode === 'setup'
? 'Could not save your card. Please try again.'
: 'Payment failed. Please try again.'));
setLoading(false);
}
// On success, Stripe redirects to return_url automatically.
});
})();
</script>
<script>window.NEURON_CFG=window.NEURON_CFG||{};window.NEURON_CFG.plan=\"" + plan + "\";window.NEURON_CFG.pub_key=\"" + pub_key + "\";</script><script src=\"/assets/js/e708dcbb3e7a.js\" defer></script>
"
}