@dipansrimany/mlink-sdk 0.4.1 → 0.4.2

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.
@@ -2,13 +2,29 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { E as EVMTransaction, C as ChainConfig, A as ActionMetadata } from '../types-DD9rJ58Y.js';
3
3
  import React from 'react';
4
4
 
5
- type MlinkStatus = 'idle' | 'loading' | 'ready' | 'executing' | 'success' | 'error';
5
+ type MlinkStatus = 'idle' | 'loading' | 'validating' | 'ready' | 'executing' | 'success' | 'error' | 'unregistered' | 'blocked';
6
+ type RegistrationStatus = 'pending' | 'approved' | 'blocked' | null;
7
+ interface RegistrationResult {
8
+ isRegistered: boolean;
9
+ status: RegistrationStatus;
10
+ error?: string;
11
+ warning?: string;
12
+ mlink?: {
13
+ mlinkId: string;
14
+ name: string;
15
+ description: string;
16
+ icon: string;
17
+ status: RegistrationStatus;
18
+ };
19
+ }
6
20
  interface MlinkInstance {
7
21
  status: MlinkStatus;
8
22
  metadata: ActionMetadata | null;
9
23
  error: string | null;
10
24
  url: string;
11
25
  refresh: () => Promise<void>;
26
+ registration: RegistrationResult | null;
27
+ isRegistered: boolean;
12
28
  }
13
29
  interface MlinkAdapter {
14
30
  connect: () => Promise<string>;
@@ -78,6 +94,14 @@ interface MlinkProps {
78
94
  onError?: (error: string) => void;
79
95
  className?: string;
80
96
  stylePreset?: 'default' | 'compact' | 'minimal';
97
+ /** Registry URL for validation (defaults to https://mlinks-fe.vercel.app) */
98
+ registryUrl?: string;
99
+ /** Whether to require registration for the mlink to work (defaults to true) */
100
+ requireRegistration?: boolean;
101
+ /** Whether to allow pending mlinks (defaults to true) */
102
+ allowPending?: boolean;
103
+ /** Whether to allow blocked mlinks (defaults to false) */
104
+ allowBlocked?: boolean;
81
105
  }
82
106
  interface ActionButtonProps {
83
107
  label: string;
@@ -97,6 +121,14 @@ interface ExecutionResult {
97
121
  interface UseMlinkOptions {
98
122
  refreshInterval?: number;
99
123
  enabled?: boolean;
124
+ /** Registry URL for validation (defaults to https://mlinks-fe.vercel.app) */
125
+ registryUrl?: string;
126
+ /** Whether to require registration for the mlink to work (defaults to true) */
127
+ requireRegistration?: boolean;
128
+ /** Whether to allow pending mlinks (defaults to true) */
129
+ allowPending?: boolean;
130
+ /** Whether to allow blocked mlinks (defaults to false) */
131
+ allowBlocked?: boolean;
100
132
  }
101
133
  interface UseExecuteMlinkReturn {
102
134
  execute: (action: string, input?: string) => Promise<ExecutionResult>;
@@ -106,7 +138,7 @@ interface UseExecuteMlinkReturn {
106
138
  reset: () => void;
107
139
  }
108
140
 
109
- declare function Mlink({ url, adapter, theme: themeProp, onSuccess, onError, className, stylePreset, }: MlinkProps): react_jsx_runtime.JSX.Element;
141
+ declare function Mlink({ url, adapter, theme: themeProp, onSuccess, onError, className, stylePreset, registryUrl, requireRegistration, allowPending, allowBlocked, }: MlinkProps): react_jsx_runtime.JSX.Element;
110
142
 
111
143
  interface MlinkContextValue {
112
144
  theme: MlinkTheme;
@@ -211,4 +243,4 @@ declare const mantleTheme: MlinkTheme;
211
243
  declare const themePresets: Record<MlinkThemePreset, MlinkTheme>;
212
244
  declare function resolveTheme(theme?: Partial<MlinkTheme> | MlinkThemePreset): MlinkTheme;
213
245
 
214
- export { type ActionButtonProps, type EthersAdapterConfig, type ExecutionResult, Mlink, type MlinkAdapter, Mlink as MlinkComponent, type MlinkInstance, type MlinkProps, MlinkProvider, type MlinkProviderConfig, type MlinkStatus, type MlinkTheme, type MlinkThemePreset, type UseExecuteMlinkReturn, type UseExecuteMlinkReturnEnhanced, type UseMlinkOptions, type WagmiAdapterConfig, createMlinkAdapter, darkTheme, lightTheme, mantleTheme, resolveTheme, themePresets, useExecuteMlink, useMlink, useMlinkContext, useMlinkEthersAdapter, useMlinkWagmiAdapter };
246
+ export { type ActionButtonProps, type EthersAdapterConfig, type ExecutionResult, Mlink, type MlinkAdapter, Mlink as MlinkComponent, type MlinkInstance, type MlinkProps, MlinkProvider, type MlinkProviderConfig, type MlinkStatus, type MlinkTheme, type MlinkThemePreset, type RegistrationResult, type RegistrationStatus, type UseExecuteMlinkReturn, type UseExecuteMlinkReturnEnhanced, type UseMlinkOptions, type WagmiAdapterConfig, createMlinkAdapter, darkTheme, lightTheme, mantleTheme, resolveTheme, themePresets, useExecuteMlink, useMlink, useMlinkContext, useMlinkEthersAdapter, useMlinkWagmiAdapter };
@@ -18,6 +18,8 @@ var MANTLE_SEPOLIA = {
18
18
  };
19
19
  var DEFAULT_CHAIN = MANTLE_SEPOLIA;
20
20
  var ACTION_QUERY_PARAM = "action";
21
+ var REGISTRY_URL = "https://mlinks-fe.vercel.app";
22
+ var REGISTRY_VALIDATE_ENDPOINT = "/api/registry/validate";
21
23
 
22
24
  // src/utils.ts
23
25
  function parseBlinkUrl(blinkUrl) {
@@ -182,22 +184,73 @@ function validateActionMetadata(data) {
182
184
  // src/react/useMlink.ts
183
185
  var DEFAULT_REFRESH_INTERVAL = 10 * 60 * 1e3;
184
186
  function useMlink(url, options = {}) {
185
- const { refreshInterval = DEFAULT_REFRESH_INTERVAL, enabled = true } = options;
187
+ const {
188
+ refreshInterval = DEFAULT_REFRESH_INTERVAL,
189
+ enabled = true,
190
+ registryUrl = REGISTRY_URL,
191
+ requireRegistration = true,
192
+ allowPending = true,
193
+ allowBlocked = false
194
+ } = options;
186
195
  const [status, setStatus] = react.useState("idle");
187
196
  const [metadata, setMetadata] = react.useState(null);
188
197
  const [error, setError] = react.useState(null);
198
+ const [registration, setRegistration] = react.useState(null);
189
199
  const abortControllerRef = react.useRef(null);
190
200
  const intervalRef = react.useRef(null);
191
201
  const actionUrl = parseBlinkUrl(url) || url;
202
+ const validateRegistration = react.useCallback(async () => {
203
+ if (!actionUrl || !requireRegistration) return null;
204
+ try {
205
+ const validateUrl = `${registryUrl}${REGISTRY_VALIDATE_ENDPOINT}?url=${encodeURIComponent(actionUrl)}`;
206
+ const response = await fetch(validateUrl, {
207
+ method: "GET",
208
+ headers: {
209
+ Accept: "application/json"
210
+ }
211
+ });
212
+ const data = await response.json();
213
+ return data;
214
+ } catch (err) {
215
+ console.error("Registry validation error:", err);
216
+ return {
217
+ isRegistered: false,
218
+ status: null,
219
+ error: "Unable to validate against registry. Please try again later."
220
+ };
221
+ }
222
+ }, [actionUrl, registryUrl, requireRegistration]);
192
223
  const fetchMetadata = react.useCallback(async () => {
193
224
  if (!actionUrl || !enabled) return;
194
225
  if (abortControllerRef.current) {
195
226
  abortControllerRef.current.abort();
196
227
  }
197
228
  abortControllerRef.current = new AbortController();
198
- setStatus("loading");
229
+ setStatus("validating");
199
230
  setError(null);
200
231
  try {
232
+ if (requireRegistration) {
233
+ const registrationResult = await validateRegistration();
234
+ setRegistration(registrationResult);
235
+ if (registrationResult) {
236
+ if (!registrationResult.isRegistered) {
237
+ setError(registrationResult.error || "This MLink is not registered.");
238
+ setStatus("unregistered");
239
+ return;
240
+ }
241
+ if (registrationResult.status === "blocked" && !allowBlocked) {
242
+ setError("This MLink has been blocked for policy violations.");
243
+ setStatus("blocked");
244
+ return;
245
+ }
246
+ if (registrationResult.status === "pending" && !allowPending) {
247
+ setError("This MLink is pending review and not yet available.");
248
+ setStatus("error");
249
+ return;
250
+ }
251
+ }
252
+ }
253
+ setStatus("loading");
201
254
  const response = await fetch(actionUrl, {
202
255
  method: "GET",
203
256
  headers: {
@@ -223,7 +276,7 @@ function useMlink(url, options = {}) {
223
276
  setError(errorMessage);
224
277
  setStatus("error");
225
278
  }
226
- }, [actionUrl, enabled]);
279
+ }, [actionUrl, enabled, requireRegistration, validateRegistration, allowBlocked, allowPending]);
227
280
  react.useEffect(() => {
228
281
  if (enabled) {
229
282
  fetchMetadata();
@@ -250,7 +303,9 @@ function useMlink(url, options = {}) {
250
303
  metadata,
251
304
  error,
252
305
  url: actionUrl,
253
- refresh: fetchMetadata
306
+ refresh: fetchMetadata,
307
+ registration,
308
+ isRegistered: registration?.isRegistered ?? false
254
309
  };
255
310
  }
256
311
  function useExecuteMlink(options) {
@@ -477,11 +532,20 @@ function Mlink({
477
532
  onSuccess,
478
533
  onError,
479
534
  className = "",
480
- stylePreset = "default"
535
+ stylePreset = "default",
536
+ registryUrl,
537
+ requireRegistration = true,
538
+ allowPending = true,
539
+ allowBlocked = false
481
540
  }) {
482
541
  const context = useMlinkContext();
483
542
  const resolvedTheme = themeProp ? resolveTheme(themeProp) : context.theme;
484
- const { status: fetchStatus, metadata, error: fetchError } = useMlink(url);
543
+ const { status: fetchStatus, metadata, error: fetchError, registration } = useMlink(url, {
544
+ registryUrl,
545
+ requireRegistration,
546
+ allowPending,
547
+ allowBlocked
548
+ });
485
549
  const {
486
550
  execute,
487
551
  status: execStatus,
@@ -544,9 +608,21 @@ function Mlink({
544
608
  const hasLinkedActions = react.useMemo(() => {
545
609
  return metadata?.links?.actions && metadata.links.actions.length > 0;
546
610
  }, [metadata]);
547
- if (fetchStatus === "loading") {
611
+ if (fetchStatus === "loading" || fetchStatus === "validating") {
548
612
  return /* @__PURE__ */ jsxRuntime.jsx(MlinkContainer, { theme: resolvedTheme, className, preset: stylePreset, children: /* @__PURE__ */ jsxRuntime.jsx(MlinkSkeleton, {}) });
549
613
  }
614
+ if (fetchStatus === "unregistered") {
615
+ return /* @__PURE__ */ jsxRuntime.jsx(MlinkContainer, { theme: resolvedTheme, className, preset: stylePreset, children: /* @__PURE__ */ jsxRuntime.jsx(
616
+ MlinkUnregistered,
617
+ {
618
+ message: fetchError || "This MLink is not registered.",
619
+ registryUrl
620
+ }
621
+ ) });
622
+ }
623
+ if (fetchStatus === "blocked") {
624
+ return /* @__PURE__ */ jsxRuntime.jsx(MlinkContainer, { theme: resolvedTheme, className, preset: stylePreset, children: /* @__PURE__ */ jsxRuntime.jsx(MlinkBlocked, { message: fetchError || "This MLink has been blocked." }) });
625
+ }
550
626
  if (fetchStatus === "error" || !metadata) {
551
627
  return /* @__PURE__ */ jsxRuntime.jsx(MlinkContainer, { theme: resolvedTheme, className, preset: stylePreset, children: /* @__PURE__ */ jsxRuntime.jsx(MlinkError, { message: fetchError || "Failed to load action" }) });
552
628
  }
@@ -823,6 +899,38 @@ function MlinkError({ message }) {
823
899
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mlink-error-message", children: message })
824
900
  ] });
825
901
  }
902
+ function MlinkUnregistered({ message, registryUrl }) {
903
+ const registerUrl = registryUrl ? `${registryUrl}/dashboard/register` : "https://mlinks-fe.vercel.app/dashboard/register";
904
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mlink-unregistered", children: [
905
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mlink-unregistered-icon", children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "48", height: "48", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
906
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10" }),
907
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
908
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
909
+ ] }) }),
910
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "mlink-unregistered-title", children: "Unregistered MLink" }),
911
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mlink-unregistered-message", children: message }),
912
+ /* @__PURE__ */ jsxRuntime.jsx(
913
+ "a",
914
+ {
915
+ href: registerUrl,
916
+ target: "_blank",
917
+ rel: "noopener noreferrer",
918
+ className: "mlink-button",
919
+ children: "Register MLink"
920
+ }
921
+ )
922
+ ] });
923
+ }
924
+ function MlinkBlocked({ message }) {
925
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mlink-blocked", children: [
926
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mlink-blocked-icon", children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "48", height: "48", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
927
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10" }),
928
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "4.93", y1: "4.93", x2: "19.07", y2: "19.07" })
929
+ ] }) }),
930
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "mlink-blocked-title", children: "Blocked MLink" }),
931
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mlink-blocked-message", children: message })
932
+ ] });
933
+ }
826
934
  function MlinkSuccess({ message, txHash, onReset }) {
827
935
  const shortHash = `${txHash.slice(0, 10)}...${txHash.slice(-8)}`;
828
936
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mlink-success", children: [