@dork-labs/cloud-api 0.75.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 +21 -0
- package/README.md +192 -0
- package/dist/billing.d.ts +328 -0
- package/dist/billing.d.ts.map +1 -0
- package/dist/billing.js +267 -0
- package/dist/billing.js.map +1 -0
- package/dist/client.d.ts +130 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +192 -0
- package/dist/client.js.map +1 -0
- package/dist/connections.d.ts +281 -0
- package/dist/connections.d.ts.map +1 -0
- package/dist/connections.js +241 -0
- package/dist/connections.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/inference.d.ts +123 -0
- package/dist/inference.d.ts.map +1 -0
- package/dist/inference.js +114 -0
- package/dist/inference.js.map +1 -0
- package/dist/instances.d.ts +60 -0
- package/dist/instances.d.ts.map +1 -0
- package/dist/instances.js +65 -0
- package/dist/instances.js.map +1 -0
- package/dist/primitives.d.ts +74 -0
- package/dist/primitives.d.ts.map +1 -0
- package/dist/primitives.js +98 -0
- package/dist/primitives.js.map +1 -0
- package/dist/problem.d.ts +96 -0
- package/dist/problem.d.ts.map +1 -0
- package/dist/problem.js +94 -0
- package/dist/problem.js.map +1 -0
- package/dist/remote.d.ts +268 -0
- package/dist/remote.d.ts.map +1 -0
- package/dist/remote.js +267 -0
- package/dist/remote.js.map +1 -0
- package/dist/routes.d.ts +273 -0
- package/dist/routes.d.ts.map +1 -0
- package/dist/routes.js +302 -0
- package/dist/routes.js.map +1 -0
- package/dist/seats.d.ts +529 -0
- package/dist/seats.d.ts.map +1 -0
- package/dist/seats.js +266 -0
- package/dist/seats.js.map +1 -0
- package/dist/session.d.ts +135 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +143 -0
- package/dist/session.js.map +1 -0
- package/fixtures/v1/billing/balance-owed.json +16 -0
- package/fixtures/v1/billing/balance.json +16 -0
- package/fixtures/v1/billing/entitlements-free.json +34 -0
- package/fixtures/v1/billing/hosted-page.json +3 -0
- package/fixtures/v1/billing/nudge.json +9 -0
- package/fixtures/v1/billing/price-list.json +13 -0
- package/fixtures/v1/billing/statement.json +5 -0
- package/fixtures/v1/billing/usage-by-model.json +21 -0
- package/fixtures/v1/connections/catalog.json +12 -0
- package/fixtures/v1/connections/events-ack.json +3 -0
- package/fixtures/v1/connections/events-pull.json +16 -0
- package/fixtures/v1/connections/execution.json +12 -0
- package/fixtures/v1/connections/list.json +16 -0
- package/fixtures/v1/connections/usage.json +16 -0
- package/fixtures/v1/index.json +58 -0
- package/fixtures/v1/inference/models.json +17 -0
- package/fixtures/v1/inference/token-revoke.json +3 -0
- package/fixtures/v1/inference/token.json +14 -0
- package/fixtures/v1/instances/heartbeat.json +5 -0
- package/fixtures/v1/instances/list.json +15 -0
- package/fixtures/v1/instances/revoke.json +3 -0
- package/fixtures/v1/problem/handle-tombstoned.json +6 -0
- package/fixtures/v1/problem/person-seat-required.json +7 -0
- package/fixtures/v1/problem/unauthenticated.json +7 -0
- package/fixtures/v1/remote/address.json +5 -0
- package/fixtures/v1/remote/command-keepalive.json +4 -0
- package/fixtures/v1/remote/command-open.json +6 -0
- package/fixtures/v1/remote/commands-ack.json +3 -0
- package/fixtures/v1/remote/credential.json +7 -0
- package/fixtures/v1/remote/custom-address.json +12 -0
- package/fixtures/v1/remote/designation.json +5 -0
- package/fixtures/v1/remote/enrolment.json +5 -0
- package/fixtures/v1/remote/events.json +3 -0
- package/fixtures/v1/remote/open.json +5 -0
- package/fixtures/v1/remote/status-closed.json +7 -0
- package/fixtures/v1/remote/status-open.json +10 -0
- package/fixtures/v1/remote/wake-token.json +5 -0
- package/fixtures/v1/seats/addons.json +11 -0
- package/fixtures/v1/seats/agent.json +9 -0
- package/fixtures/v1/seats/grants.json +20 -0
- package/fixtures/v1/seats/inbox-browse.json +17 -0
- package/fixtures/v1/seats/inbox-pull.json +17 -0
- package/fixtures/v1/seats/invitation.json +9 -0
- package/fixtures/v1/seats/members.json +12 -0
- package/fixtures/v1/seats/org.json +7 -0
- package/fixtures/v1/seats/presence.json +6 -0
- package/fixtures/v1/seats/seat.json +21 -0
- package/fixtures/v1/session/account-export.json +6 -0
- package/fixtures/v1/session/device-code.json +8 -0
- package/fixtures/v1/session/device-token-pending.json +4 -0
- package/fixtures/v1/session/device-token.json +7 -0
- package/fixtures/v1/session/signed-in.json +14 -0
- package/fixtures/v1/session/signed-out.json +4 -0
- package/package.json +58 -0
package/dist/billing.js
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { IdSchema, MicroAmountSchema, TimestampSchema } from './primitives.js';
|
|
3
|
+
/**
|
|
4
|
+
* How remote access works for the caller.
|
|
5
|
+
*
|
|
6
|
+
* Mechanism, not catalog: it says how the tunnel behaves, not what anybody
|
|
7
|
+
* bought.
|
|
8
|
+
*/
|
|
9
|
+
export const RemoteAccessCapabilitySchema = z
|
|
10
|
+
.enum(['byo', 'on_demand', 'always_available'])
|
|
11
|
+
.describe('How remote access works for the caller: their own tunnel, opened on demand, or always up.');
|
|
12
|
+
/** Whether a custom address is unavailable, purchasable as an add-on, or already included. */
|
|
13
|
+
export const CustomAddressCapabilitySchema = z
|
|
14
|
+
.enum(['none', 'addon', 'included'])
|
|
15
|
+
.describe('Whether a custom address is unavailable, available as an add-on, or already included.');
|
|
16
|
+
/** Which support channel the caller reaches. */
|
|
17
|
+
export const SupportCapabilitySchema = z
|
|
18
|
+
.enum(['community', 'priority'])
|
|
19
|
+
.describe('Which support channel the caller reaches.');
|
|
20
|
+
/**
|
|
21
|
+
* The seat block of the entitlement.
|
|
22
|
+
*
|
|
23
|
+
* There is deliberately no field here for a count of local agents. Local agents
|
|
24
|
+
* are free and unlimited and no cloud surface counts them — the absence is part
|
|
25
|
+
* of the contract, and `src/__tests__/catalog-blindness.test.ts` keeps it.
|
|
26
|
+
*/
|
|
27
|
+
export const EntitlementSeatsSchema = z
|
|
28
|
+
.object({
|
|
29
|
+
total: z.number().int().nonnegative(),
|
|
30
|
+
assigned: z.number().int().nonnegative(),
|
|
31
|
+
byKind: z.object({
|
|
32
|
+
person: z.number().int().nonnegative(),
|
|
33
|
+
agent: z.number().int().nonnegative(),
|
|
34
|
+
}),
|
|
35
|
+
})
|
|
36
|
+
.describe('Seat counts for the caller`s organization. Counts only.');
|
|
37
|
+
/** The measurable limits of the caller`s entitlement. */
|
|
38
|
+
export const EntitlementLimitsSchema = z
|
|
39
|
+
.object({
|
|
40
|
+
personSeatsIncluded: z.number().int().nonnegative(),
|
|
41
|
+
agentSeatsIncluded: z.number().int().nonnegative(),
|
|
42
|
+
includedCreditsMicro: MicroAmountSchema,
|
|
43
|
+
cloudHours: z.number().nonnegative(),
|
|
44
|
+
storageGb: z.number().nonnegative(),
|
|
45
|
+
remoteAccess: RemoteAccessCapabilitySchema,
|
|
46
|
+
alwaysAvailableInstances: z.number().int().nonnegative(),
|
|
47
|
+
customAddress: CustomAddressCapabilitySchema,
|
|
48
|
+
managedConnectionActions: z
|
|
49
|
+
.number()
|
|
50
|
+
.int()
|
|
51
|
+
.nonnegative()
|
|
52
|
+
.nullable()
|
|
53
|
+
.describe('Null means the allowance is counted per seat rather than for the organization as a whole.'),
|
|
54
|
+
support: SupportCapabilitySchema,
|
|
55
|
+
emailAddressPerSeat: z.boolean(),
|
|
56
|
+
})
|
|
57
|
+
.describe('The measurable limits of the caller`s entitlement. Interface behaviour is driven by these values, never by the plan identifier.');
|
|
58
|
+
/**
|
|
59
|
+
* `GET /v1/entitlements` — what the caller is allowed to do.
|
|
60
|
+
*
|
|
61
|
+
* A caller with no subscription gets 200 and the free entitlement, never a 404.
|
|
62
|
+
* Somebody who has never touched billing is a valid caller and the normal case.
|
|
63
|
+
*
|
|
64
|
+
* `planId` is opaque. There is no compile-time exhaustiveness over plans here,
|
|
65
|
+
* deliberately: a client renders `planDisplayName` and branches on the limit
|
|
66
|
+
* values, never on the identifier.
|
|
67
|
+
*/
|
|
68
|
+
export const EntitlementsSchema = z
|
|
69
|
+
.object({
|
|
70
|
+
planId: IdSchema.describe('An opaque identifier for the caller`s current subscription. Never switch on this value.'),
|
|
71
|
+
planDisplayName: z.string().describe('The server-supplied string to show a person.'),
|
|
72
|
+
periodStart: TimestampSchema,
|
|
73
|
+
periodEnd: TimestampSchema,
|
|
74
|
+
limits: EntitlementLimitsSchema,
|
|
75
|
+
used: z.object({
|
|
76
|
+
personSeats: z.number().int().nonnegative(),
|
|
77
|
+
agentSeats: z.number().int().nonnegative(),
|
|
78
|
+
}),
|
|
79
|
+
seats: EntitlementSeatsSchema,
|
|
80
|
+
canCreateSeat: z.boolean(),
|
|
81
|
+
canInviteMember: z.boolean(),
|
|
82
|
+
staleAt: TimestampSchema.describe('When this snapshot should be refetched.'),
|
|
83
|
+
})
|
|
84
|
+
.describe('What the caller is allowed to do. A caller with no subscription gets the free entitlement, never a 404.');
|
|
85
|
+
/**
|
|
86
|
+
* `GET /v1/balance` — the caller`s credit position.
|
|
87
|
+
*
|
|
88
|
+
* `owedMicro` is not optional and not cosmetic: it is debt carried from a turn
|
|
89
|
+
* that overran its reservation. When it is non-zero an interface must show it,
|
|
90
|
+
* and a purchase that repays it renders the repayment as its own line before
|
|
91
|
+
* the new balance rather than as a quietly smaller number.
|
|
92
|
+
*/
|
|
93
|
+
export const BalanceSchema = z
|
|
94
|
+
.object({
|
|
95
|
+
allowance: z.object({
|
|
96
|
+
grantedMicro: MicroAmountSchema,
|
|
97
|
+
remainingMicro: MicroAmountSchema,
|
|
98
|
+
resetsAt: TimestampSchema,
|
|
99
|
+
}),
|
|
100
|
+
purchased: z.object({ remainingMicro: MicroAmountSchema }),
|
|
101
|
+
heldMicro: MicroAmountSchema.describe('Reserved against turns currently running.'),
|
|
102
|
+
owedMicro: MicroAmountSchema.describe('Debt from a turn that overran its reservation. May be "0"; when it is not, show it.'),
|
|
103
|
+
autoReload: z.object({
|
|
104
|
+
enabled: z.boolean(),
|
|
105
|
+
ceilingMicro: MicroAmountSchema.nullable(),
|
|
106
|
+
}),
|
|
107
|
+
})
|
|
108
|
+
.describe('The caller`s credit position. Every amount is an exact integer of micro-units carried as a string.');
|
|
109
|
+
/**
|
|
110
|
+
* Where a usage line`s price came from.
|
|
111
|
+
*
|
|
112
|
+
* `published_price` is the published DorkOS price. It is a separate value from
|
|
113
|
+
* `managed`, which means rates an organization configured for itself and
|
|
114
|
+
* explicitly not a public price — rendering published prices under `managed`
|
|
115
|
+
* would tell a person their rate is non-public, which inverts the meaning.
|
|
116
|
+
*/
|
|
117
|
+
export const CostBasisSchema = z
|
|
118
|
+
.enum(['byo_key', 'managed', 'published_price'])
|
|
119
|
+
.describe('Where a usage line`s price came from: the caller`s own key, rates their organization configured, or the published DorkOS price.');
|
|
120
|
+
/**
|
|
121
|
+
* How a credit or subscription position reads at a glance.
|
|
122
|
+
*
|
|
123
|
+
* Widened past subscription language on purpose: `exhausted` describes a credit
|
|
124
|
+
* balance that has run out, which a subscription vocabulary has no word for.
|
|
125
|
+
*/
|
|
126
|
+
export const UsageStateSchema = z
|
|
127
|
+
.enum(['inactive', 'active', 'grace', 'exhausted', 'unknown'])
|
|
128
|
+
.describe('How a credit or subscription position reads at a glance.');
|
|
129
|
+
/** How to group a usage query. */
|
|
130
|
+
export const UsageGroupBySchema = z
|
|
131
|
+
.enum(['seat', 'model', 'day'])
|
|
132
|
+
.describe('How to group a usage query.');
|
|
133
|
+
/** `GET /v1/usage` query parameters. */
|
|
134
|
+
export const UsageQuerySchema = z
|
|
135
|
+
.object({
|
|
136
|
+
from: TimestampSchema,
|
|
137
|
+
to: TimestampSchema,
|
|
138
|
+
groupBy: UsageGroupBySchema,
|
|
139
|
+
})
|
|
140
|
+
.describe('The window and grouping for a usage query.');
|
|
141
|
+
/**
|
|
142
|
+
* One row of the caller`s usage.
|
|
143
|
+
*
|
|
144
|
+
* Carries BOTH the upstream list price and what DorkOS charged, which means it
|
|
145
|
+
* carries the difference between them. That is deliberate rather than
|
|
146
|
+
* accidental: somebody paying for inference through DorkOS can see what the
|
|
147
|
+
* routing costs them without having to ask. Dropping `listPriceMicro` is the
|
|
148
|
+
* change that would undo it, and dropping a field is a `/v2` change.
|
|
149
|
+
*
|
|
150
|
+
* There is deliberately no supplier field and no price-list version identifier
|
|
151
|
+
* here. Neither is published, and neither may be inferred client-side.
|
|
152
|
+
*/
|
|
153
|
+
export const UsageRowSchema = z
|
|
154
|
+
.object({
|
|
155
|
+
key: z
|
|
156
|
+
.string()
|
|
157
|
+
.describe('The grouping key: an opaque seat identifier, an opaque model identifier, or a date.'),
|
|
158
|
+
displayName: z.string().describe('The server-supplied string to show for this row.'),
|
|
159
|
+
units: z
|
|
160
|
+
.number()
|
|
161
|
+
.nonnegative()
|
|
162
|
+
.describe('How much was used, in the unit the row is measured in.'),
|
|
163
|
+
unit: z.string().describe('What `units` counts, as a server-supplied string.'),
|
|
164
|
+
listPriceMicro: MicroAmountSchema.describe('The upstream list price for this row.'),
|
|
165
|
+
dorkosPriceMicro: MicroAmountSchema.describe('What DorkOS charged for this row.'),
|
|
166
|
+
costBasis: CostBasisSchema,
|
|
167
|
+
})
|
|
168
|
+
.describe('One row of the caller`s own usage, projected. No supplier and no price-list version appear here.');
|
|
169
|
+
/** `GET /v1/usage` — the caller`s own usage for a window. */
|
|
170
|
+
export const UsageResponseSchema = z
|
|
171
|
+
.object({
|
|
172
|
+
from: TimestampSchema,
|
|
173
|
+
to: TimestampSchema,
|
|
174
|
+
groupBy: UsageGroupBySchema,
|
|
175
|
+
state: UsageStateSchema,
|
|
176
|
+
rows: z.array(UsageRowSchema),
|
|
177
|
+
totals: z.object({
|
|
178
|
+
listPriceMicro: MicroAmountSchema,
|
|
179
|
+
dorkosPriceMicro: MicroAmountSchema,
|
|
180
|
+
}),
|
|
181
|
+
})
|
|
182
|
+
.describe('The caller`s own usage for a window, grouped as asked.');
|
|
183
|
+
/** One entry of the published price list. */
|
|
184
|
+
export const PriceListEntrySchema = z
|
|
185
|
+
.object({
|
|
186
|
+
modelId: IdSchema.describe('An opaque model identifier. This list is the only place a price belongs.'),
|
|
187
|
+
displayName: z.string(),
|
|
188
|
+
unit: z.string().describe('What the prices below are per, as a server-supplied string.'),
|
|
189
|
+
inputMicro: MicroAmountSchema,
|
|
190
|
+
outputMicro: MicroAmountSchema,
|
|
191
|
+
})
|
|
192
|
+
.describe('One entry of the published price list.');
|
|
193
|
+
/**
|
|
194
|
+
* `GET /v1/price-list` — the published per-model price list.
|
|
195
|
+
*
|
|
196
|
+
* Published by design. It carries nothing about how the list is arrived at and
|
|
197
|
+
* no commercial terms. It is not the only route carrying an amount — `/v1/usage`
|
|
198
|
+
* and `/v1/nudge` both do, for the caller's own figures — but it is the only one
|
|
199
|
+
* that publishes the list itself.
|
|
200
|
+
*/
|
|
201
|
+
export const PriceListResponseSchema = z
|
|
202
|
+
.object({
|
|
203
|
+
version: z.string().describe('An opaque version string for this list.'),
|
|
204
|
+
effectiveFrom: TimestampSchema,
|
|
205
|
+
entries: z.array(PriceListEntrySchema),
|
|
206
|
+
})
|
|
207
|
+
.describe('The published per-model price list. The only route in this contract that carries a price.');
|
|
208
|
+
/**
|
|
209
|
+
* `GET /v1/nudge` — one already-computed comparison, delivered reduced.
|
|
210
|
+
*
|
|
211
|
+
* The server does the subtraction; the client renders what it is given and
|
|
212
|
+
* computes nothing. Exactly one subscription and one price ever appear. The
|
|
213
|
+
* route sits behind a server flag and answers 404 until it is switched on, so a
|
|
214
|
+
* client treats 404 here as "no nudge", not as an error.
|
|
215
|
+
*/
|
|
216
|
+
export const NudgeSchema = z
|
|
217
|
+
.object({
|
|
218
|
+
trailing30Micro: MicroAmountSchema,
|
|
219
|
+
suggestedPlanId: IdSchema.describe('An opaque identifier. Never switch on this value.'),
|
|
220
|
+
suggestedPlanDisplayName: z.string(),
|
|
221
|
+
suggestedPlanPriceMicro: MicroAmountSchema,
|
|
222
|
+
savingMicro: MicroAmountSchema.describe('The subtraction the server already did.'),
|
|
223
|
+
computedAt: TimestampSchema,
|
|
224
|
+
dismissible: z.literal(true),
|
|
225
|
+
})
|
|
226
|
+
.describe('One already-computed comparison. 404 from this route means "no nudge", not an error.');
|
|
227
|
+
/**
|
|
228
|
+
* A request for a hosted page.
|
|
229
|
+
*
|
|
230
|
+
* `skuId` is an identifier the client received from the server. A client never
|
|
231
|
+
* constructs one and never enumerates the set. The amount and its rendering
|
|
232
|
+
* belong to the hosted page, not to this contract.
|
|
233
|
+
*/
|
|
234
|
+
export const HostedPageRequestSchema = z
|
|
235
|
+
.object({
|
|
236
|
+
skuId: IdSchema.optional().describe('An opaque identifier the server supplied earlier. Clients never construct or enumerate one.'),
|
|
237
|
+
returnUrl: z
|
|
238
|
+
.string()
|
|
239
|
+
.url()
|
|
240
|
+
.optional()
|
|
241
|
+
.describe('Where to send the person when the hosted page is done.'),
|
|
242
|
+
})
|
|
243
|
+
.describe('A request for a hosted checkout, top-up or billing-portal page.');
|
|
244
|
+
/**
|
|
245
|
+
* The hosted page to open.
|
|
246
|
+
*
|
|
247
|
+
* `POST /v1/checkout`, `POST /v1/topup` and `POST /v1/portal` all answer with
|
|
248
|
+
* this. No origin is baked into this package: the URL is a runtime value.
|
|
249
|
+
*/
|
|
250
|
+
export const HostedPageResponseSchema = z
|
|
251
|
+
.object({ url: z.string().url() })
|
|
252
|
+
.describe('The hosted page to open. A runtime value; no origin is baked into this package.');
|
|
253
|
+
/** `GET /v1/statement` query parameters. */
|
|
254
|
+
export const StatementQuerySchema = z
|
|
255
|
+
.object({
|
|
256
|
+
period: z.string().min(1).describe('The billing period to fetch, as the server labels it.'),
|
|
257
|
+
})
|
|
258
|
+
.describe('Which billing period to fetch a statement for.');
|
|
259
|
+
/** `GET /v1/statement` — a download link for the caller`s itemised statement. */
|
|
260
|
+
export const StatementResponseSchema = z
|
|
261
|
+
.object({
|
|
262
|
+
period: z.string(),
|
|
263
|
+
downloadUrl: z.string().url(),
|
|
264
|
+
expiresAt: TimestampSchema.describe('When the download link stops working.'),
|
|
265
|
+
})
|
|
266
|
+
.describe('A short-lived download link for the caller`s own itemised usage statement.');
|
|
267
|
+
//# sourceMappingURL=billing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"billing.js","sourceRoot":"","sources":["../src/billing.ts"],"names":[],"mappings":"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"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A thin `fetch` client for the DorkOS Cloud `/v1` contract.
|
|
3
|
+
*
|
|
4
|
+
* Deliberately small and deliberately portable: no Node-only import, no
|
|
5
|
+
* dependency beyond `zod`, and no baked-in origin. A CLI, a server and a
|
|
6
|
+
* browser can all use it, and the caller supplies the base URL, so nothing in
|
|
7
|
+
* this package knows where the service lives.
|
|
8
|
+
*
|
|
9
|
+
* @packageDocumentation
|
|
10
|
+
*/
|
|
11
|
+
import type { z } from 'zod';
|
|
12
|
+
import { type Problem } from './problem.js';
|
|
13
|
+
/** The subset of the `fetch` signature this client uses. */
|
|
14
|
+
export type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
|
|
15
|
+
/** How to reach the service, and who is calling. */
|
|
16
|
+
export interface CloudApiClientOptions {
|
|
17
|
+
/** The origin the `/v1` paths hang off, e.g. `https://example.invalid`. No default: this package bakes in no host. */
|
|
18
|
+
baseUrl: string;
|
|
19
|
+
/** The bearer token, or a function returning one. Omitted for the two device-code routes, which are unauthenticated. */
|
|
20
|
+
token?: string | (() => string | undefined | Promise<string | undefined>);
|
|
21
|
+
/** The `fetch` to use. Defaults to the global one. */
|
|
22
|
+
fetch?: FetchLike;
|
|
23
|
+
/** Extra headers sent with every request. */
|
|
24
|
+
headers?: Record<string, string>;
|
|
25
|
+
}
|
|
26
|
+
/** What one call may override. */
|
|
27
|
+
export interface RequestOptions {
|
|
28
|
+
/** Query parameters. Values that are `undefined` are dropped. */
|
|
29
|
+
query?: Record<string, string | number | boolean | undefined>;
|
|
30
|
+
/** A JSON request body. */
|
|
31
|
+
body?: unknown;
|
|
32
|
+
/** Aborts the request. */
|
|
33
|
+
signal?: AbortSignal;
|
|
34
|
+
/** Extra headers for this call only. */
|
|
35
|
+
headers?: Record<string, string>;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* A response that is neither the route's success schema nor a well-formed
|
|
39
|
+
* {@link Problem}.
|
|
40
|
+
*
|
|
41
|
+
* It is its own error rather than a generic one because the two failures need
|
|
42
|
+
* different follow-up: a malformed problem envelope is a service bug, and a
|
|
43
|
+
* success body that fails its schema usually means the client is older than the
|
|
44
|
+
* contract the service is serving.
|
|
45
|
+
*/
|
|
46
|
+
export declare class CloudApiResponseError extends Error {
|
|
47
|
+
/** The HTTP status the service answered with. */
|
|
48
|
+
readonly status: number;
|
|
49
|
+
/** The raw body, for a bug report. */
|
|
50
|
+
readonly body: unknown;
|
|
51
|
+
/**
|
|
52
|
+
* Builds the error.
|
|
53
|
+
*
|
|
54
|
+
* @param message - What went wrong.
|
|
55
|
+
* @param status - The HTTP status the service answered with.
|
|
56
|
+
* @param body - The raw response body.
|
|
57
|
+
*/
|
|
58
|
+
constructor(message: string, status: number, body: unknown);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* A refusal the service described with the contract's {@link Problem}
|
|
62
|
+
* envelope.
|
|
63
|
+
*/
|
|
64
|
+
export declare class CloudApiProblemError extends Error {
|
|
65
|
+
/** The parsed problem envelope. */
|
|
66
|
+
readonly problem: Problem;
|
|
67
|
+
/**
|
|
68
|
+
* Builds the error.
|
|
69
|
+
*
|
|
70
|
+
* @param problem - The parsed problem envelope.
|
|
71
|
+
*/
|
|
72
|
+
constructor(problem: Problem);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Narrows an unknown error to a {@link CloudApiProblemError}.
|
|
76
|
+
*
|
|
77
|
+
* @param error - The caught value.
|
|
78
|
+
*/
|
|
79
|
+
export declare function isCloudApiProblemError(error: unknown): error is CloudApiProblemError;
|
|
80
|
+
/**
|
|
81
|
+
* Creates a client bound to one origin and one credential.
|
|
82
|
+
*
|
|
83
|
+
* @param options - Where to reach the service and who is calling.
|
|
84
|
+
*/
|
|
85
|
+
export declare function createCloudApiClient(options: CloudApiClientOptions): {
|
|
86
|
+
request: <T extends z.ZodTypeAny>(method: string, path: string, schema: T, init?: RequestOptions) => Promise<z.output<T>>;
|
|
87
|
+
/**
|
|
88
|
+
* `GET` one route.
|
|
89
|
+
*
|
|
90
|
+
* @param path - A `/v1` path.
|
|
91
|
+
* @param schema - The success schema for this route.
|
|
92
|
+
* @param init - Query, headers and an abort signal.
|
|
93
|
+
*/
|
|
94
|
+
get: <T extends z.ZodTypeAny>(path: string, schema: T, init?: RequestOptions) => Promise<z.core.output<T>>;
|
|
95
|
+
/**
|
|
96
|
+
* `POST` to one route.
|
|
97
|
+
*
|
|
98
|
+
* @param path - A `/v1` path.
|
|
99
|
+
* @param schema - The success schema for this route.
|
|
100
|
+
* @param init - Body, query, headers and an abort signal.
|
|
101
|
+
*/
|
|
102
|
+
post: <T extends z.ZodTypeAny>(path: string, schema: T, init?: RequestOptions) => Promise<z.core.output<T>>;
|
|
103
|
+
/**
|
|
104
|
+
* `PATCH` one route.
|
|
105
|
+
*
|
|
106
|
+
* @param path - A `/v1` path.
|
|
107
|
+
* @param schema - The success schema for this route.
|
|
108
|
+
* @param init - Body, query, headers and an abort signal.
|
|
109
|
+
*/
|
|
110
|
+
patch: <T extends z.ZodTypeAny>(path: string, schema: T, init?: RequestOptions) => Promise<z.core.output<T>>;
|
|
111
|
+
/**
|
|
112
|
+
* `PUT` one route.
|
|
113
|
+
*
|
|
114
|
+
* @param path - A `/v1` path.
|
|
115
|
+
* @param schema - The success schema for this route.
|
|
116
|
+
* @param init - Body, query, headers and an abort signal.
|
|
117
|
+
*/
|
|
118
|
+
put: <T extends z.ZodTypeAny>(path: string, schema: T, init?: RequestOptions) => Promise<z.core.output<T>>;
|
|
119
|
+
/**
|
|
120
|
+
* `DELETE` one route.
|
|
121
|
+
*
|
|
122
|
+
* @param path - A `/v1` path.
|
|
123
|
+
* @param schema - The success schema for this route.
|
|
124
|
+
* @param init - Query, headers and an abort signal.
|
|
125
|
+
*/
|
|
126
|
+
delete: <T extends z.ZodTypeAny>(path: string, schema: T, init?: RequestOptions) => Promise<z.core.output<T>>;
|
|
127
|
+
};
|
|
128
|
+
/** A client bound to one origin and one credential. */
|
|
129
|
+
export type CloudApiClient = ReturnType<typeof createCloudApiClient>;
|
|
130
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAG7B,OAAO,EAAiB,KAAK,OAAO,EAAE,MAAM,cAAc,CAAC;AAE3D,4DAA4D;AAC5D,MAAM,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAEjF,oDAAoD;AACpD,MAAM,WAAW,qBAAqB;IACpC,sHAAsH;IACtH,OAAO,EAAE,MAAM,CAAC;IAChB,wHAAwH;IACxH,KAAK,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IAC1E,sDAAsD;IACtD,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,kCAAkC;AAClC,MAAM,WAAW,cAAc;IAC7B,iEAAiE;IACjE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC;IAC9D,2BAA2B;IAC3B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,0BAA0B;IAC1B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED;;;;;;;;GAQG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,iDAAiD;IACjD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAEvB;;;;;;OAMG;gBACS,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO;CAM3D;AAED;;;GAGG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,mCAAmC;IACnC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAE1B;;;;OAIG;gBACS,OAAO,EAAE,OAAO;CAK7B;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,oBAAoB,CAEpF;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB;cAgB1C,CAAC,SAAS,CAAC,CAAC,UAAU,UACnC,MAAM,QACR,MAAM,UACJ,CAAC,SACH,cAAc,KACnB,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAqFrB;;;;;;OAMG;UACG,CAAC,SAAS,CAAC,CAAC,UAAU,QAAQ,MAAM,UAAU,CAAC,SAAS,cAAc;IAE5E;;;;;;OAMG;WACI,CAAC,SAAS,CAAC,CAAC,UAAU,QAAQ,MAAM,UAAU,CAAC,SAAS,cAAc;IAE7E;;;;;;OAMG;YACK,CAAC,SAAS,CAAC,CAAC,UAAU,QAAQ,MAAM,UAAU,CAAC,SAAS,cAAc;IAE9E;;;;;;OAMG;UACG,CAAC,SAAS,CAAC,CAAC,UAAU,QAAQ,MAAM,UAAU,CAAC,SAAS,cAAc;IAE5E;;;;;;OAMG;aACM,CAAC,SAAS,CAAC,CAAC,UAAU,QAAQ,MAAM,UAAU,CAAC,SAAS,cAAc;EAGlF;AAED,uDAAuD;AACvD,MAAM,MAAM,cAAc,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { WIRE_VERSION_HEADER, WIRE_VERSION_HEADER_VALUE } from './primitives.js';
|
|
2
|
+
import { ProblemSchema } from './problem.js';
|
|
3
|
+
/**
|
|
4
|
+
* A response that is neither the route's success schema nor a well-formed
|
|
5
|
+
* {@link Problem}.
|
|
6
|
+
*
|
|
7
|
+
* It is its own error rather than a generic one because the two failures need
|
|
8
|
+
* different follow-up: a malformed problem envelope is a service bug, and a
|
|
9
|
+
* success body that fails its schema usually means the client is older than the
|
|
10
|
+
* contract the service is serving.
|
|
11
|
+
*/
|
|
12
|
+
export class CloudApiResponseError extends Error {
|
|
13
|
+
/** The HTTP status the service answered with. */
|
|
14
|
+
status;
|
|
15
|
+
/** The raw body, for a bug report. */
|
|
16
|
+
body;
|
|
17
|
+
/**
|
|
18
|
+
* Builds the error.
|
|
19
|
+
*
|
|
20
|
+
* @param message - What went wrong.
|
|
21
|
+
* @param status - The HTTP status the service answered with.
|
|
22
|
+
* @param body - The raw response body.
|
|
23
|
+
*/
|
|
24
|
+
constructor(message, status, body) {
|
|
25
|
+
super(message);
|
|
26
|
+
this.name = 'CloudApiResponseError';
|
|
27
|
+
this.status = status;
|
|
28
|
+
this.body = body;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A refusal the service described with the contract's {@link Problem}
|
|
33
|
+
* envelope.
|
|
34
|
+
*/
|
|
35
|
+
export class CloudApiProblemError extends Error {
|
|
36
|
+
/** The parsed problem envelope. */
|
|
37
|
+
problem;
|
|
38
|
+
/**
|
|
39
|
+
* Builds the error.
|
|
40
|
+
*
|
|
41
|
+
* @param problem - The parsed problem envelope.
|
|
42
|
+
*/
|
|
43
|
+
constructor(problem) {
|
|
44
|
+
super(`${problem.code}: ${problem.title}`);
|
|
45
|
+
this.name = 'CloudApiProblemError';
|
|
46
|
+
this.problem = problem;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Narrows an unknown error to a {@link CloudApiProblemError}.
|
|
51
|
+
*
|
|
52
|
+
* @param error - The caught value.
|
|
53
|
+
*/
|
|
54
|
+
export function isCloudApiProblemError(error) {
|
|
55
|
+
return error instanceof CloudApiProblemError;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Creates a client bound to one origin and one credential.
|
|
59
|
+
*
|
|
60
|
+
* @param options - Where to reach the service and who is calling.
|
|
61
|
+
*/
|
|
62
|
+
export function createCloudApiClient(options) {
|
|
63
|
+
const doFetch = options.fetch ?? ((input, init) => globalThis.fetch(input, init));
|
|
64
|
+
const base = options.baseUrl.replace(/\/+$/, '');
|
|
65
|
+
/**
|
|
66
|
+
* Sends one request and validates the answer against `schema`.
|
|
67
|
+
*
|
|
68
|
+
* Throws {@link CloudApiProblemError} when the service refuses, and
|
|
69
|
+
* {@link CloudApiResponseError} when neither the success schema nor the
|
|
70
|
+
* problem envelope fits.
|
|
71
|
+
*
|
|
72
|
+
* @param method - The HTTP method.
|
|
73
|
+
* @param path - A `/v1` path from `V1_ROUTES` or `v1Path`.
|
|
74
|
+
* @param schema - The success schema for this route.
|
|
75
|
+
* @param init - Query, body, headers and an abort signal.
|
|
76
|
+
*/
|
|
77
|
+
async function request(method, path, schema, init = {}) {
|
|
78
|
+
const url = new URL(base + path);
|
|
79
|
+
for (const [key, value] of Object.entries(init.query ?? {})) {
|
|
80
|
+
if (value !== undefined)
|
|
81
|
+
url.searchParams.set(key, String(value));
|
|
82
|
+
}
|
|
83
|
+
// Headers are merged case-insensitively, which a plain object spread cannot
|
|
84
|
+
// do. HTTP header names are case-insensitive, so a caller passing
|
|
85
|
+
// `Authorization` alongside this client's lowercase `authorization` does not
|
|
86
|
+
// override it — `Headers` keeps both and joins them with a comma, and
|
|
87
|
+
// `Bearer a, Bearer b` is not a credential any service accepts. Same for a
|
|
88
|
+
// caller's `Accept`. Lowercasing every key before merging makes the later
|
|
89
|
+
// value win, which is what "override" has to mean.
|
|
90
|
+
const token = typeof options.token === 'function' ? await options.token() : options.token;
|
|
91
|
+
const headers = {};
|
|
92
|
+
/**
|
|
93
|
+
* Merges one set of headers, letting a later value replace an earlier one
|
|
94
|
+
* whatever its casing.
|
|
95
|
+
*
|
|
96
|
+
* @param source - The headers to merge in.
|
|
97
|
+
*/
|
|
98
|
+
const merge = (source) => {
|
|
99
|
+
for (const [key, value] of Object.entries(source ?? {}))
|
|
100
|
+
headers[key.toLowerCase()] = value;
|
|
101
|
+
};
|
|
102
|
+
merge({
|
|
103
|
+
accept: 'application/json',
|
|
104
|
+
[WIRE_VERSION_HEADER]: WIRE_VERSION_HEADER_VALUE,
|
|
105
|
+
});
|
|
106
|
+
// The token goes on before the caller's headers, so a per-call
|
|
107
|
+
// `Authorization` replaces it rather than being silently discarded.
|
|
108
|
+
if (token)
|
|
109
|
+
headers.authorization = `Bearer ${token}`;
|
|
110
|
+
if (init.body !== undefined)
|
|
111
|
+
headers['content-type'] = 'application/json';
|
|
112
|
+
merge(options.headers);
|
|
113
|
+
merge(init.headers);
|
|
114
|
+
const response = await doFetch(url.toString(), {
|
|
115
|
+
method,
|
|
116
|
+
headers,
|
|
117
|
+
signal: init.signal,
|
|
118
|
+
body: init.body === undefined ? undefined : JSON.stringify(init.body),
|
|
119
|
+
});
|
|
120
|
+
// 204 is a success with nothing to validate. Hand the schema `undefined`
|
|
121
|
+
// rather than parsing an empty string as JSON, so a route typed
|
|
122
|
+
// `z.void()` succeeds and one typed as an object fails loudly.
|
|
123
|
+
const text = response.status === 204 ? '' : await response.text();
|
|
124
|
+
let payload;
|
|
125
|
+
if (text === '') {
|
|
126
|
+
payload = undefined;
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
try {
|
|
130
|
+
payload = JSON.parse(text);
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
throw new CloudApiResponseError(`Response body was not JSON: ${error.message}`, response.status, text);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (!response.ok) {
|
|
137
|
+
const problem = ProblemSchema.safeParse(payload);
|
|
138
|
+
if (problem.success)
|
|
139
|
+
throw new CloudApiProblemError(problem.data);
|
|
140
|
+
throw new CloudApiResponseError(`HTTP ${response.status} with a body that is not a Problem envelope`, response.status, payload);
|
|
141
|
+
}
|
|
142
|
+
const parsed = schema.safeParse(payload);
|
|
143
|
+
if (!parsed.success) {
|
|
144
|
+
throw new CloudApiResponseError(`Response did not match the contract: ${parsed.error.message}`, response.status, payload);
|
|
145
|
+
}
|
|
146
|
+
return parsed.data;
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
request,
|
|
150
|
+
/**
|
|
151
|
+
* `GET` one route.
|
|
152
|
+
*
|
|
153
|
+
* @param path - A `/v1` path.
|
|
154
|
+
* @param schema - The success schema for this route.
|
|
155
|
+
* @param init - Query, headers and an abort signal.
|
|
156
|
+
*/
|
|
157
|
+
get: (path, schema, init) => request('GET', path, schema, init),
|
|
158
|
+
/**
|
|
159
|
+
* `POST` to one route.
|
|
160
|
+
*
|
|
161
|
+
* @param path - A `/v1` path.
|
|
162
|
+
* @param schema - The success schema for this route.
|
|
163
|
+
* @param init - Body, query, headers and an abort signal.
|
|
164
|
+
*/
|
|
165
|
+
post: (path, schema, init) => request('POST', path, schema, init),
|
|
166
|
+
/**
|
|
167
|
+
* `PATCH` one route.
|
|
168
|
+
*
|
|
169
|
+
* @param path - A `/v1` path.
|
|
170
|
+
* @param schema - The success schema for this route.
|
|
171
|
+
* @param init - Body, query, headers and an abort signal.
|
|
172
|
+
*/
|
|
173
|
+
patch: (path, schema, init) => request('PATCH', path, schema, init),
|
|
174
|
+
/**
|
|
175
|
+
* `PUT` one route.
|
|
176
|
+
*
|
|
177
|
+
* @param path - A `/v1` path.
|
|
178
|
+
* @param schema - The success schema for this route.
|
|
179
|
+
* @param init - Body, query, headers and an abort signal.
|
|
180
|
+
*/
|
|
181
|
+
put: (path, schema, init) => request('PUT', path, schema, init),
|
|
182
|
+
/**
|
|
183
|
+
* `DELETE` one route.
|
|
184
|
+
*
|
|
185
|
+
* @param path - A `/v1` path.
|
|
186
|
+
* @param schema - The success schema for this route.
|
|
187
|
+
* @param init - Query, headers and an abort signal.
|
|
188
|
+
*/
|
|
189
|
+
delete: (path, schema, init) => request('DELETE', path, schema, init),
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|