@vercel/sandbox 1.6.0 → 1.7.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.
@@ -7,6 +7,28 @@ function toAPINetworkPolicy(policy) {
7
7
  return { mode: "allow-all" };
8
8
  if (policy === "deny-all")
9
9
  return { mode: "deny-all" };
10
+ if (policy.allow && !Array.isArray(policy.allow)) {
11
+ const allowedDomains = Object.keys(policy.allow);
12
+ const injectionRules = [];
13
+ for (const [domain, rules] of Object.entries(policy.allow)) {
14
+ const merged = {};
15
+ for (const rule of rules) {
16
+ for (const t of rule.transform ?? []) {
17
+ Object.assign(merged, t.headers);
18
+ }
19
+ }
20
+ if (Object.keys(merged).length > 0) {
21
+ injectionRules.push({ domain, headers: merged });
22
+ }
23
+ }
24
+ return {
25
+ mode: "custom",
26
+ ...(allowedDomains.length > 0 && { allowedDomains }),
27
+ ...(injectionRules.length > 0 && { injectionRules }),
28
+ ...(policy.subnets?.allow && { allowedCIDRs: policy.subnets.allow }),
29
+ ...(policy.subnets?.deny && { deniedCIDRs: policy.subnets.deny }),
30
+ };
31
+ }
10
32
  return {
11
33
  mode: "custom",
12
34
  ...(policy.allow && { allowedDomains: policy.allow }),
@@ -19,14 +41,42 @@ function fromAPINetworkPolicy(api) {
19
41
  return "allow-all";
20
42
  if (api.mode === "deny-all")
21
43
  return "deny-all";
22
- return {
23
- ...(api.allowedDomains && { allow: api.allowedDomains }),
24
- ...((api.allowedCIDRs || api.deniedCIDRs) && {
44
+ const subnets = (api.allowedCIDRs || api.deniedCIDRs)
45
+ ? {
25
46
  subnets: {
26
47
  ...(api.allowedCIDRs && { allow: api.allowedCIDRs }),
27
48
  ...(api.deniedCIDRs && { deny: api.deniedCIDRs }),
28
49
  },
29
- }),
50
+ }
51
+ : undefined;
52
+ // If injectionRules are present, reconstruct the record form.
53
+ // The API returns headerNames (secret values are stripped), so we
54
+ // populate each header value with "<redacted>".
55
+ if (api.injectionRules && api.injectionRules.length > 0) {
56
+ const rulesByDomain = new Map(api.injectionRules.map((r) => [r.domain, r.headerNames ?? []]));
57
+ const allow = {};
58
+ for (const domain of api.allowedDomains ?? []) {
59
+ const headerNames = rulesByDomain.get(domain);
60
+ if (headerNames && headerNames.length > 0) {
61
+ const headers = Object.fromEntries(headerNames.map((n) => [n, "<redacted>"]));
62
+ allow[domain] = [{ transform: [{ headers }] }];
63
+ }
64
+ else {
65
+ allow[domain] = [];
66
+ }
67
+ }
68
+ // Include injection rules for domains not in allowedDomains
69
+ for (const rule of api.injectionRules) {
70
+ if (!(rule.domain in allow)) {
71
+ const headers = Object.fromEntries((rule.headerNames ?? []).map((n) => [n, "<redacted>"]));
72
+ allow[rule.domain] = [{ transform: [{ headers }] }];
73
+ }
74
+ }
75
+ return { allow, ...subnets };
76
+ }
77
+ return {
78
+ ...(api.allowedDomains && { allow: api.allowedDomains }),
79
+ ...subnets,
30
80
  };
31
81
  }
32
82
  //# sourceMappingURL=network-policy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"network-policy.js","sourceRoot":"","sources":["../../src/utils/network-policy.ts"],"names":[],"mappings":";;AAMA,gDASC;AAED,oDAYC;AAvBD,SAAgB,kBAAkB,CAAC,MAAqB;IACtD,IAAI,MAAM,KAAK,WAAW;QAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;IACzD,IAAI,MAAM,KAAK,UAAU;QAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;IACvD,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,cAAc,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;QACrD,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE,YAAY,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACpE,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,IAAI,EAAE,WAAW,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;KAClE,CAAC;AACJ,CAAC;AAED,SAAgB,oBAAoB,CAAC,GAAqB;IACxD,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW;QAAE,OAAO,WAAW,CAAC;IACjD,IAAI,GAAG,CAAC,IAAI,KAAK,UAAU;QAAE,OAAO,UAAU,CAAC;IAC/C,OAAO;QACL,GAAG,CAAC,GAAG,CAAC,cAAc,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,cAAc,EAAE,CAAC;QACxD,GAAG,CAAC,CAAC,GAAG,CAAC,YAAY,IAAI,GAAG,CAAC,WAAW,CAAC,IAAI;YAC3C,OAAO,EAAE;gBACP,GAAG,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,YAAY,EAAE,CAAC;gBACpD,GAAG,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC;aAClD;SACF,CAAC;KACH,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"network-policy.js","sourceRoot":"","sources":["../../src/utils/network-policy.ts"],"names":[],"mappings":"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"}
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "1.6.0";
1
+ export declare const VERSION = "1.7.0";
package/dist/version.js CHANGED
@@ -2,5 +2,5 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VERSION = void 0;
4
4
  // Autogenerated by inject-version.ts
5
- exports.VERSION = "1.6.0";
5
+ exports.VERSION = "1.7.0";
6
6
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/sandbox",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
4
4
  "description": "Software Development Kit for Vercel Sandbox",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -22,7 +22,7 @@
22
22
  },
23
23
  "license": "Apache-2.0",
24
24
  "dependencies": {
25
- "@vercel/oidc": "^3.1.0",
25
+ "@vercel/oidc": "3.2.0",
26
26
  "async-retry": "1.3.3",
27
27
  "jsonlines": "0.1.1",
28
28
  "ms": "2.1.3",
@@ -1,42 +0,0 @@
1
- import { z } from "zod";
2
- import { schema } from "./get-credentials";
3
- export declare class OidcRefreshError extends Error {
4
- name: string;
5
- }
6
- /**
7
- * Expiry implementation for JWT tokens (OIDC tokens).
8
- * Parses the JWT once and provides fast expiry validation.
9
- */
10
- export declare class JwtExpiry {
11
- readonly token: string;
12
- private expiryTime;
13
- readonly payload?: Readonly<z.infer<typeof schema>>;
14
- static fromToken(token: string): JwtExpiry | null;
15
- /**
16
- * Creates a new JWT expiry checker.
17
- *
18
- * @param token - The JWT token to parse
19
- */
20
- constructor(token: string);
21
- /**
22
- * Checks if the JWT token is valid (not expired).
23
- * @returns true if token is valid, false if expired or expiring soon
24
- */
25
- isValid(): boolean;
26
- /**
27
- * Gets the expiry date of the JWT token.
28
- *
29
- * @returns Date object representing when the token expires, or null if no expiry
30
- */
31
- getExpiryDate(): Date | null;
32
- /**
33
- * Refreshes the JWT token by fetching a new OIDC token.
34
- *
35
- * @returns Promise resolving to a new JwtExpiry instance with fresh token
36
- */
37
- refresh(): Promise<JwtExpiry>;
38
- /**
39
- * Refreshes the JWT token if it's expired or expiring soon.
40
- */
41
- tryRefresh(): Promise<JwtExpiry | null>;
42
- }
@@ -1,106 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.JwtExpiry = exports.OidcRefreshError = void 0;
7
- const decode_base64_url_1 = require("./decode-base64-url");
8
- const get_credentials_1 = require("./get-credentials");
9
- const oidc_1 = require("@vercel/oidc");
10
- const ms_1 = __importDefault(require("ms"));
11
- /** Time buffer before token expiry to consider it invalid (in milliseconds) */
12
- const BUFFER_MS = (0, ms_1.default)("5m");
13
- class OidcRefreshError extends Error {
14
- constructor() {
15
- super(...arguments);
16
- this.name = "OidcRefreshError";
17
- }
18
- }
19
- exports.OidcRefreshError = OidcRefreshError;
20
- /**
21
- * Expiry implementation for JWT tokens (OIDC tokens).
22
- * Parses the JWT once and provides fast expiry validation.
23
- */
24
- class JwtExpiry {
25
- static fromToken(token) {
26
- if (!isJwtFormat(token)) {
27
- return null;
28
- }
29
- else {
30
- return new JwtExpiry(token);
31
- }
32
- }
33
- /**
34
- * Creates a new JWT expiry checker.
35
- *
36
- * @param token - The JWT token to parse
37
- */
38
- constructor(token) {
39
- this.token = token;
40
- try {
41
- const tokenContents = token.split(".")[1];
42
- this.payload = get_credentials_1.schema.parse((0, decode_base64_url_1.decodeBase64Url)(tokenContents));
43
- this.expiryTime = this.payload.exp || null;
44
- }
45
- catch {
46
- // Malformed token - treat as expired to trigger refresh
47
- this.expiryTime = 0;
48
- }
49
- }
50
- /**
51
- * Checks if the JWT token is valid (not expired).
52
- * @returns true if token is valid, false if expired or expiring soon
53
- */
54
- isValid() {
55
- if (this.expiryTime === null) {
56
- return false; // No expiry means malformed JWT
57
- }
58
- const now = Math.floor(Date.now() / 1000);
59
- const buffer = BUFFER_MS / 1000;
60
- return now + buffer < this.expiryTime;
61
- }
62
- /**
63
- * Gets the expiry date of the JWT token.
64
- *
65
- * @returns Date object representing when the token expires, or null if no expiry
66
- */
67
- getExpiryDate() {
68
- return this.expiryTime ? new Date(this.expiryTime * 1000) : null;
69
- }
70
- /**
71
- * Refreshes the JWT token by fetching a new OIDC token.
72
- *
73
- * @returns Promise resolving to a new JwtExpiry instance with fresh token
74
- */
75
- async refresh() {
76
- try {
77
- const freshToken = await (0, oidc_1.getVercelOidcToken)();
78
- return new JwtExpiry(freshToken);
79
- }
80
- catch (cause) {
81
- throw new OidcRefreshError("Failed to refresh OIDC token", {
82
- cause,
83
- });
84
- }
85
- }
86
- /**
87
- * Refreshes the JWT token if it's expired or expiring soon.
88
- */
89
- async tryRefresh() {
90
- if (this.isValid()) {
91
- return null; // Still valid, no need to refresh
92
- }
93
- return this.refresh();
94
- }
95
- }
96
- exports.JwtExpiry = JwtExpiry;
97
- /**
98
- * Checks if a token follows JWT format (has 3 parts separated by dots).
99
- *
100
- * @param token - The token to check
101
- * @returns true if token appears to be a JWT, false otherwise
102
- */
103
- function isJwtFormat(token) {
104
- return token.split(".").length === 3;
105
- }
106
- //# sourceMappingURL=jwt-expiry.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"jwt-expiry.js","sourceRoot":"","sources":["../../src/utils/jwt-expiry.ts"],"names":[],"mappings":";;;;;;AACA,2DAAsD;AACtD,uDAA2C;AAC3C,uCAAkD;AAClD,4CAAoB;AAEpB,+EAA+E;AAC/E,MAAM,SAAS,GAAG,IAAA,YAAE,EAAC,IAAI,CAAC,CAAC;AAE3B,MAAa,gBAAiB,SAAQ,KAAK;IAA3C;;QACE,SAAI,GAAG,kBAAkB,CAAC;IAC5B,CAAC;CAAA;AAFD,4CAEC;AAED;;;GAGG;AACH,MAAa,SAAS;IAIpB,MAAM,CAAC,SAAS,CAAC,KAAa;QAC5B,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC;QACd,CAAC;aAAM,CAAC;YACN,OAAO,IAAI,SAAS,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,YAAqB,KAAa;QAAb,UAAK,GAAL,KAAK,CAAQ;QAChC,IAAI,CAAC;YACH,MAAM,aAAa,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAC1C,IAAI,CAAC,OAAO,GAAG,wBAAM,CAAC,KAAK,CAAC,IAAA,mCAAe,EAAC,aAAa,CAAC,CAAC,CAAC;YAC5D,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC;QAC7C,CAAC;QAAC,MAAM,CAAC;YACP,wDAAwD;YACxD,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,OAAO;QACL,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;YAC7B,OAAO,KAAK,CAAC,CAAC,gCAAgC;QAChD,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;QAChC,OAAO,GAAG,GAAG,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC;IACxC,CAAC;IAED;;;;OAIG;IACH,aAAa;QACX,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACnE,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,OAAO;QACX,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,MAAM,IAAA,yBAAkB,GAAE,CAAC;YAC9C,OAAO,IAAI,SAAS,CAAC,UAAU,CAAC,CAAC;QACnC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,gBAAgB,CAAC,8BAA8B,EAAE;gBACzD,KAAK;aACN,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,UAAU;QACd,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;YACnB,OAAO,IAAI,CAAC,CAAC,kCAAkC;QACjD,CAAC;QAED,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC;IACxB,CAAC;CACF;AA7ED,8BA6EC;AAED;;;;;GAKG;AACH,SAAS,WAAW,CAAC,KAAa;IAChC,OAAO,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC;AACvC,CAAC"}