@tangle-network/blueprint-ui 0.1.2 → 0.3.0
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.
- package/dist/{registry-JhwB9BPD.d.ts → BlueprintHostPanel-L1KKLNbr.d.ts} +38 -1
- package/dist/{chunk-A6PJT5YQ.js → chunk-5PCH2RJF.js} +370 -10
- package/dist/chunk-5PCH2RJF.js.map +1 -0
- package/dist/components.d.ts +2 -2
- package/dist/components.js +18 -15
- package/dist/components.js.map +1 -1
- package/dist/index.d.ts +142 -8
- package/dist/index.js +19 -21
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -0
- package/dist/wallet/index.d.ts +188 -0
- package/dist/wallet/index.js +466 -0
- package/dist/wallet/index.js.map +1 -0
- package/package.json +16 -15
- package/src/components/forms/JobExecutionDialog.tsx +10 -2
- package/src/contracts/abi.ts +3 -0
- package/src/hooks/useJobPrice.test.ts +214 -0
- package/src/hooks/useJobPrice.ts +56 -2
- package/src/hooks/useQuotes.ts +44 -1
- package/src/test-setup.ts +1 -0
- package/src/wallet/detectParentOrigin.ts +74 -0
- package/src/wallet/index.ts +67 -0
- package/src/wallet/parentBridgeConnector.ts +156 -0
- package/src/wallet/parentBridgeProtocol.ts +109 -0
- package/src/wallet/parentBridgeProvider.test.ts +209 -0
- package/src/wallet/parentBridgeProvider.ts +411 -0
- package/tsconfig.json +1 -1
- package/dist/BlueprintHostPanel-6iVEh-f1.d.ts +0 -39
- package/dist/chunk-A6PJT5YQ.js.map +0 -1
- package/dist/chunk-GD3AZEJL.js +0 -327
- package/dist/chunk-GD3AZEJL.js.map +0 -1
- package/dist/host.d.ts +0 -96
- package/dist/host.js +0 -39
- package/dist/host.js.map +0 -1
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { Address } from 'viem';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import * as class_variance_authority_types from 'class-variance-authority/types';
|
|
5
|
+
import { VariantProps } from 'class-variance-authority';
|
|
2
6
|
|
|
3
7
|
/**
|
|
4
8
|
* Blueprint Registry — defines the metadata layer for Tangle blueprints.
|
|
@@ -84,4 +88,37 @@ declare function getAllBlueprints(): BlueprintDefinition[];
|
|
|
84
88
|
declare function getBlueprintJobs(blueprintId: string, category?: JobCategory): JobDefinition[];
|
|
85
89
|
declare function getJobById(blueprintId: string, jobId: number): JobDefinition | undefined;
|
|
86
90
|
|
|
87
|
-
|
|
91
|
+
declare const buttonVariants: (props?: ({
|
|
92
|
+
variant?: "default" | "link" | "success" | "secondary" | "destructive" | "outline" | "ghost" | null | undefined;
|
|
93
|
+
size?: "default" | "sm" | "lg" | "icon" | "icon-sm" | null | undefined;
|
|
94
|
+
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
95
|
+
declare function Button({ className, variant, size, asChild, ...props }: React.ComponentProps<'button'> & VariantProps<typeof buttonVariants> & {
|
|
96
|
+
asChild?: boolean;
|
|
97
|
+
}): react_jsx_runtime.JSX.Element;
|
|
98
|
+
|
|
99
|
+
type Action = {
|
|
100
|
+
label: string;
|
|
101
|
+
href?: string;
|
|
102
|
+
onClick?: () => void;
|
|
103
|
+
variant?: React.ComponentProps<typeof Button>['variant'];
|
|
104
|
+
disabled?: boolean;
|
|
105
|
+
};
|
|
106
|
+
type BlueprintHostHeroProps = {
|
|
107
|
+
title: string;
|
|
108
|
+
tagline?: string;
|
|
109
|
+
description?: string;
|
|
110
|
+
badges?: string[];
|
|
111
|
+
actions?: Action[];
|
|
112
|
+
children?: React.ReactNode;
|
|
113
|
+
className?: string;
|
|
114
|
+
};
|
|
115
|
+
declare function BlueprintHostHero({ title, tagline, description, badges, actions, children, className, }: BlueprintHostHeroProps): react_jsx_runtime.JSX.Element;
|
|
116
|
+
|
|
117
|
+
type BlueprintHostPanelProps = {
|
|
118
|
+
title: string;
|
|
119
|
+
children: React.ReactNode;
|
|
120
|
+
className?: string;
|
|
121
|
+
};
|
|
122
|
+
declare function BlueprintHostPanel({ title, children, className, }: BlueprintHostPanelProps): react_jsx_runtime.JSX.Element;
|
|
123
|
+
|
|
124
|
+
export { type AbiContextParam as A, type BlueprintDefinition as B, type JobDefinition as J, BlueprintHostHero as a, type BlueprintHostHeroProps as b, BlueprintHostPanel as c, type BlueprintHostPanelProps as d, type JobCategory as e, type JobFieldDef as f, getAllBlueprints as g, getBlueprint as h, getBlueprintJobs as i, getJobById as j, Button as k, buttonVariants as l, registerBlueprint as r };
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
// src/utils.ts
|
|
2
|
+
import { clsx } from "clsx";
|
|
3
|
+
import { twMerge } from "tailwind-merge";
|
|
4
|
+
function cn(...inputs) {
|
|
5
|
+
return twMerge(clsx(inputs));
|
|
6
|
+
}
|
|
7
|
+
|
|
1
8
|
// src/utils/resolveOperatorRpc.ts
|
|
2
9
|
function resolveOperatorRpc(raw) {
|
|
3
10
|
if (typeof window === "undefined") return raw;
|
|
@@ -305,6 +312,9 @@ var tangleServicesAbi = [
|
|
|
305
312
|
name: "details",
|
|
306
313
|
type: "tuple",
|
|
307
314
|
components: [
|
|
315
|
+
// tnt-core v0.13.0: `requester` is the first field of QuoteDetails.
|
|
316
|
+
// The contract enforces `requester == msg.sender` and rejects address(0).
|
|
317
|
+
{ name: "requester", type: "address" },
|
|
308
318
|
{ name: "blueprintId", type: "uint64" },
|
|
309
319
|
{ name: "ttlBlocks", type: "uint64" },
|
|
310
320
|
{ name: "totalCost", type: "uint256" },
|
|
@@ -595,6 +605,295 @@ function coerceValue(value, abiType) {
|
|
|
595
605
|
}
|
|
596
606
|
}
|
|
597
607
|
|
|
608
|
+
// src/host/resolver.ts
|
|
609
|
+
var EXPERIENCE_TIER_LABELS = {
|
|
610
|
+
generic: "Protocol fallback",
|
|
611
|
+
declarative: "Declarative blueprint UI",
|
|
612
|
+
"curated-module": "Curated app module",
|
|
613
|
+
"external-app": "External app handoff"
|
|
614
|
+
};
|
|
615
|
+
var SLUG_POLICY_LABELS = {
|
|
616
|
+
reserved: "Reserved slug",
|
|
617
|
+
"publisher-scoped": "Publisher-scoped slug",
|
|
618
|
+
"public-requested": "Public requested slug"
|
|
619
|
+
};
|
|
620
|
+
var SURFACE_LABELS = {
|
|
621
|
+
"generic-overview": "Generic overview",
|
|
622
|
+
"service-explorer": "Service explorer",
|
|
623
|
+
"service-console": "Service console",
|
|
624
|
+
"actions-panel": "Actions panel",
|
|
625
|
+
resources: "Resources",
|
|
626
|
+
chat: "Chat",
|
|
627
|
+
vaults: "Vaults",
|
|
628
|
+
metrics: "Metrics",
|
|
629
|
+
permissions: "Permissions"
|
|
630
|
+
};
|
|
631
|
+
var PUBLISHER_VERIFICATION_LABELS = {
|
|
632
|
+
"first-party": "First-party publisher",
|
|
633
|
+
verified: "Verified publisher",
|
|
634
|
+
unverified: "Unverified publisher"
|
|
635
|
+
};
|
|
636
|
+
var EXTERNAL_APP_TRUST_LABELS = {
|
|
637
|
+
trusted: "Trusted external app",
|
|
638
|
+
restricted: "Restricted external app"
|
|
639
|
+
};
|
|
640
|
+
function buildCanonicalBlueprintSlug(entry) {
|
|
641
|
+
if (entry.canonicalSlug) {
|
|
642
|
+
return entry.canonicalSlug;
|
|
643
|
+
}
|
|
644
|
+
if (entry.slugPolicy === "reserved" || !entry.publisher.namespace) {
|
|
645
|
+
return entry.slug;
|
|
646
|
+
}
|
|
647
|
+
return `@${entry.publisher.namespace}/${entry.slug}`;
|
|
648
|
+
}
|
|
649
|
+
function resolveBlueprintAppView(entry) {
|
|
650
|
+
return {
|
|
651
|
+
slug: entry.slug,
|
|
652
|
+
canonicalSlug: buildCanonicalBlueprintSlug(entry),
|
|
653
|
+
blueprintId: entry.blueprintId,
|
|
654
|
+
publisher: entry.publisher,
|
|
655
|
+
tier: entry.tier,
|
|
656
|
+
slugPolicy: entry.slugPolicy,
|
|
657
|
+
manifest: entry.manifest,
|
|
658
|
+
module: entry.module,
|
|
659
|
+
fallbackEnabled: true
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
function toBlueprintAppEntry(view) {
|
|
663
|
+
return {
|
|
664
|
+
slug: view.slug,
|
|
665
|
+
canonicalSlug: view.canonicalSlug,
|
|
666
|
+
blueprintId: view.blueprintId,
|
|
667
|
+
publisher: view.publisher,
|
|
668
|
+
tier: view.tier,
|
|
669
|
+
slugPolicy: view.slugPolicy,
|
|
670
|
+
manifest: view.manifest,
|
|
671
|
+
module: view.module
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
function getBlueprintExperienceTierLabel(tier) {
|
|
675
|
+
return EXPERIENCE_TIER_LABELS[tier];
|
|
676
|
+
}
|
|
677
|
+
function getBlueprintSlugPolicyLabel(policy) {
|
|
678
|
+
return SLUG_POLICY_LABELS[policy];
|
|
679
|
+
}
|
|
680
|
+
function getBlueprintSurfaceLabel(surface) {
|
|
681
|
+
return SURFACE_LABELS[surface];
|
|
682
|
+
}
|
|
683
|
+
function getBlueprintPublisherVerificationLabel(verification) {
|
|
684
|
+
return PUBLISHER_VERIFICATION_LABELS[verification];
|
|
685
|
+
}
|
|
686
|
+
function getExternalAppTrustLabel(trust) {
|
|
687
|
+
return EXTERNAL_APP_TRUST_LABELS[trust];
|
|
688
|
+
}
|
|
689
|
+
function isVerifiedBlueprintPublisher(publisher) {
|
|
690
|
+
return publisher.verification === "first-party" || publisher.verification === "verified";
|
|
691
|
+
}
|
|
692
|
+
function canPublisherClaimSlug(slug, publisher, reservedSlugs = /* @__PURE__ */ new Set()) {
|
|
693
|
+
if (reservedSlugs.has(slug)) {
|
|
694
|
+
return false;
|
|
695
|
+
}
|
|
696
|
+
return publisher?.namespace !== void 0 && publisher.namespace.trim().length > 0 && (publisher.verification === "verified" || publisher.verification === "first-party");
|
|
697
|
+
}
|
|
698
|
+
function isTrustedExternalAppHost(host, trustedHosts = []) {
|
|
699
|
+
const normalizedHost = host.trim().toLowerCase();
|
|
700
|
+
return trustedHosts.some(
|
|
701
|
+
(trustedHost) => normalizedHost === trustedHost || normalizedHost.endsWith(`.${trustedHost}`)
|
|
702
|
+
);
|
|
703
|
+
}
|
|
704
|
+
function getBlueprintPath(view) {
|
|
705
|
+
if (view.tier === "curated-module" || view.tier === "external-app") {
|
|
706
|
+
return `/blueprints/${view.canonicalSlug}`;
|
|
707
|
+
}
|
|
708
|
+
if (view.blueprintId !== void 0) {
|
|
709
|
+
return `/blueprints/${view.blueprintId.toString()}`;
|
|
710
|
+
}
|
|
711
|
+
return `/blueprints/${view.slug}`;
|
|
712
|
+
}
|
|
713
|
+
function getBlueprintServicePath(view, serviceId) {
|
|
714
|
+
if (view.tier === "curated-module" || view.tier === "external-app") {
|
|
715
|
+
return `${getBlueprintPath(view)}/${serviceId}`;
|
|
716
|
+
}
|
|
717
|
+
return `${getBlueprintPath(view)}/services/${serviceId}`;
|
|
718
|
+
}
|
|
719
|
+
function sanitizeBlueprintSlugPart(value) {
|
|
720
|
+
return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").replace(/-{2,}/g, "-");
|
|
721
|
+
}
|
|
722
|
+
function deriveBlueprintRequestedSlug(blueprint) {
|
|
723
|
+
const fromName = sanitizeBlueprintSlugPart(blueprint.name);
|
|
724
|
+
if (fromName.length > 0) {
|
|
725
|
+
return fromName;
|
|
726
|
+
}
|
|
727
|
+
const fromAuthor = sanitizeBlueprintSlugPart(blueprint.author);
|
|
728
|
+
if (fromAuthor.length > 0) {
|
|
729
|
+
return `${fromAuthor}-${blueprint.id.toString()}`;
|
|
730
|
+
}
|
|
731
|
+
return `blueprint-${blueprint.id.toString()}`;
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
// src/components/ui/card.tsx
|
|
735
|
+
import { jsx } from "react/jsx-runtime";
|
|
736
|
+
function Card({ className, ...props }) {
|
|
737
|
+
return /* @__PURE__ */ jsx(
|
|
738
|
+
"div",
|
|
739
|
+
{
|
|
740
|
+
"data-slot": "card",
|
|
741
|
+
className: cn("glass-card rounded-xl text-bp-elements-textPrimary", className),
|
|
742
|
+
...props
|
|
743
|
+
}
|
|
744
|
+
);
|
|
745
|
+
}
|
|
746
|
+
function CardHeader({ className, ...props }) {
|
|
747
|
+
return /* @__PURE__ */ jsx("div", { "data-slot": "card-header", className: cn("flex flex-col gap-1.5 p-6", className), ...props });
|
|
748
|
+
}
|
|
749
|
+
function CardTitle({ className, ...props }) {
|
|
750
|
+
return /* @__PURE__ */ jsx("div", { "data-slot": "card-title", className: cn("leading-none font-semibold font-display", className), ...props });
|
|
751
|
+
}
|
|
752
|
+
function CardDescription({ className, ...props }) {
|
|
753
|
+
return /* @__PURE__ */ jsx("div", { "data-slot": "card-description", className: cn("text-bp-elements-textSecondary text-sm", className), ...props });
|
|
754
|
+
}
|
|
755
|
+
function CardContent({ className, ...props }) {
|
|
756
|
+
return /* @__PURE__ */ jsx("div", { "data-slot": "card-content", className: cn("px-6 pb-6", className), ...props });
|
|
757
|
+
}
|
|
758
|
+
function CardFooter({ className, ...props }) {
|
|
759
|
+
return /* @__PURE__ */ jsx("div", { "data-slot": "card-footer", className: cn("flex items-center px-6 pb-6", className), ...props });
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
// src/components/ui/badge.tsx
|
|
763
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
764
|
+
import { cva } from "class-variance-authority";
|
|
765
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
766
|
+
var badgeVariants = cva(
|
|
767
|
+
"inline-flex items-center justify-center rounded-md border px-2.5 py-0.5 text-xs font-semibold font-data uppercase tracking-wider w-fit whitespace-nowrap shrink-0 gap-1 transition-colors",
|
|
768
|
+
{
|
|
769
|
+
variants: {
|
|
770
|
+
variant: {
|
|
771
|
+
default: "border-bp-elements-borderColor bg-bp-elements-background-depth-3 text-bp-elements-textPrimary",
|
|
772
|
+
secondary: "border-bp-elements-dividerColor bg-bp-elements-background-depth-2 text-bp-elements-textSecondary",
|
|
773
|
+
destructive: "border-crimson-500/20 bg-crimson-500/10 text-bp-elements-icon-error",
|
|
774
|
+
success: "border-teal-500/20 bg-teal-500/10 text-bp-elements-icon-success",
|
|
775
|
+
outline: "text-bp-elements-textPrimary border-bp-elements-borderColor bg-transparent",
|
|
776
|
+
accent: "border-violet-500/20 bg-violet-500/10 text-violet-700 dark:text-violet-400",
|
|
777
|
+
amber: "border-amber-500/20 bg-amber-500/10 text-amber-700 dark:text-amber-400",
|
|
778
|
+
running: "border-teal-500/20 bg-teal-500/10 text-teal-600 dark:text-teal-400",
|
|
779
|
+
stopped: "border-amber-500/20 bg-amber-500/10 text-amber-600 dark:text-amber-400",
|
|
780
|
+
cold: "border-blue-500/20 bg-blue-500/10 text-blue-600 dark:text-blue-400"
|
|
781
|
+
}
|
|
782
|
+
},
|
|
783
|
+
defaultVariants: { variant: "default" }
|
|
784
|
+
}
|
|
785
|
+
);
|
|
786
|
+
function Badge({
|
|
787
|
+
className,
|
|
788
|
+
variant,
|
|
789
|
+
asChild = false,
|
|
790
|
+
...props
|
|
791
|
+
}) {
|
|
792
|
+
const Comp = asChild ? Slot : "span";
|
|
793
|
+
return /* @__PURE__ */ jsx2(Comp, { "data-slot": "badge", className: cn(badgeVariants({ variant }), className), ...props });
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
// src/components/ui/button.tsx
|
|
797
|
+
import { Slot as Slot2 } from "@radix-ui/react-slot";
|
|
798
|
+
import { cva as cva2 } from "class-variance-authority";
|
|
799
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
800
|
+
var buttonVariants = cva2(
|
|
801
|
+
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lg text-sm font-medium font-display transition-all duration-200 disabled:pointer-events-none disabled:opacity-40 [&_svg]:pointer-events-none [&_svg:not([class*="size-"])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:ring-2 focus-visible:ring-violet-400/50 focus-visible:ring-offset-2 focus-visible:ring-offset-bp-elements-background-depth-1',
|
|
802
|
+
{
|
|
803
|
+
variants: {
|
|
804
|
+
variant: {
|
|
805
|
+
default: "bg-violet-600 text-white font-semibold hover:bg-violet-500 shadow-[0_0_20px_rgba(142,89,255,0.25)] hover:shadow-[0_0_30px_rgba(142,89,255,0.35)]",
|
|
806
|
+
destructive: "bg-crimson-500/15 text-crimson-400 border border-crimson-500/20 hover:bg-crimson-500/25 hover:border-crimson-500/30",
|
|
807
|
+
outline: "glass glass-hover text-bp-elements-textPrimary",
|
|
808
|
+
secondary: "bg-bp-elements-background-depth-3 text-bp-elements-textSecondary border border-bp-elements-borderColor hover:bg-bp-elements-background-depth-4 hover:text-bp-elements-textPrimary",
|
|
809
|
+
ghost: "text-bp-elements-textSecondary hover:text-bp-elements-textPrimary hover:bg-bp-elements-item-backgroundHover",
|
|
810
|
+
link: "text-violet-700 dark:text-violet-400 underline-offset-4 hover:underline",
|
|
811
|
+
success: "bg-teal-600/15 text-teal-400 border border-teal-500/20 hover:bg-teal-600/25"
|
|
812
|
+
},
|
|
813
|
+
size: {
|
|
814
|
+
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
815
|
+
sm: "h-8 rounded-md gap-1.5 px-3 text-xs has-[>svg]:px-2.5",
|
|
816
|
+
lg: "h-11 rounded-xl px-7 text-base has-[>svg]:px-5",
|
|
817
|
+
icon: "size-9",
|
|
818
|
+
"icon-sm": "size-8"
|
|
819
|
+
}
|
|
820
|
+
},
|
|
821
|
+
defaultVariants: {
|
|
822
|
+
variant: "default",
|
|
823
|
+
size: "default"
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
);
|
|
827
|
+
function Button({
|
|
828
|
+
className,
|
|
829
|
+
variant = "default",
|
|
830
|
+
size = "default",
|
|
831
|
+
asChild = false,
|
|
832
|
+
...props
|
|
833
|
+
}) {
|
|
834
|
+
const Comp = asChild ? Slot2 : "button";
|
|
835
|
+
return /* @__PURE__ */ jsx3(
|
|
836
|
+
Comp,
|
|
837
|
+
{
|
|
838
|
+
"data-slot": "button",
|
|
839
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
840
|
+
...props
|
|
841
|
+
}
|
|
842
|
+
);
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
// src/host/components/BlueprintHostHero.tsx
|
|
846
|
+
import { jsx as jsx4, jsxs } from "react/jsx-runtime";
|
|
847
|
+
function BlueprintHostHero({
|
|
848
|
+
title,
|
|
849
|
+
tagline,
|
|
850
|
+
description,
|
|
851
|
+
badges = [],
|
|
852
|
+
actions = [],
|
|
853
|
+
children,
|
|
854
|
+
className
|
|
855
|
+
}) {
|
|
856
|
+
return /* @__PURE__ */ jsxs(Card, { className: cn("rounded-3xl border-bp-elements-borderColor/70 bg-bp-elements-background-depth-2", className), children: [
|
|
857
|
+
/* @__PURE__ */ jsxs(CardHeader, { className: "space-y-4", children: [
|
|
858
|
+
badges.length > 0 ? /* @__PURE__ */ jsx4("div", { className: "flex flex-wrap gap-2", children: badges.map((badge) => /* @__PURE__ */ jsx4(Badge, { variant: "secondary", children: badge }, badge)) }) : null,
|
|
859
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
860
|
+
/* @__PURE__ */ jsx4(CardTitle, { className: "text-3xl", children: title }),
|
|
861
|
+
tagline ? /* @__PURE__ */ jsx4(CardDescription, { className: "text-base text-bp-elements-textPrimary/80", children: tagline }) : null
|
|
862
|
+
] }),
|
|
863
|
+
description ? /* @__PURE__ */ jsx4("p", { className: "max-w-3xl text-sm leading-6 text-bp-elements-textSecondary", children: description }) : null
|
|
864
|
+
] }),
|
|
865
|
+
(actions.length > 0 || children) && /* @__PURE__ */ jsxs(CardContent, { className: "space-y-4", children: [
|
|
866
|
+
actions.length > 0 ? /* @__PURE__ */ jsx4("div", { className: "flex flex-wrap gap-3", children: actions.map((action) => {
|
|
867
|
+
const button = /* @__PURE__ */ jsx4(
|
|
868
|
+
Button,
|
|
869
|
+
{
|
|
870
|
+
variant: action.variant ?? "default",
|
|
871
|
+
onClick: action.onClick,
|
|
872
|
+
disabled: action.disabled,
|
|
873
|
+
children: action.label
|
|
874
|
+
},
|
|
875
|
+
action.label
|
|
876
|
+
);
|
|
877
|
+
return action.href ? /* @__PURE__ */ jsx4("a", { href: action.href, children: button }, action.label) : button;
|
|
878
|
+
}) }) : null,
|
|
879
|
+
children
|
|
880
|
+
] })
|
|
881
|
+
] });
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
// src/host/components/BlueprintHostPanel.tsx
|
|
885
|
+
import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
886
|
+
function BlueprintHostPanel({
|
|
887
|
+
title,
|
|
888
|
+
children,
|
|
889
|
+
className
|
|
890
|
+
}) {
|
|
891
|
+
return /* @__PURE__ */ jsxs2(Card, { className: cn("rounded-3xl border-bp-elements-borderColor/70 bg-bp-elements-background-depth-2", className), children: [
|
|
892
|
+
/* @__PURE__ */ jsx5(CardHeader, { children: /* @__PURE__ */ jsx5(CardTitle, { className: "text-xl", children: title }) }),
|
|
893
|
+
/* @__PURE__ */ jsx5(CardContent, { children })
|
|
894
|
+
] });
|
|
895
|
+
}
|
|
896
|
+
|
|
598
897
|
// src/hooks/useJobForm.ts
|
|
599
898
|
import { useState, useCallback, useEffect, useMemo } from "react";
|
|
600
899
|
function buildDefaults(job) {
|
|
@@ -754,7 +1053,13 @@ function mapJsonResourceCommitment(resource) {
|
|
|
754
1053
|
count: BigInt(resource.count ?? 0)
|
|
755
1054
|
};
|
|
756
1055
|
}
|
|
757
|
-
|
|
1056
|
+
var ZERO_ADDRESS_LOWER = ZERO_ADDRESS.toLowerCase();
|
|
1057
|
+
function useQuotes(operators, blueprintId, ttlBlocks, enabled, requester, requireTee = false) {
|
|
1058
|
+
if (enabled && (!requester || requester.toLowerCase() === ZERO_ADDRESS_LOWER)) {
|
|
1059
|
+
throw new Error(
|
|
1060
|
+
"useQuotes: `requester` is required and must be a non-zero address when `enabled=true`. Pass `useAccount().address` from wagmi. tnt-core v0.13.0 contracts reject quotes whose requester is address(0) or != msg.sender."
|
|
1061
|
+
);
|
|
1062
|
+
}
|
|
758
1063
|
const [quotes, setQuotes] = useState2([]);
|
|
759
1064
|
const [isLoading, setIsLoading] = useState2(false);
|
|
760
1065
|
const [isSolvingPow, setIsSolvingPow] = useState2(false);
|
|
@@ -788,7 +1093,8 @@ function useQuotes(operators, blueprintId, ttlBlocks, enabled, requireTee = fals
|
|
|
788
1093
|
ttlBlocks,
|
|
789
1094
|
proofOfWork: proof,
|
|
790
1095
|
challengeTimestamp: timestamp,
|
|
791
|
-
requireTee
|
|
1096
|
+
requireTee,
|
|
1097
|
+
requester
|
|
792
1098
|
});
|
|
793
1099
|
if (!response) throw new Error("No quote returned from operator");
|
|
794
1100
|
if (!cancelled) results.push(response);
|
|
@@ -810,7 +1116,7 @@ function useQuotes(operators, blueprintId, ttlBlocks, enabled, requireTee = fals
|
|
|
810
1116
|
return () => {
|
|
811
1117
|
cancelled = true;
|
|
812
1118
|
};
|
|
813
|
-
}, [operators, blueprintId, ttlBlocks, enabled, fetchKey, requireTee]);
|
|
1119
|
+
}, [operators, blueprintId, ttlBlocks, enabled, fetchKey, requireTee, requester]);
|
|
814
1120
|
const totalCost = quotes.reduce((sum, q) => sum + q.totalCost, 0n);
|
|
815
1121
|
return { quotes, isLoading, isSolvingPow, errors, totalCost, refetch };
|
|
816
1122
|
}
|
|
@@ -825,6 +1131,10 @@ async function fetchPriceFromOperator(rpcUrl2, params) {
|
|
|
825
1131
|
proof_of_work: toHex(params.proofOfWork),
|
|
826
1132
|
challenge_timestamp: String(params.challengeTimestamp),
|
|
827
1133
|
require_tee: params.requireTee,
|
|
1134
|
+
// tnt-core v0.13.0: bind the quote to the future caller. Operators
|
|
1135
|
+
// sign this address into QuoteDetails; the contract enforces
|
|
1136
|
+
// `requester == msg.sender`.
|
|
1137
|
+
requester: params.requester,
|
|
828
1138
|
resource_requirements: DEFAULT_RESOURCE_REQUIREMENTS
|
|
829
1139
|
}),
|
|
830
1140
|
signal: AbortSignal.timeout(1e4)
|
|
@@ -839,6 +1149,10 @@ async function fetchPriceFromOperator(rpcUrl2, params) {
|
|
|
839
1149
|
teeAttested: Boolean(data.tee_attested),
|
|
840
1150
|
teeProvider: data.tee_provider || void 0,
|
|
841
1151
|
details: {
|
|
1152
|
+
// Prefer the operator-signed value; fall back to the hook's input.
|
|
1153
|
+
// If the operator returns a mismatched requester the contract will
|
|
1154
|
+
// revert at submission, so callers should still verify equality.
|
|
1155
|
+
requester: data.details?.requester ?? params.requester,
|
|
842
1156
|
blueprintId: BigInt(data.details?.blueprint_id ?? params.blueprintId),
|
|
843
1157
|
ttlBlocks: BigInt(data.details?.ttl_blocks ?? params.ttlBlocks),
|
|
844
1158
|
totalCost: BigInt(data.details?.total_cost ?? "0"),
|
|
@@ -872,7 +1186,17 @@ function resolveOperatorRpc2(raw) {
|
|
|
872
1186
|
return withProto;
|
|
873
1187
|
}
|
|
874
1188
|
}
|
|
875
|
-
|
|
1189
|
+
var ZERO_ADDRESS_LOWER2 = "0x0000000000000000000000000000000000000000";
|
|
1190
|
+
function assertRequester(requester, hookName, enabled) {
|
|
1191
|
+
if (!enabled) return;
|
|
1192
|
+
if (!requester || requester.toLowerCase() === ZERO_ADDRESS_LOWER2) {
|
|
1193
|
+
throw new Error(
|
|
1194
|
+
`${hookName}: \`requester\` is required and must be a non-zero address when \`enabled=true\`. Pass \`useAccount().address\` from wagmi. tnt-core v0.13.0 contracts reject quotes whose requester is address(0) or != msg.sender.`
|
|
1195
|
+
);
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
function useJobPrice(operatorRpcUrl, serviceId, jobIndex, blueprintId, enabled, requester) {
|
|
1199
|
+
assertRequester(requester, "useJobPrice", enabled);
|
|
876
1200
|
const [quote, setQuote] = useState3(null);
|
|
877
1201
|
const [isLoading, setIsLoading] = useState3(false);
|
|
878
1202
|
const [isSolvingPow, setIsSolvingPow] = useState3(false);
|
|
@@ -905,7 +1229,10 @@ function useJobPrice(operatorRpcUrl, serviceId, jobIndex, blueprintId, enabled)
|
|
|
905
1229
|
service_id: String(serviceId),
|
|
906
1230
|
job_index: jobIndex,
|
|
907
1231
|
proof_of_work: toHex2(proof),
|
|
908
|
-
challenge_timestamp: String(timestamp)
|
|
1232
|
+
challenge_timestamp: String(timestamp),
|
|
1233
|
+
// tnt-core v0.13.0: operators sign `requester` into JobQuoteDetails;
|
|
1234
|
+
// the contract enforces `requester == msg.sender` on submission.
|
|
1235
|
+
requester
|
|
909
1236
|
}),
|
|
910
1237
|
signal: AbortSignal.timeout(1e4)
|
|
911
1238
|
});
|
|
@@ -915,6 +1242,7 @@ function useJobPrice(operatorRpcUrl, serviceId, jobIndex, blueprintId, enabled)
|
|
|
915
1242
|
const data = await response.json();
|
|
916
1243
|
if (cancelledRef.current) return;
|
|
917
1244
|
setQuote({
|
|
1245
|
+
requester: data.requester ?? requester,
|
|
918
1246
|
serviceId: BigInt(data.service_id ?? serviceId),
|
|
919
1247
|
jobIndex: data.job_index ?? jobIndex,
|
|
920
1248
|
price: BigInt(data.price ?? "0"),
|
|
@@ -938,11 +1266,12 @@ function useJobPrice(operatorRpcUrl, serviceId, jobIndex, blueprintId, enabled)
|
|
|
938
1266
|
return () => {
|
|
939
1267
|
cancelledRef.current = true;
|
|
940
1268
|
};
|
|
941
|
-
}, [operatorRpcUrl, serviceId, jobIndex, blueprintId, enabled, fetchKey]);
|
|
1269
|
+
}, [operatorRpcUrl, serviceId, jobIndex, blueprintId, enabled, fetchKey, requester]);
|
|
942
1270
|
const formattedPrice = quote ? formatCost(quote.price) : "--";
|
|
943
1271
|
return { quote, isLoading, isSolvingPow, error, formattedPrice, refetch };
|
|
944
1272
|
}
|
|
945
|
-
function useJobPrices(operatorRpcUrl, serviceId, blueprintId, jobIndexes, enabled) {
|
|
1273
|
+
function useJobPrices(operatorRpcUrl, serviceId, blueprintId, jobIndexes, enabled, requester) {
|
|
1274
|
+
assertRequester(requester, "useJobPrices", enabled);
|
|
946
1275
|
const [prices, setPrices] = useState3([]);
|
|
947
1276
|
const [isLoading, setIsLoading] = useState3(false);
|
|
948
1277
|
const [error, setError] = useState3(null);
|
|
@@ -972,7 +1301,9 @@ function useJobPrices(operatorRpcUrl, serviceId, blueprintId, jobIndexes, enable
|
|
|
972
1301
|
service_id: String(serviceId),
|
|
973
1302
|
job_index: job.index,
|
|
974
1303
|
proof_of_work: toHex2(proof),
|
|
975
|
-
challenge_timestamp: String(timestamp)
|
|
1304
|
+
challenge_timestamp: String(timestamp),
|
|
1305
|
+
// tnt-core v0.13.0: see useJobPrice notes.
|
|
1306
|
+
requester
|
|
976
1307
|
}),
|
|
977
1308
|
signal: AbortSignal.timeout(1e4)
|
|
978
1309
|
});
|
|
@@ -993,6 +1324,7 @@ function useJobPrices(operatorRpcUrl, serviceId, blueprintId, jobIndexes, enable
|
|
|
993
1324
|
formattedPrice: formatCost(price),
|
|
994
1325
|
mode: data.mode ?? "flat",
|
|
995
1326
|
quote: {
|
|
1327
|
+
requester: data.requester ?? requester,
|
|
996
1328
|
serviceId: BigInt(data.service_id ?? serviceId),
|
|
997
1329
|
jobIndex: job.index,
|
|
998
1330
|
price,
|
|
@@ -1030,7 +1362,7 @@ function useJobPrices(operatorRpcUrl, serviceId, blueprintId, jobIndexes, enable
|
|
|
1030
1362
|
return () => {
|
|
1031
1363
|
cancelled = true;
|
|
1032
1364
|
};
|
|
1033
|
-
}, [operatorRpcUrl, serviceId, blueprintId, jobIndexes, enabled, fetchKey]);
|
|
1365
|
+
}, [operatorRpcUrl, serviceId, blueprintId, jobIndexes, enabled, fetchKey, requester]);
|
|
1034
1366
|
return { prices, isLoading, error, refetch };
|
|
1035
1367
|
}
|
|
1036
1368
|
|
|
@@ -1130,6 +1462,7 @@ function useThemeValue() {
|
|
|
1130
1462
|
}
|
|
1131
1463
|
|
|
1132
1464
|
export {
|
|
1465
|
+
cn,
|
|
1133
1466
|
resolveOperatorRpc,
|
|
1134
1467
|
getEnvVar,
|
|
1135
1468
|
mainnet,
|
|
@@ -1168,6 +1501,33 @@ export {
|
|
|
1168
1501
|
publicClient,
|
|
1169
1502
|
getAddresses,
|
|
1170
1503
|
encodeJobArgs,
|
|
1504
|
+
buildCanonicalBlueprintSlug,
|
|
1505
|
+
resolveBlueprintAppView,
|
|
1506
|
+
toBlueprintAppEntry,
|
|
1507
|
+
getBlueprintExperienceTierLabel,
|
|
1508
|
+
getBlueprintSlugPolicyLabel,
|
|
1509
|
+
getBlueprintSurfaceLabel,
|
|
1510
|
+
getBlueprintPublisherVerificationLabel,
|
|
1511
|
+
getExternalAppTrustLabel,
|
|
1512
|
+
isVerifiedBlueprintPublisher,
|
|
1513
|
+
canPublisherClaimSlug,
|
|
1514
|
+
isTrustedExternalAppHost,
|
|
1515
|
+
getBlueprintPath,
|
|
1516
|
+
getBlueprintServicePath,
|
|
1517
|
+
sanitizeBlueprintSlugPart,
|
|
1518
|
+
deriveBlueprintRequestedSlug,
|
|
1519
|
+
Card,
|
|
1520
|
+
CardHeader,
|
|
1521
|
+
CardTitle,
|
|
1522
|
+
CardDescription,
|
|
1523
|
+
CardContent,
|
|
1524
|
+
CardFooter,
|
|
1525
|
+
badgeVariants,
|
|
1526
|
+
Badge,
|
|
1527
|
+
buttonVariants,
|
|
1528
|
+
Button,
|
|
1529
|
+
BlueprintHostHero,
|
|
1530
|
+
BlueprintHostPanel,
|
|
1171
1531
|
useJobForm,
|
|
1172
1532
|
solvePoW,
|
|
1173
1533
|
formatCost,
|
|
@@ -1177,4 +1537,4 @@ export {
|
|
|
1177
1537
|
useSubmitJob,
|
|
1178
1538
|
useThemeValue
|
|
1179
1539
|
};
|
|
1180
|
-
//# sourceMappingURL=chunk-
|
|
1540
|
+
//# sourceMappingURL=chunk-5PCH2RJF.js.map
|