@shipstatic/types 2.5.0-beta.10 → 2.5.0-beta.12
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 +15 -6
- package/dist/index.d.ts +233 -30
- package/dist/index.js +43 -0
- package/package.json +1 -1
- package/src/index.ts +248 -18
package/README.md
CHANGED
|
@@ -20,14 +20,24 @@ npm install @shipstatic/types
|
|
|
20
20
|
|
|
21
21
|
```typescript
|
|
22
22
|
import type {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
ListResponse, ListOptions,
|
|
24
|
+
Deployment, DeploymentListResponse, DeploymentDeleteResponse, DeploymentSetOptions,
|
|
25
|
+
Domain, DomainSetResult, DomainSetOptions, DomainListResponse, DnsRecord, DnsLookup, DomainDnsResponse, DomainRecordsResponse, DomainShareResponse, DomainValidateResponse, DomainDeleteResponse, DomainVerifyResponse,
|
|
26
|
+
Token, TokenListResponse, TokenCreateResponse, TokenCreateOptions, TokenDeleteResponse,
|
|
27
|
+
Account, AccountUsage, AccountOverrides, AccountDeleteResponse, AccountKeyResponse,
|
|
28
|
+
LabelsResponse, SetupInstructionsResponse,
|
|
27
29
|
StaticFile
|
|
28
30
|
} from '@shipstatic/types';
|
|
31
|
+
|
|
32
|
+
// Every public path, declared once — the API mounts from it, clients request against it.
|
|
33
|
+
import { API_PATHS } from '@shipstatic/types';
|
|
29
34
|
```
|
|
30
35
|
|
|
36
|
+
A mutation answers with the resource it affected — the entity when it
|
|
37
|
+
survives, otherwise the `*DeleteResponse` shape: the resource noun carrying
|
|
38
|
+
the canonical key, plus the resource's own state field where the resource is
|
|
39
|
+
mid-transition. No `message`, no `success`, no constant flags.
|
|
40
|
+
|
|
31
41
|
### Error System
|
|
32
42
|
|
|
33
43
|
```typescript
|
|
@@ -82,7 +92,7 @@ import {
|
|
|
82
92
|
DomainStatus, // pending | partial | success | paused
|
|
83
93
|
AccountPlan, // free | standard | sponsored | enterprise | suspended | terminating | terminated
|
|
84
94
|
FileValidationStatus, // pending | processing_error | excluded | validation_failed | ready
|
|
85
|
-
AuthMethod, //
|
|
95
|
+
AuthMethod, // session | apiKey | token | agent | oauth | webhook | system
|
|
86
96
|
} from '@shipstatic/types';
|
|
87
97
|
```
|
|
88
98
|
|
|
@@ -132,7 +142,6 @@ import type {
|
|
|
132
142
|
FileValidationResult,
|
|
133
143
|
ValidationIssue,
|
|
134
144
|
UploadedFile,
|
|
135
|
-
ProgressInfo,
|
|
136
145
|
} from '@shipstatic/types';
|
|
137
146
|
```
|
|
138
147
|
|
package/dist/index.d.ts
CHANGED
|
@@ -49,6 +49,49 @@ export interface DeploymentCreateResponse extends Deployment {
|
|
|
49
49
|
/** Claim URL for public deployments. Present when deployed without credentials. */
|
|
50
50
|
readonly claim?: string;
|
|
51
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* Every path the public API answers on, declared once.
|
|
54
|
+
*
|
|
55
|
+
* The URL surface used to be written out in four places — the API's mounts,
|
|
56
|
+
* the SDK's client, the dashboard's client, and the post-deploy smoke — so a
|
|
57
|
+
* rename meant finding all four. Here it is one table that the producer
|
|
58
|
+
* mounts from and the consumers request against, which is the only way a
|
|
59
|
+
* path and its handler cannot drift apart.
|
|
60
|
+
*
|
|
61
|
+
* **The operator surface is deliberately absent.** `/admin/*` paths belong
|
|
62
|
+
* to `web/my`, for the same reason its row types do: this package is
|
|
63
|
+
* published, and the operator surface is not public (see `CLAUDE.md`, "Admin
|
|
64
|
+
* types"). A path here is a promise to every npm consumer; `/admin` is a
|
|
65
|
+
* promise to one dashboard.
|
|
66
|
+
*
|
|
67
|
+
* Item paths are functions rather than templates so the key is interpolated
|
|
68
|
+
* in one place, encoded the same way by every caller.
|
|
69
|
+
*/
|
|
70
|
+
export declare const API_PATHS: {
|
|
71
|
+
readonly DEPLOYMENTS: "/deployments";
|
|
72
|
+
readonly DEPLOYMENT: (deployment: string) => string;
|
|
73
|
+
readonly DEPLOYMENT_CONFIG: (deployment: string) => string;
|
|
74
|
+
readonly DOMAINS: "/domains";
|
|
75
|
+
readonly DOMAIN: (domain: string) => string;
|
|
76
|
+
readonly DOMAIN_VERIFY: (domain: string) => string;
|
|
77
|
+
readonly DOMAIN_DNS: (domain: string) => string;
|
|
78
|
+
readonly DOMAIN_RECORDS: (domain: string) => string;
|
|
79
|
+
readonly DOMAIN_SHARE: (domain: string) => string;
|
|
80
|
+
readonly DOMAIN_PROPAGATION: (domain: string) => string;
|
|
81
|
+
readonly DOMAINS_VALIDATE: "/domains/validate";
|
|
82
|
+
readonly TOKENS: "/tokens";
|
|
83
|
+
readonly TOKEN: (token: string) => string;
|
|
84
|
+
readonly ACCOUNT: "/account";
|
|
85
|
+
readonly ACCOUNT_KEY: "/account/key";
|
|
86
|
+
readonly ACCOUNT_CLAIM: "/account/claim";
|
|
87
|
+
readonly ACTIVITIES: "/activities";
|
|
88
|
+
readonly LABELS: "/labels";
|
|
89
|
+
readonly LIMITS: "/limits";
|
|
90
|
+
readonly PING: "/ping";
|
|
91
|
+
readonly SETUP: "/setup";
|
|
92
|
+
readonly SPA_CHECK: "/spa-check";
|
|
93
|
+
readonly UPLOAD: "/upload";
|
|
94
|
+
};
|
|
52
95
|
/**
|
|
53
96
|
* The half of a list response that is identical on every list.
|
|
54
97
|
*
|
|
@@ -74,6 +117,42 @@ export interface DeploymentListResponse extends ListResponse {
|
|
|
74
117
|
/** Array of deployments */
|
|
75
118
|
deployments: Deployment[];
|
|
76
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Acknowledgement of `DELETE /deployments/:deployment` — and the shape every
|
|
122
|
+
* mutation with no entity left to return follows.
|
|
123
|
+
*
|
|
124
|
+
* **The law:** a mutation answers with the resource it affected. If the
|
|
125
|
+
* resource still exists, that means the entity itself (`Deployment`,
|
|
126
|
+
* `Domain`, …). Otherwise it means this: the resource noun carrying the
|
|
127
|
+
* item's canonical key, plus the resource's own state field — and ONLY when
|
|
128
|
+
* the resource survived in a transitional state, as an async deletion's does.
|
|
129
|
+
* Where the resource is simply gone, the key alone is the whole answer
|
|
130
|
+
* ({@link DomainDeleteResponse}, {@link TokenDeleteResponse}).
|
|
131
|
+
*
|
|
132
|
+
* Put positively: **an acknowledgement is a projection of the resource** —
|
|
133
|
+
* its key, plus its own state field where the state changed. That is the
|
|
134
|
+
* test to apply, and it is sharper than "no constant", which this shape
|
|
135
|
+
* would fail on its own terms: `status` here is the literal `'deleting'` on
|
|
136
|
+
* every success, exactly as fixed as a `changed: true` would be.
|
|
137
|
+
*
|
|
138
|
+
* The difference is not how predictable the value is, it is what the field
|
|
139
|
+
* IS. `status` is the deployment's own field — the same one `GET
|
|
140
|
+
* /deployments/:deployment` returns — so this response is `Deployment`
|
|
141
|
+
* narrowed to two members, and a client renders it with the code it already
|
|
142
|
+
* has. `changed: true`, `queued: true` and `success: true` are not fields of
|
|
143
|
+
* any entity; they exist only to assert that the call worked, which the
|
|
144
|
+
* status code already said. Sync versus accepted is likewise the status
|
|
145
|
+
* code's job — 200 versus 202 — not a boolean's.
|
|
146
|
+
*
|
|
147
|
+
* No prose either (`message`): an acknowledgement is data, and each surface
|
|
148
|
+
* composes its own copy.
|
|
149
|
+
*/
|
|
150
|
+
export interface DeploymentDeleteResponse {
|
|
151
|
+
/** The deployment hostname that was marked for removal */
|
|
152
|
+
readonly deployment: string;
|
|
153
|
+
/** The state the deployment is in while background cleanup runs */
|
|
154
|
+
readonly status: DeploymentStatusType;
|
|
155
|
+
}
|
|
77
156
|
/**
|
|
78
157
|
* Domain status constants
|
|
79
158
|
*
|
|
@@ -131,6 +210,25 @@ export interface DomainListResponse extends ListResponse {
|
|
|
131
210
|
/** Array of domains */
|
|
132
211
|
domains: Domain[];
|
|
133
212
|
}
|
|
213
|
+
/**
|
|
214
|
+
* Acknowledgement of `DELETE /domains/:domain`. The row is gone, so there is
|
|
215
|
+
* no state to state — the canonical domain name is the whole answer. See
|
|
216
|
+
* {@link DeploymentDeleteResponse} for the law.
|
|
217
|
+
*/
|
|
218
|
+
export interface DomainDeleteResponse {
|
|
219
|
+
/** The domain name that was removed, normalized */
|
|
220
|
+
readonly domain: string;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Acknowledgement of `POST /domains/:domain/verify` (202). The DNS check is
|
|
224
|
+
* queued, not performed — the accepted status code says so, and the domain's
|
|
225
|
+
* own status is unchanged until the check runs, which is why none is stated
|
|
226
|
+
* here. See {@link DeploymentDeleteResponse} for the law.
|
|
227
|
+
*/
|
|
228
|
+
export interface DomainVerifyResponse {
|
|
229
|
+
/** The domain whose DNS verification was queued, normalized */
|
|
230
|
+
readonly domain: string;
|
|
231
|
+
}
|
|
134
232
|
/**
|
|
135
233
|
* DNS record types supported for domain configuration
|
|
136
234
|
*/
|
|
@@ -156,13 +254,33 @@ export interface DnsProvider {
|
|
|
156
254
|
/**
|
|
157
255
|
* Response for domain DNS provider lookup
|
|
158
256
|
*/
|
|
257
|
+
/**
|
|
258
|
+
* What a DNS lookup found for a domain. An envelope rather than a bare
|
|
259
|
+
* {@link DnsProvider} because a lookup can succeed and learn more than the
|
|
260
|
+
* provider later; the shape is named so a consumer can hold one.
|
|
261
|
+
*/
|
|
262
|
+
export interface DnsLookup {
|
|
263
|
+
/** The provider serving this domain's DNS, absent when unidentified */
|
|
264
|
+
provider?: DnsProvider;
|
|
265
|
+
}
|
|
159
266
|
export interface DomainDnsResponse {
|
|
160
267
|
/** The domain name */
|
|
161
268
|
domain: string;
|
|
162
269
|
/** DNS provider information, null if not yet looked up */
|
|
163
|
-
dns:
|
|
164
|
-
|
|
165
|
-
|
|
270
|
+
dns: DnsLookup | null;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Response for `GET /domains/:domain/share` — the domain plus the salted
|
|
274
|
+
* hash that lets someone else complete its DNS setup without an account.
|
|
275
|
+
*
|
|
276
|
+
* `/admin/domains/:domain/share` answers the same shape, which is the admin
|
|
277
|
+
* law working: the operator surface is the public grammar with a prefix.
|
|
278
|
+
*/
|
|
279
|
+
export interface DomainShareResponse {
|
|
280
|
+
/** The domain the setup link is for */
|
|
281
|
+
readonly domain: string;
|
|
282
|
+
/** The salted setup hash that authorizes the share */
|
|
283
|
+
readonly hash: string;
|
|
166
284
|
}
|
|
167
285
|
/**
|
|
168
286
|
* Response for domain DNS records
|
|
@@ -175,6 +293,35 @@ export interface DomainRecordsResponse {
|
|
|
175
293
|
/** Required DNS records for configuration */
|
|
176
294
|
records: DnsRecord[];
|
|
177
295
|
}
|
|
296
|
+
/**
|
|
297
|
+
* Response for `GET /labels` — every label in use across the caller's
|
|
298
|
+
* deployments, domains and tokens, grouped and ordered by last use.
|
|
299
|
+
*
|
|
300
|
+
* The one plural noun outside the list contract, deliberately: labels have
|
|
301
|
+
* no identity, no row and no `created`, so there is nothing for a keyset
|
|
302
|
+
* cursor to resume after, and its consumer is an autocomplete that wants the
|
|
303
|
+
* whole set. Bounded by `PAGINATION.GLOBAL_LIMIT` rather than paginated.
|
|
304
|
+
*/
|
|
305
|
+
export interface LabelsResponse {
|
|
306
|
+
readonly labels: string[];
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Response for `POST /setup` — the DNS instructions for one domain, written
|
|
310
|
+
* for a human to follow at their registrar.
|
|
311
|
+
*
|
|
312
|
+
* `custom` is the provider-specific walkthrough when the provider is known;
|
|
313
|
+
* `generic` always answers, so a caller never has nothing to show.
|
|
314
|
+
*/
|
|
315
|
+
export interface SetupInstructionsResponse {
|
|
316
|
+
/** One-line summary of what to do */
|
|
317
|
+
readonly tldr: string;
|
|
318
|
+
/** Provider-specific instructions, null when the provider is unknown */
|
|
319
|
+
readonly custom: string | null;
|
|
320
|
+
/** Provider-agnostic instructions — always present */
|
|
321
|
+
readonly generic: string;
|
|
322
|
+
/** The identified DNS provider, null when unknown */
|
|
323
|
+
readonly provider: string | null;
|
|
324
|
+
}
|
|
178
325
|
/**
|
|
179
326
|
* Response for domain validation
|
|
180
327
|
*/
|
|
@@ -224,6 +371,15 @@ export interface TokenCreateResponse extends Token {
|
|
|
224
371
|
/** The raw credential value (shown once at creation, then never again) */
|
|
225
372
|
readonly secret: string;
|
|
226
373
|
}
|
|
374
|
+
/**
|
|
375
|
+
* Acknowledgement of `DELETE /tokens/:token`. The credential is revoked and
|
|
376
|
+
* its row is gone, so the management identifier is the whole answer. See
|
|
377
|
+
* {@link DeploymentDeleteResponse} for the law.
|
|
378
|
+
*/
|
|
379
|
+
export interface TokenDeleteResponse {
|
|
380
|
+
/** The 7-char management identifier that was revoked */
|
|
381
|
+
readonly token: string;
|
|
382
|
+
}
|
|
227
383
|
/**
|
|
228
384
|
* Account plan constants
|
|
229
385
|
*/
|
|
@@ -313,6 +469,32 @@ export interface AccountGetResponse extends Account {
|
|
|
313
469
|
/** Present only during read-only admin impersonation: the operator's account id. */
|
|
314
470
|
readonly impersonatedBy?: string;
|
|
315
471
|
}
|
|
472
|
+
/**
|
|
473
|
+
* Acknowledgement of `DELETE /account` (202). Termination is asynchronous —
|
|
474
|
+
* a cleanup consumer finishes the job — so the account survives long enough
|
|
475
|
+
* to state the plan it is transitioning through. `plan` is the account's
|
|
476
|
+
* state field, the way `status` is a deployment's. See
|
|
477
|
+
* {@link DeploymentDeleteResponse} for the law.
|
|
478
|
+
*/
|
|
479
|
+
export interface AccountDeleteResponse {
|
|
480
|
+
/** The account that was marked for termination */
|
|
481
|
+
readonly account: string;
|
|
482
|
+
/** The plan the account is in while cleanup runs */
|
|
483
|
+
readonly plan: AccountPlanType;
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* Response from `PUT /account/key` — the account's single API key, minted in
|
|
487
|
+
* place of whatever was there before.
|
|
488
|
+
*
|
|
489
|
+
* There is no entity to return: only the key's last-4 `hint` is durable
|
|
490
|
+
* (`Account.hint`), and the plaintext exists exactly once, in this response.
|
|
491
|
+
* The raw credential is `secret` on every surface that mints one — the same
|
|
492
|
+
* field `TokenCreateResponse` carries — because one concept gets one name.
|
|
493
|
+
*/
|
|
494
|
+
export interface AccountKeyResponse {
|
|
495
|
+
/** The raw API key (shown once at mint, then never again) */
|
|
496
|
+
readonly secret: string;
|
|
497
|
+
}
|
|
316
498
|
/**
|
|
317
499
|
* Account-specific configuration overrides
|
|
318
500
|
* Allows per-account customization of limits without changing plan
|
|
@@ -760,16 +942,22 @@ export interface SPACheckRequest {
|
|
|
760
942
|
/**
|
|
761
943
|
* Response from SPA check endpoint
|
|
762
944
|
*/
|
|
945
|
+
/**
|
|
946
|
+
* Which of the classifier's tiers reached the verdict, and why. Named rather
|
|
947
|
+
* than inline so the API's own `checkSPA` can return `SPACheckResponse`
|
|
948
|
+
* instead of restating its shape.
|
|
949
|
+
*/
|
|
950
|
+
export interface SPACheckDebug {
|
|
951
|
+
/** Which tier made the detection */
|
|
952
|
+
tier: 'exclusions' | 'inclusions' | 'scoring' | 'ai' | 'fallback';
|
|
953
|
+
/** The reason for the detection result */
|
|
954
|
+
reason: string;
|
|
955
|
+
}
|
|
763
956
|
export interface SPACheckResponse {
|
|
764
957
|
/** Whether the project is detected as a Single Page Application */
|
|
765
958
|
isSPA: boolean;
|
|
766
959
|
/** Debugging information about detection */
|
|
767
|
-
debug:
|
|
768
|
-
/** Which tier made the detection: 'exclusions', 'inclusions', 'scoring', 'ai', or 'fallback' */
|
|
769
|
-
tier: 'exclusions' | 'inclusions' | 'scoring' | 'ai' | 'fallback';
|
|
770
|
-
/** The reason for the detection result */
|
|
771
|
-
reason: string;
|
|
772
|
-
};
|
|
960
|
+
debug: SPACheckDebug;
|
|
773
961
|
}
|
|
774
962
|
/**
|
|
775
963
|
* Represents a file that has been processed and is ready for deploy.
|
|
@@ -864,6 +1052,33 @@ export interface ListOptions {
|
|
|
864
1052
|
/** Opaque cursor from the previous page's response. */
|
|
865
1053
|
cursor?: string;
|
|
866
1054
|
}
|
|
1055
|
+
/**
|
|
1056
|
+
* What a caller may change on an existing deployment.
|
|
1057
|
+
*
|
|
1058
|
+
* Labels and nothing else: a deployment's content is immutable by design, so
|
|
1059
|
+
* this is the whole mutable surface rather than a subset someone chose.
|
|
1060
|
+
*/
|
|
1061
|
+
export interface DeploymentSetOptions {
|
|
1062
|
+
labels: string[];
|
|
1063
|
+
}
|
|
1064
|
+
/**
|
|
1065
|
+
* What `domains.set()` may create or change. Every field is optional because
|
|
1066
|
+
* the call is a natural-key upsert: omitting `deployment` reserves the
|
|
1067
|
+
* domain, naming one links or re-points it, and labels travel either way.
|
|
1068
|
+
*
|
|
1069
|
+
* `deployment` is deliberately not nullable — unlinking is refused (400).
|
|
1070
|
+
* See `npm/ship/CLAUDE.md`, "Domain Write Semantics".
|
|
1071
|
+
*/
|
|
1072
|
+
export interface DomainSetOptions {
|
|
1073
|
+
deployment?: string;
|
|
1074
|
+
labels?: string[];
|
|
1075
|
+
}
|
|
1076
|
+
/** What a caller may set when minting a deploy token. */
|
|
1077
|
+
export interface TokenCreateOptions {
|
|
1078
|
+
/** Seconds until expiry; omit for a token that never expires. */
|
|
1079
|
+
ttl?: number;
|
|
1080
|
+
labels?: string[];
|
|
1081
|
+
}
|
|
867
1082
|
/**
|
|
868
1083
|
* Deployment resource interface - the contract all implementations must follow.
|
|
869
1084
|
*
|
|
@@ -876,32 +1091,22 @@ export interface DeploymentResource<UploadOptions extends DeploymentUploadOption
|
|
|
876
1091
|
upload: (input: DeployInput, options?: UploadOptions) => Promise<DeploymentCreateResponse>;
|
|
877
1092
|
list: (options?: ListOptions) => Promise<DeploymentListResponse>;
|
|
878
1093
|
get: (id: string) => Promise<Deployment>;
|
|
879
|
-
set: (id: string, options:
|
|
880
|
-
|
|
881
|
-
}) => Promise<Deployment>;
|
|
882
|
-
remove: (id: string) => Promise<void>;
|
|
1094
|
+
set: (id: string, options: DeploymentSetOptions) => Promise<Deployment>;
|
|
1095
|
+
remove: (id: string) => Promise<DeploymentDeleteResponse>;
|
|
883
1096
|
}
|
|
884
1097
|
/**
|
|
885
1098
|
* Domain resource interface - the contract all implementations must follow
|
|
886
1099
|
*/
|
|
887
1100
|
export interface DomainResource {
|
|
888
|
-
set: (name: string, options?:
|
|
889
|
-
deployment?: string;
|
|
890
|
-
labels?: string[];
|
|
891
|
-
}) => Promise<DomainSetResult>;
|
|
1101
|
+
set: (name: string, options?: DomainSetOptions) => Promise<DomainSetResult>;
|
|
892
1102
|
list: (options?: ListOptions) => Promise<DomainListResponse>;
|
|
893
1103
|
get: (name: string) => Promise<Domain>;
|
|
894
|
-
remove: (name: string) => Promise<
|
|
895
|
-
verify: (name: string) => Promise<
|
|
896
|
-
message: string;
|
|
897
|
-
}>;
|
|
1104
|
+
remove: (name: string) => Promise<DomainDeleteResponse>;
|
|
1105
|
+
verify: (name: string) => Promise<DomainVerifyResponse>;
|
|
898
1106
|
validate: (name: string) => Promise<DomainValidateResponse>;
|
|
899
1107
|
dns: (name: string) => Promise<DomainDnsResponse>;
|
|
900
1108
|
records: (name: string) => Promise<DomainRecordsResponse>;
|
|
901
|
-
share: (name: string) => Promise<
|
|
902
|
-
domain: string;
|
|
903
|
-
hash: string;
|
|
904
|
-
}>;
|
|
1109
|
+
share: (name: string) => Promise<DomainShareResponse>;
|
|
905
1110
|
}
|
|
906
1111
|
/**
|
|
907
1112
|
* Account resource interface - the contract all implementations must follow
|
|
@@ -913,12 +1118,10 @@ export interface AccountResource {
|
|
|
913
1118
|
* Token resource interface - the contract all implementations must follow
|
|
914
1119
|
*/
|
|
915
1120
|
export interface TokenResource {
|
|
916
|
-
create: (options?:
|
|
917
|
-
ttl?: number;
|
|
918
|
-
labels?: string[];
|
|
919
|
-
}) => Promise<TokenCreateResponse>;
|
|
1121
|
+
create: (options?: TokenCreateOptions) => Promise<TokenCreateResponse>;
|
|
920
1122
|
list: (options?: ListOptions) => Promise<TokenListResponse>;
|
|
921
|
-
|
|
1123
|
+
get: (token: string) => Promise<Token>;
|
|
1124
|
+
remove: (token: string) => Promise<TokenDeleteResponse>;
|
|
922
1125
|
}
|
|
923
1126
|
/**
|
|
924
1127
|
* Billing status response from GET /billing/status
|
package/dist/index.js
CHANGED
|
@@ -14,6 +14,49 @@ export const DeploymentStatus = {
|
|
|
14
14
|
FAILED: 'failed',
|
|
15
15
|
DELETING: 'deleting',
|
|
16
16
|
};
|
|
17
|
+
/**
|
|
18
|
+
* Every path the public API answers on, declared once.
|
|
19
|
+
*
|
|
20
|
+
* The URL surface used to be written out in four places — the API's mounts,
|
|
21
|
+
* the SDK's client, the dashboard's client, and the post-deploy smoke — so a
|
|
22
|
+
* rename meant finding all four. Here it is one table that the producer
|
|
23
|
+
* mounts from and the consumers request against, which is the only way a
|
|
24
|
+
* path and its handler cannot drift apart.
|
|
25
|
+
*
|
|
26
|
+
* **The operator surface is deliberately absent.** `/admin/*` paths belong
|
|
27
|
+
* to `web/my`, for the same reason its row types do: this package is
|
|
28
|
+
* published, and the operator surface is not public (see `CLAUDE.md`, "Admin
|
|
29
|
+
* types"). A path here is a promise to every npm consumer; `/admin` is a
|
|
30
|
+
* promise to one dashboard.
|
|
31
|
+
*
|
|
32
|
+
* Item paths are functions rather than templates so the key is interpolated
|
|
33
|
+
* in one place, encoded the same way by every caller.
|
|
34
|
+
*/
|
|
35
|
+
export const API_PATHS = {
|
|
36
|
+
DEPLOYMENTS: '/deployments',
|
|
37
|
+
DEPLOYMENT: (deployment) => `/deployments/${deployment}`,
|
|
38
|
+
DEPLOYMENT_CONFIG: (deployment) => `/deployments/${deployment}/config`,
|
|
39
|
+
DOMAINS: '/domains',
|
|
40
|
+
DOMAIN: (domain) => `/domains/${domain}`,
|
|
41
|
+
DOMAIN_VERIFY: (domain) => `/domains/${domain}/verify`,
|
|
42
|
+
DOMAIN_DNS: (domain) => `/domains/${domain}/dns`,
|
|
43
|
+
DOMAIN_RECORDS: (domain) => `/domains/${domain}/records`,
|
|
44
|
+
DOMAIN_SHARE: (domain) => `/domains/${domain}/share`,
|
|
45
|
+
DOMAIN_PROPAGATION: (domain) => `/domains/${domain}/propagation`,
|
|
46
|
+
DOMAINS_VALIDATE: '/domains/validate',
|
|
47
|
+
TOKENS: '/tokens',
|
|
48
|
+
TOKEN: (token) => `/tokens/${token}`,
|
|
49
|
+
ACCOUNT: '/account',
|
|
50
|
+
ACCOUNT_KEY: '/account/key',
|
|
51
|
+
ACCOUNT_CLAIM: '/account/claim',
|
|
52
|
+
ACTIVITIES: '/activities',
|
|
53
|
+
LABELS: '/labels',
|
|
54
|
+
LIMITS: '/limits',
|
|
55
|
+
PING: '/ping',
|
|
56
|
+
SETUP: '/setup',
|
|
57
|
+
SPA_CHECK: '/spa-check',
|
|
58
|
+
UPLOAD: '/upload',
|
|
59
|
+
};
|
|
17
60
|
// =============================================================================
|
|
18
61
|
// DOMAIN TYPES
|
|
19
62
|
// =============================================================================
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -58,6 +58,50 @@ export interface DeploymentCreateResponse extends Deployment {
|
|
|
58
58
|
readonly claim?: string;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Every path the public API answers on, declared once.
|
|
63
|
+
*
|
|
64
|
+
* The URL surface used to be written out in four places — the API's mounts,
|
|
65
|
+
* the SDK's client, the dashboard's client, and the post-deploy smoke — so a
|
|
66
|
+
* rename meant finding all four. Here it is one table that the producer
|
|
67
|
+
* mounts from and the consumers request against, which is the only way a
|
|
68
|
+
* path and its handler cannot drift apart.
|
|
69
|
+
*
|
|
70
|
+
* **The operator surface is deliberately absent.** `/admin/*` paths belong
|
|
71
|
+
* to `web/my`, for the same reason its row types do: this package is
|
|
72
|
+
* published, and the operator surface is not public (see `CLAUDE.md`, "Admin
|
|
73
|
+
* types"). A path here is a promise to every npm consumer; `/admin` is a
|
|
74
|
+
* promise to one dashboard.
|
|
75
|
+
*
|
|
76
|
+
* Item paths are functions rather than templates so the key is interpolated
|
|
77
|
+
* in one place, encoded the same way by every caller.
|
|
78
|
+
*/
|
|
79
|
+
export const API_PATHS = {
|
|
80
|
+
DEPLOYMENTS: '/deployments',
|
|
81
|
+
DEPLOYMENT: (deployment: string) => `/deployments/${deployment}`,
|
|
82
|
+
DEPLOYMENT_CONFIG: (deployment: string) => `/deployments/${deployment}/config`,
|
|
83
|
+
DOMAINS: '/domains',
|
|
84
|
+
DOMAIN: (domain: string) => `/domains/${domain}`,
|
|
85
|
+
DOMAIN_VERIFY: (domain: string) => `/domains/${domain}/verify`,
|
|
86
|
+
DOMAIN_DNS: (domain: string) => `/domains/${domain}/dns`,
|
|
87
|
+
DOMAIN_RECORDS: (domain: string) => `/domains/${domain}/records`,
|
|
88
|
+
DOMAIN_SHARE: (domain: string) => `/domains/${domain}/share`,
|
|
89
|
+
DOMAIN_PROPAGATION: (domain: string) => `/domains/${domain}/propagation`,
|
|
90
|
+
DOMAINS_VALIDATE: '/domains/validate',
|
|
91
|
+
TOKENS: '/tokens',
|
|
92
|
+
TOKEN: (token: string) => `/tokens/${token}`,
|
|
93
|
+
ACCOUNT: '/account',
|
|
94
|
+
ACCOUNT_KEY: '/account/key',
|
|
95
|
+
ACCOUNT_CLAIM: '/account/claim',
|
|
96
|
+
ACTIVITIES: '/activities',
|
|
97
|
+
LABELS: '/labels',
|
|
98
|
+
LIMITS: '/limits',
|
|
99
|
+
PING: '/ping',
|
|
100
|
+
SETUP: '/setup',
|
|
101
|
+
SPA_CHECK: '/spa-check',
|
|
102
|
+
UPLOAD: '/upload',
|
|
103
|
+
} as const;
|
|
104
|
+
|
|
61
105
|
/**
|
|
62
106
|
* The half of a list response that is identical on every list.
|
|
63
107
|
*
|
|
@@ -85,6 +129,43 @@ export interface DeploymentListResponse extends ListResponse {
|
|
|
85
129
|
deployments: Deployment[];
|
|
86
130
|
}
|
|
87
131
|
|
|
132
|
+
/**
|
|
133
|
+
* Acknowledgement of `DELETE /deployments/:deployment` — and the shape every
|
|
134
|
+
* mutation with no entity left to return follows.
|
|
135
|
+
*
|
|
136
|
+
* **The law:** a mutation answers with the resource it affected. If the
|
|
137
|
+
* resource still exists, that means the entity itself (`Deployment`,
|
|
138
|
+
* `Domain`, …). Otherwise it means this: the resource noun carrying the
|
|
139
|
+
* item's canonical key, plus the resource's own state field — and ONLY when
|
|
140
|
+
* the resource survived in a transitional state, as an async deletion's does.
|
|
141
|
+
* Where the resource is simply gone, the key alone is the whole answer
|
|
142
|
+
* ({@link DomainDeleteResponse}, {@link TokenDeleteResponse}).
|
|
143
|
+
*
|
|
144
|
+
* Put positively: **an acknowledgement is a projection of the resource** —
|
|
145
|
+
* its key, plus its own state field where the state changed. That is the
|
|
146
|
+
* test to apply, and it is sharper than "no constant", which this shape
|
|
147
|
+
* would fail on its own terms: `status` here is the literal `'deleting'` on
|
|
148
|
+
* every success, exactly as fixed as a `changed: true` would be.
|
|
149
|
+
*
|
|
150
|
+
* The difference is not how predictable the value is, it is what the field
|
|
151
|
+
* IS. `status` is the deployment's own field — the same one `GET
|
|
152
|
+
* /deployments/:deployment` returns — so this response is `Deployment`
|
|
153
|
+
* narrowed to two members, and a client renders it with the code it already
|
|
154
|
+
* has. `changed: true`, `queued: true` and `success: true` are not fields of
|
|
155
|
+
* any entity; they exist only to assert that the call worked, which the
|
|
156
|
+
* status code already said. Sync versus accepted is likewise the status
|
|
157
|
+
* code's job — 200 versus 202 — not a boolean's.
|
|
158
|
+
*
|
|
159
|
+
* No prose either (`message`): an acknowledgement is data, and each surface
|
|
160
|
+
* composes its own copy.
|
|
161
|
+
*/
|
|
162
|
+
export interface DeploymentDeleteResponse {
|
|
163
|
+
/** The deployment hostname that was marked for removal */
|
|
164
|
+
readonly deployment: string;
|
|
165
|
+
/** The state the deployment is in while background cleanup runs */
|
|
166
|
+
readonly status: DeploymentStatusType;
|
|
167
|
+
}
|
|
168
|
+
|
|
88
169
|
// =============================================================================
|
|
89
170
|
// DOMAIN TYPES
|
|
90
171
|
// =============================================================================
|
|
@@ -151,6 +232,27 @@ export interface DomainListResponse extends ListResponse {
|
|
|
151
232
|
domains: Domain[];
|
|
152
233
|
}
|
|
153
234
|
|
|
235
|
+
/**
|
|
236
|
+
* Acknowledgement of `DELETE /domains/:domain`. The row is gone, so there is
|
|
237
|
+
* no state to state — the canonical domain name is the whole answer. See
|
|
238
|
+
* {@link DeploymentDeleteResponse} for the law.
|
|
239
|
+
*/
|
|
240
|
+
export interface DomainDeleteResponse {
|
|
241
|
+
/** The domain name that was removed, normalized */
|
|
242
|
+
readonly domain: string;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Acknowledgement of `POST /domains/:domain/verify` (202). The DNS check is
|
|
247
|
+
* queued, not performed — the accepted status code says so, and the domain's
|
|
248
|
+
* own status is unchanged until the check runs, which is why none is stated
|
|
249
|
+
* here. See {@link DeploymentDeleteResponse} for the law.
|
|
250
|
+
*/
|
|
251
|
+
export interface DomainVerifyResponse {
|
|
252
|
+
/** The domain whose DNS verification was queued, normalized */
|
|
253
|
+
readonly domain: string;
|
|
254
|
+
}
|
|
255
|
+
|
|
154
256
|
/**
|
|
155
257
|
* DNS record types supported for domain configuration
|
|
156
258
|
*/
|
|
@@ -179,11 +281,35 @@ export interface DnsProvider {
|
|
|
179
281
|
/**
|
|
180
282
|
* Response for domain DNS provider lookup
|
|
181
283
|
*/
|
|
284
|
+
/**
|
|
285
|
+
* What a DNS lookup found for a domain. An envelope rather than a bare
|
|
286
|
+
* {@link DnsProvider} because a lookup can succeed and learn more than the
|
|
287
|
+
* provider later; the shape is named so a consumer can hold one.
|
|
288
|
+
*/
|
|
289
|
+
export interface DnsLookup {
|
|
290
|
+
/** The provider serving this domain's DNS, absent when unidentified */
|
|
291
|
+
provider?: DnsProvider;
|
|
292
|
+
}
|
|
293
|
+
|
|
182
294
|
export interface DomainDnsResponse {
|
|
183
295
|
/** The domain name */
|
|
184
296
|
domain: string;
|
|
185
297
|
/** DNS provider information, null if not yet looked up */
|
|
186
|
-
dns:
|
|
298
|
+
dns: DnsLookup | null;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Response for `GET /domains/:domain/share` — the domain plus the salted
|
|
303
|
+
* hash that lets someone else complete its DNS setup without an account.
|
|
304
|
+
*
|
|
305
|
+
* `/admin/domains/:domain/share` answers the same shape, which is the admin
|
|
306
|
+
* law working: the operator surface is the public grammar with a prefix.
|
|
307
|
+
*/
|
|
308
|
+
export interface DomainShareResponse {
|
|
309
|
+
/** The domain the setup link is for */
|
|
310
|
+
readonly domain: string;
|
|
311
|
+
/** The salted setup hash that authorizes the share */
|
|
312
|
+
readonly hash: string;
|
|
187
313
|
}
|
|
188
314
|
|
|
189
315
|
/**
|
|
@@ -198,6 +324,37 @@ export interface DomainRecordsResponse {
|
|
|
198
324
|
records: DnsRecord[];
|
|
199
325
|
}
|
|
200
326
|
|
|
327
|
+
/**
|
|
328
|
+
* Response for `GET /labels` — every label in use across the caller's
|
|
329
|
+
* deployments, domains and tokens, grouped and ordered by last use.
|
|
330
|
+
*
|
|
331
|
+
* The one plural noun outside the list contract, deliberately: labels have
|
|
332
|
+
* no identity, no row and no `created`, so there is nothing for a keyset
|
|
333
|
+
* cursor to resume after, and its consumer is an autocomplete that wants the
|
|
334
|
+
* whole set. Bounded by `PAGINATION.GLOBAL_LIMIT` rather than paginated.
|
|
335
|
+
*/
|
|
336
|
+
export interface LabelsResponse {
|
|
337
|
+
readonly labels: string[];
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Response for `POST /setup` — the DNS instructions for one domain, written
|
|
342
|
+
* for a human to follow at their registrar.
|
|
343
|
+
*
|
|
344
|
+
* `custom` is the provider-specific walkthrough when the provider is known;
|
|
345
|
+
* `generic` always answers, so a caller never has nothing to show.
|
|
346
|
+
*/
|
|
347
|
+
export interface SetupInstructionsResponse {
|
|
348
|
+
/** One-line summary of what to do */
|
|
349
|
+
readonly tldr: string;
|
|
350
|
+
/** Provider-specific instructions, null when the provider is unknown */
|
|
351
|
+
readonly custom: string | null;
|
|
352
|
+
/** Provider-agnostic instructions — always present */
|
|
353
|
+
readonly generic: string;
|
|
354
|
+
/** The identified DNS provider, null when unknown */
|
|
355
|
+
readonly provider: string | null;
|
|
356
|
+
}
|
|
357
|
+
|
|
201
358
|
/**
|
|
202
359
|
* Response for domain validation
|
|
203
360
|
*/
|
|
@@ -255,6 +412,16 @@ export interface TokenCreateResponse extends Token {
|
|
|
255
412
|
readonly secret: string;
|
|
256
413
|
}
|
|
257
414
|
|
|
415
|
+
/**
|
|
416
|
+
* Acknowledgement of `DELETE /tokens/:token`. The credential is revoked and
|
|
417
|
+
* its row is gone, so the management identifier is the whole answer. See
|
|
418
|
+
* {@link DeploymentDeleteResponse} for the law.
|
|
419
|
+
*/
|
|
420
|
+
export interface TokenDeleteResponse {
|
|
421
|
+
/** The 7-char management identifier that was revoked */
|
|
422
|
+
readonly token: string;
|
|
423
|
+
}
|
|
424
|
+
|
|
258
425
|
// =============================================================================
|
|
259
426
|
// ACCOUNT TYPES
|
|
260
427
|
// =============================================================================
|
|
@@ -353,6 +520,34 @@ export interface AccountGetResponse extends Account {
|
|
|
353
520
|
readonly impersonatedBy?: string;
|
|
354
521
|
}
|
|
355
522
|
|
|
523
|
+
/**
|
|
524
|
+
* Acknowledgement of `DELETE /account` (202). Termination is asynchronous —
|
|
525
|
+
* a cleanup consumer finishes the job — so the account survives long enough
|
|
526
|
+
* to state the plan it is transitioning through. `plan` is the account's
|
|
527
|
+
* state field, the way `status` is a deployment's. See
|
|
528
|
+
* {@link DeploymentDeleteResponse} for the law.
|
|
529
|
+
*/
|
|
530
|
+
export interface AccountDeleteResponse {
|
|
531
|
+
/** The account that was marked for termination */
|
|
532
|
+
readonly account: string;
|
|
533
|
+
/** The plan the account is in while cleanup runs */
|
|
534
|
+
readonly plan: AccountPlanType;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* Response from `PUT /account/key` — the account's single API key, minted in
|
|
539
|
+
* place of whatever was there before.
|
|
540
|
+
*
|
|
541
|
+
* There is no entity to return: only the key's last-4 `hint` is durable
|
|
542
|
+
* (`Account.hint`), and the plaintext exists exactly once, in this response.
|
|
543
|
+
* The raw credential is `secret` on every surface that mints one — the same
|
|
544
|
+
* field `TokenCreateResponse` carries — because one concept gets one name.
|
|
545
|
+
*/
|
|
546
|
+
export interface AccountKeyResponse {
|
|
547
|
+
/** The raw API key (shown once at mint, then never again) */
|
|
548
|
+
readonly secret: string;
|
|
549
|
+
}
|
|
550
|
+
|
|
356
551
|
/**
|
|
357
552
|
* Account-specific configuration overrides
|
|
358
553
|
* Allows per-account customization of limits without changing plan
|
|
@@ -1235,16 +1430,23 @@ export interface SPACheckRequest {
|
|
|
1235
1430
|
/**
|
|
1236
1431
|
* Response from SPA check endpoint
|
|
1237
1432
|
*/
|
|
1433
|
+
/**
|
|
1434
|
+
* Which of the classifier's tiers reached the verdict, and why. Named rather
|
|
1435
|
+
* than inline so the API's own `checkSPA` can return `SPACheckResponse`
|
|
1436
|
+
* instead of restating its shape.
|
|
1437
|
+
*/
|
|
1438
|
+
export interface SPACheckDebug {
|
|
1439
|
+
/** Which tier made the detection */
|
|
1440
|
+
tier: 'exclusions' | 'inclusions' | 'scoring' | 'ai' | 'fallback';
|
|
1441
|
+
/** The reason for the detection result */
|
|
1442
|
+
reason: string;
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1238
1445
|
export interface SPACheckResponse {
|
|
1239
1446
|
/** Whether the project is detected as a Single Page Application */
|
|
1240
1447
|
isSPA: boolean;
|
|
1241
1448
|
/** Debugging information about detection */
|
|
1242
|
-
debug:
|
|
1243
|
-
/** Which tier made the detection: 'exclusions', 'inclusions', 'scoring', 'ai', or 'fallback' */
|
|
1244
|
-
tier: 'exclusions' | 'inclusions' | 'scoring' | 'ai' | 'fallback';
|
|
1245
|
-
/** The reason for the detection result */
|
|
1246
|
-
reason: string;
|
|
1247
|
-
};
|
|
1449
|
+
debug: SPACheckDebug;
|
|
1248
1450
|
}
|
|
1249
1451
|
|
|
1250
1452
|
// =============================================================================
|
|
@@ -1357,6 +1559,36 @@ export interface ListOptions {
|
|
|
1357
1559
|
cursor?: string;
|
|
1358
1560
|
}
|
|
1359
1561
|
|
|
1562
|
+
/**
|
|
1563
|
+
* What a caller may change on an existing deployment.
|
|
1564
|
+
*
|
|
1565
|
+
* Labels and nothing else: a deployment's content is immutable by design, so
|
|
1566
|
+
* this is the whole mutable surface rather than a subset someone chose.
|
|
1567
|
+
*/
|
|
1568
|
+
export interface DeploymentSetOptions {
|
|
1569
|
+
labels: string[];
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
/**
|
|
1573
|
+
* What `domains.set()` may create or change. Every field is optional because
|
|
1574
|
+
* the call is a natural-key upsert: omitting `deployment` reserves the
|
|
1575
|
+
* domain, naming one links or re-points it, and labels travel either way.
|
|
1576
|
+
*
|
|
1577
|
+
* `deployment` is deliberately not nullable — unlinking is refused (400).
|
|
1578
|
+
* See `npm/ship/CLAUDE.md`, "Domain Write Semantics".
|
|
1579
|
+
*/
|
|
1580
|
+
export interface DomainSetOptions {
|
|
1581
|
+
deployment?: string;
|
|
1582
|
+
labels?: string[];
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
/** What a caller may set when minting a deploy token. */
|
|
1586
|
+
export interface TokenCreateOptions {
|
|
1587
|
+
/** Seconds until expiry; omit for a token that never expires. */
|
|
1588
|
+
ttl?: number;
|
|
1589
|
+
labels?: string[];
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1360
1592
|
/**
|
|
1361
1593
|
* Deployment resource interface - the contract all implementations must follow.
|
|
1362
1594
|
*
|
|
@@ -1371,26 +1603,23 @@ export interface DeploymentResource<
|
|
|
1371
1603
|
upload: (input: DeployInput, options?: UploadOptions) => Promise<DeploymentCreateResponse>;
|
|
1372
1604
|
list: (options?: ListOptions) => Promise<DeploymentListResponse>;
|
|
1373
1605
|
get: (id: string) => Promise<Deployment>;
|
|
1374
|
-
set: (id: string, options:
|
|
1375
|
-
remove: (id: string) => Promise<
|
|
1606
|
+
set: (id: string, options: DeploymentSetOptions) => Promise<Deployment>;
|
|
1607
|
+
remove: (id: string) => Promise<DeploymentDeleteResponse>;
|
|
1376
1608
|
}
|
|
1377
1609
|
|
|
1378
1610
|
/**
|
|
1379
1611
|
* Domain resource interface - the contract all implementations must follow
|
|
1380
1612
|
*/
|
|
1381
1613
|
export interface DomainResource {
|
|
1382
|
-
set: (
|
|
1383
|
-
name: string,
|
|
1384
|
-
options?: { deployment?: string; labels?: string[] },
|
|
1385
|
-
) => Promise<DomainSetResult>;
|
|
1614
|
+
set: (name: string, options?: DomainSetOptions) => Promise<DomainSetResult>;
|
|
1386
1615
|
list: (options?: ListOptions) => Promise<DomainListResponse>;
|
|
1387
1616
|
get: (name: string) => Promise<Domain>;
|
|
1388
|
-
remove: (name: string) => Promise<
|
|
1389
|
-
verify: (name: string) => Promise<
|
|
1617
|
+
remove: (name: string) => Promise<DomainDeleteResponse>;
|
|
1618
|
+
verify: (name: string) => Promise<DomainVerifyResponse>;
|
|
1390
1619
|
validate: (name: string) => Promise<DomainValidateResponse>;
|
|
1391
1620
|
dns: (name: string) => Promise<DomainDnsResponse>;
|
|
1392
1621
|
records: (name: string) => Promise<DomainRecordsResponse>;
|
|
1393
|
-
share: (name: string) => Promise<
|
|
1622
|
+
share: (name: string) => Promise<DomainShareResponse>;
|
|
1394
1623
|
}
|
|
1395
1624
|
|
|
1396
1625
|
/**
|
|
@@ -1404,9 +1633,10 @@ export interface AccountResource {
|
|
|
1404
1633
|
* Token resource interface - the contract all implementations must follow
|
|
1405
1634
|
*/
|
|
1406
1635
|
export interface TokenResource {
|
|
1407
|
-
create: (options?:
|
|
1636
|
+
create: (options?: TokenCreateOptions) => Promise<TokenCreateResponse>;
|
|
1408
1637
|
list: (options?: ListOptions) => Promise<TokenListResponse>;
|
|
1409
|
-
|
|
1638
|
+
get: (token: string) => Promise<Token>;
|
|
1639
|
+
remove: (token: string) => Promise<TokenDeleteResponse>;
|
|
1410
1640
|
}
|
|
1411
1641
|
|
|
1412
1642
|
// =============================================================================
|