@majikah/sdk 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/LICENSE +67 -0
- package/README.md +1112 -0
- package/dist/client/MajikahSDKClient.d.ts +308 -0
- package/dist/client/MajikahSDKClient.js +318 -0
- package/dist/errors/APIError.d.ts +7 -0
- package/dist/errors/APIError.js +14 -0
- package/dist/errors/AuthenticationError.d.ts +3 -0
- package/dist/errors/AuthenticationError.js +4 -0
- package/dist/errors/MajikahError.d.ts +4 -0
- package/dist/errors/MajikahError.js +9 -0
- package/dist/errors/QuotaExhaustedError.d.ts +3 -0
- package/dist/errors/QuotaExhaustedError.js +4 -0
- package/dist/errors/RateLimitError.d.ts +5 -0
- package/dist/errors/RateLimitError.js +10 -0
- package/dist/errors/ServiceUnavailableError.d.ts +3 -0
- package/dist/errors/ServiceUnavailableError.js +4 -0
- package/dist/errors/ValidationError.d.ts +5 -0
- package/dist/errors/ValidationError.js +10 -0
- package/dist/errors/index.d.ts +8 -0
- package/dist/errors/index.js +8 -0
- package/dist/errors/mapError.d.ts +3 -0
- package/dist/errors/mapError.js +22 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -0
- package/dist/services/index.d.ts +4 -0
- package/dist/services/index.js +4 -0
- package/dist/services/muid/MUIDClient.d.ts +95 -0
- package/dist/services/muid/MUIDClient.js +138 -0
- package/dist/services/muid/key-resolver.d.ts +24 -0
- package/dist/services/muid/key-resolver.js +32 -0
- package/dist/services/notary/NotaryClient.d.ts +188 -0
- package/dist/services/notary/NotaryClient.js +291 -0
- package/dist/services/notary/validation.d.ts +7 -0
- package/dist/services/notary/validation.js +19 -0
- package/dist/services/shared/encoding.d.ts +21 -0
- package/dist/services/shared/encoding.js +43 -0
- package/dist/services/shared/resolve-signature.d.ts +23 -0
- package/dist/services/shared/resolve-signature.js +31 -0
- package/dist/services/shared/sleep.d.ts +1 -0
- package/dist/services/shared/sleep.js +3 -0
- package/dist/services/shared/validation.d.ts +9 -0
- package/dist/services/shared/validation.js +16 -0
- package/dist/services/slink/SLinkClient.d.ts +174 -0
- package/dist/services/slink/SLinkClient.js +231 -0
- package/dist/services/slink/validation.d.ts +24 -0
- package/dist/services/slink/validation.js +31 -0
- package/dist/services/tsa/TSAClient.d.ts +101 -0
- package/dist/services/tsa/TSAClient.js +178 -0
- package/dist/services/tsa/validation.d.ts +2 -0
- package/dist/services/tsa/validation.js +12 -0
- package/dist/transport/HttpClient.d.ts +85 -0
- package/dist/transport/HttpClient.js +135 -0
- package/dist/transport/RouteResolver.d.ts +54 -0
- package/dist/transport/RouteResolver.js +67 -0
- package/dist/transport/retry-after.d.ts +17 -0
- package/dist/transport/retry-after.js +39 -0
- package/dist/transport/retry.d.ts +8 -0
- package/dist/transport/retry.js +61 -0
- package/dist/types/common.d.ts +133 -0
- package/dist/types/common.js +42 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.js +1 -0
- package/dist/types/muid.d.ts +80 -0
- package/dist/types/muid.js +1 -0
- package/dist/types/notary.d.ts +243 -0
- package/dist/types/notary.js +1 -0
- package/dist/types/slink.d.ts +60 -0
- package/dist/types/slink.js +1 -0
- package/dist/types/tsa.d.ts +144 -0
- package/dist/types/tsa.js +1 -0
- package/package.json +67 -0
package/README.md
ADDED
|
@@ -0,0 +1,1112 @@
|
|
|
1
|
+
# Majikah SDK
|
|
2
|
+
|
|
3
|
+
[](https://majikah.solutions)
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@majikah/sdk) [](https://www.npmjs.com/package/@majikah/sdk)
|
|
6
|
+
[](https://opensource.org/licenses/Apache-2.0) [](https://www.typescriptlang.org/) [](https://www.iana.org/assignments/media-types/application/vnd.majikah.mjksig)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
The official TypeScript SDK for the **Majikah ecosystem**.
|
|
10
|
+
|
|
11
|
+
`@majikah/sdk` provides a unified developer interface for Majikah's public services:
|
|
12
|
+
|
|
13
|
+
* **Majik Universal ID (MUID)** — public identity lookup and signature verification
|
|
14
|
+
* **Time Stamping Authority (TSA)** — trusted timestamps for digital signatures
|
|
15
|
+
* **Signed Links (SLink)** — signed claims associated with URLs and content hashes
|
|
16
|
+
* **File Notarization** — payment-aware on-chain anchoring of sealed files
|
|
17
|
+
|
|
18
|
+
The SDK is designed to work with Majikah's local cryptographic libraries, including `@majikah/majik-key`, `@majikah/majik-signature`, and `@majikah/majik-slink`.
|
|
19
|
+
|
|
20
|
+
Cryptographic operations that require private keys are performed locally. Private signing keys are not uploaded to the Majikah API by the SDK.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Why the Majikah SDK?
|
|
25
|
+
|
|
26
|
+
The SDK combines Majikah's public services with local cryptographic operations so applications can build complete signing, verification, timestamping, SLink, and notarization workflows without implementing the API protocol themselves.
|
|
27
|
+
|
|
28
|
+
For example, a single application can:
|
|
29
|
+
|
|
30
|
+
```text
|
|
31
|
+
Create or receive a signed file
|
|
32
|
+
│
|
|
33
|
+
├── Verify the signature against a MUID
|
|
34
|
+
│
|
|
35
|
+
├── Request a trusted timestamp
|
|
36
|
+
│
|
|
37
|
+
├── Publish or verify a signed URL claim
|
|
38
|
+
│
|
|
39
|
+
└── Seal and notarize the file on-chain
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The SDK also keeps service-specific functionality separated:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
majikah.muid
|
|
46
|
+
majikah.tsa
|
|
47
|
+
majikah.slink
|
|
48
|
+
majikah.notary
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
This allows you to use only the part of the ecosystem your application actually needs.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Features
|
|
56
|
+
|
|
57
|
+
### MUID
|
|
58
|
+
|
|
59
|
+
Verify signatures against public Majik Universal ID identities.
|
|
60
|
+
|
|
61
|
+
* Look up public MUID profiles
|
|
62
|
+
* Retrieve the authenticated MUID
|
|
63
|
+
* Verify existing embedded signatures
|
|
64
|
+
* Verify detached signature envelopes
|
|
65
|
+
* Select a specific signer in multi-signature files
|
|
66
|
+
* Verify against a specific MUID by ID or username
|
|
67
|
+
|
|
68
|
+
### TSA
|
|
69
|
+
|
|
70
|
+
Request trusted timestamps for digital signatures.
|
|
71
|
+
|
|
72
|
+
* Issue a TSA timestamp directly from a signature
|
|
73
|
+
* Timestamp an already-signed embedded file
|
|
74
|
+
* Timestamp a detached signature envelope
|
|
75
|
+
* Sign and timestamp a file in one operation
|
|
76
|
+
* Check TSA quota
|
|
77
|
+
* Automatically reuse the signature's TSA request payload
|
|
78
|
+
|
|
79
|
+
### SLink
|
|
80
|
+
|
|
81
|
+
Create, register, search, and cryptographically verify signed link claims.
|
|
82
|
+
|
|
83
|
+
* Register existing SLinks
|
|
84
|
+
* Create, sign, and register an SLink in one operation
|
|
85
|
+
* Search claims by URL
|
|
86
|
+
* Search claims by content hash
|
|
87
|
+
* Retrieve SLinks by ID
|
|
88
|
+
* Delete SLinks
|
|
89
|
+
* Verify SLink signatures locally
|
|
90
|
+
* Resolve public signing keys through MUID or a custom key registry
|
|
91
|
+
* Cursor-based pagination for owned SLinks
|
|
92
|
+
|
|
93
|
+
### File Notarization
|
|
94
|
+
|
|
95
|
+
Anchor sealed file hashes on-chain through a payment-aware workflow.
|
|
96
|
+
|
|
97
|
+
* Check or initiate payment for a sealed file
|
|
98
|
+
* Return the sealed artifact while payment is pending
|
|
99
|
+
* Register a paid seal hash
|
|
100
|
+
* Monitor on-chain confirmation
|
|
101
|
+
* Poll until a terminal state
|
|
102
|
+
* Embed the resulting chain anchor back into the file
|
|
103
|
+
* Seal an already-signed file and begin notarization
|
|
104
|
+
* Run the complete single-signer `sign → seal → initiate` workflow
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Installation
|
|
109
|
+
|
|
110
|
+
Install the SDK with npm:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
npm install @majikah/sdk
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The SDK is designed to work with the Majikah cryptographic packages used by the specific workflows in your application.
|
|
117
|
+
|
|
118
|
+
For example:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
npm install @majikah/sdk @majikah/majik-key @majikah/majik-signature @majikah/majik-slink
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Use the packages required by your application rather than installing the entire Majikah ecosystem unnecessarily.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Get an API Key
|
|
129
|
+
|
|
130
|
+
To use the Majikah public API, you first need to create and activate your developer account.
|
|
131
|
+
|
|
132
|
+
1. Go to [developers.majikah.solutions](https://developers.majikah.solutions/early-access).
|
|
133
|
+
2. Complete the developer onboarding process:
|
|
134
|
+
- Create your Majikah account.
|
|
135
|
+
- Create your **Majik Universal ID (MUID)**.
|
|
136
|
+
- Verify your MUID by completing the required **KYC verification**.
|
|
137
|
+
- Submit the **Early Access application** through the developer portal.
|
|
138
|
+
3. Wait for your application to be reviewed and approved by the Majikah team.
|
|
139
|
+
4. Once approved, you will receive an **email confirmation** and gain access to API key generation in the developer portal.
|
|
140
|
+
5. Generate your API key and keep it secure. You will use this key when initializing `MajikahSDKClient`.
|
|
141
|
+
|
|
142
|
+
> **Early Access:** Public API access is currently subject to developer approval. An API key cannot be generated until your Early Access application has been approved.
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Requirements
|
|
148
|
+
|
|
149
|
+
The SDK expects a modern JavaScript runtime with:
|
|
150
|
+
|
|
151
|
+
* `fetch`
|
|
152
|
+
* `URL`
|
|
153
|
+
* `AbortController`
|
|
154
|
+
* `atob` / `btoa`
|
|
155
|
+
|
|
156
|
+
These APIs are available natively in modern browsers and current Node.js, Deno, Bun, and edge runtimes.
|
|
157
|
+
|
|
158
|
+
A custom `fetch` implementation can also be supplied through the client options when integrating with a specialized runtime or transport layer.
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Authentication
|
|
163
|
+
|
|
164
|
+
Create a `MajikahSDKClient` with your public API key:
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
import { MajikahSDKClient } from "@majikah/sdk";
|
|
168
|
+
|
|
169
|
+
const majikah = new MajikahSDKClient({
|
|
170
|
+
apiKey: process.env.MAJIKAH_API_KEY!,
|
|
171
|
+
});
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
The SDK automatically sends the API key using the expected authentication header.
|
|
175
|
+
|
|
176
|
+
Do not hard-code API keys into browser source code or commit them to your repository.
|
|
177
|
+
|
|
178
|
+
For server-side applications, use environment variables or another secure secret-management mechanism.
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Client Configuration
|
|
183
|
+
|
|
184
|
+
The client supports a number of optional transport and API settings.
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
const majikah = new MajikahSDKClient({
|
|
188
|
+
apiKey: process.env.MAJIKAH_API_KEY!,
|
|
189
|
+
|
|
190
|
+
baseUrl: "https://api-public.majikah.solutions",
|
|
191
|
+
|
|
192
|
+
version: 1,
|
|
193
|
+
|
|
194
|
+
timeoutMs: 15_000,
|
|
195
|
+
|
|
196
|
+
headers: {
|
|
197
|
+
"X-Custom-Header": "example",
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
retry: {
|
|
201
|
+
maxAttempts: 3,
|
|
202
|
+
initialDelayMs: 300,
|
|
203
|
+
jitterFactor: 0.4,
|
|
204
|
+
capDelayMs: 5_000,
|
|
205
|
+
},
|
|
206
|
+
});
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Configuration options
|
|
210
|
+
|
|
211
|
+
| Option | Description | Default |
|
|
212
|
+
| ----------- | ------------------------------------------- | -------------------------------------- |
|
|
213
|
+
| `apiKey` | API key used to authenticate requests | Required |
|
|
214
|
+
| `baseUrl` | Public Majikah API base URL | `https://api-public.majikah.solutions` |
|
|
215
|
+
| `version` | Global API version or per-service versions | `1` |
|
|
216
|
+
| `timeoutMs` | Request timeout in milliseconds | `15000` |
|
|
217
|
+
| `headers` | Additional request headers | `{}` |
|
|
218
|
+
| `fetch` | Custom `fetch` implementation | Runtime `fetch` |
|
|
219
|
+
| `retry` | Retry configuration for retry-safe requests | See below |
|
|
220
|
+
|
|
221
|
+
### Per-service API versions
|
|
222
|
+
|
|
223
|
+
A single version can be applied to every service:
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
const majikah = new MajikahSDKClient({
|
|
227
|
+
apiKey,
|
|
228
|
+
version: 1,
|
|
229
|
+
});
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Individual services can also be versioned independently:
|
|
233
|
+
|
|
234
|
+
```ts
|
|
235
|
+
const majikah = new MajikahSDKClient({
|
|
236
|
+
apiKey,
|
|
237
|
+
version: {
|
|
238
|
+
tsa: 1,
|
|
239
|
+
notary: 1,
|
|
240
|
+
slink: 1,
|
|
241
|
+
muid: 2,
|
|
242
|
+
},
|
|
243
|
+
});
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Services not explicitly overridden inherit the fallback version.
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## Retry behavior
|
|
251
|
+
|
|
252
|
+
The SDK automatically retries retry-safe requests using exponential backoff with jitter.
|
|
253
|
+
|
|
254
|
+
`GET` requests are retryable by default.
|
|
255
|
+
|
|
256
|
+
`POST` requests are only retried when explicitly marked as idempotent internally.
|
|
257
|
+
|
|
258
|
+
This distinction prevents the SDK from accidentally repeating operations that could create duplicate side effects.
|
|
259
|
+
|
|
260
|
+
Default retry settings:
|
|
261
|
+
|
|
262
|
+
```ts
|
|
263
|
+
{
|
|
264
|
+
maxAttempts: 3,
|
|
265
|
+
initialDelayMs: 300,
|
|
266
|
+
jitterFactor: 0.4,
|
|
267
|
+
capDelayMs: 5_000,
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Rate-limit responses can also provide retry timing information that the SDK uses when mapping the API response.
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
# Service Modules
|
|
276
|
+
|
|
277
|
+
## 1. MUID — Identity and Signature Verification
|
|
278
|
+
|
|
279
|
+
MUID provides public identity information and lets applications verify digital signatures against a MUID.
|
|
280
|
+
|
|
281
|
+
### Look up a MUID
|
|
282
|
+
|
|
283
|
+
```ts
|
|
284
|
+
const profile = await majikah.muid.lookup("alice");
|
|
285
|
+
|
|
286
|
+
console.log(profile);
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
The lookup accepts either a MUID identifier or username.
|
|
290
|
+
|
|
291
|
+
### Get the current MUID
|
|
292
|
+
|
|
293
|
+
```ts
|
|
294
|
+
const me = await majikah.muid.me();
|
|
295
|
+
|
|
296
|
+
console.log(me);
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Verify an existing signed file
|
|
300
|
+
|
|
301
|
+
```ts
|
|
302
|
+
const result = await majikah.muid.verifyFile(signedFile, {
|
|
303
|
+
muid: "alice",
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
if (result.valid) {
|
|
307
|
+
console.log("Signature is valid.");
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
When the file contains multiple signatures, identify which signer should be verified:
|
|
312
|
+
|
|
313
|
+
```ts
|
|
314
|
+
const result = await majikah.muid.verifyFile(signedFile, {
|
|
315
|
+
expectedSignerId: signerFingerprint,
|
|
316
|
+
muid: "alice",
|
|
317
|
+
});
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
When `muid` is omitted, verification uses the MUID associated with the caller's API credentials where supported by the API.
|
|
321
|
+
|
|
322
|
+
### Verify a detached envelope
|
|
323
|
+
|
|
324
|
+
```ts
|
|
325
|
+
const result = await majikah.muid.verifyFileDetached(envelope, {
|
|
326
|
+
muid: "alice",
|
|
327
|
+
});
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
Detached verification operates on the signature envelope rather than an embedded signature inside the original file.
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## 2. TSA — Trusted Timestamping
|
|
335
|
+
|
|
336
|
+
The TSA service provides trusted timestamps for Majik Signatures.
|
|
337
|
+
|
|
338
|
+
### Timestamp an existing signature
|
|
339
|
+
|
|
340
|
+
For a file that has already been signed:
|
|
341
|
+
|
|
342
|
+
```ts
|
|
343
|
+
const { blob, signature } = await majikah.tsa.timestampFile(
|
|
344
|
+
signedFile,
|
|
345
|
+
);
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
No `MajikKey` is required for this operation because the method does not create a new signature.
|
|
349
|
+
|
|
350
|
+
For a multi-signature file:
|
|
351
|
+
|
|
352
|
+
```ts
|
|
353
|
+
const { blob, signature } = await majikah.tsa.timestampFile(
|
|
354
|
+
signedFile,
|
|
355
|
+
{
|
|
356
|
+
expectedSignerId: signerFingerprint,
|
|
357
|
+
},
|
|
358
|
+
);
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### Timestamp a detached envelope
|
|
362
|
+
|
|
363
|
+
```ts
|
|
364
|
+
const { envelope, mjksig } =
|
|
365
|
+
await majikah.tsa.timestampDetached(envelope);
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
The returned `mjksig` is the serialized detached signature envelope.
|
|
369
|
+
|
|
370
|
+
### Sign and timestamp in one operation
|
|
371
|
+
|
|
372
|
+
```ts
|
|
373
|
+
const result = await majikah.tsa.stampFile(
|
|
374
|
+
file,
|
|
375
|
+
myUnlockedMajikKey,
|
|
376
|
+
{
|
|
377
|
+
contentType: "application/pdf",
|
|
378
|
+
},
|
|
379
|
+
);
|
|
380
|
+
|
|
381
|
+
console.log(result.blob);
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
This performs:
|
|
385
|
+
|
|
386
|
+
```text
|
|
387
|
+
sign
|
|
388
|
+
↓
|
|
389
|
+
request TSA timestamp
|
|
390
|
+
↓
|
|
391
|
+
attach TSA
|
|
392
|
+
↓
|
|
393
|
+
embed signature
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### Sign and return a detached timestamped envelope
|
|
397
|
+
|
|
398
|
+
```ts
|
|
399
|
+
const result = await majikah.tsa.stampFileDetached(
|
|
400
|
+
file,
|
|
401
|
+
myUnlockedMajikKey,
|
|
402
|
+
{
|
|
403
|
+
contentType: "application/pdf",
|
|
404
|
+
},
|
|
405
|
+
);
|
|
406
|
+
|
|
407
|
+
const { envelope, mjksig } = result;
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
This is useful when the signature needs to be distributed separately from the original file.
|
|
411
|
+
|
|
412
|
+
### TSA quota
|
|
413
|
+
|
|
414
|
+
```ts
|
|
415
|
+
const quota = await majikah.tsa.quota();
|
|
416
|
+
|
|
417
|
+
console.log(quota);
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
## 3. SLink — Signed Link Claims
|
|
423
|
+
|
|
424
|
+
SLink associates cryptographically signed claims with URLs or content hashes.
|
|
425
|
+
|
|
426
|
+
A useful distinction is:
|
|
427
|
+
|
|
428
|
+
> **SLink lookup establishes that a claim exists. Cryptographic verification establishes that the claim's signature is valid.**
|
|
429
|
+
|
|
430
|
+
The API does not need to store the signer's public keys for local verification.
|
|
431
|
+
|
|
432
|
+
### Register an existing SLink
|
|
433
|
+
|
|
434
|
+
```ts
|
|
435
|
+
const stored = await majikah.slink.create(slink);
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
A `MajikSLink` instance or serialized JSON can be supplied.
|
|
439
|
+
|
|
440
|
+
### Create, sign, and register an SLink
|
|
441
|
+
|
|
442
|
+
```ts
|
|
443
|
+
const stored = await majikah.slink.registerUrl(
|
|
444
|
+
"https://example.com",
|
|
445
|
+
aliceKey,
|
|
446
|
+
userId,
|
|
447
|
+
muid,
|
|
448
|
+
);
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
A bare domain is also supported by the underlying SLink workflow:
|
|
452
|
+
|
|
453
|
+
```ts
|
|
454
|
+
const stored = await majikah.slink.registerUrl(
|
|
455
|
+
"example.com",
|
|
456
|
+
aliceKey,
|
|
457
|
+
userId,
|
|
458
|
+
muid,
|
|
459
|
+
);
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
### Search by URL
|
|
463
|
+
|
|
464
|
+
```ts
|
|
465
|
+
const results = await majikah.slink.verifyUrl(
|
|
466
|
+
"example.com",
|
|
467
|
+
);
|
|
468
|
+
|
|
469
|
+
console.log(results.matches);
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
The SDK automatically normalizes a bare domain to HTTPS before sending the request.
|
|
473
|
+
|
|
474
|
+
### Search by content hash
|
|
475
|
+
|
|
476
|
+
```ts
|
|
477
|
+
const results = await majikah.slink.verifyByHash(hash);
|
|
478
|
+
|
|
479
|
+
console.log(results.matches);
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
### Local cryptographic verification
|
|
483
|
+
|
|
484
|
+
To verify every search result cryptographically, use `verifyUrlWithProof()`.
|
|
485
|
+
|
|
486
|
+
The simplest MUID-backed approach is:
|
|
487
|
+
|
|
488
|
+
```ts
|
|
489
|
+
import { createMuidPublicKeyResolver } from "@majikah/sdk";
|
|
490
|
+
|
|
491
|
+
const results = await majikah.slink.verifyUrlWithProof(
|
|
492
|
+
"thezelijah.world",
|
|
493
|
+
createMuidPublicKeyResolver(majikah.muid),
|
|
494
|
+
);
|
|
495
|
+
|
|
496
|
+
const verified = results.filter(({ result }) => result.valid);
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
`createMuidPublicKeyResolver()`:
|
|
500
|
+
|
|
501
|
+
1. Resolves each MUID through `MUIDClient.lookup()`
|
|
502
|
+
2. Reads the public signing keys
|
|
503
|
+
3. Converts their Base64 representation to the SDK's binary key format
|
|
504
|
+
4. Supplies the keys to the local signature verifier
|
|
505
|
+
|
|
506
|
+
### Custom public key sources
|
|
507
|
+
|
|
508
|
+
Applications can supply their own trusted key registry:
|
|
509
|
+
|
|
510
|
+
```ts
|
|
511
|
+
const results = await majikah.slink.verifyUrlWithProof(
|
|
512
|
+
"example.com",
|
|
513
|
+
async (muid, signerId) => {
|
|
514
|
+
const keys = await myKeyRegistry.get(muid);
|
|
515
|
+
|
|
516
|
+
return {
|
|
517
|
+
signerId,
|
|
518
|
+
edPublicKey: keys.edPublicKey,
|
|
519
|
+
mlDsaPublicKey: keys.mlDsaPublicKey,
|
|
520
|
+
};
|
|
521
|
+
},
|
|
522
|
+
);
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
This makes SLink verification independent of a specific public-key storage backend.
|
|
526
|
+
|
|
527
|
+
### Verify already-fetched matches
|
|
528
|
+
|
|
529
|
+
If you already called `verifyUrl()` or `verifyByHash()`, you can verify the returned matches without performing another lookup:
|
|
530
|
+
|
|
531
|
+
```ts
|
|
532
|
+
const search = await majikah.slink.verifyUrl("example.com");
|
|
533
|
+
|
|
534
|
+
const verified = await majikah.slink.verifyMatches(
|
|
535
|
+
search.matches,
|
|
536
|
+
createMuidPublicKeyResolver(majikah.muid),
|
|
537
|
+
);
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
### List your SLinks
|
|
541
|
+
|
|
542
|
+
SLink ownership listings use cursor-based pagination:
|
|
543
|
+
|
|
544
|
+
```ts
|
|
545
|
+
const page = await majikah.slink.me({
|
|
546
|
+
limit: 50,
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
console.log(page.items);
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
Fetch the next page using the returned opaque cursor:
|
|
553
|
+
|
|
554
|
+
```ts
|
|
555
|
+
if (page.has_more && page.next_cursor) {
|
|
556
|
+
const nextPage = await majikah.slink.me({
|
|
557
|
+
cursor: page.next_cursor,
|
|
558
|
+
limit: 50,
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
The cursor should be treated as opaque data. Do not decode or modify it.
|
|
564
|
+
|
|
565
|
+
---
|
|
566
|
+
|
|
567
|
+
# 4. Notary — File Notarization
|
|
568
|
+
|
|
569
|
+
Notary provides payment-aware on-chain anchoring for sealed files.
|
|
570
|
+
|
|
571
|
+
A notarization is based on the file's **seal hash**, rather than uploading the entire file to the notarization service.
|
|
572
|
+
|
|
573
|
+
The sealed artifact remains with the application. The Majikah notarization service uses the seal hash to associate payment and on-chain anchoring with that artifact.
|
|
574
|
+
|
|
575
|
+
Do not re-seal or otherwise modify the artifact before finalization, as the `sealHash` must continue to correspond to the sealed content.
|
|
576
|
+
|
|
577
|
+
The high-level lifecycle is:
|
|
578
|
+
|
|
579
|
+
```mermaid
|
|
580
|
+
flowchart TD
|
|
581
|
+
A[Signed file] --> B[Create seal]
|
|
582
|
+
B --> C[sealedBlob + sealHash]
|
|
583
|
+
|
|
584
|
+
C --> D[Initiate notarization]
|
|
585
|
+
|
|
586
|
+
D --> E{Already anchored?}
|
|
587
|
+
|
|
588
|
+
E -->|Yes| F[Return notarized blob]
|
|
589
|
+
E -->|No| G[Create payment checkout]
|
|
590
|
+
|
|
591
|
+
G --> H[Return sealedBlob + sealHash + checkout]
|
|
592
|
+
H --> I[User completes payment]
|
|
593
|
+
|
|
594
|
+
I --> J[Register sealHash on-chain]
|
|
595
|
+
J --> K[Wait for chain confirmation]
|
|
596
|
+
K --> L[Embed chain anchor into sealed blob]
|
|
597
|
+
L --> M[Return notarized blob]
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
|
|
601
|
+
### Start notarization for an already-sealed file
|
|
602
|
+
|
|
603
|
+
```ts
|
|
604
|
+
const result =
|
|
605
|
+
await majikah.notary.initiateNotarization(sealedFile);
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
The result tells you what happens next.
|
|
609
|
+
|
|
610
|
+
|
|
611
|
+
### Payment required
|
|
612
|
+
|
|
613
|
+
```ts
|
|
614
|
+
const result =
|
|
615
|
+
await majikah.notary.initiateNotarization(sealedFile);
|
|
616
|
+
|
|
617
|
+
if (result.status === "payment_required") {
|
|
618
|
+
console.log(result.sealHash);
|
|
619
|
+
console.log(result.checkout.checkout_url);
|
|
620
|
+
console.log(result.sealedBlob);
|
|
621
|
+
}
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
The checkout URL can be presented as a QR code or another payment interface.
|
|
625
|
+
|
|
626
|
+
The `sealedBlob` returned with the payment-required result is the exact sealed artifact associated with the returned `sealHash`. Retain both values while payment is being completed.
|
|
627
|
+
|
|
628
|
+
After payment is completed, finalize the notarization using the returned `sealedBlob` and `sealHash`:
|
|
629
|
+
|
|
630
|
+
```ts
|
|
631
|
+
if (result.status === "payment_required") {
|
|
632
|
+
const finalized =
|
|
633
|
+
await majikah.notary.finalizeNotarization(
|
|
634
|
+
result.sealedBlob,
|
|
635
|
+
result.sealHash,
|
|
636
|
+
{
|
|
637
|
+
poll: {
|
|
638
|
+
intervalMs: 2000,
|
|
639
|
+
timeoutMs: 130_000,
|
|
640
|
+
},
|
|
641
|
+
},
|
|
642
|
+
);
|
|
643
|
+
|
|
644
|
+
console.log(finalized.anchor.id);
|
|
645
|
+
console.log(finalized.blob);
|
|
646
|
+
}
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
The sealed file is not uploaded to the notarization service as part of this flow. The service uses the seal hash to associate the payment and on-chain notarization with the sealed artifact.
|
|
650
|
+
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
### Already anchored
|
|
654
|
+
|
|
655
|
+
If the file was already notarized:
|
|
656
|
+
|
|
657
|
+
```ts
|
|
658
|
+
if (result.status === "anchored") {
|
|
659
|
+
console.log("file is already notarized.");
|
|
660
|
+
console.log(result.anchor);
|
|
661
|
+
console.log(result.blob);
|
|
662
|
+
}
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
The existing anchor is returned and the anchor information can be embedded into the file.
|
|
666
|
+
|
|
667
|
+
### Already paid
|
|
668
|
+
|
|
669
|
+
If payment was previously completed but notarization has not yet been finalized:
|
|
670
|
+
|
|
671
|
+
```ts
|
|
672
|
+
const result =
|
|
673
|
+
await majikah.notary.initiateNotarization(sealedFile);
|
|
674
|
+
|
|
675
|
+
if (result.status === "ready_to_finalize") {
|
|
676
|
+
const finalized =
|
|
677
|
+
await majikah.notary.finalizeNotarization(
|
|
678
|
+
result.sealedBlob,
|
|
679
|
+
result.sealHash,
|
|
680
|
+
);
|
|
681
|
+
|
|
682
|
+
console.log(finalized.anchor);
|
|
683
|
+
console.log(finalized.blob);
|
|
684
|
+
}
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
The result contains both the `sealHash` and the exact `sealedBlob` associated with it, so the caller does not need to reconstruct or re-seal the document.
|
|
688
|
+
|
|
689
|
+
|
|
690
|
+
### Register manually
|
|
691
|
+
|
|
692
|
+
For applications that want lower-level lifecycle control:
|
|
693
|
+
|
|
694
|
+
```ts
|
|
695
|
+
const anchor = await majikah.notary.register(sealHash);
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
Registration may initially return a pending anchor.
|
|
699
|
+
|
|
700
|
+
### Poll for confirmation
|
|
701
|
+
|
|
702
|
+
```ts
|
|
703
|
+
const anchor = await majikah.notary.pollUntilTerminal(
|
|
704
|
+
anchorId,
|
|
705
|
+
{
|
|
706
|
+
intervalMs: 2000,
|
|
707
|
+
timeoutMs: 130_000,
|
|
708
|
+
},
|
|
709
|
+
);
|
|
710
|
+
|
|
711
|
+
switch (anchor.status) {
|
|
712
|
+
case "confirmed":
|
|
713
|
+
console.log("Anchor confirmed.");
|
|
714
|
+
break;
|
|
715
|
+
|
|
716
|
+
case "finalized":
|
|
717
|
+
console.log("Anchor finalized.");
|
|
718
|
+
break;
|
|
719
|
+
|
|
720
|
+
case "failed":
|
|
721
|
+
console.error("Anchor failed.");
|
|
722
|
+
break;
|
|
723
|
+
}
|
|
724
|
+
```
|
|
725
|
+
|
|
726
|
+
A terminal `failed` status is returned as a normal result. It is not automatically converted into an exception because the failure state itself contains useful application-level information.
|
|
727
|
+
|
|
728
|
+
---
|
|
729
|
+
|
|
730
|
+
## Complete single-signer flow
|
|
731
|
+
|
|
732
|
+
For a document that needs to be signed, sealed, paid, and notarized:
|
|
733
|
+
|
|
734
|
+
```ts
|
|
735
|
+
const result =
|
|
736
|
+
await majikah.notary.signSealAndInitiateNotarization(
|
|
737
|
+
file,
|
|
738
|
+
issuerKey,
|
|
739
|
+
{
|
|
740
|
+
contentType: "application/pdf",
|
|
741
|
+
},
|
|
742
|
+
);
|
|
743
|
+
|
|
744
|
+
if (result.status === "payment_required") {
|
|
745
|
+
// Present the checkout to the user.
|
|
746
|
+
showQrCode(result.checkout.checkout_url);
|
|
747
|
+
|
|
748
|
+
// After payment has been completed:
|
|
749
|
+
const finalized =
|
|
750
|
+
await majikah.notary.finalizeNotarization(
|
|
751
|
+
result.sealedBlob,
|
|
752
|
+
result.sealHash,
|
|
753
|
+
);
|
|
754
|
+
|
|
755
|
+
console.log(finalized.anchor);
|
|
756
|
+
console.log(finalized.blob);
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
if (result.status === "ready_to_finalize") {
|
|
760
|
+
const finalized =
|
|
761
|
+
await majikah.notary.finalizeNotarization(
|
|
762
|
+
result.sealedBlob,
|
|
763
|
+
result.sealHash,
|
|
764
|
+
);
|
|
765
|
+
|
|
766
|
+
console.log(finalized.anchor);
|
|
767
|
+
console.log(finalized.blob);
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
if (result.status === "anchored") {
|
|
771
|
+
console.log(result.blob);
|
|
772
|
+
console.log(result.anchor);
|
|
773
|
+
}
|
|
774
|
+
```
|
|
775
|
+
|
|
776
|
+
This demonstrates the complete discriminated-union workflow without requiring developers to understand the lower-level `payment()` and `register()` methods first.
|
|
777
|
+
|
|
778
|
+
|
|
779
|
+
For multi-signature files, complete the signing process first, then seal and initiate notarization:
|
|
780
|
+
|
|
781
|
+
```ts
|
|
782
|
+
const result =
|
|
783
|
+
await majikah.notary.sealAndInitiateNotarization(
|
|
784
|
+
fullySignedFile,
|
|
785
|
+
issuerKey,
|
|
786
|
+
);
|
|
787
|
+
```
|
|
788
|
+
|
|
789
|
+
This keeps the seal operation as the explicit transition from a mutable signing envelope to the notarization-ready file state.
|
|
790
|
+
|
|
791
|
+
---
|
|
792
|
+
|
|
793
|
+
# Detached Signatures
|
|
794
|
+
|
|
795
|
+
Majik Signature supports detached signatures through the `.mjksig` format.
|
|
796
|
+
|
|
797
|
+
The SDK can operate directly on detached envelopes without requiring signatures to be embedded into the original file.
|
|
798
|
+
|
|
799
|
+
For example:
|
|
800
|
+
|
|
801
|
+
```ts
|
|
802
|
+
const result =
|
|
803
|
+
await majikah.tsa.stampFileDetached(
|
|
804
|
+
file,
|
|
805
|
+
key,
|
|
806
|
+
);
|
|
807
|
+
|
|
808
|
+
await saveFile(
|
|
809
|
+
result.mjksig,
|
|
810
|
+
"file.mjksig",
|
|
811
|
+
);
|
|
812
|
+
```
|
|
813
|
+
|
|
814
|
+
Detached envelopes are useful for:
|
|
815
|
+
|
|
816
|
+
* Out-of-band signature distribution
|
|
817
|
+
* Independent verification
|
|
818
|
+
* Signature storage separate from the original file
|
|
819
|
+
* Workflows where modifying the original file is undesirable
|
|
820
|
+
|
|
821
|
+
The `.mjksig` media type is registered with IANA as:
|
|
822
|
+
|
|
823
|
+
```text
|
|
824
|
+
application/vnd.majikah.mjksig
|
|
825
|
+
```
|
|
826
|
+
|
|
827
|
+
---
|
|
828
|
+
|
|
829
|
+
# Local Cryptography and Key Handling
|
|
830
|
+
|
|
831
|
+
The SDK intentionally separates API operations from local cryptographic operations.
|
|
832
|
+
|
|
833
|
+
For workflows involving private keys:
|
|
834
|
+
|
|
835
|
+
```text
|
|
836
|
+
Your application
|
|
837
|
+
│
|
|
838
|
+
├── MajikKey
|
|
839
|
+
│ │
|
|
840
|
+
│ └── private key operations stay local
|
|
841
|
+
│
|
|
842
|
+
└── Majikah API
|
|
843
|
+
│
|
|
844
|
+
├── identity lookup
|
|
845
|
+
├── TSA
|
|
846
|
+
├── SLink registry
|
|
847
|
+
└── notarization services
|
|
848
|
+
```
|
|
849
|
+
|
|
850
|
+
A `MajikKey` is supplied to operations that require signing or sealing.
|
|
851
|
+
|
|
852
|
+
The SDK does not need to upload the private signing key to the API to perform those operations.
|
|
853
|
+
|
|
854
|
+
Applications should still follow normal key-management practices and protect unlocked keys within their own execution environment.
|
|
855
|
+
|
|
856
|
+
---
|
|
857
|
+
|
|
858
|
+
# Verification Model
|
|
859
|
+
|
|
860
|
+
Majikah verification is intentionally layered.
|
|
861
|
+
|
|
862
|
+
For example, SLink verification consists of two different questions:
|
|
863
|
+
|
|
864
|
+
### Does a claim exist?
|
|
865
|
+
|
|
866
|
+
```ts
|
|
867
|
+
const result = await majikah.slink.verifyUrl(
|
|
868
|
+
"example.com",
|
|
869
|
+
);
|
|
870
|
+
```
|
|
871
|
+
|
|
872
|
+
This performs a service-side lookup.
|
|
873
|
+
|
|
874
|
+
### Is the signature cryptographically valid?
|
|
875
|
+
|
|
876
|
+
```ts
|
|
877
|
+
const result =
|
|
878
|
+
await majikah.slink.verifyUrlWithProof(
|
|
879
|
+
"example.com",
|
|
880
|
+
createMuidPublicKeyResolver(majikah.muid),
|
|
881
|
+
);
|
|
882
|
+
```
|
|
883
|
+
|
|
884
|
+
This performs local cryptographic verification using trusted public keys.
|
|
885
|
+
|
|
886
|
+
This distinction is important when building security-sensitive applications: **a registry match should not automatically be treated as cryptographic proof.**
|
|
887
|
+
|
|
888
|
+
---
|
|
889
|
+
|
|
890
|
+
# File and Signature Compatibility
|
|
891
|
+
|
|
892
|
+
The SDK is built around the Majik Signature ecosystem and accepts the `FileLike` abstractions supported by `@majikah/majik-signature`.
|
|
893
|
+
|
|
894
|
+
Depending on the workflow, the SDK can operate on:
|
|
895
|
+
|
|
896
|
+
* Regular file or blob-like data
|
|
897
|
+
* Embedded Majik Signatures
|
|
898
|
+
* Detached `.mjksig` envelopes
|
|
899
|
+
* Sealed signature envelopes
|
|
900
|
+
* files that receive a notarization chain anchor
|
|
901
|
+
|
|
902
|
+
The exact file-handling capabilities are provided by the corresponding Majikah cryptographic libraries rather than duplicated inside this SDK.
|
|
903
|
+
|
|
904
|
+
---
|
|
905
|
+
|
|
906
|
+
# Error Handling
|
|
907
|
+
|
|
908
|
+
The SDK maps API and transport failures into SDK-specific error types.
|
|
909
|
+
|
|
910
|
+
For example:
|
|
911
|
+
|
|
912
|
+
```ts
|
|
913
|
+
try {
|
|
914
|
+
await majikah.tsa.issueForSignature(signature);
|
|
915
|
+
} catch (error) {
|
|
916
|
+
console.error(error);
|
|
917
|
+
}
|
|
918
|
+
```
|
|
919
|
+
|
|
920
|
+
Applications should distinguish between:
|
|
921
|
+
|
|
922
|
+
* Validation errors caused by invalid local input
|
|
923
|
+
* API errors returned by the Majikah service
|
|
924
|
+
* Rate-limit responses
|
|
925
|
+
* Request timeouts
|
|
926
|
+
* Terminal workflow states such as a failed notarization
|
|
927
|
+
|
|
928
|
+
Not every negative application outcome is represented as an exception. For example, a notarization anchor with `status === "failed"` is a valid terminal result and can be handled through normal control flow.
|
|
929
|
+
|
|
930
|
+
---
|
|
931
|
+
|
|
932
|
+
# TypeScript
|
|
933
|
+
|
|
934
|
+
The SDK is written in TypeScript and provides typed service methods, request options, response models, and workflow results.
|
|
935
|
+
|
|
936
|
+
For example:
|
|
937
|
+
|
|
938
|
+
```ts
|
|
939
|
+
const page = await majikah.slink.me({
|
|
940
|
+
limit: 25,
|
|
941
|
+
});
|
|
942
|
+
|
|
943
|
+
page.items;
|
|
944
|
+
// MajikSLinkJSON[]
|
|
945
|
+
|
|
946
|
+
page.next_cursor;
|
|
947
|
+
// string | null
|
|
948
|
+
```
|
|
949
|
+
|
|
950
|
+
The SDK's public types are designed to make service behavior discoverable directly through IDE autocomplete and TypeScript type information.
|
|
951
|
+
|
|
952
|
+
---
|
|
953
|
+
|
|
954
|
+
# Runtime Support
|
|
955
|
+
|
|
956
|
+
The SDK is designed for modern full-stack and edge environments, including:
|
|
957
|
+
|
|
958
|
+
* Browser applications
|
|
959
|
+
* Node.js
|
|
960
|
+
* Deno
|
|
961
|
+
* Bun
|
|
962
|
+
* Cloudflare Workers
|
|
963
|
+
* Other runtimes implementing the standard web APIs used by the SDK
|
|
964
|
+
|
|
965
|
+
A custom `fetch` implementation may be supplied when required:
|
|
966
|
+
|
|
967
|
+
```ts
|
|
968
|
+
const majikah = new MajikahSDKClient({
|
|
969
|
+
apiKey,
|
|
970
|
+
fetch: customFetch,
|
|
971
|
+
});
|
|
972
|
+
```
|
|
973
|
+
|
|
974
|
+
This allows applications to integrate the SDK into environments with specialized HTTP transports or execution constraints.
|
|
975
|
+
|
|
976
|
+
---
|
|
977
|
+
|
|
978
|
+
# API Design
|
|
979
|
+
|
|
980
|
+
The SDK deliberately separates lower-level service operations from higher-level convenience workflows.
|
|
981
|
+
|
|
982
|
+
For example:
|
|
983
|
+
|
|
984
|
+
```ts
|
|
985
|
+
majikah.tsa.issue(...)
|
|
986
|
+
majikah.tsa.timestampFile(...)
|
|
987
|
+
majikah.tsa.stampFile(...)
|
|
988
|
+
```
|
|
989
|
+
|
|
990
|
+
and:
|
|
991
|
+
|
|
992
|
+
```ts
|
|
993
|
+
majikah.notary.payment(...)
|
|
994
|
+
majikah.notary.register(...)
|
|
995
|
+
majikah.notary.status(...)
|
|
996
|
+
majikah.notary.initiateNotarization(...)
|
|
997
|
+
majikah.notary.finalizeNotarization(...)
|
|
998
|
+
```
|
|
999
|
+
|
|
1000
|
+
This allows developers to choose between:
|
|
1001
|
+
|
|
1002
|
+
* **Fine-grained control** for backend workflows and infrastructure integrations
|
|
1003
|
+
* **Convenience methods** for common application flows
|
|
1004
|
+
|
|
1005
|
+
The same principle applies to SLink verification and MUID identity operations.
|
|
1006
|
+
|
|
1007
|
+
---
|
|
1008
|
+
|
|
1009
|
+
# Security Considerations
|
|
1010
|
+
|
|
1011
|
+
Applications integrating the SDK should:
|
|
1012
|
+
|
|
1013
|
+
* Keep API keys private on trusted server-side systems where appropriate
|
|
1014
|
+
* Never expose privileged API credentials in client-side source code
|
|
1015
|
+
* Protect unlocked `MajikKey` instances
|
|
1016
|
+
* Use trusted sources when resolving public signing keys
|
|
1017
|
+
* Treat API lookup results and cryptographic verification results as distinct security signals
|
|
1018
|
+
* Validate application-level authorization before allowing destructive operations
|
|
1019
|
+
* Handle rate limits and timeouts appropriately
|
|
1020
|
+
* Preserve detached signature and seal data exactly as generated
|
|
1021
|
+
|
|
1022
|
+
The SDK provides cryptographic primitives and service integration, but your application's authorization, key custody, access control, and trust policies remain the responsibility of the application.
|
|
1023
|
+
|
|
1024
|
+
---
|
|
1025
|
+
|
|
1026
|
+
# Contributing
|
|
1027
|
+
|
|
1028
|
+
Contributions, bug reports, documentation improvements, and ecosystem integrations are welcome.
|
|
1029
|
+
|
|
1030
|
+
Before submitting a change:
|
|
1031
|
+
|
|
1032
|
+
1. Keep the public API backward-compatible unless a breaking change is intentional.
|
|
1033
|
+
2. Preserve strong TypeScript typing.
|
|
1034
|
+
3. Add tests for both successful and failure paths.
|
|
1035
|
+
4. Document new public APIs with JSDoc.
|
|
1036
|
+
5. Avoid silently changing cryptographic behavior or serialization formats.
|
|
1037
|
+
|
|
1038
|
+
Please open an issue or pull request in the project repository for proposed changes.
|
|
1039
|
+
|
|
1040
|
+
---
|
|
1041
|
+
|
|
1042
|
+
# License
|
|
1043
|
+
|
|
1044
|
+
Apache-2.0
|
|
1045
|
+
|
|
1046
|
+
See [LICENSE](LICENSE) for the full license text.
|
|
1047
|
+
|
|
1048
|
+
---
|
|
1049
|
+
|
|
1050
|
+
# Maintainer
|
|
1051
|
+
|
|
1052
|
+
Developed by **Josef Elijah Fabian (Zelijah)** and **Majikah Solutions OPC**.
|
|
1053
|
+
|
|
1054
|
+
* Website: https://majikah.solutions
|
|
1055
|
+
* Developer: https://github.com/jedlsf
|
|
1056
|
+
* GitHub: https://github.com/Majikah
|
|
1057
|
+
* Organization: Majikah Solutions OPC
|
|
1058
|
+
|
|
1059
|
+
---
|
|
1060
|
+
|
|
1061
|
+
# Links
|
|
1062
|
+
|
|
1063
|
+
* **Majikah:** https://majikah.solutions
|
|
1064
|
+
* **SDK package:** https://www.npmjs.com/package/@majikah/sdk
|
|
1065
|
+
* **GitHub organization:** https://github.com/Majikah
|
|
1066
|
+
* **Majik Signature:** https://github.com/Majikah/majik-signature
|
|
1067
|
+
* **Business contact:** [business@majikah.solutions](mailto:business@majikah.solutions)
|
|
1068
|
+
|
|
1069
|
+
---
|
|
1070
|
+
|
|
1071
|
+
## Quick Reference
|
|
1072
|
+
|
|
1073
|
+
```ts
|
|
1074
|
+
import {
|
|
1075
|
+
MajikahSDKClient,
|
|
1076
|
+
createMuidPublicKeyResolver,
|
|
1077
|
+
} from "@majikah/sdk";
|
|
1078
|
+
|
|
1079
|
+
const majikah = new MajikahSDKClient({
|
|
1080
|
+
apiKey: process.env.MAJIKAH_API_KEY!,
|
|
1081
|
+
});
|
|
1082
|
+
|
|
1083
|
+
// MUID
|
|
1084
|
+
const profile = await majikah.muid.lookup("alice");
|
|
1085
|
+
|
|
1086
|
+
// TSA
|
|
1087
|
+
const stamped = await majikah.tsa.stampFile(
|
|
1088
|
+
file,
|
|
1089
|
+
signingKey,
|
|
1090
|
+
);
|
|
1091
|
+
|
|
1092
|
+
// SLink
|
|
1093
|
+
const slinks = await majikah.slink.verifyUrl(
|
|
1094
|
+
"example.com",
|
|
1095
|
+
);
|
|
1096
|
+
|
|
1097
|
+
// SLink + local cryptographic proof
|
|
1098
|
+
const verified = await majikah.slink.verifyUrlWithProof(
|
|
1099
|
+
"example.com",
|
|
1100
|
+
createMuidPublicKeyResolver(majikah.muid),
|
|
1101
|
+
);
|
|
1102
|
+
|
|
1103
|
+
// Notary
|
|
1104
|
+
const notarization =
|
|
1105
|
+
await majikah.notary.initiateNotarization(
|
|
1106
|
+
sealedFile,
|
|
1107
|
+
);
|
|
1108
|
+
```
|
|
1109
|
+
|
|
1110
|
+
**Majikah SDK — connect your applications to identity, signatures, timestamps, signed claims, and file notarization.**
|
|
1111
|
+
|
|
1112
|
+
|