adobe / target-nodejs-sdk

Adobe Target Node.js SDK
https://www.npmjs.com/package/@adobe/target-nodejs-sdk
Apache License 2.0
26 stars 20 forks source link

problem using in akamai edgworkers #54

Open blueo opened 3 years ago

blueo commented 3 years ago

Expected Behaviour

I expect I can use the sdk in an akamai edgeworker

Actual Behaviour

Edgeworker static validation fails

Reproduce Scenario (including but not limited to)

Steps to Reproduce

import sdk version > 2.1.1 to an akamai edgworker js file Upload edgworker using cli (eg akamai ew upload --codeDir ./ [workerID] reported error:

{
  "type": "/edgeworkers/error-types/edgeworkers-invalid-argument",
  "title": "Invalid Argument.",
  "detail": "Tarball validation failed: static validation failed : main.js::12:24 Unknown built-in module: \"crypto\".",
  "instance": "/edgeworkers/error-instances/124d6da6-ebb0-4153-a145-ca67704ae8fc",
  "status": 400,
  "errorCode": "EW1108",
  "traceId": "f01b60cc2d1f1c55"
}

Platform and Version

akamai edgeworker

Sample Code that illustrates the problem

main.js :

import { httpRequest } from "http-request";
import { createResponse } from "create-response";
import { logger } from "log";
import { Cookies } from "cookies";
/** end provided modules */
import TargetClient from "@adobe/target-nodejs-sdk";

const clientCode = "xxxx";
const organizationId = "xxxx;
const rulesUrl = `https://assets.adobetarget.com/${clientCode}/production/v1/rules.json`;

function createTargetClient(rules) {
  return new Promise((resolve) => {
    const result = TargetClient.create({
      client: clientCode,
      organizationId: organizationId,
      decisioningMethod: "on-device",
      artifactPayload: rules,
      pollingInterval: 0, // "0" prevents polling, if artifactPayload is provided
      targetLocationHint: "<location hint>", // prevent cluster discovery
      logger: logger, // use Akamai EdgeWorker provided logger
      fetchApi: httpRequest,
      events: {
        clientReady: () => resolve(result),
      },
    });
  });
}

export async function responseProvider(request) {
  try {
    const deliveryRequest = {
      execute: {
        mboxes: [
          {
            address: { url: request.host + request.url },
            name: "a1-serverside-ab",
          },
        ],
      },
    };

    const rules = await httpRequest(rulesUrl).then((response) => response.json());
    const client = await createTargetClient(rules);
    const cookies = new Cookies(request.getHeader("Cookie"));
    const visitorCookie = cookies.get(TargetClient.getVisitorCookieName(organizationId));
    const targetCookie = cookies.get(TargetClient.TargetCookieName);
    const { response } = await client.getOffers({ request: deliveryRequest, visitorCookie, targetCookie });

    return createResponse(200, {}, JSON.stringify(response));
  } catch (e) {
    logger.log(e);
    return createResponse(400, {}, JSON.stringify(e));
  }
}

i'm working from this example: https://github.com/artur-ciocanu/odd-akamai-edge-workers/

if I pin my version to 2.1.1 then I can avoid the issue

Logs taken while reproducing problem

artur-ciocanu commented 3 years ago

@blueo thanks a lot of for reporting the issue. We will take a look and see what can be done. As workaround you could provide your own window.crypto implementation, until we figure out how to properly fix it for EdgeWorker environment.

blueo commented 3 years ago

Thanks @artur-ciocanu I'll give it a go - at the moment I've pegged back a few versions but ideally I could just provide it as you say.

daminisinha commented 2 years ago

Hi, for the above issue which I also facing please code provide the code snippet for workaround because I tried creating a polyfill for crypto , nothing works for me. Thanks

rollup.config.js

import nodeResolve from '@rollup/plugin-node-resolve'
import typescript from '@rollup/plugin-typescript'
import json from '@rollup/plugin-json'
import commonjs from '@rollup/plugin-commonjs'
import babel from 'rollup-plugin-babel'
import filesize from 'rollup-plugin-filesize'
import polyfill from 'rollup-plugin-polyfill'

function getPlugins(babelConfig) {
  return [
    json(),
    nodeResolve({
      browser: true
    }),
    commonjs(),
    polyfill(['./cryptoPolyfill.js']),
    babel(babelConfig),
    typescript(),
    filesize()
  ]
}

export default [
  {
    input: 'src/index.ts',
    external: [
      'http-request',
      'create-response',
      'log',
      'text-encode-transform',
      'streams',
      'cookies'
    ],
    output: {
      name: 'main',
      file: 'dist/main.js',
      format: 'esm',
      sourcemap: false
    },
    plugins: getPlugins({
      inputSourceMap: true,
      sourceMaps: true,
      runtimeHelpers: true,
      exclude: ['node_modules/**', /\/core-js\//],
      presets: [
        [
          '@babel/preset-env',
          {
            useBuiltIns: 'usage',
            corejs: 3,
            modules: false,
            targets: {
              browsers: [
                'last 2 Chrome versions',
                'last 2 Firefox versions',
                'last 2 Safari versions'
              ]
            }
          }
        ]
      ],
      plugins: ['@babel/plugin-transform-runtime']
    })
  }
]

crypto polyfill -

const cryptoPolyfill = require('polyfill-crypto.getrandomvalues')
if (window && window.crypto && !window.crypto.getRandomValues) {
  window.crypto.getRandomValues = cryptoPolyfill
}

if (crypto && !crypto.getRandomValues) {
  crypto.getRandomValues = cryptoPolyfill
}
daminisinha commented 2 years ago

Hi, for the above issue which I also facing please code provide the code snippet for workaround because I tried creating a polyfill for crypto , nothing works for me. Thanks

rollup.config.js

import nodeResolve from '@rollup/plugin-node-resolve'
import typescript from '@rollup/plugin-typescript'
import json from '@rollup/plugin-json'
import commonjs from '@rollup/plugin-commonjs'
import babel from 'rollup-plugin-babel'
import filesize from 'rollup-plugin-filesize'
import polyfill from 'rollup-plugin-polyfill'

function getPlugins(babelConfig) {
  return [
    json(),
    nodeResolve({
      browser: true
    }),
    commonjs(),
    polyfill(['./cryptoPolyfill.js']),
    babel(babelConfig),
    typescript(),
    filesize()
  ]
}

export default [
  {
    input: 'src/index.ts',
    external: [
      'http-request',
      'create-response',
      'log',
      'text-encode-transform',
      'streams',
      'cookies'
    ],
    output: {
      name: 'main',
      file: 'dist/main.js',
      format: 'esm',
      sourcemap: false
    },
    plugins: getPlugins({
      inputSourceMap: true,
      sourceMaps: true,
      runtimeHelpers: true,
      exclude: ['node_modules/**', /\/core-js\//],
      presets: [
        [
          '@babel/preset-env',
          {
            useBuiltIns: 'usage',
            corejs: 3,
            modules: false,
            targets: {
              browsers: [
                'last 2 Chrome versions',
                'last 2 Firefox versions',
                'last 2 Safari versions'
              ]
            }
          }
        ]
      ],
      plugins: ['@babel/plugin-transform-runtime']
    })
  }
]

crypto polyfill -

const cryptoPolyfill = require('polyfill-crypto.getrandomvalues')
if (window && window.crypto && !window.crypto.getRandomValues) {
  window.crypto.getRandomValues = cryptoPolyfill
}

if (crypto && !crypto.getRandomValues) {
  crypto.getRandomValues = cryptoPolyfill
}

@blueo please code you help me out maybe? Thanks

blueo commented 2 years ago

@daminisinha that looks like it could be a good way around the problem - this is a while ago so I can't quite remember but I had a similar problem trying to pollyfill. I think the main issue was trying to pollyfill the 'import 'crypto' statement in /packages/target-tools/src/uuid/rng.js but this might have been my lack of rollup experience. I ended up manually editing the compiled/minified JS to 'patch' it so I could get a proof of concept going but ultimately just used an older version.

However I ran into another road block shortly after - it turns out there are some performance limits in edgworkers - particularly the JavaScript initialization timeout. No matter what I did with the code example above just having this library in the bundle meant that I hit the initialisation limit on a cold start. This pretty much made it unworkable for us so we ended up using the Akamai Audience Segmentation product instead. Not perfect but got us there in the end - sorry this isn't more helpful 🤷

daminisinha commented 2 years ago

@daminisinha that looks like it could be a good way around the problem - this is a while ago so I can't quite remember but I had a similar problem trying to pollyfill. I think the main issue was trying to pollyfill the 'import 'crypto' statement in /packages/target-tools/src/uuid/rng.js but this might have been my lack of rollup experience. I ended up manually editing the compiled/minified JS to 'patch' it so I could get a proof of concept going but ultimately just used an older version.

However I ran into another road block shortly after - it turns out there are some performance limits in edgworkers - particularly the JavaScript initialization timeout. No matter what I did with the code example above just having this library in the bundle meant that I hit the initialisation limit on a cold start. This pretty much made it unworkable for us so we ended up using the Akamai Audience Segmentation product instead. Not perfect but got us there in the end - sorry this isn't more helpful 🤷

Thanks @blueo for your response :) .

daminisinha commented 2 years ago

Somehow crypto error has gone and I started getting new error while using a package "@adobe/target-nodejs-sdk": "^2.3.0"

Seems like when we do yarn build this package throws an error.

[!] Error: 'default' is not exported by node_modules/@adobe/target-nodejs-sdk/dist/targetclient.browser.js, imported by src/index.ts https://rollupjs.org/guide/en/#error-name-is-not-exported-by-module src/index.ts (8:7)

import TargetClient from '@adobe/target-nodejs-sdk';

Does anybody know the fix about the same? Thanks