@medialane/sdk 0.159.0 → 0.161.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 +21 -0
- package/README.md +49 -315
- package/dist/{chunk-K5MWWVX5.cjs → chunk-GQWRNQD2.cjs} +56 -15
- package/dist/chunk-GQWRNQD2.cjs.map +1 -0
- package/dist/{chunk-A6EQBVUF.js → chunk-QRIOXXO6.js} +50 -16
- package/dist/chunk-QRIOXXO6.js.map +1 -0
- package/dist/{errors-6Aarmz0V.d.cts → errors-B8xAxhKE.d.cts} +7 -1
- package/dist/{errors-BJl2TojD.d.ts → errors-CBIdzKXr.d.ts} +7 -1
- package/dist/index.cjs +94 -92
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -22
- package/dist/index.js.map +1 -1
- package/dist/starknet/index.cjs +177 -122
- package/dist/starknet/index.cjs.map +1 -1
- package/dist/starknet/index.d.cts +39 -4
- package/dist/starknet/index.d.ts +39 -4
- package/dist/starknet/index.js +109 -63
- package/dist/starknet/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-A6EQBVUF.js.map +0 -1
- package/dist/chunk-K5MWWVX5.cjs.map +0 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Medialane
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
# @medialane/sdk
|
|
4
4
|
|
|
5
|
-
**
|
|
5
|
+
**Build on Medialane: the open rails for creators, collectors and creator capital markets.**
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Everything the Medialane apps can do, your app or AI agent can do too. The SDK covers both **onchain operations** (list, offer, buy, cancel, mint and deploy collections) and the **Medialane API** (assets, collections, orders, activity, search, creator profiles and metadata uploads). It is the same SDK that powers [medialane.io](https://medialane.io), [starknet.medialane.io](https://starknet.medialane.io) and [portal.medialane.io](https://portal.medialane.io).
|
|
8
|
+
|
|
9
|
+
Framework-agnostic TypeScript, designed for many chains, live today on Starknet mainnet.
|
|
8
10
|
|
|
9
11
|
---
|
|
10
12
|
|
|
@@ -25,8 +27,7 @@ The Medialane SDK provides a unified interface for interacting with the Medialan
|
|
|
25
27
|
- Query orders, tokens, collections, and activities
|
|
26
28
|
- Full-text search across the marketplace
|
|
27
29
|
- Intent-based transaction orchestration
|
|
28
|
-
- Upload metadata and files to IPFS
|
|
29
|
-
- Portal: API keys, credits, usage
|
|
30
|
+
- Upload metadata and files to IPFS
|
|
30
31
|
- ERC-1155 multi-holder ownership via `token.balances`
|
|
31
32
|
|
|
32
33
|
**IP Metadata Types**
|
|
@@ -61,166 +62,62 @@ yarn add @medialane/sdk starknet
|
|
|
61
62
|
### Initialize the Client
|
|
62
63
|
|
|
63
64
|
```typescript
|
|
64
|
-
import { MedialaneClient } from "@medialane/sdk";
|
|
65
|
+
import { MedialaneClient } from "@medialane/sdk/starknet";
|
|
65
66
|
|
|
66
67
|
const client = new MedialaneClient({
|
|
67
68
|
chain: "STARKNET", // chain-scoped (default "STARKNET"); replaces `network` (v0.37.0)
|
|
68
69
|
rpcUrl: "https://rpc.starknet.lava.build", // optional; defaults to the chain's registry rpcUrl
|
|
69
|
-
backendUrl: "https://medialane
|
|
70
|
+
backendUrl: "https://api.medialane.io", // required for .api methods
|
|
70
71
|
apiKey: "ml_live_...", // from Medialane Portal
|
|
71
72
|
});
|
|
72
73
|
```
|
|
73
74
|
|
|
74
75
|
---
|
|
75
76
|
|
|
76
|
-
##
|
|
77
|
-
|
|
78
|
-
All methods require a `starknet.js` `AccountInterface`. SNIP-12 signing and `waitForTransaction` are handled automatically. Fulfilment is **unsigned**: the caller is the fulfiller, so there is no `fulfiller`/`offerer` field to pass; cancellation still signs, but without a nonce (a per-offerer `counter` replaces it, see `incrementCounter`).
|
|
79
|
-
|
|
80
|
-
Two marketplace modules are available:
|
|
81
|
-
- `client.marketplace`: ERC-721 marketplace (`Medialane721`)
|
|
82
|
-
- `client.marketplace1155`: ERC-1155 marketplace (`Medialane1155`)
|
|
77
|
+
## Onchain actions
|
|
83
78
|
|
|
84
|
-
|
|
79
|
+
Every onchain action (list, offer, buy, cancel, checkout, mint, deploy a collection, launch a coin, sponsor) follows the same flow. You ask the API for an **intent**, sign it if it needs a signature, and execute the resulting calls from the user's own account. Nothing is ever signed or sent on the user's behalf.
|
|
85
80
|
|
|
86
81
|
```typescript
|
|
87
|
-
import {
|
|
82
|
+
import { executeIntent } from "@medialane/sdk/starknet";
|
|
83
|
+
import { RpcProvider, Account, stark } from "starknet";
|
|
88
84
|
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
tokenId: "42",
|
|
92
|
-
currency: "USDC",
|
|
93
|
-
price: "1000000", // 1 USDC (6 decimals)
|
|
94
|
-
durationSeconds: 86400 * 30, // 30 days
|
|
95
|
-
});
|
|
96
|
-
console.log("Listed:", result.txHash);
|
|
97
|
-
```
|
|
85
|
+
const provider = new RpcProvider({ nodeUrl: "https://..." });
|
|
86
|
+
const account: Account = /* the user's account */;
|
|
98
87
|
|
|
99
|
-
|
|
88
|
+
const signer = {
|
|
89
|
+
address: account.address,
|
|
90
|
+
signTypedData: async (data) => stark.formatSignature(await account.signMessage(data)),
|
|
91
|
+
execute: async (calls) => ({ txHash: (await account.execute(calls)).transaction_hash }),
|
|
92
|
+
};
|
|
100
93
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
nftContract: "
|
|
94
|
+
const { data: intent } = await client.api.createListingIntent({
|
|
95
|
+
offerer: account.address,
|
|
96
|
+
nftContract: "0x...",
|
|
104
97
|
tokenId: "42",
|
|
105
|
-
currency: "
|
|
106
|
-
price: "
|
|
107
|
-
|
|
108
|
-
});
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
### Fulfill an Order
|
|
112
|
-
|
|
113
|
-
```typescript
|
|
114
|
-
// Fetch order details first to get paymentToken and totalPrice
|
|
115
|
-
const details = await client.api.getOrder(orderHash);
|
|
116
|
-
|
|
117
|
-
const result = await client.marketplace.fulfillOrder(account, {
|
|
118
|
-
orderHash: "0x...",
|
|
119
|
-
paymentToken: "0x033068...", // from order details
|
|
120
|
-
totalPrice: "1000000", // raw token units
|
|
121
|
-
});
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
### Cart Checkout (Multiple Items)
|
|
125
|
-
|
|
126
|
-
```typescript
|
|
127
|
-
const result = await client.marketplace.checkoutCart(account, [
|
|
128
|
-
{ orderHash: "0x...", considerationToken: "0x033068...", considerationAmount: "1000000" },
|
|
129
|
-
{ orderHash: "0x...", considerationToken: "0x033068...", considerationAmount: "500000" },
|
|
130
|
-
]);
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
### Cancel an Order
|
|
134
|
-
|
|
135
|
-
```typescript
|
|
136
|
-
const result = await client.marketplace.cancelOrder(account, {
|
|
137
|
-
orderHash: "0x...",
|
|
138
|
-
});
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
### Bulk-Cancel (Invalidate All Open Orders)
|
|
142
|
-
|
|
143
|
-
```typescript
|
|
144
|
-
// Bumps the caller's counter: every previously-registered order becomes unfulfillable.
|
|
145
|
-
await client.marketplace.incrementCounter(account);
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
### Mint an IP Asset
|
|
149
|
-
|
|
150
|
-
```typescript
|
|
151
|
-
const result = await client.marketplace.mint(account, {
|
|
152
|
-
collectionId: "1", // collection ID on the registry
|
|
153
|
-
recipient: account.address,
|
|
154
|
-
tokenUri: "ipfs://...", // IPFS URI of the metadata JSON
|
|
155
|
-
royaltyBps: 500, // EIP-2981 secondary-sale royalty, 0-10_000 (required since MIP v0.4.0)
|
|
156
|
-
});
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
### Deploy a Collection
|
|
160
|
-
|
|
161
|
-
```typescript
|
|
162
|
-
const result = await client.marketplace.createCollection(account, {
|
|
163
|
-
name: "My Creative Works",
|
|
164
|
-
symbol: "MCW",
|
|
165
|
-
baseUri: "",
|
|
166
|
-
});
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
---
|
|
170
|
-
|
|
171
|
-
## ERC-1155 Marketplace (Medialane1155)
|
|
172
|
-
|
|
173
|
-
For IP assets from ERC-1155 collections (e.g. IP-Programmable-ERC1155-Collections). Contract address: read `getCoordinates("STARKNET").marketplace1155` from `src/chains.ts`, the single source of truth across redeploys.
|
|
174
|
-
|
|
175
|
-
### Create an ERC-1155 Listing
|
|
176
|
-
|
|
177
|
-
```typescript
|
|
178
|
-
const result = await client.marketplace1155.createListing(account, {
|
|
179
|
-
nftContract: "0x...", // ERC-1155 collection address
|
|
180
|
-
tokenId: "1",
|
|
181
|
-
amount: "10", // number of tokens to sell
|
|
182
|
-
pricePerUnit: "1", // human-readable price per token (e.g. "1" USDC)
|
|
183
|
-
currency: "USDC",
|
|
184
|
-
durationSeconds: 86400 * 30,
|
|
185
|
-
});
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
`set_approval_for_all` is granted automatically if not already in place.
|
|
189
|
-
|
|
190
|
-
### Fulfill an ERC-1155 Order
|
|
191
|
-
|
|
192
|
-
```typescript
|
|
193
|
-
// Fetch order details first to get paymentToken and totalPrice
|
|
194
|
-
const details = await client.api.getOrder(orderHash);
|
|
195
|
-
|
|
196
|
-
const result = await client.marketplace1155.fulfillOrder(account, {
|
|
197
|
-
orderHash: "0x...",
|
|
198
|
-
paymentToken: "0x033068...", // from order details
|
|
199
|
-
totalPrice: "10000000", // pricePerUnit × amount in raw token units
|
|
98
|
+
currency: "0x033068...", // USDC
|
|
99
|
+
price: "1000000", // 1 USDC, in the token's smallest unit
|
|
100
|
+
endTime: Math.floor(Date.now() / 1000) + 86400 * 30,
|
|
200
101
|
});
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
ERC-2981 royalties are automatically deducted by the contract at fulfillment.
|
|
204
|
-
|
|
205
|
-
### Cancel an ERC-1155 Order
|
|
206
102
|
|
|
207
|
-
|
|
208
|
-
const result = await client.marketplace1155.cancelOrder(account, {
|
|
209
|
-
orderHash: "0x...",
|
|
210
|
-
});
|
|
103
|
+
const { txHash } = await executeIntent(provider, signer, client, intent);
|
|
211
104
|
```
|
|
212
105
|
|
|
213
|
-
|
|
106
|
+
The same pattern works with `createOfferIntent`, `createFulfillIntent`, `createCancelIntent`, `createCheckoutIntent`, `createMintIntent`, `createCollectionIntent`, `createCoinIntent` and the sponsorship intents.
|
|
214
107
|
|
|
215
|
-
|
|
216
|
-
the fulfiller, since v0.26.0): there is no fulfillment typed-data builder.
|
|
108
|
+
### Launchpad services
|
|
217
109
|
|
|
218
|
-
|
|
219
|
-
import { build1155OrderTypedData, build1155CancellationTypedData } from "@medialane/sdk";
|
|
220
|
-
import { constants } from "starknet";
|
|
110
|
+
Launchpad services are available under `client.services`:
|
|
221
111
|
|
|
222
|
-
|
|
223
|
-
|
|
112
|
+
| Service | What it does |
|
|
113
|
+
|---|---|
|
|
114
|
+
| `client.services.pop` | Proof of participation badges: create, claim, issue, burn |
|
|
115
|
+
| `client.services.drop` | Timed collection drops |
|
|
116
|
+
| `client.services.erc1155Collection` | Limited editions collections |
|
|
117
|
+
| `client.services.creatorCoin` | Creator coins with a public trading pool |
|
|
118
|
+
| `client.services.ticket` | IP Tickets |
|
|
119
|
+
| `client.services.club` | IP Club memberships |
|
|
120
|
+
| `client.services.sponsorship` | IP Sponsorship |
|
|
224
121
|
|
|
225
122
|
---
|
|
226
123
|
|
|
@@ -330,40 +227,6 @@ const metaResult = await client.api.uploadMetadata({
|
|
|
330
227
|
// metaResult.data.url → "ipfs://..."
|
|
331
228
|
```
|
|
332
229
|
|
|
333
|
-
### Intents (Advanced)
|
|
334
|
-
|
|
335
|
-
The intent system handles the SNIP-12 signing flow for marketplace operations:
|
|
336
|
-
|
|
337
|
-
```typescript
|
|
338
|
-
// 1. Create intent (gets typedData to sign)
|
|
339
|
-
const intent = await client.api.createListingIntent({
|
|
340
|
-
offerer: address,
|
|
341
|
-
nftContract: "0x...",
|
|
342
|
-
tokenId: "42",
|
|
343
|
-
currency: "0x033068...",
|
|
344
|
-
price: "1000000",
|
|
345
|
-
endTime: Math.floor(Date.now() / 1000) + 86400 * 30,
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
// 2. Sign typedData
|
|
349
|
-
const signature = await account.signMessage(intent.data.typedData);
|
|
350
|
-
|
|
351
|
-
// 3. Submit signature
|
|
352
|
-
await client.api.submitIntentSignature(intent.data.id, toSignatureArray(signature));
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
Mint and collection intents are pre-signed: no signature step needed:
|
|
356
|
-
|
|
357
|
-
```typescript
|
|
358
|
-
const mintIntent = await client.api.createMintIntent({
|
|
359
|
-
owner: ownerAddress,
|
|
360
|
-
collectionId: "1",
|
|
361
|
-
recipient: recipientAddress,
|
|
362
|
-
tokenUri: "ipfs://...",
|
|
363
|
-
});
|
|
364
|
-
// mintIntent.data.calls → ready to execute
|
|
365
|
-
```
|
|
366
|
-
|
|
367
230
|
---
|
|
368
231
|
|
|
369
232
|
## IP Metadata Types
|
|
@@ -445,11 +308,12 @@ import {
|
|
|
445
308
|
## Error Handling
|
|
446
309
|
|
|
447
310
|
```typescript
|
|
448
|
-
import {
|
|
311
|
+
import { MedialaneApiError } from "@medialane/sdk";
|
|
312
|
+
import { MedialaneError, executeIntent } from "@medialane/sdk/starknet";
|
|
449
313
|
|
|
450
|
-
//
|
|
314
|
+
// Onchain errors
|
|
451
315
|
try {
|
|
452
|
-
await
|
|
316
|
+
await executeIntent(provider, signer, client, intent);
|
|
453
317
|
} catch (err) {
|
|
454
318
|
if (err instanceof MedialaneError) {
|
|
455
319
|
console.error("On-chain error:", err.message, err.cause);
|
|
@@ -476,6 +340,7 @@ message belongs to whatever your screen was trying to do.
|
|
|
476
340
|
| `MedialaneApiError` | The API refused the request | `err.message`, which is the reason the API gave or a plain statement of the status |
|
|
477
341
|
| `UserFacingError` | The SDK got partway and stopped, for example a transaction that reverted | `err.message` |
|
|
478
342
|
| `PasskeyCancelledError` | The prompt was dismissed | Nothing was submitted, so avoid wording it as a failure |
|
|
343
|
+
| `PasskeyUnsupportedError` | `err.reason`: `"no-webauthn"` or `"no-prf"` | Your own wording |
|
|
479
344
|
|
|
480
345
|
```typescript
|
|
481
346
|
import { MedialaneApiError, PasskeyCancelledError, UserFacingError } from "@medialane/sdk";
|
|
@@ -521,18 +386,15 @@ without reaching a reader.
|
|
|
521
386
|
|
|
522
387
|
## Advanced: SNIP-12 Typed Data Builders
|
|
523
388
|
|
|
524
|
-
For integrations that
|
|
389
|
+
For integrations that build and sign marketplace orders themselves:
|
|
525
390
|
|
|
526
391
|
```typescript
|
|
527
392
|
import {
|
|
528
393
|
buildOrderTypedData,
|
|
529
|
-
buildFulfillmentTypedData,
|
|
530
394
|
buildCancellationTypedData,
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
const signature = await account.signMessage(typedData);
|
|
535
|
-
await client.api.submitIntentSignature(intentId, signatureArray);
|
|
395
|
+
build1155OrderTypedData,
|
|
396
|
+
build1155CancellationTypedData,
|
|
397
|
+
} from "@medialane/sdk/starknet";
|
|
536
398
|
```
|
|
537
399
|
|
|
538
400
|
---
|
|
@@ -555,142 +417,14 @@ Built with:
|
|
|
555
417
|
|
|
556
418
|
## Changelog
|
|
557
419
|
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
### v0.37.0: multichain readiness (BREAKING)
|
|
561
|
-
- **Chain is a first-class axis.** New `chains.ts` `coordinates[chain]` registry is the single source of per-chain service coordinates (`CHAINS`, `getCoordinates`, `DEFAULT_CHAIN`, `Chain`, `ChainCoordinates`); the flat `*_MAINNET` constants derive from it.
|
|
562
|
-
- **`MedialaneConfig.chain` replaces `network`**: the client is chain-scoped; `client.network` getter → `client.chain`.
|
|
563
|
-
- **`ServiceDefinition.onchain` is per-chain**: `Partial<Record<Chain, …>>`; read `service.onchain?.STARKNET?.factoryAddress`.
|
|
564
|
-
- **`normalizeAddress(chain, address)`**: per-chain codec (Starknet pad / EVM EIP-55 / Solana base58; Bitcoin not yet implemented).
|
|
565
|
-
- **Removed** `SUPPORTED_NETWORKS`, `DEFAULT_RPC_URL`, `Network` (mainnet-only: coordinates key by chain alone). `getChainId(config)` throws for non-Starknet.
|
|
566
|
-
|
|
567
|
-
### v0.6.7
|
|
568
|
-
- **`CollectionRegistryABI`** exported from `@medialane/sdk`: minimal ABI covering `list_user_collections` and `get_collection` on the collection registry contract. Eliminates duplicated inline ABI definitions in consuming apps.
|
|
569
|
-
|
|
570
|
-
### v0.6.6
|
|
571
|
-
- **`COLLECTION_CONTRACT_MAINNET`** updated to audited v2 contract address `0x05c49ee5d3208a2c2e150fdd0c247d1195ed9ab54fa2d5dea7a633f39e4b205b`
|
|
572
|
-
|
|
573
|
-
### v0.6.5
|
|
574
|
-
- **ERC-1155 support**: `ApiToken.balances: ApiTokenBalance[] | null` replaces the single `owner` field for ownership checks
|
|
575
|
-
- **`ApiTokenBalance`** type: `{ owner: string; amount: string }`: each entry represents one holder and their quantity
|
|
576
|
-
- **`ApiToken.owner`** deprecated: always `null` after the ERC-1155 migration; use `balances` instead
|
|
577
|
-
- **`ApiCollection.standard`**: `"ERC721" | "ERC1155" | "UNKNOWN"` detected via ERC-165 `supportsInterface`
|
|
578
|
-
- **`totalSupply` fix**: ERC-1155 collections now report `SUM(holder amounts)` for an accurate circulating total
|
|
579
|
-
|
|
580
|
-
### v0.6.1
|
|
581
|
-
- **Collection Drop**: new `DropService` (`client.services.drop`) with full on-chain drop management: `claim`, `adminMint`, `setClaimConditions`, `setAllowlistEnabled`, `addToAllowlist`, `batchAddToAllowlist`, `setPaused`, `withdrawPayments`, `createDrop`
|
|
582
|
-
- **`client.api.getDropCollections(opts?)`**: list all `COLLECTION_DROP` collections
|
|
583
|
-
- **`client.api.getDropMintStatus(collection, wallet)`**: returns `{ mintedByWallet, totalMinted }`
|
|
584
|
-
- **`DropMintStatus`**, **`ClaimConditions`**, **`CreateDropParams`** types exported
|
|
585
|
-
- **`DropCollectionABI`** and **`DropFactoryABI`** exported from `@medialane/sdk`
|
|
586
|
-
- **`DROP_FACTORY_CONTRACT_MAINNET`** and **`DROP_COLLECTION_CLASS_HASH_MAINNET`** constants exported
|
|
587
|
-
- **`CollectionSource`** union extended with `"COLLECTION_DROP"`
|
|
588
|
-
|
|
589
|
-
### v0.6.0
|
|
590
|
-
- **POP Protocol**: `PopService` (`client.services.pop`): `claim`, `adminMint`, `addToAllowlist`, `batchAddToAllowlist`, `removeFromAllowlist`, `setTokenUri`, `setPaused`, `createCollection`
|
|
591
|
-
- **`client.api.getPopCollections(opts?)`** and **`client.api.getPopEligibility(collection, wallet)`**
|
|
592
|
-
- **`POPCollectionABI`** and **`POPFactoryABI`** exported
|
|
593
|
-
- **`POP_FACTORY_CONTRACT_MAINNET`** and **`POP_COLLECTION_CLASS_HASH_MAINNET`** constants exported
|
|
594
|
-
|
|
595
|
-
### v0.5.7
|
|
596
|
-
- **`ApiCollectionProfile.hasGatedContent: boolean`**: whether the collection has token-gated content configured
|
|
597
|
-
- **`ApiCollectionProfile.gatedContentTitle: string | null`**: public title of gated content (shown to all users; URL is accessible to holders only via the backend gated-content endpoint)
|
|
598
|
-
|
|
599
|
-
### v0.5.5
|
|
600
|
-
- **`extendRemixOffer(id, days, siwsToken)`**: requester extends expiry of a PENDING/AUTO_PENDING remix offer by 1–30 days (`POST /v1/remix-offers/:id/extend`)
|
|
601
|
-
- **`ApiRemixOfferPrice`** type: `{ raw, formatted, currency, decimals }` replaces flat `proposedPrice`/`proposedCurrency` fields on `ApiRemixOffer.price` (visible to participants only)
|
|
602
|
-
|
|
603
|
-
### v0.5.4
|
|
604
|
-
- **`ApiRemixOffer.price`** shape introduced: backend now serializes price as a structured object (`raw`, `formatted`, `currency`, `decimals`), replacing raw wei strings
|
|
605
|
-
|
|
606
|
-
### v0.5.3
|
|
607
|
-
- **`getTokenComments(contract, tokenId, opts?)`**: fetch on-chain NFT comments for a token (`GET /v1/tokens/:contract/:tokenId/comments`)
|
|
608
|
-
- **`ApiComment`** type: `{ id, author, content, txHash, blockNumber, blockTimestamp, isHidden, createdAt }`
|
|
609
|
-
|
|
610
|
-
### v0.5.0
|
|
611
|
-
- **Counter-offer support**: `createCounterOfferIntent(params, siwsToken)`, `getCounterOffers(query)`, `ApiCounterOffersQuery`, `CreateCounterOfferIntentParams`
|
|
612
|
-
- **`OrderStatus`** extended with `"COUNTER_OFFERED"`; **`IntentType`** with `"COUNTER_OFFER"`
|
|
613
|
-
- **`ApiOrder`** extended: `parentOrderHash?: string | null`, `counterOfferMessage?: string | null`
|
|
614
|
-
- **Remix licensing**: full set of remix offer methods and types:
|
|
615
|
-
- `submitRemixOffer(params, siwsToken)`: custom offer
|
|
616
|
-
- `submitAutoRemixOffer(params, siwsToken)`: auto offer for open-license tokens
|
|
617
|
-
- `confirmSelfRemix(params, siwsToken)`: record owner self-remix
|
|
618
|
-
- `getRemixOffers(query, siwsToken)`: list by role
|
|
619
|
-
- `getRemixOffer(id, siwsToken?)`: single offer
|
|
620
|
-
- `confirmRemixOffer(id, params, siwsToken)`: creator approves
|
|
621
|
-
- `rejectRemixOffer(id, siwsToken)`: creator rejects
|
|
622
|
-
- `getTokenRemixes(contract, tokenId, opts?)`: public remix list
|
|
623
|
-
- **New types**: `RemixOfferStatus`, `ApiRemixOffer`, `ApiPublicRemix`, `OPEN_LICENSES`, `OpenLicense`, `CreateRemixOfferParams`, `AutoRemixOfferParams`, `ConfirmSelfRemixParams`, `ConfirmRemixOfferParams`, `ApiRemixOffersQuery`
|
|
624
|
-
|
|
625
|
-
### v0.4.8
|
|
626
|
-
- **`ApiComment`** type + **`getTokenComments`** (patch release, backported into v0.5.3)
|
|
627
|
-
|
|
628
|
-
### v0.4.7
|
|
629
|
-
- **`IPType`** union type exported: `"Audio" | "Art" | "Documents" | "NFT" | "Video" | "Photography" | "Patents" | "Posts" | "Publications" | "RWA" | "Software" | "Custom"`
|
|
630
|
-
|
|
631
|
-
### v0.4.6
|
|
632
|
-
- **`ApiUserWallet`** type + `upsertMyWallet(siwsToken)` / `getMyWallet(siwsToken)` for wallet registration fallback (`POST/GET /v1/users/me`)
|
|
633
|
-
|
|
634
|
-
### v0.4.5
|
|
635
|
-
- **`ApiSearchCreatorResult`** type + `ApiSearchResult.creators`: creator profiles now included in search results
|
|
636
|
-
|
|
637
|
-
### v0.4.4
|
|
638
|
-
- **`ApiCreatorListResult`** + `getCreators(opts?)`: list creators with search/pagination via `GET /v1/creators`
|
|
639
|
-
|
|
640
|
-
### v0.4.3
|
|
641
|
-
- **`ApiCreatorProfile.username`** field + `getCreatorByUsername(username)`: resolve username slug to creator profile
|
|
642
|
-
|
|
643
|
-
### v0.4.2
|
|
644
|
-
- **WBTC** added to `SUPPORTED_TOKENS` (`0x03fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac`, 8 decimals)
|
|
645
|
-
- **`listable` field** on every `SUPPORTED_TOKENS` entry: controls whether a token appears in listing/offer dialogs vs filter-only
|
|
646
|
-
- **`getListableTokens()`**: returns tokens filtered to `listable: true`; exported from package root
|
|
647
|
-
- **ETH** promoted to `listable: true`: now available in listing and offer dialogs
|
|
648
|
-
- **USDC.e removed**: bridged USDC (`0x053c91...`) removed entirely; only Circle-native USDC remains, to avoid user confusion
|
|
649
|
-
|
|
650
|
-
### v0.4.1
|
|
651
|
-
- **Collection claims**: `claimCollection(contractAddress, walletAddress, siwsToken)` for on-chain ownership verification; `requestCollectionClaim({ contractAddress, walletAddress?, email, notes? })` for manual review
|
|
652
|
-
- **Collection profiles**: `getCollectionProfile(contractAddress)` and `updateCollectionProfile(contractAddress, data, siwsToken)` for enriched display metadata (displayName, description, image, bannerImage, social links)
|
|
653
|
-
- **Creator profiles**: `getCreatorProfile(walletAddress)` and `updateCreatorProfile(walletAddress, data, siwsToken)` for creator display metadata
|
|
654
|
-
- **New types**: `ApiCollectionClaim`, `ApiAdminCollectionClaim`, `ApiCollectionProfile`, `ApiCreatorProfile`
|
|
655
|
-
- **`ApiCollection`** extended with `source` (`"MEDIALANE_REGISTRY" | "EXTERNAL" | "PARTNERSHIP" | "IP_TICKET" | "IP_CLUB" | "GAME"`) and `claimedBy: string | null`
|
|
656
|
-
- `profile?: ApiCollectionProfile | null` optionally embedded on `ApiCollection` when `?include=profile`
|
|
657
|
-
|
|
658
|
-
### v0.4.0
|
|
659
|
-
- **Typed error codes**: `MedialaneError` and `MedialaneApiError` now expose a `.code: MedialaneErrorCode` property (`"TOKEN_NOT_FOUND"` | `"RATE_LIMITED"` | `"INTENT_EXPIRED"` | `"UNAUTHORIZED"` | `"INVALID_PARAMS"` | `"NETWORK_NOT_SUPPORTED"` | `"UNKNOWN"`)
|
|
660
|
-
- **Automatic retry**: all API requests retry up to 3 times with exponential backoff (300ms base, 5s cap) on transient failures. Configure via `retryOptions` in `MedialaneConfig`
|
|
661
|
-
- **`RetryOptions`** type exported from index
|
|
662
|
-
- **`CollectionSort`** named union type exported (`"recent" | "supply" | "floor" | "volume" | "name"`)
|
|
663
|
-
- **Sepolia guard**: constructing a client with `network: "sepolia"` and no explicit contract addresses now throws `NETWORK_NOT_SUPPORTED` immediately
|
|
664
|
-
|
|
665
|
-
### v0.3.3
|
|
666
|
-
- `getCollections(page?, limit?, isKnown?, sort?)`: added `sort` parameter: `"recent"` (default) | `"supply"` | `"floor"` | `"volume"` | `"name"`
|
|
667
|
-
- Default sort changed from `totalSupply DESC` to `createdAt DESC` (newest first): matches backend default
|
|
668
|
-
|
|
669
|
-
### v0.3.1
|
|
670
|
-
- `ApiCollection.collectionId: string | null`: on-chain registry numeric ID (decimal string). Required for `createMintIntent`. Populated for collections indexed after 2026-03-09.
|
|
671
|
-
|
|
672
|
-
### v0.3.0
|
|
673
|
-
- `normalizeAddress()` applied internally before all API calls: callers no longer need to normalize Starknet addresses
|
|
674
|
-
- `ApiCollection.owner: string | null`: populated from intent typedData or on-chain `owner()` call
|
|
675
|
-
- `getCollectionsByOwner(owner)`: fetch collections by wallet address via `GET /v1/collections?owner=`
|
|
676
|
-
|
|
677
|
-
### v0.2.6
|
|
678
|
-
- `ApiOrder.token: ApiOrderTokenMeta | null`: token name/image/description embedded on orders (batchTokenMeta); no per-row `getToken` calls needed
|
|
679
|
-
|
|
680
|
-
### v0.2.0
|
|
681
|
-
- `IpAttribute` and `IpNftMetadata` interfaces for IP metadata
|
|
682
|
-
- `ApiTokenMetadata.attributes` typed as `IpAttribute[] | null` (was `unknown`)
|
|
683
|
-
- `ApiTokenMetadata` extended with `derivatives`, `attribution`, `territory`, `aiPolicy`, `royalty`, `registration`, `standard`
|
|
684
|
-
- Added `USDC.e` (bridged USDC via Starkgate) to `SUPPORTED_TOKENS`
|
|
685
|
-
|
|
686
|
-
### v0.1.0
|
|
687
|
-
- Initial release: orders, tokens, collections, activities, intents, metadata, portal
|
|
420
|
+
See [CHANGELOG.md](./CHANGELOG.md).
|
|
688
421
|
|
|
689
422
|
---
|
|
690
423
|
|
|
691
424
|
## Links
|
|
692
425
|
|
|
693
|
-
- **
|
|
426
|
+
- **Medialane**: [medialane.io](https://medialane.io)
|
|
427
|
+
- **Docs**: [docs.medialane.io/dev](https://docs.medialane.io/dev)
|
|
694
428
|
- **Starknet App**: [starknet.medialane.io](https://starknet.medialane.io)
|
|
695
429
|
- **Developer Portal**: [portal.medialane.io](https://portal.medialane.io)
|
|
696
430
|
- **npm**: [npmjs.com/package/@medialane/sdk](https://www.npmjs.com/package/@medialane/sdk)
|
|
@@ -1164,6 +1164,15 @@ var PasskeyCancelledError = class extends Error {
|
|
|
1164
1164
|
this.name = "PasskeyCancelledError";
|
|
1165
1165
|
}
|
|
1166
1166
|
};
|
|
1167
|
+
var PasskeyUnsupportedError = class extends Error {
|
|
1168
|
+
constructor(reason) {
|
|
1169
|
+
super(
|
|
1170
|
+
reason === "no-webauthn" ? "Passkeys are not available in this environment." : "This passkey did not return a PRF secret, so it cannot seal a wallet key."
|
|
1171
|
+
);
|
|
1172
|
+
this.name = "PasskeyUnsupportedError";
|
|
1173
|
+
this.reason = reason;
|
|
1174
|
+
}
|
|
1175
|
+
};
|
|
1167
1176
|
var encodeBase64 = (buf) => {
|
|
1168
1177
|
const bytes = buf instanceof Uint8Array ? buf : new Uint8Array(buf);
|
|
1169
1178
|
let binary = "";
|
|
@@ -1184,15 +1193,24 @@ function createPasskeyOwner(config) {
|
|
|
1184
1193
|
const randomBytes = config.randomBytes ?? ((length) => crypto.getRandomValues(new Uint8Array(length)));
|
|
1185
1194
|
const credentialsApi = () => {
|
|
1186
1195
|
const api = config.credentials ?? (typeof navigator === "undefined" ? void 0 : navigator.credentials);
|
|
1187
|
-
if (!api) throw new
|
|
1196
|
+
if (!api) throw new PasskeyUnsupportedError("no-webauthn");
|
|
1188
1197
|
return api;
|
|
1189
1198
|
};
|
|
1190
|
-
const
|
|
1191
|
-
const
|
|
1192
|
-
|
|
1193
|
-
|
|
1199
|
+
const browserRefusesPrf = async () => {
|
|
1200
|
+
const read = config.clientCapabilities ?? (typeof PublicKeyCredential !== "undefined" && typeof PublicKeyCredential.getClientCapabilities === "function" ? () => PublicKeyCredential.getClientCapabilities() : void 0);
|
|
1201
|
+
if (!read) return false;
|
|
1202
|
+
try {
|
|
1203
|
+
return (await read())["extension:prf"] === false;
|
|
1204
|
+
} catch {
|
|
1205
|
+
return false;
|
|
1206
|
+
}
|
|
1207
|
+
};
|
|
1208
|
+
const ensurePrfPossible = async () => {
|
|
1209
|
+
credentialsApi();
|
|
1210
|
+
if (await browserRefusesPrf()) throw new PasskeyUnsupportedError("no-prf");
|
|
1194
1211
|
};
|
|
1195
1212
|
async function registerPasskey() {
|
|
1213
|
+
await ensurePrfPossible();
|
|
1196
1214
|
let credential;
|
|
1197
1215
|
try {
|
|
1198
1216
|
credential = await credentialsApi().create({
|
|
@@ -1207,8 +1225,7 @@ function createPasskeyOwner(config) {
|
|
|
1207
1225
|
],
|
|
1208
1226
|
authenticatorSelection: {
|
|
1209
1227
|
residentKey: "required",
|
|
1210
|
-
userVerification: "required"
|
|
1211
|
-
authenticatorAttachment: "platform"
|
|
1228
|
+
userVerification: "required"
|
|
1212
1229
|
},
|
|
1213
1230
|
extensions: { prf: { eval: { first: config.prfSalt } } }
|
|
1214
1231
|
}
|
|
@@ -1221,6 +1238,7 @@ function createPasskeyOwner(config) {
|
|
|
1221
1238
|
return { credentialId: encodeBase64(credential.rawId), prfFirst: prf?.results?.first ?? null };
|
|
1222
1239
|
}
|
|
1223
1240
|
async function prfSecret(credentialId) {
|
|
1241
|
+
await ensurePrfPossible();
|
|
1224
1242
|
let assertion;
|
|
1225
1243
|
try {
|
|
1226
1244
|
assertion = await credentialsApi().get({
|
|
@@ -1237,16 +1255,12 @@ function createPasskeyOwner(config) {
|
|
|
1237
1255
|
throw err;
|
|
1238
1256
|
}
|
|
1239
1257
|
const result = assertion.getClientExtensionResults().prf?.results?.first;
|
|
1240
|
-
if (!result) throw new
|
|
1258
|
+
if (!result) throw new PasskeyUnsupportedError("no-prf");
|
|
1241
1259
|
return new Uint8Array(result);
|
|
1242
1260
|
}
|
|
1243
1261
|
async function secretFromRegistration(registration) {
|
|
1244
1262
|
if (registration.prfFirst) return new Uint8Array(registration.prfFirst);
|
|
1245
|
-
|
|
1246
|
-
return await prfSecret(registration.credentialId);
|
|
1247
|
-
} catch {
|
|
1248
|
-
throw new Error(prfUnsupportedMessage());
|
|
1249
|
-
}
|
|
1263
|
+
return prfSecret(registration.credentialId);
|
|
1250
1264
|
}
|
|
1251
1265
|
async function seal(secret, privateKeyHex) {
|
|
1252
1266
|
const aes = await deriveAesKey(secret, config.hkdfInfo);
|
|
@@ -1292,6 +1306,26 @@ function createPasskeyOwner(config) {
|
|
|
1292
1306
|
};
|
|
1293
1307
|
}
|
|
1294
1308
|
|
|
1309
|
+
// src/routes.ts
|
|
1310
|
+
var SUPPORTED_URL_CHAINS = ["STARKNET"];
|
|
1311
|
+
function chainSlug(chain) {
|
|
1312
|
+
return chain.toLowerCase();
|
|
1313
|
+
}
|
|
1314
|
+
function chainFromSlug(slug) {
|
|
1315
|
+
const upper = slug.toUpperCase();
|
|
1316
|
+
return SUPPORTED_URL_CHAINS.includes(upper) ? upper : null;
|
|
1317
|
+
}
|
|
1318
|
+
var seg = (v) => v == null ? "" : String(v);
|
|
1319
|
+
function assetHref(chain, contract, tokenId) {
|
|
1320
|
+
return `/asset/${chainSlug(chain)}/${seg(contract)}/${seg(tokenId)}`;
|
|
1321
|
+
}
|
|
1322
|
+
function collectionHref(chain, contract) {
|
|
1323
|
+
return `/collections/${chainSlug(chain)}/${seg(contract)}`;
|
|
1324
|
+
}
|
|
1325
|
+
function coinHref(chain, address) {
|
|
1326
|
+
return `/coins/${chainSlug(chain)}/${seg(address)}`;
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1295
1329
|
// src/services/registry.ts
|
|
1296
1330
|
var SN2 = chunkH7I6TEOA_cjs.getStarknetCoordinates("STARKNET");
|
|
1297
1331
|
var SERVICES = {
|
|
@@ -1769,6 +1803,7 @@ exports.InvalidStarkPrivateKeyError = InvalidStarkPrivateKeyError;
|
|
|
1769
1803
|
exports.MedialaneApiError = MedialaneApiError;
|
|
1770
1804
|
exports.POLICY_REFUSAL_CODES = POLICY_REFUSAL_CODES;
|
|
1771
1805
|
exports.PasskeyCancelledError = PasskeyCancelledError;
|
|
1806
|
+
exports.PasskeyUnsupportedError = PasskeyUnsupportedError;
|
|
1772
1807
|
exports.STARKNET_COLLECTION_1155_CLASS_HASH = STARKNET_COLLECTION_1155_CLASS_HASH;
|
|
1773
1808
|
exports.STARKNET_COLLECTION_1155_CONTRACT = STARKNET_COLLECTION_1155_CONTRACT;
|
|
1774
1809
|
exports.STARKNET_COLLECTION_1155_FACTORY_CLASS_HASH = STARKNET_COLLECTION_1155_FACTORY_CLASS_HASH;
|
|
@@ -1806,7 +1841,13 @@ exports.STARKNET_POP_COLLECTION_CLASS_HASH = STARKNET_POP_COLLECTION_CLASS_HASH;
|
|
|
1806
1841
|
exports.STARKNET_POP_FACTORY_CONTRACT = STARKNET_POP_FACTORY_CONTRACT;
|
|
1807
1842
|
exports.STARKNET_POP_FACTORY_START_BLOCK = STARKNET_POP_FACTORY_START_BLOCK;
|
|
1808
1843
|
exports.SUPPORTED_TOKENS = SUPPORTED_TOKENS;
|
|
1844
|
+
exports.SUPPORTED_URL_CHAINS = SUPPORTED_URL_CHAINS;
|
|
1809
1845
|
exports.UserFacingError = UserFacingError;
|
|
1846
|
+
exports.assetHref = assetHref;
|
|
1847
|
+
exports.chainFromSlug = chainFromSlug;
|
|
1848
|
+
exports.chainSlug = chainSlug;
|
|
1849
|
+
exports.coinHref = coinHref;
|
|
1850
|
+
exports.collectionHref = collectionHref;
|
|
1810
1851
|
exports.computeAccountAddress = computeAccountAddress;
|
|
1811
1852
|
exports.createFailoverFetch = createFailoverFetch;
|
|
1812
1853
|
exports.createPasskeyOwner = createPasskeyOwner;
|
|
@@ -1838,5 +1879,5 @@ exports.starkKeyPairFromPrivateKey = starkKeyPairFromPrivateKey;
|
|
|
1838
1879
|
exports.stringifyBigInts = stringifyBigInts;
|
|
1839
1880
|
exports.u256ToBigInt = u256ToBigInt;
|
|
1840
1881
|
exports.unsealPrivateKey = unsealPrivateKey;
|
|
1841
|
-
//# sourceMappingURL=chunk-
|
|
1842
|
-
//# sourceMappingURL=chunk-
|
|
1882
|
+
//# sourceMappingURL=chunk-GQWRNQD2.cjs.map
|
|
1883
|
+
//# sourceMappingURL=chunk-GQWRNQD2.cjs.map
|