lansenger-cli 1.0.0 → 1.0.2

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.
@@ -3,33 +3,61 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.registerCalendarCommands = registerCalendarCommands;
4
4
  const utils_1 = require("../utils");
5
5
  function registerCalendarCommands(program) {
6
- const cmd = program.command("calendar").description("Manage calendars and schedules");
6
+ const cmd = program.command("calendar").description("Calendar and schedule operations");
7
7
  cmd
8
8
  .command("primary")
9
9
  .description("Fetch primary calendar")
10
- .option("--user-token <token>", "User token")
10
+ .option("--user-token <token>", "User token", "")
11
+ .option("--user-id <userId>", "User ID", "")
11
12
  .action(async (opts) => {
12
13
  const client = (0, utils_1.getClient)();
13
- const result = await client.fetchPrimaryCalendar({ user_token: opts.userToken || undefined });
14
+ const result = await client.fetchPrimaryCalendar({
15
+ user_token: opts.userToken || undefined,
16
+ user_id: opts.userId || undefined,
17
+ });
14
18
  (0, utils_1.checkError)(result);
15
19
  (0, utils_1.outputResult)(result);
16
20
  });
17
21
  cmd
18
22
  .command("create-schedule")
19
23
  .description("Create a schedule/event")
20
- .requiredOption("--calendar-id <calendarId>", "Calendar ID")
21
- .requiredOption("--summary <summary>", "Schedule summary/title")
22
- .requiredOption("--start-time <json>", "Start time JSON")
23
- .requiredOption("--end-time <json>", "End time JSON")
24
- .requiredOption("--attendees <json>", "Attendees JSON array")
25
- .option("--user-token <token>", "User token")
26
- .action(async (opts) => {
24
+ .argument("<calendarId>", "Calendar ID")
25
+ .argument("<summary>", "Schedule summary/title")
26
+ .argument("<startTime>", "Start time (unix timestamp in seconds)")
27
+ .argument("<endTime>", "End time (unix timestamp in seconds)")
28
+ .argument("<attendees>", "Attendees as JSON list: '[{\"staffId\":\"xxx\",\"attendeeFlag\":\"yes\"}]'")
29
+ .option("-d, --desc <desc>", "Schedule description", "")
30
+ .option("--all-day <allDay>", "yes or no", "no")
31
+ .option("--date <date>", "Date string for allDay=yes, e.g. 2026-01-01", "")
32
+ .option("--repeat <repeat>", "Repeat type: no, daily, weekly, monthly, yearly, work_day, custom", "no")
33
+ .option("--reminder <reminder>", "Reminder type: yes or no", "yes")
34
+ .option("--tz <tz>", "Time zone, e.g. Asia/Shanghai", "Asia/Shanghai")
35
+ .option("--rule <rule>", "Repeat rule (RFC 5545 JSON)", "")
36
+ .option("--expire <expire>", "Expire date type: yes or no", "")
37
+ .option("--attendee-perms <perms>", "Attendee permissions: can_modify/can_invite/can_see/none", "")
38
+ .option("--user-token <token>", "User token", "")
39
+ .option("--user-id <userId>", "User ID", "")
40
+ .action(async (calendarId, summary, startTime, endTime, attendees, opts) => {
27
41
  const client = (0, utils_1.getClient)();
28
- const startTime = (0, utils_1.parseJsonOption)(opts.startTime);
29
- const endTime = (0, utils_1.parseJsonOption)(opts.endTime);
30
- const attendees = (0, utils_1.parseJsonOption)(opts.attendees);
31
- const result = await client.createSchedule(opts.calendarId, opts.summary, startTime, endTime, attendees, {
42
+ const attendeesList = (0, utils_1.parseJsonOption)(attendees);
43
+ const startTimeInt = parseInt(startTime);
44
+ const endTimeInt = parseInt(endTime);
45
+ const startTimeDict = { time: startTimeInt, date: opts.date, timeZone: opts.tz };
46
+ const endTimeDict = { time: endTimeInt, date: opts.date, timeZone: opts.tz };
47
+ if (opts.allDay === "yes") {
48
+ startTimeDict.timeZone = "UTC";
49
+ endTimeDict.timeZone = "UTC";
50
+ }
51
+ const result = await client.createSchedule(calendarId, summary, startTimeDict, endTimeDict, attendeesList, {
52
+ description: opts.desc || undefined,
53
+ all_day: opts.allDay,
54
+ repeat_type: opts.repeat,
55
+ reminder_type: opts.reminder,
56
+ rule: opts.rule || undefined,
57
+ expire_date_type: opts.expire || undefined,
58
+ attendee_permissions: opts.attendeePerms || undefined,
32
59
  user_token: opts.userToken || undefined,
60
+ user_id: opts.userId || undefined,
33
61
  });
34
62
  (0, utils_1.checkError)(result);
35
63
  (0, utils_1.outputResult)(result);
@@ -37,38 +65,48 @@ function registerCalendarCommands(program) {
37
65
  cmd
38
66
  .command("fetch-schedule")
39
67
  .description("Fetch a schedule by ID")
40
- .requiredOption("--calendar-id <calendarId>", "Calendar ID")
41
- .requiredOption("--schedule-id <scheduleId>", "Schedule ID")
42
- .option("--user-token <token>", "User token")
43
- .action(async (opts) => {
68
+ .argument("<calendarId>", "Calendar ID")
69
+ .argument("<scheduleId>", "Schedule ID")
70
+ .option("--user-token <token>", "User token", "")
71
+ .option("--user-id <userId>", "User ID", "")
72
+ .action(async (calendarId, scheduleId, opts) => {
44
73
  const client = (0, utils_1.getClient)();
45
- const result = await client.fetchSchedule(opts.calendarId, opts.scheduleId, { user_token: opts.userToken || undefined });
74
+ const result = await client.fetchSchedule(calendarId, scheduleId, {
75
+ user_token: opts.userToken || undefined,
76
+ user_id: opts.userId || undefined,
77
+ });
46
78
  (0, utils_1.checkError)(result);
47
79
  (0, utils_1.outputResult)(result);
48
80
  });
49
81
  cmd
50
82
  .command("delete-schedule")
51
83
  .description("Delete a schedule")
52
- .requiredOption("--calendar-id <calendarId>", "Calendar ID")
53
- .requiredOption("--schedule-id <scheduleId>", "Schedule ID")
54
- .option("--user-token <token>", "User token")
55
- .action(async (opts) => {
84
+ .argument("<calendarId>", "Calendar ID")
85
+ .argument("<scheduleId>", "Schedule ID")
86
+ .option("--user-token <token>", "User token", "")
87
+ .option("--user-id <userId>", "User ID", "")
88
+ .action(async (calendarId, scheduleId, opts) => {
56
89
  const client = (0, utils_1.getClient)();
57
- const result = await client.deleteSchedule(opts.calendarId, opts.scheduleId, { user_token: opts.userToken || undefined });
90
+ const result = await client.deleteSchedule(calendarId, scheduleId, {
91
+ user_token: opts.userToken || undefined,
92
+ user_id: opts.userId || undefined,
93
+ });
58
94
  (0, utils_1.checkError)(result);
59
95
  (0, utils_1.outputResult)(result);
60
96
  });
61
97
  cmd
62
98
  .command("list-schedules")
63
99
  .description("List schedules in a time range")
64
- .requiredOption("--calendar-id <calendarId>", "Calendar ID")
65
- .requiredOption("--start-ts <startTs>", "Start timestamp (seconds)")
66
- .requiredOption("--end-ts <endTs>", "End timestamp (seconds)")
67
- .option("--user-token <token>", "User token")
68
- .action(async (opts) => {
100
+ .argument("<calendarId>", "Calendar ID")
101
+ .argument("<startTime>", "Start time (unix timestamp)")
102
+ .argument("<endTime>", "End time (unix timestamp)")
103
+ .option("--user-token <token>", "User token", "")
104
+ .option("--user-id <userId>", "User ID", "")
105
+ .action(async (calendarId, startTime, endTime, opts) => {
69
106
  const client = (0, utils_1.getClient)();
70
- const result = await client.fetchScheduleList(opts.calendarId, parseInt(opts.startTs), parseInt(opts.endTs), {
107
+ const result = await client.fetchScheduleList(calendarId, parseInt(startTime), parseInt(endTime), {
71
108
  user_token: opts.userToken || undefined,
109
+ user_id: opts.userId || undefined,
72
110
  });
73
111
  (0, utils_1.checkError)(result);
74
112
  (0, utils_1.outputResult)(result);
@@ -76,27 +114,39 @@ function registerCalendarCommands(program) {
76
114
  cmd
77
115
  .command("attendees")
78
116
  .description("Fetch schedule attendees")
79
- .requiredOption("--calendar-id <calendarId>", "Calendar ID")
80
- .requiredOption("--schedule-id <scheduleId>", "Schedule ID")
81
- .option("--user-token <token>", "User token")
82
- .action(async (opts) => {
117
+ .argument("<calendarId>", "Calendar ID")
118
+ .argument("<scheduleId>", "Schedule ID")
119
+ .option("--user-token <token>", "User token", "")
120
+ .option("--user-id <userId>", "User ID", "")
121
+ .option("-p, --page <page>", "Page number", "1")
122
+ .option("-s, --size <size>", "Page size", "500")
123
+ .action(async (calendarId, scheduleId, opts) => {
83
124
  const client = (0, utils_1.getClient)();
84
- const result = await client.fetchScheduleAttendees(opts.calendarId, opts.scheduleId, { user_token: opts.userToken || undefined });
125
+ const result = await client.fetchScheduleAttendees(calendarId, scheduleId, {
126
+ user_token: opts.userToken || undefined,
127
+ user_id: opts.userId || undefined,
128
+ page: parseInt(opts.page),
129
+ page_size: parseInt(opts.size),
130
+ });
85
131
  (0, utils_1.checkError)(result);
86
132
  (0, utils_1.outputResult)(result);
87
133
  });
88
134
  cmd
89
135
  .command("add-attendees")
90
136
  .description("Add attendees to a schedule")
91
- .requiredOption("--calendar-id <calendarId>", "Calendar ID")
92
- .requiredOption("--schedule-id <scheduleId>", "Schedule ID")
93
- .requiredOption("--attendees <ids>", "Comma-separated attendee staff IDs")
94
- .option("--user-token <token>", "User token")
95
- .action(async (opts) => {
137
+ .argument("<calendarId>", "Calendar ID")
138
+ .argument("<scheduleId>", "Schedule ID")
139
+ .argument("<attendees>", "Attendee staff IDs as JSON list: '[\"id1\",\"id2\"]'")
140
+ .option("--reminder <reminder>", "Reminder type: yes or no", "")
141
+ .option("--user-token <token>", "User token", "")
142
+ .option("--user-id <userId>", "User ID", "")
143
+ .action(async (calendarId, scheduleId, attendees, opts) => {
96
144
  const client = (0, utils_1.getClient)();
97
- const attendees = (0, utils_1.commaList)(opts.attendees);
98
- const result = await client.addScheduleAttendees(opts.calendarId, opts.scheduleId, attendees, {
145
+ const attendeesList = (0, utils_1.parseJsonOption)(attendees);
146
+ const result = await client.addScheduleAttendees(calendarId, scheduleId, attendeesList, {
147
+ reminder_type: opts.reminder || undefined,
99
148
  user_token: opts.userToken || undefined,
149
+ user_id: opts.userId || undefined,
100
150
  });
101
151
  (0, utils_1.checkError)(result);
102
152
  (0, utils_1.outputResult)(result);
@@ -104,15 +154,19 @@ function registerCalendarCommands(program) {
104
154
  cmd
105
155
  .command("delete-attendees")
106
156
  .description("Remove attendees from a schedule")
107
- .requiredOption("--calendar-id <calendarId>", "Calendar ID")
108
- .requiredOption("--schedule-id <scheduleId>", "Schedule ID")
109
- .requiredOption("--attendees <ids>", "Comma-separated attendee staff IDs")
110
- .option("--user-token <token>", "User token")
111
- .action(async (opts) => {
157
+ .argument("<calendarId>", "Calendar ID")
158
+ .argument("<scheduleId>", "Schedule ID")
159
+ .argument("<attendees>", "Attendee staff IDs as JSON list")
160
+ .option("--reminder <reminder>", "Reminder type: yes or no", "")
161
+ .option("--user-token <token>", "User token", "")
162
+ .option("--user-id <userId>", "User ID", "")
163
+ .action(async (calendarId, scheduleId, attendees, opts) => {
112
164
  const client = (0, utils_1.getClient)();
113
- const attendees = (0, utils_1.commaList)(opts.attendees);
114
- const result = await client.deleteScheduleAttendees(opts.calendarId, opts.scheduleId, attendees, {
165
+ const attendeesList = (0, utils_1.parseJsonOption)(attendees);
166
+ const result = await client.deleteScheduleAttendees(calendarId, scheduleId, attendeesList, {
167
+ reminder_type: opts.reminder || undefined,
115
168
  user_token: opts.userToken || undefined,
169
+ user_id: opts.userId || undefined,
116
170
  });
117
171
  (0, utils_1.checkError)(result);
118
172
  (0, utils_1.outputResult)(result);
@@ -120,15 +174,41 @@ function registerCalendarCommands(program) {
120
174
  cmd
121
175
  .command("update-schedule")
122
176
  .description("Update a schedule")
123
- .requiredOption("--calendar-id <calendarId>", "Calendar ID")
124
- .requiredOption("--schedule-id <scheduleId>", "Schedule ID")
125
- .option("--summary <summary>", "New summary/title")
126
- .option("--user-token <token>", "User token")
127
- .action(async (opts) => {
177
+ .argument("<calendarId>", "Calendar ID")
178
+ .argument("<scheduleId>", "Schedule ID")
179
+ .option("--summary <summary>", "New schedule summary", "")
180
+ .option("-d, --desc <desc>", "New description", "")
181
+ .option("--op <op>", "Operation type: modify_all, modify_current, modify_current_after", "modify_all")
182
+ .option("--current-time <time>", "Required when op != modify_all", "0")
183
+ .option("--reminder <reminder>", "Reminder type: yes or no", "")
184
+ .option("--repeat <repeat>", "Repeat type: no, day, week, month, year, work_day, custom", "")
185
+ .option("--rule <rule>", "RFC 5545 repeat rule", "")
186
+ .option("--expire <expire>", "Expire date type: yes or no", "")
187
+ .option("--all-day <allDay>", "All day: yes or no", "")
188
+ .option("--permissions <permissions>", "Attendee permissions: can_modify, can_invite, can_see, none", "")
189
+ .option("--start-time <json>", "Start time as JSON dict: {\"time\":..., \"date\":..., \"timeZone\":...}", "")
190
+ .option("--end-time <json>", "End time as JSON dict", "")
191
+ .option("--user-token <token>", "User token", "")
192
+ .option("--user-id <userId>", "User ID", "")
193
+ .action(async (calendarId, scheduleId, opts) => {
128
194
  const client = (0, utils_1.getClient)();
129
- const result = await client.updateSchedule(opts.calendarId, opts.scheduleId, {
195
+ const startTimeDict = opts.startTime ? (0, utils_1.parseJsonOption)(opts.startTime) : undefined;
196
+ const endTimeDict = opts.endTime ? (0, utils_1.parseJsonOption)(opts.endTime) : undefined;
197
+ const result = await client.updateSchedule(calendarId, scheduleId, {
130
198
  summary: opts.summary || undefined,
199
+ description: opts.desc || undefined,
200
+ operation_type: opts.op,
201
+ current_time: opts.currentTime ? parseInt(opts.currentTime) : undefined,
202
+ reminder_type: opts.reminder || undefined,
203
+ repeat_type: opts.repeat || undefined,
204
+ rule: opts.rule || undefined,
205
+ expire_date_type: opts.expire || undefined,
206
+ all_day: opts.allDay || undefined,
207
+ attendee_permissions: opts.permissions || undefined,
208
+ start_time: startTimeDict,
209
+ end_time: endTimeDict,
131
210
  user_token: opts.userToken || undefined,
211
+ user_id: opts.userId || undefined,
132
212
  });
133
213
  (0, utils_1.checkError)(result);
134
214
  (0, utils_1.outputResult)(result);
@@ -136,20 +216,26 @@ function registerCalendarCommands(program) {
136
216
  cmd
137
217
  .command("attendee-meta")
138
218
  .description("Update attendee metadata (rsvp, busy/free, reminders)")
139
- .requiredOption("--calendar-id <calendarId>", "Calendar ID")
140
- .requiredOption("--schedule-id <scheduleId>", "Schedule ID")
141
- .option("--rsvp-status <status>", "RSVP status")
142
- .option("--busy-free-state <state>", "Busy/free state")
143
- .option("--remind-times <times>", "Comma-separated reminder times (seconds before event)")
144
- .option("--user-token <token>", "User token")
145
- .action(async (opts) => {
219
+ .argument("<calendarId>", "Calendar ID")
220
+ .argument("<scheduleId>", "Schedule ID")
221
+ .option("--rsvp <rsvp>", "RSVP status: accept, tentative, decline", "")
222
+ .option("--color <color>", "Hex color (e.g. #FF347AFC)", "")
223
+ .option("--permissions <permissions>", "Visibility: private, public, default", "")
224
+ .option("--busy-free <state>", "Busy/free state: busy, free", "")
225
+ .option("--remind-times <json>", "Reminder offsets in minutes as JSON list, e.g. '[5,15]'", "")
226
+ .option("--user-token <token>", "User token", "")
227
+ .option("--user-id <userId>", "User ID", "")
228
+ .action(async (calendarId, scheduleId, opts) => {
146
229
  const client = (0, utils_1.getClient)();
147
- const remindTimes = opts.remindTimes ? (0, utils_1.commaList)(opts.remindTimes).map(Number) : undefined;
148
- const result = await client.updateScheduleAttendeeMeta(opts.calendarId, opts.scheduleId, {
149
- rsvp_status: opts.rsvpStatus || undefined,
150
- busy_free_state: opts.busyFreeState || undefined,
151
- remind_times: remindTimes,
230
+ const remindTimesList = opts.remindTimes ? (0, utils_1.parseJsonOption)(opts.remindTimes) : undefined;
231
+ const result = await client.updateScheduleAttendeeMeta(calendarId, scheduleId, {
232
+ rsvp_status: opts.rsvp || undefined,
233
+ color: opts.color || undefined,
234
+ permissions: opts.permissions || undefined,
235
+ busy_free_state: opts.busyFree || undefined,
236
+ remind_times: remindTimesList,
152
237
  user_token: opts.userToken || undefined,
238
+ user_id: opts.userId || undefined,
153
239
  });
154
240
  (0, utils_1.checkError)(result);
155
241
  (0, utils_1.outputResult)(result);
@@ -3,42 +3,93 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.registerCallbackCommands = registerCallbackCommands;
4
4
  const utils_1 = require("../utils");
5
5
  const lansenger_sdk_ts_1 = require("lansenger-sdk-ts");
6
+ function resolveEncodingKey(cliValue, profile) {
7
+ if (cliValue)
8
+ return cliValue;
9
+ const store = (0, utils_1.getStore)();
10
+ const creds = store.loadCredentials();
11
+ const val = creds.encoding_key || "";
12
+ if (val)
13
+ console.log(`Using encoding_key from credential store (profile: ${profile})`);
14
+ return val;
15
+ }
16
+ function resolveCallbackToken(cliValue, encodingKey, profile) {
17
+ if (cliValue)
18
+ return cliValue;
19
+ const store = (0, utils_1.getStore)();
20
+ const creds = store.loadCredentials();
21
+ const val = creds.callback_token || "";
22
+ if (val)
23
+ console.log(`Using callback_token from credential store (profile: ${profile})`);
24
+ return val;
25
+ }
6
26
  function registerCallbackCommands(program) {
7
- const cmd = program.command("callback").description("Parse and verify callback/webhook payloads");
27
+ const cmd = program.command("callback").description("Parse and verify callback events");
8
28
  cmd
9
29
  .command("parse-payload")
10
30
  .description("Parse an encrypted callback payload")
11
- .requiredOption("--data <data>", "Encrypted callback data")
12
- .option("--encoding-key <key>", "Encoding AES key")
13
- .option("--verify-signature", "Verify signature before parsing", false)
14
- .option("--timestamp <ts>", "Timestamp for signature verification")
15
- .option("--nonce <nonce>", "Nonce for signature verification")
16
- .option("--signature <sig>", "Signature for verification")
17
- .option("--callback-token <token>", "Callback token for verification")
18
- .action(async (opts) => {
19
- const events = lansenger_sdk_ts_1.LansengerClient.parseCallbackPayload(opts.data, {
20
- encoding_key: opts.encodingKey || "",
21
- verify_signature: opts.verifySignature,
31
+ .argument("<encryptedData>", "Callback data (plain JSON or encrypted dataEncrypt value)")
32
+ .option("--encoding-key <key>", "Base64-encoded AES key for decryption (reads from credential store if empty)", "")
33
+ .option("--callback-token <token>", "Token for signature verification (reads from credential store if empty; falls back to encoding_key)", "")
34
+ .option("--known-app-id <appId>", "Known appId to help split orgId/appId during decryption", "")
35
+ .option("--verify-sig", "Verify signature before parsing", false)
36
+ .option("--timestamp <ts>", "Timestamp for signature verification", "")
37
+ .option("--nonce <nonce>", "Nonce for signature verification", "")
38
+ .option("--signature <sig>", "Signature to verify", "")
39
+ .option("-P, --profile <profile>", "Credential profile (overrides global --profile)", "")
40
+ .action(async (encryptedData, opts) => {
41
+ const p = opts.profile || utils_1.activeProfile;
42
+ const resolvedKey = resolveEncodingKey(opts.encodingKey, p);
43
+ const resolvedToken = resolveCallbackToken(opts.callbackToken, resolvedKey, p);
44
+ const events = lansenger_sdk_ts_1.LansengerClient.parseCallbackPayload(encryptedData, {
45
+ encoding_key: resolvedKey,
46
+ verify_signature: opts.verifySig,
22
47
  timestamp: opts.timestamp || "",
23
48
  nonce: opts.nonce || "",
24
49
  signature: opts.signature || "",
25
- callback_token: opts.callbackToken || "",
50
+ callback_token: resolvedToken,
51
+ known_app_id: opts.knownAppId || "",
26
52
  });
27
53
  (0, utils_1.outputResult)(events);
28
54
  });
55
+ cmd
56
+ .command("decrypt-payload")
57
+ .description("Decrypt only (without parsing) a callback dataEncrypt value")
58
+ .argument("<encryptedData>", "Encrypted dataEncrypt value")
59
+ .option("--encoding-key <key>", "Base64-encoded AES key for decryption (reads from credential store if empty)", "")
60
+ .option("--known-app-id <appId>", "Known appId to help split orgId/appId in decrypted result", "")
61
+ .option("-P, --profile <profile>", "Credential profile (overrides global --profile)", "")
62
+ .action(async (encryptedData, opts) => {
63
+ const p = opts.profile || utils_1.activeProfile;
64
+ const resolvedKey = resolveEncodingKey(opts.encodingKey, p);
65
+ if (!resolvedKey) {
66
+ console.error("Error: encoding_key is required for decryption. Pass --encoding-key or set it via lansenger config set encoding_key.");
67
+ process.exit(1);
68
+ }
69
+ const result = (0, lansenger_sdk_ts_1.decryptCallbackPayload)(encryptedData, resolvedKey, opts.knownAppId || undefined);
70
+ (0, utils_1.outputResult)(result);
71
+ });
29
72
  cmd
30
73
  .command("verify-signature")
31
74
  .description("Verify callback signature")
32
- .requiredOption("--timestamp <ts>", "Timestamp")
33
- .requiredOption("--nonce <nonce>", "Nonce")
34
- .requiredOption("--signature <sig>", "Signature")
35
- .requiredOption("--encoding-key <key>", "Encoding AES key")
36
- .option("--data-encrypt <data>", "Encrypted data for verification")
37
- .option("--callback-token <token>", "Callback token")
38
- .action(async (opts) => {
39
- const valid = lansenger_sdk_ts_1.LansengerClient.verifyCallbackSignature(opts.timestamp, opts.nonce, opts.signature, opts.encodingKey, {
75
+ .argument("<timestamp>", "Timestamp")
76
+ .argument("<nonce>", "Nonce")
77
+ .argument("<signature>", "Signature")
78
+ .option("--encoding-key <key>", "Encoding key, used as token if callback-token not provided (reads from credential store if empty)", "")
79
+ .option("--data-encrypt <data>", "The encrypted dataEncrypt value (required for correct signature verification)", "")
80
+ .option("--callback-token <token>", "Token from developer center callback config (reads from credential store if empty; falls back to encoding_key)", "")
81
+ .option("-P, --profile <profile>", "Credential profile (overrides global --profile)", "")
82
+ .action(async (timestamp, nonce, signature, opts) => {
83
+ const p = opts.profile || utils_1.activeProfile;
84
+ const resolvedKey = resolveEncodingKey(opts.encodingKey, p);
85
+ if (!resolvedKey) {
86
+ console.error("Error: encoding_key is required for signature verification. Pass --encoding-key or set it via lansenger config set encoding_key.");
87
+ process.exit(1);
88
+ }
89
+ const resolvedToken = resolveCallbackToken(opts.callbackToken, resolvedKey, p);
90
+ const valid = lansenger_sdk_ts_1.LansengerClient.verifyCallbackSignature(timestamp, nonce, signature, resolvedKey, {
40
91
  data_encrypt: opts.dataEncrypt || "",
41
- callback_token: opts.callbackToken || "",
92
+ callback_token: resolvedToken,
42
93
  });
43
94
  (0, utils_1.outputResult)({ valid });
44
95
  });
@@ -2,32 +2,149 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.registerChatCommands = registerChatCommands;
4
4
  const utils_1 = require("../utils");
5
+ function splitMonths(startUs, endUs) {
6
+ const results = [];
7
+ const startDt = startUs ? new Date(startUs / 1000000) : new Date(2020, 0, 1);
8
+ const endDt = new Date(endUs / 1000000);
9
+ let year = startDt.getFullYear();
10
+ let month = startDt.getMonth();
11
+ while (new Date(year, month, 1) <= endDt) {
12
+ const lastDay = new Date(year, month + 1, 0).getDate();
13
+ const msStart = Math.floor(new Date(year, month, 1).getTime() * 1000);
14
+ const msEnd = Math.floor(new Date(year, month, lastDay, 23, 59, 59).getTime() * 1000);
15
+ results.push([msStart, msEnd]);
16
+ month++;
17
+ if (month > 11) {
18
+ month = 0;
19
+ year++;
20
+ }
21
+ }
22
+ return results;
23
+ }
5
24
  function registerChatCommands(program) {
6
- const cmd = program.command("chat").description("View chat list and message history");
25
+ const cmd = program.command("chat").description("Chat list and message history");
7
26
  cmd
8
27
  .command("list")
9
28
  .description("Fetch chat list (private + group chats)")
10
- .option("--user-token <token>", "User token")
29
+ .option("-t, --type <type>", "0=all, 1=private, 2=group", "0")
30
+ .option("-k, --keyword <keyword>", "Search keyword (only for type 1 or 2)", "")
31
+ .option("--start <start>", "Start time in microseconds", "0")
32
+ .option("--end <end>", "End time in microseconds", "0")
33
+ .option("--user-token <token>", "User token", "")
11
34
  .action(async (opts) => {
12
35
  const client = (0, utils_1.getClient)();
13
- const result = await client.fetchChatList({ user_token: opts.userToken || undefined });
36
+ const result = await client.fetchChatList({
37
+ chat_type: parseInt(opts.type),
38
+ keyword: opts.keyword || undefined,
39
+ start_time: parseInt(opts.start),
40
+ end_time: parseInt(opts.end),
41
+ user_token: opts.userToken || undefined,
42
+ });
14
43
  (0, utils_1.checkError)(result);
15
- (0, utils_1.outputResult)(result);
44
+ if (result.success) {
45
+ (0, utils_1.outputResult)(result);
46
+ if (result.staff_infos) {
47
+ (0, utils_1.outputList)(result.staff_infos, ["Staff ID", "Name", "Sectors"], (s) => [
48
+ s.staff_id || "", s.staff_name || "", String(s.sector_names || ""),
49
+ ]);
50
+ }
51
+ if (result.group_infos) {
52
+ (0, utils_1.outputList)(result.group_infos, ["Group ID", "Name"], (g) => [
53
+ g.group_id || "", g.group_name || "",
54
+ ]);
55
+ }
56
+ }
57
+ else {
58
+ (0, utils_1.outputResult)(result);
59
+ }
16
60
  });
17
61
  cmd
18
62
  .command("messages")
19
63
  .description("Fetch chat messages")
20
- .option("--staff-id <staffId>", "Staff ID for private chat messages")
21
- .option("--group-id <groupId>", "Group ID for group chat messages")
22
- .option("--user-token <token>", "User token")
64
+ .option("--staff-id <staffId>", "Private chat partner staffId", "")
65
+ .option("--group-id <groupId>", "Group openId", "")
66
+ .option("-s, --size <size>", "Per-page count (max 100)", "100")
67
+ .option("--version <version>", "Deep pagination cursor, first call: 0", "0")
68
+ .option("--start <start>", "Start time in microseconds", "0")
69
+ .option("--end <end>", "End time in microseconds", "0")
70
+ .option("--sender-id <senderId>", "Filter by sender staffId", "")
71
+ .option("--split-month", "Auto-split query by month when range > 1 month", false)
72
+ .option("--progress", "Show pagination progress (pages/messages fetched)", false)
73
+ .option("--user-token <token>", "User token", "")
23
74
  .action(async (opts) => {
24
75
  const client = (0, utils_1.getClient)();
25
- const result = await client.fetchChatMessages({
26
- staff_id: opts.staffId || undefined,
27
- group_id: opts.groupId || undefined,
28
- user_token: opts.userToken || undefined,
29
- });
30
- (0, utils_1.checkError)(result);
31
- (0, utils_1.outputResult)(result);
76
+ if (!opts.splitMonth) {
77
+ const result = await client.fetchChatMessages({
78
+ staff_id: opts.staffId || undefined,
79
+ group_id: opts.groupId || undefined,
80
+ page_size: parseInt(opts.size),
81
+ base_version: opts.version,
82
+ start_time: parseInt(opts.start),
83
+ end_time: parseInt(opts.end),
84
+ sender_id: opts.senderId || undefined,
85
+ user_token: opts.userToken || undefined,
86
+ });
87
+ (0, utils_1.checkError)(result);
88
+ if (result.success) {
89
+ (0, utils_1.outputResult)(result);
90
+ if (result.messages) {
91
+ (0, utils_1.outputList)(result.messages, ["Time", "Sender", "Type"], (m) => [
92
+ m.send_time || "", m.sender || "", m.message_type || "",
93
+ ]);
94
+ }
95
+ }
96
+ else {
97
+ (0, utils_1.outputResult)(result);
98
+ }
99
+ return;
100
+ }
101
+ const allMessages = [];
102
+ let pageCount = 0;
103
+ let msgCount = 0;
104
+ const startUs = parseInt(opts.start) || 0;
105
+ const endUs = parseInt(opts.end) || Math.floor(Date.now() * 1000);
106
+ const months = splitMonths(startUs, endUs);
107
+ for (let i = 0; i < months.length; i++) {
108
+ const [msStart, msEnd] = months[i];
109
+ let cursor = "0";
110
+ while (true) {
111
+ const result = await client.fetchChatMessages({
112
+ staff_id: opts.staffId || undefined,
113
+ group_id: opts.groupId || undefined,
114
+ page_size: parseInt(opts.size),
115
+ base_version: cursor,
116
+ start_time: msStart,
117
+ end_time: msEnd,
118
+ sender_id: opts.senderId || undefined,
119
+ user_token: opts.userToken || undefined,
120
+ });
121
+ if (!result.success) {
122
+ (0, utils_1.outputResult)(result);
123
+ return;
124
+ }
125
+ pageCount++;
126
+ msgCount += result.messages ? result.messages.length : 0;
127
+ if (result.messages)
128
+ allMessages.push(...result.messages);
129
+ if (opts.progress && !utils_1.jsonOutput) {
130
+ console.log(`Month ${i + 1}/${months.length} | Page ${pageCount} | ${msgCount} messages total`);
131
+ }
132
+ if (!(result.messages && result.has_more))
133
+ break;
134
+ cursor = String(result.last_version || "");
135
+ }
136
+ }
137
+ if (utils_1.jsonOutput) {
138
+ console.log(JSON.stringify(allMessages.map(m => m.toDict ? m.toDict() : m), null, 2));
139
+ return;
140
+ }
141
+ if (opts.progress) {
142
+ console.log(`Done: ${pageCount} pages, ${msgCount} messages across ${months.length} months`);
143
+ }
144
+ if (allMessages.length) {
145
+ (0, utils_1.outputList)(allMessages, ["Time", "Sender", "Type"], (m) => [
146
+ m.send_time || "", m.sender || "", m.message_type || "",
147
+ ]);
148
+ }
32
149
  });
33
150
  }