Skip to content
This repository was archived by the owner on Feb 25, 2022. It is now read-only.

Commit 63a4707

Browse files
authored
feat: migrate to helix-deploy (#240)
fixes #238
1 parent 70e4ba5 commit 63a4707

18 files changed

+2480
-2935
lines changed

package-lock.json

Lines changed: 1901 additions & 2397 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@adobe/helix-data-embed",
3-
"version": "2.2.1",
3+
"version": "2.2.1-hedy",
44
"private": true,
55
"description": "Helix Data Embed",
66
"main": "src/index.js",
@@ -11,14 +11,15 @@
1111
"lint": "./node_modules/.bin/eslint .",
1212
"semantic-release": "semantic-release",
1313
"commit": "git-cz",
14-
"build": "wsk-builder -v",
15-
"deploy": "wsk-builder -v --deploy --test=/_status_check/healthcheck.json",
16-
"deploy-sequences": "wsk-builder --no-build -no-hints -l latest -l major -l minor",
17-
"deploy-ci": "wsk-builder -v --deploy --test=/_status_check/healthcheck.json --pkgVersion=ci$CIRCLE_BUILD_NUM -l ci"
14+
"build": "hedy -v",
15+
"deploy": "hedy -v --deploy --test=/_status_check/healthcheck.json",
16+
"deploy-sequences": "hedy --no-build -no-hints -l latest -l major -l minor",
17+
"deploy-ci": "hedy -v --deploy --test=/_status_check/healthcheck.json --pkgVersion=ci$CIRCLE_BUILD_NUM -l ci"
1818
},
1919
"wsk": {
2020
"namespace": "helix",
21-
"name": "helix-services/data-embed@${version}"
21+
"name": "helix-services/data-embed@${version}",
22+
"memory": 512
2223
},
2324
"repository": {
2425
"type": "git",
@@ -31,22 +32,23 @@
3132
},
3233
"homepage": "https://github.com/adobe/helix-data-embed#readme",
3334
"dependencies": {
34-
"@adobe/helix-fetch": "1.9.2",
3535
"@adobe/helix-epsagon": "1.5.5",
36+
"@adobe/helix-fetch": "1.9.2",
3637
"@adobe/helix-onedrive-support": "3.1.6",
3738
"@adobe/helix-shared": "7.18.0",
3839
"@adobe/helix-status": "9.0.0",
3940
"@adobe/openwhisk-action-logger": "2.3.1",
4041
"@adobe/openwhisk-action-utils": "4.4.0",
4142
"@flighter/a1-notation": "1.0.6",
4243
"googleapis": "66.0.0",
44+
"node-fetch": "2.6.1",
4345
"rss-parser": "3.10.0"
4446
},
4547
"devDependencies": {
4648
"@adobe/eslint-config-helix": "1.1.3",
49+
"@adobe/helix-deploy": "1.14.0",
4750
"@adobe/helix-ops": "1.12.3",
4851
"@adobe/helix-testutils": "0.4.2",
49-
"@adobe/openwhisk-action-builder": "2.15.1",
5052
"@semantic-release/changelog": "5.0.1",
5153
"@semantic-release/exec": "5.0.0",
5254
"@semantic-release/git": "9.0.0",

src/data-source.js

Lines changed: 15 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,58 +9,42 @@
99
* OF ANY KIND, either express or implied. See the License for the specific language
1010
* governing permissions and limitations under the License.
1111
*/
12-
const querystring = require('querystring');
1312

1413
/**
1514
* Analyses the params and extracts the data source, which is specified by a `src` param.
1615
* For backward compatibility, the source can also be added as path, either escaped or unescaped.
1716
*
18-
* @param {string} params the openwhisk action params
19-
* @return {URL} the extracted data source or null
17+
* @param {Request} req The request
18+
* @return {HEDYContext} the universal deploy context
2019
*/
21-
function dataSource(params) {
22-
const { __ow_path: path = '', src = '' } = params;
20+
function dataSource(req, context) {
21+
const { pathInfo: { suffix } = {} } = context;
22+
const { searchParams } = new URL(req.url);
23+
const src = searchParams.get('src') || '';
2324
let url = null;
24-
if (!path) {
25+
if (!suffix) {
2526
try {
2627
url = new URL(src);
2728
} catch (e) {
2829
return null;
2930
}
3031

31-
// expect the _ow_path to start with /https:/ or /https%3a%2f
32+
// expect the suffix to start with /https:/ or /https%3a%2f
3233
// the escaping done by runtime is inconsistent, the : may be decoded
33-
} else if (path.match(/^\/https(:|%3A)%2F/)) {
34-
url = new URL(decodeURIComponent(path.substring(1)
34+
} else if (suffix.match(/^\/https(:|%3A)%2F/)) {
35+
url = new URL(decodeURIComponent(suffix.substring(1)
3536
.replace(/^https(:|%3A)%2F([^%])/, 'https://$2')));
36-
} else if (!path.startsWith('/https:/')) {
37+
} else if (!suffix.startsWith('/https:/')) {
3738
return null;
3839
} else {
39-
url = new URL(path.substring(1)
40+
url = new URL(suffix.substring(1)
4041
// workaround: Adobe I/O Runtime messes up consecutive spaces in URLs
4142
.replace(/^https:\/\/?([^/])/, 'https://$1'));
4243
}
4344

44-
if (!params.__ow_query) {
45-
// reconstruct __ow_query
46-
const q = {};
47-
Object.keys(params)
48-
.filter((key) => !/^[A-Z]+_[A-Z]+/.test(key))
49-
.filter((key) => key !== 'api')
50-
.filter((key) => key !== 'src')
51-
.filter((key) => !/^__ow_/.test(key))
52-
.forEach((key) => {
53-
q[key] = params[key];
54-
// don't append querybuilder keys to source or if a src param was given
55-
if (!key.startsWith('hlx_') && !params.src) {
56-
url.searchParams.append(key, params[key]);
57-
}
58-
});
59-
// eslint-disable-next-line no-param-reassign
60-
params.__ow_query = querystring.stringify(q);
61-
} else {
62-
// else add it to the url
63-
Object.entries(querystring.parse(params.__ow_query))
45+
if (!src) {
46+
// add query params to data source url
47+
Array.from(searchParams.entries())
6448
.filter(([key]) => (!key.startsWith('hlx_')))
6549
.forEach(([key, value]) => {
6650
url.searchParams.append(key, value);

src/embed.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,14 @@ function hasParams(list, params) {
2727
/**
2828
* Returns the data representation of the resource addressed by url.
2929
* @param {URL} url The url of the resource
30-
* @param {object} params The action params
30+
* @param {Object} params additional params
31+
* @param {object} env The action environment
3132
* @param {Logger} log logger
3233
* @returns {object} an action response with the body containing the data.
3334
*/
34-
function embed(url, params, log) {
35+
function embed(url, params, env, log) {
3536
const candidates = matchers
36-
.filter((candidate) => hasParams(candidate.required, params));
37+
.filter((candidate) => hasParams(candidate.required, env));
3738

3839
const matching = candidates.find((candidate) => candidate.accept(url));
3940

@@ -50,7 +51,7 @@ function embed(url, params, log) {
5051
}
5152
log.info(`found handler for ${url}: ${matching.name}`);
5253

53-
return matching.extract(url, params, log);
54+
return matching.extract(url, params, env, log);
5455
}
5556

5657
module.exports = embed;

src/index.js

Lines changed: 56 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -9,62 +9,81 @@
99
* OF ANY KIND, either express or implied. See the License for the specific language
1010
* governing permissions and limitations under the License.
1111
*/
12+
const { Response } = require('node-fetch');
1213
const { wrap } = require('@adobe/openwhisk-action-utils');
1314
const { logger } = require('@adobe/openwhisk-action-logger');
14-
const { wrap: status } = require('@adobe/helix-status');
15-
const { epsagon } = require('@adobe/helix-epsagon');
15+
const { wrap: helixStatus } = require('@adobe/helix-status');
1616
const embed = require('./embed');
1717
const { loadquerystring } = require('./querybuilder/url');
1818
const { createfilter } = require('./querybuilder/filter');
1919
const dataSource = require('./data-source.js');
2020

2121
const MAX_DATA_SIZE = 750000;
2222

23-
async function main(params) {
23+
async function main(req, context) {
2424
/* istanbul ignore next */
25-
const { __ow_logger: log = console } = params;
26-
const url = dataSource((params));
25+
const { log = console } = context;
26+
const url = dataSource(req, context);
2727
if (!url) {
28-
return {
29-
statusCode: 400,
30-
body: 'Expecting a datasource',
31-
};
28+
return new Response('Expecting a datasource', {
29+
status: 400,
30+
});
3231
}
33-
log.info(`data-embed for datasource ${url}`);
34-
const qbquery = loadquerystring(params.__ow_query, 'hlx_');
35-
log.debug('QB query', qbquery);
36-
const filter = createfilter(qbquery);
37-
log.debug('QB filter', filter);
38-
const result = await embed(url, params, log);
32+
try {
33+
const { searchParams } = new URL(req.url);
3934

40-
const { body } = result;
41-
delete result.body;
42-
log.debug('result', result);
43-
log.debug(`result body size: ${JSON.stringify(body).length}`);
44-
const filtered = filter(body);
45-
let size = JSON.stringify(filtered).length;
46-
log.info(`filtered result ${filtered.length} rows. size: ${size}`);
47-
if (size > MAX_DATA_SIZE) {
48-
// todo: could be optimized to be more accurate using some binary search approach
49-
const avgRowSize = size / filtered.length;
50-
const retain = Math.floor(MAX_DATA_SIZE / avgRowSize);
51-
filtered.splice(retain, filtered.length - retain);
52-
size = JSON.stringify(filtered).length;
53-
log.info(`result truncated to ${filtered.length} rows. size: ${size}`);
54-
}
55-
return {
56-
...result,
57-
body: {
35+
log.info(`data-embed for datasource ${url}`);
36+
const qbquery = loadquerystring(searchParams, 'hlx_');
37+
log.debug('QB query', qbquery);
38+
const filter = createfilter(qbquery);
39+
log.debug('QB filter', filter);
40+
const params = Array.from(searchParams.entries()).reduce((p, [key, value]) => {
41+
// eslint-disable-next-line no-param-reassign
42+
p[key] = value;
43+
return p;
44+
}, {});
45+
const result = await embed(url, params, context.env, log);
46+
47+
const {
48+
body,
49+
statusCode: status,
50+
headers,
51+
} = result;
52+
log.debug(`result body size: ${JSON.stringify(body).length}`);
53+
const filtered = filter(body);
54+
let size = JSON.stringify(filtered).length;
55+
log.info(`filtered result ${filtered.length} rows. size: ${size}`);
56+
if (size > MAX_DATA_SIZE) {
57+
// todo: could be optimized to be more accurate using some binary search approach
58+
const avgRowSize = size / filtered.length;
59+
const retain = Math.floor(MAX_DATA_SIZE / avgRowSize);
60+
filtered.splice(retain, filtered.length - retain);
61+
size = JSON.stringify(filtered).length;
62+
log.info(`result truncated to ${filtered.length} rows. size: ${size}`);
63+
}
64+
const bodyText = JSON.stringify({
5865
total: body.length,
5966
offset: filter.offset || 0,
6067
limit: filtered.length,
6168
data: filtered,
62-
},
63-
};
69+
});
70+
return new Response(bodyText, {
71+
status,
72+
headers,
73+
});
74+
} catch (e) {
75+
log.error('error fetching data', e);
76+
return new Response('error fetching data', {
77+
status: 500,
78+
headers: {
79+
'content-type': 'application/json',
80+
'cache-control': 'no-store, private, must-revalidate',
81+
},
82+
});
83+
}
6484
}
6585

6686
module.exports.main = wrap(main)
67-
.with(epsagon)
68-
.with(status)
87+
.with(helixStatus)
6988
.with(logger.trace)
7089
.with(logger);

src/matchers/excel.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,16 @@
1111
*/
1212
const { OneDrive } = require('@adobe/helix-onedrive-support');
1313

14-
async function extract(url, params, log = console) {
14+
async function extract(url, params, env, log = console) {
1515
const {
16-
AZURE_WORD2MD_CLIENT_ID: clientId,
17-
AZURE_HELIX_USER: username,
18-
AZURE_HELIX_PASSWORD: password,
1916
sheet,
2017
table,
2118
} = params;
19+
const {
20+
AZURE_WORD2MD_CLIENT_ID: clientId,
21+
AZURE_HELIX_USER: username,
22+
AZURE_HELIX_PASSWORD: password,
23+
} = env;
2224

2325
try {
2426
const drive = new OneDrive({

src/matchers/google.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,15 @@ function createOAuthClient(options, creds) {
3636
return oAuth2Client;
3737
}
3838

39-
async function extract(url, params, log = console) {
39+
async function extract(url, params, env, log = console) {
40+
const {
41+
sheet,
42+
} = params;
4043
const {
4144
GOOGLE_DOCS2MD_CLIENT_ID: clientId,
4245
GOOGLE_DOCS2MD_CLIENT_SECRET: clientSecret,
4346
GOOGLE_DOCS2MD_REFRESH_TOKEN: refresh_token,
44-
sheet,
45-
} = params;
47+
} = env;
4648

4749
try {
4850
const spreadsheetId = getId(url);

src/matchers/run-query.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const { fetch } = require('@adobe/helix-fetch').context({
2121
});
2222
const { utils } = require('@adobe/helix-shared');
2323

24-
async function extract(url, params, log = console) {
24+
async function extract(url, params, env, log = console) {
2525
const host = 'https://adobeioruntime.net';
2626
const path = '/api/v1/web/helix/helix-services/run-query@v2/';
2727
const query = url.toString().split('/').pop();

src/querybuilder/url.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,11 @@ function nest(obj) {
177177
return transformconjunctions(root);
178178
}
179179

180-
function cast(obj) {
181-
return Object.entries(obj).reduce((o, [k, v]) => {
180+
function cast(searchParams) {
181+
const entries = searchParams instanceof URLSearchParams
182+
? Array.from(searchParams.entries())
183+
: Object.entries(searchParams);
184+
return entries.reduce((o, [k, v]) => {
182185
if (v === 'true' || v === 'false') {
183186
o[k] = (v === 'true');
184187
} else if (!Number.isNaN(Number.parseFloat(v))) {
@@ -190,8 +193,10 @@ function cast(obj) {
190193
}, {});
191194
}
192195

193-
function loadquerystring(str, prefix = '') {
194-
const obj = cast(parse(str));
196+
function loadquerystring(searchParams, prefix = '') {
197+
const obj = searchParams instanceof URLSearchParams
198+
? cast(searchParams)
199+
: cast(parse(searchParams));
195200

196201
return nest(Object.entries(obj).reduce((o, [k, v]) => {
197202
if (k.startsWith(prefix)) {

0 commit comments

Comments
 (0)