@w6w/sdk 0.3.0 → 0.5.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 +5 -5
- package/dist/mod.d.ts +2 -2
- package/dist/mod.js +2 -2
- package/dist/src/client.d.ts +34 -6
- package/dist/src/client.d.ts.map +1 -1
- package/dist/src/client.js +34 -5
- package/dist/src/client.js.map +1 -1
- package/dist/src/config.d.ts +2 -2
- package/dist/src/config.js +2 -2
- package/dist/src/connections.d.ts +2 -2
- package/dist/src/connections.js +1 -1
- package/dist/src/console/api-calls.d.ts +80 -0
- package/dist/src/console/api-calls.d.ts.map +1 -0
- package/dist/src/console/api-calls.js +69 -0
- package/dist/src/console/api-calls.js.map +1 -0
- package/dist/src/console/apps.d.ts +689 -0
- package/dist/src/console/apps.d.ts.map +1 -0
- package/dist/src/console/apps.js +402 -0
- package/dist/src/console/apps.js.map +1 -0
- package/dist/src/console/auth.d.ts +241 -0
- package/dist/src/console/auth.d.ts.map +1 -0
- package/dist/src/console/auth.js +173 -0
- package/dist/src/console/auth.js.map +1 -0
- package/dist/src/console/connections.d.ts +188 -0
- package/dist/src/console/connections.d.ts.map +1 -0
- package/dist/src/console/connections.js +182 -0
- package/dist/src/console/connections.js.map +1 -0
- package/dist/src/console/dashboard.d.ts +102 -0
- package/dist/src/console/dashboard.d.ts.map +1 -0
- package/dist/src/console/dashboard.js +59 -0
- package/dist/src/console/dashboard.js.map +1 -0
- package/dist/src/console/endpoints.d.ts +264 -0
- package/dist/src/console/endpoints.d.ts.map +1 -0
- package/dist/src/console/endpoints.js +164 -0
- package/dist/src/console/endpoints.js.map +1 -0
- package/dist/src/console/functions.d.ts +165 -0
- package/dist/src/console/functions.d.ts.map +1 -0
- package/dist/src/console/functions.js +117 -0
- package/dist/src/console/functions.js.map +1 -0
- package/dist/src/console/mod.d.ts +131 -0
- package/dist/src/console/mod.d.ts.map +1 -0
- package/dist/src/console/mod.js +121 -0
- package/dist/src/console/mod.js.map +1 -0
- package/dist/src/console/projects.d.ts +107 -0
- package/dist/src/console/projects.d.ts.map +1 -0
- package/dist/src/console/projects.js +97 -0
- package/dist/src/console/projects.js.map +1 -0
- package/dist/src/console/reliability.d.ts +149 -0
- package/dist/src/console/reliability.d.ts.map +1 -0
- package/dist/src/console/reliability.js +56 -0
- package/dist/src/console/reliability.js.map +1 -0
- package/dist/src/console/saved-tests.d.ts +198 -0
- package/dist/src/console/saved-tests.d.ts.map +1 -0
- package/dist/src/console/saved-tests.js +172 -0
- package/dist/src/console/saved-tests.js.map +1 -0
- package/dist/src/console/schedules.d.ts +127 -0
- package/dist/src/console/schedules.d.ts.map +1 -0
- package/dist/src/console/schedules.js +118 -0
- package/dist/src/console/schedules.js.map +1 -0
- package/dist/src/console/step-tests.d.ts +159 -0
- package/dist/src/console/step-tests.d.ts.map +1 -0
- package/dist/src/console/step-tests.js +129 -0
- package/dist/src/console/step-tests.js.map +1 -0
- package/dist/src/console/subscriptions.d.ts +199 -0
- package/dist/src/console/subscriptions.d.ts.map +1 -0
- package/dist/src/console/subscriptions.js +191 -0
- package/dist/src/console/subscriptions.js.map +1 -0
- package/dist/src/console/tenant-oauth-apps.d.ts +188 -0
- package/dist/src/console/tenant-oauth-apps.d.ts.map +1 -0
- package/dist/src/console/tenant-oauth-apps.js +152 -0
- package/dist/src/console/tenant-oauth-apps.js.map +1 -0
- package/dist/src/console/tokens.d.ts +159 -0
- package/dist/src/console/tokens.d.ts.map +1 -0
- package/dist/src/console/tokens.js +145 -0
- package/dist/src/console/tokens.js.map +1 -0
- package/dist/src/console/vault.d.ts +188 -0
- package/dist/src/console/vault.d.ts.map +1 -0
- package/dist/src/console/vault.js +164 -0
- package/dist/src/console/vault.js.map +1 -0
- package/dist/src/console/workflows.d.ts +243 -0
- package/dist/src/console/workflows.d.ts.map +1 -0
- package/dist/src/console/workflows.js +205 -0
- package/dist/src/console/workflows.js.map +1 -0
- package/dist/src/documents.d.ts +2 -2
- package/dist/src/documents.js +1 -1
- package/dist/src/http.d.ts +32 -2
- package/dist/src/http.d.ts.map +1 -1
- package/dist/src/http.js +11 -2
- package/dist/src/http.js.map +1 -1
- package/dist/src/me.d.ts +2 -2
- package/dist/src/me.js +1 -1
- package/dist/src/run.d.ts +1 -1
- package/dist/src/types.d.ts +2 -2
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/vars.d.ts +2 -2
- package/dist/src/vars.js +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/workflows.d.ts +2 -2
- package/dist/src/workflows.js +1 -1
- package/package.json +5 -1
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `client.console.tenantOAuthApps.*` — a tenant administrator's own OAuth
|
|
3
|
+
* client overrides (list, upsert, remove) for the apps their tenant connects
|
|
4
|
+
* to.
|
|
5
|
+
*
|
|
6
|
+
* **Studio-internal, not the published partner contract.** This namespace
|
|
7
|
+
* lives under the `console` subpath export (`@w6w/sdk/console`), excluded from
|
|
8
|
+
* `endpoints.json` and from the root barrel (`mod.ts`) — see `docs/console.md`.
|
|
9
|
+
* `@w6w/sdk`'s instance-state mechanism pin still applies here exactly as it
|
|
10
|
+
* does to every other namespace (`docs/implementation.md` §MECHANISM PIN —
|
|
11
|
+
* instance state, never globals): this class holds no state of its own beyond
|
|
12
|
+
* the injected host, so two clients in one process never share a credential.
|
|
13
|
+
*
|
|
14
|
+
* **The tenant is never a parameter here.** These three routes are scoped by
|
|
15
|
+
* the caller's own credential (the tenant claim on the bearer) plus a
|
|
16
|
+
* server-side tenant-admin check — unlike the operator family
|
|
17
|
+
* (`GET/PUT/DELETE /tenants/:id/oauth-app…`, `api/admin/tenants.ts:307-309`),
|
|
18
|
+
* which takes the tenant in the path and requires an operator. A `tenant`
|
|
19
|
+
* argument on any method below would be a tenant-selection affordance the
|
|
20
|
+
* server does not offer, so there is none.
|
|
21
|
+
*
|
|
22
|
+
* **Nothing here can read a client secret back.** {@linkcode
|
|
23
|
+
* TenantOAuthAppSummary} carries `hasClientSecret: boolean` and no secret
|
|
24
|
+
* field, mirroring the server's own summary projection
|
|
25
|
+
* (`packages/server/packages/db/repos/tenant_oauth_app.ts:26-37`, whose
|
|
26
|
+
* decrypting sibling `TenantOAuthApp` is entitled to exactly one caller in the
|
|
27
|
+
* BLL). That makes "no method on this namespace can ever resolve a stored
|
|
28
|
+
* secret" a compile-time fact rather than a runtime convention.
|
|
29
|
+
*
|
|
30
|
+
* **Response shapes are flat, no envelope key to peel with `unwrap()`** —
|
|
31
|
+
* mirroring `console/auth.ts:29-32` for this whole family. `list` returns the
|
|
32
|
+
* whole body deliberately, because `callbackUrl` rides beside `configs` and an
|
|
33
|
+
* `unwrap(res, "configs")` would silently drop it; `put` reaches one level in
|
|
34
|
+
* for `body.config`, which is the shape the server answers with (W4).
|
|
35
|
+
*
|
|
36
|
+
* **Wire shapes are planner pins, not reverse-engineered from a merged route.**
|
|
37
|
+
* `plan-B.md` § WIRE PINS W3–W5 fix `GET /tenant/oauth-apps`,
|
|
38
|
+
* `PUT /tenant/oauth-app/:app/:authKey` and
|
|
39
|
+
* `DELETE /tenant/oauth-app/:app/:authKey`; the tenant-scoped handlers are
|
|
40
|
+
* added by a sibling node on the server, against the same pins. The domain
|
|
41
|
+
* rules those handlers enforce already exist and are readable today in
|
|
42
|
+
* `packages/server/packages/bll/tenant-oauth-app.ts` — in particular
|
|
43
|
+
* `effectiveRow` (`:281-296`), which is what makes {@linkcode
|
|
44
|
+
* SetTenantOAuthAppInput}'s omission rule load-bearing rather than cosmetic.
|
|
45
|
+
* See {@linkcode SetTenantOAuthAppInput}.
|
|
46
|
+
*
|
|
47
|
+
* @module
|
|
48
|
+
*/
|
|
49
|
+
import { path } from "../http.js";
|
|
50
|
+
/**
|
|
51
|
+
* Serialise {@linkcode SetTenantOAuthAppInput} for the wire: **only the keys
|
|
52
|
+
* actually present**, with `null` preserved as a real value.
|
|
53
|
+
*
|
|
54
|
+
* Written as four explicit `!== undefined` tests rather than a spread or an
|
|
55
|
+
* `Object.entries` loop, for two reasons. It keeps `undefined` off the wire
|
|
56
|
+
* without relying on `JSON.stringify` dropping it (a serializer that
|
|
57
|
+
* normalised `undefined` to `null` would silently wipe a stored credential —
|
|
58
|
+
* see {@linkcode SetTenantOAuthAppInput}), and it is an allowlist: a caller
|
|
59
|
+
* that widens the input type and passes `redirectUri` or `force` cannot get
|
|
60
|
+
* either onto the wire from here, at runtime as well as at compile time.
|
|
61
|
+
*
|
|
62
|
+
* @param input - The caller's partial update.
|
|
63
|
+
* @returns A body carrying exactly the keys `input` set.
|
|
64
|
+
*/
|
|
65
|
+
function toSetBody(input) {
|
|
66
|
+
const body = {};
|
|
67
|
+
if (input.clientId !== undefined)
|
|
68
|
+
body.clientId = input.clientId;
|
|
69
|
+
if (input.clientSecret !== undefined)
|
|
70
|
+
body.clientSecret = input.clientSecret;
|
|
71
|
+
if (input.extra !== undefined)
|
|
72
|
+
body.extra = input.extra;
|
|
73
|
+
if (input.disabled !== undefined)
|
|
74
|
+
body.disabled = input.disabled;
|
|
75
|
+
return body;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The `console.tenantOAuthApps` namespace on a `W6WClient` — the caller's own
|
|
79
|
+
* tenant, never a tenant of its choosing.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* const { configs, callbackUrl } = await client.console.tenantOAuthApps.list();
|
|
84
|
+
* // Register `callbackUrl` with the provider — never assemble it client-side.
|
|
85
|
+
* await client.console.tenantOAuthApps.put("sendgrid", "oauth2", { clientId: "abc" });
|
|
86
|
+
* await client.console.tenantOAuthApps.remove("sendgrid", "oauth2");
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
export class TenantOAuthAppsApi {
|
|
90
|
+
#host;
|
|
91
|
+
/**
|
|
92
|
+
* @param host - The client this namespace issues requests through.
|
|
93
|
+
*/
|
|
94
|
+
constructor(host) {
|
|
95
|
+
this.#host = host;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* List the caller's tenant's OAuth overrides, plus this host's callback URL.
|
|
99
|
+
*
|
|
100
|
+
* Returns the body VERBATIM rather than unwrapping `configs`: `callbackUrl`
|
|
101
|
+
* rides beside it and is the one value a caller cannot compute for itself.
|
|
102
|
+
*
|
|
103
|
+
* @returns Every override for this tenant, and the server-derived callback URL.
|
|
104
|
+
* @throws {ApiError} `403` when the caller does not administer its tenant.
|
|
105
|
+
*/
|
|
106
|
+
async list() {
|
|
107
|
+
const res = await this.#host.request({
|
|
108
|
+
method: "GET",
|
|
109
|
+
path: "/tenant/oauth-apps",
|
|
110
|
+
});
|
|
111
|
+
return res.body;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Create or update one override, sending **only the fields `input` sets**.
|
|
115
|
+
*
|
|
116
|
+
* @param appId - The app id.
|
|
117
|
+
* @param authKey - The app manifest's `oauth2` auth method key.
|
|
118
|
+
* @param input - The fields to set; an omitted field is left untouched server-side.
|
|
119
|
+
* @returns The stored summary (the server answers `201 { config }`). Never carries a secret.
|
|
120
|
+
* @throws {ApiError} `403` when the caller does not administer its tenant;
|
|
121
|
+
* `404 unknown_app` when the app does not exist or does not support a tenant
|
|
122
|
+
* OAuth client; `400 invalid_config`/`invalid_redirect_uri` when the merged
|
|
123
|
+
* row would be an enabled override missing a required field.
|
|
124
|
+
*/
|
|
125
|
+
async put(appId, authKey, input) {
|
|
126
|
+
const res = await this.#host.request({
|
|
127
|
+
method: "PUT",
|
|
128
|
+
path: path `/tenant/oauth-app/${appId}/${authKey}`,
|
|
129
|
+
body: toSetBody(input),
|
|
130
|
+
});
|
|
131
|
+
return res.body.config;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Remove one override; the tenant falls back to the host's own OAuth client.
|
|
135
|
+
*
|
|
136
|
+
* Resolves `void`, discarding the server's uninformative `{ok: true}` —
|
|
137
|
+
* mirroring `projects.delete`/`schedules.delete`, not `apps.delete` (which
|
|
138
|
+
* keeps a genuinely informative count).
|
|
139
|
+
*
|
|
140
|
+
* @param appId - The app id.
|
|
141
|
+
* @param authKey - The app manifest's `oauth2` auth method key.
|
|
142
|
+
* @throws {ApiError} `403` when the caller does not administer its tenant;
|
|
143
|
+
* `404 unknown_tenant_oauth_app` when there is no override to remove.
|
|
144
|
+
*/
|
|
145
|
+
async remove(appId, authKey) {
|
|
146
|
+
await this.#host.request({
|
|
147
|
+
method: "DELETE",
|
|
148
|
+
path: path `/tenant/oauth-app/${appId}/${authKey}`,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=tenant-oauth-apps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenant-oauth-apps.js","sourceRoot":"","sources":["../../../src/console/tenant-oauth-apps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAEH,OAAO,EAAqB,IAAI,EAAuB,MAAM,YAAY,CAAC;AAyF1E;;;;;;;;;;;;;;GAcG;AACH,SAAS,SAAS,CAAC,KAA6B;IAC9C,MAAM,IAAI,GAA4B,EAAE,CAAC;IACzC,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS;QAAE,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;IACjE,IAAI,KAAK,CAAC,YAAY,KAAK,SAAS;QAAE,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC,YAAY,CAAC;IAC7E,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS;QAAE,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IACxD,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS;QAAE,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;IACjE,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,kBAAkB;IACpB,KAAK,CAAsB;IAEpC;;OAEG;IACH,YAAY,IAAyB;QACnC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACpB,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,IAAI;QACR,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAA0B;YAC5D,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,oBAAoB;SAC3B,CAAC,CAAC;QACH,OAAO,GAAG,CAAC,IAAI,CAAC;IAClB,CAAC;IAED;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,GAAG,CACP,KAAa,EACb,OAAe,EACf,KAA6B;QAE7B,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAoC;YACtE,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,IAAI,CAAA,qBAAqB,KAAK,IAAI,OAAO,EAAE;YACjD,IAAI,EAAE,SAAS,CAAC,KAAK,CAAC;SACvB,CAAC,CAAC;QACH,OAAO,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;IACzB,CAAC;IAED;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,MAAM,CAAC,KAAa,EAAE,OAAe;QACzC,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAU;YAChC,MAAM,EAAE,QAAQ;YAChB,IAAI,EAAE,IAAI,CAAA,qBAAqB,KAAK,IAAI,OAAO,EAAE;SAClD,CAAC,CAAC;IACL,CAAC;CACF"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `client.console.tokens.*` — long-lived API tokens for programmatic access
|
|
3
|
+
* (list, create, disable, enable, revoke), relocated from the studio's own
|
|
4
|
+
* API client.
|
|
5
|
+
*
|
|
6
|
+
* **Studio-internal, not the published partner contract.** This namespace
|
|
7
|
+
* lives under the `console` subpath export (`@w6w/sdk/console`), excluded from
|
|
8
|
+
* `endpoints.json` and from the root barrel (`mod.ts`) — see `docs/console.md`
|
|
9
|
+
* and HITL-1 in this task's contract. `@w6w/sdk`'s instance-state mechanism
|
|
10
|
+
* pin still applies here exactly as it does to every other namespace
|
|
11
|
+
* (`docs/implementation.md` §MECHANISM PIN — instance state, never globals):
|
|
12
|
+
* this class holds no state of its own beyond the injected host, so two
|
|
13
|
+
* clients in one process never share a credential.
|
|
14
|
+
*
|
|
15
|
+
* **`create`'s plaintext-once invariant is the mechanism this whole domain
|
|
16
|
+
* rests on.** `POST /tokens` is the ONLY response in this entire package that
|
|
17
|
+
* returns a token's plaintext — there is no reveal-later route. That is why
|
|
18
|
+
* {@linkcode CreateTokenResponse} is a SEPARATE type from {@linkcode ApiToken}
|
|
19
|
+
* rather than an optional `secret?` field bolted onto it: `ApiToken` — the
|
|
20
|
+
* return type of every other method here (`list`/`disable`/`enable`/`revoke`)
|
|
21
|
+
* — structurally cannot carry a `secret`, which makes "nothing reachable
|
|
22
|
+
* through those four methods can ever carry a secret" a compile-time fact,
|
|
23
|
+
* not a runtime convention. The server's own `toWire()` doc comment states
|
|
24
|
+
* the same invariant server-side: "never carries the secret, the hash, or
|
|
25
|
+
* internals."
|
|
26
|
+
*
|
|
27
|
+
* Five methods relocate from the studio's own `// API tokens` comment block
|
|
28
|
+
* (`packages/studio/src/api/client.ts:280-303` on the current merged tree) —
|
|
29
|
+
* field-for-field, not redesigned. Studio never sends `account` or
|
|
30
|
+
* `includeRevoked` on `list` (the server's list default already excludes
|
|
31
|
+
* revoked) — per HITL-4's own philosophy ("SDK completeness tracks studio's
|
|
32
|
+
* actual call surface, not the server's full route surface"), neither is
|
|
33
|
+
* added here.
|
|
34
|
+
*
|
|
35
|
+
* None of these methods take a `project` scoping parameter — tokens are
|
|
36
|
+
* account-scoped via the credential alone — so `TokensHost` needs only the
|
|
37
|
+
* transport, mirroring `VarsHost`/`ConnectionsHost`, not `DocumentsHost`.
|
|
38
|
+
*
|
|
39
|
+
* @module
|
|
40
|
+
*/
|
|
41
|
+
import { type HttpResponse, type RequestOptions } from "../http.ts";
|
|
42
|
+
/**
|
|
43
|
+
* The slice of `W6WClient` this namespace needs: the transport, and nothing
|
|
44
|
+
* else. Structural rather than a concrete client type, so the namespace stays
|
|
45
|
+
* independently constructible in a test and this module never imports the
|
|
46
|
+
* client back — mirrors `ConnectionsHost` in `./connections.ts`.
|
|
47
|
+
*/
|
|
48
|
+
export interface TokensHost {
|
|
49
|
+
/** Perform one request. */
|
|
50
|
+
request<T>(options: RequestOptions): Promise<HttpResponse<T>>;
|
|
51
|
+
}
|
|
52
|
+
/** Lifecycle status of an API token. `revoked` is terminal; `disabled` is reversible. */
|
|
53
|
+
export type ApiTokenStatus = "active" | "disabled" | "revoked";
|
|
54
|
+
/**
|
|
55
|
+
* A long-lived API token for programmatic access — distinct from the studio's
|
|
56
|
+
* own session JWT. **Never carries `secret`** — the server's `toWire()` never
|
|
57
|
+
* puts it on the wire for this shape, and neither does this type. The
|
|
58
|
+
* plaintext is reachable only once, from {@linkcode CreateTokenResponse}.
|
|
59
|
+
*/
|
|
60
|
+
export interface ApiToken {
|
|
61
|
+
/** Server-issued id. */
|
|
62
|
+
id: string;
|
|
63
|
+
/** The account this token authenticates as. */
|
|
64
|
+
account: string;
|
|
65
|
+
/** Caller-chosen label. */
|
|
66
|
+
name: string;
|
|
67
|
+
/** Lifecycle status. */
|
|
68
|
+
status: ApiTokenStatus;
|
|
69
|
+
/** ISO-8601 timestamp. */
|
|
70
|
+
createdAt: string;
|
|
71
|
+
/** ISO-8601 timestamp. */
|
|
72
|
+
updatedAt: string;
|
|
73
|
+
/** ISO-8601 timestamp of revocation, or `null` while active/disabled. */
|
|
74
|
+
revokedAt: string | null;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* `create`'s result — the token's metadata plus its plaintext secret, shown
|
|
78
|
+
* exactly ONCE. Defined as a type **separate** from {@linkcode ApiToken}, not
|
|
79
|
+
* an optional field on it — see this module's header comment for why that
|
|
80
|
+
* separation is load-bearing rather than a style choice. There is no
|
|
81
|
+
* reveal-later route: if the caller does not capture `secret` here, it is
|
|
82
|
+
* gone.
|
|
83
|
+
*/
|
|
84
|
+
export interface CreateTokenResponse {
|
|
85
|
+
/** The created token's metadata. Never carries the secret. */
|
|
86
|
+
token: ApiToken;
|
|
87
|
+
/** The plaintext credential. Shown exactly once — never logged, never re-fetchable. */
|
|
88
|
+
secret: string;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* The `console.tokens` namespace on a `W6WClient`.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```ts
|
|
95
|
+
* const tokens = await client.console.tokens.list();
|
|
96
|
+
* const { token, secret } = await client.console.tokens.create("ci-deploy");
|
|
97
|
+
* console.log(secret); // shown exactly once — capture it now or it is gone
|
|
98
|
+
* await client.console.tokens.disable(token.id);
|
|
99
|
+
* await client.console.tokens.enable(token.id);
|
|
100
|
+
* await client.console.tokens.revoke(token.id);
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
export declare class TokensApi {
|
|
104
|
+
#private;
|
|
105
|
+
/**
|
|
106
|
+
* @param host - The client this namespace issues requests through.
|
|
107
|
+
*/
|
|
108
|
+
constructor(host: TokensHost);
|
|
109
|
+
/**
|
|
110
|
+
* List the account's tokens. Excludes revoked tokens (the server's default);
|
|
111
|
+
* this method does not expose a parameter to include them, matching
|
|
112
|
+
* studio's own call surface.
|
|
113
|
+
*
|
|
114
|
+
* @returns The tokens, unwrapped from the `tokens` envelope. Never carries `secret`.
|
|
115
|
+
*/
|
|
116
|
+
list(): Promise<ApiToken[]>;
|
|
117
|
+
/**
|
|
118
|
+
* Create a token. **Returns the plaintext secret exactly once** — there is
|
|
119
|
+
* no reveal-later route, so a caller that does not capture it here has
|
|
120
|
+
* permanently lost it.
|
|
121
|
+
*
|
|
122
|
+
* **No envelope key to peel — the whole body IS `{token, secret}`.** Typed
|
|
123
|
+
* directly as `request<CreateTokenResponse>(...)`, returning `res.body`,
|
|
124
|
+
* mirroring `console.connections.test`'s/`console.reliability.list`'s
|
|
125
|
+
* established "no envelope key" pattern. `unwrap()` is deliberately not
|
|
126
|
+
* called here: there is no single key to unwrap.
|
|
127
|
+
*
|
|
128
|
+
* @param name - Caller-chosen label.
|
|
129
|
+
* @returns The created token's metadata plus its one-time plaintext secret.
|
|
130
|
+
* @throws {ApiError} `400 invalid_name`.
|
|
131
|
+
*/
|
|
132
|
+
create(name: string): Promise<CreateTokenResponse>;
|
|
133
|
+
/**
|
|
134
|
+
* Disable a token. Reversible — see {@linkcode enable}.
|
|
135
|
+
*
|
|
136
|
+
* @param id - The token id.
|
|
137
|
+
* @returns The updated token, unwrapped from the `token` envelope. Never carries `secret`.
|
|
138
|
+
* @throws {ApiError} `404 unknown_token`/`unknown_account`.
|
|
139
|
+
*/
|
|
140
|
+
disable(id: string): Promise<ApiToken>;
|
|
141
|
+
/**
|
|
142
|
+
* Re-enable a disabled token.
|
|
143
|
+
*
|
|
144
|
+
* @param id - The token id.
|
|
145
|
+
* @returns The updated token, unwrapped from the `token` envelope. Never carries `secret`.
|
|
146
|
+
* @throws {ApiError} `404 unknown_token`/`unknown_account`; `409 invalid_transition` when the
|
|
147
|
+
* token is revoked (revoke is terminal).
|
|
148
|
+
*/
|
|
149
|
+
enable(id: string): Promise<ApiToken>;
|
|
150
|
+
/**
|
|
151
|
+
* Revoke a token. Terminal — a revoked token cannot be re-enabled.
|
|
152
|
+
*
|
|
153
|
+
* @param id - The token id.
|
|
154
|
+
* @returns The updated token, unwrapped from the `token` envelope. Never carries `secret`.
|
|
155
|
+
* @throws {ApiError} `404 unknown_token`/`unknown_account`.
|
|
156
|
+
*/
|
|
157
|
+
revoke(id: string): Promise<ApiToken>;
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=tokens.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../../src/console/tokens.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,OAAO,EAAE,KAAK,YAAY,EAAQ,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AAG1E;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,2BAA2B;IAC3B,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;CAC/D;AAED,yFAAyF;AACzF,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;AAE/D;;;;;GAKG;AACH,MAAM,WAAW,QAAQ;IACvB,wBAAwB;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,+CAA+C;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,wBAAwB;IACxB,MAAM,EAAE,cAAc,CAAC;IACvB,0BAA0B;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,0BAA0B;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAmB;IAClC,8DAA8D;IAC9D,KAAK,EAAE,QAAQ,CAAC;IAChB,uFAAuF;IACvF,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,SAAS;;IAGpB;;OAEG;gBACS,IAAI,EAAE,UAAU;IAI5B;;;;;;OAMG;IACG,IAAI,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IAKjC;;;;;;;;;;;;;;OAcG;IACG,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IASxD;;;;;;OAMG;IACG,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAS5C;;;;;;;OAOG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAS3C;;;;;;OAMG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;CAQ5C"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `client.console.tokens.*` — long-lived API tokens for programmatic access
|
|
3
|
+
* (list, create, disable, enable, revoke), relocated from the studio's own
|
|
4
|
+
* API client.
|
|
5
|
+
*
|
|
6
|
+
* **Studio-internal, not the published partner contract.** This namespace
|
|
7
|
+
* lives under the `console` subpath export (`@w6w/sdk/console`), excluded from
|
|
8
|
+
* `endpoints.json` and from the root barrel (`mod.ts`) — see `docs/console.md`
|
|
9
|
+
* and HITL-1 in this task's contract. `@w6w/sdk`'s instance-state mechanism
|
|
10
|
+
* pin still applies here exactly as it does to every other namespace
|
|
11
|
+
* (`docs/implementation.md` §MECHANISM PIN — instance state, never globals):
|
|
12
|
+
* this class holds no state of its own beyond the injected host, so two
|
|
13
|
+
* clients in one process never share a credential.
|
|
14
|
+
*
|
|
15
|
+
* **`create`'s plaintext-once invariant is the mechanism this whole domain
|
|
16
|
+
* rests on.** `POST /tokens` is the ONLY response in this entire package that
|
|
17
|
+
* returns a token's plaintext — there is no reveal-later route. That is why
|
|
18
|
+
* {@linkcode CreateTokenResponse} is a SEPARATE type from {@linkcode ApiToken}
|
|
19
|
+
* rather than an optional `secret?` field bolted onto it: `ApiToken` — the
|
|
20
|
+
* return type of every other method here (`list`/`disable`/`enable`/`revoke`)
|
|
21
|
+
* — structurally cannot carry a `secret`, which makes "nothing reachable
|
|
22
|
+
* through those four methods can ever carry a secret" a compile-time fact,
|
|
23
|
+
* not a runtime convention. The server's own `toWire()` doc comment states
|
|
24
|
+
* the same invariant server-side: "never carries the secret, the hash, or
|
|
25
|
+
* internals."
|
|
26
|
+
*
|
|
27
|
+
* Five methods relocate from the studio's own `// API tokens` comment block
|
|
28
|
+
* (`packages/studio/src/api/client.ts:280-303` on the current merged tree) —
|
|
29
|
+
* field-for-field, not redesigned. Studio never sends `account` or
|
|
30
|
+
* `includeRevoked` on `list` (the server's list default already excludes
|
|
31
|
+
* revoked) — per HITL-4's own philosophy ("SDK completeness tracks studio's
|
|
32
|
+
* actual call surface, not the server's full route surface"), neither is
|
|
33
|
+
* added here.
|
|
34
|
+
*
|
|
35
|
+
* None of these methods take a `project` scoping parameter — tokens are
|
|
36
|
+
* account-scoped via the credential alone — so `TokensHost` needs only the
|
|
37
|
+
* transport, mirroring `VarsHost`/`ConnectionsHost`, not `DocumentsHost`.
|
|
38
|
+
*
|
|
39
|
+
* @module
|
|
40
|
+
*/
|
|
41
|
+
import { path } from "../http.js";
|
|
42
|
+
import { unwrap } from "../types.js";
|
|
43
|
+
/**
|
|
44
|
+
* The `console.tokens` namespace on a `W6WClient`.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* const tokens = await client.console.tokens.list();
|
|
49
|
+
* const { token, secret } = await client.console.tokens.create("ci-deploy");
|
|
50
|
+
* console.log(secret); // shown exactly once — capture it now or it is gone
|
|
51
|
+
* await client.console.tokens.disable(token.id);
|
|
52
|
+
* await client.console.tokens.enable(token.id);
|
|
53
|
+
* await client.console.tokens.revoke(token.id);
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export class TokensApi {
|
|
57
|
+
#host;
|
|
58
|
+
/**
|
|
59
|
+
* @param host - The client this namespace issues requests through.
|
|
60
|
+
*/
|
|
61
|
+
constructor(host) {
|
|
62
|
+
this.#host = host;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* List the account's tokens. Excludes revoked tokens (the server's default);
|
|
66
|
+
* this method does not expose a parameter to include them, matching
|
|
67
|
+
* studio's own call surface.
|
|
68
|
+
*
|
|
69
|
+
* @returns The tokens, unwrapped from the `tokens` envelope. Never carries `secret`.
|
|
70
|
+
*/
|
|
71
|
+
async list() {
|
|
72
|
+
const res = await this.#host.request({ method: "GET", path: "/tokens" });
|
|
73
|
+
return unwrap(res, "tokens");
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Create a token. **Returns the plaintext secret exactly once** — there is
|
|
77
|
+
* no reveal-later route, so a caller that does not capture it here has
|
|
78
|
+
* permanently lost it.
|
|
79
|
+
*
|
|
80
|
+
* **No envelope key to peel — the whole body IS `{token, secret}`.** Typed
|
|
81
|
+
* directly as `request<CreateTokenResponse>(...)`, returning `res.body`,
|
|
82
|
+
* mirroring `console.connections.test`'s/`console.reliability.list`'s
|
|
83
|
+
* established "no envelope key" pattern. `unwrap()` is deliberately not
|
|
84
|
+
* called here: there is no single key to unwrap.
|
|
85
|
+
*
|
|
86
|
+
* @param name - Caller-chosen label.
|
|
87
|
+
* @returns The created token's metadata plus its one-time plaintext secret.
|
|
88
|
+
* @throws {ApiError} `400 invalid_name`.
|
|
89
|
+
*/
|
|
90
|
+
async create(name) {
|
|
91
|
+
const res = await this.#host.request({
|
|
92
|
+
method: "POST",
|
|
93
|
+
path: "/tokens",
|
|
94
|
+
body: { name },
|
|
95
|
+
});
|
|
96
|
+
return res.body;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Disable a token. Reversible — see {@linkcode enable}.
|
|
100
|
+
*
|
|
101
|
+
* @param id - The token id.
|
|
102
|
+
* @returns The updated token, unwrapped from the `token` envelope. Never carries `secret`.
|
|
103
|
+
* @throws {ApiError} `404 unknown_token`/`unknown_account`.
|
|
104
|
+
*/
|
|
105
|
+
async disable(id) {
|
|
106
|
+
const res = await this.#host.request({
|
|
107
|
+
method: "POST",
|
|
108
|
+
path: path `/tokens/${id}/disable`,
|
|
109
|
+
body: {},
|
|
110
|
+
});
|
|
111
|
+
return unwrap(res, "token");
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Re-enable a disabled token.
|
|
115
|
+
*
|
|
116
|
+
* @param id - The token id.
|
|
117
|
+
* @returns The updated token, unwrapped from the `token` envelope. Never carries `secret`.
|
|
118
|
+
* @throws {ApiError} `404 unknown_token`/`unknown_account`; `409 invalid_transition` when the
|
|
119
|
+
* token is revoked (revoke is terminal).
|
|
120
|
+
*/
|
|
121
|
+
async enable(id) {
|
|
122
|
+
const res = await this.#host.request({
|
|
123
|
+
method: "POST",
|
|
124
|
+
path: path `/tokens/${id}/enable`,
|
|
125
|
+
body: {},
|
|
126
|
+
});
|
|
127
|
+
return unwrap(res, "token");
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Revoke a token. Terminal — a revoked token cannot be re-enabled.
|
|
131
|
+
*
|
|
132
|
+
* @param id - The token id.
|
|
133
|
+
* @returns The updated token, unwrapped from the `token` envelope. Never carries `secret`.
|
|
134
|
+
* @throws {ApiError} `404 unknown_token`/`unknown_account`.
|
|
135
|
+
*/
|
|
136
|
+
async revoke(id) {
|
|
137
|
+
const res = await this.#host.request({
|
|
138
|
+
method: "POST",
|
|
139
|
+
path: path `/tokens/${id}/revoke`,
|
|
140
|
+
body: {},
|
|
141
|
+
});
|
|
142
|
+
return unwrap(res, "token");
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=tokens.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../../src/console/tokens.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,OAAO,EAAqB,IAAI,EAAuB,MAAM,YAAY,CAAC;AAC1E,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAsDrC;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,SAAS;IACX,KAAK,CAAa;IAE3B;;OAEG;IACH,YAAY,IAAgB;QAC1B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACpB,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,IAAI;QACR,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAU,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;QAClF,OAAO,MAAM,CAAa,GAAG,EAAE,QAAQ,CAAC,CAAC;IAC3C,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACH,KAAK,CAAC,MAAM,CAAC,IAAY;QACvB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAsB;YACxD,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,EAAE,IAAI,EAAE;SACf,CAAC,CAAC;QACH,OAAO,GAAG,CAAC,IAAI,CAAC;IAClB,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,OAAO,CAAC,EAAU;QACtB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAU;YAC5C,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAA,WAAW,EAAE,UAAU;YACjC,IAAI,EAAE,EAAE;SACT,CAAC,CAAC;QACH,OAAO,MAAM,CAAW,GAAG,EAAE,OAAO,CAAC,CAAC;IACxC,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,MAAM,CAAC,EAAU;QACrB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAU;YAC5C,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAA,WAAW,EAAE,SAAS;YAChC,IAAI,EAAE,EAAE;SACT,CAAC,CAAC;QACH,OAAO,MAAM,CAAW,GAAG,EAAE,OAAO,CAAC,CAAC;IACxC,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,MAAM,CAAC,EAAU;QACrB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAU;YAC5C,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAA,WAAW,EAAE,SAAS;YAChC,IAAI,EAAE,EAAE;SACT,CAAC,CAAC;QACH,OAAO,MAAM,CAAW,GAAG,EAAE,OAAO,CAAC,CAAC;IACxC,CAAC;CACF"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `client.console.vault.*` — the write-only secret store (list, get, create,
|
|
3
|
+
* update, delete, seal), relocated from the studio's own API client.
|
|
4
|
+
*
|
|
5
|
+
* **Studio-internal, not the published partner contract.** This namespace
|
|
6
|
+
* lives under the `console` subpath export (`@w6w/sdk/console`), excluded from
|
|
7
|
+
* `endpoints.json` and from the root barrel (`mod.ts`) — see `docs/console.md`
|
|
8
|
+
* and HITL-1 in this task's contract. `@w6w/sdk`'s instance-state mechanism
|
|
9
|
+
* pin still applies here exactly as it does to every other namespace
|
|
10
|
+
* (`docs/implementation.md` §MECHANISM PIN — instance state, never globals):
|
|
11
|
+
* this class holds no state of its own beyond the injected host, so two
|
|
12
|
+
* clients in one process never share a credential.
|
|
13
|
+
*
|
|
14
|
+
* **Write-only, no-plaintext-in-responses is the invariant this whole domain
|
|
15
|
+
* rests on** (`packages/server/packages/api/admin/vault.ts:1-21`'s own header
|
|
16
|
+
* comment: "plaintext values NEVER appear in a response"). `list`/`get` never
|
|
17
|
+
* carry `value` — by the server's wire contract itself, not by client
|
|
18
|
+
* discipline — which is why {@linkcode VaultSecretSummary} has no `value`
|
|
19
|
+
* field. `create`/`update` forward `value` verbatim to *write* it, and it is
|
|
20
|
+
* simply never echoed back. `seal` is the one deliberate exception, and even
|
|
21
|
+
* there it never returns the plaintext: it answers with a ciphertext envelope
|
|
22
|
+
* (`SecretValue`) — an encrypt-only oracle with no matching decrypt route, so
|
|
23
|
+
* an authed caller learns nothing they didn't already provide.
|
|
24
|
+
*
|
|
25
|
+
* Six methods relocate from the studio's own `// Vault` comment block
|
|
26
|
+
* (`packages/studio/src/api/client.ts:257-278` on the current merged tree) —
|
|
27
|
+
* field-for-field, not redesigned.
|
|
28
|
+
*
|
|
29
|
+
* `value` is opaque — forwarded verbatim on `create`/`update`/`seal`, never
|
|
30
|
+
* inspected, logged, or transformed. This is a security-adjacent discipline,
|
|
31
|
+
* not a style note: the whole point of this field is a caller-opaque secret
|
|
32
|
+
* payload.
|
|
33
|
+
*
|
|
34
|
+
* None of these methods take a `project` scoping parameter — vault secrets
|
|
35
|
+
* are subject-scoped like `vars`, not project-scoped — so `VaultHost` needs
|
|
36
|
+
* only the transport, mirroring `VarsHost`/`ConnectionsHost`, not
|
|
37
|
+
* `DocumentsHost`.
|
|
38
|
+
*
|
|
39
|
+
* @module
|
|
40
|
+
*/
|
|
41
|
+
import { type HttpResponse, type RequestOptions } from "../http.ts";
|
|
42
|
+
/**
|
|
43
|
+
* The slice of `W6WClient` this namespace needs: the transport, and nothing
|
|
44
|
+
* else. Structural rather than a concrete client type, so the namespace stays
|
|
45
|
+
* independently constructible in a test and this module never imports the
|
|
46
|
+
* client back — mirrors `ConnectionsHost` in `./connections.ts`.
|
|
47
|
+
*/
|
|
48
|
+
export interface VaultHost {
|
|
49
|
+
/** Perform one request. */
|
|
50
|
+
request<T>(options: RequestOptions): Promise<HttpResponse<T>>;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Public projection of a stored vault secret. **`value` is deliberately
|
|
54
|
+
* absent** — the server never puts a secret's plaintext on the wire for
|
|
55
|
+
* `list`/`get`/`create`/`update`, and declaring the field here would promise a
|
|
56
|
+
* caller something that can never arrive.
|
|
57
|
+
*/
|
|
58
|
+
export interface VaultSecretSummary {
|
|
59
|
+
/** Server-issued id, `sec_…`. */
|
|
60
|
+
id: string;
|
|
61
|
+
/** Caller-chosen name, matching `^[a-z_][a-z0-9_]*$`. */
|
|
62
|
+
name: string;
|
|
63
|
+
/** Free-text description; `""` when unset. */
|
|
64
|
+
description: string;
|
|
65
|
+
/** ISO-8601 timestamp. */
|
|
66
|
+
createdAt: string;
|
|
67
|
+
/** ISO-8601 timestamp. */
|
|
68
|
+
updatedAt: string;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* An at-rest ciphertext envelope for one ad-hoc secret value, produced by
|
|
72
|
+
* {@linkcode VaultApi.seal}. Field-for-field identical to
|
|
73
|
+
* `packages/ui/src/types.ts`'s `SecretValue` shape, defined locally here
|
|
74
|
+
* rather than imported from `@w6w/ui` — this SDK has no dependency on
|
|
75
|
+
* `packages/ui` and must not gain one (wrong dependency direction for a
|
|
76
|
+
* published SDK). TypeScript's structural typing makes this value satisfy
|
|
77
|
+
* `@w6w/ui`'s `ExpressionOptions.sealSecret` prop shape at a studio call site
|
|
78
|
+
* with no shared import needed.
|
|
79
|
+
*/
|
|
80
|
+
export interface SecretValue {
|
|
81
|
+
type: "secret";
|
|
82
|
+
/** Base64-encoded ciphertext. */
|
|
83
|
+
ciphertext: string;
|
|
84
|
+
/** Base64-encoded initialization vector. */
|
|
85
|
+
iv: string;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The `console.vault` namespace on a `W6WClient`.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```ts
|
|
92
|
+
* const secrets = await client.console.vault.list();
|
|
93
|
+
* const created = await client.console.vault.create({ name: "openai_key", value: "sk-…" });
|
|
94
|
+
* await client.console.vault.update(created.id, { description: "Prod key" });
|
|
95
|
+
* const sealed = await client.console.vault.seal("sk-live-…");
|
|
96
|
+
* await client.console.vault.delete(created.id);
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
export declare class VaultApi {
|
|
100
|
+
#private;
|
|
101
|
+
/**
|
|
102
|
+
* @param host - The client this namespace issues requests through.
|
|
103
|
+
*/
|
|
104
|
+
constructor(host: VaultHost);
|
|
105
|
+
/**
|
|
106
|
+
* List the account's vault secrets.
|
|
107
|
+
*
|
|
108
|
+
* @returns The secrets, unwrapped from the `secrets` envelope. Never
|
|
109
|
+
* carries `value`.
|
|
110
|
+
*/
|
|
111
|
+
list(): Promise<VaultSecretSummary[]>;
|
|
112
|
+
/**
|
|
113
|
+
* Fetch one secret's metadata.
|
|
114
|
+
*
|
|
115
|
+
* **Zero studio callers today** — built for SDK completeness only. No 404
|
|
116
|
+
* special-casing — propagates as `ApiError` like every other "get" in this
|
|
117
|
+
* package except `console.schedules.get`, which has its own documented,
|
|
118
|
+
* unrelated exception.
|
|
119
|
+
*
|
|
120
|
+
* @param id - The `sec_…` id.
|
|
121
|
+
* @returns The secret, unwrapped from the `secret` envelope. Never carries `value`.
|
|
122
|
+
* @throws {ApiError} `404 unknown_secret` when there is no such id.
|
|
123
|
+
*/
|
|
124
|
+
get(id: string): Promise<VaultSecretSummary>;
|
|
125
|
+
/**
|
|
126
|
+
* Create a secret.
|
|
127
|
+
*
|
|
128
|
+
* `value` is opaque — forwarded verbatim, never inspected, logged, or
|
|
129
|
+
* transformed.
|
|
130
|
+
*
|
|
131
|
+
* @param body - `name` (unique, matches `^[a-z_][a-z0-9_]*$`), `value` (the
|
|
132
|
+
* plaintext to store), and an optional `description`.
|
|
133
|
+
* @returns The created secret, unwrapped from the `secret` envelope (the
|
|
134
|
+
* server answers `201`). Never carries `value`.
|
|
135
|
+
* @throws {ApiError} `400 invalid_name`/`invalid_value`/`invalid_description`; `409 secret_exists`.
|
|
136
|
+
*/
|
|
137
|
+
create(body: {
|
|
138
|
+
name: string;
|
|
139
|
+
value: string;
|
|
140
|
+
description?: string;
|
|
141
|
+
}): Promise<VaultSecretSummary>;
|
|
142
|
+
/**
|
|
143
|
+
* Update a secret: replace its value and/or its description.
|
|
144
|
+
*
|
|
145
|
+
* `value` is opaque — forwarded verbatim, never inspected, logged, or
|
|
146
|
+
* transformed, same discipline as {@linkcode create}.
|
|
147
|
+
*
|
|
148
|
+
* @param id - The `sec_…` id.
|
|
149
|
+
* @param body - `value` and/or `description`, forwarded verbatim.
|
|
150
|
+
* @returns The updated secret, unwrapped from the `secret` envelope. Never carries `value`.
|
|
151
|
+
* @throws {ApiError} `400 invalid_value`/`invalid_description`; `404 unknown_secret`.
|
|
152
|
+
*/
|
|
153
|
+
update(id: string, body: {
|
|
154
|
+
value?: string;
|
|
155
|
+
description?: string;
|
|
156
|
+
}): Promise<VaultSecretSummary>;
|
|
157
|
+
/**
|
|
158
|
+
* Delete a secret.
|
|
159
|
+
*
|
|
160
|
+
* Returns nothing: the server's `{ok: true}` carries no information a
|
|
161
|
+
* caller can use, mirroring `console.projects.delete`/
|
|
162
|
+
* `console.schedules.delete`/`console.connections.delete` in this same
|
|
163
|
+
* package (NOT `console.apps.delete`, which is the one documented
|
|
164
|
+
* exception) — vault delete has no such value to preserve.
|
|
165
|
+
*
|
|
166
|
+
* @param id - The `sec_…` id.
|
|
167
|
+
* @throws {ApiError} `404 unknown_secret` when there is no such id.
|
|
168
|
+
*/
|
|
169
|
+
delete(id: string): Promise<void>;
|
|
170
|
+
/**
|
|
171
|
+
* Encrypt an ad-hoc secret value into an at-rest ciphertext envelope,
|
|
172
|
+
* without storing it.
|
|
173
|
+
*
|
|
174
|
+
* **An encrypt-only oracle — there is no matching decrypt route.** The
|
|
175
|
+
* server's own header comment states the security property directly: "an
|
|
176
|
+
* authed caller learns nothing they didn't provide." `value` is opaque —
|
|
177
|
+
* forwarded verbatim, never inspected, logged, or transformed. **No
|
|
178
|
+
* envelope key to peel on the request side** — the body IS `{ value }` —
|
|
179
|
+
* but the *response* IS enveloped under `sealed`, unlike `console.
|
|
180
|
+
* connections.test`'s/`console.reliability.list`'s whole-body responses.
|
|
181
|
+
*
|
|
182
|
+
* @param value - The plaintext to seal. Never logged, never echoed back.
|
|
183
|
+
* @returns The ciphertext envelope, unwrapped from the `sealed` envelope.
|
|
184
|
+
* @throws {ApiError} `400 invalid_value` when `value` is empty.
|
|
185
|
+
*/
|
|
186
|
+
seal(value: string): Promise<SecretValue>;
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=vault.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vault.d.ts","sourceRoot":"","sources":["../../../src/console/vault.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,OAAO,EAAE,KAAK,YAAY,EAAQ,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AAG1E;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACxB,2BAA2B;IAC3B,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;CAC/D;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,iCAAiC;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,WAAW,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,0BAA0B;IAC1B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,QAAQ,CAAC;IACf,iCAAiC;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,4CAA4C;IAC5C,EAAE,EAAE,MAAM,CAAC;CACZ;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,QAAQ;;IAGnB;;OAEG;gBACS,IAAI,EAAE,SAAS;IAI3B;;;;;OAKG;IACG,IAAI,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAK3C;;;;;;;;;;;OAWG;IACG,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAKlD;;;;;;;;;;;OAWG;IACG,MAAM,CACV,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GAC1D,OAAO,CAAC,kBAAkB,CAAC;IAK9B;;;;;;;;;;OAUG;IACG,MAAM,CACV,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GAC7C,OAAO,CAAC,kBAAkB,CAAC;IAS9B;;;;;;;;;;;OAWG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvC;;;;;;;;;;;;;;;OAeG;IACG,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;CAQhD"}
|