@hubspot/app-functions-dev-server
Advanced tools
Comparing version 0.8.38 to 0.8.39
import { http } from '@hubspot/local-dev-lib/http'; | ||
export type PrivateAppUserTokenResponse = { | ||
userId: number; | ||
portalId: number; | ||
appId: number; | ||
scopeGroups: Array<string>; | ||
userTokenKey: string; | ||
expiresAt: string; | ||
clientId: string; | ||
}; | ||
import type { PrivateAppUserToken } from '../types'; | ||
export type GetReturn<T> = ReturnType<typeof http.get<T>>; | ||
export type PostReturn<T> = ReturnType<typeof http.post<T>>; | ||
export type PutReturn<T> = ReturnType<typeof http.put<T>>; | ||
export declare function fetchPrivateAppUserToken(accountId: number, appId: number): GetReturn<PrivateAppUserTokenResponse>; | ||
export declare function createPrivateAppUserToken(accountId: number, appId: number, scopeGroups?: Array<string>, expiresAt?: string): PostReturn<PrivateAppUserTokenResponse>; | ||
export declare function updatePrivateAppUserToken(accountId: number, appId: number, userTokenKey: string, scopeGroups?: Array<string>, expiresAt?: string): PutReturn<PrivateAppUserTokenResponse>; | ||
interface TokenOptions { | ||
userTokenKey: string; | ||
scopeGroups?: string[]; | ||
expiresAt?: string; | ||
privateAppToken?: string; | ||
} | ||
interface UserOptions { | ||
accountId: number; | ||
appId: number; | ||
} | ||
export declare function fetchPrivateAppUserToken({ accountId, appId, }: UserOptions): GetReturn<PrivateAppUserToken>; | ||
export declare function createPrivateAppUserToken({ accountId, appId, scopeGroups, expiresAt, privateAppToken, }: UserOptions & Partial<TokenOptions>): PostReturn<PrivateAppUserToken>; | ||
export declare function updatePrivateAppUserToken({ accountId, appId, userTokenKey, scopeGroups, expiresAt, privateAppToken, }: TokenOptions & UserOptions): PutReturn<PrivateAppUserToken>; | ||
export {}; |
@@ -6,3 +6,3 @@ "use strict"; | ||
const LOCALDEVAUTH_API_PRIVATE_APP_USER_TOKEN_PATH = 'localdevauth/v1/private-app/user-token'; | ||
async function fetchPrivateAppUserToken(accountId, appId) { | ||
async function fetchPrivateAppUserToken({ accountId, appId, }) { | ||
return await http_1.http.get(accountId, { | ||
@@ -13,3 +13,3 @@ url: `${LOCALDEVAUTH_API_PRIVATE_APP_USER_TOKEN_PATH}/${appId}`, | ||
exports.fetchPrivateAppUserToken = fetchPrivateAppUserToken; | ||
async function createPrivateAppUserToken(accountId, appId, scopeGroups, expiresAt) { | ||
async function createPrivateAppUserToken({ accountId, appId, scopeGroups, expiresAt, privateAppToken, }) { | ||
return await http_1.http.post(accountId, { | ||
@@ -20,2 +20,3 @@ url: `${LOCALDEVAUTH_API_PRIVATE_APP_USER_TOKEN_PATH}/${appId}`, | ||
...(expiresAt && { expiresAt }), | ||
...(privateAppToken && { privateAppToken }), | ||
}, | ||
@@ -25,3 +26,3 @@ }); | ||
exports.createPrivateAppUserToken = createPrivateAppUserToken; | ||
async function updatePrivateAppUserToken(accountId, appId, userTokenKey, scopeGroups, expiresAt) { | ||
async function updatePrivateAppUserToken({ accountId, appId, userTokenKey, scopeGroups, expiresAt, privateAppToken, }) { | ||
return await http_1.http.put(accountId, { | ||
@@ -33,2 +34,3 @@ url: `${LOCALDEVAUTH_API_PRIVATE_APP_USER_TOKEN_PATH}/${appId}`, | ||
...(expiresAt && { expiresAt }), | ||
...(privateAppToken && { privateAppToken }), | ||
}, | ||
@@ -35,0 +37,0 @@ }); |
import { FunctionCallback, LocalExecutionInputs, ServiceConfiguration } from './types'; | ||
export declare function executeFunction(config: ServiceConfiguration, functionName: string, localExecutionInputs: LocalExecutionInputs, callback: FunctionCallback): Promise<void>; | ||
import { PrivateAppUserTokenManager } from './services/PrivateAppUserTokenManager'; | ||
export declare function executeFunction(config: ServiceConfiguration, functionName: string, localExecutionInputs: LocalExecutionInputs, callback: FunctionCallback, privateAppUserTokenManager?: PrivateAppUserTokenManager): Promise<void>; |
@@ -17,5 +17,5 @@ "use strict"; | ||
const constants_1 = require("./constants"); | ||
async function executeFunction(config, functionName, localExecutionInputs, callback) { | ||
async function executeFunction(config, functionName, localExecutionInputs, callback, privateAppUserTokenManager) { | ||
const { logger } = config; | ||
const { appId, privateAppUserToken } = localExecutionInputs; | ||
const { appId } = localExecutionInputs; | ||
const functionInfo = (0, config_1.loadFunctionInfo)(config, functionName, appId); | ||
@@ -41,6 +41,12 @@ const functionPath = path_1.default.resolve(path_1.default.join(functionInfo.srcDir, functionInfo.file)); | ||
const savedEnv = { ...process.env }; | ||
const secrets = (0, secrets_1.loadSecrets)(functionInfo.srcDir, { | ||
logger, | ||
privateAppUserToken, | ||
}); | ||
const initialSecrets = (0, secrets_1.loadSecrets)(functionInfo.srcDir); | ||
// app token from the env file | ||
const privateAppToken = process.env[constants_1.PRIVATE_APP_ACCESS_TOKEN]; | ||
// fetch the user token from the local dev service | ||
const privateAppUserToken = typeof appId === 'number' | ||
? await privateAppUserTokenManager?.getPrivateAppUserToken(appId, { | ||
privateAppToken, | ||
}) | ||
: undefined; | ||
const secrets = (0, secrets_1.setProperTokenInSecrets)(initialSecrets, logger, privateAppUserToken); | ||
const { deleted: missingSecrets } = (0, utils_1.diffLists)( | ||
@@ -47,0 +53,0 @@ // secrets expected |
@@ -1,7 +0,5 @@ | ||
import { FunctionContext, ProxyServiceConfig } from './types'; | ||
interface LoadSecretsOptions { | ||
logger: ProxyServiceConfig['logger']; | ||
privateAppUserToken?: string; | ||
} | ||
export declare function loadSecrets(srcDir: string, options?: LoadSecretsOptions): FunctionContext['secrets']; | ||
import type { FunctionContext, ProxyServiceConfig, PrivateAppUserToken } from './types'; | ||
type Secrets = FunctionContext['secrets']; | ||
export declare function setProperTokenInSecrets(secrets: Secrets, logger: ProxyServiceConfig['logger'], privateAppUserToken?: PrivateAppUserToken): Secrets; | ||
export declare function loadSecrets(srcDir: string): Secrets; | ||
export {}; |
@@ -6,3 +6,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.loadSecrets = void 0; | ||
exports.loadSecrets = exports.setProperTokenInSecrets = void 0; | ||
const fs_1 = __importDefault(require("fs")); | ||
@@ -12,2 +12,3 @@ const path_1 = __importDefault(require("path")); | ||
const constants_1 = require("./constants"); | ||
const PrivateAppUserTokenManager_1 = require("./services/PrivateAppUserTokenManager"); | ||
function getEnvPath(srcDir) { | ||
@@ -21,9 +22,26 @@ const mode = process.env.NODE_ENV; | ||
} | ||
function loadSecrets(srcDir, options) { | ||
if (options?.privateAppUserToken) { | ||
if (process.env[constants_1.PRIVATE_APP_ACCESS_TOKEN]) { | ||
options.logger.info('The private app user token was overridden by the PRIVATE_APP_ACCESS_TOKEN in the environment file. For local development, you no longer need a PRIVATE_APP_ACCESS_TOKEN in the environment file. You can safely remove it.'); | ||
function setProperTokenInSecrets(secrets, logger, privateAppUserToken) { | ||
if (!privateAppUserToken) | ||
return secrets; | ||
const privateAppToken = secrets?.[constants_1.PRIVATE_APP_ACCESS_TOKEN]; | ||
if (privateAppToken && privateAppUserToken) { | ||
/* | ||
* Make sure that the privateAppUserToken has all the scopes from the privateAppToken. | ||
* If they do, suggest that they remove the privateAppToken from the environment file. | ||
*/ | ||
if (PrivateAppUserTokenManager_1.PrivateAppUserTokenManager.doesUserTokenContainAppTokenScopes(privateAppUserToken)) { | ||
logger.info('The private app user token was overridden by the PRIVATE_APP_ACCESS_TOKEN in the environment file. For local development, you no longer need a PRIVATE_APP_ACCESS_TOKEN in the environment file. You can safely remove it.'); | ||
} | ||
process.env[constants_1.PRIVATE_APP_ACCESS_TOKEN] = options.privateAppUserToken; | ||
// privateAppToken it's already in the secrets and it takes precedence. just return | ||
return secrets; | ||
} | ||
// has only one of the tokens. Set the proper one in the secrets taking into account that privateAppToken takes precedence | ||
const result = { ...secrets }; | ||
const theToken = privateAppToken ?? privateAppUserToken?.userTokenKey; | ||
result[constants_1.PRIVATE_APP_ACCESS_TOKEN] = theToken; | ||
process.env[constants_1.PRIVATE_APP_ACCESS_TOKEN] = theToken; | ||
return result; | ||
} | ||
exports.setProperTokenInSecrets = setProperTokenInSecrets; | ||
function loadSecrets(srcDir) { | ||
// Load secrets into process.env | ||
@@ -30,0 +48,0 @@ dotenv_1.default.config({ |
@@ -32,4 +32,3 @@ "use strict"; | ||
try { | ||
const privateAppUserToken = await privateAppUserTokenManager.getPrivateAppUserToken(appId); | ||
await (0, executor_1.executeFunction)(config, functionName, { appId, objectQuery, parameters, event, privateAppUserToken }, onSuccess); | ||
await (0, executor_1.executeFunction)(config, functionName, { appId, objectQuery, parameters, event }, onSuccess, privateAppUserTokenManager); | ||
} | ||
@@ -36,0 +35,0 @@ catch (err) { |
@@ -1,2 +0,6 @@ | ||
import type { ServiceConfiguration } from '../types'; | ||
import type { ServiceConfiguration, PrivateAppUserToken } from '../types'; | ||
export interface GetPrivateAppUserTokenOptions { | ||
scopeGroups?: string[]; | ||
privateAppToken?: string; | ||
} | ||
export declare class PrivateAppUserTokenManager { | ||
@@ -11,3 +15,3 @@ accountId: number; | ||
cleanup(): void; | ||
getPrivateAppUserToken(appId: number, scopeGroups?: string[]): Promise<string | undefined>; | ||
getPrivateAppUserToken(appId: number, { scopeGroups, privateAppToken }?: GetPrivateAppUserTokenOptions): Promise<PrivateAppUserToken | undefined>; | ||
private cacheToken; | ||
@@ -18,2 +22,3 @@ private validateToken; | ||
private getExistingToken; | ||
static doesUserTokenContainAppTokenScopes(privateAppUserToken: PrivateAppUserToken): boolean; | ||
} |
@@ -50,3 +50,3 @@ "use strict"; | ||
} | ||
async getPrivateAppUserToken(appId, scopeGroups = []) { | ||
async getPrivateAppUserToken(appId, { scopeGroups = [], privateAppToken } = {}) { | ||
if (!this.isEnabled()) { | ||
@@ -61,3 +61,3 @@ this.logger.debug((0, messages_1.generateTokensNotEnabledMessage)(this.accountId, appId)); | ||
this.logger.debug((0, messages_1.generateCahedTokeMessage)(appId)); | ||
return tokenInCache.token.userTokenKey; | ||
return tokenInCache.token; | ||
} | ||
@@ -69,4 +69,5 @@ let token = await this.getExistingToken(appId); | ||
appId, | ||
scopeGroups, | ||
privateAppToken, | ||
userTokenKey: token.userTokenKey, | ||
scopeGroups, | ||
}); | ||
@@ -76,6 +77,6 @@ } | ||
else if (token === null) { | ||
token = await this.createNewToken(appId, scopeGroups); | ||
token = await this.createNewToken(appId, scopeGroups, privateAppToken); | ||
} | ||
this.cacheToken(appId, token, scopeGroups); | ||
return token.userTokenKey; | ||
return token; | ||
} | ||
@@ -121,5 +122,11 @@ catch (err) { | ||
} | ||
async createNewToken(appId, scopeGroups) { | ||
async createNewToken(appId, scopeGroups, privateAppToken) { | ||
this.logger.debug((0, messages_1.generateCreateTokenMessage)(appId)); | ||
const response = await (0, privateAppUserToken_1.createPrivateAppUserToken)(this.accountId, appId, scopeGroups, getTokenExpirationDate()); | ||
const response = await (0, privateAppUserToken_1.createPrivateAppUserToken)({ | ||
appId, | ||
scopeGroups, | ||
privateAppToken, | ||
accountId: this.accountId, | ||
expiresAt: getTokenExpirationDate(), | ||
}); | ||
if (response.status === 200) { | ||
@@ -134,5 +141,12 @@ return response.data; | ||
} | ||
async updateToken({ appId, userTokenKey, scopeGroups, }) { | ||
async updateToken({ appId, userTokenKey, scopeGroups, privateAppToken, }) { | ||
this.logger.debug((0, messages_1.generateTokenRefreshMessage)(appId)); | ||
const response = await (0, privateAppUserToken_1.updatePrivateAppUserToken)(this.accountId, appId, userTokenKey, scopeGroups, getTokenExpirationDate()); | ||
const response = await (0, privateAppUserToken_1.updatePrivateAppUserToken)({ | ||
appId, | ||
userTokenKey, | ||
scopeGroups, | ||
privateAppToken, | ||
accountId: this.accountId, | ||
expiresAt: getTokenExpirationDate(), | ||
}); | ||
if (response.status === 200) { | ||
@@ -149,3 +163,6 @@ return response.data; | ||
try { | ||
const response = await (0, privateAppUserToken_1.fetchPrivateAppUserToken)(this.accountId, appId); | ||
const response = await (0, privateAppUserToken_1.fetchPrivateAppUserToken)({ | ||
accountId: this.accountId, | ||
appId, | ||
}); | ||
if (response.status === 200) { | ||
@@ -163,3 +180,15 @@ return response.data; | ||
} | ||
static doesUserTokenContainAppTokenScopes(privateAppUserToken) { | ||
const privateAppToken = privateAppUserToken.privateAppTokenInfo; | ||
// if the private app token is not present, we can't compare the scopes | ||
if (!privateAppToken) | ||
return false; | ||
const privateAppTokenScopes = privateAppToken.scopeGroups ?? []; | ||
const privateAppUserTokenScopes = privateAppUserToken.scopeGroups ?? []; | ||
const areBothEmpty = privateAppUserTokenScopes.length === 0 && | ||
privateAppTokenScopes.length === 0; | ||
return (areBothEmpty || | ||
privateAppTokenScopes.every((scope) => privateAppUserTokenScopes.includes(scope))); | ||
} | ||
} | ||
exports.PrivateAppUserTokenManager = PrivateAppUserTokenManager; |
@@ -114,3 +114,2 @@ /// <reference types="node" /> | ||
event?: ServerlessExecutionRequest['event']; | ||
privateAppUserToken?: string; | ||
} | ||
@@ -160,2 +159,18 @@ export interface LocalDevUrlMapping { | ||
} | ||
export type PrivateAppUserToken = { | ||
userId: number; | ||
portalId: number; | ||
appId: number; | ||
scopeGroups: string[]; | ||
userTokenKey: string; | ||
expiresAt: string; | ||
clientId: string; | ||
privateAppTokenInfo?: { | ||
userId: number; | ||
portalId: number; | ||
appId: number; | ||
scopeGroups: string[]; | ||
expiresAt: string; | ||
}; | ||
}; | ||
export {}; |
{ | ||
"name": "@hubspot/app-functions-dev-server", | ||
"version": "0.8.38", | ||
"version": "0.8.39", | ||
"description": "A tool for testing HubSpot private app functions locally", | ||
@@ -19,3 +19,3 @@ "engines": { | ||
"axios": "^1.6.8", | ||
"body-parser": "1.20.2", | ||
"body-parser": "1.20.3", | ||
"cors": "^2.8.5", | ||
@@ -55,3 +55,3 @@ "dotenv": "^16.3.1", | ||
}, | ||
"gitHead": "87aa6e40049142bccafd175446fbd7d5c08caab6" | ||
"gitHead": "3dbfe0afee58682d51c4a5eb7e0e40a6e3920631" | ||
} |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
68232
1520
0
- Removedbody-parser@1.20.2(transitive)
- Removedqs@6.11.0(transitive)
Updatedbody-parser@1.20.3