in src/function-builder.ts [52:233]
function assertRuntimeOptionsValid(runtimeOptions: RuntimeOptions): boolean {
if (
runtimeOptions.memory &&
!_.includes(VALID_MEMORY_OPTIONS, runtimeOptions.memory)
) {
throw new Error(
`The only valid memory allocation values are: ${VALID_MEMORY_OPTIONS.join(
', '
)}`
);
}
if (
runtimeOptions.timeoutSeconds > MAX_TIMEOUT_SECONDS ||
runtimeOptions.timeoutSeconds < 0
) {
throw new Error(
`TimeoutSeconds must be between 0 and ${MAX_TIMEOUT_SECONDS}`
);
}
if (
runtimeOptions.ingressSettings &&
!_.includes(INGRESS_SETTINGS_OPTIONS, runtimeOptions.ingressSettings)
) {
throw new Error(
`The only valid ingressSettings values are: ${INGRESS_SETTINGS_OPTIONS.join(
','
)}`
);
}
if (
runtimeOptions.vpcConnectorEgressSettings &&
!_.includes(
VPC_EGRESS_SETTINGS_OPTIONS,
runtimeOptions.vpcConnectorEgressSettings
)
) {
throw new Error(
`The only valid vpcConnectorEgressSettings values are: ${VPC_EGRESS_SETTINGS_OPTIONS.join(
','
)}`
);
}
if (runtimeOptions.failurePolicy !== undefined) {
if (
_.isBoolean(runtimeOptions.failurePolicy) === false &&
_.isObjectLike(runtimeOptions.failurePolicy) === false
) {
throw new Error(`failurePolicy must be a boolean or an object.`);
}
if (typeof runtimeOptions.failurePolicy === 'object') {
if (
_.isObjectLike(runtimeOptions.failurePolicy.retry) === false ||
_.isEmpty(runtimeOptions.failurePolicy.retry) === false
) {
throw new Error('failurePolicy.retry must be an empty object.');
}
}
}
if (
runtimeOptions.serviceAccount &&
runtimeOptions.serviceAccount !== 'default' &&
!_.includes(runtimeOptions.serviceAccount, '@')
) {
throw new Error(
`serviceAccount must be set to 'default', a service account email, or '{serviceAccountName}@'`
);
}
if (runtimeOptions.labels) {
// Labels must follow the rules listed in
// https://cloud.google.com/resource-manager/docs/creating-managing-labels#requirements
if (Object.keys(runtimeOptions.labels).length > MAX_NUMBER_USER_LABELS) {
throw new Error(
`A function must not have more than ${MAX_NUMBER_USER_LABELS} user-defined labels.`
);
}
// We reserve the 'deployment' and 'firebase' namespaces for future feature development.
const reservedKeys = Object.keys(runtimeOptions.labels).filter(
(key) => key.startsWith('deployment') || key.startsWith('firebase')
);
if (reservedKeys.length) {
throw new Error(
`Invalid labels: ${reservedKeys.join(
', '
)}. Labels may not start with reserved names 'deployment' or 'firebase'`
);
}
const invalidLengthKeys = Object.keys(runtimeOptions.labels).filter(
(key) => key.length < 1 || key.length > 63
);
if (invalidLengthKeys.length > 0) {
throw new Error(
`Invalid labels: ${invalidLengthKeys.join(
', '
)}. Label keys must be between 1 and 63 characters in length.`
);
}
const invalidLengthValues = Object.values(runtimeOptions.labels).filter(
(value) => value.length > 63
);
if (invalidLengthValues.length > 0) {
throw new Error(
`Invalid labels: ${invalidLengthValues.join(
', '
)}. Label values must be less than 64 charcters.`
);
}
// Keys can contain lowercase letters, foreign characters, numbers, _ or -. They must start with a letter.
const validKeyPattern = /^[\p{Ll}\p{Lo}][\p{Ll}\p{Lo}\p{N}_-]{0,62}$/u;
const invalidKeys = Object.keys(runtimeOptions.labels).filter(
(key) => !validKeyPattern.test(key)
);
if (invalidKeys.length > 0) {
throw new Error(
`Invalid labels: ${invalidKeys.join(
', '
)}. Label keys can only contain lowercase letters, international characters, numbers, _ or -, and must start with a letter.`
);
}
// Values can contain lowercase letters, foreign characters, numbers, _ or -.
const validValuePattern = /^[\p{Ll}\p{Lo}\p{N}_-]{0,63}$/u;
const invalidValues = Object.values(runtimeOptions.labels).filter(
(value) => !validValuePattern.test(value)
);
if (invalidValues.length > 0) {
throw new Error(
`Invalid labels: ${invalidValues.join(
', '
)}. Label values can only contain lowercase letters, international characters, numbers, _ or -.`
);
}
}
if (
typeof runtimeOptions.invoker === 'string' &&
runtimeOptions.invoker.length === 0
) {
throw new Error(
'Invalid service account for function invoker, must be a non-empty string'
);
}
if (
runtimeOptions.invoker !== undefined &&
Array.isArray(runtimeOptions.invoker)
) {
if (runtimeOptions.invoker.length === 0) {
throw new Error(
'Invalid invoker array, must contain at least 1 service account entry'
);
}
for (const serviceAccount of runtimeOptions.invoker) {
if (serviceAccount.length === 0) {
throw new Error(
'Invalid invoker array, a service account must be a non-empty string'
);
}
if (serviceAccount === 'public') {
throw new Error(
"Invalid invoker array, a service account cannot be set to the 'public' identifier"
);
}
if (serviceAccount === 'private') {
throw new Error(
"Invalid invoker array, a service account cannot be set to the 'private' identifier"
);
}
}
}
return true;
}