@arcadiasystems/morse-uploader 0.1.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/ui.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ import { o as MorseFileDownloaderProps, p as MorseFileUploaderProps } from './types-COaFRpWK.js';
2
+ import { ReactElement } from 'react';
3
+ import '@arcadiasystems/morse-sdk';
4
+ import '@mysten/seal';
5
+ import '@mysten/sui/cryptography';
6
+ import '@mysten/sui/grpc';
7
+ import '@mysten/sui/transactions';
8
+
9
+ /**
10
+ * Drop-in single-file viewer/downloader for a share link. Loads the on-chain
11
+ * metadata, then downloads (public read) or decrypts (recipient) the bytes with
12
+ * the correct filename and MIME type. A RecipientFile has no on-chain encrypted
13
+ * flag, so encryption is inferred from Seal material in the share link. Logic
14
+ * lives in {@link useFileDownload}.
15
+ */
16
+ declare function MorseFileDownloader(props: MorseFileDownloaderProps): ReactElement;
17
+
18
+ /**
19
+ * Drop-in file uploader for the 0.4.0 RecipientFile flow. Pick a file, choose a
20
+ * storage duration, and upload. Encryption and the recipient set are controlled
21
+ * by props (`encrypt`, `recipients`); the connected wallet is auto-added as a
22
+ * recipient on chain. Emits the completed upload (with seal material and share
23
+ * link) via `onUploaded`. All logic lives in hooks; this component only renders.
24
+ */
25
+ declare function MorseFileUploader(props: MorseFileUploaderProps): ReactElement;
26
+
27
+ export { MorseFileDownloader, MorseFileDownloaderProps, MorseFileUploader, MorseFileUploaderProps };
package/dist/ui.js ADDED
@@ -0,0 +1,225 @@
1
+ import { useFileDownload, formatBytes, useFileUpload, useClipboard, useStorageCostEstimate, useDropzone, uploadPhases, formatUsd, uploadPhaseLabel } from './chunk-2FYBTRTH.js';
2
+ import { formatUserMessage } from '@arcadiasystems/morse-sdk';
3
+ import { useMemo, useState } from 'react';
4
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
+
6
+ function MorseFileDownloader(props) {
7
+ const { fileId, sealIdPrefix, sealNonce, className } = props;
8
+ const seal = useMemo(() => {
9
+ if (sealIdPrefix === void 0 || sealIdPrefix === null) {
10
+ return null;
11
+ }
12
+ if (sealNonce === void 0 || sealNonce === null) {
13
+ return null;
14
+ }
15
+ return { sealIdPrefix, sealNonce };
16
+ }, [sealIdPrefix, sealNonce]);
17
+ const dl = useFileDownload(fileId, seal);
18
+ const { file } = dl;
19
+ if (dl.metaStatus === "loading" || dl.metaStatus === "idle") {
20
+ return /* @__PURE__ */ jsx("section", { className: `mu-view ${className ?? ""}`, "data-mu": "view", children: /* @__PURE__ */ jsx("span", { className: "mu-muted", children: "Loading file..." }) });
21
+ }
22
+ if (dl.metaStatus === "error" || file === null) {
23
+ return /* @__PURE__ */ jsx("section", { className: `mu-view ${className ?? ""}`, "data-mu": "view", children: /* @__PURE__ */ jsx("p", { className: "mu-error", role: "alert", children: "Could not load this file. The id may be wrong or the record may have been deleted." }) });
24
+ }
25
+ const bytesError = dl.error === null ? null : formatUserMessage(dl.error);
26
+ return /* @__PURE__ */ jsxs("section", { className: `mu-view ${className ?? ""}`, "data-mu": "view", children: [
27
+ /* @__PURE__ */ jsxs("header", { className: "mu-view-head", children: [
28
+ /* @__PURE__ */ jsx("strong", { className: "mu-view-name", children: file.name }),
29
+ /* @__PURE__ */ jsxs("span", { className: "mu-muted", children: [
30
+ file.contentType,
31
+ " \xB7 ",
32
+ formatBytes(file.size),
33
+ dl.encrypted ? " \xB7 encrypted" : ""
34
+ ] })
35
+ ] }),
36
+ /* @__PURE__ */ jsxs("div", { className: "mu-view-body", children: [
37
+ dl.status === "ready" && dl.isImage && dl.objectUrl !== null ? /* @__PURE__ */ jsx("img", { className: "mu-view-img", src: dl.objectUrl, alt: file.name }) : null,
38
+ dl.status === "ready" ? /* @__PURE__ */ jsx("button", { type: "button", className: "mu-upload", onClick: () => dl.save(), children: "Save file" }) : /* @__PURE__ */ jsx(
39
+ "button",
40
+ {
41
+ type: "button",
42
+ className: "mu-upload",
43
+ disabled: dl.status === "loading",
44
+ onClick: () => {
45
+ void (dl.isImage ? dl.load() : dl.download());
46
+ },
47
+ children: dl.status === "loading" ? dl.encrypted ? "Decrypting..." : "Downloading..." : dl.encrypted ? "Decrypt and open" : "Download"
48
+ }
49
+ ),
50
+ bytesError !== null ? /* @__PURE__ */ jsxs("div", { className: "mu-error", role: "alert", children: [
51
+ /* @__PURE__ */ jsx("strong", { children: bytesError.title }),
52
+ /* @__PURE__ */ jsx("span", { children: bytesError.description })
53
+ ] }) : null
54
+ ] })
55
+ ] });
56
+ }
57
+
58
+ // src/utils/clamp.ts
59
+ function clamp(value, min, max) {
60
+ if (value < min) {
61
+ return min;
62
+ }
63
+ if (value > max) {
64
+ return max;
65
+ }
66
+ return value;
67
+ }
68
+ var DEFAULT_EPOCHS = 5;
69
+ var WALRUS_MAX_EPOCHS = 53;
70
+ function MorseFileUploader(props) {
71
+ const {
72
+ className,
73
+ recipients,
74
+ encrypt = false,
75
+ defaultEpochs,
76
+ minEpochs = 1,
77
+ maxEpochs = WALRUS_MAX_EPOCHS,
78
+ onUploaded
79
+ } = props;
80
+ const [file, setFile] = useState(null);
81
+ const [epochs, setEpochs] = useState(defaultEpochs ?? DEFAULT_EPOCHS);
82
+ const upload = useFileUpload();
83
+ const clipboard = useClipboard();
84
+ const { estimate } = useStorageCostEstimate({
85
+ sizeBytes: file?.size ?? 0,
86
+ epochs,
87
+ encrypt
88
+ });
89
+ const { getRootProps, getInputProps } = useDropzone({
90
+ multiple: false,
91
+ ariaLabel: "Choose a file to upload",
92
+ onFiles: (files) => setFile(files[0] ?? null)
93
+ });
94
+ const handleUpload = async () => {
95
+ if (file === null) {
96
+ return;
97
+ }
98
+ const result = await upload.upload({
99
+ file,
100
+ epochs,
101
+ encrypt,
102
+ ...recipients === void 0 ? {} : { recipients }
103
+ });
104
+ onUploaded?.(result);
105
+ };
106
+ const handleReset = () => {
107
+ upload.reset();
108
+ setFile(null);
109
+ };
110
+ const phases = uploadPhases(encrypt);
111
+ const activeIndex = upload.phase === null ? -1 : phases.indexOf(upload.phase);
112
+ const errorMessage = upload.error === null ? null : formatUserMessage(upload.error);
113
+ return /* @__PURE__ */ jsxs("div", { className: `mu-uploader ${className ?? ""}`, "data-mu": "uploader", children: [
114
+ /* @__PURE__ */ jsxs("div", { className: "mu-dropzone", ...getRootProps(), children: [
115
+ /* @__PURE__ */ jsx("input", { className: "mu-input", ...getInputProps() }),
116
+ /* @__PURE__ */ jsx("span", { className: "mu-dropzone-icon", "aria-hidden": "true" }),
117
+ file === null ? /* @__PURE__ */ jsxs(Fragment, { children: [
118
+ /* @__PURE__ */ jsx("span", { className: "mu-dropzone-hint", children: "Drag a file here, or click to browse" }),
119
+ /* @__PURE__ */ jsx("span", { className: "mu-dropzone-sub", children: "Any file type" })
120
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
121
+ /* @__PURE__ */ jsx("span", { className: "mu-dropzone-hint", children: file.name }),
122
+ /* @__PURE__ */ jsxs("span", { className: "mu-dropzone-sub", children: [
123
+ formatBytes(file.size),
124
+ " \xB7 click to replace"
125
+ ] })
126
+ ] })
127
+ ] }),
128
+ /* @__PURE__ */ jsxs("label", { className: "mu-field", children: [
129
+ /* @__PURE__ */ jsx("span", { className: "mu-field-label", children: "Storage duration (epochs)" }),
130
+ /* @__PURE__ */ jsx(
131
+ "input",
132
+ {
133
+ className: "mu-epochs-input",
134
+ type: "number",
135
+ min: minEpochs,
136
+ max: maxEpochs,
137
+ value: epochs,
138
+ onChange: (event) => setEpochs(
139
+ clamp(
140
+ Number.parseInt(event.target.value, 10) || minEpochs,
141
+ minEpochs,
142
+ maxEpochs
143
+ )
144
+ )
145
+ }
146
+ ),
147
+ /* @__PURE__ */ jsx(
148
+ "span",
149
+ {
150
+ className: "mu-field-help",
151
+ title: `Walrus storage is a lease, not permanent. You can buy at most ${maxEpochs} epochs ahead. An epoch is about 1 day on testnet and about 2 weeks on mainnet.`,
152
+ children: `\u2248 ${Math.round(estimate.days)} day${Math.round(estimate.days) === 1 ? "" : "s"} of storage \xB7 max ${maxEpochs} epochs`
153
+ }
154
+ )
155
+ ] }),
156
+ /* @__PURE__ */ jsxs("div", { className: "mu-cost", "data-mu": "cost", children: [
157
+ /* @__PURE__ */ jsx("span", { className: "mu-cost-label", children: encrypt ? "Estimated storage cost (encrypted)" : "Estimated storage cost" }),
158
+ /* @__PURE__ */ jsx("span", { className: "mu-cost-value", children: formatUsd(estimate.usd) })
159
+ ] }),
160
+ /* @__PURE__ */ jsx(
161
+ "button",
162
+ {
163
+ type: "button",
164
+ className: "mu-upload",
165
+ disabled: file === null || upload.status === "uploading",
166
+ onClick: () => {
167
+ void handleUpload();
168
+ },
169
+ children: upload.status === "uploading" ? "Uploading..." : encrypt ? "Encrypt and upload" : "Upload"
170
+ }
171
+ ),
172
+ upload.status === "uploading" ? /* @__PURE__ */ jsx("ol", { className: "mu-stepper", "data-mu": "stepper", children: phases.map((phase, index) => /* @__PURE__ */ jsxs(
173
+ "li",
174
+ {
175
+ className: "mu-step",
176
+ "data-state": index < activeIndex ? "done" : index === activeIndex ? "active" : "pending",
177
+ children: [
178
+ /* @__PURE__ */ jsx("span", { className: "mu-step-dot", "aria-hidden": "true", children: index + 1 }),
179
+ /* @__PURE__ */ jsx("span", { className: "mu-step-label", children: uploadPhaseLabel(phase) })
180
+ ]
181
+ },
182
+ phase
183
+ )) }) : null,
184
+ errorMessage !== null ? /* @__PURE__ */ jsxs("div", { className: "mu-error", role: "alert", children: [
185
+ /* @__PURE__ */ jsx("strong", { children: errorMessage.title }),
186
+ /* @__PURE__ */ jsx("span", { children: errorMessage.description })
187
+ ] }) : null,
188
+ upload.data !== null ? /* @__PURE__ */ jsxs("div", { className: "mu-result", "data-mu": "result", children: [
189
+ /* @__PURE__ */ jsxs("span", { className: "mu-result-head", children: [
190
+ /* @__PURE__ */ jsx("span", { className: "mu-result-badge", "aria-hidden": "true", children: "\u2713" }),
191
+ /* @__PURE__ */ jsx("strong", { children: upload.data.encrypted ? "Encrypted and uploaded" : "Uploaded" })
192
+ ] }),
193
+ /* @__PURE__ */ jsxs("div", { className: "mu-result-actions", children: [
194
+ /* @__PURE__ */ jsx(
195
+ "a",
196
+ {
197
+ className: "mu-upload mu-result-link",
198
+ href: upload.data.shareLink,
199
+ target: "_blank",
200
+ rel: "noreferrer",
201
+ children: "Open share link"
202
+ }
203
+ ),
204
+ /* @__PURE__ */ jsx(
205
+ "button",
206
+ {
207
+ type: "button",
208
+ className: "mu-ghost mu-result-copy",
209
+ onClick: () => {
210
+ void clipboard.copy(upload.data?.shareLink ?? "");
211
+ },
212
+ children: clipboard.copied ? "Copied!" : "Copy link"
213
+ }
214
+ ),
215
+ /* @__PURE__ */ jsx("button", { type: "button", className: "mu-ghost", onClick: handleReset, children: "Upload another" })
216
+ ] }),
217
+ /* @__PURE__ */ jsx("code", { className: "mu-result-id", children: upload.data.fileId }),
218
+ upload.data.encrypted ? /* @__PURE__ */ jsx("span", { className: "mu-result-note", children: "The share link carries the decryption key; only recipients can open it." }) : null
219
+ ] }) : null
220
+ ] });
221
+ }
222
+
223
+ export { MorseFileDownloader, MorseFileUploader };
224
+ //# sourceMappingURL=ui.js.map
225
+ //# sourceMappingURL=ui.js.map
package/dist/ui.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ui/morse-file-downloader.tsx","../src/utils/clamp.ts","../src/ui/morse-file-uploader.tsx"],"names":["formatUserMessage","jsxs","jsx"],"mappings":"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","file":"ui.js","sourcesContent":["import { formatUserMessage } from \"@arcadiasystems/morse-sdk\";\nimport { type ReactElement, useMemo } from \"react\";\nimport type { MorseFileDownloaderProps, SealMaterial } from \"../files/types.js\";\nimport { useFileDownload } from \"../files/use-file-download.js\";\nimport { formatBytes } from \"../utils/format-bytes.js\";\n\n/**\n * Drop-in single-file viewer/downloader for a share link. Loads the on-chain\n * metadata, then downloads (public read) or decrypts (recipient) the bytes with\n * the correct filename and MIME type. A RecipientFile has no on-chain encrypted\n * flag, so encryption is inferred from Seal material in the share link. Logic\n * lives in {@link useFileDownload}.\n */\nexport function MorseFileDownloader(\n\tprops: MorseFileDownloaderProps,\n): ReactElement {\n\tconst { fileId, sealIdPrefix, sealNonce, className } = props;\n\tconst seal = useMemo<SealMaterial | null>(() => {\n\t\tif (sealIdPrefix === undefined || sealIdPrefix === null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (sealNonce === undefined || sealNonce === null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn { sealIdPrefix, sealNonce };\n\t}, [sealIdPrefix, sealNonce]);\n\n\tconst dl = useFileDownload(fileId, seal);\n\tconst { file } = dl;\n\n\tif (dl.metaStatus === \"loading\" || dl.metaStatus === \"idle\") {\n\t\treturn (\n\t\t\t<section className={`mu-view ${className ?? \"\"}`} data-mu=\"view\">\n\t\t\t\t<span className=\"mu-muted\">Loading file...</span>\n\t\t\t</section>\n\t\t);\n\t}\n\n\tif (dl.metaStatus === \"error\" || file === null) {\n\t\treturn (\n\t\t\t<section className={`mu-view ${className ?? \"\"}`} data-mu=\"view\">\n\t\t\t\t<p className=\"mu-error\" role=\"alert\">\n\t\t\t\t\tCould not load this file. The id may be wrong or the record may have\n\t\t\t\t\tbeen deleted.\n\t\t\t\t</p>\n\t\t\t</section>\n\t\t);\n\t}\n\n\tconst bytesError = dl.error === null ? null : formatUserMessage(dl.error);\n\n\treturn (\n\t\t<section className={`mu-view ${className ?? \"\"}`} data-mu=\"view\">\n\t\t\t<header className=\"mu-view-head\">\n\t\t\t\t<strong className=\"mu-view-name\">{file.name}</strong>\n\t\t\t\t<span className=\"mu-muted\">\n\t\t\t\t\t{file.contentType} · {formatBytes(file.size)}\n\t\t\t\t\t{dl.encrypted ? \" · encrypted\" : \"\"}\n\t\t\t\t</span>\n\t\t\t</header>\n\n\t\t\t<div className=\"mu-view-body\">\n\t\t\t\t{dl.status === \"ready\" && dl.isImage && dl.objectUrl !== null ? (\n\t\t\t\t\t<img className=\"mu-view-img\" src={dl.objectUrl} alt={file.name} />\n\t\t\t\t) : null}\n\n\t\t\t\t{dl.status === \"ready\" ? (\n\t\t\t\t\t<button type=\"button\" className=\"mu-upload\" onClick={() => dl.save()}>\n\t\t\t\t\t\tSave file\n\t\t\t\t\t</button>\n\t\t\t\t) : (\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclassName=\"mu-upload\"\n\t\t\t\t\t\tdisabled={dl.status === \"loading\"}\n\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\tvoid (dl.isImage ? dl.load() : dl.download());\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t{dl.status === \"loading\"\n\t\t\t\t\t\t\t? dl.encrypted\n\t\t\t\t\t\t\t\t? \"Decrypting...\"\n\t\t\t\t\t\t\t\t: \"Downloading...\"\n\t\t\t\t\t\t\t: dl.encrypted\n\t\t\t\t\t\t\t\t? \"Decrypt and open\"\n\t\t\t\t\t\t\t\t: \"Download\"}\n\t\t\t\t\t</button>\n\t\t\t\t)}\n\n\t\t\t\t{bytesError !== null ? (\n\t\t\t\t\t<div className=\"mu-error\" role=\"alert\">\n\t\t\t\t\t\t<strong>{bytesError.title}</strong>\n\t\t\t\t\t\t<span>{bytesError.description}</span>\n\t\t\t\t\t</div>\n\t\t\t\t) : null}\n\t\t\t</div>\n\t\t</section>\n\t);\n}\n","/** Clamp a number to the inclusive [min, max] range. */\nexport function clamp(value: number, min: number, max: number): number {\n\tif (value < min) {\n\t\treturn min;\n\t}\n\tif (value > max) {\n\t\treturn max;\n\t}\n\treturn value;\n}\n","import { formatUserMessage } from \"@arcadiasystems/morse-sdk\";\nimport { type ReactElement, useState } from \"react\";\nimport type { MorseFileUploaderProps } from \"../files/types.js\";\nimport { uploadPhaseLabel } from \"../files/upload-phase-label.js\";\nimport { uploadPhases } from \"../files/upload-phases.js\";\nimport { useFileUpload } from \"../files/use-file-upload.js\";\nimport { useStorageCostEstimate } from \"../files/use-storage-cost-estimate.js\";\nimport { useClipboard } from \"../primitives/use-clipboard.js\";\nimport { useDropzone } from \"../primitives/use-dropzone.js\";\nimport { clamp } from \"../utils/clamp.js\";\nimport { formatBytes } from \"../utils/format-bytes.js\";\nimport { formatUsd } from \"../utils/format-usd.js\";\n\nconst DEFAULT_EPOCHS = 5;\n// Walrus caps a lease at 53 epochs ahead on both networks.\nconst WALRUS_MAX_EPOCHS = 53;\n\n/**\n * Drop-in file uploader for the 0.4.0 RecipientFile flow. Pick a file, choose a\n * storage duration, and upload. Encryption and the recipient set are controlled\n * by props (`encrypt`, `recipients`); the connected wallet is auto-added as a\n * recipient on chain. Emits the completed upload (with seal material and share\n * link) via `onUploaded`. All logic lives in hooks; this component only renders.\n */\nexport function MorseFileUploader(props: MorseFileUploaderProps): ReactElement {\n\tconst {\n\t\tclassName,\n\t\trecipients,\n\t\tencrypt = false,\n\t\tdefaultEpochs,\n\t\tminEpochs = 1,\n\t\tmaxEpochs = WALRUS_MAX_EPOCHS,\n\t\tonUploaded,\n\t} = props;\n\n\tconst [file, setFile] = useState<File | null>(null);\n\tconst [epochs, setEpochs] = useState(defaultEpochs ?? DEFAULT_EPOCHS);\n\tconst upload = useFileUpload();\n\tconst clipboard = useClipboard();\n\n\tconst { estimate } = useStorageCostEstimate({\n\t\tsizeBytes: file?.size ?? 0,\n\t\tepochs,\n\t\tencrypt,\n\t});\n\n\tconst { getRootProps, getInputProps } = useDropzone({\n\t\tmultiple: false,\n\t\tariaLabel: \"Choose a file to upload\",\n\t\tonFiles: (files) => setFile(files[0] ?? null),\n\t});\n\n\tconst handleUpload = async () => {\n\t\tif (file === null) {\n\t\t\treturn;\n\t\t}\n\t\tconst result = await upload.upload({\n\t\t\tfile,\n\t\t\tepochs,\n\t\t\tencrypt,\n\t\t\t...(recipients === undefined ? {} : { recipients }),\n\t\t});\n\t\tonUploaded?.(result);\n\t};\n\n\tconst handleReset = () => {\n\t\tupload.reset();\n\t\tsetFile(null);\n\t};\n\n\tconst phases = uploadPhases(encrypt);\n\tconst activeIndex = upload.phase === null ? -1 : phases.indexOf(upload.phase);\n\tconst errorMessage =\n\t\tupload.error === null ? null : formatUserMessage(upload.error);\n\n\treturn (\n\t\t<div className={`mu-uploader ${className ?? \"\"}`} data-mu=\"uploader\">\n\t\t\t<div className=\"mu-dropzone\" {...getRootProps()}>\n\t\t\t\t<input className=\"mu-input\" {...getInputProps()} />\n\t\t\t\t<span className=\"mu-dropzone-icon\" aria-hidden=\"true\" />\n\t\t\t\t{file === null ? (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<span className=\"mu-dropzone-hint\">\n\t\t\t\t\t\t\tDrag a file here, or click to browse\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span className=\"mu-dropzone-sub\">Any file type</span>\n\t\t\t\t\t</>\n\t\t\t\t) : (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<span className=\"mu-dropzone-hint\">{file.name}</span>\n\t\t\t\t\t\t<span className=\"mu-dropzone-sub\">\n\t\t\t\t\t\t\t{formatBytes(file.size)} · click to replace\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t</div>\n\n\t\t\t<label className=\"mu-field\">\n\t\t\t\t<span className=\"mu-field-label\">Storage duration (epochs)</span>\n\t\t\t\t<input\n\t\t\t\t\tclassName=\"mu-epochs-input\"\n\t\t\t\t\ttype=\"number\"\n\t\t\t\t\tmin={minEpochs}\n\t\t\t\t\tmax={maxEpochs}\n\t\t\t\t\tvalue={epochs}\n\t\t\t\t\tonChange={(event) =>\n\t\t\t\t\t\tsetEpochs(\n\t\t\t\t\t\t\tclamp(\n\t\t\t\t\t\t\t\tNumber.parseInt(event.target.value, 10) || minEpochs,\n\t\t\t\t\t\t\t\tminEpochs,\n\t\t\t\t\t\t\t\tmaxEpochs,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t/>\n\t\t\t\t<span\n\t\t\t\t\tclassName=\"mu-field-help\"\n\t\t\t\t\ttitle={`Walrus storage is a lease, not permanent. You can buy at most ${maxEpochs} epochs ahead. An epoch is about 1 day on testnet and about 2 weeks on mainnet.`}\n\t\t\t\t>\n\t\t\t\t\t{`≈ ${Math.round(estimate.days)} day${\n\t\t\t\t\t\tMath.round(estimate.days) === 1 ? \"\" : \"s\"\n\t\t\t\t\t} of storage · max ${maxEpochs} epochs`}\n\t\t\t\t</span>\n\t\t\t</label>\n\n\t\t\t<div className=\"mu-cost\" data-mu=\"cost\">\n\t\t\t\t<span className=\"mu-cost-label\">\n\t\t\t\t\t{encrypt\n\t\t\t\t\t\t? \"Estimated storage cost (encrypted)\"\n\t\t\t\t\t\t: \"Estimated storage cost\"}\n\t\t\t\t</span>\n\t\t\t\t<span className=\"mu-cost-value\">{formatUsd(estimate.usd)}</span>\n\t\t\t</div>\n\n\t\t\t<button\n\t\t\t\ttype=\"button\"\n\t\t\t\tclassName=\"mu-upload\"\n\t\t\t\tdisabled={file === null || upload.status === \"uploading\"}\n\t\t\t\tonClick={() => {\n\t\t\t\t\tvoid handleUpload();\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{upload.status === \"uploading\"\n\t\t\t\t\t? \"Uploading...\"\n\t\t\t\t\t: encrypt\n\t\t\t\t\t\t? \"Encrypt and upload\"\n\t\t\t\t\t\t: \"Upload\"}\n\t\t\t</button>\n\n\t\t\t{upload.status === \"uploading\" ? (\n\t\t\t\t<ol className=\"mu-stepper\" data-mu=\"stepper\">\n\t\t\t\t\t{phases.map((phase, index) => (\n\t\t\t\t\t\t<li\n\t\t\t\t\t\t\tkey={phase}\n\t\t\t\t\t\t\tclassName=\"mu-step\"\n\t\t\t\t\t\t\tdata-state={\n\t\t\t\t\t\t\t\tindex < activeIndex\n\t\t\t\t\t\t\t\t\t? \"done\"\n\t\t\t\t\t\t\t\t\t: index === activeIndex\n\t\t\t\t\t\t\t\t\t\t? \"active\"\n\t\t\t\t\t\t\t\t\t\t: \"pending\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<span className=\"mu-step-dot\" aria-hidden=\"true\">\n\t\t\t\t\t\t\t\t{index + 1}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t<span className=\"mu-step-label\">{uploadPhaseLabel(phase)}</span>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t))}\n\t\t\t\t</ol>\n\t\t\t) : null}\n\n\t\t\t{errorMessage !== null ? (\n\t\t\t\t<div className=\"mu-error\" role=\"alert\">\n\t\t\t\t\t<strong>{errorMessage.title}</strong>\n\t\t\t\t\t<span>{errorMessage.description}</span>\n\t\t\t\t</div>\n\t\t\t) : null}\n\n\t\t\t{upload.data !== null ? (\n\t\t\t\t<div className=\"mu-result\" data-mu=\"result\">\n\t\t\t\t\t<span className=\"mu-result-head\">\n\t\t\t\t\t\t<span className=\"mu-result-badge\" aria-hidden=\"true\">\n\t\t\t\t\t\t\t✓\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<strong>\n\t\t\t\t\t\t\t{upload.data.encrypted ? \"Encrypted and uploaded\" : \"Uploaded\"}\n\t\t\t\t\t\t</strong>\n\t\t\t\t\t</span>\n\t\t\t\t\t<div className=\"mu-result-actions\">\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\tclassName=\"mu-upload mu-result-link\"\n\t\t\t\t\t\t\thref={upload.data.shareLink}\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tOpen share link\n\t\t\t\t\t\t</a>\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclassName=\"mu-ghost mu-result-copy\"\n\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\tvoid clipboard.copy(upload.data?.shareLink ?? \"\");\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{clipboard.copied ? \"Copied!\" : \"Copy link\"}\n\t\t\t\t\t\t</button>\n\t\t\t\t\t\t<button type=\"button\" className=\"mu-ghost\" onClick={handleReset}>\n\t\t\t\t\t\t\tUpload another\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</div>\n\t\t\t\t\t<code className=\"mu-result-id\">{upload.data.fileId}</code>\n\t\t\t\t\t{upload.data.encrypted ? (\n\t\t\t\t\t\t<span className=\"mu-result-note\">\n\t\t\t\t\t\t\tThe share link carries the decryption key; only recipients can\n\t\t\t\t\t\t\topen it.\n\t\t\t\t\t\t</span>\n\t\t\t\t\t) : null}\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t</div>\n\t);\n}\n"]}
@@ -0,0 +1,29 @@
1
+ import { Transaction } from '@mysten/sui/transactions';
2
+ import { WalletAdapter, SuiAddress, TransactionExecutor, ObjectReader, TxReceipt, SimulationReturnValues } from '@arcadiasystems/morse-sdk';
3
+
4
+ /**
5
+ * A wallet's sign-and-execute callback, e.g. dapp-kit's
6
+ * `useSignAndExecuteTransaction().mutateAsync`. Returns the executed digest.
7
+ */
8
+ type WalletSignAndExecute = (input: {
9
+ transaction: Transaction;
10
+ }) => Promise<{
11
+ digest: string;
12
+ }>;
13
+
14
+ /**
15
+ * Browser `WalletAdapter` for morse-sdk ops, backed by a wallet's
16
+ * sign-and-execute callback (e.g. dapp-kit). Vendored here as an optional
17
+ * helper so consumers do not hand-copy it. The user's key never leaves the
18
+ * wallet; the dapp-kit wiring stays in the host app.
19
+ */
20
+ declare class WalletStandardAdapter implements WalletAdapter {
21
+ private readonly signAndExecute;
22
+ private readonly client;
23
+ readonly address: SuiAddress;
24
+ constructor(address: string, signAndExecute: WalletSignAndExecute, client: TransactionExecutor & ObjectReader);
25
+ signAndExecuteTransaction(tx: Transaction, signal?: AbortSignal): Promise<TxReceipt>;
26
+ simulateTransaction(tx: Transaction, signal?: AbortSignal): Promise<SimulationReturnValues>;
27
+ }
28
+
29
+ export { type WalletSignAndExecute, WalletStandardAdapter };
@@ -0,0 +1,3 @@
1
+ export { WalletStandardAdapter } from './chunk-A2AMSP5S.js';
2
+ //# sourceMappingURL=wallet-standard.js.map
3
+ //# sourceMappingURL=wallet-standard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"wallet-standard.js"}
package/package.json ADDED
@@ -0,0 +1,116 @@
1
+ {
2
+ "name": "@arcadiasystems/morse-uploader",
3
+ "version": "0.1.0",
4
+ "description": "Headless-first React components and hooks for encrypted file sharing on Sui and Walrus, built on morse-sdk.",
5
+ "license": "MIT",
6
+ "author": "Arcadia Systems",
7
+ "type": "module",
8
+ "workspaces": [
9
+ "examples/*"
10
+ ],
11
+ "sideEffects": [
12
+ "**/*.css"
13
+ ],
14
+ "publishConfig": {
15
+ "access": "public",
16
+ "provenance": true
17
+ },
18
+ "keywords": [
19
+ "sui",
20
+ "walrus",
21
+ "seal",
22
+ "morse",
23
+ "react",
24
+ "file-upload",
25
+ "uploader",
26
+ "web3",
27
+ "decentralized"
28
+ ],
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/arcadiasystems/morse-uploader.git"
32
+ },
33
+ "homepage": "https://github.com/arcadiasystems/morse-uploader#readme",
34
+ "bugs": {
35
+ "url": "https://github.com/arcadiasystems/morse-uploader/issues"
36
+ },
37
+ "files": [
38
+ "dist",
39
+ "README.md",
40
+ "LICENSE",
41
+ "CHANGELOG.md"
42
+ ],
43
+ "main": "./dist/index.js",
44
+ "module": "./dist/index.js",
45
+ "types": "./dist/index.d.ts",
46
+ "exports": {
47
+ ".": {
48
+ "types": "./dist/index.d.ts",
49
+ "import": "./dist/index.js"
50
+ },
51
+ "./ui": {
52
+ "types": "./dist/ui.d.ts",
53
+ "import": "./dist/ui.js"
54
+ },
55
+ "./styles.css": "./dist/styles.css",
56
+ "./wallet-standard": {
57
+ "types": "./dist/wallet-standard.d.ts",
58
+ "import": "./dist/wallet-standard.js"
59
+ },
60
+ "./package.json": "./package.json"
61
+ },
62
+ "scripts": {
63
+ "build": "tsup",
64
+ "dev": "tsup --watch",
65
+ "typecheck": "tsc --noEmit",
66
+ "lint": "biome check .",
67
+ "lint:fix": "biome check --write .",
68
+ "test": "vitest run",
69
+ "test:watch": "vitest",
70
+ "test:coverage": "vitest run --coverage",
71
+ "check:exports": "publint && attw --pack . --profile esm-only --exclude-entrypoints styles.css",
72
+ "build:example": "bun run build && cd examples/web && bun run build",
73
+ "prepublishOnly": "bun run lint && bun run typecheck && bun run test && bun run build && bun run check:exports"
74
+ },
75
+ "engines": {
76
+ "node": ">=18.0.0",
77
+ "bun": ">=1.2.0"
78
+ },
79
+ "peerDependencies": {
80
+ "@arcadiasystems/morse-sdk": ">=0.4.2 <0.5.0",
81
+ "@mysten/seal": ">=1.1.3 <1.2.0",
82
+ "@mysten/sui": ">=2.16.2 <2.17.0",
83
+ "@mysten/walrus": ">=1.1.6 <1.2.0",
84
+ "react": ">=18.0.0",
85
+ "react-dom": ">=18.0.0"
86
+ },
87
+ "peerDependenciesMeta": {
88
+ "@mysten/seal": {
89
+ "optional": true
90
+ },
91
+ "@mysten/walrus": {
92
+ "optional": true
93
+ }
94
+ },
95
+ "devDependencies": {
96
+ "@arcadiasystems/morse-sdk": "0.4.2",
97
+ "@arethetypeswrong/cli": "^0.18.1",
98
+ "@biomejs/biome": "2.4.7",
99
+ "@mysten/seal": "1.1.3",
100
+ "@mysten/sui": "2.16.2",
101
+ "@mysten/walrus": "1.1.6",
102
+ "@testing-library/jest-dom": "^6.4.0",
103
+ "@testing-library/react": "^16.0.0",
104
+ "@testing-library/user-event": "^14.5.0",
105
+ "@types/react": "^18.3.0",
106
+ "@types/react-dom": "^18.3.0",
107
+ "@vitest/coverage-v8": "^2.1.0",
108
+ "jsdom": "^25.0.0",
109
+ "publint": "^0.2.0",
110
+ "react": "^18.3.0",
111
+ "react-dom": "^18.3.0",
112
+ "tsup": "^8.3.0",
113
+ "typescript": "^5.6.0",
114
+ "vitest": "^2.1.0"
115
+ }
116
+ }