@wtfalch/edge 0.2.0 → 0.3.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/README.md +10 -2
- package/dist/client.d.ts +17 -1
- package/dist/client.js +16 -0
- package/dist/types.d.ts +56 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ browser with Fetch support. The client has no runtime package dependencies.
|
|
|
5
5
|
|
|
6
6
|
## Status
|
|
7
7
|
|
|
8
|
-
Published:
|
|
8
|
+
Published: yes, v0.3.0, 2026-10-06.
|
|
9
9
|
|
|
10
10
|
```sh
|
|
11
11
|
npm install @wtfalch/edge
|
|
@@ -25,12 +25,20 @@ if ((await edge.available('alice')).available) {
|
|
|
25
25
|
}
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
```ts
|
|
29
|
+
// DNS records under the org's domain (`records:read`, `records:edit`)
|
|
30
|
+
const { records } = await edge.records.list();
|
|
31
|
+
const www = await edge.records.create({ label: 'www', type: 'A', content: '203.0.113.7' });
|
|
32
|
+
await edge.records.update(www.id, { ttl: 300 });
|
|
33
|
+
await edge.records.remove(www.id);
|
|
34
|
+
```
|
|
35
|
+
|
|
28
36
|
The key carries the organisation and the one domain its names live under, so
|
|
29
37
|
no call names either. `claim` is safe to repeat: the same `ref` returns the same
|
|
30
38
|
claim, and a new `port` moves its route. `get(ref)` finds the claim for a `ref` without listing. `close` makes the name answer 404 and
|
|
31
39
|
keeps it claimed; `remove` deletes the tunnel and record. `setReservedLabels`,
|
|
32
40
|
`mintKey` and `revokeKey` need the platform credential and are refused for an
|
|
33
|
-
entry key. A `remove` that already happened succeeds again, so a lost response is safe to retry. `rate_limited` errors carry `retryAfterSeconds`; a `conflict` with `reason: 'upstream_rejected'` means Cloudflare permanently refused, so do not retry it. API failures reject with `EdgeApiError`, which carries `status` and
|
|
41
|
+
entry key. A `remove` that already happened succeeds again, so a lost response is safe to retry. `rate_limited` errors carry `retryAfterSeconds`; a `conflict` with `reason: 'upstream_rejected'` means Cloudflare permanently refused, so do not retry it. `records.list()` also shows the zone's other records as `owner: 'platform'`, `locked: true`; they are never changed through edge. `records.create` takes `label` (`@` for the apex, TXT only), `type` (TXT, MX, CNAME, A, AAAA, CAA) and `content`, or `data` for CAA. `records.update` changes `content`, `data`, `ttl` or `priority`; to change a label or type, remove the record and create another. A records `conflict` carries a `reason` of `busy`, `pending`, `removing`, `taken` or `upstream_rejected` (`RecordConflictReason`); a record the platform owns answers `forbidden`, and the org's records cap answers `over_budget`. API failures reject with `EdgeApiError`, which carries `status` and
|
|
34
42
|
a typed `code` (see `EdgeError`); the SDK never throws a bare `Error` for a
|
|
35
43
|
service failure.
|
|
36
44
|
|
package/dist/client.d.ts
CHANGED
|
@@ -1,10 +1,26 @@
|
|
|
1
1
|
import { type ClientOptions } from './transport.js';
|
|
2
|
-
import type { AvailableResponse, ClaimNameRequest, ListClaimsResponse, MintKeyRequest, MintKeyResponse, NameClaim, OrgSettingsRequest, TokenResponse } from './types.js';
|
|
2
|
+
import type { AvailableResponse, ClaimNameRequest, ListClaimsResponse, ListRecordsResponse, MintKeyRequest, MintKeyResponse, NameClaim, OrgSettingsRequest, RecordInput, RecordPatch, RecordView, TokenResponse } from './types.js';
|
|
3
3
|
export { EdgeApiError, type ClientOptions } from './transport.js';
|
|
4
4
|
/** Called with an entry's key: the key carries its organisation and domain, so
|
|
5
5
|
* no call names either. `setReservedLabels`, `mintKey` and `revokeKey` are
|
|
6
6
|
* refused by the service for any credential but the platform's own. */
|
|
7
7
|
export declare function createEdgeClient(options: ClientOptions): {
|
|
8
|
+
/** The org's DNS records. Needs `records:read` (`records:edit` for changes). */
|
|
9
|
+
records: {
|
|
10
|
+
/** The org's own records, then every other live record in the zone as a
|
|
11
|
+
* locked platform record. */
|
|
12
|
+
list: () => Promise<ListRecordsResponse>;
|
|
13
|
+
/** Rejects with `not_found` when there is no such record. */
|
|
14
|
+
get: (id: string) => Promise<RecordView>;
|
|
15
|
+
/** Rejects with `conflict` (see `RecordConflictReason`) when the record
|
|
16
|
+
* exists or clashes, `forbidden` for a platform-owned label, and
|
|
17
|
+
* `over_budget` at the org's records cap. */
|
|
18
|
+
create: (input: RecordInput) => Promise<RecordView>;
|
|
19
|
+
/** Changes content, ttl or priority of the org's own record. */
|
|
20
|
+
update: (id: string, patch: RecordPatch) => Promise<RecordView>;
|
|
21
|
+
/** Returns the tombstone (`state: 'removed'`); repeating it is safe. */
|
|
22
|
+
remove: (id: string) => Promise<RecordView>;
|
|
23
|
+
};
|
|
8
24
|
/** True when the name is free: not reserved, no record in the zone, not claimed. */
|
|
9
25
|
available: (name: string) => Promise<AvailableResponse>;
|
|
10
26
|
/** Creates the tunnel, routes `name` to `127.0.0.1:<port>` with a 404
|
package/dist/client.js
CHANGED
|
@@ -6,6 +6,22 @@ export { EdgeApiError } from './transport.js';
|
|
|
6
6
|
export function createEdgeClient(options) {
|
|
7
7
|
const call = createTransport(options);
|
|
8
8
|
return {
|
|
9
|
+
/** The org's DNS records. Needs `records:read` (`records:edit` for changes). */
|
|
10
|
+
records: {
|
|
11
|
+
/** The org's own records, then every other live record in the zone as a
|
|
12
|
+
* locked platform record. */
|
|
13
|
+
list: () => call('GET', '/v1/records'),
|
|
14
|
+
/** Rejects with `not_found` when there is no such record. */
|
|
15
|
+
get: (id) => call('GET', `/v1/records/${encodeURIComponent(id)}`),
|
|
16
|
+
/** Rejects with `conflict` (see `RecordConflictReason`) when the record
|
|
17
|
+
* exists or clashes, `forbidden` for a platform-owned label, and
|
|
18
|
+
* `over_budget` at the org's records cap. */
|
|
19
|
+
create: (input) => call('POST', '/v1/records', input),
|
|
20
|
+
/** Changes content, ttl or priority of the org's own record. */
|
|
21
|
+
update: (id, patch) => call('PATCH', `/v1/records/${encodeURIComponent(id)}`, patch),
|
|
22
|
+
/** Returns the tombstone (`state: 'removed'`); repeating it is safe. */
|
|
23
|
+
remove: (id) => call('DELETE', `/v1/records/${encodeURIComponent(id)}`),
|
|
24
|
+
},
|
|
9
25
|
/** True when the name is free: not reserved, no record in the zone, not claimed. */
|
|
10
26
|
available: (name) => call('GET', `/v1/names/available?${new URLSearchParams({ name })}`),
|
|
11
27
|
/** Creates the tunnel, routes `name` to `127.0.0.1:<port>` with a 404
|
package/dist/types.d.ts
CHANGED
|
@@ -90,6 +90,8 @@ export interface OrgSettingsRequest {
|
|
|
90
90
|
organisationId: string;
|
|
91
91
|
/** Most live claims (pending, active, closed) this org may hold. */
|
|
92
92
|
maxClaims?: number | null;
|
|
93
|
+
/** Most live DNS records this org may hold. */
|
|
94
|
+
maxRecords?: number | null;
|
|
93
95
|
/** Rate bucket: calls allowed in a burst. */
|
|
94
96
|
rateBurst?: number | null;
|
|
95
97
|
/** Rate bucket: calls refilled per second. */
|
|
@@ -101,3 +103,57 @@ export interface OrgSettingsRequest {
|
|
|
101
103
|
* retry. `held`: the name was removed less than 30 days ago; do not retry
|
|
102
104
|
* until the hold ends. `upstream_rejected`: Cloudflare permanently refused; do not retry. */
|
|
103
105
|
export type EdgeConflictReason = 'busy' | 'pending' | 'removing' | 'taken' | 'held' | 'upstream_rejected';
|
|
106
|
+
export type RecordType = 'TXT' | 'MX' | 'CNAME' | 'A' | 'AAAA' | 'CAA';
|
|
107
|
+
/** CAA's structured value, in Cloudflare's form. */
|
|
108
|
+
export interface CaaData {
|
|
109
|
+
flags: number;
|
|
110
|
+
tag: string;
|
|
111
|
+
value: string;
|
|
112
|
+
}
|
|
113
|
+
/** A DNS record in the organisation's zone. The org's own records have
|
|
114
|
+
* `owner: 'organisation'`; every other live record in the zone is shown as
|
|
115
|
+
* `owner: 'platform'` with `locked: true` and is never changed through edge. */
|
|
116
|
+
export interface RecordView {
|
|
117
|
+
/** The row id for the org's own record; Cloudflare's id for a platform one. */
|
|
118
|
+
id: string;
|
|
119
|
+
/** The label under the org's domain; the apex is `@`. */
|
|
120
|
+
label: string;
|
|
121
|
+
type: string;
|
|
122
|
+
content: string;
|
|
123
|
+
/** Seconds, or 1 for automatic. */
|
|
124
|
+
ttl: number;
|
|
125
|
+
/** MX only; null otherwise. */
|
|
126
|
+
priority: number | null;
|
|
127
|
+
owner: 'organisation' | 'platform';
|
|
128
|
+
locked: boolean;
|
|
129
|
+
/** `pending`: still being set up. `removing`: teardown started. `removed`:
|
|
130
|
+
* the tombstone `records.remove` returns. */
|
|
131
|
+
state: 'pending' | 'active' | 'removing' | 'removed';
|
|
132
|
+
}
|
|
133
|
+
export interface RecordInput {
|
|
134
|
+
label: string;
|
|
135
|
+
type: RecordType;
|
|
136
|
+
/** Every type but CAA. */
|
|
137
|
+
content?: string;
|
|
138
|
+
/** CAA only. */
|
|
139
|
+
data?: CaaData;
|
|
140
|
+
/** Seconds (60 to 86400), or 1 for automatic (the default). */
|
|
141
|
+
ttl?: number;
|
|
142
|
+
/** MX only, 0 to 65535. */
|
|
143
|
+
priority?: number;
|
|
144
|
+
}
|
|
145
|
+
/** The label and type never change: remove the record and create another. */
|
|
146
|
+
export interface RecordPatch {
|
|
147
|
+
content?: string;
|
|
148
|
+
data?: CaaData;
|
|
149
|
+
ttl?: number;
|
|
150
|
+
priority?: number;
|
|
151
|
+
}
|
|
152
|
+
export interface ListRecordsResponse {
|
|
153
|
+
records: RecordView[];
|
|
154
|
+
}
|
|
155
|
+
/** Why a records call answered `conflict`: `busy` (retry soon), `pending`
|
|
156
|
+
* (still being set up), `removing` (teardown in progress), or `taken` (the
|
|
157
|
+
* record, or one it clashes with, already exists; do not retry), or `upstream_rejected`
|
|
158
|
+
* (Cloudflare permanently refused; do not retry). */
|
|
159
|
+
export type RecordConflictReason = Extract<EdgeConflictReason, 'busy' | 'pending' | 'removing' | 'taken' | 'upstream_rejected'>;
|