@foxtware/mineral 0.1.5 → 0.1.7

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.
@@ -0,0 +1,46 @@
1
+ const { SLACK_API_BASE_URL } = require('../slack/slack.constants');
2
+ const {
3
+ FetchClient,
4
+ Chain,
5
+ appendUrlToBase,
6
+ fetchClientCommonSteps,
7
+ } = require('../utils');
8
+
9
+ const addUrlAndAuthHeaders = async (state) => {
10
+ const { requestPayload, context } = state;
11
+ const { creds } = context;
12
+ const {
13
+ BOT_TOKEN,
14
+ } = creds;
15
+
16
+ return {
17
+ requestPayload: {
18
+ ...requestPayload,
19
+ method: requestPayload.method || 'post',
20
+ url: appendUrlToBase(SLACK_API_BASE_URL, requestPayload.url),
21
+ headers: {
22
+ 'Content-Type': 'application/json',
23
+ Authorization: `Bearer ${ BOT_TOKEN }`,
24
+ ...requestPayload.headers,
25
+ },
26
+ },
27
+ };
28
+ };
29
+
30
+
31
+ const slackClientRequestPreparer = new Chain([
32
+ addUrlAndAuthHeaders,
33
+ ]);
34
+
35
+ const slackClientResponseInterpreter = new Chain([
36
+ fetchClientCommonSteps.exitEarlyOnNotOk,
37
+ ]);
38
+
39
+ const slackClient = new FetchClient({
40
+ requestPreparer: slackClientRequestPreparer,
41
+ responseInterpreter: slackClientResponseInterpreter,
42
+ });
43
+
44
+ module.exports = {
45
+ slackClient,
46
+ };
@@ -0,0 +1,85 @@
1
+ // https://docs.slack.dev/reference/methods/chat.postmessage
2
+
3
+ const { credsFromPayload, objHasAny, ArgsWarden } = require('../utils');
4
+ const { credsValidator } = require('../validators');
5
+ const { slackClient } = require('../slack/slack.utils');
6
+
7
+ const channelIdentifierValidator = (channelIdentifier) => {
8
+ return objHasAny(channelIdentifier, ['channelName', 'channelId']);
9
+ };
10
+
11
+ const messagePayloadValidator = (messagePayload) => {
12
+ return objHasAny(messagePayload, ['text', 'blocks', 'markdownText']);
13
+ };
14
+
15
+ const argsWarden = new ArgsWarden([
16
+ ['credsPayload', credsValidator],
17
+ ['channelIdentifier', channelIdentifierValidator],
18
+ ['messagePayload', messagePayloadValidator],
19
+ ]);
20
+
21
+ const slackMessagePost = async (
22
+ credsPayload,
23
+ channelIdentifier,
24
+ messagePayload,
25
+ {
26
+ inspect = false,
27
+ } = {},
28
+ ) => {
29
+
30
+ const rejectResponse = await argsWarden.responseIfRejectingArgs({
31
+ credsPayload,
32
+ channelIdentifier,
33
+ messagePayload,
34
+ });
35
+ if (rejectResponse) {
36
+ return rejectResponse;
37
+ }
38
+
39
+ const creds = await credsFromPayload(credsPayload);
40
+
41
+ const {
42
+ channelName,
43
+ channelId,
44
+ } = channelIdentifier;
45
+
46
+ const {
47
+ text,
48
+ blocks,
49
+ markdownText,
50
+ } = messagePayload;
51
+
52
+ const response = await slackClient.fetch({
53
+ url: '/chat.postMessage',
54
+ method: 'post',
55
+ body: {
56
+ channel: channelId || channelName,
57
+ ...text && { text },
58
+ ...blocks && { blocks },
59
+ ...markdownText && { markdown_text: markdownText },
60
+ },
61
+ context: { creds },
62
+ inspect,
63
+ });
64
+
65
+ return response;
66
+ };
67
+
68
+ const funcApiConfig = {
69
+ argsWarden,
70
+ };
71
+
72
+ module.exports = {
73
+ slackMessagePost,
74
+ funcApiConfig,
75
+ };
76
+
77
+ /*
78
+ curl -X POST "http://localhost:8000/slackMessagePost" \
79
+ -H "Content-Type: application/json" \
80
+ -d '{
81
+ "credsPayload": { "credsPath": "slack" },
82
+ "channelIdentifier": { "channelName": "#hidden_testing" },
83
+ "messagePayload": { "text": "new number, who dis?" }
84
+ }'
85
+ */
package/api/utils.js CHANGED
@@ -146,14 +146,14 @@ const customFetch = async (url, {
146
146
  });
147
147
 
148
148
  const responseContentType = response.headers.get('content-type');
149
- console.log(responseContentType);
149
+ !HOSTED && console.log('responseContentType', responseContentType);
150
150
 
151
151
  if (!responseParser) {
152
152
  responseParser = getResponseParser(responseContentType);
153
153
  }
154
154
 
155
155
  const parsedResponse = await responseParser(response);
156
- logDeep({ parsedResponse });
156
+ !HOSTED && logDeep({ parsedResponse });
157
157
 
158
158
  if (response.ok) {
159
159
  return {
@@ -278,7 +278,6 @@ const pathAsArray = (path) => {
278
278
 
279
279
  const objectDigNodeAtPath = (obj, path) => {
280
280
  let nodes = pathAsArray(path);
281
- console.log(nodes);
282
281
 
283
282
  let output = obj;
284
283
  for (const node of nodes) {
@@ -1161,7 +1160,6 @@ module.exports = {
1161
1160
  actionSingleOrMultiple,
1162
1161
  Processor,
1163
1162
  Getter,
1164
- capitaliseString,
1165
1163
  sentenceCaseString,
1166
1164
  ArgsWarden,
1167
1165
  };
package/bin/mineral.js CHANGED
@@ -3,7 +3,7 @@
3
3
  const command = process.argv[2];
4
4
 
5
5
  if (command === 'host') {
6
- const { deployFromHostingYml } = require('../_deploy_scripts/deployFromHostingYml');
6
+ const { deployFromHostingYml } = require('../hosting/deployFromHostingYml');
7
7
  deployFromHostingYml().catch((error) => {
8
8
  console.error(error);
9
9
  process.exit(1);
@@ -4,21 +4,18 @@ google_cloud_info:
4
4
 
5
5
  # TODO: consider credsPayload in google_cloud_info instead of workspace .creds.yml
6
6
 
7
- env:
8
- - HOSTED_API_KEY
9
-
10
7
  functions:
11
8
  exampleFunction:
12
9
  max_instances: 1
13
10
  timeout: 300s
14
- wrappers:
15
- # entry_point: otherExportName
16
- - requireHostedApiKey
11
+ before_wrappers:
17
12
  - allowCrossOriginCallsAndHandleOptions
13
+ - requireHostedApiKey
14
+ # entry_point: otherHandlerName
18
15
 
19
16
  pokemonPokeballThrow:
20
17
  max_instances: 1
21
- wrappers:
18
+ before_wrappers:
22
19
  - checkTrainer
23
20
 
24
21
  groups:
@@ -0,0 +1,48 @@
1
+ const fs = require('fs');
2
+ const yaml = require('yaml');
3
+
4
+ const copyCredsToEnv = (workspace) => {
5
+ const normalizedWorkspace = workspace.replace(/\/$/, '');
6
+ const credsPath = `${ normalizedWorkspace }/.creds.yml`;
7
+ const envPath = `${ normalizedWorkspace }/.env`;
8
+
9
+ if (!fs.existsSync(credsPath)) {
10
+ throw new Error(`Missing .creds.yml in workspace: ${ workspace }`);
11
+ }
12
+
13
+ const credsText = fs.readFileSync(credsPath, 'utf8');
14
+ const credsFromYml = yaml.parse(credsText);
15
+ const newCredsLine = `CREDS=${ JSON.stringify(credsFromYml) }`;
16
+
17
+ let envFileContents = '';
18
+ if (fs.existsSync(envPath)) {
19
+ envFileContents = fs.readFileSync(envPath, 'utf8');
20
+ }
21
+
22
+ if (!envFileContents) {
23
+ fs.writeFileSync(envPath, `${ newCredsLine }\n`);
24
+ return;
25
+ }
26
+
27
+ if (/^CREDS=/m.test(envFileContents)) {
28
+ const updatedFileContents = envFileContents.replace(/^CREDS=.*$/m, newCredsLine);
29
+
30
+ if (updatedFileContents !== envFileContents) {
31
+ fs.writeFileSync(envPath, updatedFileContents);
32
+ }
33
+
34
+ return;
35
+ }
36
+
37
+ fs.appendFileSync(envPath, `\n\n${ newCredsLine }\n`);
38
+ };
39
+
40
+ if (require.main === module) {
41
+ const workspace = process.argv[2] || process.cwd();
42
+ copyCredsToEnv(workspace);
43
+ console.log('Copied CREDS from .creds.yml to .env');
44
+ }
45
+
46
+ module.exports = {
47
+ copyCredsToEnv,
48
+ };
@@ -1,14 +1,13 @@
1
1
  const readline = require('readline');
2
- const { toAbsolutePath, setWorkspace } = require('../api/workspace');
2
+ const { toAbsolutePath, setWorkspace, loadWorkspaceEnv } = require('../api/workspace');
3
3
  const { getApiDirs, readCliFlag } = require('../cli');
4
4
  const { loadHandlers } = require('../server');
5
5
  const {
6
6
  readHostingYml,
7
- getCredsJsonForDeploy,
8
- validateEnvVarsForDeploy,
7
+ ensureWorkspaceEnvForDeploy,
9
8
  resolveHostedHandlersForDeploy,
10
9
  functionUsesWrapper,
11
- } = require('../hosting.utils');
10
+ } = require('./hosting.utils');
12
11
  const { writeHostedJs } = require('./generateHosted');
13
12
  const { execCommand } = require('./execCommand');
14
13
  const { formatSetEnvVarsForGcloud, shellQuoteSingle } = require('./setEnvVarsGcloud');
@@ -91,8 +90,6 @@ const deployFunction = async ({
91
90
  functionConfig,
92
91
  googleCloudInfo,
93
92
  workspace,
94
- credsJson,
95
- deployEnvVars = {},
96
93
  }) => {
97
94
  const config = {
98
95
  ...googleCloudInfo,
@@ -107,20 +104,17 @@ const deployFunction = async ({
107
104
  allow_unauthenticated: allowUnauthenticated = true,
108
105
  gen2 = true,
109
106
  set_env_vars: extraSetEnvVars,
110
- entry_point: entryPoint,
107
+ entry_point,
111
108
  schedules,
112
109
  groups,
113
- wrappers,
110
+ before_wrappers,
111
+ after_wrappers,
114
112
  source,
113
+ env,
115
114
  ...gcloudArgs
116
115
  } = config;
117
116
 
118
- const resolvedEntryPoint = entryPoint || functionName;
119
- const envParts = [
120
- 'HOSTED=true',
121
- `CREDS=${ credsJson }`,
122
- ...Object.entries(deployEnvVars).map(([envName, envValue]) => `${ envName }=${ envValue }`),
123
- ];
117
+ const envParts = ['HOSTED=true'];
124
118
 
125
119
  if (extraSetEnvVars) {
126
120
  envParts.push(extraSetEnvVars);
@@ -134,7 +128,7 @@ const deployFunction = async ({
134
128
  `--project ${ project }`,
135
129
  `--region ${ region }`,
136
130
  `--source ${ shellQuoteSingle(workspace) }`,
137
- `--entry-point ${ resolvedEntryPoint }`,
131
+ `--entry-point ${ functionName }`,
138
132
  `--trigger-${ trigger }`,
139
133
  `--runtime ${ runtime }`,
140
134
  `--set-env-vars ${ shellQuoteSingle(setEnvVarsForGcloud) }`,
@@ -157,7 +151,7 @@ const deployFunction = async ({
157
151
  }
158
152
 
159
153
  const requiresHostedApiKey = functionUsesWrapper(functionConfig, 'requireHostedApiKey');
160
- const hostedApiKey = deployEnvVars.HOSTED_API_KEY;
154
+ const hostedApiKey = process.env.HOSTED_API_KEY;
161
155
 
162
156
  for (const schedule of schedules) {
163
157
  const {
@@ -203,17 +197,18 @@ const deployFunction = async ({
203
197
  const deployFromHostingYml = async (options = {}) => {
204
198
  const config = getHostConfig(options);
205
199
  setWorkspace(config.workspace);
200
+ ensureWorkspaceEnvForDeploy(config.workspace);
201
+ loadWorkspaceEnv();
206
202
 
207
203
  const hostingConfig = readHostingYml(config.workspace);
208
204
  const {
209
205
  google_cloud_info: googleCloudInfo,
210
- env: envNames = [],
211
206
  functions = {},
212
207
  groups = {},
213
208
  } = hostingConfig;
214
209
 
215
210
  if (!googleCloudInfo?.project || !googleCloudInfo?.region) {
216
- throw new Error('.hosting.yml requires google_cloud_info.project and google_cloud_info.region');
211
+ throw new Error('hosting/.hosting.yml requires google_cloud_info.project and google_cloud_info.region');
217
212
  }
218
213
 
219
214
  const handlers = loadHandlers({
@@ -227,19 +222,16 @@ const deployFromHostingYml = async (options = {}) => {
227
222
  handlersByName,
228
223
  });
229
224
 
230
- const deployEnvVars = validateEnvVarsForDeploy(config.workspace, envNames);
231
-
232
225
  writeHostedJs({
233
226
  workspace: config.workspace,
234
227
  hostedHandlers,
235
228
  });
236
229
 
237
- const credsJson = getCredsJsonForDeploy(config.workspace);
238
230
  const deployArgs = getDeployArgs();
239
231
 
240
232
  const deployOne = async (functionName) => {
241
233
  if (!functions[functionName]) {
242
- console.log(`Function ${ functionName } not found in .hosting.yml, skipping`);
234
+ console.log(`Function ${ functionName } not found in hosting/.hosting.yml, skipping`);
243
235
  return;
244
236
  }
245
237
 
@@ -248,15 +240,13 @@ const deployFromHostingYml = async (options = {}) => {
248
240
  functionConfig: functions[functionName],
249
241
  googleCloudInfo,
250
242
  workspace: config.workspace,
251
- credsJson,
252
- deployEnvVars,
253
243
  });
254
244
  };
255
245
 
256
246
  if (deployArgs.includes('group')) {
257
247
  const groupNames = Object.keys(groups);
258
248
  if (!groupNames.length) {
259
- console.log('No groups defined in .hosting.yml');
249
+ console.log('No groups defined in hosting/.hosting.yml');
260
250
  return;
261
251
  }
262
252
 
@@ -270,7 +260,7 @@ const deployFromHostingYml = async (options = {}) => {
270
260
  if (deployArgs.includes('function')) {
271
261
  const functionNames = Object.keys(functions);
272
262
  if (!functionNames.length) {
273
- console.log('No functions defined in .hosting.yml');
263
+ console.log('No functions defined in hosting/.hosting.yml');
274
264
  return;
275
265
  }
276
266
 
@@ -305,14 +295,3 @@ module.exports = {
305
295
  deployFromHostingYml,
306
296
  getHostConfig,
307
297
  };
308
-
309
- /*
310
- Deploy everything:
311
- mineral host all
312
-
313
- Deploy a single function:
314
- mineral host function
315
-
316
- Deploy a group of functions:
317
- mineral host group
318
- */
@@ -0,0 +1,87 @@
1
+ const fs = require('fs');
2
+ const { wrapHostedFunction } = require('./hosting.utils');
3
+
4
+ const formatResolvedWrapperForHostedJs = ({ modulePath, wrapperName }) => (
5
+ `require('${ modulePath }').${ wrapperName }`
6
+ );
7
+
8
+ const formatWrapperList = (resolvedWrappers = []) => {
9
+ if (!resolvedWrappers.length) {
10
+ return '';
11
+ }
12
+
13
+ const wrapperLines = resolvedWrappers.map((resolvedWrapper) => (
14
+ ` ${ formatResolvedWrapperForHostedJs(resolvedWrapper) },`
15
+ ));
16
+
17
+ return `\n${ wrapperLines.join('\n') }\n `;
18
+ };
19
+
20
+ const formatWrappersArg = ({
21
+ resolvedBeforeWrappers = [],
22
+ resolvedAfterWrappers = [],
23
+ } = {}) => {
24
+ if (!resolvedBeforeWrappers.length && !resolvedAfterWrappers.length) {
25
+ return '';
26
+ }
27
+
28
+ const beforeWrappersBlock = formatWrapperList(resolvedBeforeWrappers);
29
+ const afterWrappersBlock = formatWrapperList(resolvedAfterWrappers);
30
+
31
+ return `, {
32
+ beforeWrappers: [${ beforeWrappersBlock }],
33
+ afterWrappers: [${ afterWrappersBlock }],
34
+ }`;
35
+ };
36
+
37
+ const generateHostedJs = ({
38
+ hostedHandlers,
39
+ }) => {
40
+ const exportLines = [];
41
+
42
+ for (const hostedHandler of hostedHandlers) {
43
+ const {
44
+ hostedName,
45
+ handlerName,
46
+ resolvedBeforeWrappers = [],
47
+ resolvedAfterWrappers = [],
48
+ requirePath,
49
+ } = hostedHandler;
50
+ const wrappersArg = formatWrappersArg({
51
+ resolvedBeforeWrappers,
52
+ resolvedAfterWrappers,
53
+ });
54
+
55
+ exportLines.push(
56
+ ` ${ hostedName }: wrapHostedFunction(() => require('${ requirePath }'), '${ handlerName }'${ wrappersArg }),`,
57
+ );
58
+ }
59
+
60
+ return `// Generated by mineral — do not edit
61
+ const { wrapHostedFunction } = require('@foxtware/mineral/hosting/hosting.utils');
62
+
63
+ module.exports = {
64
+ ${ exportLines.join('\n') }
65
+ };
66
+ `;
67
+ };
68
+
69
+ const writeHostedJs = ({
70
+ workspace,
71
+ hostedHandlers,
72
+ }) => {
73
+ const { getHostingDir } = require('./hosting.utils');
74
+ const hostedPath = `${ getHostingDir(workspace) }/hosted.js`;
75
+ const content = generateHostedJs({
76
+ hostedHandlers,
77
+ });
78
+
79
+ fs.mkdirSync(getHostingDir(workspace), { recursive: true });
80
+ fs.writeFileSync(hostedPath, content);
81
+ return hostedPath;
82
+ };
83
+
84
+ module.exports = {
85
+ generateHostedJs,
86
+ writeHostedJs,
87
+ };
@@ -1,4 +1,4 @@
1
- const MINERAL_ROOT = __dirname;
1
+ const MINERAL_ROOT = `${ __dirname }/..`;
2
2
  const MINERAL_API_DIR = `${ MINERAL_ROOT }/api`;
3
3
 
4
4
  const getRequirePathForHandler = (handler, workspace) => {
@@ -1,4 +1,6 @@
1
1
  const fs = require('fs');
2
+ const path = require('path');
3
+ const dotenv = require('dotenv');
2
4
  const { createRequire } = require('module');
3
5
  const yaml = require('yaml');
4
6
  const { getRequirePathForHandler } = require('./handlerPaths');
@@ -10,10 +12,16 @@ const {
10
12
  funcApi,
11
13
  wrapFunction,
12
14
  statusCodeFromResult,
13
- } = require('./server.utils');
15
+ } = require('../server.utils');
14
16
 
15
- const MINERAL_WRAPPERS_MODULE = '@foxtware/mineral/wrappers.js';
16
- const WORKSPACE_WRAPPERS_MODULE = './wrappers.js';
17
+ dotenv.config({
18
+ path: path.join(process.cwd(), '.env'),
19
+ });
20
+
21
+ const MINERAL_WRAPPERS_MODULE = '@foxtware/mineral/hosting/wrappers.js';
22
+ const WORKSPACE_WRAPPERS_MODULE = './hosting/wrappers.js';
23
+
24
+ const getHostingDir = (workspace) => `${ workspace.replace(/\/$/, '') }/hosting`;
17
25
 
18
26
  const getMineralWrappers = (workspaceRequire) => {
19
27
  try {
@@ -63,13 +71,16 @@ const getHostedEntries = (functions = {}) => (
63
71
  Object.entries(functions).map(([hostedName, functionConfig = {}]) => ({
64
72
  hostedName,
65
73
  handlerName: functionConfig.entry_point || functionConfig.entryPoint || hostedName,
66
- wrappers: Array.isArray(functionConfig.wrappers) ? functionConfig.wrappers : [],
74
+ beforeWrappers: Array.isArray(functionConfig.before_wrappers) ? functionConfig.before_wrappers : [],
75
+ afterWrappers: Array.isArray(functionConfig.after_wrappers) ? functionConfig.after_wrappers : [],
67
76
  }))
68
77
  );
69
78
 
70
- const functionUsesWrapper = (functionConfig = {}, wrapperName) => (
71
- Array.isArray(functionConfig.wrappers) && functionConfig.wrappers.includes(wrapperName)
72
- );
79
+ const functionUsesWrapper = (functionConfig = {}, wrapperName) => {
80
+ const { before_wrappers = [], after_wrappers = [] } = functionConfig;
81
+
82
+ return before_wrappers.includes(wrapperName) || after_wrappers.includes(wrapperName);
83
+ };
73
84
 
74
85
  const getFuncApiConfig = ({
75
86
  moduleExports,
@@ -92,7 +103,10 @@ const getFuncApiConfig = ({
92
103
  }
93
104
  };
94
105
 
95
- const wrapHostedFunction = (loader, exportName, wrappers = []) => {
106
+ const wrapHostedFunction = (loader, exportName, {
107
+ beforeWrappers = [],
108
+ afterWrappers = [],
109
+ } = {}) => {
96
110
  let handler = null;
97
111
  let usesFuncApi = false;
98
112
 
@@ -121,7 +135,10 @@ const wrapHostedFunction = (loader, exportName, wrappers = []) => {
121
135
  : await handler(...args);
122
136
  };
123
137
 
124
- const wrappedHandler = wrapFunction(coreHandler, wrappers);
138
+ const wrappedHandler = wrapFunction(coreHandler, {
139
+ beforeWrappers,
140
+ afterWrappers,
141
+ });
125
142
 
126
143
  return async (req, res) => {
127
144
  try {
@@ -156,60 +173,31 @@ const wrapHostedFunction = (loader, exportName, wrappers = []) => {
156
173
  };
157
174
 
158
175
  const readHostingYml = (workspace) => {
159
- const hostingPath = `${ workspace }/.hosting.yml`;
176
+ const hostingPath = `${ getHostingDir(workspace) }/.hosting.yml`;
160
177
 
161
178
  if (!fs.existsSync(hostingPath)) {
162
- throw new Error(`Missing .hosting.yml in workspace: ${ workspace }`);
179
+ throw new Error(`Missing hosting/.hosting.yml in workspace: ${ workspace }`);
163
180
  }
164
181
 
165
182
  const hostingText = fs.readFileSync(hostingPath, 'utf8');
166
183
  const hostingConfig = yaml.parse(hostingText);
167
184
 
168
185
  if (!hostingConfig || typeof hostingConfig !== 'object' || Array.isArray(hostingConfig)) {
169
- throw new Error('Invalid .hosting.yml');
186
+ throw new Error('Invalid hosting/.hosting.yml');
170
187
  }
171
188
 
172
189
  return hostingConfig;
173
190
  };
174
191
 
175
- const getCredsJsonForDeploy = (workspace) => {
176
- const credsPath = `${ workspace }/.creds.yml`;
177
-
178
- if (!fs.existsSync(credsPath)) {
179
- throw new Error(`Missing .creds.yml in workspace: ${ workspace }`);
180
- }
181
-
182
- const credsText = fs.readFileSync(credsPath, 'utf8');
183
- return JSON.stringify(yaml.parse(credsText));
184
- };
192
+ const ensureWorkspaceEnvForDeploy = (workspace) => {
193
+ const { copyCredsToEnv } = require('./copyCredsToEnv');
194
+ const envPath = `${ workspace.replace(/\/$/, '') }/.env`;
185
195
 
186
- const getEnvValueForDeploy = (workspace, envName) => {
187
- const envPath = `${ workspace }/.env`;
196
+ copyCredsToEnv(workspace);
188
197
 
189
198
  if (!fs.existsSync(envPath)) {
190
- return '';
199
+ throw new Error(`Missing .env in workspace: ${ workspace }`);
191
200
  }
192
-
193
- const envText = fs.readFileSync(envPath, 'utf8');
194
- const match = envText.match(new RegExp(`^${ envName }=(.*)$`, 'm'));
195
- return match ? match[1].trim() : '';
196
- };
197
-
198
- const getEnvVarsForDeploy = (workspace, envNames = []) => (
199
- Object.fromEntries(
200
- envNames.map((envName) => [envName, getEnvValueForDeploy(workspace, envName)]),
201
- )
202
- );
203
-
204
- const validateEnvVarsForDeploy = (workspace, envNames = []) => {
205
- const envVars = getEnvVarsForDeploy(workspace, envNames);
206
- const missing = envNames.filter((envName) => !envVars[envName]);
207
-
208
- if (missing.length) {
209
- throw new Error(`Missing required .env values: ${ missing.join(', ') }`);
210
- }
211
-
212
- return envVars;
213
201
  };
214
202
 
215
203
  const resolveHostedHandlersForDeploy = ({
@@ -221,9 +209,16 @@ const resolveHostedHandlersForDeploy = ({
221
209
  const hostedEntries = getHostedEntries(functions);
222
210
 
223
211
  return hostedEntries.map((hostedEntry) => {
224
- const { handlerName, wrappers = [] } = hostedEntry;
212
+ const {
213
+ handlerName,
214
+ beforeWrappers = [],
215
+ afterWrappers = [],
216
+ } = hostedEntry;
225
217
 
226
- const resolvedWrappers = wrappers.map((wrapperName) => (
218
+ const resolvedBeforeWrappers = beforeWrappers.map((wrapperName) => (
219
+ resolveWrapperName(wrapperName, workspaceRequire)
220
+ ));
221
+ const resolvedAfterWrappers = afterWrappers.map((wrapperName) => (
227
222
  resolveWrapperName(wrapperName, workspaceRequire)
228
223
  ));
229
224
 
@@ -236,7 +231,8 @@ const resolveHostedHandlersForDeploy = ({
236
231
 
237
232
  return {
238
233
  ...hostedEntry,
239
- resolvedWrappers,
234
+ resolvedBeforeWrappers,
235
+ resolvedAfterWrappers,
240
236
  requirePath: getRequirePathForHandler(handler, workspace),
241
237
  };
242
238
  });
@@ -245,13 +241,12 @@ const resolveHostedHandlersForDeploy = ({
245
241
  // TODO: support credsPayload in google_cloud_info instead of full workspace .creds.yml
246
242
 
247
243
  module.exports = {
244
+ getHostingDir,
248
245
  resolveWrapperName,
249
246
  getFuncApiConfig,
250
247
  wrapHostedFunction,
251
248
  readHostingYml,
252
- getCredsJsonForDeploy,
253
- getEnvVarsForDeploy,
254
- validateEnvVarsForDeploy,
249
+ ensureWorkspaceEnvForDeploy,
255
250
  getHostedEntries,
256
251
  resolveHostedHandlersForDeploy,
257
252
  functionUsesWrapper,
@@ -1,4 +1,4 @@
1
- const { HOSTED } = require('./api/constants');
1
+ const { HOSTED } = require('../api/constants');
2
2
 
3
3
  const requireHostedApiKey = async (req) => {
4
4
  if (!HOSTED) {
@@ -22,7 +22,7 @@ const allowCrossOriginCallsAndHandleOptions = async (req, res) => {
22
22
 
23
23
  res.setHeader('Access-Control-Allow-Origin', origin || '*');
24
24
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
25
- res.setHeader('Access-Control-Allow-Headers', 'Content-Type, x-api-key, x-wf-token, x-wf-value');
25
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, x-api-key, x-wf-token, x-wf-value');
26
26
 
27
27
  if (req.method === 'OPTIONS') {
28
28
  res.writeHead(204);