@cursor/july 0.1.31 → 0.1.33

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.
Files changed (75) hide show
  1. package/dist/docs/404.html +1 -1
  2. package/dist/docs/ab.html +2 -2
  3. package/dist/docs/assets/{app.DigB_9cQ.js → app.CgZqLyWL.js} +1 -1
  4. package/dist/docs/assets/chunks/@localSearchIndexroot.B1uHGxBZ.js +1 -0
  5. package/dist/docs/assets/chunks/{VPLocalSearchBox.BCMX25Bv.js → VPLocalSearchBox.C4KigoQn.js} +1 -1
  6. package/dist/docs/assets/chunks/{theme.BDDWeELx.js → theme.C_Ty4yT7.js} +2 -2
  7. package/dist/docs/building-with-agents.html +2 -2
  8. package/dist/docs/concepts.html +2 -2
  9. package/dist/docs/deployment.html +2 -2
  10. package/dist/docs/evals.html +2 -2
  11. package/dist/docs/example-agents/approval-buddy.html +2 -2
  12. package/dist/docs/example-agents/benny.html +2 -2
  13. package/dist/docs/example-agents/bugbot.html +2 -2
  14. package/dist/docs/example-agents/codebase-wiki.html +2 -2
  15. package/dist/docs/example-agents/codeowners-review.html +2 -2
  16. package/dist/docs/example-agents/concierge.html +2 -2
  17. package/dist/docs/example-agents/fsd.html +2 -2
  18. package/dist/docs/example-agents/index.html +2 -2
  19. package/dist/docs/example-agents/knowledge-base.html +2 -2
  20. package/dist/docs/example-agents/oncall.html +2 -2
  21. package/dist/docs/example-agents/security-reviewer.html +2 -2
  22. package/dist/docs/example-agents/slack-agent.html +2 -2
  23. package/dist/docs/example-agents/weather-agent.html +2 -2
  24. package/dist/docs/guides/agent-to-agent.html +2 -2
  25. package/dist/docs/guides/cloud-runtime.html +2 -2
  26. package/dist/docs/guides/github.html +2 -2
  27. package/dist/docs/guides/human-in-the-loop.html +2 -2
  28. package/dist/docs/guides/mcp-oauth.html +2 -2
  29. package/dist/docs/guides/slack.html +2 -2
  30. package/dist/docs/guides/webhooks.html +2 -2
  31. package/dist/docs/hillclimbing.html +2 -2
  32. package/dist/docs/index.html +2 -2
  33. package/dist/docs/quickstart.html +2 -2
  34. package/dist/docs/reference/agent-config.html +2 -2
  35. package/dist/docs/reference/channels.html +2 -2
  36. package/dist/docs/reference/cli.html +2 -2
  37. package/dist/docs/reference/connections.html +2 -2
  38. package/dist/docs/reference/hooks.html +2 -2
  39. package/dist/docs/reference/http-api.html +2 -2
  40. package/dist/docs/reference/instructions.html +2 -2
  41. package/dist/docs/reference/playground.html +2 -2
  42. package/dist/docs/reference/project-layout.html +2 -2
  43. package/dist/docs/reference/prompt.html +2 -2
  44. package/dist/docs/reference/schedules.html +2 -2
  45. package/dist/docs/reference/sessions.html +2 -2
  46. package/dist/docs/reference/skills.html +2 -2
  47. package/dist/docs/reference/subagents.html +2 -2
  48. package/dist/docs/reference/tools.html +2 -2
  49. package/dist/docs/scaffolding-agents.html +2 -2
  50. package/dist/docs/storage.html +2 -2
  51. package/dist/docs/troubleshooting.html +2 -2
  52. package/dist/files-backends/agent-store-presigned-url.d.ts +9 -98
  53. package/dist/files-backends/agent-store-presigned-url.d.ts.map +1 -1
  54. package/dist/files-backends/agent-store-presigned-url.js +199 -314
  55. package/dist/files-backends/cursor-hosted.d.ts.map +1 -1
  56. package/dist/files-backends/cursor-hosted.js +25 -2
  57. package/dist/internal/cursor-relay-core.d.ts +12 -0
  58. package/dist/internal/cursor-relay-core.d.ts.map +1 -1
  59. package/dist/internal/cursor-relay-core.js +42 -8
  60. package/dist/internal/review-comments.d.ts +9 -1
  61. package/dist/internal/review-comments.d.ts.map +1 -1
  62. package/dist/internal/review-comments.js +76 -0
  63. package/dist/internal/server.js +8 -1
  64. package/dist/playground/assets/index-BRhBbnd4.css +1 -0
  65. package/dist/playground/assets/index-CVlCAcUx.js +85 -0
  66. package/dist/playground/index.html +2 -2
  67. package/package.json +3 -23
  68. package/src/files-backends/agent-store-presigned-url.ts +9 -401
  69. package/src/files-backends/cursor-hosted.ts +32 -6
  70. package/src/internal/cursor-relay-core.ts +62 -3
  71. package/src/internal/review-comments.ts +102 -2
  72. package/src/internal/server.ts +9 -1
  73. package/dist/docs/assets/chunks/@localSearchIndexroot.CnFFl07y.js +0 -1
  74. package/dist/playground/assets/index-50PKeJlG.css +0 -1
  75. package/dist/playground/assets/index-C0f2Wl1q.js +0 -85
@@ -1,347 +1,232 @@
1
- /**
2
- * Vendored from `@anysphere/agent-store-sync` `presigned-url.ts` so the
3
- * published `@cursor/july` tarball does not depend on that private workspace
4
- * package (not on npm). Keep in sync when the source validator changes.
5
- */
6
- export class PresignedUrlRejectedError extends Error {
7
- constructor(options) {
8
- super(options.message);
9
- this.name = "PresignedUrlRejectedError";
10
- this.code = options.code;
11
- this.url = options.url;
12
- }
13
- }
14
- /**
15
- * Strict default: accepts `https:` URLs to an AWS S3 endpoint with no
16
- * userinfo and no private/internal address. Rejects DNS hosts that
17
- * resolve into the private IP space and IPv4-mapped IPv6 literals.
18
- */
19
- export function defaultPresignedUrlValidator(url) {
20
- assertSafeAuthority(url);
21
- if (url.protocol !== "https:") {
22
- throw new PresignedUrlRejectedError({
23
- code: "scheme_not_allowed",
24
- message: `Refused presigned URL with non-https scheme: ${url.protocol}`,
25
- url: redactPresignedUrlString(url),
26
- });
27
- }
28
- const hostname = stripIPv6Brackets(url.hostname);
29
- if (isLocalOrInternalHost(hostname)) {
30
- throw new PresignedUrlRejectedError({
31
- code: "private_host_not_allowed",
32
- message: `Refused https presigned URL with private/internal host: ${hostname}`,
33
- url: redactPresignedUrlString(url),
34
- });
35
- }
36
- if (!isAwsS3Hostname(hostname)) {
37
- throw new PresignedUrlRejectedError({
38
- code: "host_not_allowed",
39
- message: `Refused presigned URL whose host is not an AWS S3 endpoint: ${hostname}`,
40
- url: redactPresignedUrlString(url),
41
- });
42
- }
43
- }
44
- /**
45
- * True when `hostname` is an AWS S3 object-storage endpoint:
46
- * `*.amazonaws.com` with at least one label in
47
- * {@link S3_OBJECT_LABELS}. Covers modern virtual-host, path-style,
48
- * dualstack, accelerate, and FIPS URLs. Rejects the S3-named control
49
- * planes (`s3-control`, `s3-outposts`, `s3-object-lambda`) and the
50
- * legacy regional virtual-host form AWS deprecated in 2019, both of
51
- * which would otherwise let a tampered presign issuer turn the sync
52
- * client into a signed-request gadget against non-storage APIs.
53
- */
54
- export function isAwsS3Hostname(hostname) {
55
- const lowered = hostname.toLowerCase();
56
- if (lowered !== "amazonaws.com" && !lowered.endsWith(".amazonaws.com")) {
57
- return false;
58
- }
59
- const labels = lowered.split(".");
60
- return labels.some(label => S3_OBJECT_LABELS.has(label));
61
- }
62
- const S3_OBJECT_LABELS = new Set(["s3", "s3-accelerate", "s3-fips"]);
63
- /**
64
- * Like {@link defaultPresignedUrlValidator} plus a case-insensitive
65
- * exact-match check against `allowedHosts` (no subdomain wildcards).
66
- */
67
- export function createHostAllowlistValidator(allowedHosts) {
68
- const allowed = new Set(allowedHosts.map(host => host.toLowerCase()));
69
- return (url) => {
70
- defaultPresignedUrlValidator(url);
71
- if (!allowed.has(url.hostname.toLowerCase())) {
72
- throw new PresignedUrlRejectedError({
73
- code: "host_not_allowed",
74
- message: `Refused presigned URL whose host is not in the allowlist: ${url.hostname}`,
75
- url: redactPresignedUrlString(url),
76
- });
77
- }
78
- };
1
+ // ../agent-store-sync/dist/presigned-url.js
2
+ var PresignedUrlRejectedError = class extends Error {
3
+ constructor(options) {
4
+ super(options.message);
5
+ this.name = "PresignedUrlRejectedError";
6
+ this.code = options.code;
7
+ this.url = options.url;
8
+ }
9
+ };
10
+ function defaultPresignedUrlValidator(url) {
11
+ assertSafeAuthority(url);
12
+ if (url.protocol !== "https:") {
13
+ throw new PresignedUrlRejectedError({
14
+ code: "scheme_not_allowed",
15
+ message: `Refused presigned URL with non-https scheme: ${url.protocol}`,
16
+ url: redactPresignedUrlString(url)
17
+ });
18
+ }
19
+ const hostname = stripIPv6Brackets(url.hostname);
20
+ if (isLocalOrInternalHost(hostname)) {
21
+ throw new PresignedUrlRejectedError({
22
+ code: "private_host_not_allowed",
23
+ message: `Refused https presigned URL with private/internal host: ${hostname}`,
24
+ url: redactPresignedUrlString(url)
25
+ });
26
+ }
27
+ if (!isAwsS3Hostname(hostname)) {
28
+ throw new PresignedUrlRejectedError({
29
+ code: "host_not_allowed",
30
+ message: `Refused presigned URL whose host is not an AWS S3 endpoint: ${hostname}`,
31
+ url: redactPresignedUrlString(url)
32
+ });
33
+ }
79
34
  }
80
- /**
81
- * Virtual-host S3 endpoints for the production `agent-stores` bucket
82
- * (matches backend `getAgentStoreBucket()` in
83
- * `backend/server/src/agent-stores/utils/agentStoreS3.ts`, which presigns
84
- * with a `us-east-1` `S3Client` and the SDK's default virtual-host
85
- * addressing). Both the regional form emitted by modern AWS SDK v3 and
86
- * the legacy global form are listed so a presign issuer upgrade or
87
- * downgrade can't trip the allowlist. Path-style (`s3.amazonaws.com/agent-stores/…`)
88
- * is intentionally not listed: the server never sets `forcePathStyle`,
89
- * and admitting bare `s3.amazonaws.com` would re-open the "any bucket"
90
- * gap this allowlist exists to close.
91
- */
92
- export const BCS_AGENT_STORE_BUCKET_HOSTS = [
93
- "agent-stores.s3.us-east-1.amazonaws.com",
94
- "agent-stores.s3.amazonaws.com",
35
+ function isAwsS3Hostname(hostname) {
36
+ const lowered = hostname.toLowerCase();
37
+ if (lowered !== "amazonaws.com" && !lowered.endsWith(".amazonaws.com")) {
38
+ return false;
39
+ }
40
+ const labels = lowered.split(".");
41
+ return labels.some((label) => S3_OBJECT_LABELS.has(label));
42
+ }
43
+ var S3_OBJECT_LABELS = /* @__PURE__ */ new Set(["s3", "s3-accelerate", "s3-fips"]);
44
+ function createHostAllowlistValidator(allowedHosts) {
45
+ const allowed = new Set(allowedHosts.map((host) => host.toLowerCase()));
46
+ return (url) => {
47
+ defaultPresignedUrlValidator(url);
48
+ if (!allowed.has(url.hostname.toLowerCase())) {
49
+ throw new PresignedUrlRejectedError({
50
+ code: "host_not_allowed",
51
+ message: `Refused presigned URL whose host is not in the allowlist: ${url.hostname}`,
52
+ url: redactPresignedUrlString(url)
53
+ });
54
+ }
55
+ };
56
+ }
57
+ var BCS_AGENT_STORE_BUCKET_HOSTS = [
58
+ "agent-stores.s3.us-east-1.amazonaws.com",
59
+ "agent-stores.s3.amazonaws.com"
95
60
  ];
96
- const PLAYGROUND_AGENT_STORE_BUCKET_HOSTS = [
97
- "agent-stores-928182716709-us-west-2-an.s3.us-west-2.amazonaws.com",
98
- "agent-stores-928182716709-us-west-2-an.s3.amazonaws.com",
61
+ var PLAYGROUND_AGENT_STORE_BUCKET_HOSTS = [
62
+ "agent-stores-928182716709-us-west-2-an.s3.us-west-2.amazonaws.com",
63
+ "agent-stores-928182716709-us-west-2-an.s3.amazonaws.com"
99
64
  ];
100
- /**
101
- * Production validator for the BCS agent-store sync transport: strict
102
- * default (https, S3 endpoint, no private hosts, no userinfo) plus the
103
- * {@link BCS_AGENT_STORE_BUCKET_HOSTS} pin. Pre-built so callers don't
104
- * accidentally pass {@link defaultPresignedUrlValidator}, which would
105
- * accept any AWS S3 bucket on the internet and let a buggy or
106
- * compromised presign issuer redirect sync traffic away from the real
107
- * `agent-stores` bucket.
108
- */
109
- export function createBcsPresignedUrlValidator() {
110
- return createHostAllowlistValidator(BCS_AGENT_STORE_BUCKET_HOSTS);
65
+ function createBcsPresignedUrlValidator() {
66
+ return createHostAllowlistValidator(BCS_AGENT_STORE_BUCKET_HOSTS);
111
67
  }
112
- /**
113
- * True when `backendUrl` targets a local dev backend (localhost or
114
- * lclhst.build). Matches IDE checks in `cursor-always-local` /
115
- * `cursorCredsService`.
116
- */
117
- export function isLocalAgentStoreBackendUrl(backendUrl) {
118
- const trimmed = backendUrl.trim();
119
- if (trimmed === "") {
120
- return false;
121
- }
122
- return trimmed.includes("localhost") || trimmed.includes("lclhst.build");
68
+ function isLocalAgentStoreBackendUrl(backendUrl) {
69
+ const trimmed = backendUrl.trim();
70
+ if (trimmed === "") {
71
+ return false;
72
+ }
73
+ return trimmed.includes("localhost") || trimmed.includes("lclhst.build");
123
74
  }
124
75
  function isPlaygroundAgentStoreBackendUrl(backendUrl) {
125
- try {
126
- const hostname = new URL(backendUrl).hostname.toLowerCase();
127
- return (hostname === "playground.cursor.sh" ||
128
- hostname.endsWith(".playground.cursor.sh"));
129
- }
130
- catch (_a) {
131
- return false;
132
- }
76
+ try {
77
+ const hostname = new URL(backendUrl).hostname.toLowerCase();
78
+ return hostname === "playground.cursor.sh" || hostname.endsWith(".playground.cursor.sh");
79
+ } catch (_a) {
80
+ return false;
81
+ }
133
82
  }
134
- /**
135
- * Presign validator for the sync client. Production/staging and playground
136
- * backends are pinned to their respective agent-store buckets. For a local dev API (see
137
- * {@link isLocalAgentStoreBackendUrl}), allow `http:` to loopback only
138
- * (LocalStack) and still pin all other URLs to {@link BCS_AGENT_STORE_BUCKET_HOSTS}.
139
- */
140
- export function createAgentStorePresignedUrlValidatorForBackend(backendUrl) {
141
- if (isLocalAgentStoreBackendUrl(backendUrl)) {
142
- return createLocalDevAgentStorePresignedUrlValidator();
143
- }
144
- if (isPlaygroundAgentStoreBackendUrl(backendUrl)) {
145
- return createHostAllowlistValidator(PLAYGROUND_AGENT_STORE_BUCKET_HOSTS);
146
- }
147
- return createBcsPresignedUrlValidator();
83
+ function createAgentStorePresignedUrlValidatorForBackend(backendUrl) {
84
+ if (isLocalAgentStoreBackendUrl(backendUrl)) {
85
+ return createLocalDevAgentStorePresignedUrlValidator();
86
+ }
87
+ if (isPlaygroundAgentStoreBackendUrl(backendUrl)) {
88
+ return createHostAllowlistValidator(PLAYGROUND_AGENT_STORE_BUCKET_HOSTS);
89
+ }
90
+ return createBcsPresignedUrlValidator();
148
91
  }
149
92
  function createLocalDevAgentStorePresignedUrlValidator() {
150
- const bcsValidator = createBcsPresignedUrlValidator();
151
- return (url) => {
152
- assertSafeAuthority(url);
153
- const hostname = stripIPv6Brackets(url.hostname);
154
- if (url.protocol === "http:" && isLoopbackHostName(hostname)) {
155
- return;
156
- }
157
- bcsValidator(url);
158
- };
159
- }
160
- /**
161
- * Like {@link defaultPresignedUrlValidator} plus `http://localhost` /
162
- * `127.0.0.1` / `[::1]` (any port) for LocalStack-backed unit tests.
163
- * Non-loopback `https:` URLs fall through to the strict default (any S3
164
- * bucket). Do not use for IDE wiring — use
165
- * {@link createAgentStorePresignedUrlValidatorForBackend} instead.
166
- */
167
- export function localhostPermissivePresignedUrlValidator(url) {
93
+ const bcsValidator = createBcsPresignedUrlValidator();
94
+ return (url) => {
168
95
  assertSafeAuthority(url);
169
96
  const hostname = stripIPv6Brackets(url.hostname);
170
97
  if (url.protocol === "http:" && isLoopbackHostName(hostname)) {
171
- return;
98
+ return;
172
99
  }
173
- defaultPresignedUrlValidator(url);
100
+ bcsValidator(url);
101
+ };
174
102
  }
175
103
  function assertSafeAuthority(url) {
176
- if (url.username !== "" || url.password !== "") {
177
- throw new PresignedUrlRejectedError({
178
- code: "userinfo_not_allowed",
179
- message: "Refused presigned URL with embedded userinfo",
180
- url: redactPresignedUrlString(url),
181
- });
182
- }
183
- }
184
- /**
185
- * Strip the query string and userinfo from a presigned URL so the AWS
186
- * SigV4 signature never reaches error messages or telemetry.
187
- */
188
- export function redactPresignedUrlString(url) {
189
- try {
190
- const parsed = typeof url === "string" ? new URL(url) : url;
191
- return `${parsed.protocol}//${parsed.host}${parsed.pathname}`;
192
- }
193
- catch (_a) {
194
- return "<unparseable-presigned-url>";
195
- }
104
+ if (url.username !== "" || url.password !== "") {
105
+ throw new PresignedUrlRejectedError({
106
+ code: "userinfo_not_allowed",
107
+ message: "Refused presigned URL with embedded userinfo",
108
+ url: redactPresignedUrlString(url)
109
+ });
110
+ }
196
111
  }
197
- /**
198
- * Parse and validate a server-returned presigned URL before fetch. Uses
199
- * {@link relPath} in error text (never the raw URL) so SigV4 credentials
200
- * cannot leak into messages.
201
- */
202
- export function assertPresignedUrlSafe(args) {
203
- let parsed;
204
- try {
205
- parsed = new URL(args.rawUrl);
206
- }
207
- catch (_a) {
208
- throw new Error(`Refusing unparseable presigned URL for ${args.relPath}`);
209
- }
210
- try {
211
- args.validatePresignedUrl(parsed);
212
- }
213
- catch (error) {
214
- throw new Error(`Refusing presigned URL for ${args.relPath}: ${error instanceof Error ? error.message : String(error)}`, { cause: error instanceof Error ? error : undefined });
215
- }
112
+ function redactPresignedUrlString(url) {
113
+ try {
114
+ const parsed = typeof url === "string" ? new URL(url) : url;
115
+ return `${parsed.protocol}//${parsed.host}${parsed.pathname}`;
116
+ } catch (_a) {
117
+ return "<unparseable-presigned-url>";
118
+ }
216
119
  }
217
120
  function isLoopbackHostName(hostname) {
218
- const lowered = hostname.toLowerCase();
219
- return (lowered === "localhost" ||
220
- lowered === "ip6-localhost" ||
221
- lowered === "127.0.0.1" ||
222
- lowered === "::1" ||
223
- lowered === "0:0:0:0:0:0:0:1");
121
+ const lowered = hostname.toLowerCase();
122
+ return lowered === "localhost" || lowered === "ip6-localhost" || lowered === "127.0.0.1" || lowered === "::1" || lowered === "0:0:0:0:0:0:0:1";
224
123
  }
225
124
  function isLocalOrInternalHost(hostname) {
226
- if (hostname.length === 0) {
227
- return true;
228
- }
229
- if (isLoopbackHostName(hostname)) {
230
- return true;
231
- }
232
- if (isIPv4Address(hostname)) {
233
- return isPrivateOrInternalIPv4(hostname);
234
- }
235
- if (isIPv6Address(hostname)) {
236
- return isPrivateOrInternalIPv6(hostname);
237
- }
238
- // DNS hostnames can't be classified without resolving; the caller
239
- // relies on transport-level allowlists for those.
240
- return false;
125
+ if (hostname.length === 0) {
126
+ return true;
127
+ }
128
+ if (isLoopbackHostName(hostname)) {
129
+ return true;
130
+ }
131
+ if (isIPv4Address(hostname)) {
132
+ return isPrivateOrInternalIPv4(hostname);
133
+ }
134
+ if (isIPv6Address(hostname)) {
135
+ return isPrivateOrInternalIPv6(hostname);
136
+ }
137
+ return false;
241
138
  }
242
139
  function stripIPv6Brackets(hostname) {
243
- return hostname.startsWith("[") && hostname.endsWith("]")
244
- ? hostname.slice(1, -1)
245
- : hostname;
140
+ return hostname.startsWith("[") && hostname.endsWith("]") ? hostname.slice(1, -1) : hostname;
246
141
  }
247
142
  function isIPv4Address(hostname) {
248
- const parts = hostname.split(".");
249
- if (parts.length !== 4) {
250
- return false;
143
+ const parts = hostname.split(".");
144
+ if (parts.length !== 4) {
145
+ return false;
146
+ }
147
+ return parts.every((part) => {
148
+ if (part.length === 0 || part.length > 3) {
149
+ return false;
251
150
  }
252
- return parts.every(part => {
253
- if (part.length === 0 || part.length > 3) {
254
- return false;
255
- }
256
- if (!/^\d+$/.test(part)) {
257
- return false;
258
- }
259
- const n = Number(part);
260
- return Number.isInteger(n) && n >= 0 && n <= 255;
261
- });
151
+ if (!/^\d+$/.test(part)) {
152
+ return false;
153
+ }
154
+ const n = Number(part);
155
+ return Number.isInteger(n) && n >= 0 && n <= 255;
156
+ });
262
157
  }
263
158
  function isPrivateOrInternalIPv4(hostname) {
264
- const [a, b] = hostname.split(".").map(Number);
265
- if (a === undefined || b === undefined) {
266
- return true;
267
- }
268
- // RFC1918, loopback, link-local, multicast, unspecified, broadcast,
269
- // carrier-grade NAT, and reserved blocks.
270
- if (a === 0)
271
- return true;
272
- if (a === 10)
273
- return true;
274
- if (a === 127)
275
- return true;
276
- if (a === 169 && b === 254)
277
- return true;
278
- if (a === 172 && b >= 16 && b <= 31)
279
- return true;
280
- if (a === 192 && b === 168)
281
- return true;
282
- if (a === 100 && b >= 64 && b <= 127)
283
- return true;
284
- if (a >= 224 && a <= 239)
285
- return true;
286
- if (a >= 240)
287
- return true;
288
- return false;
159
+ const [a, b] = hostname.split(".").map(Number);
160
+ if (a === void 0 || b === void 0) {
161
+ return true;
162
+ }
163
+ if (a === 0)
164
+ return true;
165
+ if (a === 10)
166
+ return true;
167
+ if (a === 127)
168
+ return true;
169
+ if (a === 169 && b === 254)
170
+ return true;
171
+ if (a === 172 && b >= 16 && b <= 31)
172
+ return true;
173
+ if (a === 192 && b === 168)
174
+ return true;
175
+ if (a === 100 && b >= 64 && b <= 127)
176
+ return true;
177
+ if (a >= 224 && a <= 239)
178
+ return true;
179
+ if (a >= 240)
180
+ return true;
181
+ return false;
289
182
  }
290
183
  function isIPv6Address(hostname) {
291
- // Loose check — just enough to route the host to the IPv6 classifier.
292
- return hostname.includes(":");
184
+ return hostname.includes(":");
293
185
  }
294
186
  function isPrivateOrInternalIPv6(hostname) {
295
- const lowered = hostname.toLowerCase();
296
- if (lowered === "::" || lowered === "::1") {
297
- return true;
298
- }
299
- // IPv4-mapped IPv6 (RFC4291) routes back through the IPv4 classifier
300
- // so `[::ffff:169.254.169.254]` can't slip past the private-IP check.
301
- const mapped = extractIPv4MappedAddress(lowered);
302
- if (mapped !== undefined) {
303
- return isPrivateOrInternalIPv4(mapped);
304
- }
305
- // ULA fc00::/7, link-local fe80::/10, multicast ff00::/8.
306
- if (lowered.startsWith("fc") || lowered.startsWith("fd")) {
307
- return true;
308
- }
309
- if (lowered.startsWith("fe8") || lowered.startsWith("fe9")) {
310
- return true;
311
- }
312
- if (lowered.startsWith("fea") || lowered.startsWith("feb")) {
313
- return true;
314
- }
315
- if (lowered.startsWith("ff")) {
316
- return true;
317
- }
318
- return false;
187
+ const lowered = hostname.toLowerCase();
188
+ if (lowered === "::" || lowered === "::1") {
189
+ return true;
190
+ }
191
+ const mapped = extractIPv4MappedAddress(lowered);
192
+ if (mapped !== void 0) {
193
+ return isPrivateOrInternalIPv4(mapped);
194
+ }
195
+ if (lowered.startsWith("fc") || lowered.startsWith("fd")) {
196
+ return true;
197
+ }
198
+ if (lowered.startsWith("fe8") || lowered.startsWith("fe9")) {
199
+ return true;
200
+ }
201
+ if (lowered.startsWith("fea") || lowered.startsWith("feb")) {
202
+ return true;
203
+ }
204
+ if (lowered.startsWith("ff")) {
205
+ return true;
206
+ }
207
+ return false;
319
208
  }
320
- // Convert an IPv4-mapped IPv6 literal (`::ffff:a.b.c.d` or
321
- // `::ffff:hhhh:hhhh`) to its dotted-quad form. Returns undefined otherwise.
322
209
  function extractIPv4MappedAddress(hostname) {
323
- const dotted = hostname.match(/^(?:0:0:0:0:0|::):?ffff:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/i);
324
- if (dotted) {
325
- return dotted[1];
326
- }
327
- if (hostname.startsWith("::ffff:")) {
328
- const tail = hostname.slice("::ffff:".length);
329
- if (isIPv4Address(tail)) {
330
- return tail;
331
- }
332
- const hex = tail.match(/^([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i);
333
- if (hex) {
334
- const high = Number.parseInt(hex[1], 16);
335
- const low = Number.parseInt(hex[2], 16);
336
- if (Number.isFinite(high) &&
337
- Number.isFinite(low) &&
338
- high >= 0 &&
339
- high <= 0xffff &&
340
- low >= 0 &&
341
- low <= 0xffff) {
342
- return `${(high >> 8) & 0xff}.${high & 0xff}.${(low >> 8) & 0xff}.${low & 0xff}`;
343
- }
344
- }
345
- }
346
- return undefined;
347
- }
210
+ const dotted = hostname.match(/^(?:0:0:0:0:0|::):?ffff:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/i);
211
+ if (dotted) {
212
+ return dotted[1];
213
+ }
214
+ if (hostname.startsWith("::ffff:")) {
215
+ const tail = hostname.slice("::ffff:".length);
216
+ if (isIPv4Address(tail)) {
217
+ return tail;
218
+ }
219
+ const hex = tail.match(/^([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i);
220
+ if (hex) {
221
+ const high = Number.parseInt(hex[1], 16);
222
+ const low = Number.parseInt(hex[2], 16);
223
+ if (Number.isFinite(high) && Number.isFinite(low) && high >= 0 && high <= 65535 && low >= 0 && low <= 65535) {
224
+ return `${high >> 8 & 255}.${high & 255}.${low >> 8 & 255}.${low & 255}`;
225
+ }
226
+ }
227
+ }
228
+ return void 0;
229
+ }
230
+ export {
231
+ createAgentStorePresignedUrlValidatorForBackend
232
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"cursor-hosted.d.ts","sourceRoot":"","sources":["../../src/files-backends/cursor-hosted.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAGH,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,YAAY,EAGlB,MAAM,aAAa,CAAC;AAWrB;;;;;;GAMG;AACH,eAAO,MAAM,mCAAmC,gCACjB,CAAC;AAgBhC;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAC1C,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAGT;AAED,MAAM,WAAW,wBAAwB;IACvC,oFAAoF;IACpF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2CAA2C;IAC3C,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAuCD,KAAK,kBAAkB,GAAG,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,GAAG;IAChD,gFAAgF;IAChF,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAAC;CACrD,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,GAAE,wBAA6B,GACrC,kBAAkB,CA8VpB"}
1
+ {"version":3,"file":"cursor-hosted.d.ts","sourceRoot":"","sources":["../../src/files-backends/cursor-hosted.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAGH,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,YAAY,EAGlB,MAAM,aAAa,CAAC;AAWrB;;;;;;GAMG;AACH,eAAO,MAAM,mCAAmC,gCACjB,CAAC;AAgBhC;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAC1C,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAGT;AAED,MAAM,WAAW,wBAAwB;IACvC,oFAAoF;IACpF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2CAA2C;IAC3C,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAuCD,KAAK,kBAAkB,GAAG,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,GAAG;IAChD,gFAAgF;IAChF,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAAC;CACrD,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,GAAE,wBAA6B,GACrC,kBAAkB,CAyWpB"}
@@ -347,7 +347,19 @@ export function cursorHostedFiles(options = {}) {
347
347
  return __awaiter(this, void 0, void 0, function* () {
348
348
  return yield withFiles((files) => __awaiter(this, void 0, void 0, function* () {
349
349
  var _a, _b;
350
- const presigned = yield storePost(options, files.path("/download"), { paths: [key] });
350
+ // Presigning a read of a path the store has no live object for — never
351
+ // written, or deleted and now holding a tombstone — is a 404. That is
352
+ // absence, which `read()` reports as undefined, not a failure.
353
+ let presigned;
354
+ try {
355
+ presigned = yield storePost(options, files.path("/download"), { paths: [key] });
356
+ }
357
+ catch (error) {
358
+ if (error instanceof StoreApiError && error.status === 404) {
359
+ return undefined;
360
+ }
361
+ throw error;
362
+ }
351
363
  const url = (_b = (_a = presigned.files) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.url;
352
364
  if (url === undefined) {
353
365
  return undefined;
@@ -510,11 +522,22 @@ function sendJson(options, url, method, body) {
510
522
  throw new Error(`cursorHostedFiles ${url} returned non-JSON (${response.status})`);
511
523
  }
512
524
  if (!response.ok) {
513
- throw new Error(`cursorHostedFiles ${url}: ${describeError(parsed, response.status)}`);
525
+ throw new StoreApiError(response.status, `cursorHostedFiles ${url}: ${describeError(parsed, response.status)}`);
514
526
  }
515
527
  return parsed;
516
528
  });
517
529
  }
530
+ /**
531
+ * A non-2xx answer from the files API, carrying the status so a caller can
532
+ * tell "absent" apart from a failure it must not swallow.
533
+ */
534
+ class StoreApiError extends Error {
535
+ constructor(status, message) {
536
+ super(message);
537
+ this.status = status;
538
+ this.name = "StoreApiError";
539
+ }
540
+ }
518
541
  function describeError(parsed, status) {
519
542
  if (parsed !== null &&
520
543
  typeof parsed === "object" &&
@@ -73,7 +73,18 @@ export interface CursorRelayCoreOptions<TEvent extends {
73
73
  fetchImpl?: typeof fetch;
74
74
  /** Test seam: override long-poll wait (default 25s). */
75
75
  pollWaitMs?: number;
76
+ /**
77
+ * Desired-revision generation for hosted engines. Sent as
78
+ * `x-agent-serve-generation` so the control plane can fence zombies after
79
+ * a redeploy. Defaults to `process.env.AGENT_SERVE_GENERATION` when set.
80
+ */
81
+ deploymentGeneration?: number;
76
82
  }
83
+ /** Must match server-shared `AGENT_SERVE_GENERATION_HEADER`. */
84
+ export declare const AGENT_SERVE_GENERATION_HEADER = "x-agent-serve-generation";
85
+ /** Must match server-shared `AGENT_SERVE_GENERATION_ENV_VAR`. */
86
+ export declare const AGENT_SERVE_GENERATION_ENV_VAR = "AGENT_SERVE_GENERATION";
87
+ export declare function resolveAgentServeDeploymentGeneration(explicit?: number): number | undefined;
77
88
  export declare class CursorRelayCore<TEvent extends {
78
89
  offset: string;
79
90
  }> {
@@ -84,6 +95,7 @@ export declare class CursorRelayCore<TEvent extends {
84
95
  private consumePromise;
85
96
  private readonly offsetStore;
86
97
  private readonly fetchImpl;
98
+ private readonly deploymentGeneration;
87
99
  private consumerId;
88
100
  /** undefined until the first registration, so a clean first success logs. */
89
101
  private lastRegistrationLog;
@@ -1 +1 @@
1
- {"version":3,"file":"cursor-relay-core.d.ts","sourceRoot":"","sources":["../../src/internal/cursor-relay-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA6BH,8DAA8D;AAC9D,qBAAa,gBAAgB;IACf,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAArC,YAA6B,QAAQ,EAAE,MAAM,EAAI;IAEjD,OAAO,KAAK,QAAQ,GAEnB;IAEK,IAAI,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAcxC;IAEK,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWxC;CACF;AAED,6CAA6C;AAC7C,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAMjE;AASD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEzD;AAQD;;;;GAIG;AACH,MAAM,WAAW,YAAY,CAAC,MAAM,SAAS;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE;IAC7D,2EAA2E;IAC3E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,2EAA2E;IAC3E,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,kDAAkD;IAClD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,0DAA0D;IAC1D,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;IACnD;;;;;;OAMG;IACH,uBAAuB,CAAC,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;IACtD;;;;;OAKG;IACH,yBAAyB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,EAAE,CAAC;IACnD;;;;OAIG;IACH,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IACvC;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,sBAAsB,CAAC,MAAM,SAAS;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE;IACvE,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IAC9B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,2CAA2C;IAC3C,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,wDAAwD;IACxD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,eAAe,CAAC,MAAM,SAAS;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE;IAmBhD,OAAO,CAAC,QAAQ,CAAC,OAAO;IAlBpC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,KAAK,CAA8B;IAC3C,OAAO,CAAC,aAAa,CAA6B;IAClD,OAAO,CAAC,cAAc,CAA4B;IAClD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAmB;IAC/C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IACzC,OAAO,CAAC,UAAU,CAAM;IACxB,6EAA6E;IAC7E,OAAO,CAAC,mBAAmB,CAAqB;IAChD,2EAA2E;IAC3E,OAAO,CAAC,cAAc,CAAS;IAC/B;;;;OAIG;IACH,OAAO,CAAC,gBAAgB,CAA+B;IAEvD,YAA6B,OAAO,EAAE,sBAAsB,CAAC,MAAM,CAAC,EAGnE;IAED,KAAK,IAAI,IAAI,CAKZ;IAED;;;;OAIG;YACW,GAAG;IAWjB;;;;;OAKG;IACG,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,CA2BzC;IAEK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAsB1B;IAED;;;;;;OAMG;YACW,UAAU;IAuCxB,OAAO,CAAC,GAAG;YAMG,OAAO;IAiBrB,4EAA4E;YAC9D,oBAAoB;IAYlC;;;;OAIG;YACW,YAAY;IA8B1B,8EAA8E;IAC9E,OAAO,CAAC,sBAAsB;YAShB,WAAW;IAsFzB;;;;;;OAMG;YACW,iBAAiB;IA8B/B,2EAA2E;YAC7D,uBAAuB;IAgBrC,OAAO,CAAC,KAAK;IAkBb,OAAO,CAAC,OAAO;CAKhB"}
1
+ {"version":3,"file":"cursor-relay-core.d.ts","sourceRoot":"","sources":["../../src/internal/cursor-relay-core.ts"],"names":[],"mappings":"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"}