@shiprev/server-sdk-node 0.0.0-stage → 0.1.0-beta.1
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 +202 -0
- package/README.md +276 -2
- package/dist/auth/token-verifier.d.ts +56 -0
- package/dist/auth/token-verifier.js +257 -0
- package/dist/client/connection-supervisor.d.ts +148 -0
- package/dist/client/connection-supervisor.js +650 -0
- package/dist/client/shiprev-client.d.ts +139 -0
- package/dist/client/shiprev-client.js +400 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +47 -0
- package/dist/metering/backlog/host-adapter-backlog.d.ts +10 -0
- package/dist/metering/backlog/host-adapter-backlog.js +27 -0
- package/dist/metering/backlog/journal-backlog.d.ts +14 -0
- package/dist/metering/backlog/journal-backlog.js +135 -0
- package/dist/metering/backlog/memory-backlog.d.ts +9 -0
- package/dist/metering/backlog/memory-backlog.js +34 -0
- package/dist/metering/usage-buffer.d.ts +59 -0
- package/dist/metering/usage-buffer.js +175 -0
- package/dist/mirror/degradation.d.ts +22 -0
- package/dist/mirror/degradation.js +67 -0
- package/dist/mirror/entitlement-mirror.d.ts +61 -0
- package/dist/mirror/entitlement-mirror.js +143 -0
- package/dist/nest/decorators.d.ts +15 -0
- package/dist/nest/decorators.js +21 -0
- package/dist/nest/index.d.ts +4 -0
- package/dist/nest/index.js +21 -0
- package/dist/nest/shiprev-auth.guard.d.ts +7 -0
- package/dist/nest/shiprev-auth.guard.js +52 -0
- package/dist/nest/shiprev-capability.guard.d.ts +9 -0
- package/dist/nest/shiprev-capability.guard.js +65 -0
- package/dist/nest/shiprev.module.d.ts +17 -0
- package/dist/nest/shiprev.module.js +57 -0
- package/dist/ruling/adjudicator.d.ts +15 -0
- package/dist/ruling/adjudicator.js +123 -0
- package/dist/transport/event-stream.d.ts +27 -0
- package/dist/transport/event-stream.js +92 -0
- package/dist/transport/http.transport.d.ts +69 -0
- package/dist/transport/http.transport.js +238 -0
- package/dist/transport/wire.d.ts +79 -0
- package/dist/transport/wire.js +8 -0
- package/dist/types.d.ts +252 -0
- package/dist/types.js +37 -0
- package/dist/util/decimal.d.ts +14 -0
- package/dist/util/decimal.js +57 -0
- package/package.json +96 -3
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Server-Sent Events reader for `GET /sdk/v1/events`, on top of a `fetch` response body. No
|
|
4
|
+
* dependency: the frames are parsed here.
|
|
5
|
+
*
|
|
6
|
+
* Accepts what the format allows: frames split across reads or several per read, LF, CRLF or CR
|
|
7
|
+
* line endings, comment lines (starting with `:`), and `data` spread over several lines (joined
|
|
8
|
+
* with a newline). Fields other than `event` and `data` are ignored.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.EventStreamParser = void 0;
|
|
12
|
+
exports.readEventStream = readEventStream;
|
|
13
|
+
/** Incremental parser: feed it text, it returns the frames completed so far. */
|
|
14
|
+
class EventStreamParser {
|
|
15
|
+
pending = '';
|
|
16
|
+
eventType = '';
|
|
17
|
+
dataLines = [];
|
|
18
|
+
push(chunk) {
|
|
19
|
+
this.pending += chunk;
|
|
20
|
+
const frames = [];
|
|
21
|
+
let start = 0;
|
|
22
|
+
for (let i = 0; i < this.pending.length; i++) {
|
|
23
|
+
const ch = this.pending[i];
|
|
24
|
+
if (ch !== '\n' && ch !== '\r')
|
|
25
|
+
continue;
|
|
26
|
+
// A CR at the very end may be the first half of a CRLF split across reads: wait for more.
|
|
27
|
+
if (ch === '\r' && i === this.pending.length - 1)
|
|
28
|
+
break;
|
|
29
|
+
const line = this.pending.slice(start, i);
|
|
30
|
+
if (ch === '\r' && this.pending[i + 1] === '\n')
|
|
31
|
+
i++;
|
|
32
|
+
start = i + 1;
|
|
33
|
+
const frame = this.line(line);
|
|
34
|
+
if (frame)
|
|
35
|
+
frames.push(frame);
|
|
36
|
+
}
|
|
37
|
+
this.pending = this.pending.slice(start);
|
|
38
|
+
return frames;
|
|
39
|
+
}
|
|
40
|
+
line(line) {
|
|
41
|
+
if (line === '') {
|
|
42
|
+
if (this.dataLines.length === 0) {
|
|
43
|
+
this.eventType = '';
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
const frame = { event: this.eventType || 'message', data: this.dataLines.join('\n') };
|
|
47
|
+
this.eventType = '';
|
|
48
|
+
this.dataLines = [];
|
|
49
|
+
return frame;
|
|
50
|
+
}
|
|
51
|
+
if (line.startsWith(':'))
|
|
52
|
+
return undefined;
|
|
53
|
+
const colon = line.indexOf(':');
|
|
54
|
+
const field = colon === -1 ? line : line.slice(0, colon);
|
|
55
|
+
let value = colon === -1 ? '' : line.slice(colon + 1);
|
|
56
|
+
if (value.startsWith(' '))
|
|
57
|
+
value = value.slice(1);
|
|
58
|
+
if (field === 'event') {
|
|
59
|
+
this.eventType = value;
|
|
60
|
+
}
|
|
61
|
+
else if (field === 'data') {
|
|
62
|
+
this.dataLines.push(value);
|
|
63
|
+
}
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
exports.EventStreamParser = EventStreamParser;
|
|
68
|
+
/**
|
|
69
|
+
* Reads the body of an event stream response and hands every frame to `onFrame`. Resolves when the
|
|
70
|
+
* body ends, rejects on a read error (a reset connection, an abort).
|
|
71
|
+
*/
|
|
72
|
+
async function readEventStream(body, onFrame) {
|
|
73
|
+
const reader = body.getReader();
|
|
74
|
+
const decoder = new TextDecoder('utf-8');
|
|
75
|
+
const parser = new EventStreamParser();
|
|
76
|
+
try {
|
|
77
|
+
for (;;) {
|
|
78
|
+
const { done, value } = await reader.read();
|
|
79
|
+
if (done) {
|
|
80
|
+
for (const frame of parser.push(decoder.decode() + '\n'))
|
|
81
|
+
onFrame(frame);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
for (const frame of parser.push(decoder.decode(value, { stream: true })))
|
|
85
|
+
onFrame(frame);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
finally {
|
|
89
|
+
reader.releaseLock();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=event-stream.js.map
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { AdjudicationLookupRequest, AdjudicationLookupResponse, ConfirmReservationResult, JwksResponse, ReleaseReservationResult, ReservationResult, ReserveOptions, Snapshot, UsageEventItem, UsageEventsResponse, UsageSendEvent, UsageSendResult } from '../types';
|
|
2
|
+
/** A non-success HTTP answer from the instance; `status` lets callers tell a refused token from an outage. */
|
|
3
|
+
export declare class HttpError extends Error {
|
|
4
|
+
readonly status: number;
|
|
5
|
+
constructor(message: string, status: number);
|
|
6
|
+
}
|
|
7
|
+
/** True when `error` is an HTTP answer with one of the given statuses. */
|
|
8
|
+
export declare function isHttpStatus(error: unknown, ...statuses: number[]): boolean;
|
|
9
|
+
export interface TransportOptions {
|
|
10
|
+
baseUrl: string;
|
|
11
|
+
connectTimeoutMs?: number;
|
|
12
|
+
clientVersion?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare class HttpTransport {
|
|
15
|
+
private readonly baseUrl;
|
|
16
|
+
private readonly timeoutMs;
|
|
17
|
+
private readonly userAgent;
|
|
18
|
+
constructor(options: TransportOptions);
|
|
19
|
+
/**
|
|
20
|
+
* Fetches public JWKS keys from the unauthenticated runtime endpoint GET /sdk/v1/jwks
|
|
21
|
+
*/
|
|
22
|
+
fetchJwks(): Promise<JwksResponse>;
|
|
23
|
+
/**
|
|
24
|
+
* Exchanges an SDK-scoped API key for an RS256 short-lived M2M JWT token
|
|
25
|
+
*/
|
|
26
|
+
exchangeM2MToken(apiKey: string): Promise<{
|
|
27
|
+
access_token: string;
|
|
28
|
+
expires_in: number;
|
|
29
|
+
}>;
|
|
30
|
+
/**
|
|
31
|
+
* Fetches the application-level entitlement snapshot: GET /sdk/v1/entitlements/snapshot.
|
|
32
|
+
* With `organizationId` the envelope carries that organization only (used to refill a mirror miss).
|
|
33
|
+
*/
|
|
34
|
+
fetchSnapshot(token: string, organizationId?: string): Promise<Snapshot>;
|
|
35
|
+
/**
|
|
36
|
+
* Submits a batch of usage events: POST /sdk/v1/usage-events.
|
|
37
|
+
* Quantities are sent as decimal strings; `properties` travel as the event's `dimensions`.
|
|
38
|
+
*/
|
|
39
|
+
reportUsageEvents(events: UsageEventItem[], token: string): Promise<UsageEventsResponse>;
|
|
40
|
+
/**
|
|
41
|
+
* Sends a batch of usage events as they are: POST /sdk/v1/usage-events. A string quantity travels unchanged,
|
|
42
|
+
* so decimals keep every digit.
|
|
43
|
+
*/
|
|
44
|
+
sendUsageEvents(events: UsageSendEvent[], token: string): Promise<UsageSendResult>;
|
|
45
|
+
/**
|
|
46
|
+
* Authoritative ruling when the mirror misses an organization or capability: POST /sdk/v1/adjudicate.
|
|
47
|
+
*/
|
|
48
|
+
lookupAdjudication(request: AdjudicationLookupRequest, token: string): Promise<AdjudicationLookupResponse>;
|
|
49
|
+
/**
|
|
50
|
+
* Requests a two-phase reservation: POST /sdk/v1/reservations/reserve.
|
|
51
|
+
*/
|
|
52
|
+
reserve(options: ReserveOptions, token: string): Promise<ReservationResult>;
|
|
53
|
+
/**
|
|
54
|
+
* Confirms a pending reservation with the quantity actually used: POST /sdk/v1/reservations/:id/confirm.
|
|
55
|
+
*/
|
|
56
|
+
confirmReservation(reservationId: string, actualAmount: number, token: string): Promise<ConfirmReservationResult>;
|
|
57
|
+
/**
|
|
58
|
+
* Releases a pending reservation: POST /sdk/v1/reservations/:id/release.
|
|
59
|
+
*/
|
|
60
|
+
releaseReservation(reservationId: string, token: string): Promise<ReleaseReservationResult>;
|
|
61
|
+
/**
|
|
62
|
+
* Opens the push stream `GET /sdk/v1/events`. Resolves with the response once the headers arrive;
|
|
63
|
+
* the body stays open until the instance ends it or `signal` aborts it, so no request timeout
|
|
64
|
+
* applies here (the caller bounds the wait for `ready`).
|
|
65
|
+
*/
|
|
66
|
+
openEventStream(token: string, signal: AbortSignal): Promise<Response>;
|
|
67
|
+
private postJson;
|
|
68
|
+
private request;
|
|
69
|
+
}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HttpTransport = exports.HttpError = void 0;
|
|
4
|
+
exports.isHttpStatus = isHttpStatus;
|
|
5
|
+
const decimal_1 = require("../util/decimal");
|
|
6
|
+
/** A non-success HTTP answer from the instance; `status` lets callers tell a refused token from an outage. */
|
|
7
|
+
class HttpError extends Error {
|
|
8
|
+
status;
|
|
9
|
+
constructor(message, status) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.status = status;
|
|
12
|
+
this.name = 'HttpError';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.HttpError = HttpError;
|
|
16
|
+
/** True when `error` is an HTTP answer with one of the given statuses. */
|
|
17
|
+
function isHttpStatus(error, ...statuses) {
|
|
18
|
+
return error instanceof HttpError && statuses.includes(error.status);
|
|
19
|
+
}
|
|
20
|
+
class HttpTransport {
|
|
21
|
+
baseUrl;
|
|
22
|
+
timeoutMs;
|
|
23
|
+
userAgent;
|
|
24
|
+
constructor(options) {
|
|
25
|
+
// Strip trailing slashes
|
|
26
|
+
this.baseUrl = options.baseUrl.replace(/\/+$/, '');
|
|
27
|
+
this.timeoutMs = options.connectTimeoutMs ?? 5000;
|
|
28
|
+
this.userAgent = `@shiprev/server-sdk-node/${options.clientVersion ?? '0.0.0'}`;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Fetches public JWKS keys from the unauthenticated runtime endpoint GET /sdk/v1/jwks
|
|
32
|
+
*/
|
|
33
|
+
async fetchJwks() {
|
|
34
|
+
const url = `${this.baseUrl}/sdk/v1/jwks`;
|
|
35
|
+
const response = await this.request(url, {
|
|
36
|
+
method: 'GET',
|
|
37
|
+
});
|
|
38
|
+
if (!response.ok) {
|
|
39
|
+
throw new HttpError(`Failed to fetch JWKS from ${url}: HTTP ${response.status}`, response.status);
|
|
40
|
+
}
|
|
41
|
+
return (await response.json());
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Exchanges an SDK-scoped API key for an RS256 short-lived M2M JWT token
|
|
45
|
+
*/
|
|
46
|
+
async exchangeM2MToken(apiKey) {
|
|
47
|
+
const url = `${this.baseUrl}/sdk/v1/m2m/token`;
|
|
48
|
+
const response = await this.request(url, {
|
|
49
|
+
method: 'POST',
|
|
50
|
+
headers: {
|
|
51
|
+
'Content-Type': 'application/json',
|
|
52
|
+
},
|
|
53
|
+
body: JSON.stringify({ api_key: apiKey }),
|
|
54
|
+
});
|
|
55
|
+
if (!response.ok) {
|
|
56
|
+
const errorText = await response.text();
|
|
57
|
+
throw new HttpError(`Failed to exchange M2M token: HTTP ${response.status} - ${errorText}`, response.status);
|
|
58
|
+
}
|
|
59
|
+
return (await response.json());
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Fetches the application-level entitlement snapshot: GET /sdk/v1/entitlements/snapshot.
|
|
63
|
+
* With `organizationId` the envelope carries that organization only (used to refill a mirror miss).
|
|
64
|
+
*/
|
|
65
|
+
async fetchSnapshot(token, organizationId) {
|
|
66
|
+
const url = organizationId
|
|
67
|
+
? `${this.baseUrl}/sdk/v1/entitlements/snapshot?organization_id=${encodeURIComponent(organizationId)}`
|
|
68
|
+
: `${this.baseUrl}/sdk/v1/entitlements/snapshot`;
|
|
69
|
+
const response = await this.request(url, {
|
|
70
|
+
method: 'GET',
|
|
71
|
+
headers: {
|
|
72
|
+
Authorization: `Bearer ${token}`,
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
if (!response.ok) {
|
|
76
|
+
throw new HttpError(`Failed to fetch snapshot: HTTP ${response.status}`, response.status);
|
|
77
|
+
}
|
|
78
|
+
return (await response.json());
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Submits a batch of usage events: POST /sdk/v1/usage-events.
|
|
82
|
+
* Quantities are sent as decimal strings; `properties` travel as the event's `dimensions`.
|
|
83
|
+
*/
|
|
84
|
+
async reportUsageEvents(events, token) {
|
|
85
|
+
const wireEvents = events.map((event) => ({
|
|
86
|
+
usage_event_id: event.usage_event_id,
|
|
87
|
+
organization_id: event.organization_id,
|
|
88
|
+
capability_key: event.capability_key,
|
|
89
|
+
quantity: (0, decimal_1.toDecimalString)(event.quantity),
|
|
90
|
+
occurred_at: event.occurred_at,
|
|
91
|
+
...(event.properties !== undefined ? { dimensions: event.properties } : {}),
|
|
92
|
+
}));
|
|
93
|
+
const body = await this.postJson('/sdk/v1/usage-events', { events: wireEvents }, token, 'Failed to report usage events');
|
|
94
|
+
return {
|
|
95
|
+
accepted: body.accepted_count,
|
|
96
|
+
duplicates_dropped: body.duplicates_dropped,
|
|
97
|
+
rejected: body.rejected ?? [],
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Sends a batch of usage events as they are: POST /sdk/v1/usage-events. A string quantity travels unchanged,
|
|
102
|
+
* so decimals keep every digit.
|
|
103
|
+
*/
|
|
104
|
+
async sendUsageEvents(events, token) {
|
|
105
|
+
const wireEvents = events.map((event) => ({
|
|
106
|
+
usage_event_id: event.usage_event_id,
|
|
107
|
+
organization_id: event.organization_id,
|
|
108
|
+
capability_key: event.capability_key,
|
|
109
|
+
quantity: typeof event.quantity === 'string' ? event.quantity.trim() : (0, decimal_1.toDecimalString)(event.quantity),
|
|
110
|
+
occurred_at: event.occurred_at,
|
|
111
|
+
...(event.properties !== undefined ? { dimensions: event.properties } : {}),
|
|
112
|
+
}));
|
|
113
|
+
const body = await this.postJson('/sdk/v1/usage-events', { events: wireEvents }, token, 'Failed to send usage events');
|
|
114
|
+
return {
|
|
115
|
+
accepted_count: body.accepted_count,
|
|
116
|
+
duplicates_dropped: body.duplicates_dropped,
|
|
117
|
+
rejected: body.rejected ?? [],
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Authoritative ruling when the mirror misses an organization or capability: POST /sdk/v1/adjudicate.
|
|
122
|
+
*/
|
|
123
|
+
async lookupAdjudication(request, token) {
|
|
124
|
+
const wireRequest = {
|
|
125
|
+
organization_id: request.organization_id,
|
|
126
|
+
capability_key: request.capability_key,
|
|
127
|
+
operation: request.operation,
|
|
128
|
+
...(request.quantity !== undefined ? { quantity: (0, decimal_1.toDecimalString)(request.quantity) } : {}),
|
|
129
|
+
};
|
|
130
|
+
const body = await this.postJson('/sdk/v1/adjudicate', wireRequest, token, 'Authoritative lookup failed');
|
|
131
|
+
return {
|
|
132
|
+
allowed: body.allowed,
|
|
133
|
+
remaining: (0, decimal_1.decimalToNumber)(body.remaining),
|
|
134
|
+
limit: (0, decimal_1.decimalToNumber)(body.limit),
|
|
135
|
+
source: 'authoritative',
|
|
136
|
+
reason: body.reason ?? undefined,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Requests a two-phase reservation: POST /sdk/v1/reservations/reserve.
|
|
141
|
+
*/
|
|
142
|
+
async reserve(options, token) {
|
|
143
|
+
const wireRequest = {
|
|
144
|
+
organization_id: options.organization_id,
|
|
145
|
+
capability_key: options.capability_key,
|
|
146
|
+
quantity: (0, decimal_1.toDecimalString)(options.amount),
|
|
147
|
+
...(options.ttl_seconds !== undefined ? { ttl_seconds: options.ttl_seconds } : {}),
|
|
148
|
+
};
|
|
149
|
+
const body = await this.postJson('/sdk/v1/reservations/reserve', wireRequest, token, 'Reservation failed');
|
|
150
|
+
return {
|
|
151
|
+
reservation_id: body.reservation_id,
|
|
152
|
+
status: body.status,
|
|
153
|
+
expires_at: body.expires_at,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Confirms a pending reservation with the quantity actually used: POST /sdk/v1/reservations/:id/confirm.
|
|
158
|
+
*/
|
|
159
|
+
async confirmReservation(reservationId, actualAmount, token) {
|
|
160
|
+
const wireRequest = { actual_quantity: (0, decimal_1.toDecimalString)(actualAmount) };
|
|
161
|
+
const body = await this.postJson(`/sdk/v1/reservations/${encodeURIComponent(reservationId)}/confirm`, wireRequest, token, 'Reservation confirm failed');
|
|
162
|
+
return {
|
|
163
|
+
reservation_id: body.reservation_id,
|
|
164
|
+
status: 'CONFIRMED',
|
|
165
|
+
confirmed_amount: (0, decimal_1.decimalToNumber)(body.actual_quantity) ?? actualAmount,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Releases a pending reservation: POST /sdk/v1/reservations/:id/release.
|
|
170
|
+
*/
|
|
171
|
+
async releaseReservation(reservationId, token) {
|
|
172
|
+
const body = await this.postJson(`/sdk/v1/reservations/${encodeURIComponent(reservationId)}/release`, {}, token, 'Reservation release failed');
|
|
173
|
+
return { reservation_id: body.reservation_id, status: 'RELEASED' };
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Opens the push stream `GET /sdk/v1/events`. Resolves with the response once the headers arrive;
|
|
177
|
+
* the body stays open until the instance ends it or `signal` aborts it, so no request timeout
|
|
178
|
+
* applies here (the caller bounds the wait for `ready`).
|
|
179
|
+
*/
|
|
180
|
+
async openEventStream(token, signal) {
|
|
181
|
+
const url = `${this.baseUrl}/sdk/v1/events`;
|
|
182
|
+
const response = await fetch(url, {
|
|
183
|
+
method: 'GET',
|
|
184
|
+
headers: {
|
|
185
|
+
Authorization: `Bearer ${token}`,
|
|
186
|
+
Accept: 'text/event-stream',
|
|
187
|
+
'User-Agent': this.userAgent,
|
|
188
|
+
},
|
|
189
|
+
signal,
|
|
190
|
+
});
|
|
191
|
+
if (!response.ok || !response.body) {
|
|
192
|
+
await response.body?.cancel().catch(() => undefined);
|
|
193
|
+
throw new HttpError(`Failed to open the event stream: HTTP ${response.status}`, response.status);
|
|
194
|
+
}
|
|
195
|
+
return response;
|
|
196
|
+
}
|
|
197
|
+
async postJson(path, payload, token, failure) {
|
|
198
|
+
const response = await this.request(`${this.baseUrl}${path}`, {
|
|
199
|
+
method: 'POST',
|
|
200
|
+
headers: {
|
|
201
|
+
'Content-Type': 'application/json',
|
|
202
|
+
Authorization: `Bearer ${token}`,
|
|
203
|
+
},
|
|
204
|
+
body: JSON.stringify(payload),
|
|
205
|
+
});
|
|
206
|
+
if (!response.ok) {
|
|
207
|
+
const errorText = await response.text();
|
|
208
|
+
throw new HttpError(`${failure}: HTTP ${response.status} - ${errorText}`, response.status);
|
|
209
|
+
}
|
|
210
|
+
return (await response.json());
|
|
211
|
+
}
|
|
212
|
+
async request(url, init) {
|
|
213
|
+
const controller = new AbortController();
|
|
214
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
215
|
+
try {
|
|
216
|
+
const headers = new Headers(init.headers);
|
|
217
|
+
headers.set('User-Agent', this.userAgent);
|
|
218
|
+
headers.set('Accept', 'application/json');
|
|
219
|
+
const response = await fetch(url, {
|
|
220
|
+
...init,
|
|
221
|
+
headers,
|
|
222
|
+
signal: controller.signal,
|
|
223
|
+
});
|
|
224
|
+
return response;
|
|
225
|
+
}
|
|
226
|
+
catch (err) {
|
|
227
|
+
if (err instanceof Error && err.name === 'AbortError') {
|
|
228
|
+
throw new Error(`Request to ${url} timed out after ${this.timeoutMs}ms`);
|
|
229
|
+
}
|
|
230
|
+
throw err;
|
|
231
|
+
}
|
|
232
|
+
finally {
|
|
233
|
+
clearTimeout(timeoutId);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
exports.HttpTransport = HttpTransport;
|
|
238
|
+
//# sourceMappingURL=http.transport.js.map
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request and response bodies of the service's `sdk` partition, exactly as they travel on the wire.
|
|
3
|
+
* The service owns these shapes; the transport maps them to and from the public SDK types, so
|
|
4
|
+
* nothing outside `transport/` depends on them. Quantities are fixed-point decimal strings.
|
|
5
|
+
*/
|
|
6
|
+
/** `POST /sdk/v1/adjudicate` request. */
|
|
7
|
+
export interface WireAdjudicateRequest {
|
|
8
|
+
organization_id: string;
|
|
9
|
+
capability_key: string;
|
|
10
|
+
quantity?: string;
|
|
11
|
+
operation: 'read' | 'write';
|
|
12
|
+
}
|
|
13
|
+
/** `POST /sdk/v1/adjudicate` response. */
|
|
14
|
+
export interface WireAdjudicateResponse {
|
|
15
|
+
allowed: boolean;
|
|
16
|
+
remaining: string;
|
|
17
|
+
limit?: string;
|
|
18
|
+
source: 'AUTHORITATIVE';
|
|
19
|
+
reason?: string | null;
|
|
20
|
+
adjudicated_at: number;
|
|
21
|
+
}
|
|
22
|
+
/** One event of `POST /sdk/v1/usage-events`. */
|
|
23
|
+
export interface WireUsageEvent {
|
|
24
|
+
usage_event_id: string;
|
|
25
|
+
organization_id: string;
|
|
26
|
+
capability_key: string;
|
|
27
|
+
quantity: string;
|
|
28
|
+
occurred_at: string;
|
|
29
|
+
dimensions?: Record<string, unknown>;
|
|
30
|
+
}
|
|
31
|
+
/** `POST /sdk/v1/usage-events` response. */
|
|
32
|
+
export interface WireUsageEventsResponse {
|
|
33
|
+
accepted_count: number;
|
|
34
|
+
duplicates_dropped: number;
|
|
35
|
+
rejected_count: number;
|
|
36
|
+
rejected: Array<{
|
|
37
|
+
usage_event_id: string;
|
|
38
|
+
reason: string;
|
|
39
|
+
}>;
|
|
40
|
+
}
|
|
41
|
+
/** `POST /sdk/v1/reservations/reserve` request. */
|
|
42
|
+
export interface WireReserveRequest {
|
|
43
|
+
organization_id: string;
|
|
44
|
+
capability_key: string;
|
|
45
|
+
quantity: string;
|
|
46
|
+
ttl_seconds?: number;
|
|
47
|
+
}
|
|
48
|
+
/** `POST /sdk/v1/reservations/reserve` response. */
|
|
49
|
+
export interface WireReservationResponse {
|
|
50
|
+
reservation_id: string;
|
|
51
|
+
project_id: string;
|
|
52
|
+
organization_id: string;
|
|
53
|
+
capability_key: string;
|
|
54
|
+
quantity: string;
|
|
55
|
+
status: 'RESERVED' | 'CONFIRMED' | 'RELEASED';
|
|
56
|
+
expires_at: string;
|
|
57
|
+
created_at: string;
|
|
58
|
+
}
|
|
59
|
+
/** `POST /sdk/v1/reservations/:id/confirm` request. */
|
|
60
|
+
export interface WireConfirmReservationRequest {
|
|
61
|
+
actual_quantity: string;
|
|
62
|
+
}
|
|
63
|
+
/** `POST /sdk/v1/reservations/:id/confirm` response. */
|
|
64
|
+
export interface WireConfirmReservationResponse {
|
|
65
|
+
reservation_id: string;
|
|
66
|
+
status: 'CONFIRMED';
|
|
67
|
+
reserved_quantity: string;
|
|
68
|
+
actual_quantity: string;
|
|
69
|
+
difference_refunded?: string;
|
|
70
|
+
difference_debited?: string;
|
|
71
|
+
settled_at: string;
|
|
72
|
+
}
|
|
73
|
+
/** `POST /sdk/v1/reservations/:id/release` response. */
|
|
74
|
+
export interface WireReleaseReservationResponse {
|
|
75
|
+
reservation_id: string;
|
|
76
|
+
status: 'RELEASED';
|
|
77
|
+
released_quantity: string;
|
|
78
|
+
released_at: string;
|
|
79
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Request and response bodies of the service's `sdk` partition, exactly as they travel on the wire.
|
|
4
|
+
* The service owns these shapes; the transport maps them to and from the public SDK types, so
|
|
5
|
+
* nothing outside `transport/` depends on them. Quantities are fixed-point decimal strings.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
//# sourceMappingURL=wire.js.map
|