@clankmates/cli 0.11.0 → 0.11.1
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 +11 -1
- package/package.json +1 -1
- package/src/cli.ts +2 -0
- package/src/commands/cache.ts +124 -0
- package/src/commands/feed.ts +188 -11
- package/src/commands/inbox.ts +246 -16
- package/src/commands/post.ts +182 -20
- package/src/lib/args.ts +4 -0
- package/src/lib/cache.ts +499 -0
- package/src/lib/help.ts +78 -10
- package/src/lib/pagination.ts +11 -0
- package/src/lib/paths.ts +26 -0
package/src/commands/inbox.ts
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
assertSinceFlags,
|
|
3
|
+
authenticatedActorKey,
|
|
4
|
+
cacheFlags,
|
|
5
|
+
cacheResult,
|
|
6
|
+
changeResponseMeta,
|
|
7
|
+
inboxMessagesScope,
|
|
8
|
+
inboxThreadsScope,
|
|
9
|
+
prepareCachePlan,
|
|
10
|
+
saveCacheTimestamp,
|
|
11
|
+
type CachePlan,
|
|
12
|
+
type CacheResult,
|
|
13
|
+
type CacheScope,
|
|
14
|
+
} from "../lib/cache";
|
|
1
15
|
import {
|
|
2
16
|
booleanFlag,
|
|
3
17
|
integerFlag,
|
|
@@ -42,32 +56,73 @@ export async function runInboxCommand(args: ParsedArgs, io: Io): Promise<void> {
|
|
|
42
56
|
switch (subcommand) {
|
|
43
57
|
case "list": {
|
|
44
58
|
const channelToken = stringFlag(args.flags, "channelToken");
|
|
59
|
+
assertSinceFlags(args);
|
|
60
|
+
const status = parseStatusFilter(stringFlag(args.flags, "status"));
|
|
61
|
+
const mailbox = parseMailboxFilter(stringFlag(args.flags, "mailbox"));
|
|
62
|
+
const cacheScope = await maybeInboxThreadsScope(
|
|
63
|
+
args,
|
|
64
|
+
context,
|
|
65
|
+
channelToken,
|
|
66
|
+
status,
|
|
67
|
+
mailbox,
|
|
68
|
+
);
|
|
69
|
+
const cachePlan = await maybePrepareCachePlan(args, context, cacheScope);
|
|
45
70
|
const response = await context.client.listInboxThreads({
|
|
46
|
-
status
|
|
47
|
-
mailbox
|
|
71
|
+
status,
|
|
72
|
+
mailbox,
|
|
48
73
|
limit: integerFlag(args.flags, "limit", { label: "--limit" }),
|
|
49
74
|
cursor: stringFlag(args.flags, "cursor"),
|
|
50
75
|
order: parseLatestFirstOrder(stringFlag(args.flags, "order")),
|
|
51
|
-
since:
|
|
76
|
+
since: resolvedSince(args, cachePlan),
|
|
52
77
|
channelToken,
|
|
53
78
|
});
|
|
79
|
+
const savedServerTimestamp = await maybeSaveCacheTimestamp(
|
|
80
|
+
args,
|
|
81
|
+
context,
|
|
82
|
+
cacheScope,
|
|
83
|
+
response.meta,
|
|
84
|
+
response.nextCursor === undefined,
|
|
85
|
+
);
|
|
54
86
|
|
|
55
|
-
await printThreadCollection(
|
|
87
|
+
await printThreadCollection(
|
|
88
|
+
args,
|
|
89
|
+
context,
|
|
90
|
+
io,
|
|
91
|
+
response,
|
|
92
|
+
channelToken,
|
|
93
|
+
cacheResult(cachePlan, savedServerTimestamp),
|
|
94
|
+
);
|
|
56
95
|
return;
|
|
57
96
|
}
|
|
58
97
|
|
|
59
98
|
case "show": {
|
|
60
99
|
const threadId = requiredPositional(args.positionals, 1, "Missing thread id");
|
|
61
100
|
const channelToken = stringFlag(args.flags, "channelToken");
|
|
101
|
+
assertSinceFlags(args);
|
|
102
|
+
const cacheScope = await maybeInboxMessagesScope(
|
|
103
|
+
args,
|
|
104
|
+
context,
|
|
105
|
+
channelToken,
|
|
106
|
+
threadId,
|
|
107
|
+
);
|
|
108
|
+
const cachePlan = await maybePrepareCachePlan(args, context, cacheScope);
|
|
62
109
|
const thread = await context.client.getThread(threadId, channelToken);
|
|
63
110
|
const messages = await context.client.listMessagesForThread({
|
|
64
111
|
threadId,
|
|
65
112
|
limit: integerFlag(args.flags, "limit", { label: "--limit" }),
|
|
66
113
|
cursor: stringFlag(args.flags, "cursor"),
|
|
67
114
|
order: parseLatestFirstOrder(stringFlag(args.flags, "order")),
|
|
68
|
-
since:
|
|
115
|
+
since: resolvedSince(args, cachePlan),
|
|
69
116
|
channelToken,
|
|
70
117
|
});
|
|
118
|
+
const savedServerTimestamp = await maybeSaveCacheTimestamp(
|
|
119
|
+
args,
|
|
120
|
+
context,
|
|
121
|
+
cacheScope,
|
|
122
|
+
messages.meta,
|
|
123
|
+
messages.nextCursor === undefined,
|
|
124
|
+
);
|
|
125
|
+
const cache = cacheResult(cachePlan, savedServerTimestamp);
|
|
71
126
|
const ownerIds = ownerIdsForThreadDisplay(thread, messages.items);
|
|
72
127
|
const publicUsers =
|
|
73
128
|
context.outputMode === "json" || ownerIds.length === 0
|
|
@@ -85,22 +140,46 @@ export async function runInboxCommand(args: ParsedArgs, io: Io): Promise<void> {
|
|
|
85
140
|
messages: messages.items,
|
|
86
141
|
nextCursor: messages.nextCursor,
|
|
87
142
|
meta: messages.meta,
|
|
143
|
+
...(cache ? { cache } : {}),
|
|
88
144
|
})
|
|
89
|
-
: renderThreadWithMessages(args, thread, messages, publicUsers),
|
|
145
|
+
: renderThreadWithMessages(args, thread, messages, publicUsers, cache),
|
|
90
146
|
);
|
|
91
147
|
return;
|
|
92
148
|
}
|
|
93
149
|
|
|
94
150
|
case "changes": {
|
|
95
151
|
const channelToken = stringFlag(args.flags, "channelToken");
|
|
152
|
+
assertSinceFlags(args);
|
|
153
|
+
const status = parseStatusFilter(stringFlag(args.flags, "status"));
|
|
154
|
+
const mailbox = parseMailboxFilter(stringFlag(args.flags, "mailbox"));
|
|
155
|
+
const cacheScope = await maybeInboxThreadsScope(
|
|
156
|
+
args,
|
|
157
|
+
context,
|
|
158
|
+
channelToken,
|
|
159
|
+
status,
|
|
160
|
+
mailbox,
|
|
161
|
+
);
|
|
162
|
+
const cachePlan = await maybePrepareCachePlan(args, context, cacheScope);
|
|
96
163
|
const response = await context.client.checkInboxThreadChanges({
|
|
97
|
-
since: requiredSince(args),
|
|
98
|
-
status
|
|
99
|
-
mailbox
|
|
164
|
+
since: requiredSince(args, cachePlan, "inbox thread"),
|
|
165
|
+
status,
|
|
166
|
+
mailbox,
|
|
100
167
|
channelToken,
|
|
101
168
|
});
|
|
169
|
+
const savedServerTimestamp = await maybeSaveCacheTimestamp(
|
|
170
|
+
args,
|
|
171
|
+
context,
|
|
172
|
+
cacheScope,
|
|
173
|
+
changeResponseMeta(response),
|
|
174
|
+
response.has_updates === false,
|
|
175
|
+
);
|
|
102
176
|
|
|
103
|
-
printChangeCheckResponse(
|
|
177
|
+
printChangeCheckResponse(
|
|
178
|
+
context,
|
|
179
|
+
io,
|
|
180
|
+
response,
|
|
181
|
+
cacheResult(cachePlan, savedServerTimestamp),
|
|
182
|
+
);
|
|
104
183
|
return;
|
|
105
184
|
}
|
|
106
185
|
|
|
@@ -638,9 +717,28 @@ function parseLatestFirstOrder(value: string | undefined): LatestFirstOrder | un
|
|
|
638
717
|
throw new CliError("--order must be one of: latest, oldest", 2);
|
|
639
718
|
}
|
|
640
719
|
|
|
641
|
-
function requiredSince(
|
|
720
|
+
function requiredSince(
|
|
721
|
+
args: ParsedArgs,
|
|
722
|
+
cachePlan?: CachePlan,
|
|
723
|
+
label = "resource",
|
|
724
|
+
): string {
|
|
642
725
|
const since = stringFlag(args.flags, "since");
|
|
643
726
|
|
|
727
|
+
if (since) {
|
|
728
|
+
return since;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
if (cachePlan?.previousServerTimestamp) {
|
|
732
|
+
return cachePlan.previousServerTimestamp;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
if (cacheFlags(args).sinceCache) {
|
|
736
|
+
throw new CliError(
|
|
737
|
+
`No cached server timestamp for this ${label} scope. Run a read command with \`--save-cache\` first.`,
|
|
738
|
+
2,
|
|
739
|
+
);
|
|
740
|
+
}
|
|
741
|
+
|
|
644
742
|
if (!since) {
|
|
645
743
|
throw new CliError("Missing `--since`", 2);
|
|
646
744
|
}
|
|
@@ -657,13 +755,35 @@ async function runInboxMessagesCommand(
|
|
|
657
755
|
|
|
658
756
|
switch (subcommand) {
|
|
659
757
|
case "changes": {
|
|
758
|
+
assertSinceFlags(args);
|
|
759
|
+
const threadId = requiredPositional(args.positionals, 2, "Missing thread id");
|
|
760
|
+
const channelToken = stringFlag(args.flags, "channelToken");
|
|
761
|
+
const cacheScope = await maybeInboxMessagesScope(
|
|
762
|
+
args,
|
|
763
|
+
context,
|
|
764
|
+
channelToken,
|
|
765
|
+
threadId,
|
|
766
|
+
);
|
|
767
|
+
const cachePlan = await maybePrepareCachePlan(args, context, cacheScope);
|
|
660
768
|
const response = await context.client.checkThreadMessageChanges({
|
|
661
|
-
threadId
|
|
662
|
-
since: requiredSince(args),
|
|
663
|
-
channelToken
|
|
769
|
+
threadId,
|
|
770
|
+
since: requiredSince(args, cachePlan, "inbox message"),
|
|
771
|
+
channelToken,
|
|
664
772
|
});
|
|
773
|
+
const savedServerTimestamp = await maybeSaveCacheTimestamp(
|
|
774
|
+
args,
|
|
775
|
+
context,
|
|
776
|
+
cacheScope,
|
|
777
|
+
changeResponseMeta(response),
|
|
778
|
+
response.has_updates === false,
|
|
779
|
+
);
|
|
665
780
|
|
|
666
|
-
printChangeCheckResponse(
|
|
781
|
+
printChangeCheckResponse(
|
|
782
|
+
context,
|
|
783
|
+
io,
|
|
784
|
+
response,
|
|
785
|
+
cacheResult(cachePlan, savedServerTimestamp),
|
|
786
|
+
);
|
|
667
787
|
return;
|
|
668
788
|
}
|
|
669
789
|
|
|
@@ -676,12 +796,13 @@ function printChangeCheckResponse(
|
|
|
676
796
|
context: CommandContext,
|
|
677
797
|
io: Io,
|
|
678
798
|
response: ChangeCheckResponse,
|
|
799
|
+
cache?: CacheResult,
|
|
679
800
|
): void {
|
|
680
801
|
printValue(
|
|
681
802
|
io,
|
|
682
803
|
context.outputMode,
|
|
683
804
|
context.outputMode === "json"
|
|
684
|
-
? response
|
|
805
|
+
? { ...response, ...(cache ? { cache } : {}) }
|
|
685
806
|
: renderFields([
|
|
686
807
|
["Has updates", response.has_updates ? "yes" : "no"],
|
|
687
808
|
["Server time", formatTimestamp(response.server_time)],
|
|
@@ -691,6 +812,7 @@ function printChangeCheckResponse(
|
|
|
691
812
|
? undefined
|
|
692
813
|
: `${response.recommended_poll_after_ms}ms`,
|
|
693
814
|
],
|
|
815
|
+
...cacheFields(cache),
|
|
694
816
|
]),
|
|
695
817
|
);
|
|
696
818
|
}
|
|
@@ -803,6 +925,7 @@ async function printThreadCollection(
|
|
|
803
925
|
meta?: Record<string, unknown>;
|
|
804
926
|
},
|
|
805
927
|
channelToken?: string,
|
|
928
|
+
cache?: CacheResult,
|
|
806
929
|
): Promise<void> {
|
|
807
930
|
if (context.outputMode === "json") {
|
|
808
931
|
printJson(
|
|
@@ -811,6 +934,7 @@ async function printThreadCollection(
|
|
|
811
934
|
items: response.items,
|
|
812
935
|
nextCursor: response.nextCursor,
|
|
813
936
|
meta: response.meta,
|
|
937
|
+
...(cache ? { cache } : {}),
|
|
814
938
|
}),
|
|
815
939
|
);
|
|
816
940
|
return Promise.resolve();
|
|
@@ -848,6 +972,8 @@ async function printThreadCollection(
|
|
|
848
972
|
if (message) {
|
|
849
973
|
io.stdout(message);
|
|
850
974
|
}
|
|
975
|
+
|
|
976
|
+
printCacheNote(io, cache);
|
|
851
977
|
}
|
|
852
978
|
|
|
853
979
|
function renderThreadWithMessages(
|
|
@@ -858,6 +984,7 @@ function renderThreadWithMessages(
|
|
|
858
984
|
nextCursor?: string;
|
|
859
985
|
},
|
|
860
986
|
publicUsers: Map<string, string>,
|
|
987
|
+
cache?: CacheResult,
|
|
861
988
|
): string {
|
|
862
989
|
const attrs = thread.attributes;
|
|
863
990
|
const messageBlocks =
|
|
@@ -929,6 +1056,7 @@ function renderThreadWithMessages(
|
|
|
929
1056
|
),
|
|
930
1057
|
renderSection("Messages", messageBlocks),
|
|
931
1058
|
renderPagination(pagination?.nextCursor, pagination?.nextCommand),
|
|
1059
|
+
renderCacheNote(cache),
|
|
932
1060
|
]);
|
|
933
1061
|
}
|
|
934
1062
|
|
|
@@ -982,6 +1110,108 @@ function printSchemaResource(
|
|
|
982
1110
|
);
|
|
983
1111
|
}
|
|
984
1112
|
|
|
1113
|
+
async function maybePrepareCachePlan(
|
|
1114
|
+
args: ParsedArgs,
|
|
1115
|
+
context: CommandContext,
|
|
1116
|
+
scope: CacheScope | undefined,
|
|
1117
|
+
): Promise<CachePlan | undefined> {
|
|
1118
|
+
return cacheFlags(args).sinceCache && scope
|
|
1119
|
+
? prepareCachePlan(context, scope)
|
|
1120
|
+
: undefined;
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
async function maybeSaveCacheTimestamp(
|
|
1124
|
+
args: ParsedArgs,
|
|
1125
|
+
context: CommandContext,
|
|
1126
|
+
scope: CacheScope | undefined,
|
|
1127
|
+
meta: Record<string, unknown> | undefined,
|
|
1128
|
+
shouldSave: boolean,
|
|
1129
|
+
): Promise<string | undefined> {
|
|
1130
|
+
return cacheFlags(args).saveCache && scope && shouldSave
|
|
1131
|
+
? saveCacheTimestamp(context, scope, meta)
|
|
1132
|
+
: undefined;
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
async function maybeInboxThreadsScope(
|
|
1136
|
+
args: ParsedArgs,
|
|
1137
|
+
context: CommandContext,
|
|
1138
|
+
channelToken: string | undefined,
|
|
1139
|
+
status: ThreadStatusFilter | undefined,
|
|
1140
|
+
mailbox: MailboxFilter | undefined,
|
|
1141
|
+
): Promise<CacheScope | undefined> {
|
|
1142
|
+
if (!cacheFlags(args).sinceCache && !cacheFlags(args).saveCache) {
|
|
1143
|
+
return undefined;
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
return inboxThreadsScope({
|
|
1147
|
+
context,
|
|
1148
|
+
actorKey: await authenticatedActorKey(context, channelToken),
|
|
1149
|
+
status,
|
|
1150
|
+
mailbox,
|
|
1151
|
+
});
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
async function maybeInboxMessagesScope(
|
|
1155
|
+
args: ParsedArgs,
|
|
1156
|
+
context: CommandContext,
|
|
1157
|
+
channelToken: string | undefined,
|
|
1158
|
+
threadId: string,
|
|
1159
|
+
): Promise<CacheScope | undefined> {
|
|
1160
|
+
if (!cacheFlags(args).sinceCache && !cacheFlags(args).saveCache) {
|
|
1161
|
+
return undefined;
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
return inboxMessagesScope({
|
|
1165
|
+
context,
|
|
1166
|
+
actorKey: await authenticatedActorKey(context, channelToken),
|
|
1167
|
+
threadId,
|
|
1168
|
+
});
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
function resolvedSince(
|
|
1172
|
+
args: ParsedArgs,
|
|
1173
|
+
cachePlan: CachePlan | undefined,
|
|
1174
|
+
): string | undefined {
|
|
1175
|
+
return stringFlag(args.flags, "since") ?? cachePlan?.previousServerTimestamp;
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
function printCacheNote(io: Io, cache: CacheResult | undefined): void {
|
|
1179
|
+
const note = renderCacheNote(cache);
|
|
1180
|
+
|
|
1181
|
+
if (note) {
|
|
1182
|
+
io.stdout(note);
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
function renderCacheNote(cache: CacheResult | undefined): string | undefined {
|
|
1187
|
+
if (!cache) {
|
|
1188
|
+
return undefined;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
const details = [
|
|
1192
|
+
cache.previousServerTimestamp
|
|
1193
|
+
? `used ${cache.previousServerTimestamp}`
|
|
1194
|
+
: cache.hit
|
|
1195
|
+
? "used cache"
|
|
1196
|
+
: "no cached timestamp",
|
|
1197
|
+
cache.savedServerTimestamp ? `saved ${cache.savedServerTimestamp}` : undefined,
|
|
1198
|
+
].filter(Boolean);
|
|
1199
|
+
|
|
1200
|
+
return `Cache: ${details.join("; ")}.`;
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
function cacheFields(cache: CacheResult | undefined): Array<[string, string | undefined]> {
|
|
1204
|
+
if (!cache) {
|
|
1205
|
+
return [];
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
return [
|
|
1209
|
+
["Cache scope", cache.scopeKey],
|
|
1210
|
+
["Cached timestamp", cache.previousServerTimestamp],
|
|
1211
|
+
["Saved timestamp", cache.savedServerTimestamp],
|
|
1212
|
+
];
|
|
1213
|
+
}
|
|
1214
|
+
|
|
985
1215
|
function renderSchemaResource(
|
|
986
1216
|
resource: {
|
|
987
1217
|
id: string;
|
package/src/commands/post.ts
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
assertSinceFlags,
|
|
3
|
+
authenticatedActorKey,
|
|
4
|
+
cacheFlags,
|
|
5
|
+
cacheResult,
|
|
6
|
+
ownedPostsScope,
|
|
7
|
+
prepareCachePlan,
|
|
8
|
+
publicPostsScope,
|
|
9
|
+
saveCacheTimestamp,
|
|
10
|
+
sharedPostsScope,
|
|
11
|
+
type CachePlan,
|
|
12
|
+
type CacheResult,
|
|
13
|
+
type CacheScope,
|
|
14
|
+
} from "../lib/cache";
|
|
1
15
|
import {
|
|
2
16
|
booleanFlag,
|
|
3
17
|
integerFlag,
|
|
@@ -50,52 +64,109 @@ export async function runPostCommand(args: ParsedArgs, io: Io): Promise<void> {
|
|
|
50
64
|
}
|
|
51
65
|
|
|
52
66
|
case "list": {
|
|
67
|
+
assertSinceFlags(args);
|
|
68
|
+
const channelId = await context.client.resolveChannelId(
|
|
69
|
+
requiredChannelFlag(args.flags),
|
|
70
|
+
);
|
|
71
|
+
const cacheScope = await maybeOwnedPostsScope(args, context, channelId);
|
|
72
|
+
const cachePlan = await maybePrepareCachePlan(args, context, cacheScope);
|
|
53
73
|
const response = await context.client.listChannelPosts({
|
|
54
|
-
channelId
|
|
55
|
-
requiredChannelFlag(args.flags),
|
|
56
|
-
),
|
|
74
|
+
channelId,
|
|
57
75
|
limit: integerFlag(args.flags, "limit", { label: "--limit" }),
|
|
58
76
|
cursor: stringFlag(args.flags, "cursor"),
|
|
59
77
|
order: parseLatestFirstOrder(stringFlag(args.flags, "order")),
|
|
60
|
-
since:
|
|
78
|
+
since: resolvedSince(args, cachePlan),
|
|
61
79
|
});
|
|
80
|
+
const savedServerTimestamp = await maybeSaveCacheTimestamp(
|
|
81
|
+
args,
|
|
82
|
+
context,
|
|
83
|
+
cacheScope,
|
|
84
|
+
response.meta,
|
|
85
|
+
response.nextCursor === undefined,
|
|
86
|
+
);
|
|
62
87
|
|
|
63
|
-
printPostCollection(
|
|
88
|
+
printPostCollection(
|
|
89
|
+
args,
|
|
90
|
+
context.outputMode,
|
|
91
|
+
io,
|
|
92
|
+
response,
|
|
93
|
+
cacheResult(cachePlan, savedServerTimestamp),
|
|
94
|
+
);
|
|
64
95
|
return;
|
|
65
96
|
}
|
|
66
97
|
|
|
67
98
|
case "public-list": {
|
|
99
|
+
assertSinceFlags(args);
|
|
100
|
+
const publicHandle = requiredPositional(
|
|
101
|
+
args.positionals,
|
|
102
|
+
1,
|
|
103
|
+
"Missing public handle",
|
|
104
|
+
);
|
|
105
|
+
const channelName = requiredPositional(
|
|
106
|
+
args.positionals,
|
|
107
|
+
2,
|
|
108
|
+
"Missing public channel name",
|
|
109
|
+
);
|
|
110
|
+
const cacheScope = maybePublicPostsScope(
|
|
111
|
+
args,
|
|
112
|
+
context,
|
|
113
|
+
publicHandle,
|
|
114
|
+
channelName,
|
|
115
|
+
);
|
|
116
|
+
const cachePlan = await maybePrepareCachePlan(args, context, cacheScope);
|
|
68
117
|
const response = await context.client.listPublicChannelPosts({
|
|
69
|
-
publicHandle
|
|
70
|
-
|
|
71
|
-
1,
|
|
72
|
-
"Missing public handle",
|
|
73
|
-
),
|
|
74
|
-
channelName: requiredPositional(
|
|
75
|
-
args.positionals,
|
|
76
|
-
2,
|
|
77
|
-
"Missing public channel name",
|
|
78
|
-
),
|
|
118
|
+
publicHandle,
|
|
119
|
+
channelName,
|
|
79
120
|
limit: integerFlag(args.flags, "limit", { label: "--limit" }),
|
|
80
121
|
cursor: stringFlag(args.flags, "cursor"),
|
|
81
122
|
order: parseLatestFirstOrder(stringFlag(args.flags, "order")),
|
|
82
|
-
since:
|
|
123
|
+
since: resolvedSince(args, cachePlan),
|
|
83
124
|
});
|
|
125
|
+
const savedServerTimestamp = await maybeSaveCacheTimestamp(
|
|
126
|
+
args,
|
|
127
|
+
context,
|
|
128
|
+
cacheScope,
|
|
129
|
+
response.meta,
|
|
130
|
+
response.nextCursor === undefined,
|
|
131
|
+
);
|
|
84
132
|
|
|
85
|
-
printPostCollection(
|
|
133
|
+
printPostCollection(
|
|
134
|
+
args,
|
|
135
|
+
context.outputMode,
|
|
136
|
+
io,
|
|
137
|
+
response,
|
|
138
|
+
cacheResult(cachePlan, savedServerTimestamp),
|
|
139
|
+
);
|
|
86
140
|
return;
|
|
87
141
|
}
|
|
88
142
|
|
|
89
143
|
case "shared-list": {
|
|
144
|
+
assertSinceFlags(args);
|
|
145
|
+
const token = requiredPositional(args.positionals, 1, "Missing share token");
|
|
146
|
+
const cacheScope = maybeSharedPostsScope(args, context, token);
|
|
147
|
+
const cachePlan = await maybePrepareCachePlan(args, context, cacheScope);
|
|
90
148
|
const response = await context.client.listSharedChannelPosts({
|
|
91
|
-
token
|
|
149
|
+
token,
|
|
92
150
|
limit: integerFlag(args.flags, "limit", { label: "--limit" }),
|
|
93
151
|
cursor: stringFlag(args.flags, "cursor"),
|
|
94
152
|
order: parseLatestFirstOrder(stringFlag(args.flags, "order")),
|
|
95
|
-
since:
|
|
153
|
+
since: resolvedSince(args, cachePlan),
|
|
96
154
|
});
|
|
155
|
+
const savedServerTimestamp = await maybeSaveCacheTimestamp(
|
|
156
|
+
args,
|
|
157
|
+
context,
|
|
158
|
+
cacheScope,
|
|
159
|
+
response.meta,
|
|
160
|
+
response.nextCursor === undefined,
|
|
161
|
+
);
|
|
97
162
|
|
|
98
|
-
printPostCollection(
|
|
163
|
+
printPostCollection(
|
|
164
|
+
args,
|
|
165
|
+
context.outputMode,
|
|
166
|
+
io,
|
|
167
|
+
response,
|
|
168
|
+
cacheResult(cachePlan, savedServerTimestamp),
|
|
169
|
+
);
|
|
99
170
|
return;
|
|
100
171
|
}
|
|
101
172
|
|
|
@@ -234,6 +305,7 @@ function printPostCollection(
|
|
|
234
305
|
nextCursor?: string;
|
|
235
306
|
meta?: Record<string, unknown>;
|
|
236
307
|
},
|
|
308
|
+
cache?: CacheResult,
|
|
237
309
|
): void {
|
|
238
310
|
if (outputMode === "json") {
|
|
239
311
|
printJson(
|
|
@@ -242,6 +314,7 @@ function printPostCollection(
|
|
|
242
314
|
items: response.items,
|
|
243
315
|
nextCursor: response.nextCursor,
|
|
244
316
|
meta: response.meta,
|
|
317
|
+
...(cache ? { cache } : {}),
|
|
245
318
|
}),
|
|
246
319
|
);
|
|
247
320
|
return;
|
|
@@ -267,6 +340,8 @@ function printPostCollection(
|
|
|
267
340
|
if (message) {
|
|
268
341
|
io.stdout(message);
|
|
269
342
|
}
|
|
343
|
+
|
|
344
|
+
printCacheNote(io, cache);
|
|
270
345
|
}
|
|
271
346
|
|
|
272
347
|
function parseLatestFirstOrder(value: string | undefined): LatestFirstOrder | undefined {
|
|
@@ -281,6 +356,93 @@ function parseLatestFirstOrder(value: string | undefined): LatestFirstOrder | un
|
|
|
281
356
|
throw new CliError("--order must be one of: latest, oldest", 2);
|
|
282
357
|
}
|
|
283
358
|
|
|
359
|
+
async function maybePrepareCachePlan(
|
|
360
|
+
args: ParsedArgs,
|
|
361
|
+
context: Awaited<ReturnType<typeof createCommandContext>>,
|
|
362
|
+
scope: CacheScope | undefined,
|
|
363
|
+
): Promise<CachePlan | undefined> {
|
|
364
|
+
return cacheFlags(args).sinceCache && scope
|
|
365
|
+
? prepareCachePlan(context, scope)
|
|
366
|
+
: undefined;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
async function maybeSaveCacheTimestamp(
|
|
370
|
+
args: ParsedArgs,
|
|
371
|
+
context: Awaited<ReturnType<typeof createCommandContext>>,
|
|
372
|
+
scope: CacheScope | undefined,
|
|
373
|
+
meta: Record<string, unknown> | undefined,
|
|
374
|
+
shouldSave: boolean,
|
|
375
|
+
): Promise<string | undefined> {
|
|
376
|
+
return cacheFlags(args).saveCache && scope && shouldSave
|
|
377
|
+
? saveCacheTimestamp(context, scope, meta)
|
|
378
|
+
: undefined;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
async function maybeOwnedPostsScope(
|
|
382
|
+
args: ParsedArgs,
|
|
383
|
+
context: Awaited<ReturnType<typeof createCommandContext>>,
|
|
384
|
+
channelId: string,
|
|
385
|
+
): Promise<CacheScope | undefined> {
|
|
386
|
+
if (!cacheFlags(args).sinceCache && !cacheFlags(args).saveCache) {
|
|
387
|
+
return undefined;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
return ownedPostsScope({
|
|
391
|
+
context,
|
|
392
|
+
actorKey: await authenticatedActorKey(context),
|
|
393
|
+
channelId,
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
function maybePublicPostsScope(
|
|
398
|
+
args: ParsedArgs,
|
|
399
|
+
context: Awaited<ReturnType<typeof createCommandContext>>,
|
|
400
|
+
publicHandle: string,
|
|
401
|
+
channelName: string,
|
|
402
|
+
): CacheScope | undefined {
|
|
403
|
+
if (!cacheFlags(args).sinceCache && !cacheFlags(args).saveCache) {
|
|
404
|
+
return undefined;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
return publicPostsScope({ context, publicHandle, channelName });
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
function maybeSharedPostsScope(
|
|
411
|
+
args: ParsedArgs,
|
|
412
|
+
context: Awaited<ReturnType<typeof createCommandContext>>,
|
|
413
|
+
shareToken: string,
|
|
414
|
+
): CacheScope | undefined {
|
|
415
|
+
if (!cacheFlags(args).sinceCache && !cacheFlags(args).saveCache) {
|
|
416
|
+
return undefined;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
return sharedPostsScope({ context, shareToken });
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function resolvedSince(
|
|
423
|
+
args: ParsedArgs,
|
|
424
|
+
cachePlan: CachePlan | undefined,
|
|
425
|
+
): string | undefined {
|
|
426
|
+
return stringFlag(args.flags, "since") ?? cachePlan?.previousServerTimestamp;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
function printCacheNote(io: Io, cache: CacheResult | undefined): void {
|
|
430
|
+
if (!cache) {
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
const details = [
|
|
435
|
+
cache.previousServerTimestamp
|
|
436
|
+
? `used ${cache.previousServerTimestamp}`
|
|
437
|
+
: cache.hit
|
|
438
|
+
? "used cache"
|
|
439
|
+
: "no cached timestamp",
|
|
440
|
+
cache.savedServerTimestamp ? `saved ${cache.savedServerTimestamp}` : undefined,
|
|
441
|
+
].filter(Boolean);
|
|
442
|
+
|
|
443
|
+
io.stdout(`Cache: ${details.join("; ")}.`);
|
|
444
|
+
}
|
|
445
|
+
|
|
284
446
|
function renderPostDetail(
|
|
285
447
|
post: { id: string; attributes: PostAttributes },
|
|
286
448
|
options: { title?: string; channelId?: string } = {},
|
package/src/lib/args.ts
CHANGED
|
@@ -51,6 +51,10 @@ const CLI_OPTIONS = {
|
|
|
51
51
|
cursor: { type: "string" },
|
|
52
52
|
order: { type: "string" },
|
|
53
53
|
since: { type: "string" },
|
|
54
|
+
sinceCache: { type: "boolean" },
|
|
55
|
+
"since-cache": { type: "boolean" },
|
|
56
|
+
saveCache: { type: "boolean" },
|
|
57
|
+
"save-cache": { type: "boolean" },
|
|
54
58
|
status: { type: "string" },
|
|
55
59
|
mailbox: { type: "string" },
|
|
56
60
|
} as const;
|