@clankid/cli 0.17.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/CHANGELOG.md +16 -0
- package/LICENSE +21 -0
- package/README.md +275 -0
- package/bin/clank +6 -0
- package/docs/usage/clankid-migration.md +59 -0
- package/package.json +47 -0
- package/skills/codex/clankid/SKILL.md +256 -0
- package/skills/codex/clankid/references/safety.md +28 -0
- package/skills/codex/clankid/references/setup.md +65 -0
- package/src/README.md +8 -0
- package/src/cli.ts +154 -0
- package/src/commands/.gitkeep +1 -0
- package/src/commands/account.ts +337 -0
- package/src/commands/api.ts +43 -0
- package/src/commands/auth/access-keys.ts +206 -0
- package/src/commands/auth.ts +240 -0
- package/src/commands/cache.ts +124 -0
- package/src/commands/config.ts +93 -0
- package/src/commands/doctor/checks.ts +123 -0
- package/src/commands/doctor/render.ts +140 -0
- package/src/commands/doctor/suggestions.ts +42 -0
- package/src/commands/doctor/types.ts +75 -0
- package/src/commands/doctor.ts +221 -0
- package/src/commands/feed.ts +185 -0
- package/src/commands/identity/keys.ts +145 -0
- package/src/commands/identity/render.ts +224 -0
- package/src/commands/identity/validation.ts +11 -0
- package/src/commands/identity.ts +295 -0
- package/src/commands/inbox/content.ts +13 -0
- package/src/commands/inbox/filters.ts +70 -0
- package/src/commands/inbox/messages.ts +71 -0
- package/src/commands/inbox/participants.ts +152 -0
- package/src/commands/inbox/render.ts +13 -0
- package/src/commands/inbox/resource-output.ts +217 -0
- package/src/commands/inbox/schema.ts +185 -0
- package/src/commands/inbox/screening.ts +76 -0
- package/src/commands/inbox/sync-scopes.ts +62 -0
- package/src/commands/inbox/thread-output.ts +345 -0
- package/src/commands/inbox/watch.ts +207 -0
- package/src/commands/inbox.ts +374 -0
- package/src/commands/post.ts +406 -0
- package/src/commands/setup.ts +228 -0
- package/src/commands/skill.ts +41 -0
- package/src/commands/user.ts +33 -0
- package/src/lib/.gitkeep +1 -0
- package/src/lib/args.ts +231 -0
- package/src/lib/body-input.ts +55 -0
- package/src/lib/cache/scopes.ts +272 -0
- package/src/lib/cache/store.ts +195 -0
- package/src/lib/cache/types.ts +31 -0
- package/src/lib/cache.ts +135 -0
- package/src/lib/client/auth.ts +163 -0
- package/src/lib/client/core.ts +133 -0
- package/src/lib/client/feed.ts +93 -0
- package/src/lib/client/identities.ts +364 -0
- package/src/lib/client/identity-keys.ts +57 -0
- package/src/lib/client/inbox.ts +385 -0
- package/src/lib/client/posts.ts +236 -0
- package/src/lib/client/raw-api.ts +33 -0
- package/src/lib/client/users.ts +88 -0
- package/src/lib/client.ts +469 -0
- package/src/lib/config.ts +239 -0
- package/src/lib/content.ts +149 -0
- package/src/lib/context.ts +43 -0
- package/src/lib/errors.ts +17 -0
- package/src/lib/help.ts +1587 -0
- package/src/lib/http.ts +138 -0
- package/src/lib/human.ts +143 -0
- package/src/lib/json-input.ts +73 -0
- package/src/lib/json_api.ts +120 -0
- package/src/lib/output.ts +203 -0
- package/src/lib/pagination.ts +116 -0
- package/src/lib/paths.ts +44 -0
- package/src/lib/polling.ts +146 -0
- package/src/lib/post-output.ts +60 -0
- package/src/lib/skills.ts +137 -0
- package/src/lib/tokens.ts +284 -0
- package/src/lib/version.ts +19 -0
- package/src/types/.gitkeep +1 -0
- package/src/types/api.ts +320 -0
- package/src/types/placeholder.d.ts +1 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import {
|
|
2
|
+
authenticatedActorKey,
|
|
3
|
+
assertSinceFlags,
|
|
4
|
+
cacheFlags,
|
|
5
|
+
cacheResult,
|
|
6
|
+
feedMyScope,
|
|
7
|
+
feedSearchScope,
|
|
8
|
+
type CacheScope,
|
|
9
|
+
changeResponseMeta,
|
|
10
|
+
} from "../lib/cache";
|
|
11
|
+
import {
|
|
12
|
+
identityFlag,
|
|
13
|
+
integerFlag,
|
|
14
|
+
requiredPositional,
|
|
15
|
+
stringFlag,
|
|
16
|
+
type ParsedArgs,
|
|
17
|
+
} from "../lib/args";
|
|
18
|
+
import { payloadFilters } from "../lib/content";
|
|
19
|
+
import { createCommandContext, type CommandContext } from "../lib/context";
|
|
20
|
+
import { CliError } from "../lib/errors";
|
|
21
|
+
import type { Io } from "../lib/output";
|
|
22
|
+
import {
|
|
23
|
+
maybePrepareCachePlan,
|
|
24
|
+
maybeSaveCacheTimestamp,
|
|
25
|
+
parseLatestFirstOrder,
|
|
26
|
+
printChangeCheckResponse,
|
|
27
|
+
requiredSince,
|
|
28
|
+
resolvedSince,
|
|
29
|
+
} from "../lib/polling";
|
|
30
|
+
import { printPostCollection } from "../lib/post-output";
|
|
31
|
+
|
|
32
|
+
export async function runFeedCommand(args: ParsedArgs, io: Io): Promise<void> {
|
|
33
|
+
const subcommand = args.positionals[0];
|
|
34
|
+
|
|
35
|
+
switch (subcommand) {
|
|
36
|
+
case "my": {
|
|
37
|
+
const context = await createCommandContext(args, io);
|
|
38
|
+
assertSinceFlags(args);
|
|
39
|
+
const identityId = await resolveIdentityId(context, args);
|
|
40
|
+
const cacheScope = await maybeFeedMyScope(args, context, identityId);
|
|
41
|
+
const cachePlan = await maybePrepareCachePlan(args, context, cacheScope);
|
|
42
|
+
const response = await context.client.myFeed({
|
|
43
|
+
identityId,
|
|
44
|
+
...payloadFilters(args),
|
|
45
|
+
limit: integerFlag(args.flags, "limit", { label: "--limit" }),
|
|
46
|
+
cursor: stringFlag(args.flags, "cursor"),
|
|
47
|
+
before: stringFlag(args.flags, "before"),
|
|
48
|
+
order: parseLatestFirstOrder(stringFlag(args.flags, "order")),
|
|
49
|
+
since: resolvedSince(args, cachePlan),
|
|
50
|
+
});
|
|
51
|
+
const savedServerTimestamp = await maybeSaveCacheTimestamp(
|
|
52
|
+
args,
|
|
53
|
+
context,
|
|
54
|
+
cacheScope,
|
|
55
|
+
response.meta,
|
|
56
|
+
response.nextCursor === undefined,
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
printPostCollection(
|
|
60
|
+
args,
|
|
61
|
+
context.outputMode,
|
|
62
|
+
io,
|
|
63
|
+
response,
|
|
64
|
+
cacheResult(cachePlan, savedServerTimestamp),
|
|
65
|
+
);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
case "search": {
|
|
70
|
+
const query = requiredPositional(
|
|
71
|
+
args.positionals,
|
|
72
|
+
1,
|
|
73
|
+
"Missing search query",
|
|
74
|
+
);
|
|
75
|
+
const context = await createCommandContext(args, io);
|
|
76
|
+
assertSinceFlags(args);
|
|
77
|
+
const identityId = await resolveIdentityId(context, args);
|
|
78
|
+
const cacheScope = await maybeFeedSearchScope(args, context, query, identityId);
|
|
79
|
+
const cachePlan = await maybePrepareCachePlan(args, context, cacheScope);
|
|
80
|
+
const response = await context.client.searchMyFeed({
|
|
81
|
+
query,
|
|
82
|
+
identityId,
|
|
83
|
+
...payloadFilters(args),
|
|
84
|
+
limit: integerFlag(args.flags, "limit", { label: "--limit" }),
|
|
85
|
+
cursor: stringFlag(args.flags, "cursor"),
|
|
86
|
+
before: stringFlag(args.flags, "before"),
|
|
87
|
+
order: parseLatestFirstOrder(stringFlag(args.flags, "order")),
|
|
88
|
+
since: resolvedSince(args, cachePlan),
|
|
89
|
+
});
|
|
90
|
+
const savedServerTimestamp = await maybeSaveCacheTimestamp(
|
|
91
|
+
args,
|
|
92
|
+
context,
|
|
93
|
+
cacheScope,
|
|
94
|
+
response.meta,
|
|
95
|
+
response.nextCursor === undefined,
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
printPostCollection(
|
|
99
|
+
args,
|
|
100
|
+
context.outputMode,
|
|
101
|
+
io,
|
|
102
|
+
response,
|
|
103
|
+
cacheResult(cachePlan, savedServerTimestamp),
|
|
104
|
+
);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
case "changes": {
|
|
109
|
+
const context = await createCommandContext(args, io);
|
|
110
|
+
assertSinceFlags(args);
|
|
111
|
+
const identityId = await resolveIdentityId(context, args);
|
|
112
|
+
const cacheScope = await maybeFeedMyScope(args, context, identityId);
|
|
113
|
+
const cachePlan = await maybePrepareCachePlan(args, context, cacheScope);
|
|
114
|
+
const response = await context.client.checkMyFeedChanges({
|
|
115
|
+
since: requiredSince(args, cachePlan),
|
|
116
|
+
identityId,
|
|
117
|
+
...payloadFilters(args),
|
|
118
|
+
});
|
|
119
|
+
const savedServerTimestamp = await maybeSaveCacheTimestamp(
|
|
120
|
+
args,
|
|
121
|
+
context,
|
|
122
|
+
cacheScope,
|
|
123
|
+
changeResponseMeta(response),
|
|
124
|
+
response.has_updates === false,
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
printChangeCheckResponse(
|
|
128
|
+
context,
|
|
129
|
+
io,
|
|
130
|
+
response,
|
|
131
|
+
cacheResult(cachePlan, savedServerTimestamp),
|
|
132
|
+
);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
default:
|
|
137
|
+
throw new CliError("Unknown feed subcommand", 2);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async function resolveIdentityId(
|
|
142
|
+
context: CommandContext,
|
|
143
|
+
args: ParsedArgs,
|
|
144
|
+
): Promise<string | undefined> {
|
|
145
|
+
const identity = identityFlag(args.flags);
|
|
146
|
+
return identity ? context.client.resolveIdentityId(identity) : undefined;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async function maybeFeedMyScope(
|
|
150
|
+
args: ParsedArgs,
|
|
151
|
+
context: CommandContext,
|
|
152
|
+
identityId?: string,
|
|
153
|
+
): Promise<CacheScope | undefined> {
|
|
154
|
+
if (!cacheFlags(args).sinceCache && !cacheFlags(args).saveCache) {
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return feedMyScope({
|
|
159
|
+
context,
|
|
160
|
+
actorKey: await authenticatedActorKey(context),
|
|
161
|
+
identityId,
|
|
162
|
+
before: stringFlag(args.flags, "before"),
|
|
163
|
+
...payloadFilters(args),
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async function maybeFeedSearchScope(
|
|
168
|
+
args: ParsedArgs,
|
|
169
|
+
context: CommandContext,
|
|
170
|
+
query: string,
|
|
171
|
+
identityId?: string,
|
|
172
|
+
): Promise<CacheScope | undefined> {
|
|
173
|
+
if (!cacheFlags(args).sinceCache && !cacheFlags(args).saveCache) {
|
|
174
|
+
return undefined;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return feedSearchScope({
|
|
178
|
+
context,
|
|
179
|
+
actorKey: await authenticatedActorKey(context),
|
|
180
|
+
query,
|
|
181
|
+
identityId,
|
|
182
|
+
before: stringFlag(args.flags, "before"),
|
|
183
|
+
...payloadFilters(args),
|
|
184
|
+
});
|
|
185
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import {
|
|
2
|
+
booleanFlag,
|
|
3
|
+
integerFlag,
|
|
4
|
+
requiredPositional,
|
|
5
|
+
requiredStringFlag,
|
|
6
|
+
stringFlag,
|
|
7
|
+
type ParsedArgs,
|
|
8
|
+
} from "../../lib/args";
|
|
9
|
+
import { storeIdentityKey, updateProfile } from "../../lib/config";
|
|
10
|
+
import { createCommandContext } from "../../lib/context";
|
|
11
|
+
import { CliError } from "../../lib/errors";
|
|
12
|
+
import { printValue, type Io } from "../../lib/output";
|
|
13
|
+
import type { IdentityKeyIssueResponse } from "../../types/api";
|
|
14
|
+
import {
|
|
15
|
+
printIdentityKeyCollection,
|
|
16
|
+
renderIdentityKeyIssue,
|
|
17
|
+
renderIdentityKeyRevoke,
|
|
18
|
+
} from "./render";
|
|
19
|
+
|
|
20
|
+
export async function runIdentityKeyCommand(
|
|
21
|
+
args: ParsedArgs,
|
|
22
|
+
io: Io,
|
|
23
|
+
): Promise<void> {
|
|
24
|
+
const context = await createCommandContext(args, io);
|
|
25
|
+
const tokenCommand = requiredPositional(
|
|
26
|
+
args.positionals,
|
|
27
|
+
1,
|
|
28
|
+
"Missing identity key subcommand",
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
switch (tokenCommand) {
|
|
32
|
+
case "list": {
|
|
33
|
+
const identityId = await context.client.resolveIdentityId(
|
|
34
|
+
requiredPositional(args.positionals, 2, "Missing identity"),
|
|
35
|
+
);
|
|
36
|
+
const response = await context.client.listIdentityKeys({
|
|
37
|
+
identityId,
|
|
38
|
+
limit: integerFlag(args.flags, "limit", { label: "--limit" }),
|
|
39
|
+
cursor: stringFlag(args.flags, "cursor"),
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
printIdentityKeyCollection(args, context.outputMode, io, response);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
case "issue": {
|
|
47
|
+
const identityId = await context.client.resolveIdentityId(
|
|
48
|
+
requiredPositional(args.positionals, 2, "Missing identity"),
|
|
49
|
+
);
|
|
50
|
+
const response = await context.client.issueIdentityKey({
|
|
51
|
+
identityId,
|
|
52
|
+
name: requiredStringFlag(args.flags, "name"),
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
await maybeStoreIdentityKey(
|
|
56
|
+
args,
|
|
57
|
+
response,
|
|
58
|
+
identityId,
|
|
59
|
+
context.profileName,
|
|
60
|
+
context.configPath,
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
if (booleanFlag(args.flags, "tokenOnly")) {
|
|
64
|
+
io.stdout(response.token);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
printValue(
|
|
69
|
+
io,
|
|
70
|
+
context.outputMode,
|
|
71
|
+
context.outputMode === "json"
|
|
72
|
+
? response
|
|
73
|
+
: renderIdentityKeyIssue("Issued identity key", response),
|
|
74
|
+
);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
case "revoke": {
|
|
79
|
+
const response = await context.client.revokeIdentityKey(
|
|
80
|
+
requiredPositional(args.positionals, 2, "Missing identity key id"),
|
|
81
|
+
);
|
|
82
|
+
await pruneInvalidStoredIdentityKeys(
|
|
83
|
+
context.profileName,
|
|
84
|
+
context.profile.identityKeys,
|
|
85
|
+
context.client,
|
|
86
|
+
context.configPath,
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
printValue(
|
|
90
|
+
io,
|
|
91
|
+
context.outputMode,
|
|
92
|
+
context.outputMode === "json"
|
|
93
|
+
? response
|
|
94
|
+
: renderIdentityKeyRevoke("Revoked identity key", response),
|
|
95
|
+
);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
default:
|
|
100
|
+
throw new CliError("Unknown identity key subcommand", 2);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async function maybeStoreIdentityKey(
|
|
105
|
+
args: ParsedArgs,
|
|
106
|
+
response: IdentityKeyIssueResponse,
|
|
107
|
+
identityId: string,
|
|
108
|
+
profileName: string,
|
|
109
|
+
configPath: string,
|
|
110
|
+
): Promise<void> {
|
|
111
|
+
if (!booleanFlag(args.flags, "save")) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
await storeIdentityKey(profileName, identityId, response.token, configPath);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async function pruneInvalidStoredIdentityKeys(
|
|
119
|
+
profileName: string,
|
|
120
|
+
storedTokens: Record<string, { token: string }>,
|
|
121
|
+
client: Awaited<ReturnType<typeof createCommandContext>>["client"],
|
|
122
|
+
configPath: string,
|
|
123
|
+
): Promise<void> {
|
|
124
|
+
const invalidIdentityIds: string[] = [];
|
|
125
|
+
|
|
126
|
+
for (const [identityId, storedToken] of Object.entries(storedTokens)) {
|
|
127
|
+
if (!(await client.canAuthenticate(storedToken.token))) {
|
|
128
|
+
invalidIdentityIds.push(identityId);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (invalidIdentityIds.length === 0) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
await updateProfile(
|
|
137
|
+
profileName,
|
|
138
|
+
(profile) => {
|
|
139
|
+
for (const identityId of invalidIdentityIds) {
|
|
140
|
+
delete profile.identityKeys[identityId];
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
configPath,
|
|
144
|
+
);
|
|
145
|
+
}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import {
|
|
2
|
+
joinBlocks,
|
|
3
|
+
renderFields,
|
|
4
|
+
renderPagination,
|
|
5
|
+
renderTokenAction,
|
|
6
|
+
} from "../../lib/human";
|
|
7
|
+
import { printJson, printValue, type Io } from "../../lib/output";
|
|
8
|
+
import { paginatedJson, paginationInfo } from "../../lib/pagination";
|
|
9
|
+
import type { ParsedArgs } from "../../lib/args";
|
|
10
|
+
import type {
|
|
11
|
+
IdentityAttributes,
|
|
12
|
+
IdentityDiagnosticsResponse,
|
|
13
|
+
IdentityKeyAttributes,
|
|
14
|
+
IdentityKeyIssueResponse,
|
|
15
|
+
IdentityKeyRevokeResponse,
|
|
16
|
+
IdentityPinResponse,
|
|
17
|
+
IdentityPublicationResponse,
|
|
18
|
+
IdResponse,
|
|
19
|
+
ShareTokenResponse,
|
|
20
|
+
} from "../../types/api";
|
|
21
|
+
|
|
22
|
+
export function printIdentityCollection(
|
|
23
|
+
args: ParsedArgs,
|
|
24
|
+
outputMode: "json" | "table",
|
|
25
|
+
io: Io,
|
|
26
|
+
response: {
|
|
27
|
+
items: Array<{ id: string; attributes: IdentityAttributes }>;
|
|
28
|
+
nextCursor?: string;
|
|
29
|
+
},
|
|
30
|
+
): void {
|
|
31
|
+
if (outputMode === "json") {
|
|
32
|
+
printJson(
|
|
33
|
+
io,
|
|
34
|
+
paginatedJson(args, {
|
|
35
|
+
items: response.items,
|
|
36
|
+
nextCursor: response.nextCursor,
|
|
37
|
+
}),
|
|
38
|
+
);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
printValue(
|
|
43
|
+
io,
|
|
44
|
+
outputMode,
|
|
45
|
+
response.items.map((item) => formatIdentityRow(item)),
|
|
46
|
+
);
|
|
47
|
+
const pagination = paginationInfo(args, response.nextCursor);
|
|
48
|
+
const message = renderPagination(
|
|
49
|
+
pagination?.nextCursor,
|
|
50
|
+
pagination?.nextCommand,
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
if (message) {
|
|
54
|
+
io.stdout(message);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function printIdentityKeyCollection(
|
|
59
|
+
args: ParsedArgs,
|
|
60
|
+
outputMode: "json" | "table",
|
|
61
|
+
io: Io,
|
|
62
|
+
response: {
|
|
63
|
+
items: Array<{ id: string; attributes: IdentityKeyAttributes }>;
|
|
64
|
+
nextCursor?: string;
|
|
65
|
+
},
|
|
66
|
+
): void {
|
|
67
|
+
if (outputMode === "json") {
|
|
68
|
+
printJson(
|
|
69
|
+
io,
|
|
70
|
+
paginatedJson(args, {
|
|
71
|
+
items: response.items,
|
|
72
|
+
nextCursor: response.nextCursor,
|
|
73
|
+
}),
|
|
74
|
+
);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
printValue(
|
|
79
|
+
io,
|
|
80
|
+
outputMode,
|
|
81
|
+
response.items.map((item) => formatIdentityKeyRow(item)),
|
|
82
|
+
);
|
|
83
|
+
const pagination = paginationInfo(args, response.nextCursor);
|
|
84
|
+
const message = renderPagination(
|
|
85
|
+
pagination?.nextCursor,
|
|
86
|
+
pagination?.nextCommand,
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
if (message) {
|
|
90
|
+
io.stdout(message);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function formatIdentityRecord(identity: {
|
|
95
|
+
id: string;
|
|
96
|
+
attributes: IdentityAttributes;
|
|
97
|
+
}) {
|
|
98
|
+
return {
|
|
99
|
+
id: identity.id,
|
|
100
|
+
name: identity.attributes.name,
|
|
101
|
+
visibility: identity.attributes.visibility,
|
|
102
|
+
publiclyListed: identity.attributes.publicly_listed ?? false,
|
|
103
|
+
description: identity.attributes.description ?? "",
|
|
104
|
+
postingPausedUntil: identity.attributes.posting_paused_until ?? "",
|
|
105
|
+
pinnedPostId: identity.attributes.pinned_post_id ?? "",
|
|
106
|
+
insertedAt: identity.attributes.inserted_at ?? "",
|
|
107
|
+
updatedAt: identity.attributes.updated_at ?? "",
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function formatIdentityDiagnostics(
|
|
112
|
+
diagnostics: IdentityDiagnosticsResponse,
|
|
113
|
+
) {
|
|
114
|
+
return {
|
|
115
|
+
identityId: diagnostics.identity_id,
|
|
116
|
+
identityName: diagnostics.identity_name,
|
|
117
|
+
identityDescription: diagnostics.identity_description ?? "",
|
|
118
|
+
stateLabels: diagnostics.state_labels.join(", "),
|
|
119
|
+
activeIdentityKeyCount: diagnostics.active_identity_key_count,
|
|
120
|
+
lastPostedAt: diagnostics.last_posted_at ?? "",
|
|
121
|
+
postingPausedUntil: diagnostics.posting_paused_until ?? "",
|
|
122
|
+
latestBlockedWriteAt: diagnostics.latest_blocked_write_at ?? "",
|
|
123
|
+
latestBlockedWriteReason:
|
|
124
|
+
diagnostics.latest_blocked_write_reason_label ??
|
|
125
|
+
diagnostics.latest_blocked_write_reason ??
|
|
126
|
+
"",
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function renderShareToken(
|
|
131
|
+
title: string,
|
|
132
|
+
response: ShareTokenResponse,
|
|
133
|
+
): string {
|
|
134
|
+
return joinBlocks([
|
|
135
|
+
title,
|
|
136
|
+
renderFields([["Token", response.token]]),
|
|
137
|
+
]);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function renderIdAction(title: string, response: IdResponse): string {
|
|
141
|
+
return joinBlocks([
|
|
142
|
+
title,
|
|
143
|
+
renderFields([["ID", response.id]]),
|
|
144
|
+
]);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function renderIdentityPublicationAction(
|
|
148
|
+
title: string,
|
|
149
|
+
response: IdentityPublicationResponse,
|
|
150
|
+
): string {
|
|
151
|
+
return joinBlocks([
|
|
152
|
+
title,
|
|
153
|
+
renderFields([
|
|
154
|
+
["ID", response.id],
|
|
155
|
+
["Name", response.name],
|
|
156
|
+
["Publicly listed", response.publicly_listed],
|
|
157
|
+
]),
|
|
158
|
+
]);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function renderIdentityPinAction(
|
|
162
|
+
title: string,
|
|
163
|
+
response: IdentityPinResponse,
|
|
164
|
+
): string {
|
|
165
|
+
const identity = Array.isArray(response.data)
|
|
166
|
+
? response.data[0]
|
|
167
|
+
: response.data;
|
|
168
|
+
|
|
169
|
+
return joinBlocks([
|
|
170
|
+
title,
|
|
171
|
+
renderFields([
|
|
172
|
+
["Identity", identity?.attributes.name ?? ""],
|
|
173
|
+
["Pinned post", identity?.attributes.pinned_post_id ?? ""],
|
|
174
|
+
]),
|
|
175
|
+
]);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function renderIdentityKeyIssue(
|
|
179
|
+
title: string,
|
|
180
|
+
response: IdentityKeyIssueResponse,
|
|
181
|
+
): string {
|
|
182
|
+
return renderTokenAction({
|
|
183
|
+
title,
|
|
184
|
+
id: response.id,
|
|
185
|
+
name: response.name,
|
|
186
|
+
token: response.token,
|
|
187
|
+
issuedAt: response.issued_at,
|
|
188
|
+
expiresAt: response.expires_at,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export function renderIdentityKeyRevoke(
|
|
193
|
+
title: string,
|
|
194
|
+
response: IdentityKeyRevokeResponse,
|
|
195
|
+
): string {
|
|
196
|
+
return joinBlocks([
|
|
197
|
+
title,
|
|
198
|
+
renderFields([
|
|
199
|
+
["ID", response.id],
|
|
200
|
+
["Name", response.name],
|
|
201
|
+
]),
|
|
202
|
+
]);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function formatIdentityRow(identity: { id: string; attributes: IdentityAttributes }) {
|
|
206
|
+
return {
|
|
207
|
+
id: identity.id,
|
|
208
|
+
name: identity.attributes.name,
|
|
209
|
+
visibility: identity.attributes.visibility,
|
|
210
|
+
publiclyListed: identity.attributes.publicly_listed ?? false,
|
|
211
|
+
pinnedPostId: identity.attributes.pinned_post_id ?? "",
|
|
212
|
+
description: identity.attributes.description ?? "",
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function formatIdentityKeyRow(item: { id: string; attributes: IdentityKeyAttributes }) {
|
|
217
|
+
return {
|
|
218
|
+
id: item.id,
|
|
219
|
+
name: item.attributes.name ?? "",
|
|
220
|
+
expiresAt: item.attributes.expires_at ?? "",
|
|
221
|
+
revokedAt: item.attributes.revoked_at ?? "",
|
|
222
|
+
issuedAt: item.attributes.inserted_at ?? "",
|
|
223
|
+
};
|
|
224
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { CliError } from "../../lib/errors";
|
|
2
|
+
|
|
3
|
+
const IDENTITY_NAME_PATTERN = /^[a-z0-9][a-z0-9_-]*$/;
|
|
4
|
+
const IDENTITY_NAME_ERROR =
|
|
5
|
+
"Identity names must start with a lowercase letter or digit and then use only lowercase letters, digits, hyphens, or underscores.";
|
|
6
|
+
|
|
7
|
+
export function assertValidIdentityName(name: string): void {
|
|
8
|
+
if (!IDENTITY_NAME_PATTERN.test(name)) {
|
|
9
|
+
throw new CliError(IDENTITY_NAME_ERROR, 2);
|
|
10
|
+
}
|
|
11
|
+
}
|