@tokenoftrust/storefront-runner 2.2.110 → 2.2.112

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -220,8 +220,8 @@
220
220
  }
221
221
  }
222
222
 
223
- function showMsg(kind, text) {
224
- const el = $("msg");
223
+ function showMsg(kind, text, targetId) {
224
+ const el = $(targetId || "msg");
225
225
  el.className = "msg " + kind;
226
226
  el.replaceChildren();
227
227
  if (typeof text === "string") {
@@ -242,15 +242,21 @@
242
242
  btn.className = "secondary";
243
243
  btn.textContent = "Provision now?";
244
244
  btn.title = "Create the store repo on this environment, then retry the invite";
245
- btn.addEventListener("click", () => provisionStore(btn));
245
+ btn.addEventListener("click", () => provisionStore(btn, { successHint: "Click Send invite again." }));
246
246
  wrap.appendChild(line);
247
247
  wrap.appendChild(btn);
248
248
  showMsg("err", wrap);
249
249
  }
250
250
 
251
- async function provisionStore(btn) {
251
+ // Shared by the invite dead-end's one-shot "Provision now?" button AND the
252
+ // persistent "Repair store connection" button below — same idempotent
253
+ // POST /api/grants/provision-store, which re-asserts the repo AND its webhooks
254
+ // on every call, even when the repo is already provisioned.
255
+ async function provisionStore(btn, opts) {
256
+ opts = opts || {};
257
+ const targetId = opts.targetId || "msg";
252
258
  if (btn) btn.disabled = true;
253
- showMsg("", "Provisioning store repo…");
259
+ showMsg("", opts.pendingMessage || "Provisioning store repo…", targetId);
254
260
  try {
255
261
  const res = await fetch("/api/grants/provision-store", {
256
262
  method: "POST",
@@ -262,14 +268,15 @@
262
268
  const created = body.created ? "created" : "already present";
263
269
  showMsg(
264
270
  "ok",
265
- "Store repo " + created + " for " + (body.tenant || tenant) +
266
- ". Click Send invite again.",
271
+ "Store repo " + created + " for " + (body.tenant || tenant) + "." +
272
+ (opts.successHint ? " " + opts.successHint : ""),
273
+ targetId,
267
274
  );
268
275
  } else {
269
- showMsg("err", body.error || ("Provision failed (HTTP " + res.status + ")."));
276
+ showMsg("err", body.error || ("Provision failed (HTTP " + res.status + ")."), targetId);
270
277
  }
271
278
  } catch (e) {
272
- showMsg("err", "Provision failed: " + (e && e.message ? e.message : e));
279
+ showMsg("err", "Provision failed: " + (e && e.message ? e.message : e), targetId);
273
280
  } finally {
274
281
  if (btn) btn.disabled = false;
275
282
  }
@@ -330,5 +337,20 @@
330
337
  inviteBtn.addEventListener("click", invite);
331
338
  emailInput.addEventListener("keydown", (e) => { if (e.key === "Enter") invite(); });
332
339
  }
340
+
341
+ // Persistent repair affordance: the invite dead-end's "Provision now?" button only
342
+ // ever appears as a 409 reaction, so once a repo is `provisioned: true` that path
343
+ // can never recur — leaving no self-service way to re-run the same idempotent
344
+ // repair (e.g. when the repo's registered webhook has drifted). This button is
345
+ // always available, independent of invite state.
346
+ const repairBtn = $("repairBtn");
347
+ if (repairBtn) {
348
+ repairBtn.addEventListener("click", () => provisionStore(repairBtn, {
349
+ targetId: "repairMsg",
350
+ pendingMessage: "Repairing store connection…",
351
+ successHint: "Webhooks re-synced.",
352
+ }));
353
+ }
354
+
333
355
  loadMembers();
334
356
  })();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tokenoftrust/storefront-runner",
3
- "version": "2.2.110",
3
+ "version": "2.2.112",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "description": "World-shareable storefront runner: multi-tenant renderer on Astro/Cloudflare. No control plane.",
6
6
  "packageManager": "pnpm@11.9.0",