@medialane/ui 0.154.0 → 0.155.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.
@@ -1,13 +1,31 @@
1
+ import { BuildAssetMetadataInput } from '@medialane/sdk';
2
+
1
3
  interface UploadedIpfsFile {
2
4
  cid: string;
3
5
  uri: string;
4
6
  }
5
- declare function uploadFileToIpfs(file: File, token: string | null, kind?: "image" | "document" | "media"): Promise<UploadedIpfsFile>;
6
- declare function uploadJsonToIpfs(payload: unknown, token: string | null): Promise<string>;
7
+ type SignedUploadKind = "image" | "document" | "media";
8
+ declare function uploadFileToIpfs(file: File, kind?: SignedUploadKind): Promise<UploadedIpfsFile>;
9
+ declare function uploadJsonToIpfs(payload: unknown): Promise<string>;
10
+ declare function uploadDirectoryToIpfs(files: {
11
+ name: string;
12
+ content: unknown;
13
+ }[]): Promise<{
14
+ cid: string;
15
+ baseUri: string;
16
+ }>;
7
17
  declare function isUserRejection(err: unknown): boolean;
8
18
  declare function uploadFailureToast(err: unknown): {
9
19
  title: string;
10
20
  description?: string;
11
21
  };
22
+ interface PinAssetMetadataInput extends Omit<BuildAssetMetadataInput, "registrationDate"> {
23
+ imageFile?: File | null;
24
+ }
25
+ interface PinnedAsset {
26
+ uri: string;
27
+ imageUri: string | null;
28
+ }
29
+ declare function pinAssetMetadata(input: PinAssetMetadataInput): Promise<PinnedAsset>;
12
30
 
13
- export { type UploadedIpfsFile, isUserRejection, uploadFailureToast, uploadFileToIpfs, uploadJsonToIpfs };
31
+ export { type PinAssetMetadataInput, type PinnedAsset, type SignedUploadKind, type UploadedIpfsFile, isUserRejection, pinAssetMetadata, uploadDirectoryToIpfs, uploadFailureToast, uploadFileToIpfs, uploadJsonToIpfs };
@@ -1,21 +1,16 @@
1
- function authHeaders(token) {
2
- return token ? { Authorization: `Bearer ${token}` } : {};
3
- }
4
- async function uploadFileToIpfs(file, token, kind = "image") {
5
- const signedRes = await fetch("/api/pinata/signed-url", {
6
- method: "POST",
7
- headers: { "Content-Type": "application/json", ...authHeaders(token) },
8
- body: JSON.stringify({ kind })
9
- });
1
+ import { buildAssetMetadata } from "@medialane/sdk";
2
+ async function uploadFileToIpfs(file, kind = "image") {
3
+ const signedRes = await fetch(`/api/proxy/v1/metadata/signed-url?kind=${kind}`);
10
4
  const signed = await signedRes.json().catch(() => ({}));
11
- if (!signedRes.ok || !signed.url) {
5
+ const signedUrl = signed.data?.url;
6
+ if (!signedRes.ok || !signedUrl) {
12
7
  throw new Error(signed.error ?? "Failed to prepare the upload");
13
8
  }
14
9
  const formData = new FormData();
15
10
  formData.append("file", file, file.name);
16
11
  formData.append("network", "public");
17
12
  formData.append("name", file.name);
18
- const uploadRes = await fetch(signed.url, { method: "POST", body: formData });
13
+ const uploadRes = await fetch(signedUrl, { method: "POST", body: formData });
19
14
  const uploadJson = await uploadRes.json().catch(() => ({}));
20
15
  const cid = uploadJson.data?.cid;
21
16
  if (!uploadRes.ok || !cid) {
@@ -23,17 +18,30 @@ async function uploadFileToIpfs(file, token, kind = "image") {
23
18
  }
24
19
  return { cid, uri: `ipfs://${cid}` };
25
20
  }
26
- async function uploadJsonToIpfs(payload, token) {
27
- const res = await fetch("/api/pinata/json", {
21
+ async function uploadJsonToIpfs(payload) {
22
+ const res = await fetch("/api/proxy/v1/metadata/upload", {
28
23
  method: "POST",
29
- headers: { "Content-Type": "application/json", ...authHeaders(token) },
24
+ headers: { "Content-Type": "application/json" },
30
25
  body: JSON.stringify(payload)
31
26
  });
32
- const data = await res.json().catch(() => ({}));
33
- if (!res.ok || !data.uri) {
34
- throw new Error(data.error ?? "Metadata upload failed");
27
+ const body = await res.json().catch(() => ({}));
28
+ const uri = body.data?.url;
29
+ if (!res.ok || !uri) {
30
+ throw new Error(body.error ?? "Metadata upload failed");
35
31
  }
36
- return data.uri;
32
+ return uri;
33
+ }
34
+ async function uploadDirectoryToIpfs(files) {
35
+ const res = await fetch("/api/proxy/v1/metadata/upload-directory", {
36
+ method: "POST",
37
+ headers: { "Content-Type": "application/json" },
38
+ body: JSON.stringify({ files })
39
+ });
40
+ const body = await res.json().catch(() => ({}));
41
+ if (!res.ok || !body.data?.baseUri || !body.data.cid) {
42
+ throw new Error(body.error ?? "Directory pin failed");
43
+ }
44
+ return { cid: body.data.cid, baseUri: body.data.baseUri };
37
45
  }
38
46
  function isUserRejection(err) {
39
47
  const msg = err instanceof Error ? err.message : String(err ?? "");
@@ -43,7 +51,7 @@ function uploadFailureToast(err) {
43
51
  if (isUserRejection(err)) {
44
52
  return {
45
53
  title: "Signature declined",
46
- description: "Uploads need a one-time, free sign-in signature \u2014 it's not a transaction and costs nothing. Try again and approve the request in your wallet."
54
+ description: "Try again and approve the request in your wallet."
47
55
  };
48
56
  }
49
57
  return {
@@ -51,8 +59,25 @@ function uploadFailureToast(err) {
51
59
  description: err instanceof Error ? err.message : void 0
52
60
  };
53
61
  }
62
+ async function pinAssetMetadata(input) {
63
+ const { imageFile, ...fields } = input;
64
+ let imageUri = fields.imageUri ?? null;
65
+ if (!imageUri && imageFile && imageFile.size > 0) {
66
+ imageUri = (await uploadFileToIpfs(imageFile)).uri;
67
+ }
68
+ const uri = await uploadJsonToIpfs(
69
+ buildAssetMetadata({
70
+ ...fields,
71
+ imageUri,
72
+ externalUrl: fields.externalUrl || "https://medialane.io"
73
+ })
74
+ );
75
+ return { uri, imageUri };
76
+ }
54
77
  export {
55
78
  isUserRejection,
79
+ pinAssetMetadata,
80
+ uploadDirectoryToIpfs,
56
81
  uploadFailureToast,
57
82
  uploadFileToIpfs,
58
83
  uploadJsonToIpfs
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/ipfs-upload.ts"],"sourcesContent":["export interface UploadedIpfsFile {\n cid: string;\n uri: string;\n}\n\nfunction authHeaders(token: string | null): Record<string, string> {\n return token ? { Authorization: `Bearer ${token}` } : {};\n}\n\nexport async function uploadFileToIpfs(\n file: File,\n token: string | null,\n kind: \"image\" | \"document\" | \"media\" = \"image\",\n): Promise<UploadedIpfsFile> {\n const signedRes = await fetch(\"/api/pinata/signed-url\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", ...authHeaders(token) },\n body: JSON.stringify({ kind }),\n });\n const signed = (await signedRes.json().catch(() => ({}))) as { url?: string; error?: string };\n if (!signedRes.ok || !signed.url) {\n throw new Error(signed.error ?? \"Failed to prepare the upload\");\n }\n\n const formData = new FormData();\n formData.append(\"file\", file, file.name);\n formData.append(\"network\", \"public\");\n formData.append(\"name\", file.name);\n\n const uploadRes = await fetch(signed.url, { method: \"POST\", body: formData });\n const uploadJson = (await uploadRes.json().catch(() => ({}))) as { data?: { cid?: string } };\n const cid = uploadJson.data?.cid;\n if (!uploadRes.ok || !cid) {\n throw new Error(\"Upload to IPFS failed\");\n }\n\n return { cid, uri: `ipfs://${cid}` };\n}\n\nexport async function uploadJsonToIpfs(payload: unknown, token: string | null): Promise<string> {\n const res = await fetch(\"/api/pinata/json\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", ...authHeaders(token) },\n body: JSON.stringify(payload),\n });\n const data = (await res.json().catch(() => ({}))) as { uri?: string; error?: string };\n\n if (!res.ok || !data.uri) {\n throw new Error(data.error ?? \"Metadata upload failed\");\n }\n\n return data.uri;\n}\n\nexport function isUserRejection(err: unknown): boolean {\n const msg = err instanceof Error ? err.message : String(err ?? \"\");\n return /reject|denied|declin|abort|cancel|refus/i.test(msg);\n}\n\nexport function uploadFailureToast(err: unknown): { title: string; description?: string } {\n if (isUserRejection(err)) {\n return {\n title: \"Signature declined\",\n description:\n \"Uploads need a one-time, free sign-in signature — it's not a transaction and costs nothing. Try again and approve the request in your wallet.\",\n };\n }\n return {\n title: \"Upload failed\",\n description: err instanceof Error ? err.message : undefined,\n };\n}\n"],"mappings":"AAKA,SAAS,YAAY,OAA8C;AACjE,SAAO,QAAQ,EAAE,eAAe,UAAU,KAAK,GAAG,IAAI,CAAC;AACzD;AAEA,eAAsB,iBACpB,MACA,OACA,OAAuC,SACZ;AAC3B,QAAM,YAAY,MAAM,MAAM,0BAA0B;AAAA,IACtD,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,oBAAoB,GAAG,YAAY,KAAK,EAAE;AAAA,IACrE,MAAM,KAAK,UAAU,EAAE,KAAK,CAAC;AAAA,EAC/B,CAAC;AACD,QAAM,SAAU,MAAM,UAAU,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AACvD,MAAI,CAAC,UAAU,MAAM,CAAC,OAAO,KAAK;AAChC,UAAM,IAAI,MAAM,OAAO,SAAS,8BAA8B;AAAA,EAChE;AAEA,QAAM,WAAW,IAAI,SAAS;AAC9B,WAAS,OAAO,QAAQ,MAAM,KAAK,IAAI;AACvC,WAAS,OAAO,WAAW,QAAQ;AACnC,WAAS,OAAO,QAAQ,KAAK,IAAI;AAEjC,QAAM,YAAY,MAAM,MAAM,OAAO,KAAK,EAAE,QAAQ,QAAQ,MAAM,SAAS,CAAC;AAC5E,QAAM,aAAc,MAAM,UAAU,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAC3D,QAAM,MAAM,WAAW,MAAM;AAC7B,MAAI,CAAC,UAAU,MAAM,CAAC,KAAK;AACzB,UAAM,IAAI,MAAM,uBAAuB;AAAA,EACzC;AAEA,SAAO,EAAE,KAAK,KAAK,UAAU,GAAG,GAAG;AACrC;AAEA,eAAsB,iBAAiB,SAAkB,OAAuC;AAC9F,QAAM,MAAM,MAAM,MAAM,oBAAoB;AAAA,IAC1C,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,oBAAoB,GAAG,YAAY,KAAK,EAAE;AAAA,IACrE,MAAM,KAAK,UAAU,OAAO;AAAA,EAC9B,CAAC;AACD,QAAM,OAAQ,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAE/C,MAAI,CAAC,IAAI,MAAM,CAAC,KAAK,KAAK;AACxB,UAAM,IAAI,MAAM,KAAK,SAAS,wBAAwB;AAAA,EACxD;AAEA,SAAO,KAAK;AACd;AAEO,SAAS,gBAAgB,KAAuB;AACrD,QAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,OAAO,EAAE;AACjE,SAAO,2CAA2C,KAAK,GAAG;AAC5D;AAEO,SAAS,mBAAmB,KAAuD;AACxF,MAAI,gBAAgB,GAAG,GAAG;AACxB,WAAO;AAAA,MACL,OAAO;AAAA,MACP,aACE;AAAA,IACJ;AAAA,EACF;AACA,SAAO;AAAA,IACL,OAAO;AAAA,IACP,aAAa,eAAe,QAAQ,IAAI,UAAU;AAAA,EACpD;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/utils/ipfs-upload.ts"],"sourcesContent":["import { buildAssetMetadata, type BuildAssetMetadataInput } from \"@medialane/sdk\";\n\nexport interface UploadedIpfsFile {\n cid: string;\n uri: string;\n}\n\nexport type SignedUploadKind = \"image\" | \"document\" | \"media\";\n\nexport async function uploadFileToIpfs(\n file: File,\n kind: SignedUploadKind = \"image\",\n): Promise<UploadedIpfsFile> {\n const signedRes = await fetch(`/api/proxy/v1/metadata/signed-url?kind=${kind}`);\n const signed = (await signedRes.json().catch(() => ({}))) as {\n data?: { url?: string };\n error?: string;\n };\n const signedUrl = signed.data?.url;\n if (!signedRes.ok || !signedUrl) {\n throw new Error(signed.error ?? \"Failed to prepare the upload\");\n }\n\n const formData = new FormData();\n formData.append(\"file\", file, file.name);\n formData.append(\"network\", \"public\");\n formData.append(\"name\", file.name);\n\n const uploadRes = await fetch(signedUrl, { method: \"POST\", body: formData });\n const uploadJson = (await uploadRes.json().catch(() => ({}))) as { data?: { cid?: string } };\n const cid = uploadJson.data?.cid;\n if (!uploadRes.ok || !cid) {\n throw new Error(\"Upload to IPFS failed\");\n }\n\n return { cid, uri: `ipfs://${cid}` };\n}\n\nexport async function uploadJsonToIpfs(payload: unknown): Promise<string> {\n const res = await fetch(\"/api/proxy/v1/metadata/upload\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(payload),\n });\n const body = (await res.json().catch(() => ({}))) as {\n data?: { url?: string };\n error?: string;\n };\n const uri = body.data?.url;\n if (!res.ok || !uri) {\n throw new Error(body.error ?? \"Metadata upload failed\");\n }\n\n return uri;\n}\n\nexport async function uploadDirectoryToIpfs(\n files: { name: string; content: unknown }[],\n): Promise<{ cid: string; baseUri: string }> {\n const res = await fetch(\"/api/proxy/v1/metadata/upload-directory\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ files }),\n });\n const body = (await res.json().catch(() => ({}))) as {\n data?: { cid?: string; baseUri?: string };\n error?: string;\n };\n if (!res.ok || !body.data?.baseUri || !body.data.cid) {\n throw new Error(body.error ?? \"Directory pin failed\");\n }\n return { cid: body.data.cid, baseUri: body.data.baseUri };\n}\n\nexport function isUserRejection(err: unknown): boolean {\n const msg = err instanceof Error ? err.message : String(err ?? \"\");\n return /reject|denied|declin|abort|cancel|refus/i.test(msg);\n}\n\nexport function uploadFailureToast(err: unknown): { title: string; description?: string } {\n if (isUserRejection(err)) {\n return {\n title: \"Signature declined\",\n description: \"Try again and approve the request in your wallet.\",\n };\n }\n return {\n title: \"Upload failed\",\n description: err instanceof Error ? err.message : undefined,\n };\n}\n\nexport interface PinAssetMetadataInput extends Omit<BuildAssetMetadataInput, \"registrationDate\"> {\n imageFile?: File | null;\n}\n\nexport interface PinnedAsset {\n uri: string;\n imageUri: string | null;\n}\n\nexport async function pinAssetMetadata(input: PinAssetMetadataInput): Promise<PinnedAsset> {\n const { imageFile, ...fields } = input;\n\n let imageUri = fields.imageUri ?? null;\n if (!imageUri && imageFile && imageFile.size > 0) {\n imageUri = (await uploadFileToIpfs(imageFile)).uri;\n }\n\n const uri = await uploadJsonToIpfs(\n buildAssetMetadata({\n ...fields,\n imageUri,\n externalUrl: fields.externalUrl || \"https://medialane.io\",\n }),\n );\n\n return { uri, imageUri };\n}\n"],"mappings":"AAAA,SAAS,0BAAwD;AASjE,eAAsB,iBACpB,MACA,OAAyB,SACE;AAC3B,QAAM,YAAY,MAAM,MAAM,0CAA0C,IAAI,EAAE;AAC9E,QAAM,SAAU,MAAM,UAAU,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAIvD,QAAM,YAAY,OAAO,MAAM;AAC/B,MAAI,CAAC,UAAU,MAAM,CAAC,WAAW;AAC/B,UAAM,IAAI,MAAM,OAAO,SAAS,8BAA8B;AAAA,EAChE;AAEA,QAAM,WAAW,IAAI,SAAS;AAC9B,WAAS,OAAO,QAAQ,MAAM,KAAK,IAAI;AACvC,WAAS,OAAO,WAAW,QAAQ;AACnC,WAAS,OAAO,QAAQ,KAAK,IAAI;AAEjC,QAAM,YAAY,MAAM,MAAM,WAAW,EAAE,QAAQ,QAAQ,MAAM,SAAS,CAAC;AAC3E,QAAM,aAAc,MAAM,UAAU,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAC3D,QAAM,MAAM,WAAW,MAAM;AAC7B,MAAI,CAAC,UAAU,MAAM,CAAC,KAAK;AACzB,UAAM,IAAI,MAAM,uBAAuB;AAAA,EACzC;AAEA,SAAO,EAAE,KAAK,KAAK,UAAU,GAAG,GAAG;AACrC;AAEA,eAAsB,iBAAiB,SAAmC;AACxE,QAAM,MAAM,MAAM,MAAM,iCAAiC;AAAA,IACvD,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAC9C,MAAM,KAAK,UAAU,OAAO;AAAA,EAC9B,CAAC;AACD,QAAM,OAAQ,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAI/C,QAAM,MAAM,KAAK,MAAM;AACvB,MAAI,CAAC,IAAI,MAAM,CAAC,KAAK;AACnB,UAAM,IAAI,MAAM,KAAK,SAAS,wBAAwB;AAAA,EACxD;AAEA,SAAO;AACT;AAEA,eAAsB,sBACpB,OAC2C;AAC3C,QAAM,MAAM,MAAM,MAAM,2CAA2C;AAAA,IACjE,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAC9C,MAAM,KAAK,UAAU,EAAE,MAAM,CAAC;AAAA,EAChC,CAAC;AACD,QAAM,OAAQ,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAI/C,MAAI,CAAC,IAAI,MAAM,CAAC,KAAK,MAAM,WAAW,CAAC,KAAK,KAAK,KAAK;AACpD,UAAM,IAAI,MAAM,KAAK,SAAS,sBAAsB;AAAA,EACtD;AACA,SAAO,EAAE,KAAK,KAAK,KAAK,KAAK,SAAS,KAAK,KAAK,QAAQ;AAC1D;AAEO,SAAS,gBAAgB,KAAuB;AACrD,QAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,OAAO,EAAE;AACjE,SAAO,2CAA2C,KAAK,GAAG;AAC5D;AAEO,SAAS,mBAAmB,KAAuD;AACxF,MAAI,gBAAgB,GAAG,GAAG;AACxB,WAAO;AAAA,MACL,OAAO;AAAA,MACP,aAAa;AAAA,IACf;AAAA,EACF;AACA,SAAO;AAAA,IACL,OAAO;AAAA,IACP,aAAa,eAAe,QAAQ,IAAI,UAAU;AAAA,EACpD;AACF;AAWA,eAAsB,iBAAiB,OAAoD;AACzF,QAAM,EAAE,WAAW,GAAG,OAAO,IAAI;AAEjC,MAAI,WAAW,OAAO,YAAY;AAClC,MAAI,CAAC,YAAY,aAAa,UAAU,OAAO,GAAG;AAChD,gBAAY,MAAM,iBAAiB,SAAS,GAAG;AAAA,EACjD;AAEA,QAAM,MAAM,MAAM;AAAA,IAChB,mBAAmB;AAAA,MACjB,GAAG;AAAA,MACH;AAAA,MACA,aAAa,OAAO,eAAe;AAAA,IACrC,CAAC;AAAA,EACH;AAEA,SAAO,EAAE,KAAK,SAAS;AACzB;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@medialane/ui",
3
- "version": "0.154.0",
3
+ "version": "0.155.0",
4
4
  "description": "Shared UI components for Medialane apps",
5
5
  "type": "module",
6
6
  "sideEffects": false,