@1sat/permission-module-ui 0.0.38 → 0.0.40

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.
@@ -15,7 +15,7 @@ export interface OneSatPermissionPromptProps {
15
15
  *
16
16
  * The host wallet feeds in the `request` it received from its promptHandler
17
17
  * callback and wires `onApprove`/`onReject` to resolve the same Promise.
18
- * Layout mirrors the design in `1sat-permissions-popups.pen` — 1Sat coin
18
+ * Layout mirrors `docs/plans/mockups/p1sat-permissions.pen` — 1Sat coin
19
19
  * badge, intent title, asset detail card, network/fee, approve/reject.
20
20
  */
21
21
  export declare function OneSatPermissionPrompt({ request, onApprove, onReject, theme, }: OneSatPermissionPromptProps): import("react").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"OneSatPermissionPrompt.d.ts","sourceRoot":"","sources":["../src/OneSatPermissionPrompt.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAU5D,MAAM,MAAM,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAA;AAE7C,MAAM,WAAW,2BAA2B;IAC3C,mEAAmE;IACnE,OAAO,EAAE,aAAa,CAAA;IACtB,yFAAyF;IACzF,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,yFAAyF;IACzF,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,2EAA2E;IAC3E,KAAK,CAAC,EAAE,KAAK,CAAA;CACb;AAqCD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,EACtC,OAAO,EACP,SAAS,EACT,QAAQ,EACR,KAAc,GACd,EAAE,2BAA2B,+BAuH7B"}
1
+ {"version":3,"file":"OneSatPermissionPrompt.d.ts","sourceRoot":"","sources":["../src/OneSatPermissionPrompt.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAU5D,MAAM,MAAM,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAA;AAE7C,MAAM,WAAW,2BAA2B;IAC3C,mEAAmE;IACnE,OAAO,EAAE,aAAa,CAAA;IACtB,yFAAyF;IACzF,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,yFAAyF;IACzF,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,2EAA2E;IAC3E,KAAK,CAAC,EAAE,KAAK,CAAA;CACb;AA8DD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,EACtC,OAAO,EACP,SAAS,EACT,QAAQ,EACR,KAAc,GACd,EAAE,2BAA2B,+BAyL7B"}
package/dist/index.js CHANGED
@@ -5,6 +5,31 @@ var ORDINALS_BASKET = "p 1sat ordinals";
5
5
  var BSV21_BASKET = "p 1sat bsv21";
6
6
  var OPNS_BASKET = "p 1sat opns";
7
7
  var LOCK_BASKET = "p 1sat lock";
8
+ var P1SAT_INTENTS = {
9
+ OPNS_REGISTER: "opns.register",
10
+ OPNS_DEREGISTER: "opns.deregister",
11
+ OPNS_LIST: "opns.list",
12
+ OPNS_TRANSFER: "opns.transfer",
13
+ OPNS_CANCEL_LISTING: "opns.cancel-listing",
14
+ OPNS_PURCHASE: "opns.purchase",
15
+ ORDINAL_TRANSFER: "ordinal.transfer",
16
+ ORDINAL_LIST: "ordinal.list",
17
+ ORDINAL_CANCEL_LISTING: "ordinal.cancel-listing",
18
+ ORDINAL_PURCHASE: "ordinal.purchase",
19
+ ORDINAL_BURN: "ordinal.burn",
20
+ ORDINAL_INSCRIBE: "ordinal.inscribe",
21
+ ORDINAL_INSCRIBE_SIGMA: "ordinal.inscribe-sigma",
22
+ ORDINAL_MINT_COLLECTION: "ordinal.mint-collection",
23
+ ORDINAL_MINT_ITEM: "ordinal.mint-item",
24
+ LOCK_LOCK: "lock.lock",
25
+ LOCK_UNLOCK: "lock.unlock",
26
+ BSV21_TRANSFER: "bsv21.transfer",
27
+ BSV21_PURCHASE: "bsv21.purchase",
28
+ BSV21_MINT: "bsv21.mint",
29
+ BSV21_DEPLOY: "bsv21.deploy"
30
+ };
31
+ var P1SAT_INTENT_IDS = new Set(Object.values(P1SAT_INTENTS));
32
+ var OPNS_REGISTER_LOCK_PLACEHOLDER_HEX = "00".repeat(142);
8
33
  var MAX_INSCRIPTION_BYTES = 50 * 1024 * 1024;
9
34
  var EXCHANGE_RATE_CACHE_TTL = 5 * 60 * 1000;
10
35
  var DEFAULT_STREAM_CHUNK_SIZE = 1024 * 1024;
@@ -53,6 +78,12 @@ var promptStyles = `
53
78
  --opp-reject-border: #d1d5db;
54
79
  --opp-status-bg: #FFFBE6;
55
80
  --opp-status-fg: #E5A920;
81
+ --opp-trust-ok-bg: #ECFDF5;
82
+ --opp-trust-ok-fg: #059669;
83
+ --opp-trust-warn-bg: #FFFBEB;
84
+ --opp-trust-warn-fg: #D97706;
85
+ --opp-trust-bad-bg: #FEF2F2;
86
+ --opp-trust-bad-fg: #DC2626;
56
87
 
57
88
  font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
58
89
  background: var(--opp-bg);
@@ -84,6 +115,12 @@ var promptStyles = `
84
115
  --opp-reject-border: #2D3142;
85
116
  --opp-status-bg: #2A2408;
86
117
  --opp-status-fg: #E5A920;
118
+ --opp-trust-ok-bg: #0A2E1F;
119
+ --opp-trust-ok-fg: #34D399;
120
+ --opp-trust-warn-bg: #2A2008;
121
+ --opp-trust-warn-fg: #FBBF24;
122
+ --opp-trust-bad-bg: #2A1215;
123
+ --opp-trust-bad-fg: #F87171;
87
124
  }
88
125
 
89
126
  .opp-body {
@@ -145,7 +182,7 @@ var promptStyles = `
145
182
  background: var(--opp-card-bg);
146
183
  border: 1px solid var(--opp-card-border);
147
184
  border-radius: 10px;
148
- margin: 0 20px;
185
+ margin: 0 20px 8px;
149
186
  padding: 16px;
150
187
  }
151
188
 
@@ -154,15 +191,30 @@ var promptStyles = `
154
191
  height: 80px;
155
192
  border-radius: 8px;
156
193
  object-fit: cover;
157
- background: rgba(0, 0, 0, 0.1);
194
+ background: rgba(0, 0, 0, 0.08);
158
195
  flex-shrink: 0;
159
196
  }
160
197
 
198
+ .opp-featured-image-token {
199
+ width: 48px;
200
+ height: 48px;
201
+ border-radius: 999px;
202
+ }
203
+
204
+ .opp-featured-placeholder {
205
+ display: flex;
206
+ align-items: center;
207
+ justify-content: center;
208
+ color: var(--opp-muted);
209
+ font-size: 18px;
210
+ }
211
+
161
212
  .opp-featured-meta {
162
213
  display: flex;
163
214
  flex-direction: column;
164
215
  gap: 4px;
165
216
  min-width: 0;
217
+ flex: 1;
166
218
  }
167
219
 
168
220
  .opp-featured-title {
@@ -176,9 +228,71 @@ var promptStyles = `
176
228
  .opp-featured-subtitle {
177
229
  font-size: 12px;
178
230
  color: var(--opp-muted);
231
+ display: flex;
232
+ align-items: center;
233
+ gap: 6px;
234
+ min-width: 0;
235
+ }
236
+
237
+ .opp-featured-subtitle-text {
179
238
  white-space: nowrap;
180
239
  overflow: hidden;
181
240
  text-overflow: ellipsis;
241
+ min-width: 0;
242
+ font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, monospace;
243
+ }
244
+
245
+ .opp-trust-wrap {
246
+ display: flex;
247
+ flex-direction: column;
248
+ gap: 8px;
249
+ margin: 0 20px 8px;
250
+ }
251
+
252
+ .opp-trust {
253
+ display: inline-flex;
254
+ align-self: flex-start;
255
+ padding: 3px 8px;
256
+ border-radius: 999px;
257
+ font-size: 10px;
258
+ font-weight: 600;
259
+ }
260
+
261
+ .opp-trust-verified {
262
+ background: var(--opp-trust-ok-bg);
263
+ color: var(--opp-trust-ok-fg);
264
+ }
265
+
266
+ .opp-trust-unverified {
267
+ background: var(--opp-trust-warn-bg);
268
+ color: var(--opp-trust-warn-fg);
269
+ }
270
+
271
+ .opp-trust-mismatch {
272
+ background: var(--opp-trust-bad-bg);
273
+ color: var(--opp-trust-bad-fg);
274
+ }
275
+
276
+ .opp-trust-note {
277
+ padding: 10px;
278
+ border-radius: 8px;
279
+ font-size: 11px;
280
+ line-height: 1.35;
281
+ }
282
+
283
+ .opp-trust-note-verified {
284
+ background: var(--opp-trust-ok-bg);
285
+ color: var(--opp-trust-ok-fg);
286
+ }
287
+
288
+ .opp-trust-note-unverified {
289
+ background: var(--opp-trust-warn-bg);
290
+ color: var(--opp-trust-warn-fg);
291
+ }
292
+
293
+ .opp-trust-note-mismatch {
294
+ background: var(--opp-trust-bad-bg);
295
+ color: var(--opp-trust-bad-fg);
182
296
  }
183
297
 
184
298
  .opp-row {
@@ -190,31 +304,54 @@ var promptStyles = `
190
304
 
191
305
  .opp-row-key {
192
306
  color: var(--opp-muted);
307
+ flex-shrink: 0;
308
+ }
309
+
310
+ .opp-row-value-wrap {
311
+ display: flex;
312
+ align-items: center;
313
+ gap: 6px;
314
+ min-width: 0;
315
+ max-width: 70%;
316
+ justify-content: flex-end;
193
317
  }
194
318
 
195
319
  .opp-row-value {
196
320
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, monospace;
197
- font-size: 13px;
321
+ font-size: 12px;
198
322
  font-weight: 500;
199
323
  text-align: right;
200
324
  white-space: nowrap;
201
325
  overflow: hidden;
202
326
  text-overflow: ellipsis;
203
327
  min-width: 0;
204
- max-width: 60%;
205
328
  }
206
329
 
207
- .opp-meta {
208
- display: flex;
209
- justify-content: space-between;
210
- padding: 12px 20px;
211
- font-size: 12px;
212
- color: var(--opp-muted);
330
+ .opp-copy {
331
+ flex-shrink: 0;
332
+ width: 22px;
333
+ height: 22px;
334
+ padding: 0;
335
+ display: inline-flex;
336
+ align-items: center;
337
+ justify-content: center;
338
+ border-radius: 6px;
339
+ border: 1px solid var(--opp-reject-border);
340
+ background: var(--opp-bg);
341
+ color: var(--opp-fg);
342
+ cursor: pointer;
213
343
  }
214
344
 
215
- .opp-meta-value {
216
- color: var(--opp-fg);
217
- font-weight: 500;
345
+ .opp-copy:hover {
346
+ border-color: var(--opp-accent);
347
+ color: var(--opp-accent);
348
+ }
349
+
350
+ .opp-fee-note {
351
+ font-size: 11px;
352
+ color: var(--opp-muted);
353
+ line-height: 1.3;
354
+ margin-top: -4px;
218
355
  }
219
356
 
220
357
  .opp-actions {
@@ -264,7 +401,7 @@ var promptStyles = `
264
401
  `;
265
402
 
266
403
  // src/OneSatPermissionPrompt.tsx
267
- import { jsx, jsxs } from "react/jsx-runtime";
404
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
268
405
  function OneSatPermissionPrompt({
269
406
  request,
270
407
  onApprove,
@@ -272,8 +409,25 @@ function OneSatPermissionPrompt({
272
409
  theme = "auto"
273
410
  }) {
274
411
  const resolvedTheme = useResolvedTheme(theme);
275
- const summary = summarizeRequest(request);
412
+ const base = summarizeRequest(request);
276
413
  const [busy, setBusy] = useState(false);
414
+ const [verified, setVerified] = useState(undefined);
415
+ const verification = request.intent?.verification;
416
+ useEffect(() => {
417
+ if (!verification)
418
+ return;
419
+ let live = true;
420
+ verification.then((res) => {
421
+ if (live && res)
422
+ setVerified(res);
423
+ }).catch(() => {
424
+ return;
425
+ });
426
+ return () => {
427
+ live = false;
428
+ };
429
+ }, [verification]);
430
+ const summary = verified ? applyVerification(base, verified) : base;
277
431
  const handle = (action) => () => {
278
432
  if (busy)
279
433
  return;
@@ -289,6 +443,8 @@ function OneSatPermissionPrompt({
289
443
  };
290
444
  useEffect(() => {
291
445
  const onKey = (e) => {
446
+ if (busy)
447
+ return;
292
448
  if (e.key === "Escape")
293
449
  onReject();
294
450
  else if (e.key === "Enter")
@@ -296,8 +452,9 @@ function OneSatPermissionPrompt({
296
452
  };
297
453
  window.addEventListener("keydown", onKey);
298
454
  return () => window.removeEventListener("keydown", onKey);
299
- }, [onApprove, onReject]);
455
+ }, [onApprove, onReject, busy]);
300
456
  const className = `opp-root${resolvedTheme === "dark" ? " opp-dark" : ""}`;
457
+ const featuredVariant = summary.featured?.variant ?? "ordinal";
301
458
  return /* @__PURE__ */ jsxs("div", {
302
459
  className,
303
460
  children: [
@@ -355,12 +512,16 @@ function OneSatPermissionPrompt({
355
512
  ]
356
513
  }),
357
514
  summary.featured && /* @__PURE__ */ jsxs("div", {
358
- className: "opp-featured",
515
+ className: `opp-featured${featuredVariant === "token" ? " opp-featured-token" : ""}`,
359
516
  children: [
360
- /* @__PURE__ */ jsx("img", {
361
- className: "opp-featured-image",
517
+ summary.featured.imageUrl ? /* @__PURE__ */ jsx("img", {
518
+ className: featuredVariant === "token" ? "opp-featured-image opp-featured-image-token" : "opp-featured-image",
362
519
  src: summary.featured.imageUrl,
363
520
  alt: summary.featured.title
521
+ }) : /* @__PURE__ */ jsx("div", {
522
+ className: featuredVariant === "token" ? "opp-featured-image opp-featured-image-token opp-featured-placeholder" : "opp-featured-image opp-featured-placeholder",
523
+ "aria-hidden": true,
524
+ children: featuredVariant === "token" ? "◎" : "▭"
364
525
  }),
365
526
  /* @__PURE__ */ jsxs("div", {
366
527
  className: "opp-featured-meta",
@@ -369,61 +530,89 @@ function OneSatPermissionPrompt({
369
530
  className: "opp-featured-title",
370
531
  children: summary.featured.title
371
532
  }),
372
- summary.featured.subtitle && /* @__PURE__ */ jsx("div", {
533
+ summary.featured.subtitle && /* @__PURE__ */ jsxs("div", {
373
534
  className: "opp-featured-subtitle",
374
- children: summary.featured.subtitle
535
+ children: [
536
+ /* @__PURE__ */ jsx("span", {
537
+ className: "opp-featured-subtitle-text",
538
+ children: summary.featured.subtitle
539
+ }),
540
+ summary.featured.subtitleCopy && /* @__PURE__ */ jsx(CopyButton, {
541
+ text: summary.featured.subtitleCopy
542
+ })
543
+ ]
375
544
  })
376
545
  ]
377
546
  })
378
547
  ]
379
548
  }),
380
- summary.rows.length > 0 && /* @__PURE__ */ jsx("div", {
381
- className: "opp-card",
382
- children: summary.rows.map((row) => /* @__PURE__ */ jsxs("div", {
383
- className: "opp-row",
384
- children: [
385
- /* @__PURE__ */ jsx("span", {
386
- className: "opp-row-key",
387
- children: row.key
388
- }),
389
- /* @__PURE__ */ jsx("span", {
390
- className: "opp-row-value",
391
- children: row.value
392
- })
393
- ]
394
- }, `${row.key}:${row.value}`))
549
+ summary.trust && /* @__PURE__ */ jsxs("div", {
550
+ className: "opp-trust-wrap",
551
+ children: [
552
+ /* @__PURE__ */ jsx("span", {
553
+ className: `opp-trust opp-trust-${summary.trust.state}`,
554
+ children: trustLabel(summary.trust.state)
555
+ }),
556
+ summary.trust.note && /* @__PURE__ */ jsx("div", {
557
+ className: `opp-trust-note opp-trust-note-${summary.trust.state}`,
558
+ children: summary.trust.note
559
+ })
560
+ ]
395
561
  }),
396
- /* @__PURE__ */ jsxs("div", {
397
- className: "opp-bottom",
562
+ (summary.rows.length > 0 || summary.indexerFee) && /* @__PURE__ */ jsxs("div", {
563
+ className: "opp-card",
398
564
  children: [
399
- (summary.network || summary.feeSats !== undefined) && /* @__PURE__ */ jsxs("div", {
400
- className: "opp-meta",
565
+ summary.rows.map((row) => /* @__PURE__ */ jsxs("div", {
566
+ className: "opp-row",
401
567
  children: [
402
- summary.network && /* @__PURE__ */ jsxs("span", {
568
+ /* @__PURE__ */ jsx("span", {
569
+ className: "opp-row-key",
570
+ children: row.key
571
+ }),
572
+ /* @__PURE__ */ jsxs("span", {
573
+ className: "opp-row-value-wrap",
403
574
  children: [
404
- "Network",
405
- " ",
406
575
  /* @__PURE__ */ jsx("span", {
407
- className: "opp-meta-value",
408
- children: summary.network
576
+ className: "opp-row-value",
577
+ title: row.copyValue ?? row.value,
578
+ children: row.value
579
+ }),
580
+ row.copyValue && /* @__PURE__ */ jsx(CopyButton, {
581
+ text: row.copyValue
409
582
  })
410
583
  ]
411
- }),
412
- summary.feeSats !== undefined && /* @__PURE__ */ jsxs("span", {
584
+ })
585
+ ]
586
+ }, `${row.key}:${row.value}`)),
587
+ summary.indexerFee && /* @__PURE__ */ jsxs(Fragment, {
588
+ children: [
589
+ /* @__PURE__ */ jsxs("div", {
590
+ className: "opp-row",
413
591
  children: [
414
- "Estimated Fee",
415
- " ",
592
+ /* @__PURE__ */ jsx("span", {
593
+ className: "opp-row-key",
594
+ children: "Indexer fee"
595
+ }),
416
596
  /* @__PURE__ */ jsxs("span", {
417
- className: "opp-meta-value",
597
+ className: "opp-row-value",
418
598
  children: [
419
- summary.feeSats,
599
+ formatSats(summary.indexerFee.sats),
420
600
  " sats"
421
601
  ]
422
602
  })
423
603
  ]
604
+ }),
605
+ summary.indexerFee.note && /* @__PURE__ */ jsx("div", {
606
+ className: "opp-fee-note",
607
+ children: summary.indexerFee.note
424
608
  })
425
609
  ]
426
- }),
610
+ })
611
+ ]
612
+ }),
613
+ /* @__PURE__ */ jsxs("div", {
614
+ className: "opp-bottom",
615
+ children: [
427
616
  /* @__PURE__ */ jsxs("div", {
428
617
  className: "opp-actions",
429
618
  children: [
@@ -454,6 +643,72 @@ function OneSatPermissionPrompt({
454
643
  ]
455
644
  });
456
645
  }
646
+ function trustLabel(state) {
647
+ if (state === "verified")
648
+ return "Verified";
649
+ if (state === "mismatch")
650
+ return "Mismatch";
651
+ return "Unverified";
652
+ }
653
+ function formatSats(n) {
654
+ return n.toLocaleString("en-US");
655
+ }
656
+ function CopyButton({ text }) {
657
+ const [copied, setCopied] = useState(false);
658
+ const onCopy = () => {
659
+ navigator.clipboard?.writeText(text).then(() => {
660
+ setCopied(true);
661
+ window.setTimeout(() => setCopied(false), 1200);
662
+ });
663
+ };
664
+ return /* @__PURE__ */ jsx("button", {
665
+ type: "button",
666
+ className: "opp-copy",
667
+ onClick: onCopy,
668
+ "aria-label": copied ? "Copied" : "Copy full value",
669
+ title: copied ? "Copied" : "Copy",
670
+ children: copied ? /* @__PURE__ */ jsx("svg", {
671
+ width: "12",
672
+ height: "12",
673
+ viewBox: "0 0 24 24",
674
+ fill: "none",
675
+ "aria-hidden": true,
676
+ children: /* @__PURE__ */ jsx("path", {
677
+ d: "M5 13l4 4L19 7",
678
+ stroke: "currentColor",
679
+ strokeWidth: "2.5",
680
+ strokeLinecap: "round",
681
+ strokeLinejoin: "round"
682
+ })
683
+ }) : /* @__PURE__ */ jsxs("svg", {
684
+ width: "12",
685
+ height: "12",
686
+ viewBox: "0 0 24 24",
687
+ fill: "none",
688
+ "aria-hidden": true,
689
+ children: [
690
+ /* @__PURE__ */ jsx("rect", {
691
+ x: "9",
692
+ y: "9",
693
+ width: "11",
694
+ height: "11",
695
+ rx: "2",
696
+ stroke: "currentColor",
697
+ strokeWidth: "2"
698
+ }),
699
+ /* @__PURE__ */ jsx("path", {
700
+ d: "M5 15V5a2 2 0 012-2h10",
701
+ stroke: "currentColor",
702
+ strokeWidth: "2",
703
+ strokeLinecap: "round"
704
+ })
705
+ ]
706
+ })
707
+ });
708
+ }
709
+ function copyable(key, full) {
710
+ return { key, value: shortenValue(full), copyValue: full };
711
+ }
457
712
  function useResolvedTheme(theme) {
458
713
  const [resolved, setResolved] = useState(() => theme === "auto" ? readSystemTheme() : theme);
459
714
  useEffect(() => {
@@ -474,9 +729,38 @@ function readSystemTheme() {
474
729
  return "light";
475
730
  return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
476
731
  }
732
+ function applyVerification(base, res) {
733
+ const rows = base.rows.map((row) => {
734
+ if (row.key === "Origin" && res.origin)
735
+ return copyable("Origin", res.origin);
736
+ if (row.key === "Type" && res.contentType) {
737
+ return { key: "Type", value: res.contentType };
738
+ }
739
+ return row;
740
+ });
741
+ if (res.contentLength !== undefined && !rows.some((r) => r.key === "Size")) {
742
+ rows.push({
743
+ key: "Size",
744
+ value: `${res.contentLength.toLocaleString("en-US")} bytes`
745
+ });
746
+ }
747
+ return {
748
+ ...base,
749
+ rows,
750
+ trust: { state: res.state, note: res.note },
751
+ featured: base.featured ? {
752
+ ...base.featured,
753
+ title: res.name ?? base.featured.title,
754
+ imageUrl: res.contentUrl ?? base.featured.imageUrl
755
+ } : undefined
756
+ };
757
+ }
477
758
  function summarizeRequest(req) {
478
759
  if (req.kind === "transaction") {
479
760
  const intent = req.intent;
761
+ const byIntent = summarizeByP1SatIntent(req, intent);
762
+ if (byIntent)
763
+ return byIntent;
480
764
  switch (intent.kind) {
481
765
  case "ordinal-transfer":
482
766
  return summarizeOrdinalTransfer(req, intent);
@@ -522,6 +806,128 @@ function summarizeBasketAccess(req) {
522
806
  }))
523
807
  };
524
808
  }
809
+ var INTENT_TITLES = {
810
+ "opns.register": "Publish name",
811
+ "opns.deregister": "Unpublish name",
812
+ "opns.list": "List name for sale",
813
+ "opns.transfer": "Transfer name",
814
+ "opns.cancel-listing": "Cancel listing",
815
+ "opns.purchase": "Buy name",
816
+ "ordinal.transfer": "Send ordinal",
817
+ "ordinal.list": "List for sale",
818
+ "ordinal.cancel-listing": "Cancel listing",
819
+ "ordinal.purchase": "Buy ordinal",
820
+ "ordinal.burn": "Burn ordinal",
821
+ "ordinal.inscribe": "Create inscription",
822
+ "ordinal.inscribe-sigma": "Create inscription",
823
+ "ordinal.mint-collection": "Mint collection",
824
+ "ordinal.mint-item": "Mint collection item",
825
+ "lock.lock": "Lock BSV",
826
+ "lock.unlock": "Unlock BSV",
827
+ "bsv21.transfer": "Send tokens",
828
+ "bsv21.purchase": "Buy tokens",
829
+ "bsv21.mint": "Mint tokens",
830
+ "bsv21.deploy": "Deploy token"
831
+ };
832
+ function summarizeByP1SatIntent(req, intent) {
833
+ const id = intent.p1satIntent;
834
+ if (!id || !INTENT_TITLES[id])
835
+ return;
836
+ let base;
837
+ switch (intent.kind) {
838
+ case "ordinal-transfer":
839
+ base = summarizeOrdinalTransfer(req, intent);
840
+ break;
841
+ case "token-transfer":
842
+ base = summarizeTokenTransfer(req, intent);
843
+ break;
844
+ case "lock":
845
+ base = summarizeLock(req, intent);
846
+ break;
847
+ case "unlock":
848
+ base = summarizeUnlock(req, intent);
849
+ break;
850
+ case "inscription":
851
+ base = summarizeInscription(req, intent);
852
+ break;
853
+ case "listing":
854
+ base = summarizeListing(req, intent);
855
+ break;
856
+ case "cancel-listing":
857
+ base = summarizeCancelListing(req, intent);
858
+ break;
859
+ case "purchase":
860
+ base = summarizePurchase(req, intent);
861
+ break;
862
+ case "opns":
863
+ base = summarizeOpns(req, intent);
864
+ break;
865
+ default:
866
+ base = summarizeUnknownTx(req, intent);
867
+ }
868
+ return {
869
+ ...base,
870
+ title: INTENT_TITLES[id],
871
+ subtitle: intentSubtitle(req, id, intent),
872
+ feeSats: undefined,
873
+ network: undefined,
874
+ trust: intent.trust ?? base.trust,
875
+ indexerFee: intent.indexerFeeSats != null && intent.indexerFeeSats > 0 ? {
876
+ sats: intent.indexerFeeSats,
877
+ note: intent.indexerFeeNote
878
+ } : base.indexerFee
879
+ };
880
+ }
881
+ function intentSubtitle(req, id, intent) {
882
+ const o = shortenOriginator(req.originator);
883
+ const name = tagValue(intent.inputs[0]?.tags, "name") ?? tagValue(intent.outputs.find((out) => out.tags.some((t) => t.startsWith("name:")))?.tags, "name");
884
+ const quoted = name ? `“${name}”` : undefined;
885
+ switch (id) {
886
+ case "opns.register":
887
+ return `${o} wants to publish ${quoted ?? "an OpNS name"}`;
888
+ case "opns.deregister":
889
+ return `${o} wants to unpublish ${quoted ?? "an OpNS name"}`;
890
+ case "opns.list":
891
+ return `${o} wants to list ${quoted ?? "an OpNS name"} for sale`;
892
+ case "opns.transfer":
893
+ return `${o} wants to transfer ${quoted ?? "an OpNS name"}`;
894
+ case "opns.cancel-listing":
895
+ return `${o} wants to cancel ${quoted ? `the listing of ${quoted}` : "an OpNS listing"}`;
896
+ case "opns.purchase":
897
+ return `${o} wants to buy ${quoted ?? "an OpNS name"}`;
898
+ case "ordinal.transfer":
899
+ return `${o} wants to transfer an ordinal`;
900
+ case "ordinal.list":
901
+ return `${o} wants to list ${quoted ?? "an ordinal"} for sale`;
902
+ case "ordinal.cancel-listing":
903
+ return `${o} wants to cancel ${quoted ? `the listing of ${quoted}` : "an ordinal listing"}`;
904
+ case "ordinal.purchase":
905
+ return `${o} wants to purchase an ordinal into your wallet`;
906
+ case "ordinal.burn":
907
+ return `${o} wants to burn an ordinal`;
908
+ case "ordinal.inscribe":
909
+ case "ordinal.inscribe-sigma":
910
+ return `${o} wants to inscribe content into your wallet`;
911
+ case "ordinal.mint-collection":
912
+ return `${o} wants to mint a collection`;
913
+ case "ordinal.mint-item":
914
+ return `${o} wants to mint a collection item`;
915
+ case "lock.lock":
916
+ return `${o} wants to time-lock funds`;
917
+ case "lock.unlock":
918
+ return `${o} wants to unlock matured locks`;
919
+ case "bsv21.transfer":
920
+ return `${o} wants to send tokens`;
921
+ case "bsv21.purchase":
922
+ return `${o} wants to purchase tokens into your wallet`;
923
+ case "bsv21.mint":
924
+ return `${o} wants to mint tokens`;
925
+ case "bsv21.deploy":
926
+ return `${o} wants to deploy a BSV21 token`;
927
+ default:
928
+ return `${o} wants to ${req.summary.toLowerCase()}`;
929
+ }
930
+ }
525
931
  function tagValue(tags, key) {
526
932
  if (!tags)
527
933
  return;
@@ -542,21 +948,20 @@ function summarizeOrdinalTransfer(req, intent) {
542
948
  const imageUrl = origin ? intent.contentUrls?.[origin] : undefined;
543
949
  const rows = [];
544
950
  if (recipient)
545
- rows.push({ key: "Recipient", value: shortenValue(recipient) });
951
+ rows.push(copyable("Recipient", recipient));
546
952
  if (origin)
547
- rows.push({ key: "Origin", value: shortenValue(origin) });
953
+ rows.push(copyable("Origin", origin));
548
954
  if (contentType)
549
955
  rows.push({ key: "Type", value: contentType });
550
956
  return {
551
- title: "NFT Transfer",
957
+ title: "Send ordinal",
552
958
  subtitle: `${shortenOriginator(req.originator)} wants to transfer an ordinal`,
553
959
  rows,
554
960
  featured: imageUrl ? {
555
961
  imageUrl,
556
962
  title: name ?? "Untitled ordinal",
557
963
  subtitle: collectionId ?? contentType
558
- } : undefined,
559
- network: networkLabel(intent.chain)
964
+ } : undefined
560
965
  };
561
966
  }
562
967
  function summarizeTokenTransfer(req, intent) {
@@ -565,12 +970,12 @@ function summarizeTokenTransfer(req, intent) {
565
970
  const tokenId = tagValue(input.tags, "bsv21");
566
971
  if (!tokenId)
567
972
  continue;
568
- const sym = tagValue(input.tags, "sym");
973
+ const sym2 = tagValue(input.tags, "sym");
569
974
  const amt = BigInt(tagValue(input.tags, "amt") ?? "0");
570
- const cur = totals.get(tokenId) ?? { sym, inAmt: 0n, changeAmt: 0n };
975
+ const cur = totals.get(tokenId) ?? { sym: sym2, inAmt: 0n, changeAmt: 0n };
571
976
  cur.inAmt += amt;
572
- if (!cur.sym && sym)
573
- cur.sym = sym;
977
+ if (!cur.sym && sym2)
978
+ cur.sym = sym2;
574
979
  totals.set(tokenId, cur);
575
980
  }
576
981
  for (const output of intent.outputs) {
@@ -585,36 +990,75 @@ function summarizeTokenTransfer(req, intent) {
585
990
  cur.changeAmt += amt;
586
991
  }
587
992
  const rows = [];
993
+ let featured;
994
+ let primaryTokenId;
588
995
  for (const [tokenId, info] of totals) {
589
- rows.push({
590
- key: "Token",
591
- value: info.sym ? `${info.sym} — ${shortenId(tokenId)}` : shortenId(tokenId)
592
- });
996
+ if (!primaryTokenId)
997
+ primaryTokenId = tokenId;
593
998
  const sent = info.inAmt - info.changeAmt;
594
- rows.push({ key: "Amount", value: sent.toString() });
999
+ rows.push({ key: "Amount", value: sent.toLocaleString("en-US") });
595
1000
  }
596
- const recipient = intent.outputs.find((o) => o.recipient && o.basket !== BSV21_BASKET)?.recipient;
597
- if (recipient)
598
- rows.push({ key: "Recipient", value: shortenValue(recipient) });
1001
+ const to = intent.outputs.find((o) => o.recipient && o.satoshis === 1)?.recipient;
1002
+ if (to)
1003
+ rows.push(copyable("Recipient", to));
1004
+ const firstIn = intent.inputs.find((i) => tagValue(i.tags, "bsv21"));
1005
+ const sym = (primaryTokenId ? totals.get(primaryTokenId)?.sym : undefined) ?? tagValue(firstIn?.tags, "sym");
1006
+ const iconRef = tagValue(firstIn?.tags, "icon");
1007
+ const iconUrl = iconRef && intent.contentUrls?.[iconRef] || primaryTokenId && intent.contentUrls?.[primaryTokenId] || undefined;
1008
+ if (primaryTokenId) {
1009
+ featured = {
1010
+ variant: "token",
1011
+ imageUrl: iconUrl,
1012
+ title: sym ?? "Token",
1013
+ subtitle: shortenId(primaryTokenId),
1014
+ subtitleCopy: primaryTokenId
1015
+ };
1016
+ }
1017
+ const indexerFee = resolveIndexerFee(intent);
599
1018
  return {
600
- title: "Token Transfer",
1019
+ title: "Send tokens",
601
1020
  subtitle: `${shortenOriginator(req.originator)} wants to send tokens`,
602
1021
  rows,
603
- network: networkLabel(intent.chain)
1022
+ featured,
1023
+ indexerFee
604
1024
  };
605
1025
  }
1026
+ function resolveIndexerFee(intent) {
1027
+ if (intent.indexerFeeSats != null && intent.indexerFeeSats > 0) {
1028
+ return {
1029
+ sats: intent.indexerFeeSats,
1030
+ note: intent.indexerFeeNote
1031
+ };
1032
+ }
1033
+ const tokenOutCount = intent.outputs.filter((o) => o.basket === BSV21_BASKET || tagValue(o.tags, "bsv21")).length;
1034
+ const feeLike = intent.outputs.filter((o) => !o.basket && o.recipient && o.satoshis > 1);
1035
+ const isPurchase = intent.p1satIntent?.endsWith(".purchase") || intent.kind === "purchase";
1036
+ if (isPurchase || feeLike.length !== 1)
1037
+ return;
1038
+ const fee = feeLike[0];
1039
+ if (!fee || fee.satoshis <= 0)
1040
+ return;
1041
+ const note = tokenOutCount > 0 ? `Overlay processing · ${formatSats(Math.round(fee.satoshis / tokenOutCount))} sats × ${tokenOutCount} token outs` : "Overlay processing fee";
1042
+ return { sats: fee.satoshis, note };
1043
+ }
606
1044
  function summarizeLock(req, intent) {
607
- const lockOutputs = intent.outputs.filter((o) => o.basket === LOCK_BASKET);
1045
+ const decoded = intent.outputs.filter((o) => o.lockUntilHeight !== undefined);
1046
+ const lockOutputs = decoded.length > 0 ? decoded : intent.outputs.filter((o) => o.basket === LOCK_BASKET);
608
1047
  const sats = (lockOutputs.length > 0 ? lockOutputs : intent.outputs).reduce((s, o) => s + o.satoshis, 0);
609
- const until = (lockOutputs.length > 0 ? lockOutputs : intent.outputs).flatMap((o) => o.tags).find((t) => t.startsWith("until:"))?.slice("until:".length);
610
- const rows = [{ key: "Amount", value: `${sats} sats` }];
611
- if (until)
612
- rows.push({ key: "Lock until block", value: until });
1048
+ const until = decoded[0]?.lockUntilHeight;
1049
+ const rows = [
1050
+ { key: "Amount", value: `${sats.toLocaleString("en-US")} sats` }
1051
+ ];
1052
+ if (until !== undefined) {
1053
+ rows.push({
1054
+ key: "Lock until block",
1055
+ value: until.toLocaleString("en-US")
1056
+ });
1057
+ }
613
1058
  return {
614
1059
  title: "Lock BSV",
615
1060
  subtitle: `${shortenOriginator(req.originator)} wants to time-lock funds`,
616
- rows,
617
- network: networkLabel(intent.chain)
1061
+ rows
618
1062
  };
619
1063
  }
620
1064
  function summarizeUnlock(req, intent) {
@@ -622,8 +1066,7 @@ function summarizeUnlock(req, intent) {
622
1066
  return {
623
1067
  title: "Unlock Matured",
624
1068
  subtitle: `${shortenOriginator(req.originator)} wants to unlock matured locks`,
625
- rows: [{ key: "Amount", value: `${sats} sats` }],
626
- network: networkLabel(intent.chain)
1069
+ rows: [{ key: "Amount", value: `${sats} sats` }]
627
1070
  };
628
1071
  }
629
1072
  function summarizeInscription(req, intent) {
@@ -637,30 +1080,30 @@ function summarizeInscription(req, intent) {
637
1080
  if (name)
638
1081
  rows.push({ key: "Name", value: name });
639
1082
  if (recipient)
640
- rows.push({ key: "Recipient", value: shortenValue(recipient) });
1083
+ rows.push(copyable("Recipient", recipient));
641
1084
  return {
642
1085
  title: "Create Inscription",
643
1086
  subtitle: `${shortenOriginator(req.originator)} wants to inscribe content into your wallet`,
644
- rows,
645
- network: networkLabel(intent.chain)
1087
+ rows
646
1088
  };
647
1089
  }
648
1090
  function summarizeListing(req, intent) {
649
- const listingOutput = intent.outputs.find((o) => o.tags.some((t) => t.startsWith("price:")));
1091
+ const listingOutput = intent.outputs.find((o) => o.listingPriceSats !== undefined) ?? intent.outputs.find((o) => o.tags.some((t) => t.startsWith("price:")));
650
1092
  const ordinal = intent.inputs[0];
651
1093
  const origin = tagValue(ordinal?.tags, "origin") ?? tagValue(listingOutput?.tags, "origin");
652
1094
  const name = tagValue(ordinal?.tags, "name") ?? tagValue(listingOutput?.tags, "name");
653
1095
  const contentType = tagValue(ordinal?.tags, "type") ?? tagValue(listingOutput?.tags, "type");
654
1096
  const collectionId = tagValue(ordinal?.tags, "collectionId");
655
1097
  const imageUrl = origin ? intent.contentUrls?.[origin] : undefined;
656
- const price = tagValue(listingOutput?.tags, "price");
1098
+ const price = listingOutput?.listingPriceSats;
657
1099
  const rows = [];
658
1100
  if (name)
659
1101
  rows.push({ key: "Name", value: name });
660
- if (price)
661
- rows.push({ key: "Price", value: `${price} sats` });
1102
+ if (price !== undefined) {
1103
+ rows.push({ key: "Price", value: `${price.toLocaleString("en-US")} sats` });
1104
+ }
662
1105
  if (origin)
663
- rows.push({ key: "Origin", value: shortenValue(origin) });
1106
+ rows.push(copyable("Origin", origin));
664
1107
  if (contentType)
665
1108
  rows.push({ key: "Type", value: contentType });
666
1109
  return {
@@ -671,8 +1114,7 @@ function summarizeListing(req, intent) {
671
1114
  imageUrl,
672
1115
  title: name ?? "Untitled ordinal",
673
1116
  subtitle: collectionId ?? contentType
674
- } : undefined,
675
- network: networkLabel(intent.chain)
1117
+ } : undefined
676
1118
  };
677
1119
  }
678
1120
  function summarizeCancelListing(req, intent) {
@@ -690,7 +1132,7 @@ function summarizeCancelListing(req, intent) {
690
1132
  if (price)
691
1133
  rows.push({ key: "Original price", value: `${price} sats` });
692
1134
  if (origin)
693
- rows.push({ key: "Origin", value: shortenValue(origin) });
1135
+ rows.push(copyable("Origin", origin));
694
1136
  if (contentType)
695
1137
  rows.push({ key: "Type", value: contentType });
696
1138
  return {
@@ -701,8 +1143,7 @@ function summarizeCancelListing(req, intent) {
701
1143
  imageUrl,
702
1144
  title: name ?? "Untitled ordinal",
703
1145
  subtitle: collectionId ?? contentType
704
- } : undefined,
705
- network: networkLabel(intent.chain)
1146
+ } : undefined
706
1147
  };
707
1148
  }
708
1149
  function summarizePurchase(req, intent) {
@@ -719,41 +1160,49 @@ function summarizePurchase(req, intent) {
719
1160
  const price = sellerOutput?.satoshis;
720
1161
  const rows = [];
721
1162
  if (price !== undefined)
722
- rows.push({ key: "Price", value: `${price} sats` });
1163
+ rows.push({ key: "Price", value: `${price.toLocaleString("en-US")} sats` });
723
1164
  if (isToken) {
724
1165
  if (amt)
725
1166
  rows.push({ key: "Amount", value: amt });
726
- if (sym || tokenId) {
727
- rows.push({
728
- key: "Token",
729
- value: sym && tokenId ? `${sym} — ${shortenId(tokenId)}` : sym ?? shortenId(tokenId ?? "")
730
- });
731
- }
732
1167
  } else {
733
1168
  if (origin)
734
- rows.push({ key: "Origin", value: shortenValue(origin) });
1169
+ rows.push(copyable("Origin", origin));
735
1170
  if (contentType)
736
1171
  rows.push({ key: "Type", value: contentType });
737
1172
  }
738
1173
  const featuredImage = !isToken && origin ? intent.contentUrls?.[origin] : undefined;
739
- return {
740
- title: isToken ? "Purchase Tokens" : "Purchase Ordinal",
741
- subtitle: isToken ? `${shortenOriginator(req.originator)} wants to purchase tokens into your wallet` : `${shortenOriginator(req.originator)} wants to purchase an ordinal into your wallet`,
742
- rows,
743
- featured: !isToken && featuredImage ? {
1174
+ const iconRef = tagValue(incoming?.tags, "icon");
1175
+ const iconUrl = iconRef && intent.contentUrls?.[iconRef] || tokenId && intent.contentUrls?.[tokenId] || undefined;
1176
+ let featured;
1177
+ if (isToken && (sym || tokenId)) {
1178
+ featured = {
1179
+ variant: "token",
1180
+ imageUrl: iconUrl,
1181
+ title: sym ?? "Token",
1182
+ subtitle: tokenId ? shortenId(tokenId) : undefined,
1183
+ subtitleCopy: tokenId
1184
+ };
1185
+ } else if (featuredImage) {
1186
+ featured = {
744
1187
  imageUrl: featuredImage,
745
1188
  title: name ?? "Untitled ordinal",
746
1189
  subtitle: collectionId ?? contentType
747
- } : undefined,
748
- network: networkLabel(intent.chain)
1190
+ };
1191
+ }
1192
+ return {
1193
+ title: isToken ? "Buy tokens" : "Buy ordinal",
1194
+ subtitle: isToken ? `${shortenOriginator(req.originator)} wants to purchase tokens into your wallet` : `${shortenOriginator(req.originator)} wants to purchase an ordinal into your wallet`,
1195
+ rows,
1196
+ featured,
1197
+ trust: intent.trust,
1198
+ indexerFee: resolveIndexerFee(intent)
749
1199
  };
750
1200
  }
751
1201
  function summarizeSocialPost(req, intent) {
752
1202
  return {
753
1203
  title: "Social Post",
754
1204
  subtitle: `${shortenOriginator(req.originator)} wants to publish a post`,
755
- rows: [],
756
- network: networkLabel(intent.chain)
1205
+ rows: []
757
1206
  };
758
1207
  }
759
1208
  function summarizeOpns(req, intent) {
@@ -762,34 +1211,52 @@ function summarizeOpns(req, intent) {
762
1211
  const recipient = intent.outputs.find((o) => !o.basket && o.recipient)?.recipient;
763
1212
  const name = tagValue(input?.tags, "name") ?? tagValue(opnsOutput?.tags, "name");
764
1213
  const origin = tagValue(input?.tags, "origin") ?? tagValue(opnsOutput?.tags, "origin");
1214
+ const priceTag = intent.outputs.flatMap((o) => o.tags).find((t) => t.startsWith("price:"));
1215
+ const price = priceTag?.slice("price:".length);
765
1216
  const rows = [];
766
1217
  if (name)
767
1218
  rows.push({ key: "Name", value: name });
768
1219
  if (recipient)
769
- rows.push({ key: "Recipient", value: shortenValue(recipient) });
1220
+ rows.push(copyable("Recipient", recipient));
1221
+ if (price)
1222
+ rows.push({ key: "Price", value: `${price} sats` });
770
1223
  if (origin)
771
- rows.push({ key: "Origin", value: shortenValue(origin) });
772
- const isTransfer = Boolean(recipient);
1224
+ rows.push(copyable("Origin", origin));
1225
+ const copy = opnsCopy(intent.p1satIntent, Boolean(recipient));
1226
+ const nameBit = name ? `“${name}”` : "an OpNS name";
773
1227
  return {
774
- title: isTransfer ? "Transfer OpNS Name" : "Update OpNS Name",
775
- subtitle: `${shortenOriginator(req.originator)} wants to ${isTransfer ? "transfer" : "update"} ${name ? `“${name}”` : "an OpNS name"}`,
776
- rows,
777
- network: networkLabel(intent.chain)
1228
+ title: copy.title,
1229
+ subtitle: `${shortenOriginator(req.originator)} wants to ${copy.verb} ${nameBit}`,
1230
+ rows
778
1231
  };
779
1232
  }
1233
+ function opnsCopy(p1satIntent, isTransferHeuristic) {
1234
+ switch (p1satIntent) {
1235
+ case "opns.register":
1236
+ return { title: "Publish name", verb: "publish" };
1237
+ case "opns.deregister":
1238
+ return { title: "Unpublish name", verb: "unpublish" };
1239
+ case "opns.list":
1240
+ return { title: "List name for sale", verb: "list" };
1241
+ case "opns.transfer":
1242
+ return { title: "Transfer name", verb: "transfer" };
1243
+ case "opns.cancel-listing":
1244
+ return { title: "Cancel listing", verb: "cancel the listing of" };
1245
+ case "opns.purchase":
1246
+ return { title: "Buy name", verb: "buy" };
1247
+ default:
1248
+ return isTransferHeuristic ? { title: "Transfer OpNS Name", verb: "transfer" } : { title: "Update OpNS Name", verb: "update" };
1249
+ }
1250
+ }
780
1251
  function summarizeUnknownTx(req, intent) {
781
1252
  const ins = intent.inputs.length;
782
1253
  const outs = intent.outputs.length;
783
1254
  return {
784
1255
  title: "Transaction Request",
785
1256
  subtitle: `${shortenOriginator(req.originator)} wants to ${req.summary.toLowerCase()}`,
786
- rows: [{ key: "Inputs / Outputs", value: `${ins} / ${outs}` }],
787
- network: networkLabel(intent.chain)
1257
+ rows: [{ key: "Inputs / Outputs", value: `${ins} / ${outs}` }]
788
1258
  };
789
1259
  }
790
- function networkLabel(chain) {
791
- return chain === "testnet" ? "BSV Testnet" : "BSV Mainnet";
792
- }
793
1260
  function shortenId(id, max = 24) {
794
1261
  if (id.length <= max)
795
1262
  return id;
package/dist/styles.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * CSS string for the OneSatPermissionPrompt component. Inlined as a style
3
3
  * tag so the host wallet doesn't have to wire up CSS imports.
4
4
  *
5
- * Colors match the design in `1sat-permissions-popups.pen`.
5
+ * Colors match `docs/plans/mockups/p1sat-permissions.pen`.
6
6
  */
7
- export declare const promptStyles = "\n.opp-root {\n --opp-bg: #ffffff;\n --opp-fg: #111827;\n --opp-muted: #6b7280;\n --opp-card-bg: #f7f8fa;\n --opp-card-border: #eceef2;\n --opp-accent: #E5A920;\n --opp-approve-bg: #E5A920;\n --opp-approve-fg: #ffffff;\n --opp-reject-bg: #ffffff;\n --opp-reject-fg: #111827;\n --opp-reject-border: #d1d5db;\n --opp-status-bg: #FFFBE6;\n --opp-status-fg: #E5A920;\n\n font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: var(--opp-bg);\n color: var(--opp-fg);\n border-radius: 16px;\n display: flex;\n flex-direction: column;\n width: 100%;\n max-width: 480px;\n min-height: 100%;\n overflow-x: hidden;\n overflow-y: auto;\n}\n\n.opp-bottom {\n margin-top: auto;\n display: flex;\n flex-direction: column;\n}\n\n.opp-root.opp-dark {\n --opp-bg: #0F1117;\n --opp-fg: #F9FAFB;\n --opp-muted: #9ca3af;\n --opp-card-bg: #1A1D27;\n --opp-card-border: #232636;\n --opp-reject-bg: #0F1117;\n --opp-reject-fg: #F9FAFB;\n --opp-reject-border: #2D3142;\n --opp-status-bg: #2A2408;\n --opp-status-fg: #E5A920;\n}\n\n.opp-body {\n padding: 24px 20px 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n align-items: center;\n}\n\n.opp-coin {\n width: 48px;\n height: 48px;\n flex-shrink: 0;\n}\n\n.opp-title {\n font-size: 16px;\n font-weight: 700;\n margin: 0;\n text-align: center;\n}\n\n.opp-subtitle {\n font-size: 12px;\n color: var(--opp-muted);\n margin: 0;\n text-align: center;\n line-height: 1.4;\n}\n\n.opp-status {\n background: var(--opp-status-bg);\n color: var(--opp-status-fg);\n padding: 4px 12px;\n border-radius: 999px;\n font-size: 11px;\n font-weight: 600;\n margin-top: 4px;\n border: 1px solid var(--opp-card-border);\n}\n\n.opp-card {\n background: var(--opp-card-bg);\n border: 1px solid var(--opp-card-border);\n border-radius: 10px;\n margin: 0 20px;\n padding: 16px;\n font-size: 13px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.opp-featured {\n display: flex;\n align-items: center;\n gap: 12px;\n background: var(--opp-card-bg);\n border: 1px solid var(--opp-card-border);\n border-radius: 10px;\n margin: 0 20px;\n padding: 16px;\n}\n\n.opp-featured-image {\n width: 80px;\n height: 80px;\n border-radius: 8px;\n object-fit: cover;\n background: rgba(0, 0, 0, 0.1);\n flex-shrink: 0;\n}\n\n.opp-featured-meta {\n display: flex;\n flex-direction: column;\n gap: 4px;\n min-width: 0;\n}\n\n.opp-featured-title {\n font-size: 14px;\n font-weight: 600;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.opp-featured-subtitle {\n font-size: 12px;\n color: var(--opp-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.opp-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n gap: 12px;\n}\n\n.opp-row-key {\n color: var(--opp-muted);\n}\n\n.opp-row-value {\n font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, monospace;\n font-size: 13px;\n font-weight: 500;\n text-align: right;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n min-width: 0;\n max-width: 60%;\n}\n\n.opp-meta {\n display: flex;\n justify-content: space-between;\n padding: 12px 20px;\n font-size: 12px;\n color: var(--opp-muted);\n}\n\n.opp-meta-value {\n color: var(--opp-fg);\n font-weight: 500;\n}\n\n.opp-actions {\n display: flex;\n gap: 12px;\n padding: 20px 20px 12px;\n}\n\n.opp-button {\n flex: 1;\n padding: 0 16px;\n height: 48px;\n border-radius: 10px;\n font-size: 15px;\n font-weight: 600;\n cursor: pointer;\n border: 1px solid transparent;\n transition: opacity 120ms ease;\n}\n\n.opp-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.opp-button-reject {\n background: var(--opp-reject-bg);\n color: var(--opp-reject-fg);\n border-color: var(--opp-reject-border);\n}\n\n.opp-button-approve {\n background: var(--opp-approve-bg);\n color: var(--opp-approve-fg);\n}\n\n.opp-footer {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n padding: 8px 20px 16px;\n font-size: 11px;\n font-weight: 500;\n color: var(--opp-muted);\n}\n";
7
+ export declare const promptStyles = "\n.opp-root {\n --opp-bg: #ffffff;\n --opp-fg: #111827;\n --opp-muted: #6b7280;\n --opp-card-bg: #f7f8fa;\n --opp-card-border: #eceef2;\n --opp-accent: #E5A920;\n --opp-approve-bg: #E5A920;\n --opp-approve-fg: #ffffff;\n --opp-reject-bg: #ffffff;\n --opp-reject-fg: #111827;\n --opp-reject-border: #d1d5db;\n --opp-status-bg: #FFFBE6;\n --opp-status-fg: #E5A920;\n --opp-trust-ok-bg: #ECFDF5;\n --opp-trust-ok-fg: #059669;\n --opp-trust-warn-bg: #FFFBEB;\n --opp-trust-warn-fg: #D97706;\n --opp-trust-bad-bg: #FEF2F2;\n --opp-trust-bad-fg: #DC2626;\n\n font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: var(--opp-bg);\n color: var(--opp-fg);\n border-radius: 16px;\n display: flex;\n flex-direction: column;\n width: 100%;\n max-width: 480px;\n min-height: 100%;\n overflow-x: hidden;\n overflow-y: auto;\n}\n\n.opp-bottom {\n margin-top: auto;\n display: flex;\n flex-direction: column;\n}\n\n.opp-root.opp-dark {\n --opp-bg: #0F1117;\n --opp-fg: #F9FAFB;\n --opp-muted: #9ca3af;\n --opp-card-bg: #1A1D27;\n --opp-card-border: #232636;\n --opp-reject-bg: #0F1117;\n --opp-reject-fg: #F9FAFB;\n --opp-reject-border: #2D3142;\n --opp-status-bg: #2A2408;\n --opp-status-fg: #E5A920;\n --opp-trust-ok-bg: #0A2E1F;\n --opp-trust-ok-fg: #34D399;\n --opp-trust-warn-bg: #2A2008;\n --opp-trust-warn-fg: #FBBF24;\n --opp-trust-bad-bg: #2A1215;\n --opp-trust-bad-fg: #F87171;\n}\n\n.opp-body {\n padding: 24px 20px 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n align-items: center;\n}\n\n.opp-coin {\n width: 48px;\n height: 48px;\n flex-shrink: 0;\n}\n\n.opp-title {\n font-size: 16px;\n font-weight: 700;\n margin: 0;\n text-align: center;\n}\n\n.opp-subtitle {\n font-size: 12px;\n color: var(--opp-muted);\n margin: 0;\n text-align: center;\n line-height: 1.4;\n}\n\n.opp-status {\n background: var(--opp-status-bg);\n color: var(--opp-status-fg);\n padding: 4px 12px;\n border-radius: 999px;\n font-size: 11px;\n font-weight: 600;\n margin-top: 4px;\n border: 1px solid var(--opp-card-border);\n}\n\n.opp-card {\n background: var(--opp-card-bg);\n border: 1px solid var(--opp-card-border);\n border-radius: 10px;\n margin: 0 20px;\n padding: 16px;\n font-size: 13px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.opp-featured {\n display: flex;\n align-items: center;\n gap: 12px;\n background: var(--opp-card-bg);\n border: 1px solid var(--opp-card-border);\n border-radius: 10px;\n margin: 0 20px 8px;\n padding: 16px;\n}\n\n.opp-featured-image {\n width: 80px;\n height: 80px;\n border-radius: 8px;\n object-fit: cover;\n background: rgba(0, 0, 0, 0.08);\n flex-shrink: 0;\n}\n\n.opp-featured-image-token {\n width: 48px;\n height: 48px;\n border-radius: 999px;\n}\n\n.opp-featured-placeholder {\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--opp-muted);\n font-size: 18px;\n}\n\n.opp-featured-meta {\n display: flex;\n flex-direction: column;\n gap: 4px;\n min-width: 0;\n flex: 1;\n}\n\n.opp-featured-title {\n font-size: 14px;\n font-weight: 600;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.opp-featured-subtitle {\n font-size: 12px;\n color: var(--opp-muted);\n display: flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n}\n\n.opp-featured-subtitle-text {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n min-width: 0;\n font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, monospace;\n}\n\n.opp-trust-wrap {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin: 0 20px 8px;\n}\n\n.opp-trust {\n display: inline-flex;\n align-self: flex-start;\n padding: 3px 8px;\n border-radius: 999px;\n font-size: 10px;\n font-weight: 600;\n}\n\n.opp-trust-verified {\n background: var(--opp-trust-ok-bg);\n color: var(--opp-trust-ok-fg);\n}\n\n.opp-trust-unverified {\n background: var(--opp-trust-warn-bg);\n color: var(--opp-trust-warn-fg);\n}\n\n.opp-trust-mismatch {\n background: var(--opp-trust-bad-bg);\n color: var(--opp-trust-bad-fg);\n}\n\n.opp-trust-note {\n padding: 10px;\n border-radius: 8px;\n font-size: 11px;\n line-height: 1.35;\n}\n\n.opp-trust-note-verified {\n background: var(--opp-trust-ok-bg);\n color: var(--opp-trust-ok-fg);\n}\n\n.opp-trust-note-unverified {\n background: var(--opp-trust-warn-bg);\n color: var(--opp-trust-warn-fg);\n}\n\n.opp-trust-note-mismatch {\n background: var(--opp-trust-bad-bg);\n color: var(--opp-trust-bad-fg);\n}\n\n.opp-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n gap: 12px;\n}\n\n.opp-row-key {\n color: var(--opp-muted);\n flex-shrink: 0;\n}\n\n.opp-row-value-wrap {\n display: flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n max-width: 70%;\n justify-content: flex-end;\n}\n\n.opp-row-value {\n font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, monospace;\n font-size: 12px;\n font-weight: 500;\n text-align: right;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n min-width: 0;\n}\n\n.opp-copy {\n flex-shrink: 0;\n width: 22px;\n height: 22px;\n padding: 0;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n border: 1px solid var(--opp-reject-border);\n background: var(--opp-bg);\n color: var(--opp-fg);\n cursor: pointer;\n}\n\n.opp-copy:hover {\n border-color: var(--opp-accent);\n color: var(--opp-accent);\n}\n\n.opp-fee-note {\n font-size: 11px;\n color: var(--opp-muted);\n line-height: 1.3;\n margin-top: -4px;\n}\n\n.opp-actions {\n display: flex;\n gap: 12px;\n padding: 20px 20px 12px;\n}\n\n.opp-button {\n flex: 1;\n padding: 0 16px;\n height: 48px;\n border-radius: 10px;\n font-size: 15px;\n font-weight: 600;\n cursor: pointer;\n border: 1px solid transparent;\n transition: opacity 120ms ease;\n}\n\n.opp-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.opp-button-reject {\n background: var(--opp-reject-bg);\n color: var(--opp-reject-fg);\n border-color: var(--opp-reject-border);\n}\n\n.opp-button-approve {\n background: var(--opp-approve-bg);\n color: var(--opp-approve-fg);\n}\n\n.opp-footer {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n padding: 8px 20px 16px;\n font-size: 11px;\n font-weight: 500;\n color: var(--opp-muted);\n}\n";
8
8
  //# sourceMappingURL=styles.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,YAAY,0nIA+NxB,CAAA"}
1
+ {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,YAAY,g3MA+UxB,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@1sat/permission-module-ui",
3
- "version": "0.0.38",
3
+ "version": "0.0.40",
4
4
  "description": "React component for the 1Sat permission module's prompt UX",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -28,8 +28,8 @@
28
28
  ],
29
29
  "license": "MIT",
30
30
  "dependencies": {
31
- "@1sat/permission-module": "0.0.42",
32
- "@1sat/types": "0.0.37"
31
+ "@1sat/permission-module": "0.0.44",
32
+ "@1sat/types": "0.0.38"
33
33
  },
34
34
  "peerDependencies": {
35
35
  "react": "^18.0.0 || ^19.0.0"