@dipansrimany/mlink-sdk 0.3.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.
@@ -16,6 +16,8 @@ var MANTLE_SEPOLIA = {
16
16
  };
17
17
  var DEFAULT_CHAIN = MANTLE_SEPOLIA;
18
18
  var ACTION_QUERY_PARAM = "action";
19
+ var REGISTRY_URL = "https://mlinks-fe.vercel.app";
20
+ var REGISTRY_VALIDATE_ENDPOINT = "/api/registry/validate";
19
21
 
20
22
  // src/utils.ts
21
23
  function parseBlinkUrl(blinkUrl) {
@@ -39,18 +41,113 @@ var ActionButtonSchema = z.object({
39
41
  placeholder: z.string().optional(),
40
42
  disabled: z.boolean().optional()
41
43
  });
44
+ z.enum([
45
+ "text",
46
+ "number",
47
+ "email",
48
+ "url",
49
+ "date",
50
+ "datetime-local",
51
+ "textarea",
52
+ "select",
53
+ "radio",
54
+ "checkbox",
55
+ "address",
56
+ "token",
57
+ "amount"
58
+ ]);
59
+ var ActionParameterOptionSchema = z.object({
60
+ label: z.string().min(1),
61
+ value: z.string(),
62
+ selected: z.boolean().optional()
63
+ });
64
+ var ActionParameterBaseSchema = z.object({
65
+ name: z.string().min(1).max(50),
66
+ label: z.string().max(100).optional(),
67
+ required: z.boolean().optional(),
68
+ pattern: z.string().optional(),
69
+ patternDescription: z.string().optional(),
70
+ min: z.union([z.string(), z.number()]).optional(),
71
+ max: z.union([z.string(), z.number()]).optional()
72
+ });
73
+ var ActionParameterSchema = ActionParameterBaseSchema.extend({
74
+ type: z.enum([
75
+ "text",
76
+ "number",
77
+ "email",
78
+ "url",
79
+ "date",
80
+ "datetime-local",
81
+ "textarea",
82
+ "address",
83
+ "token",
84
+ "amount"
85
+ ]).optional()
86
+ });
87
+ var ActionParameterSelectableSchema = ActionParameterBaseSchema.extend({
88
+ type: z.enum(["select", "radio", "checkbox"]),
89
+ options: z.array(ActionParameterOptionSchema).min(1)
90
+ });
91
+ var TypedActionParameterSchema = z.union([
92
+ ActionParameterSelectableSchema,
93
+ ActionParameterSchema
94
+ ]);
95
+ var LinkedActionTypeSchema = z.enum(["transaction", "post", "external-link"]);
96
+ var LinkedActionSchema = z.object({
97
+ type: LinkedActionTypeSchema.optional(),
98
+ href: z.string().min(1),
99
+ label: z.string().min(1).max(50),
100
+ disabled: z.boolean().optional(),
101
+ parameters: z.array(TypedActionParameterSchema).optional()
102
+ });
103
+ var ActionLinksSchema = z.object({
104
+ actions: z.array(LinkedActionSchema).min(1)
105
+ });
106
+ var PostNextActionLinkSchema = z.object({
107
+ type: z.literal("post"),
108
+ href: z.string().min(1)
109
+ });
110
+ var InlineNextActionLinkSchema = z.object({
111
+ type: z.literal("inline"),
112
+ action: z.lazy(() => ActionMetadataSchema)
113
+ });
114
+ var NextActionLinkSchema = z.union([
115
+ PostNextActionLinkSchema,
116
+ InlineNextActionLinkSchema
117
+ ]);
118
+ var iconSchema = z.string().refine(
119
+ (val) => {
120
+ if (val.startsWith("http://") || val.startsWith("https://")) return true;
121
+ if (val.startsWith("data:image/")) return true;
122
+ if (val.startsWith("/")) return true;
123
+ return false;
124
+ },
125
+ { message: "Icon must be a valid URL, base64 data URI, or relative path" }
126
+ );
42
127
  var ActionMetadataSchema = z.object({
43
- title: z.string().min(1).max(100),
44
- icon: z.string().url(),
45
- description: z.string().min(1).max(500),
46
- actions: z.array(ActionButtonSchema).min(1),
128
+ type: z.enum(["action", "completed"]).optional(),
129
+ title: z.string().min(1).max(200),
130
+ icon: iconSchema,
131
+ description: z.string().min(1).max(1e3),
132
+ label: z.string().max(50).optional(),
133
+ // Legacy actions (optional)
134
+ actions: z.array(ActionButtonSchema).optional(),
135
+ // Solana-style linked actions (optional)
136
+ links: ActionLinksSchema.optional(),
47
137
  disabled: z.boolean().optional(),
48
138
  error: z.object({ message: z.string() }).optional()
49
- });
139
+ }).refine(
140
+ (data) => {
141
+ return data.actions && data.actions.length > 0 || data.links?.actions && data.links.actions.length > 0;
142
+ },
143
+ { message: "Must have at least one action or linked action" }
144
+ );
50
145
  z.object({
51
146
  account: z.string().regex(addressRegex, "Invalid Ethereum address"),
52
147
  action: z.string().min(1),
53
- input: z.string().optional()
148
+ input: z.string().optional(),
149
+ // Solana-style parameter data
150
+ data: z.record(z.union([z.string(), z.array(z.string())])).optional()
54
151
  });
55
152
  var EVMTransactionSchema = z.object({
56
153
  to: z.string().regex(addressRegex, "Invalid to address"),
@@ -58,10 +155,22 @@ var EVMTransactionSchema = z.object({
58
155
  data: z.string().regex(hexRegex, "Invalid hex data"),
59
156
  chainId: z.number().positive()
60
157
  });
61
- var TransactionResponseSchema = z.object({
62
- transaction: EVMTransactionSchema,
63
- message: z.string().optional()
64
- });
158
+ z.object({
159
+ // Single transaction (legacy)
160
+ transaction: EVMTransactionSchema.optional(),
161
+ // Multiple transactions (batch)
162
+ transactions: z.array(EVMTransactionSchema).optional(),
163
+ message: z.string().optional(),
164
+ // Action chaining
165
+ links: z.object({
166
+ next: NextActionLinkSchema.optional()
167
+ }).optional()
168
+ }).refine(
169
+ (data) => {
170
+ return data.transaction !== void 0 || data.transactions && data.transactions.length > 0;
171
+ },
172
+ { message: "Must have either transaction or transactions" }
173
+ );
65
174
  function validateActionMetadata(data) {
66
175
  const result = ActionMetadataSchema.safeParse(data);
67
176
  if (result.success) {
@@ -69,33 +178,77 @@ function validateActionMetadata(data) {
69
178
  }
70
179
  return { success: false, error: result.error.message };
71
180
  }
72
- function validateTransactionResponse(data) {
73
- const result = TransactionResponseSchema.safeParse(data);
74
- if (result.success) {
75
- return { success: true, data: result.data };
76
- }
77
- return { success: false, error: result.error.message };
78
- }
79
181
 
80
182
  // src/react/useMlink.ts
81
183
  var DEFAULT_REFRESH_INTERVAL = 10 * 60 * 1e3;
82
184
  function useMlink(url, options = {}) {
83
- const { refreshInterval = DEFAULT_REFRESH_INTERVAL, enabled = true } = options;
185
+ const {
186
+ refreshInterval = DEFAULT_REFRESH_INTERVAL,
187
+ enabled = true,
188
+ registryUrl = REGISTRY_URL,
189
+ requireRegistration = true,
190
+ allowPending = true,
191
+ allowBlocked = false
192
+ } = options;
84
193
  const [status, setStatus] = useState("idle");
85
194
  const [metadata, setMetadata] = useState(null);
86
195
  const [error, setError] = useState(null);
196
+ const [registration, setRegistration] = useState(null);
87
197
  const abortControllerRef = useRef(null);
88
198
  const intervalRef = useRef(null);
89
199
  const actionUrl = parseBlinkUrl(url) || url;
200
+ const validateRegistration = useCallback(async () => {
201
+ if (!actionUrl || !requireRegistration) return null;
202
+ try {
203
+ const validateUrl = `${registryUrl}${REGISTRY_VALIDATE_ENDPOINT}?url=${encodeURIComponent(actionUrl)}`;
204
+ const response = await fetch(validateUrl, {
205
+ method: "GET",
206
+ headers: {
207
+ Accept: "application/json"
208
+ }
209
+ });
210
+ const data = await response.json();
211
+ return data;
212
+ } catch (err) {
213
+ console.error("Registry validation error:", err);
214
+ return {
215
+ isRegistered: false,
216
+ status: null,
217
+ error: "Unable to validate against registry. Please try again later."
218
+ };
219
+ }
220
+ }, [actionUrl, registryUrl, requireRegistration]);
90
221
  const fetchMetadata = useCallback(async () => {
91
222
  if (!actionUrl || !enabled) return;
92
223
  if (abortControllerRef.current) {
93
224
  abortControllerRef.current.abort();
94
225
  }
95
226
  abortControllerRef.current = new AbortController();
96
- setStatus("loading");
227
+ setStatus("validating");
97
228
  setError(null);
98
229
  try {
230
+ if (requireRegistration) {
231
+ const registrationResult = await validateRegistration();
232
+ setRegistration(registrationResult);
233
+ if (registrationResult) {
234
+ if (!registrationResult.isRegistered) {
235
+ setError(registrationResult.error || "This MLink is not registered.");
236
+ setStatus("unregistered");
237
+ return;
238
+ }
239
+ if (registrationResult.status === "blocked" && !allowBlocked) {
240
+ setError("This MLink has been blocked for policy violations.");
241
+ setStatus("blocked");
242
+ return;
243
+ }
244
+ if (registrationResult.status === "pending" && !allowPending) {
245
+ setError("This MLink is pending review and not yet available.");
246
+ setStatus("error");
247
+ return;
248
+ }
249
+ }
250
+ }
251
+ setStatus("loading");
99
252
  const response = await fetch(actionUrl, {
100
253
  method: "GET",
101
254
  headers: {
@@ -121,7 +274,7 @@ function useMlink(url, options = {}) {
121
274
  setError(errorMessage);
122
275
  setStatus("error");
123
276
  }
124
- }, [actionUrl, enabled]);
277
+ }, [actionUrl, enabled, requireRegistration, validateRegistration, allowBlocked, allowPending]);
125
278
  useEffect(() => {
126
279
  if (enabled) {
127
280
  fetchMetadata();
@@ -148,7 +301,9 @@ function useMlink(url, options = {}) {
148
301
  metadata,
149
302
  error,
150
303
  url: actionUrl,
151
- refresh: fetchMetadata
304
+ refresh: fetchMetadata,
305
+ registration,
306
+ isRegistered: registration?.isRegistered ?? false
152
307
  };
153
308
  }
154
309
  function useExecuteMlink(options) {
@@ -162,7 +317,7 @@ function useExecuteMlink(options) {
162
317
  setError(null);
163
318
  }, []);
164
319
  const execute = useCallback(
165
- async (action, input) => {
320
+ async (action, input, data) => {
166
321
  setStatus("executing");
167
322
  setError(null);
168
323
  setTxHash(null);
@@ -179,28 +334,33 @@ function useExecuteMlink(options) {
179
334
  body: JSON.stringify({
180
335
  account,
181
336
  action,
182
- input
337
+ input,
338
+ data
339
+ // Include parameter data
183
340
  })
184
341
  });
185
342
  if (!response.ok) {
186
343
  const errorData = await response.json().catch(() => ({}));
187
344
  throw new Error(
188
- errorData.message || `HTTP ${response.status}: ${response.statusText}`
345
+ errorData.error?.message || errorData.message || `HTTP ${response.status}: ${response.statusText}`
189
346
  );
190
347
  }
191
- const data = await response.json();
192
- const validation = validateTransactionResponse(data);
193
- if (!validation.success) {
194
- throw new Error(`Invalid response: ${validation.error}`);
348
+ const responseData = await response.json();
349
+ const transactions = responseData.transactions ? responseData.transactions : responseData.transaction ? [responseData.transaction] : [];
350
+ if (transactions.length === 0) {
351
+ throw new Error("No transaction returned from action");
352
+ }
353
+ let lastHash = "";
354
+ for (const tx of transactions) {
355
+ lastHash = await adapter.signAndSendTransaction(tx);
195
356
  }
196
- const hash = await adapter.signAndSendTransaction(data.transaction);
197
- setTxHash(hash);
357
+ setTxHash(lastHash);
198
358
  setStatus("success");
199
- onSuccess?.(hash, action);
359
+ onSuccess?.(lastHash, action);
200
360
  return {
201
361
  success: true,
202
- txHash: hash,
203
- message: data.message
362
+ txHash: lastHash,
363
+ message: responseData.message
204
364
  };
205
365
  } catch (err) {
206
366
  const errorMessage = err instanceof Error ? err.message : "Transaction failed";
@@ -346,6 +506,23 @@ function useMlinkContext() {
346
506
  }
347
507
  return context;
348
508
  }
509
+
510
+ // src/builders.ts
511
+ function buildHref(template, params) {
512
+ let result = template;
513
+ for (const [key, value] of Object.entries(params)) {
514
+ const placeholder = `{${key}}`;
515
+ const replacement = Array.isArray(value) ? value.join(",") : value;
516
+ result = result.replace(new RegExp(placeholder, "g"), encodeURIComponent(replacement));
517
+ }
518
+ return result;
519
+ }
520
+ function hasParameters(action) {
521
+ return Boolean(action.parameters && action.parameters.length > 0);
522
+ }
523
+ function isSelectableParam(param) {
524
+ return param.type === "select" || param.type === "radio" || param.type === "checkbox";
525
+ }
349
526
  function Mlink({
350
527
  url,
351
528
  adapter,
@@ -353,11 +530,20 @@ function Mlink({
353
530
  onSuccess,
354
531
  onError,
355
532
  className = "",
356
- stylePreset = "default"
533
+ stylePreset = "default",
534
+ registryUrl,
535
+ requireRegistration = true,
536
+ allowPending = true,
537
+ allowBlocked = false
357
538
  }) {
358
539
  const context = useMlinkContext();
359
540
  const resolvedTheme = themeProp ? resolveTheme(themeProp) : context.theme;
360
- const { status: fetchStatus, metadata, error: fetchError } = useMlink(url);
541
+ const { status: fetchStatus, metadata, error: fetchError, registration } = useMlink(url, {
542
+ registryUrl,
543
+ requireRegistration,
544
+ allowPending,
545
+ allowBlocked
546
+ });
361
547
  const {
362
548
  execute,
363
549
  status: execStatus,
@@ -371,9 +557,14 @@ function Mlink({
371
557
  onError
372
558
  });
373
559
  const [inputValues, setInputValues] = useState({});
560
+ const [paramValues, setParamValues] = useState({});
561
+ const [selectedLinkedAction, setSelectedLinkedAction] = useState(null);
374
562
  const handleInputChange = useCallback((actionValue, value) => {
375
563
  setInputValues((prev) => ({ ...prev, [actionValue]: value }));
376
564
  }, []);
565
+ const handleParamChange = useCallback((name, value) => {
566
+ setParamValues((prev) => ({ ...prev, [name]: value }));
567
+ }, []);
377
568
  const handleAction = useCallback(
378
569
  async (action) => {
379
570
  const input = action.type === "input" ? inputValues[action.value] : void 0;
@@ -381,9 +572,55 @@ function Mlink({
381
572
  },
382
573
  [execute, inputValues]
383
574
  );
384
- if (fetchStatus === "loading") {
575
+ const handleLinkedAction = useCallback(
576
+ async (action) => {
577
+ if (hasParameters(action)) {
578
+ setSelectedLinkedAction(action);
579
+ const defaults = {};
580
+ action.parameters?.forEach((param) => {
581
+ if (isSelectableParam(param)) {
582
+ const selectedOption = param.options.find((o) => o.selected);
583
+ if (selectedOption) {
584
+ defaults[param.name] = param.type === "checkbox" ? [selectedOption.value] : selectedOption.value;
585
+ }
586
+ }
587
+ });
588
+ setParamValues(defaults);
589
+ } else {
590
+ await execute(action.href, void 0, {});
591
+ }
592
+ },
593
+ [execute]
594
+ );
595
+ const handleExecuteWithParams = useCallback(async () => {
596
+ if (!selectedLinkedAction) return;
597
+ const finalHref = buildHref(selectedLinkedAction.href, paramValues);
598
+ await execute(finalHref, void 0, paramValues);
599
+ setSelectedLinkedAction(null);
600
+ setParamValues({});
601
+ }, [selectedLinkedAction, paramValues, execute]);
602
+ const handleCancelParams = useCallback(() => {
603
+ setSelectedLinkedAction(null);
604
+ setParamValues({});
605
+ }, []);
606
+ const hasLinkedActions = useMemo(() => {
607
+ return metadata?.links?.actions && metadata.links.actions.length > 0;
608
+ }, [metadata]);
609
+ if (fetchStatus === "loading" || fetchStatus === "validating") {
385
610
  return /* @__PURE__ */ jsx(MlinkContainer, { theme: resolvedTheme, className, preset: stylePreset, children: /* @__PURE__ */ jsx(MlinkSkeleton, {}) });
386
611
  }
612
+ if (fetchStatus === "unregistered") {
613
+ return /* @__PURE__ */ jsx(MlinkContainer, { theme: resolvedTheme, className, preset: stylePreset, children: /* @__PURE__ */ jsx(
614
+ MlinkUnregistered,
615
+ {
616
+ message: fetchError || "This MLink is not registered.",
617
+ registryUrl
618
+ }
619
+ ) });
620
+ }
621
+ if (fetchStatus === "blocked") {
622
+ return /* @__PURE__ */ jsx(MlinkContainer, { theme: resolvedTheme, className, preset: stylePreset, children: /* @__PURE__ */ jsx(MlinkBlocked, { message: fetchError || "This MLink has been blocked." }) });
623
+ }
387
624
  if (fetchStatus === "error" || !metadata) {
388
625
  return /* @__PURE__ */ jsx(MlinkContainer, { theme: resolvedTheme, className, preset: stylePreset, children: /* @__PURE__ */ jsx(MlinkError, { message: fetchError || "Failed to load action" }) });
389
626
  }
@@ -397,6 +634,45 @@ function Mlink({
397
634
  }
398
635
  ) });
399
636
  }
637
+ if (selectedLinkedAction && hasParameters(selectedLinkedAction)) {
638
+ return /* @__PURE__ */ jsxs(MlinkContainer, { theme: resolvedTheme, className, preset: stylePreset, children: [
639
+ /* @__PURE__ */ jsxs("div", { className: "mlink-content", children: [
640
+ /* @__PURE__ */ jsx("h3", { className: "mlink-title", children: selectedLinkedAction.label }),
641
+ /* @__PURE__ */ jsx("p", { className: "mlink-description", children: "Fill in the details below" })
642
+ ] }),
643
+ execError && /* @__PURE__ */ jsx("div", { className: "mlink-error-banner", children: execError }),
644
+ /* @__PURE__ */ jsx("div", { className: "mlink-params", children: selectedLinkedAction.parameters?.map((param) => /* @__PURE__ */ jsx(
645
+ ParameterInput,
646
+ {
647
+ param,
648
+ value: paramValues[param.name] || "",
649
+ onChange: (value) => handleParamChange(param.name, value),
650
+ disabled: execStatus === "executing"
651
+ },
652
+ param.name
653
+ )) }),
654
+ /* @__PURE__ */ jsxs("div", { className: "mlink-actions", children: [
655
+ /* @__PURE__ */ jsx(
656
+ "button",
657
+ {
658
+ className: "mlink-button",
659
+ onClick: handleExecuteWithParams,
660
+ disabled: execStatus === "executing",
661
+ children: execStatus === "executing" ? /* @__PURE__ */ jsx(MlinkSpinner, {}) : selectedLinkedAction.label
662
+ }
663
+ ),
664
+ /* @__PURE__ */ jsx(
665
+ "button",
666
+ {
667
+ className: "mlink-button mlink-button-secondary",
668
+ onClick: handleCancelParams,
669
+ disabled: execStatus === "executing",
670
+ children: "Back"
671
+ }
672
+ )
673
+ ] })
674
+ ] });
675
+ }
400
676
  return /* @__PURE__ */ jsxs(MlinkContainer, { theme: resolvedTheme, className, preset: stylePreset, children: [
401
677
  /* @__PURE__ */ jsx("div", { className: "mlink-icon", children: /* @__PURE__ */ jsx("img", { src: metadata.icon, alt: metadata.title }) }),
402
678
  /* @__PURE__ */ jsxs("div", { className: "mlink-content", children: [
@@ -404,7 +680,29 @@ function Mlink({
404
680
  /* @__PURE__ */ jsx("p", { className: "mlink-description", children: metadata.description })
405
681
  ] }),
406
682
  execError && /* @__PURE__ */ jsx("div", { className: "mlink-error-banner", children: execError }),
407
- /* @__PURE__ */ jsx("div", { className: "mlink-actions", children: metadata.actions.map((action, index) => /* @__PURE__ */ jsx(
683
+ hasLinkedActions && /* @__PURE__ */ jsxs("div", { className: "mlink-actions", children: [
684
+ /* @__PURE__ */ jsx("div", { className: "mlink-quick-actions", children: metadata.links.actions.filter((a) => !hasParameters(a)).map((action, index) => /* @__PURE__ */ jsx(
685
+ "button",
686
+ {
687
+ className: "mlink-button mlink-button-quick",
688
+ onClick: () => handleLinkedAction(action),
689
+ disabled: metadata.disabled || action.disabled || execStatus === "executing",
690
+ children: execStatus === "executing" ? /* @__PURE__ */ jsx(MlinkSpinner, {}) : action.label
691
+ },
692
+ `${action.href}-${index}`
693
+ )) }),
694
+ metadata.links.actions.filter((a) => hasParameters(a)).map((action, index) => /* @__PURE__ */ jsx(
695
+ "button",
696
+ {
697
+ className: "mlink-button mlink-button-custom",
698
+ onClick: () => handleLinkedAction(action),
699
+ disabled: metadata.disabled || action.disabled || execStatus === "executing",
700
+ children: action.label
701
+ },
702
+ `param-${action.href}-${index}`
703
+ ))
704
+ ] }),
705
+ !hasLinkedActions && metadata.actions && /* @__PURE__ */ jsx("div", { className: "mlink-actions", children: metadata.actions.map((action, index) => /* @__PURE__ */ jsx(
408
706
  ActionButtonComponent,
409
707
  {
410
708
  action,
@@ -418,6 +716,161 @@ function Mlink({
418
716
  )) })
419
717
  ] });
420
718
  }
719
+ function ParameterInput({ param, value, onChange, disabled }) {
720
+ const strValue = Array.isArray(value) ? value.join(",") : value;
721
+ if (isSelectableParam(param)) {
722
+ return /* @__PURE__ */ jsx(
723
+ SelectableParamInput,
724
+ {
725
+ param,
726
+ value,
727
+ onChange,
728
+ disabled
729
+ }
730
+ );
731
+ }
732
+ const inputType = getInputType(param.type);
733
+ if (param.type === "textarea") {
734
+ return /* @__PURE__ */ jsxs("div", { className: "mlink-param-group", children: [
735
+ param.label && /* @__PURE__ */ jsx("label", { className: "mlink-param-label", children: param.label }),
736
+ /* @__PURE__ */ jsx(
737
+ "textarea",
738
+ {
739
+ className: "mlink-textarea",
740
+ value: strValue,
741
+ onChange: (e) => onChange(e.target.value),
742
+ disabled,
743
+ required: param.required
744
+ }
745
+ )
746
+ ] });
747
+ }
748
+ return /* @__PURE__ */ jsxs("div", { className: "mlink-param-group", children: [
749
+ param.label && /* @__PURE__ */ jsxs("label", { className: "mlink-param-label", children: [
750
+ param.label,
751
+ param.required && /* @__PURE__ */ jsx("span", { className: "mlink-required", children: "*" })
752
+ ] }),
753
+ /* @__PURE__ */ jsx(
754
+ "input",
755
+ {
756
+ type: inputType,
757
+ className: "mlink-input",
758
+ value: strValue,
759
+ onChange: (e) => onChange(e.target.value),
760
+ disabled,
761
+ required: param.required,
762
+ pattern: param.pattern,
763
+ min: param.min?.toString(),
764
+ max: param.max?.toString(),
765
+ placeholder: param.label || param.name
766
+ }
767
+ ),
768
+ param.patternDescription && /* @__PURE__ */ jsx("span", { className: "mlink-param-hint", children: param.patternDescription })
769
+ ] });
770
+ }
771
+ function SelectableParamInput({
772
+ param,
773
+ value,
774
+ onChange,
775
+ disabled
776
+ }) {
777
+ const arrayValue = Array.isArray(value) ? value : value ? [value] : [];
778
+ if (param.type === "select") {
779
+ return /* @__PURE__ */ jsxs("div", { className: "mlink-param-group", children: [
780
+ param.label && /* @__PURE__ */ jsxs("label", { className: "mlink-param-label", children: [
781
+ param.label,
782
+ param.required && /* @__PURE__ */ jsx("span", { className: "mlink-required", children: "*" })
783
+ ] }),
784
+ /* @__PURE__ */ jsxs(
785
+ "select",
786
+ {
787
+ className: "mlink-select",
788
+ value: arrayValue[0] || "",
789
+ onChange: (e) => onChange(e.target.value),
790
+ disabled,
791
+ required: param.required,
792
+ children: [
793
+ /* @__PURE__ */ jsxs("option", { value: "", children: [
794
+ "Select ",
795
+ param.label || param.name
796
+ ] }),
797
+ param.options.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value))
798
+ ]
799
+ }
800
+ )
801
+ ] });
802
+ }
803
+ if (param.type === "radio") {
804
+ return /* @__PURE__ */ jsxs("div", { className: "mlink-param-group", children: [
805
+ param.label && /* @__PURE__ */ jsxs("label", { className: "mlink-param-label", children: [
806
+ param.label,
807
+ param.required && /* @__PURE__ */ jsx("span", { className: "mlink-required", children: "*" })
808
+ ] }),
809
+ /* @__PURE__ */ jsx("div", { className: "mlink-radio-group", children: param.options.map((opt) => /* @__PURE__ */ jsxs("label", { className: "mlink-radio-label", children: [
810
+ /* @__PURE__ */ jsx(
811
+ "input",
812
+ {
813
+ type: "radio",
814
+ name: param.name,
815
+ value: opt.value,
816
+ checked: arrayValue[0] === opt.value,
817
+ onChange: (e) => onChange(e.target.value),
818
+ disabled
819
+ }
820
+ ),
821
+ opt.label
822
+ ] }, opt.value)) })
823
+ ] });
824
+ }
825
+ if (param.type === "checkbox") {
826
+ return /* @__PURE__ */ jsxs("div", { className: "mlink-param-group", children: [
827
+ param.label && /* @__PURE__ */ jsxs("label", { className: "mlink-param-label", children: [
828
+ param.label,
829
+ param.required && /* @__PURE__ */ jsx("span", { className: "mlink-required", children: "*" })
830
+ ] }),
831
+ /* @__PURE__ */ jsx("div", { className: "mlink-checkbox-group", children: param.options.map((opt) => /* @__PURE__ */ jsxs("label", { className: "mlink-checkbox-label", children: [
832
+ /* @__PURE__ */ jsx(
833
+ "input",
834
+ {
835
+ type: "checkbox",
836
+ value: opt.value,
837
+ checked: arrayValue.includes(opt.value),
838
+ onChange: (e) => {
839
+ if (e.target.checked) {
840
+ onChange([...arrayValue, opt.value]);
841
+ } else {
842
+ onChange(arrayValue.filter((v) => v !== opt.value));
843
+ }
844
+ },
845
+ disabled
846
+ }
847
+ ),
848
+ opt.label
849
+ ] }, opt.value)) })
850
+ ] });
851
+ }
852
+ return null;
853
+ }
854
+ function getInputType(paramType) {
855
+ switch (paramType) {
856
+ case "number":
857
+ case "amount":
858
+ return "number";
859
+ case "email":
860
+ return "email";
861
+ case "url":
862
+ return "url";
863
+ case "date":
864
+ return "date";
865
+ case "datetime-local":
866
+ return "datetime-local";
867
+ case "address":
868
+ case "token":
869
+ case "text":
870
+ default:
871
+ return "text";
872
+ }
873
+ }
421
874
  function MlinkContainer({ theme, className, preset, children }) {
422
875
  return /* @__PURE__ */ jsx(
423
876
  "div",
@@ -444,6 +897,38 @@ function MlinkError({ message }) {
444
897
  /* @__PURE__ */ jsx("p", { className: "mlink-error-message", children: message })
445
898
  ] });
446
899
  }
900
+ function MlinkUnregistered({ message, registryUrl }) {
901
+ const registerUrl = registryUrl ? `${registryUrl}/dashboard/register` : "https://mlinks-fe.vercel.app/dashboard/register";
902
+ return /* @__PURE__ */ jsxs("div", { className: "mlink-unregistered", children: [
903
+ /* @__PURE__ */ jsx("div", { className: "mlink-unregistered-icon", children: /* @__PURE__ */ jsxs("svg", { width: "48", height: "48", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
904
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
905
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
906
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
907
+ ] }) }),
908
+ /* @__PURE__ */ jsx("h3", { className: "mlink-unregistered-title", children: "Unregistered MLink" }),
909
+ /* @__PURE__ */ jsx("p", { className: "mlink-unregistered-message", children: message }),
910
+ /* @__PURE__ */ jsx(
911
+ "a",
912
+ {
913
+ href: registerUrl,
914
+ target: "_blank",
915
+ rel: "noopener noreferrer",
916
+ className: "mlink-button",
917
+ children: "Register MLink"
918
+ }
919
+ )
920
+ ] });
921
+ }
922
+ function MlinkBlocked({ message }) {
923
+ return /* @__PURE__ */ jsxs("div", { className: "mlink-blocked", children: [
924
+ /* @__PURE__ */ jsx("div", { className: "mlink-blocked-icon", children: /* @__PURE__ */ jsxs("svg", { width: "48", height: "48", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
925
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
926
+ /* @__PURE__ */ jsx("line", { x1: "4.93", y1: "4.93", x2: "19.07", y2: "19.07" })
927
+ ] }) }),
928
+ /* @__PURE__ */ jsx("h3", { className: "mlink-blocked-title", children: "Blocked MLink" }),
929
+ /* @__PURE__ */ jsx("p", { className: "mlink-blocked-message", children: message })
930
+ ] });
931
+ }
447
932
  function MlinkSuccess({ message, txHash, onReset }) {
448
933
  const shortHash = `${txHash.slice(0, 10)}...${txHash.slice(-8)}`;
449
934
  return /* @__PURE__ */ jsxs("div", { className: "mlink-success", children: [