claude-threads 1.32.0 → 1.33.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 +13 -0
- package/dist/index.js +26 -5
- package/dist/mcp/mcp-server.js +581 -121
- package/docs/app-user-posts-spec.md +79 -0
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.33.0] - 2026-09-02
|
|
11
|
+
|
|
12
|
+
### Security
|
|
13
|
+
- **fast-uri floored at 4.1.4** (transitive via `ajv`), clearing four fresh high-severity advisories (host confusion and SSRF classes, GHSA-5jgf-p345-68v8 and siblings). Override floor raised from `>=4.1.2`; no direct dependency changes.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
- **Slack: posts made through the app's own user token count as the person's message** (#527, thanks @kaza). Tooling that posts into the channel via the app's user token (same `app_id` + team, acting user set) previously looked bot-authored and was ignored; such posts now command the bot as the acting user. Authorship is decided only from server-authoritative envelope identity (`app_id` learned from the `hello` frame and per-envelope `api_app_id`) — content-based spoofing cannot trigger it, and events that don't match fail closed to today's behavior. Closes #526.
|
|
17
|
+
|
|
18
|
+
## [1.32.1] - 2026-09-02
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
- **Dependency updates.** Production: hono 4.13.5, zod 4.5.4, js-yaml 4.3.2, express-rate-limit 8.7.0 (#522); dev-dependency group refreshed (#521). Validated with the full unit and Slack integration suites.
|
|
22
|
+
|
|
10
23
|
## [1.32.0] - 2026-09-01
|
|
11
24
|
|
|
12
25
|
### Added
|
package/dist/index.js
CHANGED
|
@@ -71932,6 +71932,8 @@ class SlackClient extends BasePlatformClient {
|
|
|
71932
71932
|
userCache = new Map;
|
|
71933
71933
|
usernameToIdCache = new Map;
|
|
71934
71934
|
botUserId = null;
|
|
71935
|
+
appId = null;
|
|
71936
|
+
teamId = null;
|
|
71935
71937
|
botUser = null;
|
|
71936
71938
|
teamUrl = null;
|
|
71937
71939
|
lastProcessedTs = null;
|
|
@@ -71997,7 +71999,9 @@ class SlackClient extends BasePlatformClient {
|
|
|
71997
71999
|
return;
|
|
71998
72000
|
this.channelClients.delete(channelId);
|
|
71999
72001
|
}
|
|
72000
|
-
_injectSlackEvent(event) {
|
|
72002
|
+
_injectSlackEvent(event, appId) {
|
|
72003
|
+
if (appId)
|
|
72004
|
+
this.appId = appId;
|
|
72001
72005
|
this.handleSlackEvent(event);
|
|
72002
72006
|
}
|
|
72003
72007
|
disconnect() {
|
|
@@ -72218,21 +72222,37 @@ class SlackClient extends BasePlatformClient {
|
|
|
72218
72222
|
}
|
|
72219
72223
|
return;
|
|
72220
72224
|
}
|
|
72225
|
+
if (envelope.type === "hello" && envelope.connection_info?.app_id) {
|
|
72226
|
+
this.appId = envelope.connection_info.app_id;
|
|
72227
|
+
}
|
|
72221
72228
|
if (envelope.type === "events_api" && envelope.payload?.event) {
|
|
72229
|
+
if (envelope.payload.api_app_id)
|
|
72230
|
+
this.appId = envelope.payload.api_app_id;
|
|
72222
72231
|
this.handleSlackEvent(envelope.payload.event);
|
|
72223
72232
|
}
|
|
72224
72233
|
}
|
|
72234
|
+
isBotAuthored(message) {
|
|
72235
|
+
if (message.user === this.botUserId)
|
|
72236
|
+
return true;
|
|
72237
|
+
if (!message.bot_id)
|
|
72238
|
+
return false;
|
|
72239
|
+
const isOurUserTokenPost = Boolean(this.appId && message.app_id === this.appId && this.teamId && message.team === this.teamId && message.user);
|
|
72240
|
+
if (isOurUserTokenPost) {
|
|
72241
|
+
wsLogger.debug(`Accepting post by ${message.user} made through this app's user token`);
|
|
72242
|
+
}
|
|
72243
|
+
return !isOurUserTokenPost;
|
|
72244
|
+
}
|
|
72225
72245
|
handleSlackEvent(event) {
|
|
72226
72246
|
const eventChannel = event.channel || event.item?.channel;
|
|
72227
72247
|
if (eventChannel && eventChannel !== this.channelId) {
|
|
72228
72248
|
const secondary = this.channelClients.get(eventChannel);
|
|
72229
72249
|
if (secondary) {
|
|
72230
|
-
secondary._injectSlackEvent(event);
|
|
72250
|
+
secondary._injectSlackEvent(event, this.appId);
|
|
72231
72251
|
return;
|
|
72232
72252
|
}
|
|
72233
72253
|
}
|
|
72234
72254
|
if (event.type === "message" && (!event.subtype || event.subtype === "file_share")) {
|
|
72235
|
-
if (
|
|
72255
|
+
if (this.isBotAuthored(event)) {
|
|
72236
72256
|
return;
|
|
72237
72257
|
}
|
|
72238
72258
|
if (event.channel !== this.channelId) {
|
|
@@ -72332,7 +72352,7 @@ class SlackClient extends BasePlatformClient {
|
|
|
72332
72352
|
log40.info(`Recovered ${messages.length} missed message(s)`);
|
|
72333
72353
|
const sortedMessages = messages.sort((a, b) => parseFloat(a.ts) - parseFloat(b.ts));
|
|
72334
72354
|
for (const message of sortedMessages) {
|
|
72335
|
-
if (
|
|
72355
|
+
if (this.isBotAuthored(message)) {
|
|
72336
72356
|
continue;
|
|
72337
72357
|
}
|
|
72338
72358
|
this.lastProcessedTs = message.ts;
|
|
@@ -72350,6 +72370,7 @@ class SlackClient extends BasePlatformClient {
|
|
|
72350
72370
|
async fetchBotUser() {
|
|
72351
72371
|
const response = await this.api("POST", "auth.test");
|
|
72352
72372
|
this.botUserId = response.user_id;
|
|
72373
|
+
this.teamId = response.team_id ?? null;
|
|
72353
72374
|
this.teamUrl = response.url.replace(/\/$/, "");
|
|
72354
72375
|
const userResponse = await this.api("GET", `users.info?user=${response.user_id}`);
|
|
72355
72376
|
this.botUser = userResponse.user;
|
|
@@ -72559,7 +72580,7 @@ class SlackClient extends BasePlatformClient {
|
|
|
72559
72580
|
const cursorParam = cursor ? `&cursor=${encodeURIComponent(cursor)}` : "";
|
|
72560
72581
|
const response = await this.api("GET", `conversations.replies?channel=${this.channelId}&ts=${threadId}&limit=1000${cursorParam}`);
|
|
72561
72582
|
for (const msg of response.messages || []) {
|
|
72562
|
-
if (options?.excludeBotMessages &&
|
|
72583
|
+
if (options?.excludeBotMessages && this.isBotAuthored(msg))
|
|
72563
72584
|
continue;
|
|
72564
72585
|
filtered.push(msg);
|
|
72565
72586
|
}
|
package/dist/mcp/mcp-server.js
CHANGED
|
@@ -3035,10 +3035,12 @@ var require_data = __commonJS((exports, module) => {
|
|
|
3035
3035
|
var require_utils = __commonJS((exports, module) => {
|
|
3036
3036
|
var isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu);
|
|
3037
3037
|
var isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u);
|
|
3038
|
+
var isPort = RegExp.prototype.test.bind(/^\d*$/u);
|
|
3038
3039
|
var isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu);
|
|
3039
3040
|
var isUnreserved = RegExp.prototype.test.bind(/^[\da-z\-._~]$/iu);
|
|
3040
|
-
var isPathCharacter = RegExp.prototype.test.bind(/^[
|
|
3041
|
-
var isQueryFragmentCharacter = RegExp.prototype.test.bind(/^[
|
|
3041
|
+
var isPathCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:@/]$/u);
|
|
3042
|
+
var isQueryFragmentCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:@/?]$/u);
|
|
3043
|
+
var isUserinfoCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:]$/u);
|
|
3042
3044
|
function stringArrayToHexStripped(input) {
|
|
3043
3045
|
let acc = "";
|
|
3044
3046
|
let code = 0;
|
|
@@ -3063,91 +3065,127 @@ var require_utils = __commonJS((exports, module) => {
|
|
|
3063
3065
|
}
|
|
3064
3066
|
return acc;
|
|
3065
3067
|
}
|
|
3068
|
+
var isHextet = RegExp.prototype.test.bind(/^[\dA-Fa-f]{1,4}$/);
|
|
3069
|
+
var isIPvFuture = RegExp.prototype.test.bind(/^[vV][\dA-Fa-f]+\.[A-Za-z\d\-._~!$&'()*+,;=:]+$/);
|
|
3070
|
+
var isZoneCharacter = RegExp.prototype.test.bind(/^[A-Za-z\d\-._~]$/);
|
|
3066
3071
|
var nonSimpleDomain = RegExp.prototype.test.bind(/[^!"$&'()*+,\-.;=_`a-z{}~]/u);
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3072
|
+
var nonSimpleDomainChars = RegExp.prototype.test.bind(/[^\d!"$&'()*+,\-.;=_`a-z{}~]/u);
|
|
3073
|
+
var numericLastLabel = RegExp.prototype.test.bind(/(?:^|\.)\d+$/u);
|
|
3074
|
+
function nonSimpleMailtoDomain(domain) {
|
|
3075
|
+
return nonSimpleDomainChars(domain) || numericLastLabel(domain);
|
|
3070
3076
|
}
|
|
3071
|
-
function
|
|
3072
|
-
if (
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3077
|
+
function isZoneIdentifier(zone) {
|
|
3078
|
+
if (zone.length === 0)
|
|
3079
|
+
return false;
|
|
3080
|
+
for (let i = 0;i < zone.length; i++) {
|
|
3081
|
+
if (isZoneCharacter(zone[i]))
|
|
3082
|
+
continue;
|
|
3083
|
+
if (zone[i] === "%" && i + 2 < zone.length && isHexPair(zone.slice(i + 1, i + 3))) {
|
|
3084
|
+
i += 2;
|
|
3085
|
+
continue;
|
|
3079
3086
|
}
|
|
3080
|
-
|
|
3087
|
+
return false;
|
|
3081
3088
|
}
|
|
3082
3089
|
return true;
|
|
3083
3090
|
}
|
|
3084
|
-
function
|
|
3085
|
-
let
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
let
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
if (cursor === ":") {
|
|
3098
|
-
if (endipv6Encountered === true) {
|
|
3099
|
-
endIpv6 = true;
|
|
3100
|
-
}
|
|
3101
|
-
if (!consume(buffer, address, output)) {
|
|
3102
|
-
break;
|
|
3091
|
+
function compressIPv6ZeroRun(hextets) {
|
|
3092
|
+
let bestStart = -1;
|
|
3093
|
+
let bestLength = 0;
|
|
3094
|
+
let runStart = -1;
|
|
3095
|
+
let runLength = 0;
|
|
3096
|
+
for (let i = 0;i < hextets.length; i++) {
|
|
3097
|
+
if (hextets[i] === "0") {
|
|
3098
|
+
if (runStart === -1)
|
|
3099
|
+
runStart = i;
|
|
3100
|
+
runLength++;
|
|
3101
|
+
if (runLength > bestLength) {
|
|
3102
|
+
bestLength = runLength;
|
|
3103
|
+
bestStart = runStart;
|
|
3103
3104
|
}
|
|
3104
|
-
if (++tokenCount > 7) {
|
|
3105
|
-
output.error = true;
|
|
3106
|
-
break;
|
|
3107
|
-
}
|
|
3108
|
-
if (i > 0 && input[i - 1] === ":") {
|
|
3109
|
-
endipv6Encountered = true;
|
|
3110
|
-
}
|
|
3111
|
-
address.push(":");
|
|
3112
|
-
continue;
|
|
3113
|
-
} else if (cursor === "%") {
|
|
3114
|
-
if (!consume(buffer, address, output)) {
|
|
3115
|
-
break;
|
|
3116
|
-
}
|
|
3117
|
-
consume = consumeIsZone;
|
|
3118
3105
|
} else {
|
|
3119
|
-
|
|
3120
|
-
|
|
3106
|
+
runStart = -1;
|
|
3107
|
+
runLength = 0;
|
|
3121
3108
|
}
|
|
3122
3109
|
}
|
|
3123
|
-
if (
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3110
|
+
if (bestLength < 2)
|
|
3111
|
+
return hextets.join(":");
|
|
3112
|
+
const head = hextets.slice(0, bestStart).join(":");
|
|
3113
|
+
const tail = hextets.slice(bestStart + bestLength).join(":");
|
|
3114
|
+
return head + "::" + tail;
|
|
3115
|
+
}
|
|
3116
|
+
function normalizeIPv6Address(input) {
|
|
3117
|
+
const compression = input.indexOf("::");
|
|
3118
|
+
if (compression !== -1 && input.indexOf("::", compression + 1) !== -1)
|
|
3119
|
+
return;
|
|
3120
|
+
const left = compression === -1 ? input.split(":") : input.slice(0, compression).split(":");
|
|
3121
|
+
const right = compression === -1 ? [] : input.slice(compression + 2).split(":");
|
|
3122
|
+
if (compression !== -1) {
|
|
3123
|
+
if (left.length === 1 && left[0] === "")
|
|
3124
|
+
left.length = 0;
|
|
3125
|
+
if (right.length === 1 && right[0] === "")
|
|
3126
|
+
right.length = 0;
|
|
3127
|
+
}
|
|
3128
|
+
const parts = left.concat(right);
|
|
3129
|
+
let hextetCount = 0;
|
|
3130
|
+
for (let i = 0;i < parts.length; i++) {
|
|
3131
|
+
const part = parts[i];
|
|
3132
|
+
if (part === "")
|
|
3133
|
+
return;
|
|
3134
|
+
if (part.indexOf(".") !== -1) {
|
|
3135
|
+
if (i !== parts.length - 1 || compression !== -1 && right.length === 0 || !isIPv4(part))
|
|
3136
|
+
return;
|
|
3137
|
+
hextetCount += 2;
|
|
3138
|
+
continue;
|
|
3130
3139
|
}
|
|
3140
|
+
if (!isHextet(part))
|
|
3141
|
+
return;
|
|
3142
|
+
parts[i] = parseInt(part, 16).toString(16);
|
|
3143
|
+
hextetCount++;
|
|
3131
3144
|
}
|
|
3132
|
-
|
|
3133
|
-
|
|
3145
|
+
if (compression === -1) {
|
|
3146
|
+
if (hextetCount !== 8)
|
|
3147
|
+
return;
|
|
3148
|
+
return compressIPv6ZeroRun(parts);
|
|
3149
|
+
}
|
|
3150
|
+
if (hextetCount >= 8)
|
|
3151
|
+
return;
|
|
3152
|
+
const expanded = parts.slice(0, left.length);
|
|
3153
|
+
for (let i = hextetCount;i < 8; i++)
|
|
3154
|
+
expanded.push("0");
|
|
3155
|
+
for (let i = left.length;i < parts.length; i++)
|
|
3156
|
+
expanded.push(parts[i]);
|
|
3157
|
+
return compressIPv6ZeroRun(expanded);
|
|
3134
3158
|
}
|
|
3135
3159
|
function normalizeIPv6(host) {
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
}
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3160
|
+
const bracketed = host[0] === "[" && host[host.length - 1] === "]";
|
|
3161
|
+
const hasBracket = host[0] === "[" || host[host.length - 1] === "]";
|
|
3162
|
+
if (hasBracket && !bracketed)
|
|
3163
|
+
return { host, isIPV6: false, error: true };
|
|
3164
|
+
let input = bracketed ? host.slice(1, -1) : host;
|
|
3165
|
+
if (bracketed && isIPvFuture(input)) {
|
|
3166
|
+
input = input.toLowerCase();
|
|
3167
|
+
return { host: `[${input}]`, escapedHost: input, isIPV6: false, isIPVFuture: true };
|
|
3168
|
+
}
|
|
3169
|
+
if (findToken(input, ":") < 2) {
|
|
3170
|
+
return { host, isIPV6: false, error: bracketed };
|
|
3171
|
+
}
|
|
3172
|
+
let zoneIdentifier = "";
|
|
3173
|
+
const zoneSeparator = input.indexOf("%");
|
|
3174
|
+
if (zoneSeparator !== -1) {
|
|
3175
|
+
const separatorLength = input.slice(zoneSeparator, zoneSeparator + 3).toLowerCase() === "%25" ? 3 : 1;
|
|
3176
|
+
zoneIdentifier = input.slice(zoneSeparator + separatorLength);
|
|
3177
|
+
if (!isZoneIdentifier(zoneIdentifier))
|
|
3178
|
+
return { host, isIPV6: false, error: true };
|
|
3179
|
+
input = input.slice(0, zoneSeparator);
|
|
3180
|
+
}
|
|
3181
|
+
const address = normalizeIPv6Address(input);
|
|
3182
|
+
if (address === undefined)
|
|
3183
|
+
return { host, isIPV6: false, error: true };
|
|
3184
|
+
return {
|
|
3185
|
+
host: address + (zoneIdentifier ? "%" + zoneIdentifier : ""),
|
|
3186
|
+
escapedHost: address + (zoneIdentifier ? "%25" + zoneIdentifier : ""),
|
|
3187
|
+
isIPV6: true
|
|
3188
|
+
};
|
|
3151
3189
|
}
|
|
3152
3190
|
function findToken(str, token) {
|
|
3153
3191
|
let ind = 0;
|
|
@@ -3324,6 +3362,45 @@ var require_utils = __commonJS((exports, module) => {
|
|
|
3324
3362
|
}
|
|
3325
3363
|
return output;
|
|
3326
3364
|
}
|
|
3365
|
+
function serializePathEncoding(input, pathNoScheme = false) {
|
|
3366
|
+
let output = "";
|
|
3367
|
+
let firstSegment = pathNoScheme && input[0] !== "/";
|
|
3368
|
+
for (let i = 0;i < input.length; i++) {
|
|
3369
|
+
const ch = input[i];
|
|
3370
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
3371
|
+
const hex = input.slice(i + 1, i + 3);
|
|
3372
|
+
if (isHexPair(hex)) {
|
|
3373
|
+
output += "%" + hex.toUpperCase();
|
|
3374
|
+
i += 2;
|
|
3375
|
+
continue;
|
|
3376
|
+
}
|
|
3377
|
+
}
|
|
3378
|
+
if (ch === "/") {
|
|
3379
|
+
firstSegment = false;
|
|
3380
|
+
}
|
|
3381
|
+
if (isPathCharacter(ch) && (ch !== ":" || !firstSegment)) {
|
|
3382
|
+
output += ch;
|
|
3383
|
+
} else {
|
|
3384
|
+
const code = input.charCodeAt(i);
|
|
3385
|
+
if (code < 128) {
|
|
3386
|
+
output += BYTE_HEX[code];
|
|
3387
|
+
} else if (code < 55296 || code > 57343) {
|
|
3388
|
+
output += percentEncodeNonAscii(code);
|
|
3389
|
+
} else if (code <= 56319 && i + 1 < input.length) {
|
|
3390
|
+
const low = input.charCodeAt(i + 1);
|
|
3391
|
+
if (low >= 56320 && low <= 57343) {
|
|
3392
|
+
output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
3393
|
+
i++;
|
|
3394
|
+
} else {
|
|
3395
|
+
output += percentEncodeNonAscii(65533);
|
|
3396
|
+
}
|
|
3397
|
+
} else {
|
|
3398
|
+
output += percentEncodeNonAscii(65533);
|
|
3399
|
+
}
|
|
3400
|
+
}
|
|
3401
|
+
}
|
|
3402
|
+
return output;
|
|
3403
|
+
}
|
|
3327
3404
|
function normalizeQueryFragmentEncoding(input) {
|
|
3328
3405
|
let output = "";
|
|
3329
3406
|
for (let i = 0;i < input.length; i++) {
|
|
@@ -3365,6 +3442,50 @@ var require_utils = __commonJS((exports, module) => {
|
|
|
3365
3442
|
}
|
|
3366
3443
|
return output;
|
|
3367
3444
|
}
|
|
3445
|
+
function encodeComponent(input, isAllowed) {
|
|
3446
|
+
let output = "";
|
|
3447
|
+
for (let i = 0;i < input.length; i++) {
|
|
3448
|
+
const ch = input[i];
|
|
3449
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
3450
|
+
const hex = input.slice(i + 1, i + 3);
|
|
3451
|
+
if (isHexPair(hex)) {
|
|
3452
|
+
output += "%" + hex.toUpperCase();
|
|
3453
|
+
i += 2;
|
|
3454
|
+
continue;
|
|
3455
|
+
}
|
|
3456
|
+
}
|
|
3457
|
+
if (isAllowed(ch)) {
|
|
3458
|
+
output += ch;
|
|
3459
|
+
} else {
|
|
3460
|
+
const code = input.charCodeAt(i);
|
|
3461
|
+
if (code < 128) {
|
|
3462
|
+
output += BYTE_HEX[code];
|
|
3463
|
+
} else if (code < 55296 || code > 57343) {
|
|
3464
|
+
output += percentEncodeNonAscii(code);
|
|
3465
|
+
} else if (code <= 56319 && i + 1 < input.length) {
|
|
3466
|
+
const low = input.charCodeAt(i + 1);
|
|
3467
|
+
if (low >= 56320 && low <= 57343) {
|
|
3468
|
+
output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
3469
|
+
i++;
|
|
3470
|
+
} else {
|
|
3471
|
+
output += percentEncodeNonAscii(65533);
|
|
3472
|
+
}
|
|
3473
|
+
} else {
|
|
3474
|
+
output += percentEncodeNonAscii(65533);
|
|
3475
|
+
}
|
|
3476
|
+
}
|
|
3477
|
+
}
|
|
3478
|
+
return output;
|
|
3479
|
+
}
|
|
3480
|
+
function encodeUserinfo(input) {
|
|
3481
|
+
return encodeComponent(input, isUserinfoCharacter);
|
|
3482
|
+
}
|
|
3483
|
+
function encodeQuery(input) {
|
|
3484
|
+
return encodeComponent(input, isQueryFragmentCharacter);
|
|
3485
|
+
}
|
|
3486
|
+
function encodeFragment(input) {
|
|
3487
|
+
return encodeComponent(input, isQueryFragmentCharacter);
|
|
3488
|
+
}
|
|
3368
3489
|
function escapePreservingEscapes(input) {
|
|
3369
3490
|
let output = "";
|
|
3370
3491
|
for (let i = 0;i < input.length; i++) {
|
|
@@ -3399,14 +3520,18 @@ var require_utils = __commonJS((exports, module) => {
|
|
|
3399
3520
|
function recomposeAuthority(component) {
|
|
3400
3521
|
const uriTokens = [];
|
|
3401
3522
|
if (component.userinfo !== undefined) {
|
|
3402
|
-
uriTokens.push(component.userinfo);
|
|
3523
|
+
uriTokens.push(encodeUserinfo(component.userinfo));
|
|
3403
3524
|
uriTokens.push("@");
|
|
3404
3525
|
}
|
|
3405
3526
|
if (component.host !== undefined) {
|
|
3406
|
-
let host =
|
|
3527
|
+
let host = component.host;
|
|
3407
3528
|
if (!isIPv4(host)) {
|
|
3408
|
-
|
|
3409
|
-
if (ipV6res.isIPV6
|
|
3529
|
+
let ipV6res = normalizeIPv6(host);
|
|
3530
|
+
if (ipV6res.isIPV6 !== true && ipV6res.isIPVFuture !== true) {
|
|
3531
|
+
host = normalizePercentEncoding(host, true);
|
|
3532
|
+
ipV6res = normalizeIPv6(host);
|
|
3533
|
+
}
|
|
3534
|
+
if (ipV6res.isIPV6 === true || ipV6res.isIPVFuture === true) {
|
|
3410
3535
|
host = `[${ipV6res.escapedHost}]`;
|
|
3411
3536
|
} else {
|
|
3412
3537
|
host = reescapeHostDelimiters(host, false);
|
|
@@ -3415,18 +3540,29 @@ var require_utils = __commonJS((exports, module) => {
|
|
|
3415
3540
|
uriTokens.push(host);
|
|
3416
3541
|
}
|
|
3417
3542
|
if (typeof component.port === "number" || typeof component.port === "string") {
|
|
3543
|
+
const port = String(component.port);
|
|
3544
|
+
if (!isPort(port)) {
|
|
3545
|
+
throw new TypeError("URI port is malformed.");
|
|
3546
|
+
}
|
|
3418
3547
|
uriTokens.push(":");
|
|
3419
|
-
uriTokens.push(
|
|
3548
|
+
uriTokens.push(port);
|
|
3420
3549
|
}
|
|
3421
3550
|
return uriTokens.length ? uriTokens.join("") : undefined;
|
|
3422
3551
|
}
|
|
3423
3552
|
module.exports = {
|
|
3553
|
+
BYTE_HEX,
|
|
3554
|
+
percentEncodeNonAscii,
|
|
3424
3555
|
nonSimpleDomain,
|
|
3556
|
+
nonSimpleMailtoDomain,
|
|
3425
3557
|
recomposeAuthority,
|
|
3426
3558
|
reescapeHostDelimiters,
|
|
3427
3559
|
normalizePercentEncoding,
|
|
3428
3560
|
normalizePathEncoding,
|
|
3561
|
+
serializePathEncoding,
|
|
3429
3562
|
normalizeQueryFragmentEncoding,
|
|
3563
|
+
encodeUserinfo,
|
|
3564
|
+
encodeQuery,
|
|
3565
|
+
encodeFragment,
|
|
3430
3566
|
escapePreservingEscapes,
|
|
3431
3567
|
removeDotSegments,
|
|
3432
3568
|
isIPv4,
|
|
@@ -3438,15 +3574,16 @@ var require_utils = __commonJS((exports, module) => {
|
|
|
3438
3574
|
|
|
3439
3575
|
// node_modules/fast-uri/lib/schemes.js
|
|
3440
3576
|
var require_schemes = __commonJS((exports, module) => {
|
|
3441
|
-
var { isUUID } = require_utils();
|
|
3442
|
-
var URN_REG =
|
|
3577
|
+
var { isUUID, BYTE_HEX, percentEncodeNonAscii, nonSimpleMailtoDomain } = require_utils();
|
|
3578
|
+
var URN_REG = /^([\da-z][\d\-a-z]{0,31}):((?:[\w!$'()*+,\-./:;=@]|%[\da-f]{2})+)$/iu;
|
|
3443
3579
|
var supportedSchemeNames = [
|
|
3444
3580
|
"http",
|
|
3445
3581
|
"https",
|
|
3446
3582
|
"ws",
|
|
3447
3583
|
"wss",
|
|
3448
3584
|
"urn",
|
|
3449
|
-
"urn:uuid"
|
|
3585
|
+
"urn:uuid",
|
|
3586
|
+
"mailto"
|
|
3450
3587
|
];
|
|
3451
3588
|
function isValidSchemeName(name) {
|
|
3452
3589
|
return supportedSchemeNames.indexOf(name) !== -1;
|
|
@@ -3494,9 +3631,10 @@ var require_schemes = __commonJS((exports, module) => {
|
|
|
3494
3631
|
wsComponent.secure = undefined;
|
|
3495
3632
|
}
|
|
3496
3633
|
if (wsComponent.resourceName) {
|
|
3497
|
-
const
|
|
3634
|
+
const queryIndex = wsComponent.resourceName.indexOf("?");
|
|
3635
|
+
const path = queryIndex === -1 ? wsComponent.resourceName : wsComponent.resourceName.slice(0, queryIndex);
|
|
3498
3636
|
wsComponent.path = path && path !== "/" ? path : undefined;
|
|
3499
|
-
wsComponent.query =
|
|
3637
|
+
wsComponent.query = queryIndex === -1 ? undefined : wsComponent.resourceName.slice(queryIndex + 1);
|
|
3500
3638
|
wsComponent.resourceName = undefined;
|
|
3501
3639
|
}
|
|
3502
3640
|
wsComponent.fragment = undefined;
|
|
@@ -3508,7 +3646,7 @@ var require_schemes = __commonJS((exports, module) => {
|
|
|
3508
3646
|
return urnComponent;
|
|
3509
3647
|
}
|
|
3510
3648
|
const matches = urnComponent.path.match(URN_REG);
|
|
3511
|
-
if (matches) {
|
|
3649
|
+
if (matches && matches[0] === urnComponent.path) {
|
|
3512
3650
|
const scheme = options.scheme || urnComponent.scheme || "urn";
|
|
3513
3651
|
urnComponent.nid = matches[1].toLowerCase();
|
|
3514
3652
|
urnComponent.nss = matches[2];
|
|
@@ -3590,13 +3728,235 @@ var require_schemes = __commonJS((exports, module) => {
|
|
|
3590
3728
|
serialize: urnuuidSerialize,
|
|
3591
3729
|
skipNormalize: true
|
|
3592
3730
|
};
|
|
3731
|
+
var LOCAL_PART_ALLOWED = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$'()*+=";
|
|
3732
|
+
var HFNAME_ALLOWED = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$'()*+,;:@";
|
|
3733
|
+
var DTEXT_ALLOWED = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$'()*+;:";
|
|
3734
|
+
function allowSet(chars, allowNonAscii = false) {
|
|
3735
|
+
const table = new Uint8Array(128);
|
|
3736
|
+
for (let i = 0;i < chars.length; i++) {
|
|
3737
|
+
table[chars.charCodeAt(i)] = 1;
|
|
3738
|
+
}
|
|
3739
|
+
const escaped = chars.replace(/[\\\]^-]/gu, "\\$&");
|
|
3740
|
+
const cls = allowNonAscii ? `[${escaped}]|[^\\0-\\x7F\\uD800-\\uDFFF]` : `[${escaped}]`;
|
|
3741
|
+
return { all: new RegExp(`^(?:${cls})*$`, "u"), table, allowNonAscii };
|
|
3742
|
+
}
|
|
3743
|
+
var LOCAL_PART = allowSet(LOCAL_PART_ALLOWED);
|
|
3744
|
+
var HFNAME = allowSet(HFNAME_ALLOWED);
|
|
3745
|
+
var DTEXT = allowSet(DTEXT_ALLOWED);
|
|
3746
|
+
var DTEXT_IRI = allowSet(DTEXT_ALLOWED, true);
|
|
3747
|
+
var HEX_PAIR = /^[\da-f]{2}$/iu;
|
|
3748
|
+
var MAILTO_DOMAIN_LITERAL = /^\[[\x21-\x5A\x5E-\x7E]*\]$/u;
|
|
3749
|
+
var MAILTO_DOMAIN_ERROR = "URI mailto has an invalid recipient domain.";
|
|
3750
|
+
var HAS_SURROGATE = /[\uD800-\uDFFF]/u;
|
|
3751
|
+
function decodeHex(str) {
|
|
3752
|
+
if (typeof str !== "string" || str.indexOf("%") === -1) {
|
|
3753
|
+
return str;
|
|
3754
|
+
}
|
|
3755
|
+
try {
|
|
3756
|
+
return decodeURIComponent(str);
|
|
3757
|
+
} catch {
|
|
3758
|
+
return str;
|
|
3759
|
+
}
|
|
3760
|
+
}
|
|
3761
|
+
function replaceLoneSurrogates(input) {
|
|
3762
|
+
let result = "";
|
|
3763
|
+
for (let i = 0;i < input.length; i++) {
|
|
3764
|
+
const code = input.charCodeAt(i);
|
|
3765
|
+
if (code >= 55296 && code <= 56319 && i + 1 < input.length) {
|
|
3766
|
+
const low = input.charCodeAt(i + 1);
|
|
3767
|
+
if (low >= 56320 && low <= 57343) {
|
|
3768
|
+
result += input[i] + input[i + 1];
|
|
3769
|
+
i++;
|
|
3770
|
+
continue;
|
|
3771
|
+
}
|
|
3772
|
+
}
|
|
3773
|
+
result += code >= 55296 && code <= 57343 ? "�" : input[i];
|
|
3774
|
+
}
|
|
3775
|
+
return result;
|
|
3776
|
+
}
|
|
3777
|
+
function encodeWithAllow(input, set2) {
|
|
3778
|
+
if (set2.all.test(input)) {
|
|
3779
|
+
return input;
|
|
3780
|
+
}
|
|
3781
|
+
const table = set2.table;
|
|
3782
|
+
let result = "";
|
|
3783
|
+
for (let i = 0;i < input.length; i++) {
|
|
3784
|
+
const code = input.charCodeAt(i);
|
|
3785
|
+
if (code < 128) {
|
|
3786
|
+
if (table[code] === 1) {
|
|
3787
|
+
result += input[i];
|
|
3788
|
+
} else if (code === 37 && i + 2 < input.length && HEX_PAIR.test(input.slice(i + 1, i + 3))) {
|
|
3789
|
+
result += "%" + input.slice(i + 1, i + 3).toUpperCase();
|
|
3790
|
+
i += 2;
|
|
3791
|
+
} else {
|
|
3792
|
+
result += BYTE_HEX[code];
|
|
3793
|
+
}
|
|
3794
|
+
continue;
|
|
3795
|
+
}
|
|
3796
|
+
if (code < 55296 || code > 57343) {
|
|
3797
|
+
result += set2.allowNonAscii ? input[i] : percentEncodeNonAscii(code);
|
|
3798
|
+
continue;
|
|
3799
|
+
}
|
|
3800
|
+
if (code <= 56319 && i + 1 < input.length) {
|
|
3801
|
+
const low = input.charCodeAt(i + 1);
|
|
3802
|
+
if (low >= 56320 && low <= 57343) {
|
|
3803
|
+
result += set2.allowNonAscii ? input[i] + input[i + 1] : percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
3804
|
+
i++;
|
|
3805
|
+
continue;
|
|
3806
|
+
}
|
|
3807
|
+
}
|
|
3808
|
+
result += set2.allowNonAscii ? "�" : percentEncodeNonAscii(65533);
|
|
3809
|
+
}
|
|
3810
|
+
return result;
|
|
3811
|
+
}
|
|
3812
|
+
function mailtoNormalizeDomain(domain, options, component) {
|
|
3813
|
+
const normalizedDomain = String(domain).toLowerCase();
|
|
3814
|
+
if (MAILTO_DOMAIN_LITERAL.test(normalizedDomain)) {
|
|
3815
|
+
return normalizedDomain;
|
|
3816
|
+
}
|
|
3817
|
+
if (normalizedDomain !== "" && !nonSimpleMailtoDomain(normalizedDomain)) {
|
|
3818
|
+
return normalizedDomain;
|
|
3819
|
+
}
|
|
3820
|
+
try {
|
|
3821
|
+
const parsedDomain = new URL("http://" + normalizedDomain);
|
|
3822
|
+
if (parsedDomain.username || parsedDomain.password || parsedDomain.port || parsedDomain.pathname !== "/" || parsedDomain.search || parsedDomain.hash || !parsedDomain.hostname) {
|
|
3823
|
+
throw new Error(MAILTO_DOMAIN_ERROR);
|
|
3824
|
+
}
|
|
3825
|
+
return options && options.unicodeSupport ? normalizedDomain : parsedDomain.hostname;
|
|
3826
|
+
} catch {
|
|
3827
|
+
if (component) {
|
|
3828
|
+
component.error = component.error || MAILTO_DOMAIN_ERROR;
|
|
3829
|
+
}
|
|
3830
|
+
return normalizedDomain;
|
|
3831
|
+
}
|
|
3832
|
+
}
|
|
3833
|
+
function mailtoEncodeDomain(domain, options) {
|
|
3834
|
+
const set2 = options && options.unicodeSupport ? DTEXT_IRI : DTEXT;
|
|
3835
|
+
if (domain.length > 1 && domain[0] === "[" && domain[domain.length - 1] === "]") {
|
|
3836
|
+
return "[" + encodeWithAllow(domain.slice(1, -1), set2) + "]";
|
|
3837
|
+
}
|
|
3838
|
+
return encodeWithAllow(domain, set2);
|
|
3839
|
+
}
|
|
3840
|
+
function mailtoParse(component, options) {
|
|
3841
|
+
const mailtoComponent = component;
|
|
3842
|
+
let rawPath = mailtoComponent.path;
|
|
3843
|
+
let rawQuery = mailtoComponent.query;
|
|
3844
|
+
if (rawPath && HAS_SURROGATE.test(rawPath))
|
|
3845
|
+
rawPath = replaceLoneSurrogates(rawPath);
|
|
3846
|
+
if (rawQuery && HAS_SURROGATE.test(rawQuery))
|
|
3847
|
+
rawQuery = replaceLoneSurrogates(rawQuery);
|
|
3848
|
+
const to = rawPath ? rawPath.indexOf(",") === -1 ? [rawPath] : rawPath.split(",") : [];
|
|
3849
|
+
mailtoComponent.path = undefined;
|
|
3850
|
+
if (rawQuery) {
|
|
3851
|
+
let headers = null;
|
|
3852
|
+
let start = 0;
|
|
3853
|
+
while (start <= rawQuery.length) {
|
|
3854
|
+
let end = rawQuery.indexOf("&", start);
|
|
3855
|
+
if (end === -1)
|
|
3856
|
+
end = rawQuery.length;
|
|
3857
|
+
const token = rawQuery.slice(start, end);
|
|
3858
|
+
start = end + 1;
|
|
3859
|
+
const eqIdx = token.indexOf("=");
|
|
3860
|
+
if (eqIdx !== token.lastIndexOf("=")) {
|
|
3861
|
+
mailtoComponent.error = mailtoComponent.error || "URI mailto has malformed header fields.";
|
|
3862
|
+
continue;
|
|
3863
|
+
}
|
|
3864
|
+
const name = eqIdx === -1 ? token : token.slice(0, eqIdx);
|
|
3865
|
+
const value = eqIdx === -1 ? "" : token.slice(eqIdx + 1);
|
|
3866
|
+
if (name === "to") {
|
|
3867
|
+
const addrs = value.split(",");
|
|
3868
|
+
for (let j = 0;j < addrs.length; j++)
|
|
3869
|
+
to.push(addrs[j]);
|
|
3870
|
+
continue;
|
|
3871
|
+
}
|
|
3872
|
+
if (name === "subject") {
|
|
3873
|
+
mailtoComponent.subject = decodeHex(value);
|
|
3874
|
+
continue;
|
|
3875
|
+
}
|
|
3876
|
+
if (name === "body") {
|
|
3877
|
+
mailtoComponent.body = decodeHex(value);
|
|
3878
|
+
continue;
|
|
3879
|
+
}
|
|
3880
|
+
if (headers === null)
|
|
3881
|
+
headers = Object.create(null);
|
|
3882
|
+
headers[decodeHex(name)] = decodeHex(value);
|
|
3883
|
+
}
|
|
3884
|
+
if (headers !== null)
|
|
3885
|
+
mailtoComponent.headers = headers;
|
|
3886
|
+
}
|
|
3887
|
+
mailtoComponent.query = undefined;
|
|
3888
|
+
for (let i = 0;i < to.length; i++) {
|
|
3889
|
+
const rawAddr = to[i];
|
|
3890
|
+
const atIdx = rawAddr.lastIndexOf("@");
|
|
3891
|
+
if (atIdx < 0) {
|
|
3892
|
+
mailtoComponent.error = mailtoComponent.error || MAILTO_DOMAIN_ERROR;
|
|
3893
|
+
to[i] = decodeHex(rawAddr);
|
|
3894
|
+
continue;
|
|
3895
|
+
}
|
|
3896
|
+
const local = decodeHex(rawAddr.slice(0, atIdx));
|
|
3897
|
+
const domain = mailtoNormalizeDomain(decodeHex(rawAddr.slice(atIdx + 1)), options, mailtoComponent);
|
|
3898
|
+
to[i] = local + "@" + domain;
|
|
3899
|
+
}
|
|
3900
|
+
if (to.length)
|
|
3901
|
+
mailtoComponent.to = to;
|
|
3902
|
+
return mailtoComponent;
|
|
3903
|
+
}
|
|
3904
|
+
function mailtoSerialize(component, options) {
|
|
3905
|
+
const mailtoComponent = component;
|
|
3906
|
+
const to = Array.isArray(mailtoComponent.to) ? mailtoComponent.to.slice() : [];
|
|
3907
|
+
if (to.length) {
|
|
3908
|
+
for (let i = 0;i < to.length; i++) {
|
|
3909
|
+
const addr = String(to[i]);
|
|
3910
|
+
const atIdx = addr.lastIndexOf("@");
|
|
3911
|
+
const rawLocal = atIdx >= 0 ? addr.slice(0, atIdx) : addr;
|
|
3912
|
+
const rawDomain = atIdx >= 0 ? addr.slice(atIdx + 1) : "";
|
|
3913
|
+
const local = encodeWithAllow(rawLocal, LOCAL_PART);
|
|
3914
|
+
const decodedDomain = decodeHex(rawDomain);
|
|
3915
|
+
const normalizedDomain = mailtoNormalizeDomain(decodedDomain, options);
|
|
3916
|
+
to[i] = local + "@" + mailtoEncodeDomain(normalizedDomain, options);
|
|
3917
|
+
}
|
|
3918
|
+
mailtoComponent.path = to.join(",");
|
|
3919
|
+
options.skipEscape = true;
|
|
3920
|
+
} else {
|
|
3921
|
+
mailtoComponent.path = undefined;
|
|
3922
|
+
}
|
|
3923
|
+
const headers = mailtoComponent.headers && typeof mailtoComponent.headers === "object" ? Object.assign(Object.create(null), mailtoComponent.headers) : Object.create(null);
|
|
3924
|
+
if (mailtoComponent.subject)
|
|
3925
|
+
headers.subject = mailtoComponent.subject;
|
|
3926
|
+
if (mailtoComponent.body)
|
|
3927
|
+
headers.body = mailtoComponent.body;
|
|
3928
|
+
mailtoComponent.headers = headers;
|
|
3929
|
+
let query = "";
|
|
3930
|
+
let count = 0;
|
|
3931
|
+
for (const name in headers) {
|
|
3932
|
+
if (count++ !== 0)
|
|
3933
|
+
query += "&";
|
|
3934
|
+
query += encodeWithAllow(name, HFNAME) + "=" + encodeWithAllow(String(headers[name]), HFNAME);
|
|
3935
|
+
}
|
|
3936
|
+
if (count !== 0) {
|
|
3937
|
+
mailtoComponent.query = query;
|
|
3938
|
+
} else {
|
|
3939
|
+
mailtoComponent.headers = undefined;
|
|
3940
|
+
}
|
|
3941
|
+
return mailtoComponent;
|
|
3942
|
+
}
|
|
3943
|
+
var mailto = {
|
|
3944
|
+
scheme: "mailto",
|
|
3945
|
+
parse: mailtoParse,
|
|
3946
|
+
serialize: mailtoSerialize,
|
|
3947
|
+
domainHost: false,
|
|
3948
|
+
unicodeSupport: true,
|
|
3949
|
+
skipNormalize: true,
|
|
3950
|
+
absolutePath: true
|
|
3951
|
+
};
|
|
3593
3952
|
var SCHEMES = {
|
|
3594
3953
|
http,
|
|
3595
3954
|
https,
|
|
3596
3955
|
ws,
|
|
3597
3956
|
wss,
|
|
3598
3957
|
urn,
|
|
3599
|
-
"urn:uuid": urnuuid
|
|
3958
|
+
"urn:uuid": urnuuid,
|
|
3959
|
+
mailto
|
|
3600
3960
|
};
|
|
3601
3961
|
Object.setPrototypeOf(SCHEMES, null);
|
|
3602
3962
|
function getSchemeHandler(scheme) {
|
|
@@ -3612,8 +3972,17 @@ var require_schemes = __commonJS((exports, module) => {
|
|
|
3612
3972
|
|
|
3613
3973
|
// node_modules/fast-uri/index.js
|
|
3614
3974
|
var require_fast_uri = __commonJS((exports, module) => {
|
|
3615
|
-
var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, normalizeQueryFragmentEncoding,
|
|
3975
|
+
var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, serializePathEncoding, normalizeQueryFragmentEncoding, encodeQuery, encodeFragment, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
|
|
3616
3976
|
var { SCHEMES, getSchemeHandler } = require_schemes();
|
|
3977
|
+
var VALID_SCHEME = /^[A-Za-z][A-Za-z0-9+.-]*$/u;
|
|
3978
|
+
var MALFORMED_SCHEME_ERROR = "URI scheme is malformed.";
|
|
3979
|
+
function decodeValidScheme(scheme) {
|
|
3980
|
+
const decodedScheme = unescape(String(scheme));
|
|
3981
|
+
if (!VALID_SCHEME.test(decodedScheme)) {
|
|
3982
|
+
throw new TypeError(MALFORMED_SCHEME_ERROR);
|
|
3983
|
+
}
|
|
3984
|
+
return decodedScheme;
|
|
3985
|
+
}
|
|
3617
3986
|
function normalize(uri, options) {
|
|
3618
3987
|
if (typeof uri === "string") {
|
|
3619
3988
|
uri = normalizeString(uri, options);
|
|
@@ -3624,12 +3993,34 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3624
3993
|
}
|
|
3625
3994
|
function resolve(baseURI, relativeURI, options) {
|
|
3626
3995
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
3627
|
-
const {
|
|
3628
|
-
|
|
3629
|
-
|
|
3996
|
+
const {
|
|
3997
|
+
parsed: baseParsed,
|
|
3998
|
+
malformedAuthorityOrPort: baseMalformed,
|
|
3999
|
+
malformedPercentEncoding: baseMalformedPercentEncoding,
|
|
4000
|
+
malformedSchemeSpecific: baseMalformedSchemeSpecific,
|
|
4001
|
+
malformedHost: baseMalformedHost,
|
|
4002
|
+
malformedScheme: baseMalformedScheme
|
|
4003
|
+
} = parseWithStatus(baseURI, schemelessOptions);
|
|
4004
|
+
const {
|
|
4005
|
+
parsed: relativeParsed,
|
|
4006
|
+
malformedAuthorityOrPort: relativeMalformed,
|
|
4007
|
+
malformedPercentEncoding: relativeMalformedPercentEncoding,
|
|
4008
|
+
malformedSchemeSpecific: relativeMalformedSchemeSpecific,
|
|
4009
|
+
malformedHost: relativeMalformedHost,
|
|
4010
|
+
malformedScheme: relativeMalformedScheme
|
|
4011
|
+
} = parseWithStatus(relativeURI, schemelessOptions);
|
|
4012
|
+
if (baseMalformed || relativeMalformed || baseMalformedPercentEncoding || relativeMalformedPercentEncoding || baseMalformedSchemeSpecific || relativeMalformedSchemeSpecific || baseMalformedHost || relativeMalformedHost || baseMalformedScheme || relativeMalformedScheme) {
|
|
3630
4013
|
throw new Error(baseParsed.error || relativeParsed.error || "URI is malformed.");
|
|
3631
4014
|
}
|
|
3632
4015
|
const resolved = resolveComponent(baseParsed, relativeParsed, schemelessOptions, true);
|
|
4016
|
+
const resolvedSchemeHandler = getSchemeHandler(options && options.scheme || resolved.scheme);
|
|
4017
|
+
const resolvedHost = resolved.host;
|
|
4018
|
+
const resolvedHostIsIP = resolvedHost !== undefined && resolvedHost !== "" && (isIPv4(resolvedHost) || normalizeIPv6(resolvedHost).isIPV6);
|
|
4019
|
+
canonicalizeHost(resolved, options || {}, resolvedSchemeHandler, resolvedHostIsIP);
|
|
4020
|
+
const encodedASCIIHost = resolvedHost && resolvedHost.indexOf("%") !== -1 && !/\P{ASCII}/u.test(resolvedHost);
|
|
4021
|
+
if (resolved.error && !encodedASCIIHost) {
|
|
4022
|
+
throw new Error(resolved.error);
|
|
4023
|
+
}
|
|
3633
4024
|
schemelessOptions.skipEscape = true;
|
|
3634
4025
|
return serialize(resolved, schemelessOptions);
|
|
3635
4026
|
}
|
|
@@ -3689,7 +4080,7 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3689
4080
|
function equal(uriA, uriB, options) {
|
|
3690
4081
|
const normalizedA = normalizeComparableURI(uriA, options);
|
|
3691
4082
|
const normalizedB = normalizeComparableURI(uriB, options);
|
|
3692
|
-
return normalizedA !== undefined && normalizedB !== undefined && normalizedA
|
|
4083
|
+
return normalizedA !== undefined && normalizedB !== undefined && normalizedA === normalizedB;
|
|
3693
4084
|
}
|
|
3694
4085
|
function serialize(cmpts, opts) {
|
|
3695
4086
|
const component = {
|
|
@@ -3706,24 +4097,31 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3706
4097
|
reference: cmpts.reference,
|
|
3707
4098
|
resourceName: cmpts.resourceName,
|
|
3708
4099
|
secure: cmpts.secure,
|
|
4100
|
+
to: cmpts.to,
|
|
4101
|
+
subject: cmpts.subject,
|
|
4102
|
+
body: cmpts.body,
|
|
4103
|
+
headers: cmpts.headers,
|
|
3709
4104
|
error: ""
|
|
3710
4105
|
};
|
|
3711
4106
|
const options = Object.assign({}, opts);
|
|
3712
4107
|
const uriTokens = [];
|
|
4108
|
+
if (component.scheme) {
|
|
4109
|
+
component.scheme = decodeValidScheme(component.scheme);
|
|
4110
|
+
}
|
|
3713
4111
|
const schemeHandler = getSchemeHandler(options.scheme || component.scheme);
|
|
3714
4112
|
if (schemeHandler && schemeHandler.serialize)
|
|
3715
4113
|
schemeHandler.serialize(component, options);
|
|
4114
|
+
const hasAuthority = component.userinfo !== undefined || component.host !== undefined || component.port !== undefined;
|
|
4115
|
+
const pathNoScheme = !options.skipEscape && component.scheme === undefined && !hasAuthority;
|
|
3716
4116
|
if (component.path !== undefined) {
|
|
3717
4117
|
if (!options.skipEscape) {
|
|
3718
|
-
component.path =
|
|
3719
|
-
if (component.scheme !== undefined) {
|
|
3720
|
-
component.path = component.path.split("%3A").join(":");
|
|
3721
|
-
}
|
|
4118
|
+
component.path = serializePathEncoding(component.path, pathNoScheme);
|
|
3722
4119
|
} else {
|
|
3723
4120
|
component.path = normalizePercentEncoding(component.path);
|
|
3724
4121
|
}
|
|
3725
4122
|
}
|
|
3726
4123
|
if (options.reference !== "suffix" && component.scheme) {
|
|
4124
|
+
component.scheme = decodeValidScheme(component.scheme);
|
|
3727
4125
|
uriTokens.push(component.scheme, ":");
|
|
3728
4126
|
}
|
|
3729
4127
|
const authority = recomposeAuthority(component);
|
|
@@ -3741,16 +4139,19 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3741
4139
|
if (!options.absolutePath && (!schemeHandler || !schemeHandler.absolutePath)) {
|
|
3742
4140
|
s = removeDotSegments(s);
|
|
3743
4141
|
}
|
|
4142
|
+
if (pathNoScheme) {
|
|
4143
|
+
s = serializePathEncoding(s, true);
|
|
4144
|
+
}
|
|
3744
4145
|
if (authority === undefined && s[0] === "/" && s[1] === "/") {
|
|
3745
4146
|
s = "/%2F" + s.slice(2);
|
|
3746
4147
|
}
|
|
3747
4148
|
uriTokens.push(s);
|
|
3748
4149
|
}
|
|
3749
4150
|
if (component.query !== undefined) {
|
|
3750
|
-
uriTokens.push("?", component.query);
|
|
4151
|
+
uriTokens.push("?", encodeQuery(component.query));
|
|
3751
4152
|
}
|
|
3752
4153
|
if (component.fragment !== undefined) {
|
|
3753
|
-
uriTokens.push("#", component.fragment);
|
|
4154
|
+
uriTokens.push("#", encodeFragment(component.fragment));
|
|
3754
4155
|
}
|
|
3755
4156
|
return uriTokens.join("");
|
|
3756
4157
|
}
|
|
@@ -3766,6 +4167,37 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3766
4167
|
}
|
|
3767
4168
|
return;
|
|
3768
4169
|
}
|
|
4170
|
+
function hasMalformedPercentEncoding(component) {
|
|
4171
|
+
if (component === undefined)
|
|
4172
|
+
return false;
|
|
4173
|
+
let percent = component.indexOf("%");
|
|
4174
|
+
while (percent !== -1) {
|
|
4175
|
+
if (percent + 2 >= component.length || !/^[\da-f]{2}$/iu.test(component.slice(percent + 1, percent + 3))) {
|
|
4176
|
+
return true;
|
|
4177
|
+
}
|
|
4178
|
+
percent = component.indexOf("%", percent + 3);
|
|
4179
|
+
}
|
|
4180
|
+
return false;
|
|
4181
|
+
}
|
|
4182
|
+
function isIPLiteral(host) {
|
|
4183
|
+
return host[0] === "[" && host[host.length - 1] === "]";
|
|
4184
|
+
}
|
|
4185
|
+
function hasMalformedComponentPercentEncoding(matches) {
|
|
4186
|
+
const host = matches[4];
|
|
4187
|
+
return hasMalformedPercentEncoding(matches[3]) || host !== undefined && !isIPLiteral(host) && hasMalformedPercentEncoding(host) || hasMalformedPercentEncoding(matches[6]) || hasMalformedPercentEncoding(matches[7]) || hasMalformedPercentEncoding(matches[8]);
|
|
4188
|
+
}
|
|
4189
|
+
function canonicalizeHost(parsed, options, schemeHandler, isIP) {
|
|
4190
|
+
const bracketedIPLiteral = parsed.host && parsed.host[0] === "[" && parsed.host[parsed.host.length - 1] === "]";
|
|
4191
|
+
if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport) && parsed.host && !isIPLiteral(parsed.host) && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP === false && !bracketedIPLiteral && nonSimpleDomain(parsed.host)) {
|
|
4192
|
+
try {
|
|
4193
|
+
parsed.host = new URL("http://" + parsed.host).hostname;
|
|
4194
|
+
} catch (e) {
|
|
4195
|
+
parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e;
|
|
4196
|
+
return true;
|
|
4197
|
+
}
|
|
4198
|
+
}
|
|
4199
|
+
return false;
|
|
4200
|
+
}
|
|
3769
4201
|
function parseWithStatus(uri, opts) {
|
|
3770
4202
|
const options = Object.assign({}, opts);
|
|
3771
4203
|
const parsed = {
|
|
@@ -3778,6 +4210,11 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3778
4210
|
fragment: undefined
|
|
3779
4211
|
};
|
|
3780
4212
|
let malformedAuthorityOrPort = false;
|
|
4213
|
+
let malformedPercentEncoding = false;
|
|
4214
|
+
let malformedSchemeSpecific = false;
|
|
4215
|
+
let malformedHost = false;
|
|
4216
|
+
let malformedIPLiteral = false;
|
|
4217
|
+
let malformedScheme = false;
|
|
3781
4218
|
let isIP = false;
|
|
3782
4219
|
if (options.reference === "suffix") {
|
|
3783
4220
|
if (options.scheme) {
|
|
@@ -3807,13 +4244,26 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3807
4244
|
}
|
|
3808
4245
|
const matches = uri.match(URI_PARSE);
|
|
3809
4246
|
if (matches) {
|
|
3810
|
-
parsed.scheme = matches[1]
|
|
4247
|
+
parsed.scheme = matches[1];
|
|
3811
4248
|
parsed.userinfo = matches[3];
|
|
3812
4249
|
parsed.host = matches[4];
|
|
3813
4250
|
parsed.port = parseInt(matches[5], 10);
|
|
3814
4251
|
parsed.path = matches[6] || "";
|
|
3815
4252
|
parsed.query = matches[7];
|
|
3816
4253
|
parsed.fragment = matches[8];
|
|
4254
|
+
if (parsed.scheme !== undefined) {
|
|
4255
|
+
const decodedScheme = unescape(parsed.scheme);
|
|
4256
|
+
if (VALID_SCHEME.test(decodedScheme)) {
|
|
4257
|
+
parsed.scheme = decodedScheme.toLowerCase();
|
|
4258
|
+
} else {
|
|
4259
|
+
parsed.error = parsed.error || MALFORMED_SCHEME_ERROR;
|
|
4260
|
+
malformedScheme = true;
|
|
4261
|
+
}
|
|
4262
|
+
}
|
|
4263
|
+
malformedPercentEncoding = hasMalformedComponentPercentEncoding(matches);
|
|
4264
|
+
if (malformedPercentEncoding) {
|
|
4265
|
+
parsed.error = parsed.error || "URI contains malformed percent-encoding.";
|
|
4266
|
+
}
|
|
3817
4267
|
if (isNaN(parsed.port)) {
|
|
3818
4268
|
parsed.port = matches[5];
|
|
3819
4269
|
}
|
|
@@ -3825,9 +4275,16 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3825
4275
|
if (parsed.host) {
|
|
3826
4276
|
const ipv4result = isIPv4(parsed.host);
|
|
3827
4277
|
if (ipv4result === false) {
|
|
4278
|
+
const bracketedIPLiteral = isIPLiteral(parsed.host);
|
|
4279
|
+
const hasIPLiteralBracket = parsed.host.indexOf("[") !== -1 || parsed.host.indexOf("]") !== -1;
|
|
3828
4280
|
const ipv6result = normalizeIPv6(parsed.host);
|
|
3829
|
-
|
|
3830
|
-
|
|
4281
|
+
isIP = ipv6result.isIPV6 || ipv6result.isIPVFuture === true;
|
|
4282
|
+
malformedIPLiteral = hasIPLiteralBracket && (!bracketedIPLiteral || ipv6result.error === true);
|
|
4283
|
+
parsed.host = isIP ? ipv6result.host : ipv6result.host.toLowerCase();
|
|
4284
|
+
if (malformedIPLiteral) {
|
|
4285
|
+
parsed.error = parsed.error || "URI host is malformed.";
|
|
4286
|
+
malformedAuthorityOrPort = true;
|
|
4287
|
+
}
|
|
3831
4288
|
} else {
|
|
3832
4289
|
isIP = true;
|
|
3833
4290
|
}
|
|
@@ -3845,22 +4302,14 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3845
4302
|
parsed.error = parsed.error || "URI is not a " + options.reference + " reference.";
|
|
3846
4303
|
}
|
|
3847
4304
|
const schemeHandler = getSchemeHandler(options.scheme || parsed.scheme);
|
|
3848
|
-
if (!
|
|
3849
|
-
|
|
3850
|
-
try {
|
|
3851
|
-
parsed.host = new URL("http://" + parsed.host).hostname;
|
|
3852
|
-
} catch (e) {
|
|
3853
|
-
parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e;
|
|
3854
|
-
}
|
|
3855
|
-
}
|
|
4305
|
+
if (!malformedIPLiteral) {
|
|
4306
|
+
malformedHost = canonicalizeHost(parsed, options, schemeHandler, isIP);
|
|
3856
4307
|
}
|
|
3857
4308
|
if (!schemeHandler || schemeHandler && !schemeHandler.skipNormalize) {
|
|
3858
4309
|
if (uri.indexOf("%") !== -1) {
|
|
3859
|
-
if (parsed.
|
|
3860
|
-
parsed.
|
|
3861
|
-
|
|
3862
|
-
if (parsed.host !== undefined) {
|
|
3863
|
-
parsed.host = reescapeHostDelimiters(unescape(parsed.host), isIP);
|
|
4310
|
+
if (parsed.host !== undefined && !malformedIPLiteral) {
|
|
4311
|
+
const host = isIP ? parsed.host : normalizePercentEncoding(parsed.host, true);
|
|
4312
|
+
parsed.host = reescapeHostDelimiters(host, isIP);
|
|
3864
4313
|
}
|
|
3865
4314
|
}
|
|
3866
4315
|
if (parsed.path) {
|
|
@@ -3875,11 +4324,14 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3875
4324
|
}
|
|
3876
4325
|
if (schemeHandler && schemeHandler.parse) {
|
|
3877
4326
|
schemeHandler.parse(parsed, options);
|
|
4327
|
+
if (schemeHandler === SCHEMES.urn && parsed.nid === undefined) {
|
|
4328
|
+
malformedSchemeSpecific = true;
|
|
4329
|
+
}
|
|
3878
4330
|
}
|
|
3879
4331
|
} else {
|
|
3880
4332
|
parsed.error = parsed.error || "URI can not be parsed.";
|
|
3881
4333
|
}
|
|
3882
|
-
return { parsed, malformedAuthorityOrPort };
|
|
4334
|
+
return { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme };
|
|
3883
4335
|
}
|
|
3884
4336
|
function parse6(uri, opts) {
|
|
3885
4337
|
return parseWithStatus(uri, opts).parsed;
|
|
@@ -3888,20 +4340,28 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3888
4340
|
return normalizeStringWithStatus(uri, opts).normalized;
|
|
3889
4341
|
}
|
|
3890
4342
|
function normalizeStringWithStatus(uri, opts) {
|
|
3891
|
-
const { parsed, malformedAuthorityOrPort } = parseWithStatus(uri, opts);
|
|
4343
|
+
const { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = parseWithStatus(uri, opts);
|
|
3892
4344
|
return {
|
|
3893
|
-
normalized: malformedAuthorityOrPort ? uri : serialize(parsed, opts),
|
|
3894
|
-
malformedAuthorityOrPort
|
|
4345
|
+
normalized: malformedAuthorityOrPort || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? uri : serialize(parsed, opts),
|
|
4346
|
+
malformedAuthorityOrPort,
|
|
4347
|
+
malformedPercentEncoding,
|
|
4348
|
+
malformedSchemeSpecific,
|
|
4349
|
+
malformedHost,
|
|
4350
|
+
malformedScheme
|
|
3895
4351
|
};
|
|
3896
4352
|
}
|
|
3897
4353
|
function normalizeComparableURI(uri, opts) {
|
|
3898
|
-
if (typeof uri
|
|
3899
|
-
|
|
3900
|
-
return malformedAuthorityOrPort ? undefined : normalized;
|
|
4354
|
+
if (typeof uri !== "string" && typeof uri !== "object") {
|
|
4355
|
+
return;
|
|
3901
4356
|
}
|
|
3902
|
-
|
|
3903
|
-
|
|
4357
|
+
let value;
|
|
4358
|
+
try {
|
|
4359
|
+
value = typeof uri === "string" ? uri : serialize(uri, opts);
|
|
4360
|
+
} catch {
|
|
4361
|
+
return;
|
|
3904
4362
|
}
|
|
4363
|
+
const { normalized, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = normalizeStringWithStatus(value, opts);
|
|
4364
|
+
return malformedAuthorityOrPort || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? undefined : normalized;
|
|
3905
4365
|
}
|
|
3906
4366
|
var fastUri = {
|
|
3907
4367
|
SCHEMES,
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Posts made through the app's own user token are the person's messages
|
|
2
|
+
|
|
3
|
+
Upstream discussion: anneschuth/claude-threads#526.
|
|
4
|
+
|
|
5
|
+
## What it does
|
|
6
|
+
|
|
7
|
+
A message posted with `chat.postMessage` and a **user token of this app**
|
|
8
|
+
(`xoxp-…`, obtained when a person authorises the app) shows up in Slack as
|
|
9
|
+
that person, and Slack delivers it with `user` = the person **and**
|
|
10
|
+
`bot_id` + `app_id` of the app. Today the Slack client drops every message
|
|
11
|
+
that carries a `bot_id`, so such a post never reaches Claude, silently.
|
|
12
|
+
|
|
13
|
+
With this change the client treats a message as bot-authored only when
|
|
14
|
+
|
|
15
|
+
- its `user` is the bot's own user (the daemon's replies), or
|
|
16
|
+
- it carries a `bot_id` and is **not** a post from this app, from this
|
|
17
|
+
workspace, with a `user`.
|
|
18
|
+
|
|
19
|
+
So a post relayed through this app's own user token is handled exactly like
|
|
20
|
+
the person typing it: same session routing, same allow-list, same everything.
|
|
21
|
+
Other apps' bot posts, classic bot posts without a `user`, the daemon's own
|
|
22
|
+
replies, and a bot copy of this same app installed in another workspace that
|
|
23
|
+
shares a Slack Connect channel (same `app_id`, other `team`) stay ignored,
|
|
24
|
+
as before.
|
|
25
|
+
|
|
26
|
+
The rule is applied in the three places the filter lives: live events,
|
|
27
|
+
missed-message recovery after a reconnect, and thread history with
|
|
28
|
+
`excludeBotMessages`.
|
|
29
|
+
|
|
30
|
+
## Why
|
|
31
|
+
|
|
32
|
+
Any integration that speaks *for* a person — a voice front desk, a phone
|
|
33
|
+
bridge, an approval UI — posts on the person's behalf with the app's user
|
|
34
|
+
token, because that is the only way to keep attribution honest and the bot's
|
|
35
|
+
consent gate (channel membership, allow-lists) intact. Slack marks every
|
|
36
|
+
API-posted message with the app's `bot_id`; there is no way to post a
|
|
37
|
+
"pure" human message through the API. Without this exception the daemon
|
|
38
|
+
can never be driven by such an integration.
|
|
39
|
+
|
|
40
|
+
Origin: the VVS live voice desk (`voice/` on the `local/voice-desk` branch
|
|
41
|
+
of the kaza fork) relayed a spoken question into a task channel as the
|
|
42
|
+
speaker, and the daemon ACKed the event and dropped it at the `bot_id`
|
|
43
|
+
check with no log line. Seen 2026-09-02, message
|
|
44
|
+
`{user: U…, bot_id: B0BUDMNPD26, app_id: A0BSH7L7N9E, bot_profile: {…}}`.
|
|
45
|
+
|
|
46
|
+
## How
|
|
47
|
+
|
|
48
|
+
- The client learns its workspace from `auth.test` (`team_id`, already
|
|
49
|
+
called for the bot user) and its own app id from the Socket Mode `hello`
|
|
50
|
+
(`connection_info.app_id`) and, belt and braces, from every `events_api`
|
|
51
|
+
envelope (`payload.api_app_id`). Secondary clients on a shared socket get
|
|
52
|
+
it handed over with each injected event. No new config, no new API call.
|
|
53
|
+
- One predicate, `isBotAuthored(message)`, replaces the three inline
|
|
54
|
+
`user === botUserId || bot_id` checks.
|
|
55
|
+
- `app_id` is added to the `SlackEvent` and `SlackMessage` types; it was
|
|
56
|
+
already on the wire.
|
|
57
|
+
- Until app and team ids are known (only possible before the first `hello`), the
|
|
58
|
+
old rule applies: anything with a `bot_id` is ignored. Conservative, and
|
|
59
|
+
the window is the connection handshake.
|
|
60
|
+
|
|
61
|
+
Why `app_id` and not `bot_id`: the `bot_id` on a user-token post is a
|
|
62
|
+
per-authorisation bot profile (`B0BUDMNPD26` above), different from the
|
|
63
|
+
bot token's own `bot_id` from `auth.test` (`B0BSH828Z6U`). `app_id` is the
|
|
64
|
+
one stable identity.
|
|
65
|
+
|
|
66
|
+
## Decisions
|
|
67
|
+
|
|
68
|
+
| Decision | Why |
|
|
69
|
+
|---|---|
|
|
70
|
+
| No config flag | with `app_id` and `team` checked, only this installation's own user tokens qualify; nothing to opt out of |
|
|
71
|
+
| `team` must match too (Codex review) | Slack Connect lets the same app be installed on both sides of a shared channel; the other copy's bot shares our `app_id` but not our `team`, and two daemons answering each other is the one loop this must never open |
|
|
72
|
+
| Learn the app id from the socket, not config | zero setup; every install already receives it |
|
|
73
|
+
| Old behaviour until the app id is known | never widen the filter on a guess |
|
|
74
|
+
|
|
75
|
+
## Lessons learned
|
|
76
|
+
|
|
77
|
+
- A dropped event at the "ignore ourselves" check leaves no trace in the
|
|
78
|
+
log. Reproducing needed `conversations.history` on the exact `ts` to see
|
|
79
|
+
the stored message's fields.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-threads",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.33.0",
|
|
4
4
|
"description": "Run Claude Code from Slack or Mattermost. Sessions stream live into threads where your whole team can watch and steer.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"commander": "^14.0.2",
|
|
77
77
|
"diff": "^8.0.3",
|
|
78
78
|
"express-rate-limit": "^8.3.0",
|
|
79
|
-
"hono": "4.13.
|
|
79
|
+
"hono": "4.13.5",
|
|
80
80
|
"ink": "^6.6.0",
|
|
81
81
|
"ink-scroll-view": "^0.3.5",
|
|
82
82
|
"js-yaml": "^4.3.1",
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
"@types/ws": "^8.18.0",
|
|
100
100
|
"eslint": "^10.7.0",
|
|
101
101
|
"husky": "^9.1.7",
|
|
102
|
-
"knip": "6.
|
|
102
|
+
"knip": "6.33.0",
|
|
103
103
|
"lint-staged": "^17.0.4",
|
|
104
104
|
"prettier": "^3.9.5",
|
|
105
105
|
"typescript": "^6.0.2",
|
|
@@ -122,7 +122,7 @@
|
|
|
122
122
|
"flatted": ">=3.4.0",
|
|
123
123
|
"picomatch": ">=2.3.2",
|
|
124
124
|
"path-to-regexp": ">=8.4.0",
|
|
125
|
-
"fast-uri": ">=4.1.
|
|
125
|
+
"fast-uri": ">=4.1.4",
|
|
126
126
|
"brace-expansion": ">=5.0.9",
|
|
127
127
|
"ip-address": ">=10.3.1",
|
|
128
128
|
"ws": "$ws",
|
|
@@ -135,7 +135,7 @@
|
|
|
135
135
|
"flatted": ">=3.4.0",
|
|
136
136
|
"picomatch": ">=2.3.2",
|
|
137
137
|
"path-to-regexp": ">=8.4.0",
|
|
138
|
-
"fast-uri": ">=4.1.
|
|
138
|
+
"fast-uri": ">=4.1.4",
|
|
139
139
|
"brace-expansion": ">=5.0.9",
|
|
140
140
|
"ip-address": ">=10.3.1",
|
|
141
141
|
"ws": "$ws",
|