Add marketplace checkout harness controls to launcher

This commit is contained in:
Joshua 2026-02-18 13:14:09 -08:00
parent 9b989bd735
commit b1fb4706a8
4 changed files with 119 additions and 7 deletions

View File

@ -37,9 +37,10 @@ Advanced integration controls (collapsible):
1. API/chain connection settings
2. Wallet intent + verify primitives
3. Membership quote + confirm primitives
4. Member channel register/poll primitives
5. Governance install + lease primitives
6. Raw response log for deterministic troubleshooting
4. Marketplace offer list + checkout quote/confirm primitives
5. Member channel register/poll primitives
6. Governance install + lease primitives
7. Raw response log for deterministic troubleshooting
Wallet automation helpers remain available in advanced controls:

View File

@ -6,6 +6,7 @@ const state = {
eventMap: new Map(),
lastIntent: null,
lastQuote: null,
lastCheckoutQuote: null,
channelReady: false,
};
@ -584,6 +585,68 @@ async function onInstallStatus() {
return out;
}
async function onListOffers() {
const out = await request("GET", "/marketplace/offers");
logLine("marketplace offers", out);
return out;
}
async function onCheckoutQuote() {
const payload = {
wallet: requireWallet(),
offer_id: $("checkoutOfferId").value.trim(),
org_root_id: orgRootID(),
principal_id: principalID(),
principal_role: principalRole(),
include_membership_if_missing: true,
};
const payerWallet = $("payerWallet").value.trim();
const payerProof = $("payerProof").value.trim();
if (payerWallet) {
payload.payer_wallet = payerWallet;
}
if (payerProof) {
payload.ownership_proof = payerProof;
}
const out = await request("POST", "/marketplace/checkout/quote", payload);
state.lastCheckoutQuote = out;
$("checkoutQuoteId").value = out.quote_id || "";
$("checkoutTotal").value = out.total_amount || "";
logLine("marketplace checkout quote", out);
return out;
}
async function onCheckoutConfirm() {
const quoteID = $("checkoutQuoteId").value.trim();
if (!quoteID) {
throw new Error("checkout quote id is required");
}
const txHash = $("checkoutTxHash").value.trim();
if (!txHash) {
throw new Error("checkout tx hash is required");
}
const offerID = state.lastCheckoutQuote?.offer_id || $("checkoutOfferId").value.trim();
const out = await request("POST", "/marketplace/checkout/confirm", {
quote_id: quoteID,
wallet: requireWallet(),
offer_id: offerID,
org_root_id: orgRootID(),
principal_id: principalID(),
principal_role: principalRole(),
tx_hash: txHash,
chain_id: chainID(),
});
$("checkoutEntitlementId").value = out.entitlement_id || "";
logLine("marketplace checkout confirm", out);
return out;
}
async function onListEntitlements() {
const out = await request("GET", `/marketplace/entitlements?wallet=${encodeURIComponent(requireWallet())}`);
logLine("marketplace entitlements", out);
return out;
}
async function ensureChannelBinding() {
if (state.channelReady) {
return;
@ -690,6 +753,10 @@ bind("btnInstallConfirm", onInstallConfirm);
bind("btnInstallStatus", onInstallStatus);
bind("btnLeaseHeartbeat", onLeaseHeartbeat);
bind("btnOfflineRenew", onOfflineRenew);
bind("btnListOffers", onListOffers);
bind("btnCheckoutQuote", onCheckoutQuote);
bind("btnCheckoutConfirm", onCheckoutConfirm);
bind("btnListEntitlements", onListEntitlements);
logLine("launcher shell ready", {
api_base: baseURL(),

View File

@ -167,6 +167,46 @@
</label>
</section>
<section class="subpanel">
<h2>Marketplace Checkout</h2>
<div class="actions">
<button id="btnListOffers">List offers</button>
<button id="btnCheckoutQuote">Checkout quote</button>
<button id="btnCheckoutConfirm">Checkout confirm</button>
<button id="btnListEntitlements">List entitlements</button>
</div>
<div class="grid three">
<label>
Offer ID
<select id="checkoutOfferId">
<option value="edut.solo.core">edut.solo.core</option>
<option value="edut.workspace.core">edut.workspace.core</option>
<option value="edut.workspace.ai">edut.workspace.ai</option>
<option value="edut.workspace.lane24">edut.workspace.lane24</option>
<option value="edut.workspace.sovereign">edut.workspace.sovereign</option>
</select>
</label>
<label>
Checkout quote ID
<input id="checkoutQuoteId" />
</label>
<label>
Checkout tx hash
<input id="checkoutTxHash" placeholder="0x..." />
</label>
</div>
<div class="grid two">
<label>
Checkout total
<input id="checkoutTotal" />
</label>
<label>
Checkout entitlement ID
<input id="checkoutEntitlementId" />
</label>
</div>
</section>
<section class="subpanel">
<h2>Member Channel</h2>
<div class="grid three">

View File

@ -9,10 +9,14 @@ Launcher integrates with EDUT web/backend contracts as follows:
3. `POST /secret/membership/quote`
4. `POST /secret/membership/confirm`
5. `GET /secret/membership/status`
6. `POST /governance/install/token`
7. `POST /governance/install/confirm`
8. `GET /governance/install/status`
9. `GET /member/channel/events`
6. `GET /marketplace/offers`
7. `POST /marketplace/checkout/quote`
8. `POST /marketplace/checkout/confirm`
9. `GET /marketplace/entitlements`
10. `POST /governance/install/token`
11. `POST /governance/install/confirm`
12. `GET /governance/install/status`
13. `GET /member/channel/events`
## Deterministic Requirements