@misofm/api-client 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +171 -5
- package/dist/cache.d.ts +71 -0
- package/dist/cache.js +119 -0
- package/dist/client.d.ts +150 -0
- package/dist/client.js +265 -0
- package/dist/index.d.ts +6 -0
- package/{src/index.ts → dist/index.js} +3 -9
- package/dist/schemas.d.ts +1314 -0
- package/dist/schemas.js +335 -0
- package/{src/types.ts → dist/types.d.ts} +1 -13
- package/dist/types.js +6 -0
- package/package.json +26 -12
- package/src/cache.test.ts +0 -90
- package/src/cache.ts +0 -91
- package/src/client.test.ts +0 -284
- package/src/client.ts +0 -325
- package/src/schemas.ts +0 -382
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import type { z } from "zod";
|
|
2
|
+
import { queryPolicy } from "./cache.js";
|
|
3
|
+
import type { ArtistProfile, Balance, ListingView, OwnedParty, PendingMembership, OwnedRecord, OwnedWork, Ownership, PartySummary, PressingView, PurchaseReceipt, RecordAlbum, ReleaseDetail, WorkDetail } from "./types.js";
|
|
4
|
+
export interface MisoRequestOptions {
|
|
5
|
+
/** Cancels this request without affecting other calls made by the client. */
|
|
6
|
+
signal?: AbortSignal;
|
|
7
|
+
/** Additional request headers. `Accept: application/json` is supplied by default. */
|
|
8
|
+
headers?: HeadersInit;
|
|
9
|
+
}
|
|
10
|
+
export interface MisoApiErrorOptions {
|
|
11
|
+
requestId?: string;
|
|
12
|
+
retryAfter?: number;
|
|
13
|
+
}
|
|
14
|
+
export declare class MisoApiError extends Error {
|
|
15
|
+
readonly status: number;
|
|
16
|
+
readonly code: string;
|
|
17
|
+
/** Correlation id supplied by the API, when available. */
|
|
18
|
+
readonly requestId?: string;
|
|
19
|
+
/** Delay requested by `Retry-After`, normalized to seconds. */
|
|
20
|
+
readonly retryAfter?: number;
|
|
21
|
+
constructor(status: number, code: string, message: string, metadata?: MisoApiErrorOptions);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The server said something this client cannot describe. Distinct from
|
|
25
|
+
* `MisoApiError`: this indicates API/client version skew rather than an
|
|
26
|
+
* expected API outcome.
|
|
27
|
+
*/
|
|
28
|
+
export declare class MisoApiContractError extends Error {
|
|
29
|
+
readonly issues: z.core.$ZodIssue[];
|
|
30
|
+
/** Correlation id supplied by the API, when available. */
|
|
31
|
+
readonly requestId?: string;
|
|
32
|
+
constructor(path: string, issues: z.core.$ZodIssue[], metadata?: MisoApiErrorOptions);
|
|
33
|
+
}
|
|
34
|
+
export interface MisoApiClientOptions {
|
|
35
|
+
/** Public API origin, e.g. `https://api.testnet.miso.fm`. */
|
|
36
|
+
baseUrl: string;
|
|
37
|
+
/**
|
|
38
|
+
* Cache buster appended as `?v=` to mutable public reads only. A surface that
|
|
39
|
+
* has just written something and must see its own change supplies a fresh
|
|
40
|
+
* value here (see {@link cacheBuster}). Returning `undefined` sends no `v`.
|
|
41
|
+
*
|
|
42
|
+
* Private wallet reads and immutable receipts/base record-album reads ignore
|
|
43
|
+
* this value: they are either not shared-cached or can never become fresher.
|
|
44
|
+
*/
|
|
45
|
+
version?: () => string | undefined;
|
|
46
|
+
/** Injectable for tests, Workers, and anything with its own fetch. */
|
|
47
|
+
fetch?: typeof globalThis.fetch;
|
|
48
|
+
/**
|
|
49
|
+
* Path the read endpoints are mounted under on `baseUrl`. The gateway routes
|
|
50
|
+
* `/read/*` to the read service, whose own routes are rooted at `/v1`.
|
|
51
|
+
*/
|
|
52
|
+
prefix?: string;
|
|
53
|
+
}
|
|
54
|
+
export type WalletOwnershipTarget = {
|
|
55
|
+
partyId: string;
|
|
56
|
+
recordId?: never;
|
|
57
|
+
} | {
|
|
58
|
+
partyId?: never;
|
|
59
|
+
recordId: string;
|
|
60
|
+
};
|
|
61
|
+
export declare function createMisoApiClient(options: MisoApiClientOptions): {
|
|
62
|
+
getPressing: (pressingId: string, opts?: MisoRequestOptions) => Promise<PressingView | null>;
|
|
63
|
+
getPressingListing: (pressingId: string, currencyType: string, opts?: MisoRequestOptions) => Promise<ListingView | null>;
|
|
64
|
+
getRelease: (releaseId: string, opts?: MisoRequestOptions & {
|
|
65
|
+
include?: readonly "trackCredits"[];
|
|
66
|
+
}) => Promise<ReleaseDetail | null>;
|
|
67
|
+
getRecordAlbum: (recordId: string, opts?: MisoRequestOptions & {
|
|
68
|
+
include?: readonly ("release" | "trackCredits")[];
|
|
69
|
+
}) => Promise<RecordAlbum | null>;
|
|
70
|
+
getArtist: (partyId: string, opts?: MisoRequestOptions & {
|
|
71
|
+
include?: readonly ("roles" | "tags")[];
|
|
72
|
+
}) => Promise<ArtistProfile | null>;
|
|
73
|
+
listArtists: (ids: readonly string[], opts?: MisoRequestOptions) => Promise<PartySummary[]>;
|
|
74
|
+
listWalletRecords: (address: string, opts?: MisoRequestOptions) => Promise<OwnedRecord[]>;
|
|
75
|
+
listWalletParties: (address: string, opts?: MisoRequestOptions) => Promise<OwnedParty[]>;
|
|
76
|
+
listWalletPendingMemberships: (address: string, opts?: MisoRequestOptions) => Promise<PendingMembership[]>;
|
|
77
|
+
listWalletWorks: (address: string, opts?: MisoRequestOptions) => Promise<OwnedWork[]>;
|
|
78
|
+
getWork: (capId: string, opts?: MisoRequestOptions) => Promise<WorkDetail | null>;
|
|
79
|
+
getWalletBalance: (address: string, coinType?: string, opts?: MisoRequestOptions) => Promise<Balance>;
|
|
80
|
+
getWalletOwnership: (address: string, target: WalletOwnershipTarget, opts?: MisoRequestOptions) => Promise<Ownership>;
|
|
81
|
+
getWalletPartyOwnership: (address: string, partyId: string, opts?: MisoRequestOptions) => Promise<Ownership>;
|
|
82
|
+
getWalletRecordOwnership: (address: string, recordId: string, opts?: MisoRequestOptions) => Promise<Ownership>;
|
|
83
|
+
getPurchaseReceipt: (pressingId: string, txDigest: string, opts?: MisoRequestOptions) => Promise<PurchaseReceipt | null>;
|
|
84
|
+
/** @deprecated Use {@link getPressingListing}. */
|
|
85
|
+
getListing: (pressingId: string, currencyType: string, opts?: MisoRequestOptions) => Promise<ListingView | null>;
|
|
86
|
+
/** @deprecated Use {@link listArtists}. */
|
|
87
|
+
getArtists: (ids: readonly string[], opts?: MisoRequestOptions) => Promise<PartySummary[]>;
|
|
88
|
+
/** @deprecated Use {@link listWalletRecords}. */
|
|
89
|
+
getWalletRecords: (address: string, opts?: MisoRequestOptions) => Promise<OwnedRecord[]>;
|
|
90
|
+
/** @deprecated Use {@link listWalletParties}. */
|
|
91
|
+
getWalletParties: (address: string, opts?: MisoRequestOptions) => Promise<OwnedParty[]>;
|
|
92
|
+
/** @deprecated Use {@link listWalletPendingMemberships}. */
|
|
93
|
+
getPendingMemberships: (address: string, opts?: MisoRequestOptions) => Promise<PendingMembership[]>;
|
|
94
|
+
/** @deprecated Use {@link listWalletWorks}. */
|
|
95
|
+
getWalletWorks: (address: string, opts?: MisoRequestOptions) => Promise<OwnedWork[]>;
|
|
96
|
+
/** @deprecated Use {@link getWalletBalance}. */
|
|
97
|
+
getBalance: (address: string, coinType?: string, opts?: MisoRequestOptions) => Promise<Balance>;
|
|
98
|
+
/** @deprecated Use {@link getWalletPartyOwnership}. */
|
|
99
|
+
ownsParty: (address: string, partyId: string, opts?: MisoRequestOptions) => Promise<Ownership>;
|
|
100
|
+
/** @deprecated Use {@link getWalletRecordOwnership}. */
|
|
101
|
+
ownsRecord: (address: string, recordId: string, opts?: MisoRequestOptions) => Promise<Ownership>;
|
|
102
|
+
/** @deprecated Use {@link getPurchaseReceipt}. */
|
|
103
|
+
getReceipt: (pressingId: string, txDigest: string, opts?: MisoRequestOptions) => Promise<PurchaseReceipt | null>;
|
|
104
|
+
};
|
|
105
|
+
export type MisoApiClient = ReturnType<typeof createMisoApiClient>;
|
|
106
|
+
/**
|
|
107
|
+
* A cache-buster value for {@link MisoApiClientOptions.version}.
|
|
108
|
+
*
|
|
109
|
+
* Call this once after a write lands on-chain, retain the returned value, and
|
|
110
|
+
* use it for the writer's subsequent mutable public reads. The timestamp keeps
|
|
111
|
+
* the bypass bounded; the random nonce prevents an attacker from pre-filling
|
|
112
|
+
* the exact URL before the writer reaches it.
|
|
113
|
+
*/
|
|
114
|
+
export declare function cacheBuster(nowMs?: number, nonce?: string): string;
|
|
115
|
+
/**
|
|
116
|
+
* Static cache classes for callers aligning their query options with the edge.
|
|
117
|
+
* `getRelease` is response-dependent and therefore absent. `getRecordAlbum`
|
|
118
|
+
* describes only the unexpanded base response; use `recordAlbumQueryPolicy`
|
|
119
|
+
* when requesting relationship expansions.
|
|
120
|
+
*
|
|
121
|
+
* Legacy keys remain for source compatibility with existing applications.
|
|
122
|
+
*/
|
|
123
|
+
export declare const READ_CACHE_CLASS: {
|
|
124
|
+
readonly getPressing: "sale";
|
|
125
|
+
readonly getPressingListing: "sale";
|
|
126
|
+
readonly getListing: "sale";
|
|
127
|
+
readonly getRecordAlbum: "immutable";
|
|
128
|
+
readonly getPurchaseReceipt: "immutable";
|
|
129
|
+
readonly getReceipt: "immutable";
|
|
130
|
+
readonly getArtist: "artist";
|
|
131
|
+
readonly listArtists: "artist";
|
|
132
|
+
readonly getArtists: "artist";
|
|
133
|
+
readonly listWalletRecords: "private";
|
|
134
|
+
readonly getWalletRecords: "private";
|
|
135
|
+
readonly listWalletParties: "private";
|
|
136
|
+
readonly getWalletParties: "private";
|
|
137
|
+
readonly listWalletPendingMemberships: "private";
|
|
138
|
+
readonly getPendingMemberships: "private";
|
|
139
|
+
readonly listWalletWorks: "private";
|
|
140
|
+
readonly getWalletWorks: "private";
|
|
141
|
+
readonly getWork: "private";
|
|
142
|
+
readonly getWalletBalance: "private";
|
|
143
|
+
readonly getBalance: "private";
|
|
144
|
+
readonly getWalletOwnership: "private";
|
|
145
|
+
readonly getWalletPartyOwnership: "private";
|
|
146
|
+
readonly ownsParty: "private";
|
|
147
|
+
readonly getWalletRecordOwnership: "private";
|
|
148
|
+
readonly ownsRecord: "private";
|
|
149
|
+
};
|
|
150
|
+
export { queryPolicy };
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
// Copyright (c) Miso Labs, Inc.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
//
|
|
4
|
+
// The typed client for the Miso read API. Every response is parsed at the
|
|
5
|
+
// boundary so API/client version skew fails loudly and locally.
|
|
6
|
+
import * as s from "./schemas.js";
|
|
7
|
+
import { queryPolicy } from "./cache.js";
|
|
8
|
+
export class MisoApiError extends Error {
|
|
9
|
+
status;
|
|
10
|
+
code;
|
|
11
|
+
/** Correlation id supplied by the API, when available. */
|
|
12
|
+
requestId;
|
|
13
|
+
/** Delay requested by `Retry-After`, normalized to seconds. */
|
|
14
|
+
retryAfter;
|
|
15
|
+
constructor(status, code, message, metadata = {}) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = "MisoApiError";
|
|
18
|
+
this.status = status;
|
|
19
|
+
this.code = code;
|
|
20
|
+
this.requestId = metadata.requestId;
|
|
21
|
+
this.retryAfter = metadata.retryAfter;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function errorMetadata(headers) {
|
|
25
|
+
const requestId = headers.get("X-Request-Id")?.trim() || undefined;
|
|
26
|
+
const rawRetryAfter = headers.get("Retry-After")?.trim();
|
|
27
|
+
if (!rawRetryAfter)
|
|
28
|
+
return { requestId };
|
|
29
|
+
const seconds = Number(rawRetryAfter);
|
|
30
|
+
if (Number.isFinite(seconds) && seconds >= 0)
|
|
31
|
+
return { requestId, retryAfter: seconds };
|
|
32
|
+
const timestamp = Date.parse(rawRetryAfter);
|
|
33
|
+
return Number.isFinite(timestamp)
|
|
34
|
+
? {
|
|
35
|
+
requestId,
|
|
36
|
+
retryAfter: Math.max(0, Math.ceil((timestamp - Date.now()) / 1000)),
|
|
37
|
+
}
|
|
38
|
+
: { requestId };
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The server said something this client cannot describe. Distinct from
|
|
42
|
+
* `MisoApiError`: this indicates API/client version skew rather than an
|
|
43
|
+
* expected API outcome.
|
|
44
|
+
*/
|
|
45
|
+
export class MisoApiContractError extends Error {
|
|
46
|
+
issues;
|
|
47
|
+
/** Correlation id supplied by the API, when available. */
|
|
48
|
+
requestId;
|
|
49
|
+
constructor(path, issues, metadata = {}) {
|
|
50
|
+
const first = issues[0];
|
|
51
|
+
super(`Response from ${path} did not match the expected contract` +
|
|
52
|
+
(first ? `: ${first.path.join(".")} — ${first.message}` : "") +
|
|
53
|
+
". The API and @misofm/api-client are likely different versions.");
|
|
54
|
+
this.name = "MisoApiContractError";
|
|
55
|
+
this.issues = issues;
|
|
56
|
+
this.requestId = metadata.requestId;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/** Encode exactly one dynamic route segment, including `/`, `%`, `?`, and `#`. */
|
|
60
|
+
function segment(value) {
|
|
61
|
+
const encoded = encodeURIComponent(value);
|
|
62
|
+
// WHATWG URL parsing treats literal and percent-encoded `.` / `..` as path
|
|
63
|
+
// navigation. Double-encoding dot-only inputs keeps even hostile values in
|
|
64
|
+
// the one dynamic segment where the caller supplied them.
|
|
65
|
+
return encoded === "."
|
|
66
|
+
? "%252E"
|
|
67
|
+
: encoded === ".."
|
|
68
|
+
? "%252E%252E"
|
|
69
|
+
: encoded;
|
|
70
|
+
}
|
|
71
|
+
/** Add the default Accept header without requiring a global Headers constructor. */
|
|
72
|
+
function requestHeaders(input) {
|
|
73
|
+
if (!input)
|
|
74
|
+
return { Accept: "application/json" };
|
|
75
|
+
const entries = [];
|
|
76
|
+
if (Array.isArray(input)) {
|
|
77
|
+
for (const [name, value] of input)
|
|
78
|
+
entries.push([name, value]);
|
|
79
|
+
}
|
|
80
|
+
else if (typeof input.forEach === "function") {
|
|
81
|
+
input.forEach((value, name) => entries.push([name, value]));
|
|
82
|
+
}
|
|
83
|
+
else if (typeof input[Symbol.iterator] === "function") {
|
|
84
|
+
for (const [name, value] of input) {
|
|
85
|
+
entries.push([name, value]);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
entries.push(...Object.entries(input));
|
|
90
|
+
}
|
|
91
|
+
if (!entries.some(([name]) => name.toLowerCase() === "accept")) {
|
|
92
|
+
entries.unshift(["Accept", "application/json"]);
|
|
93
|
+
}
|
|
94
|
+
return entries;
|
|
95
|
+
}
|
|
96
|
+
export function createMisoApiClient(options) {
|
|
97
|
+
const base = options.baseUrl.replace(/\/$/, "");
|
|
98
|
+
const prefix = options.prefix ?? "/read/v1";
|
|
99
|
+
const doFetch = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
100
|
+
function url(path, query = {}, mutable = false) {
|
|
101
|
+
const u = new URL(`${base}${prefix}${path}`);
|
|
102
|
+
for (const [key, value] of Object.entries(query)) {
|
|
103
|
+
if (value !== undefined && value !== null && value !== "")
|
|
104
|
+
u.searchParams.set(key, String(value));
|
|
105
|
+
}
|
|
106
|
+
const version = mutable ? options.version?.() : undefined;
|
|
107
|
+
if (version)
|
|
108
|
+
u.searchParams.set("v", version);
|
|
109
|
+
return u.toString();
|
|
110
|
+
}
|
|
111
|
+
async function request(schema, path, query = {}, opts = {}) {
|
|
112
|
+
const target = url(path, query, opts.mutable);
|
|
113
|
+
const response = await doFetch(target, {
|
|
114
|
+
headers: requestHeaders(opts.headers),
|
|
115
|
+
signal: opts.signal,
|
|
116
|
+
});
|
|
117
|
+
if (response.status === 404 && opts.nullOn404)
|
|
118
|
+
return null;
|
|
119
|
+
if (!response.ok) {
|
|
120
|
+
const body = await response.json().catch(() => null);
|
|
121
|
+
const parsed = s.apiErrorSchema.safeParse(body);
|
|
122
|
+
const metadata = errorMetadata(response.headers);
|
|
123
|
+
throw parsed.success
|
|
124
|
+
? new MisoApiError(response.status, parsed.data.error.code, parsed.data.error.message, metadata)
|
|
125
|
+
: new MisoApiError(response.status, "unknown", `Request to ${path} failed (${response.status})`, metadata);
|
|
126
|
+
}
|
|
127
|
+
const json = await response.json().catch(() => {
|
|
128
|
+
throw new MisoApiError(response.status, "bad_response", `Response from ${path} was not JSON`, errorMetadata(response.headers));
|
|
129
|
+
});
|
|
130
|
+
const parsed = schema.safeParse(json);
|
|
131
|
+
if (!parsed.success)
|
|
132
|
+
throw new MisoApiContractError(path, parsed.error.issues, errorMetadata(response.headers));
|
|
133
|
+
return parsed.data;
|
|
134
|
+
}
|
|
135
|
+
async function required(schema, path, query, opts) {
|
|
136
|
+
return (await request(schema, path, query, opts));
|
|
137
|
+
}
|
|
138
|
+
// Each implementation is defined once so compatibility aliases cannot drift.
|
|
139
|
+
const getPressing = (pressingId, opts = {}) => request(s.pressingViewSchema, `/pressings/${segment(pressingId)}`, {}, {
|
|
140
|
+
...opts,
|
|
141
|
+
nullOn404: true,
|
|
142
|
+
mutable: true,
|
|
143
|
+
});
|
|
144
|
+
const getPressingListing = (pressingId, currencyType, opts = {}) => request(s.listingViewSchema, `/pressings/${segment(pressingId)}/listing`, { currencyType }, { ...opts, nullOn404: true, mutable: true });
|
|
145
|
+
const getRelease = (releaseId, opts = {}) => request(s.releaseDetailSchema, `/releases/${segment(releaseId)}`, { include: opts.include?.join(",") }, { ...opts, nullOn404: true, mutable: true });
|
|
146
|
+
const getRecordAlbum = (recordId, opts = {}) => request(s.recordAlbumSchema, `/records/${segment(recordId)}/album`, { include: opts.include?.join(",") }, {
|
|
147
|
+
...opts,
|
|
148
|
+
nullOn404: true,
|
|
149
|
+
// The relation is immutable; expanded release metadata can change.
|
|
150
|
+
mutable: (opts.include?.length ?? 0) > 0,
|
|
151
|
+
});
|
|
152
|
+
const getArtist = (partyId, opts = {}) => request(s.artistProfileSchema, `/artists/${segment(partyId)}`, { include: opts.include?.join(",") }, { ...opts, nullOn404: true, mutable: true });
|
|
153
|
+
const listArtists = (ids, opts = {}) => ids.length === 0
|
|
154
|
+
? Promise.resolve([])
|
|
155
|
+
: required(s.partySummariesSchema, "/artists", { ids: ids.join(",") }, {
|
|
156
|
+
...opts,
|
|
157
|
+
mutable: true,
|
|
158
|
+
});
|
|
159
|
+
const listWalletRecords = (address, opts = {}) => required(s.ownedRecordsSchema, `/wallets/${segment(address)}/records`, {}, opts);
|
|
160
|
+
const listWalletParties = (address, opts = {}) => required(s.ownedPartiesSchema, `/wallets/${segment(address)}/parties`, {}, opts);
|
|
161
|
+
const listWalletPendingMemberships = (address, opts = {}) => required(s.pendingMembershipsSchema, `/wallets/${segment(address)}/pending-memberships`, {}, opts);
|
|
162
|
+
const listWalletWorks = (address, opts = {}) => required(s.ownedWorksSchema, `/wallets/${segment(address)}/works`, {}, opts);
|
|
163
|
+
const getWork = (capId, opts = {}) => request(s.workDetailSchema, `/works/${segment(capId)}`, {}, {
|
|
164
|
+
...opts,
|
|
165
|
+
nullOn404: true,
|
|
166
|
+
});
|
|
167
|
+
const getWalletBalance = (address, coinType, opts = {}) => required(s.balanceSchema, `/wallets/${segment(address)}/balance`, { coinType }, opts);
|
|
168
|
+
const getWalletPartyOwnership = (address, partyId, opts = {}) => required(s.ownershipSchema, `/wallets/${segment(address)}/owns`, { party: partyId }, opts);
|
|
169
|
+
const getWalletOwnership = (address, target, opts = {}) => required(s.ownershipSchema, `/wallets/${segment(address)}/owns`, {
|
|
170
|
+
party: target.partyId,
|
|
171
|
+
record: target.recordId,
|
|
172
|
+
}, opts);
|
|
173
|
+
const getWalletRecordOwnership = (address, recordId, opts = {}) => required(s.ownershipSchema, `/wallets/${segment(address)}/owns`, { record: recordId }, opts);
|
|
174
|
+
const getPurchaseReceipt = (pressingId, txDigest, opts = {}) => request(s.purchaseReceiptSchema, `/receipts/${segment(pressingId)}/${segment(txDigest)}`, {}, { ...opts, nullOn404: true });
|
|
175
|
+
return {
|
|
176
|
+
getPressing,
|
|
177
|
+
getPressingListing,
|
|
178
|
+
getRelease,
|
|
179
|
+
getRecordAlbum,
|
|
180
|
+
getArtist,
|
|
181
|
+
listArtists,
|
|
182
|
+
listWalletRecords,
|
|
183
|
+
listWalletParties,
|
|
184
|
+
listWalletPendingMemberships,
|
|
185
|
+
listWalletWorks,
|
|
186
|
+
getWork,
|
|
187
|
+
getWalletBalance,
|
|
188
|
+
getWalletOwnership,
|
|
189
|
+
getWalletPartyOwnership,
|
|
190
|
+
getWalletRecordOwnership,
|
|
191
|
+
getPurchaseReceipt,
|
|
192
|
+
/** @deprecated Use {@link getPressingListing}. */
|
|
193
|
+
getListing: getPressingListing,
|
|
194
|
+
/** @deprecated Use {@link listArtists}. */
|
|
195
|
+
getArtists: listArtists,
|
|
196
|
+
/** @deprecated Use {@link listWalletRecords}. */
|
|
197
|
+
getWalletRecords: listWalletRecords,
|
|
198
|
+
/** @deprecated Use {@link listWalletParties}. */
|
|
199
|
+
getWalletParties: listWalletParties,
|
|
200
|
+
/** @deprecated Use {@link listWalletPendingMemberships}. */
|
|
201
|
+
getPendingMemberships: listWalletPendingMemberships,
|
|
202
|
+
/** @deprecated Use {@link listWalletWorks}. */
|
|
203
|
+
getWalletWorks: listWalletWorks,
|
|
204
|
+
/** @deprecated Use {@link getWalletBalance}. */
|
|
205
|
+
getBalance: getWalletBalance,
|
|
206
|
+
/** @deprecated Use {@link getWalletPartyOwnership}. */
|
|
207
|
+
ownsParty: getWalletPartyOwnership,
|
|
208
|
+
/** @deprecated Use {@link getWalletRecordOwnership}. */
|
|
209
|
+
ownsRecord: getWalletRecordOwnership,
|
|
210
|
+
/** @deprecated Use {@link getPurchaseReceipt}. */
|
|
211
|
+
getReceipt: getPurchaseReceipt,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* A cache-buster value for {@link MisoApiClientOptions.version}.
|
|
216
|
+
*
|
|
217
|
+
* Call this once after a write lands on-chain, retain the returned value, and
|
|
218
|
+
* use it for the writer's subsequent mutable public reads. The timestamp keeps
|
|
219
|
+
* the bypass bounded; the random nonce prevents an attacker from pre-filling
|
|
220
|
+
* the exact URL before the writer reaches it.
|
|
221
|
+
*/
|
|
222
|
+
export function cacheBuster(nowMs = Date.now(), nonce = crypto.getRandomValues(new Uint32Array(1))[0]
|
|
223
|
+
.toString(16)
|
|
224
|
+
.padStart(8, "0")) {
|
|
225
|
+
if (!/^[0-9a-fA-F]{8}$/.test(nonce)) {
|
|
226
|
+
throw new RangeError("cacheBuster nonce must be exactly 8 hexadecimal characters.");
|
|
227
|
+
}
|
|
228
|
+
return `${Math.floor(nowMs / 1000)}-${nonce.toLowerCase()}`;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Static cache classes for callers aligning their query options with the edge.
|
|
232
|
+
* `getRelease` is response-dependent and therefore absent. `getRecordAlbum`
|
|
233
|
+
* describes only the unexpanded base response; use `recordAlbumQueryPolicy`
|
|
234
|
+
* when requesting relationship expansions.
|
|
235
|
+
*
|
|
236
|
+
* Legacy keys remain for source compatibility with existing applications.
|
|
237
|
+
*/
|
|
238
|
+
export const READ_CACHE_CLASS = {
|
|
239
|
+
getPressing: "sale",
|
|
240
|
+
getPressingListing: "sale",
|
|
241
|
+
getListing: "sale",
|
|
242
|
+
getRecordAlbum: "immutable",
|
|
243
|
+
getPurchaseReceipt: "immutable",
|
|
244
|
+
getReceipt: "immutable",
|
|
245
|
+
getArtist: "artist",
|
|
246
|
+
listArtists: "artist",
|
|
247
|
+
getArtists: "artist",
|
|
248
|
+
listWalletRecords: "private",
|
|
249
|
+
getWalletRecords: "private",
|
|
250
|
+
listWalletParties: "private",
|
|
251
|
+
getWalletParties: "private",
|
|
252
|
+
listWalletPendingMemberships: "private",
|
|
253
|
+
getPendingMemberships: "private",
|
|
254
|
+
listWalletWorks: "private",
|
|
255
|
+
getWalletWorks: "private",
|
|
256
|
+
getWork: "private",
|
|
257
|
+
getWalletBalance: "private",
|
|
258
|
+
getBalance: "private",
|
|
259
|
+
getWalletOwnership: "private",
|
|
260
|
+
getWalletPartyOwnership: "private",
|
|
261
|
+
ownsParty: "private",
|
|
262
|
+
getWalletRecordOwnership: "private",
|
|
263
|
+
ownsRecord: "private",
|
|
264
|
+
};
|
|
265
|
+
export { queryPolicy };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { createMisoApiClient, cacheBuster, MisoApiError, MisoApiContractError, READ_CACHE_CLASS, queryPolicy } from "./client.js";
|
|
2
|
+
export type { MisoApiClient, MisoApiClientOptions, MisoApiErrorOptions, MisoRequestOptions, WalletOwnershipTarget } from "./client.js";
|
|
3
|
+
export { CACHE_POLICIES, browserCacheControl, cacheControl, cdnCacheControl, workCacheClass, recordAlbumCacheClass, recordAlbumQueryPolicy } from "./cache.js";
|
|
4
|
+
export type { CacheClass, CachePolicy, RecordAlbumCacheOptions, RecordAlbumCacheValue } from "./cache.js";
|
|
5
|
+
export * as schemas from "./schemas.js";
|
|
6
|
+
export type * from "./types.js";
|
|
@@ -10,12 +10,6 @@
|
|
|
10
10
|
//
|
|
11
11
|
// import { createMisoApiClient } from "@misofm/api-client";
|
|
12
12
|
// const api = createMisoApiClient({ baseUrl: "https://api.testnet.miso.fm" });
|
|
13
|
-
|
|
14
|
-
export {
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
export { CACHE_POLICIES, cacheControl, workCacheClass } from "./cache.ts";
|
|
18
|
-
export type { CacheClass, CachePolicy } from "./cache.ts";
|
|
19
|
-
|
|
20
|
-
export * as schemas from "./schemas.ts";
|
|
21
|
-
export type * from "./types.ts";
|
|
13
|
+
export { createMisoApiClient, cacheBuster, MisoApiError, MisoApiContractError, READ_CACHE_CLASS, queryPolicy } from "./client.js";
|
|
14
|
+
export { CACHE_POLICIES, browserCacheControl, cacheControl, cdnCacheControl, workCacheClass, recordAlbumCacheClass, recordAlbumQueryPolicy } from "./cache.js";
|
|
15
|
+
export * as schemas from "./schemas.js";
|