@whooshbang/sdk 1.0.0-rc.17 → 1.0.0-rc.19
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/dist/cli/arguments.d.ts +22 -0
- package/dist/cli/arguments.js +59 -0
- package/dist/cli/arguments.js.map +1 -0
- package/dist/cli/bin.d.ts +2 -0
- package/dist/cli/bin.js +18 -0
- package/dist/cli/bin.js.map +1 -0
- package/dist/cli/commands.d.ts +14 -0
- package/dist/cli/commands.js +257 -0
- package/dist/cli/commands.js.map +1 -0
- package/dist/cli/config.d.ts +45 -0
- package/dist/cli/config.js +85 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/main.d.ts +4 -0
- package/dist/cli/main.js +136 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/oauth.d.ts +93 -0
- package/dist/cli/oauth.js +225 -0
- package/dist/cli/oauth.js.map +1 -0
- package/dist/cli/output.d.ts +19 -0
- package/dist/cli/output.js +39 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/session.d.ts +29 -0
- package/dist/cli/session.js +161 -0
- package/dist/cli/session.js.map +1 -0
- package/package.json +4 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A very small argv reader.
|
|
3
|
+
*
|
|
4
|
+
* `node:util`'s `parseArgs` is here and capable, but it wants the option
|
|
5
|
+
* vocabulary declared up front and this CLI's options differ per command. The
|
|
6
|
+
* whole grammar is `wb <words…> [--flag value] [--switch]`, which is a dozen
|
|
7
|
+
* lines to read directly and no dependency to carry into a package a library
|
|
8
|
+
* consumer also installs.
|
|
9
|
+
*/
|
|
10
|
+
export interface ParsedArguments {
|
|
11
|
+
/** The command path: `["project", "create"]`. */
|
|
12
|
+
readonly words: readonly string[];
|
|
13
|
+
readonly options: ReadonlyMap<string, string>;
|
|
14
|
+
readonly switches: ReadonlySet<string>;
|
|
15
|
+
/** Values repeated across several `--flag value` pairs, e.g. `--scope`. */
|
|
16
|
+
readonly repeated: ReadonlyMap<string, readonly string[]>;
|
|
17
|
+
}
|
|
18
|
+
export declare function parseArguments(argv: readonly string[]): ParsedArguments;
|
|
19
|
+
export declare class UsageError extends Error {
|
|
20
|
+
constructor(message: string);
|
|
21
|
+
}
|
|
22
|
+
export declare function required(parsed: ParsedArguments, name: string, what: string): string;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const SWITCHES = new Set([
|
|
2
|
+
"help",
|
|
3
|
+
"json",
|
|
4
|
+
"version",
|
|
5
|
+
"credential-stdin",
|
|
6
|
+
"yes",
|
|
7
|
+
]);
|
|
8
|
+
export function parseArguments(argv) {
|
|
9
|
+
const words = [];
|
|
10
|
+
const options = new Map();
|
|
11
|
+
const switches = new Set();
|
|
12
|
+
const repeated = new Map();
|
|
13
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
14
|
+
const token = argv[index];
|
|
15
|
+
if (!token.startsWith("--")) {
|
|
16
|
+
words.push(token);
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
const body = token.slice(2);
|
|
20
|
+
const equals = body.indexOf("=");
|
|
21
|
+
const name = equals === -1 ? body : body.slice(0, equals);
|
|
22
|
+
if (equals !== -1) {
|
|
23
|
+
const value = body.slice(equals + 1);
|
|
24
|
+
options.set(name, value);
|
|
25
|
+
repeated.set(name, [...(repeated.get(name) ?? []), value]);
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
if (SWITCHES.has(name)) {
|
|
29
|
+
switches.add(name);
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
const next = argv[index + 1];
|
|
33
|
+
if (next === undefined || next.startsWith("--")) {
|
|
34
|
+
// A bare unknown flag is a switch rather than an error: the command
|
|
35
|
+
// decides what it does and does not understand, and it can say so in its
|
|
36
|
+
// own words.
|
|
37
|
+
switches.add(name);
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
options.set(name, next);
|
|
41
|
+
repeated.set(name, [...(repeated.get(name) ?? []), next]);
|
|
42
|
+
index += 1;
|
|
43
|
+
}
|
|
44
|
+
return { options, repeated, switches, words };
|
|
45
|
+
}
|
|
46
|
+
export class UsageError extends Error {
|
|
47
|
+
constructor(message) {
|
|
48
|
+
super(message);
|
|
49
|
+
this.name = "UsageError";
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export function required(parsed, name, what) {
|
|
53
|
+
const value = parsed.options.get(name);
|
|
54
|
+
if (value === undefined || value.length === 0) {
|
|
55
|
+
throw new UsageError(`--${name} is required: ${what}.`);
|
|
56
|
+
}
|
|
57
|
+
return value;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=arguments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"arguments.js","sourceRoot":"","sources":["../../src/cli/arguments.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/bin.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* The `wb` executable, and nothing else.
|
|
4
|
+
*
|
|
5
|
+
* `main.ts` used to end with an "am I the entry point?" guard comparing
|
|
6
|
+
* `import.meta.url` against `process.argv[1]`. npm installs a bin as a symlink,
|
|
7
|
+
* so `argv[1]` is `node_modules/.bin/wb` while `import.meta.url` is the real
|
|
8
|
+
* file — the guard was false, and `wb --help` printed nothing and exited 0.
|
|
9
|
+
* A CLI that silently succeeds while doing nothing is worse than one that
|
|
10
|
+
* crashes, and it shipped in 1.0.0-rc.18.
|
|
11
|
+
*
|
|
12
|
+
* There is no guard here to get wrong. This file is the entry point because it
|
|
13
|
+
* is the only thing `bin` names, it is imported by nothing, and running it runs
|
|
14
|
+
* the CLI.
|
|
15
|
+
*/
|
|
16
|
+
import { run } from "./main.js";
|
|
17
|
+
process.exitCode = await run(process.argv.slice(2));
|
|
18
|
+
//# sourceMappingURL=bin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../../src/cli/bin.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAEhC,OAAO,CAAC,QAAQ,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type ParsedArguments } from "./arguments.js";
|
|
2
|
+
import { type Writer } from "./output.js";
|
|
3
|
+
import { resolveOrigin } from "./session.js";
|
|
4
|
+
export interface CommandContext {
|
|
5
|
+
readonly parsed: ParsedArguments;
|
|
6
|
+
readonly writer: Writer;
|
|
7
|
+
readonly origin: string;
|
|
8
|
+
readonly openUrl: (url: string) => Promise<void>;
|
|
9
|
+
readonly readStdin: () => Promise<string>;
|
|
10
|
+
readonly credentialsFile?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function resolveCommand(words: readonly string[]): ((context: CommandContext) => Promise<void>) | null;
|
|
13
|
+
export declare const COMMAND_NAMES: string[];
|
|
14
|
+
export { resolveOrigin };
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { required, UsageError } from "./arguments.js";
|
|
3
|
+
import { emit, emitSecret, table } from "./output.js";
|
|
4
|
+
import { authorizedClient, resolveOrigin, signIn, signOut } from "./session.js";
|
|
5
|
+
/**
|
|
6
|
+
* Every side-effecting call needs an idempotency key, and a person running a
|
|
7
|
+
* command by hand has no opinion about one. Generating it means a retried
|
|
8
|
+
* `wb message send` after a dropped connection is a replay rather than a
|
|
9
|
+
* second message — but only within the one invocation, which is why `--key`
|
|
10
|
+
* exists for anybody scripting a genuinely repeatable operation.
|
|
11
|
+
*/
|
|
12
|
+
function idempotency(parsed) {
|
|
13
|
+
return { idempotencyKey: parsed.options.get("key") ?? randomUUID() };
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* `connection` unless asked otherwise, which matches what the API does for an
|
|
17
|
+
* ordinary subscriber id. Naming it on every send keeps a script auditable:
|
|
18
|
+
* somebody reading it can see which transport it meant without knowing the
|
|
19
|
+
* defaulting rule.
|
|
20
|
+
*/
|
|
21
|
+
function deliveryTarget(parsed) {
|
|
22
|
+
const value = parsed.options.get("target") ?? "connection";
|
|
23
|
+
if (value !== "connection" && value !== "simulator") {
|
|
24
|
+
throw new UsageError("--target must be connection or simulator.");
|
|
25
|
+
}
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
function environmentArguments(parsed) {
|
|
29
|
+
return {
|
|
30
|
+
environmentId: required(parsed, "environment", "the environment id the operation acts in"),
|
|
31
|
+
projectId: required(parsed, "project", "the project id"),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
async function client(context) {
|
|
35
|
+
return authorizedClient({
|
|
36
|
+
...(context.credentialsFile === undefined
|
|
37
|
+
? {}
|
|
38
|
+
: { credentialsFile: context.credentialsFile }),
|
|
39
|
+
origin: context.origin,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
const commands = {
|
|
43
|
+
async login(context) {
|
|
44
|
+
const scopes = context.parsed.repeated.get("scope");
|
|
45
|
+
const session = await signIn({
|
|
46
|
+
...(context.credentialsFile === undefined
|
|
47
|
+
? {}
|
|
48
|
+
: { credentialsFile: context.credentialsFile }),
|
|
49
|
+
openUrl: context.openUrl,
|
|
50
|
+
origin: context.origin,
|
|
51
|
+
...(scopes && scopes.length > 0 ? { scopes } : {}),
|
|
52
|
+
});
|
|
53
|
+
const api = await client(context);
|
|
54
|
+
const account = await api.getAccount();
|
|
55
|
+
emit(context.writer, { account: account.id, origin: context.origin, scopes: session.scopes }, [
|
|
56
|
+
`Signed in to ${context.origin}.`,
|
|
57
|
+
`Account ${account.id}.`,
|
|
58
|
+
`Permissions: ${session.scopes.join(", ")}`,
|
|
59
|
+
]);
|
|
60
|
+
},
|
|
61
|
+
async logout(context) {
|
|
62
|
+
const removed = await signOut(context.origin, context.credentialsFile);
|
|
63
|
+
emit(context.writer, { origin: context.origin, signedOut: removed }, [
|
|
64
|
+
removed
|
|
65
|
+
? `Signed out of ${context.origin}.`
|
|
66
|
+
: `Not signed in to ${context.origin}.`,
|
|
67
|
+
]);
|
|
68
|
+
},
|
|
69
|
+
async whoami(context) {
|
|
70
|
+
const account = await (await client(context)).getAccount();
|
|
71
|
+
emit(context.writer, account, [
|
|
72
|
+
`Account ${account.id}`,
|
|
73
|
+
...(account.name ? [account.name] : []),
|
|
74
|
+
]);
|
|
75
|
+
},
|
|
76
|
+
async "project list"(context) {
|
|
77
|
+
const projects = await (await client(context)).listProjects();
|
|
78
|
+
emit(context.writer, projects, table([
|
|
79
|
+
["ID", "SLUG", "NAME"],
|
|
80
|
+
...projects.items.map((project) => [
|
|
81
|
+
project.id,
|
|
82
|
+
project.slug,
|
|
83
|
+
project.name,
|
|
84
|
+
]),
|
|
85
|
+
]));
|
|
86
|
+
},
|
|
87
|
+
async "project create"(context) {
|
|
88
|
+
const name = context.parsed.words[2];
|
|
89
|
+
if (!name)
|
|
90
|
+
throw new UsageError("wb project create <name> [--slug <slug>]");
|
|
91
|
+
const slug = context.parsed.options.get("slug") ??
|
|
92
|
+
name
|
|
93
|
+
.toLowerCase()
|
|
94
|
+
.replace(/[^a-z0-9]+/gu, "-")
|
|
95
|
+
.replace(/^-+|-+$/gu, "");
|
|
96
|
+
const project = await (await client(context)).createProject({ name, slug }, idempotency(context.parsed));
|
|
97
|
+
emit(context.writer, project, [
|
|
98
|
+
`Created project ${project.id} (${project.slug}).`,
|
|
99
|
+
...table([
|
|
100
|
+
["ENVIRONMENT", "KIND", "DEFAULT NOTIFIER"],
|
|
101
|
+
...project.environments.map((environment) => [
|
|
102
|
+
environment.id,
|
|
103
|
+
environment.kind,
|
|
104
|
+
environment.default_notifier.id,
|
|
105
|
+
]),
|
|
106
|
+
]),
|
|
107
|
+
]);
|
|
108
|
+
},
|
|
109
|
+
async "credential create"(context) {
|
|
110
|
+
const { environmentId, projectId } = environmentArguments(context.parsed);
|
|
111
|
+
const label = required(context.parsed, "label", "what this credential is for");
|
|
112
|
+
// The contract types the scope list as a bounded tuple, so a plain
|
|
113
|
+
// string[] cannot be passed. The values are validated by the API either
|
|
114
|
+
// way; the assertion buys the caller a shape the compiler accepts.
|
|
115
|
+
const scopes = (context.parsed.repeated.get("scope") ?? [
|
|
116
|
+
"messages:write",
|
|
117
|
+
"messages:read",
|
|
118
|
+
"subscriptions:write",
|
|
119
|
+
"subscriptions:read",
|
|
120
|
+
]);
|
|
121
|
+
const created = await (await client(context)).createApiCredential(projectId, environmentId, { label, scopes });
|
|
122
|
+
if (context.writer.json) {
|
|
123
|
+
emit(context.writer, created, []);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
emitSecret(context.writer, created.secret, "The complete secret is shown once and is not retrievable later. Store it now.");
|
|
127
|
+
},
|
|
128
|
+
async "connection list"(context) {
|
|
129
|
+
const { environmentId, projectId } = environmentArguments(context.parsed);
|
|
130
|
+
const connections = await (await client(context)).listChannelConnections(projectId, environmentId);
|
|
131
|
+
emit(context.writer, connections, table([
|
|
132
|
+
["ID", "MODE", "STATUS", "NAME"],
|
|
133
|
+
...connections.items.map((connection) => [
|
|
134
|
+
connection.id,
|
|
135
|
+
connection.mode,
|
|
136
|
+
connection.status,
|
|
137
|
+
connection.display_name,
|
|
138
|
+
]),
|
|
139
|
+
]));
|
|
140
|
+
},
|
|
141
|
+
async "connection providers"(context) {
|
|
142
|
+
const { environmentId, projectId } = environmentArguments(context.parsed);
|
|
143
|
+
const providers = await (await client(context)).listConnectionProviders(projectId, environmentId);
|
|
144
|
+
emit(context.writer, providers, table([
|
|
145
|
+
["PROVIDER", "SHARED IDENTITY", "DISPLAY NAME"],
|
|
146
|
+
...providers.items.flatMap((provider) => provider.shared_identities.map((identity) => [
|
|
147
|
+
provider.provider,
|
|
148
|
+
identity.id,
|
|
149
|
+
identity.display_name,
|
|
150
|
+
])),
|
|
151
|
+
]));
|
|
152
|
+
},
|
|
153
|
+
async "connection create"(context) {
|
|
154
|
+
const { environmentId, projectId } = environmentArguments(context.parsed);
|
|
155
|
+
const mode = required(context.parsed, "mode", "whooshbang_shared, customer_managed, or customer_byok");
|
|
156
|
+
const displayName = required(context.parsed, "name", "what to call this connection");
|
|
157
|
+
let request = {
|
|
158
|
+
display_name: displayName,
|
|
159
|
+
mode,
|
|
160
|
+
};
|
|
161
|
+
if (mode === "whooshbang_shared") {
|
|
162
|
+
request["shared_identity_id"] = required(context.parsed, "shared-identity", "which shared identity to select — see `wb connection providers`");
|
|
163
|
+
}
|
|
164
|
+
else if (mode === "customer_byok") {
|
|
165
|
+
if (!context.parsed.switches.has("credential-stdin")) {
|
|
166
|
+
throw new UsageError("customer_byok needs --credential-stdin, and the token on standard input. A bot token passed as an argument is visible to every process on the machine and lands in your shell history.");
|
|
167
|
+
}
|
|
168
|
+
request = {
|
|
169
|
+
...request,
|
|
170
|
+
confirm_webhook_takeover: true,
|
|
171
|
+
credential: (await context.readStdin()).trim(),
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
else if (mode === "customer_managed") {
|
|
175
|
+
const username = context.parsed.options.get("username");
|
|
176
|
+
if (username)
|
|
177
|
+
request["suggested_username"] = username;
|
|
178
|
+
}
|
|
179
|
+
const connection = await (await client(context)).createChannelConnection(projectId, environmentId, request, idempotency(context.parsed));
|
|
180
|
+
emit(context.writer, connection, [
|
|
181
|
+
`Created connection ${connection.id} (${connection.status}).`,
|
|
182
|
+
...(connection.setup?.handoff_url
|
|
183
|
+
? [`Finish setup in Telegram: ${connection.setup.handoff_url}`]
|
|
184
|
+
: []),
|
|
185
|
+
]);
|
|
186
|
+
},
|
|
187
|
+
async "connection route"(context) {
|
|
188
|
+
const { environmentId, projectId } = environmentArguments(context.parsed);
|
|
189
|
+
const routes = await (await client(context)).attachNotifierConnection(projectId, environmentId, {
|
|
190
|
+
connection_id: required(context.parsed, "connection", "the connection to route through"),
|
|
191
|
+
notifier_id: required(context.parsed, "notifier", "the notifier to route"),
|
|
192
|
+
});
|
|
193
|
+
emit(context.writer, routes, table([
|
|
194
|
+
["NOTIFIER", "CONNECTION", "DEFAULT"],
|
|
195
|
+
...routes.items.map((route) => [
|
|
196
|
+
route.notifier_id,
|
|
197
|
+
route.connection_id,
|
|
198
|
+
route.is_default ? "yes" : "no",
|
|
199
|
+
]),
|
|
200
|
+
]));
|
|
201
|
+
},
|
|
202
|
+
async "link create"(context) {
|
|
203
|
+
const { environmentId, projectId } = environmentArguments(context.parsed);
|
|
204
|
+
const connectionId = context.parsed.options.get("connection");
|
|
205
|
+
const link = await (await client(context)).createSubscriptionLinkInEnvironment(projectId, environmentId, {
|
|
206
|
+
channels: ["telegram"],
|
|
207
|
+
...(connectionId === undefined ? {} : { connection_id: connectionId }),
|
|
208
|
+
subscriber_id: required(context.parsed, "subscriber", "your own identifier for this subscriber"),
|
|
209
|
+
}, idempotency(context.parsed));
|
|
210
|
+
emit(context.writer, link, [
|
|
211
|
+
`Link ${link.id} (${link.status}).`,
|
|
212
|
+
// A link carries no authorization URL once it has been used, and an
|
|
213
|
+
// idempotent replay returns the used one. Printing "undefined" there
|
|
214
|
+
// would read as a defect rather than as the link having done its job.
|
|
215
|
+
...(link.authorization_url
|
|
216
|
+
? ["Send the subscriber here:", link.authorization_url]
|
|
217
|
+
: ["This link has already been used; issue another to invite again."]),
|
|
218
|
+
]);
|
|
219
|
+
},
|
|
220
|
+
async "message send"(context) {
|
|
221
|
+
const { environmentId, projectId } = environmentArguments(context.parsed);
|
|
222
|
+
const message = await (await client(context)).createMessageInEnvironment(projectId, environmentId, {
|
|
223
|
+
content: {
|
|
224
|
+
text: required(context.parsed, "text", "the message body"),
|
|
225
|
+
type: "text",
|
|
226
|
+
},
|
|
227
|
+
delivery_target: deliveryTarget(context.parsed),
|
|
228
|
+
to: {
|
|
229
|
+
subscriber_id: required(context.parsed, "subscriber", "who to send to"),
|
|
230
|
+
},
|
|
231
|
+
}, idempotency(context.parsed));
|
|
232
|
+
emit(context.writer, message, [
|
|
233
|
+
`Accepted ${message.id} (${message.state}).`,
|
|
234
|
+
`Read it with: wb message get ${message.id} --project ${projectId} --environment ${environmentId}`,
|
|
235
|
+
]);
|
|
236
|
+
},
|
|
237
|
+
async "message get"(context) {
|
|
238
|
+
const { environmentId, projectId } = environmentArguments(context.parsed);
|
|
239
|
+
const messageId = context.parsed.words[2];
|
|
240
|
+
if (!messageId)
|
|
241
|
+
throw new UsageError("wb message get <message-id>");
|
|
242
|
+
const message = await (await client(context)).getMessageInEnvironment(projectId, environmentId, messageId);
|
|
243
|
+
emit(context.writer, message, [
|
|
244
|
+
`${message.id} ${message.state}`,
|
|
245
|
+
`provider: ${message.delivery.highest_proven_provider_state}`,
|
|
246
|
+
`attempts: ${message.delivery.attempt_count}`,
|
|
247
|
+
]);
|
|
248
|
+
},
|
|
249
|
+
};
|
|
250
|
+
export function resolveCommand(words) {
|
|
251
|
+
const two = words.slice(0, 2).join(" ");
|
|
252
|
+
const one = words[0] ?? "";
|
|
253
|
+
return commands[two] ?? commands[one] ?? null;
|
|
254
|
+
}
|
|
255
|
+
export const COMMAND_NAMES = Object.keys(commands);
|
|
256
|
+
export { resolveOrigin };
|
|
257
|
+
//# sourceMappingURL=commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/cli/commands.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the CLI keeps what it learned about a deployment.
|
|
3
|
+
*
|
|
4
|
+
* One file, holding one record per origin. A developer who works against
|
|
5
|
+
* staging and production is the ordinary case, not an exotic one, and a single
|
|
6
|
+
* unkeyed token would silently send staging work to production the first time
|
|
7
|
+
* somebody changed `--api-url`.
|
|
8
|
+
*
|
|
9
|
+
* `$XDG_CONFIG_HOME` is honoured where it is set, and `~/.config/whooshbang`
|
|
10
|
+
* otherwise, which is where this project already keeps operator files.
|
|
11
|
+
*/
|
|
12
|
+
export interface StoredSession {
|
|
13
|
+
/** The client id dynamic registration returned. Reused on later logins. */
|
|
14
|
+
readonly clientId: string;
|
|
15
|
+
readonly accessToken: string;
|
|
16
|
+
readonly refreshToken?: string;
|
|
17
|
+
/** Epoch milliseconds, or absent when the server named no expiry. */
|
|
18
|
+
readonly expiresAt?: number;
|
|
19
|
+
readonly scopes: readonly string[];
|
|
20
|
+
}
|
|
21
|
+
export interface StoredCredentials {
|
|
22
|
+
readonly version: 1;
|
|
23
|
+
/** Keyed by API origin, exactly as the caller spelled it. */
|
|
24
|
+
readonly origins: Record<string, StoredSession>;
|
|
25
|
+
}
|
|
26
|
+
export declare function credentialsDirectory(environment?: NodeJS.ProcessEnv): string;
|
|
27
|
+
export declare function credentialsPath(environment?: NodeJS.ProcessEnv): string;
|
|
28
|
+
/**
|
|
29
|
+
* A missing or unreadable file is an empty store rather than an error: not
|
|
30
|
+
* being logged in is the ordinary first state, and a corrupted file should send
|
|
31
|
+
* somebody to `wb login` rather than to a stack trace.
|
|
32
|
+
*/
|
|
33
|
+
export declare function readCredentials(file?: string): Promise<StoredCredentials>;
|
|
34
|
+
/**
|
|
35
|
+
* Written owner-only, in a directory created owner-only.
|
|
36
|
+
*
|
|
37
|
+
* `writeFile`'s mode is subject to the process umask, so the permissions are
|
|
38
|
+
* set explicitly afterwards rather than hoped for. The token is a bearer
|
|
39
|
+
* credential for the whole account; a group-readable home directory is common
|
|
40
|
+
* enough that leaving this to umask is not a defensible default.
|
|
41
|
+
*/
|
|
42
|
+
export declare function writeCredentials(credentials: StoredCredentials, file?: string): Promise<void>;
|
|
43
|
+
export declare function storeSession(origin: string, session: StoredSession, file?: string): Promise<void>;
|
|
44
|
+
export declare function forgetSession(origin: string, file?: string): Promise<StoredSession | null>;
|
|
45
|
+
export declare function loadSession(origin: string, file?: string): Promise<StoredSession | null>;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { chmod, mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
const EMPTY = { origins: {}, version: 1 };
|
|
5
|
+
export function credentialsDirectory(environment = process.env) {
|
|
6
|
+
const xdg = environment.XDG_CONFIG_HOME?.trim();
|
|
7
|
+
const base = xdg && xdg.length > 0 ? xdg : path.join(os.homedir(), ".config");
|
|
8
|
+
return path.join(base, "whooshbang");
|
|
9
|
+
}
|
|
10
|
+
export function credentialsPath(environment = process.env) {
|
|
11
|
+
return path.join(credentialsDirectory(environment), "cli-credentials.json");
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* A missing or unreadable file is an empty store rather than an error: not
|
|
15
|
+
* being logged in is the ordinary first state, and a corrupted file should send
|
|
16
|
+
* somebody to `wb login` rather than to a stack trace.
|
|
17
|
+
*/
|
|
18
|
+
export async function readCredentials(file = credentialsPath()) {
|
|
19
|
+
let contents;
|
|
20
|
+
try {
|
|
21
|
+
contents = await readFile(file, "utf8");
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return EMPTY;
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
const parsed = JSON.parse(contents);
|
|
28
|
+
if (typeof parsed !== "object" ||
|
|
29
|
+
parsed === null ||
|
|
30
|
+
parsed.version !== 1 ||
|
|
31
|
+
typeof parsed.origins !== "object" ||
|
|
32
|
+
parsed.origins === null) {
|
|
33
|
+
return EMPTY;
|
|
34
|
+
}
|
|
35
|
+
return parsed;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return EMPTY;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Written owner-only, in a directory created owner-only.
|
|
43
|
+
*
|
|
44
|
+
* `writeFile`'s mode is subject to the process umask, so the permissions are
|
|
45
|
+
* set explicitly afterwards rather than hoped for. The token is a bearer
|
|
46
|
+
* credential for the whole account; a group-readable home directory is common
|
|
47
|
+
* enough that leaving this to umask is not a defensible default.
|
|
48
|
+
*/
|
|
49
|
+
export async function writeCredentials(credentials, file = credentialsPath()) {
|
|
50
|
+
await mkdir(path.dirname(file), { mode: 0o700, recursive: true });
|
|
51
|
+
await chmod(path.dirname(file), 0o700).catch(() => undefined);
|
|
52
|
+
await writeFile(file, `${JSON.stringify(credentials, null, 2)}\n`, {
|
|
53
|
+
mode: 0o600,
|
|
54
|
+
});
|
|
55
|
+
await chmod(file, 0o600);
|
|
56
|
+
}
|
|
57
|
+
export async function storeSession(origin, session, file = credentialsPath()) {
|
|
58
|
+
const current = await readCredentials(file);
|
|
59
|
+
await writeCredentials({
|
|
60
|
+
origins: { ...current.origins, [origin]: session },
|
|
61
|
+
version: 1,
|
|
62
|
+
}, file);
|
|
63
|
+
}
|
|
64
|
+
export async function forgetSession(origin, file = credentialsPath()) {
|
|
65
|
+
const current = await readCredentials(file);
|
|
66
|
+
const session = current.origins[origin] ?? null;
|
|
67
|
+
if (!session)
|
|
68
|
+
return null;
|
|
69
|
+
const origins = { ...current.origins };
|
|
70
|
+
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
|
71
|
+
delete origins[origin];
|
|
72
|
+
if (Object.keys(origins).length === 0) {
|
|
73
|
+
// Nothing left to hold: remove the file rather than leave an empty husk
|
|
74
|
+
// that reads, to anybody auditing a home directory, like a live credential.
|
|
75
|
+
await rm(file, { force: true });
|
|
76
|
+
return session;
|
|
77
|
+
}
|
|
78
|
+
await writeCredentials({ origins, version: 1 }, file);
|
|
79
|
+
return session;
|
|
80
|
+
}
|
|
81
|
+
export async function loadSession(origin, file = credentialsPath()) {
|
|
82
|
+
const current = await readCredentials(file);
|
|
83
|
+
return current.origins[origin] ?? null;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/cli/config.ts"],"names":[],"mappings":"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"}
|