@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.
@@ -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) {
@@ -41,18 +43,113 @@ var ActionButtonSchema = zod.z.object({
41
43
  placeholder: zod.z.string().optional(),
42
44
  disabled: zod.z.boolean().optional()
43
45
  });
46
+ zod.z.enum([
47
+ "text",
48
+ "number",
49
+ "email",
50
+ "url",
51
+ "date",
52
+ "datetime-local",
53
+ "textarea",
54
+ "select",
55
+ "radio",
56
+ "checkbox",
57
+ "address",
58
+ "token",
59
+ "amount"
60
+ ]);
61
+ var ActionParameterOptionSchema = zod.z.object({
62
+ label: zod.z.string().min(1),
63
+ value: zod.z.string(),
64
+ selected: zod.z.boolean().optional()
65
+ });
66
+ var ActionParameterBaseSchema = zod.z.object({
67
+ name: zod.z.string().min(1).max(50),
68
+ label: zod.z.string().max(100).optional(),
69
+ required: zod.z.boolean().optional(),
70
+ pattern: zod.z.string().optional(),
71
+ patternDescription: zod.z.string().optional(),
72
+ min: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
73
+ max: zod.z.union([zod.z.string(), zod.z.number()]).optional()
74
+ });
75
+ var ActionParameterSchema = ActionParameterBaseSchema.extend({
76
+ type: zod.z.enum([
77
+ "text",
78
+ "number",
79
+ "email",
80
+ "url",
81
+ "date",
82
+ "datetime-local",
83
+ "textarea",
84
+ "address",
85
+ "token",
86
+ "amount"
87
+ ]).optional()
88
+ });
89
+ var ActionParameterSelectableSchema = ActionParameterBaseSchema.extend({
90
+ type: zod.z.enum(["select", "radio", "checkbox"]),
91
+ options: zod.z.array(ActionParameterOptionSchema).min(1)
92
+ });
93
+ var TypedActionParameterSchema = zod.z.union([
94
+ ActionParameterSelectableSchema,
95
+ ActionParameterSchema
96
+ ]);
97
+ var LinkedActionTypeSchema = zod.z.enum(["transaction", "post", "external-link"]);
98
+ var LinkedActionSchema = zod.z.object({
99
+ type: LinkedActionTypeSchema.optional(),
100
+ href: zod.z.string().min(1),
101
+ label: zod.z.string().min(1).max(50),
102
+ disabled: zod.z.boolean().optional(),
103
+ parameters: zod.z.array(TypedActionParameterSchema).optional()
104
+ });
105
+ var ActionLinksSchema = zod.z.object({
106
+ actions: zod.z.array(LinkedActionSchema).min(1)
107
+ });
108
+ var PostNextActionLinkSchema = zod.z.object({
109
+ type: zod.z.literal("post"),
110
+ href: zod.z.string().min(1)
111
+ });
112
+ var InlineNextActionLinkSchema = zod.z.object({
113
+ type: zod.z.literal("inline"),
114
+ action: zod.z.lazy(() => ActionMetadataSchema)
115
+ });
116
+ var NextActionLinkSchema = zod.z.union([
117
+ PostNextActionLinkSchema,
118
+ InlineNextActionLinkSchema
119
+ ]);
120
+ var iconSchema = zod.z.string().refine(
121
+ (val) => {
122
+ if (val.startsWith("http://") || val.startsWith("https://")) return true;
123
+ if (val.startsWith("data:image/")) return true;
124
+ if (val.startsWith("/")) return true;
125
+ return false;
126
+ },
127
+ { message: "Icon must be a valid URL, base64 data URI, or relative path" }
128
+ );
44
129
  var ActionMetadataSchema = zod.z.object({
45
- title: zod.z.string().min(1).max(100),
46
- icon: zod.z.string().url(),
47
- description: zod.z.string().min(1).max(500),
48
- actions: zod.z.array(ActionButtonSchema).min(1),
130
+ type: zod.z.enum(["action", "completed"]).optional(),
131
+ title: zod.z.string().min(1).max(200),
132
+ icon: iconSchema,
133
+ description: zod.z.string().min(1).max(1e3),
134
+ label: zod.z.string().max(50).optional(),
135
+ // Legacy actions (optional)
136
+ actions: zod.z.array(ActionButtonSchema).optional(),
137
+ // Solana-style linked actions (optional)
138
+ links: ActionLinksSchema.optional(),
49
139
  disabled: zod.z.boolean().optional(),
50
140
  error: zod.z.object({ message: zod.z.string() }).optional()
51
- });
141
+ }).refine(
142
+ (data) => {
143
+ return data.actions && data.actions.length > 0 || data.links?.actions && data.links.actions.length > 0;
144
+ },
145
+ { message: "Must have at least one action or linked action" }
146
+ );
52
147
  zod.z.object({
53
148
  account: zod.z.string().regex(addressRegex, "Invalid Ethereum address"),
54
149
  action: zod.z.string().min(1),
55
- input: zod.z.string().optional()
150
+ input: zod.z.string().optional(),
151
+ // Solana-style parameter data
152
+ data: zod.z.record(zod.z.union([zod.z.string(), zod.z.array(zod.z.string())])).optional()
56
153
  });
57
154
  var EVMTransactionSchema = zod.z.object({
58
155
  to: zod.z.string().regex(addressRegex, "Invalid to address"),
@@ -60,10 +157,22 @@ var EVMTransactionSchema = zod.z.object({
60
157
  data: zod.z.string().regex(hexRegex, "Invalid hex data"),
61
158
  chainId: zod.z.number().positive()
62
159
  });
63
- var TransactionResponseSchema = zod.z.object({
64
- transaction: EVMTransactionSchema,
65
- message: zod.z.string().optional()
66
- });
160
+ zod.z.object({
161
+ // Single transaction (legacy)
162
+ transaction: EVMTransactionSchema.optional(),
163
+ // Multiple transactions (batch)
164
+ transactions: zod.z.array(EVMTransactionSchema).optional(),
165
+ message: zod.z.string().optional(),
166
+ // Action chaining
167
+ links: zod.z.object({
168
+ next: NextActionLinkSchema.optional()
169
+ }).optional()
170
+ }).refine(
171
+ (data) => {
172
+ return data.transaction !== void 0 || data.transactions && data.transactions.length > 0;
173
+ },
174
+ { message: "Must have either transaction or transactions" }
175
+ );
67
176
  function validateActionMetadata(data) {
68
177
  const result = ActionMetadataSchema.safeParse(data);
69
178
  if (result.success) {
@@ -71,33 +180,77 @@ function validateActionMetadata(data) {
71
180
  }
72
181
  return { success: false, error: result.error.message };
73
182
  }
74
- function validateTransactionResponse(data) {
75
- const result = TransactionResponseSchema.safeParse(data);
76
- if (result.success) {
77
- return { success: true, data: result.data };
78
- }
79
- return { success: false, error: result.error.message };
80
- }
81
183
 
82
184
  // src/react/useMlink.ts
83
185
  var DEFAULT_REFRESH_INTERVAL = 10 * 60 * 1e3;
84
186
  function useMlink(url, options = {}) {
85
- 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;
86
195
  const [status, setStatus] = react.useState("idle");
87
196
  const [metadata, setMetadata] = react.useState(null);
88
197
  const [error, setError] = react.useState(null);
198
+ const [registration, setRegistration] = react.useState(null);
89
199
  const abortControllerRef = react.useRef(null);
90
200
  const intervalRef = react.useRef(null);
91
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]);
92
223
  const fetchMetadata = react.useCallback(async () => {
93
224
  if (!actionUrl || !enabled) return;
94
225
  if (abortControllerRef.current) {
95
226
  abortControllerRef.current.abort();
96
227
  }
97
228
  abortControllerRef.current = new AbortController();
98
- setStatus("loading");
229
+ setStatus("validating");
99
230
  setError(null);
100
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");
101
254
  const response = await fetch(actionUrl, {
102
255
  method: "GET",
103
256
  headers: {
@@ -123,7 +276,7 @@ function useMlink(url, options = {}) {
123
276
  setError(errorMessage);
124
277
  setStatus("error");
125
278
  }
126
- }, [actionUrl, enabled]);
279
+ }, [actionUrl, enabled, requireRegistration, validateRegistration, allowBlocked, allowPending]);
127
280
  react.useEffect(() => {
128
281
  if (enabled) {
129
282
  fetchMetadata();
@@ -150,7 +303,9 @@ function useMlink(url, options = {}) {
150
303
  metadata,
151
304
  error,
152
305
  url: actionUrl,
153
- refresh: fetchMetadata
306
+ refresh: fetchMetadata,
307
+ registration,
308
+ isRegistered: registration?.isRegistered ?? false
154
309
  };
155
310
  }
156
311
  function useExecuteMlink(options) {
@@ -164,7 +319,7 @@ function useExecuteMlink(options) {
164
319
  setError(null);
165
320
  }, []);
166
321
  const execute = react.useCallback(
167
- async (action, input) => {
322
+ async (action, input, data) => {
168
323
  setStatus("executing");
169
324
  setError(null);
170
325
  setTxHash(null);
@@ -181,28 +336,33 @@ function useExecuteMlink(options) {
181
336
  body: JSON.stringify({
182
337
  account,
183
338
  action,
184
- input
339
+ input,
340
+ data
341
+ // Include parameter data
185
342
  })
186
343
  });
187
344
  if (!response.ok) {
188
345
  const errorData = await response.json().catch(() => ({}));
189
346
  throw new Error(
190
- errorData.message || `HTTP ${response.status}: ${response.statusText}`
347
+ errorData.error?.message || errorData.message || `HTTP ${response.status}: ${response.statusText}`
191
348
  );
192
349
  }
193
- const data = await response.json();
194
- const validation = validateTransactionResponse(data);
195
- if (!validation.success) {
196
- throw new Error(`Invalid response: ${validation.error}`);
350
+ const responseData = await response.json();
351
+ const transactions = responseData.transactions ? responseData.transactions : responseData.transaction ? [responseData.transaction] : [];
352
+ if (transactions.length === 0) {
353
+ throw new Error("No transaction returned from action");
354
+ }
355
+ let lastHash = "";
356
+ for (const tx of transactions) {
357
+ lastHash = await adapter.signAndSendTransaction(tx);
197
358
  }
198
- const hash = await adapter.signAndSendTransaction(data.transaction);
199
- setTxHash(hash);
359
+ setTxHash(lastHash);
200
360
  setStatus("success");
201
- onSuccess?.(hash, action);
361
+ onSuccess?.(lastHash, action);
202
362
  return {
203
363
  success: true,
204
- txHash: hash,
205
- message: data.message
364
+ txHash: lastHash,
365
+ message: responseData.message
206
366
  };
207
367
  } catch (err) {
208
368
  const errorMessage = err instanceof Error ? err.message : "Transaction failed";
@@ -348,6 +508,23 @@ function useMlinkContext() {
348
508
  }
349
509
  return context;
350
510
  }
511
+
512
+ // src/builders.ts
513
+ function buildHref(template, params) {
514
+ let result = template;
515
+ for (const [key, value] of Object.entries(params)) {
516
+ const placeholder = `{${key}}`;
517
+ const replacement = Array.isArray(value) ? value.join(",") : value;
518
+ result = result.replace(new RegExp(placeholder, "g"), encodeURIComponent(replacement));
519
+ }
520
+ return result;
521
+ }
522
+ function hasParameters(action) {
523
+ return Boolean(action.parameters && action.parameters.length > 0);
524
+ }
525
+ function isSelectableParam(param) {
526
+ return param.type === "select" || param.type === "radio" || param.type === "checkbox";
527
+ }
351
528
  function Mlink({
352
529
  url,
353
530
  adapter,
@@ -355,11 +532,20 @@ function Mlink({
355
532
  onSuccess,
356
533
  onError,
357
534
  className = "",
358
- stylePreset = "default"
535
+ stylePreset = "default",
536
+ registryUrl,
537
+ requireRegistration = true,
538
+ allowPending = true,
539
+ allowBlocked = false
359
540
  }) {
360
541
  const context = useMlinkContext();
361
542
  const resolvedTheme = themeProp ? resolveTheme(themeProp) : context.theme;
362
- 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
+ });
363
549
  const {
364
550
  execute,
365
551
  status: execStatus,
@@ -373,9 +559,14 @@ function Mlink({
373
559
  onError
374
560
  });
375
561
  const [inputValues, setInputValues] = react.useState({});
562
+ const [paramValues, setParamValues] = react.useState({});
563
+ const [selectedLinkedAction, setSelectedLinkedAction] = react.useState(null);
376
564
  const handleInputChange = react.useCallback((actionValue, value) => {
377
565
  setInputValues((prev) => ({ ...prev, [actionValue]: value }));
378
566
  }, []);
567
+ const handleParamChange = react.useCallback((name, value) => {
568
+ setParamValues((prev) => ({ ...prev, [name]: value }));
569
+ }, []);
379
570
  const handleAction = react.useCallback(
380
571
  async (action) => {
381
572
  const input = action.type === "input" ? inputValues[action.value] : void 0;
@@ -383,9 +574,55 @@ function Mlink({
383
574
  },
384
575
  [execute, inputValues]
385
576
  );
386
- if (fetchStatus === "loading") {
577
+ const handleLinkedAction = react.useCallback(
578
+ async (action) => {
579
+ if (hasParameters(action)) {
580
+ setSelectedLinkedAction(action);
581
+ const defaults = {};
582
+ action.parameters?.forEach((param) => {
583
+ if (isSelectableParam(param)) {
584
+ const selectedOption = param.options.find((o) => o.selected);
585
+ if (selectedOption) {
586
+ defaults[param.name] = param.type === "checkbox" ? [selectedOption.value] : selectedOption.value;
587
+ }
588
+ }
589
+ });
590
+ setParamValues(defaults);
591
+ } else {
592
+ await execute(action.href, void 0, {});
593
+ }
594
+ },
595
+ [execute]
596
+ );
597
+ const handleExecuteWithParams = react.useCallback(async () => {
598
+ if (!selectedLinkedAction) return;
599
+ const finalHref = buildHref(selectedLinkedAction.href, paramValues);
600
+ await execute(finalHref, void 0, paramValues);
601
+ setSelectedLinkedAction(null);
602
+ setParamValues({});
603
+ }, [selectedLinkedAction, paramValues, execute]);
604
+ const handleCancelParams = react.useCallback(() => {
605
+ setSelectedLinkedAction(null);
606
+ setParamValues({});
607
+ }, []);
608
+ const hasLinkedActions = react.useMemo(() => {
609
+ return metadata?.links?.actions && metadata.links.actions.length > 0;
610
+ }, [metadata]);
611
+ if (fetchStatus === "loading" || fetchStatus === "validating") {
387
612
  return /* @__PURE__ */ jsxRuntime.jsx(MlinkContainer, { theme: resolvedTheme, className, preset: stylePreset, children: /* @__PURE__ */ jsxRuntime.jsx(MlinkSkeleton, {}) });
388
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
+ }
389
626
  if (fetchStatus === "error" || !metadata) {
390
627
  return /* @__PURE__ */ jsxRuntime.jsx(MlinkContainer, { theme: resolvedTheme, className, preset: stylePreset, children: /* @__PURE__ */ jsxRuntime.jsx(MlinkError, { message: fetchError || "Failed to load action" }) });
391
628
  }
@@ -399,6 +636,45 @@ function Mlink({
399
636
  }
400
637
  ) });
401
638
  }
639
+ if (selectedLinkedAction && hasParameters(selectedLinkedAction)) {
640
+ return /* @__PURE__ */ jsxRuntime.jsxs(MlinkContainer, { theme: resolvedTheme, className, preset: stylePreset, children: [
641
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mlink-content", children: [
642
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "mlink-title", children: selectedLinkedAction.label }),
643
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mlink-description", children: "Fill in the details below" })
644
+ ] }),
645
+ execError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mlink-error-banner", children: execError }),
646
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mlink-params", children: selectedLinkedAction.parameters?.map((param) => /* @__PURE__ */ jsxRuntime.jsx(
647
+ ParameterInput,
648
+ {
649
+ param,
650
+ value: paramValues[param.name] || "",
651
+ onChange: (value) => handleParamChange(param.name, value),
652
+ disabled: execStatus === "executing"
653
+ },
654
+ param.name
655
+ )) }),
656
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mlink-actions", children: [
657
+ /* @__PURE__ */ jsxRuntime.jsx(
658
+ "button",
659
+ {
660
+ className: "mlink-button",
661
+ onClick: handleExecuteWithParams,
662
+ disabled: execStatus === "executing",
663
+ children: execStatus === "executing" ? /* @__PURE__ */ jsxRuntime.jsx(MlinkSpinner, {}) : selectedLinkedAction.label
664
+ }
665
+ ),
666
+ /* @__PURE__ */ jsxRuntime.jsx(
667
+ "button",
668
+ {
669
+ className: "mlink-button mlink-button-secondary",
670
+ onClick: handleCancelParams,
671
+ disabled: execStatus === "executing",
672
+ children: "Back"
673
+ }
674
+ )
675
+ ] })
676
+ ] });
677
+ }
402
678
  return /* @__PURE__ */ jsxRuntime.jsxs(MlinkContainer, { theme: resolvedTheme, className, preset: stylePreset, children: [
403
679
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mlink-icon", children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: metadata.icon, alt: metadata.title }) }),
404
680
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mlink-content", children: [
@@ -406,7 +682,29 @@ function Mlink({
406
682
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mlink-description", children: metadata.description })
407
683
  ] }),
408
684
  execError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mlink-error-banner", children: execError }),
409
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mlink-actions", children: metadata.actions.map((action, index) => /* @__PURE__ */ jsxRuntime.jsx(
685
+ hasLinkedActions && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mlink-actions", children: [
686
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mlink-quick-actions", children: metadata.links.actions.filter((a) => !hasParameters(a)).map((action, index) => /* @__PURE__ */ jsxRuntime.jsx(
687
+ "button",
688
+ {
689
+ className: "mlink-button mlink-button-quick",
690
+ onClick: () => handleLinkedAction(action),
691
+ disabled: metadata.disabled || action.disabled || execStatus === "executing",
692
+ children: execStatus === "executing" ? /* @__PURE__ */ jsxRuntime.jsx(MlinkSpinner, {}) : action.label
693
+ },
694
+ `${action.href}-${index}`
695
+ )) }),
696
+ metadata.links.actions.filter((a) => hasParameters(a)).map((action, index) => /* @__PURE__ */ jsxRuntime.jsx(
697
+ "button",
698
+ {
699
+ className: "mlink-button mlink-button-custom",
700
+ onClick: () => handleLinkedAction(action),
701
+ disabled: metadata.disabled || action.disabled || execStatus === "executing",
702
+ children: action.label
703
+ },
704
+ `param-${action.href}-${index}`
705
+ ))
706
+ ] }),
707
+ !hasLinkedActions && metadata.actions && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mlink-actions", children: metadata.actions.map((action, index) => /* @__PURE__ */ jsxRuntime.jsx(
410
708
  ActionButtonComponent,
411
709
  {
412
710
  action,
@@ -420,6 +718,161 @@ function Mlink({
420
718
  )) })
421
719
  ] });
422
720
  }
721
+ function ParameterInput({ param, value, onChange, disabled }) {
722
+ const strValue = Array.isArray(value) ? value.join(",") : value;
723
+ if (isSelectableParam(param)) {
724
+ return /* @__PURE__ */ jsxRuntime.jsx(
725
+ SelectableParamInput,
726
+ {
727
+ param,
728
+ value,
729
+ onChange,
730
+ disabled
731
+ }
732
+ );
733
+ }
734
+ const inputType = getInputType(param.type);
735
+ if (param.type === "textarea") {
736
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mlink-param-group", children: [
737
+ param.label && /* @__PURE__ */ jsxRuntime.jsx("label", { className: "mlink-param-label", children: param.label }),
738
+ /* @__PURE__ */ jsxRuntime.jsx(
739
+ "textarea",
740
+ {
741
+ className: "mlink-textarea",
742
+ value: strValue,
743
+ onChange: (e) => onChange(e.target.value),
744
+ disabled,
745
+ required: param.required
746
+ }
747
+ )
748
+ ] });
749
+ }
750
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mlink-param-group", children: [
751
+ param.label && /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "mlink-param-label", children: [
752
+ param.label,
753
+ param.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mlink-required", children: "*" })
754
+ ] }),
755
+ /* @__PURE__ */ jsxRuntime.jsx(
756
+ "input",
757
+ {
758
+ type: inputType,
759
+ className: "mlink-input",
760
+ value: strValue,
761
+ onChange: (e) => onChange(e.target.value),
762
+ disabled,
763
+ required: param.required,
764
+ pattern: param.pattern,
765
+ min: param.min?.toString(),
766
+ max: param.max?.toString(),
767
+ placeholder: param.label || param.name
768
+ }
769
+ ),
770
+ param.patternDescription && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mlink-param-hint", children: param.patternDescription })
771
+ ] });
772
+ }
773
+ function SelectableParamInput({
774
+ param,
775
+ value,
776
+ onChange,
777
+ disabled
778
+ }) {
779
+ const arrayValue = Array.isArray(value) ? value : value ? [value] : [];
780
+ if (param.type === "select") {
781
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mlink-param-group", children: [
782
+ param.label && /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "mlink-param-label", children: [
783
+ param.label,
784
+ param.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mlink-required", children: "*" })
785
+ ] }),
786
+ /* @__PURE__ */ jsxRuntime.jsxs(
787
+ "select",
788
+ {
789
+ className: "mlink-select",
790
+ value: arrayValue[0] || "",
791
+ onChange: (e) => onChange(e.target.value),
792
+ disabled,
793
+ required: param.required,
794
+ children: [
795
+ /* @__PURE__ */ jsxRuntime.jsxs("option", { value: "", children: [
796
+ "Select ",
797
+ param.label || param.name
798
+ ] }),
799
+ param.options.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: opt.value, children: opt.label }, opt.value))
800
+ ]
801
+ }
802
+ )
803
+ ] });
804
+ }
805
+ if (param.type === "radio") {
806
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mlink-param-group", children: [
807
+ param.label && /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "mlink-param-label", children: [
808
+ param.label,
809
+ param.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mlink-required", children: "*" })
810
+ ] }),
811
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mlink-radio-group", children: param.options.map((opt) => /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "mlink-radio-label", children: [
812
+ /* @__PURE__ */ jsxRuntime.jsx(
813
+ "input",
814
+ {
815
+ type: "radio",
816
+ name: param.name,
817
+ value: opt.value,
818
+ checked: arrayValue[0] === opt.value,
819
+ onChange: (e) => onChange(e.target.value),
820
+ disabled
821
+ }
822
+ ),
823
+ opt.label
824
+ ] }, opt.value)) })
825
+ ] });
826
+ }
827
+ if (param.type === "checkbox") {
828
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mlink-param-group", children: [
829
+ param.label && /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "mlink-param-label", children: [
830
+ param.label,
831
+ param.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mlink-required", children: "*" })
832
+ ] }),
833
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mlink-checkbox-group", children: param.options.map((opt) => /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "mlink-checkbox-label", children: [
834
+ /* @__PURE__ */ jsxRuntime.jsx(
835
+ "input",
836
+ {
837
+ type: "checkbox",
838
+ value: opt.value,
839
+ checked: arrayValue.includes(opt.value),
840
+ onChange: (e) => {
841
+ if (e.target.checked) {
842
+ onChange([...arrayValue, opt.value]);
843
+ } else {
844
+ onChange(arrayValue.filter((v) => v !== opt.value));
845
+ }
846
+ },
847
+ disabled
848
+ }
849
+ ),
850
+ opt.label
851
+ ] }, opt.value)) })
852
+ ] });
853
+ }
854
+ return null;
855
+ }
856
+ function getInputType(paramType) {
857
+ switch (paramType) {
858
+ case "number":
859
+ case "amount":
860
+ return "number";
861
+ case "email":
862
+ return "email";
863
+ case "url":
864
+ return "url";
865
+ case "date":
866
+ return "date";
867
+ case "datetime-local":
868
+ return "datetime-local";
869
+ case "address":
870
+ case "token":
871
+ case "text":
872
+ default:
873
+ return "text";
874
+ }
875
+ }
423
876
  function MlinkContainer({ theme, className, preset, children }) {
424
877
  return /* @__PURE__ */ jsxRuntime.jsx(
425
878
  "div",
@@ -446,6 +899,38 @@ function MlinkError({ message }) {
446
899
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mlink-error-message", children: message })
447
900
  ] });
448
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
+ }
449
934
  function MlinkSuccess({ message, txHash, onReset }) {
450
935
  const shortHash = `${txHash.slice(0, 10)}...${txHash.slice(-8)}`;
451
936
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mlink-success", children: [