Example
// @requirements REQ-PRODUCT-PAID-ORDER-ARCHIVES // @requirements REQ-PRODUCT-DEMO-WORKSPACE REQ-PRODUCT-MOBILE import {test} from 'node:test'; import {readFile} from 'node:fs/promises'; import assert from 'node:assert/strict'; import {serveHost} from '../host.mjs'; import {DemoWorkspace} from '../worker.mjs'; import {createSyntheticStorage} from '../../packages/notabenda-cf/examples/synthetic.mjs'; import data from '../dist/server-data.json' with {type:'json'}; const req=(path,init={})=>new Request('https://demo.example.test'+path,init); const digest=async value=>Buffer.from(await crypto.subtle.digest('SHA-256',new TextEncoder().encode(value))).toString('hex'); function environment(){ const objects=new Map();let allocations=0; const env={ADMIN_KEY:'a'.repeat(64),ASSETS:{fetch:async request=>new URL(request.url).pathname.startsWith('/assets/guarantees/')?new Response(await readFile(new URL('../dist/public'+new URL(request.url).pathname,import.meta.url)),{headers:{'Content-Type':'image/svg+xml'}}):new Response('
Fictional example',{headers:{'Content-Type':'text/html'}})},DEMO_PROVISION_LIMITER:{limit:async()=>({success:true})},WORKSPACE:{idFromName(){throw new Error('Operational workspace must never be selected');}}}; env.DEMO_WORKSPACES={idFromName:name=>name,get(name){allocations++;if(!objects.has(name)){ const storage=createSyntheticStorage([]);storage.setAlarm=async at=>{storage.deadline=at;};storage.deleteAll=async()=>{for(const key of (await storage.list({prefix:'',limit:10000})).keys())await storage.delete(key);}; objects.set(name,{storage,workspace:new DemoWorkspace({storage,blockConcurrencyWhile:fn=>fn()},env)}); }return {fetch:request=>objects.get(name).workspace.fetch(request)};}}; return {env,objects,allocations:()=>allocations}; } async function session(env){const response=await serveHost(req('/demo/admin'),env);assert.equal(response.status,200,await response.clone().text());const cookie=response.headers.get('Set-Cookie').split(';')[0],value=cookie.split('=')[1];return {cookie,generation:await digest(value.split('.')[0]),response};} const headers=s=>({Cookie:s.cookie,'X-Notabenda-Demo-Generation':s.generation}); // @requirements REQ-EU-ORDER-ACTION REQ-EU-GUARANTEE-LABEL REQ-PRODUCT-A11Y test('order examples issue session-bound quotes and retain one exact request with readable isolated history',async()=>{ const {env,objects}=environment(),a=await session(env),b=await session(env); for(const route of ['mixed','deferred','conditional']){ const page=await serveHost(req('/orders/'+route+'/',{headers:headers(a)}),env);assert.equal(page.status,200);const html=await page.text();assert.match(html,/notabenda-demo-generation/);assert.match(html,/class="demo-corner"/);assert.match(page.headers.get('Content-Security-Policy'),/script-src 'self'/); const get=s=>serveHost(req('/demo/orders/'+route+'/quote',{headers:headers(s)}),env),review=await(await get(a)).json(),other=await(await get(b)).json();assert.notEqual(review.quote.contextRef,other.quote.contextRef);assert.equal(review.definition.definitionId,data.paidOrders[route].definition.definitionId);assert.deepEqual(await(await get(a)).json(),review); const request={schemaVersion:1,requestId:crypto.randomUUID(),reviewId:review.reviewId,definitionId:review.definition.definitionId,quoteId:review.quote.quoteId,quoteRevision:review.quote.revision,contextRef:review.quote.contextRef}; const post=(s,body)=>serveHost(req('/demo/orders/'+route+'/submit',{method:'POST',headers:{...headers(s),Origin:'https://demo.example.test','Content-Type':'application/json','X-Notabenda-Demo':'1'},body:JSON.stringify(body)}),env),responses=await Promise.all([post(a,request),post(a,request)]);assert.deepEqual(responses.map(r=>r.status),[200,200]);const outcome=await responses[0].json();assert.deepEqual(await responses[1].json(),outcome);assert.equal(outcome.status,'received');assert.equal((await post(b,request)).status,409);assert.equal((await post(a,{...request,quoteRevision:'other'})).status,409); const detail=await serveHost(req('/demo/admin/orders/record?id='+outcome.id,{headers:headers(a)}),env),content=await detail.text();assert.equal(detail.status,200);for(const label of ['Information presented','Payment','Not reported','Not prepared',request.requestId,request.reviewId])assert.ok(content.includes(label),label);assert.match(content,/class="demo-corner"/);assert.match(content,/Inspect retained review/);const archive=await serveHost(req('/demo/admin/orders/order-review?id='+outcome.id,{headers:headers(a)}),env);assert.equal(archive.status,200);assert.match(await archive.text(),/Retained review/);assert.equal((await serveHost(req('/demo/admin/orders/record?id='+outcome.id,{headers:headers(b)}),env)).status,404); const search=await serveHost(req('/demo/admin/orders?q='+request.requestId,{headers:headers(a)}),env);assert.equal(search.status,200);assert.match(await search.text(),/1 record on this page/); const image=review.definition.items.find(i=>i.guarantee?.status==='label-provided')?.guarantee.label.asset;if(image){const view=await serveHost(req('/demo/admin/orders/order-review?id='+outcome.id,{headers:headers(a)}),env);assert.match(await view.text(),/Guarantee artwork © European Union.*Source and use conditions/u);const path='/demo/admin/orders/order-image?id='+outcome.id+'&sha256='+image.sha256,response=await serveHost(req(path,{headers:headers(a)}),env);assert.equal(response.status,200);assert.match(response.headers.get('Content-Security-Policy'),/^sandbox;/);assert.equal((await response.arrayBuffer()).byteLength,image.bytes);assert.equal((await serveHost(req(path,{headers:headers(b)}),env)).status,404);} } const stores=[...objects.values()].map(o=>o.storage);for(const storage of stores){const records=await storage.list({prefix:'notabenda/orders/juniper-order-example/events/',limit:200});assert.equal(records.size,storage===stores[0]?6:3);} const denied=await serveHost(req('/demo/orders/mixed/quote'),env);assert.equal(denied.status,409); }); // @requirements REQ-EU-ORDER-ACTION test('a retained order outcome remains recoverable at the demo limit if outer command accounting was interrupted',async()=>{ const {env,objects}=environment(),s=await session(env),review=await(await serveHost(req('/demo/orders/conditional/quote',{headers:headers(s)}),env)).json(),body={schemaVersion:1,requestId:crypto.randomUUID(),reviewId:review.reviewId,definitionId:review.definition.definitionId,quoteId:review.quote.quoteId,quoteRevision:review.quote.revision,contextRef:review.quote.contextRef},path='/demo/orders/conditional/submit',post=()=>serveHost(req(path,{method:'POST',headers:{...headers(s),Origin:'https://demo.example.test','Content-Type':'application/json','X-Notabenda-Demo':'1'},body:JSON.stringify(body)}),env),receipt=await(await post()).json(),storage=[...objects.values()][0].storage; await storage.delete('demo/commands/'+path+'/'+body.requestId);await storage.put('demo/command-count',200);assert.deepEqual(await(await post()).json(),receipt);body.requestId=crypto.randomUUID();assert.equal((await post()).status,429); }); test('demo navigation keeps its overview and public exits within the bounded sidebar',async()=>{const {adminPresentation}=await import('../admin-presentation.mjs'),links=adminPresentation('/demo/admin').navigation;assert.ok(links.length<=12);for(const path of ['/demo/admin','/demo/admin/orders','/examples','/website-privacy'])assert.ok(links.some(link=>link.href===path),path);}); test('visitors receive independent seeded DO databases while operational admin stays protected',async()=>{ const {env,objects}=environment(),a=await session(env),b=await session(env);assert.notEqual(a.cookie,b.cookie);assert.equal(objects.size,2); assert.match(a.response.headers.get('Set-Cookie'),/^__Host-notabenda_demo=[a-f0-9]{64}\.[a-f0-9]{64}; Path=\/; HttpOnly; SameSite=Lax; Secure$/);assert.equal(a.response.headers.get('Vary'),'Cookie');assert.equal(a.response.headers.get('Cache-Control'),'private, no-store, no-transform'); for(const {storage} of objects.values()){ assert.equal((await storage.list({prefix:`notabenda/consent/${data.consent.notice.siteId}/events/`,limit:100})).size,27); assert.equal((await storage.list({prefix:'notabenda/terms/juniper-agreement/events/',limit:100})).size,10); assert.equal((await storage.list({prefix:`notabenda/processing/${data.processing.notice.siteId}/events/`,limit:100})).size,8); } const head=async s=>(await(await serveHost(req('/demo/choices/head',{headers:headers(s)}),env)).json()); const first=await head(a),other=await head(b);assert.notEqual(first.streamRef,other.streamRef); const body={schemaVersion:1,noticeId:data.recordedConsent.notice.noticeId,requestId:crypto.randomUUID(),expectedRevision:0,action:'revoke-all',choices:Object.fromEntries(Object.keys(data.recordedConsent.notice.scopes).map(id=>[id,false])),clientAt:new Date().toISOString()}; const post=s=>serveHost(req('/demo/choices/record',{method:'POST',headers:{...headers(s),Origin:'https://demo.example.test','Content-Type':'application/json','X-Notabenda-Demo':'1'},body:JSON.stringify(body)}),env); const saved=await post(a);assert.equal(saved.status,200);const result=await saved.json();assert.equal((await head(b)).revision,0);assert.equal((await head(a)).revision,1); const record=await serveHost(req('/demo/admin/recorded/record?id='+result.receipt.id,{headers:headers(a)}),env);assert.equal(record.status,200);const html=await record.text();assert.match(html,/Your demo workspace/);assert.doesNotMatch(html,/href="\/backoffice/); const unavailable=await serveHost(req('/demo/admin/recorded/record?id='+result.receipt.id,{headers:headers(b)}),env);assert.equal(unavailable.status,404); assert.equal((await serveHost(req('/backoffice',{headers:{Cookie:a.cookie}}),env)).status,401); // A replaced browser cookie cannot carry an older tab's command into the new workspace. const crossed={...a,cookie:b.cookie};assert.equal((await post(crossed)).status,409);assert.equal((await head(b)).revision,0); const object=[...objects.values()][0];await object.storage.put('demo/command-count',200);assert.equal((await post(a)).status,200);body.requestId=crypto.randomUUID();body.expectedRevision=1;assert.equal((await post(a)).status,429); }); test('only provisioning initializes; expiry and alarm cleanup cannot resurrect an old capability',async()=>{ const {env,objects}=environment(),s=await session(env),entry=[...objects.values()][0],before=await entry.storage.get('demo/session'); const idle={...before,lastUsedAt:before.lastUsedAt-7200000,expiresAt:before.expiresAt-7200000};await entry.storage.put('demo/session',idle); await serveHost(req('/demo/admin/history',{headers:headers(s)}),env);const after=await entry.storage.get('demo/session');assert.ok(after.expiresAt>idle.expiresAt);assert.equal(after.createdAt,before.createdAt);assert.ok(after.lastUsedAt>=before.lastUsedAt);assert.equal(after.expiresAt-after.lastUsedAt,86400000); await entry.workspace.alarm();assert.ok(await entry.storage.get('demo/seed-v1')); // An earlier queued alarm must not destroy an active demo. await entry.storage.put('demo/session',{...before,expiresAt:Date.now()-1});const expired=await serveHost(req('/demo/admin/history',{headers:headers(s)}),env);assert.equal(expired.status,410);assert.match(await expired.clone().text(),/Your demo session ended/);assert.match(expired.headers.get('Set-Cookie'),/Max-Age=0/);assert.equal((await entry.storage.list({prefix:'notabenda/',limit:100})).size,0); await entry.workspace.alarm();assert.equal((await serveHost(req('/demo/admin/history',{headers:headers(s)}),env)).status,410);assert.equal(await entry.storage.get('demo/seed-v1'),undefined); const forged={cookie:'__Host-notabenda_demo='+'f'.repeat(64),generation:await digest('f'.repeat(64))};assert.equal((await serveHost(req('/demo/admin',{headers:headers(forged)}),env)).status,410);assert.equal(objects.size,1); }); test('public demo validates origin, capability, generation and provisioning budget before allocating storage',async()=>{ const {env,allocations}=environment();env.DEMO_PROVISION_LIMITER.limit=async()=>({success:false});assert.equal((await serveHost(req('/demo/admin'),env)).status,429);assert.equal(allocations(),0); const body='{}';assert.equal((await serveHost(req('/demo/choices/record',{method:'POST',headers:{Origin:'https://attacker.test','Content-Type':'application/json','X-Notabenda-Demo':'1'},body}),env)).status,400);assert.equal(allocations(),0); assert.equal((await serveHost(req('/demo/provision',{method:'POST'}),env)).status,405);assert.equal((await serveHost(req('/demo/choices/head'),env)).status,409);assert.equal(allocations(),0); }); test('demo example pages bind their generation without exposing the capability or operational admin',async()=>{ const {env}=environment(),s=await session(env); for(const path of ['/agreement/index.html','/%61greement/index.html','/dark/agreement/index.html','/recorded-choices/','/processing-choices/']){ const response=await serveHost(req(path,{headers:headers(s)}),env);assert.equal(response.status,200);assert.equal(response.headers.get('Cache-Control'),'private, no-store, no-transform');assert.equal(response.headers.get('Vary'),'Cookie');assert.match(response.headers.get('Content-Security-Policy'),/frame-ancestors 'none'/);const html=await response.text();assert.match(html,new RegExp('content="'+s.generation+'"'));assert.ok(!html.includes(s.cookie.split('=')[1])); } env.ASSETS.fetch=async()=>new Response(null,{status:308,headers:{Location:'/agreement/'}});const redirect=await serveHost(req('/agreement',{headers:headers(s)}),env);assert.equal(redirect.status,308);assert.equal(redirect.headers.get('Cache-Control'),'private, no-store, no-transform'); }); test('forged capability signatures cannot allocate objects and interrupted seeding resumes without duplication',async()=>{ const {env,objects,allocations}=environment();let calls=0;env.DEMO_PROVISION_LIMITER.limit=async()=>{calls++;return {success:true};}; for(let n=0;n<8;n++){const cookie='__Host-notabenda_demo='+String(n).repeat(64)+'.'+'f'.repeat(64);assert.equal((await serveHost(req('/demo/admin',{headers:{Cookie:cookie}}),env)).status,410);} assert.equal(allocations(),0);assert.equal(calls,0); const s=await session(env),entry=[...objects.values()][0];await entry.storage.delete('demo/seed-v1'); const before=await entry.storage.list({prefix:'notabenda/',limit:10000});entry.workspace=new DemoWorkspace({storage:entry.storage,blockConcurrencyWhile:fn=>fn()},env); assert.equal((await serveHost(req('/demo/admin/history',{headers:headers(s)}),env)).status,200);assert.deepEqual(await entry.storage.list({prefix:'notabenda/',limit:10000}),before); }); test('the demo session recovery message is terminal-specific, text-only and does not duplicate itself',async()=>{ const {JSDOM}=await import('jsdom');const {readFile}=await import('node:fs/promises'); const dom=new JSDOM('Example