From 9adcf69ca886bf1f1fe0511a5ba645cd445e1f09 Mon Sep 17 00:00:00 2001 From: MichaelGoberling Date: Tue, 23 Apr 2024 13:37:57 +0000 Subject: [PATCH] =?UTF-8?q?Deploying=20to=20gh-pages=20from=20@=20AdobeDoc?= =?UTF-8?q?s/app-builder@3c8418194bb118e2e2c2ba14b4afa38ec50d8b96=20?= =?UTF-8?q?=F0=9F=9A=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 404.html | 2 +- 404/index.html | 2 +- chunk-map.json | 2 +- ...troubleshooting-md-3259bccd023c4b55277f.js | 2 + ...bleshooting-md-3259bccd023c4b55277f.js.map | 2 +- ...troubleshooting-md-380a1fff950a126349b5.js | 2 - ...iguration-index-md-59201e843287f51ead6a.js | 4 +- ...ation-index-md-59201e843287f51ead6a.js.map | 1 + ...ation-index-md-7bc95ef25b3ec2459e8f.js.map | 1 - ...des-tips-tricks-md-48f3f92f76d63450e5e6.js | 2 - ...tips-tricks-md-48f3f92f76d63450e5e6.js.map | 1 - ...des-tips-tricks-md-76b2d98659179f02cb96.js | 2 + ...tips-tricks-md-76b2d98659179f02cb96.js.map | 1 + ...hboard-lesson-2-md-eefecb058a6ab28704fb.js | 2 + ...rd-lesson-2-md-eefecb058a6ab28704fb.js.map | 1 + ...hboard-lesson-2-md-f7bc173b5f67f81a1b33.js | 2 - ...rd-lesson-2-md-f7bc173b5f67f81a1b33.js.map | 1 - ...driven-lesson-3-md-85152016b2cedeb468df.js | 2 + ...en-lesson-3-md-85152016b2cedeb468df.js.map | 1 + ...driven-lesson-3-md-c82e875c5ffd8a8aaf7c.js | 2 - ...en-lesson-3-md-c82e875c5ffd8a8aaf7c.js.map | 1 - ...driven-lesson-4-md-79ac71d0982a0dc526e3.js | 2 - ...en-lesson-4-md-79ac71d0982a0dc526e3.js.map | 1 - ...driven-lesson-4-md-7e789bf584551cda4578.js | 2 + ...en-lesson-4-md-7e789bf584551cda4578.js.map | 1 + ...-snippets-index-md-0bd5d2cbaed0f9e5560b.js | 2 + ...ppets-index-md-0bd5d2cbaed0f9e5560b.js.map | 1 + ...-snippets-index-md-15d357addb93f54e944f.js | 2 - ...ppets-index-md-15d357addb93f54e944f.js.map | 1 - .../common_troubleshooting/index.html | 14 +-- getting_started/first_app/index.html | 104 +++++++++--------- getting_started/index.html | 14 +-- getting_started/publish_app/index.html | 10 +- guides/app-hooks/index.html | 28 ++--- .../azure_log_analytics/index.html | 14 +-- guides/application_logging/index.html | 14 +-- .../application_logging/new_relic/index.html | 14 +-- .../splunk_cloud/index.html | 18 +-- .../splunk_enterprise/index.html | 18 +-- guides/application_state/index.html | 14 +-- guides/configuration/index.html | 31 +++++- .../webpack-configuration/index.html | 2 +- guides/contribution_guides/index.html | 2 +- guides/credential-rotation/index.html | 16 +-- .../ci_cd_for_firefly_apps/index.html | 2 +- guides/deployment/index.html | 2 +- guides/events/custom-events/index.html | 2 +- guides/events/webhooks/index.html | 2 +- guides/exc_app/index.html | 2 +- guides/exc_app/interfaces/index.html | 8 +- .../interfaces/index.runtime/index.html | 8 +- .../interfaces/page.objectwithhref/index.html | 10 +- .../interfaces/page.objectwithpath/index.html | 10 +- .../interfaces/page.pageapi/index.html | 46 ++++---- .../page.pageapiproperties/index.html | 30 ++--- .../interfaces/topbar.callback/index.html | 8 +- .../topbar.customfeedbackconfig/index.html | 8 +- .../topbar.customsearchconfig/index.html | 8 +- .../topbar.externalfeedbackconfig/index.html | 8 +- .../index.html | 8 +- .../interfaces/topbar.solution/index.html | 10 +- .../interfaces/topbar.topbarapi/index.html | 22 ++-- .../topbar.topbarapiproperties/index.html | 20 ++-- .../interfaces/user.userapi/index.html | 10 +- .../interfaces/user.userinfo/index.html | 8 +- guides/exc_app/modules/index.html | 18 +-- guides/exc_app/modules/page/index.html | 16 +-- guides/exc_app/modules/topbar/index.html | 16 +-- guides/exc_app/modules/user/index.html | 20 ++-- .../extension_migration_guide/index.html | 2 +- guides/extensions/index.html | 2 +- guides/extensions/ui_extensibility/index.html | 2 +- guides/index.html | 10 +- .../introduction_to_react_spectrum/index.html | 8 +- .../index.html | 2 +- guides/packaging/index.html | 10 +- guides/reference_documentation/index.html | 2 +- guides/security/index.html | 2 +- .../understanding_authentication/index.html | 2 +- guides/telemetry/index.html | 14 +-- guides/tips_tricks/index.html | 18 +-- guides/using_sdks/index.html | 16 +-- overview/community/index.html | 8 +- overview/faq/index.html | 8 +- overview/firefly_and_runtime/index.html | 8 +- overview/getting_access/index.html | 10 +- overview/how_it_works/index.html | 8 +- overview/index.html | 10 +- page-data/app-data.json | 2 +- page-data/sq/d/1814815295.json | 2 +- .../asset-compute-worker-ps-api/index.html | 2 +- .../lesson1/index.html | 2 +- .../lesson2/index.html | 2 +- .../lesson3/index.html | 2 +- .../lesson4/index.html | 2 +- .../requirements/index.html | 2 +- .../welldone/index.html | 2 +- resources/barcode-reader/barcode/index.html | 28 ++--- resources/barcode-reader/bootstrap/index.html | 26 ++--- resources/barcode-reader/index.html | 10 +- .../barcode-reader/requirements/index.html | 8 +- resources/barcode-reader/test/index.html | 44 ++++---- resources/barcode-reader/welldone/index.html | 10 +- resources/blog_articles/index.html | 8 +- resources/ci-cd/index.html | 8 +- resources/ci-cd/lesson1/index.html | 30 ++--- resources/ci-cd/lesson2/index.html | 10 +- resources/ci-cd/lesson3/index.html | 18 +-- resources/ci-cd/requirements/index.html | 8 +- resources/ci-cd/welldone/index.html | 8 +- resources/cron-jobs/index.html | 8 +- resources/cron-jobs/lesson1/index.html | 18 +-- resources/cron-jobs/lesson2/index.html | 12 +- resources/cron-jobs/lesson3/index.html | 12 +- resources/cron-jobs/requirements/index.html | 8 +- resources/cron-jobs/welldone/index.html | 8 +- .../aem-cloud-assets/index.html | 10 +- .../custom-asset-compute-worker/index.html | 10 +- .../lesson1/index.html | 10 +- .../lesson2/index.html | 12 +- .../lesson3/index.html | 28 ++--- .../lesson4/index.html | 20 ++-- .../lesson5/index.html | 18 +-- .../our-worker/index.html | 10 +- .../requirements/index.html | 8 +- .../welldone/index.html | 8 +- resources/customer-dashboard/index.html | 8 +- .../customer-dashboard/lesson1/index.html | 16 +-- .../customer-dashboard/lesson2/index.html | 18 +-- .../customer-dashboard/lesson3/index.html | 14 +-- .../customer-dashboard/lesson4/index.html | 16 +-- .../customer-dashboard/lesson5/index.html | 32 +++--- .../requirements/index.html | 8 +- .../customer-dashboard/welldone/index.html | 8 +- resources/debugging/index.html | 10 +- resources/debugging/lesson1/index.html | 10 +- resources/debugging/lesson2/index.html | 14 +-- resources/debugging/lesson3/index.html | 12 +- resources/debugging/requirements/index.html | 8 +- resources/debugging/welldone/index.html | 8 +- resources/event-driven/index.html | 10 +- resources/event-driven/lesson1/index.html | 14 +-- resources/event-driven/lesson2/index.html | 22 ++-- resources/event-driven/lesson3/index.html | 26 ++--- resources/event-driven/lesson4/index.html | 20 ++-- .../event-driven/requirements/index.html | 12 +- resources/event-driven/welldone/index.html | 10 +- resources/events-runtime/index.html | 10 +- resources/events-runtime/lesson1/index.html | 22 ++-- resources/events-runtime/lesson2/index.html | 10 +- .../events-runtime/requirements/index.html | 8 +- resources/events-runtime/welldone/index.html | 8 +- resources/index.html | 8 +- resources/journaling-events/index.html | 10 +- .../journaling-events/lesson1/index.html | 16 +-- .../journaling-events/lesson2/index.html | 18 +-- .../journaling-events/lesson3/index.html | 8 +- .../journaling-events/requirements/index.html | 8 +- .../journaling-events/welldone/index.html | 8 +- .../code_snippets/analytics/index.html | 12 +- .../code_snippets/events/index.html | 12 +- .../code_snippets/files/index.html | 24 ++-- .../sample_apps/code_snippets/index.html | 14 +-- .../code_snippets/state/index.html | 16 +-- resources/sample_apps/demo/index.html | 8 +- resources/sample_apps/index.html | 8 +- resources/spectrum-intro/index.html | 8 +- resources/spectrum-intro/lesson1/index.html | 10 +- resources/spectrum-intro/lesson2/index.html | 28 ++--- resources/spectrum-intro/lesson3/index.html | 18 +-- resources/spectrum-intro/lesson4/index.html | 16 +-- .../spectrum-intro/requirements/index.html | 8 +- resources/spectrum-intro/welldone/index.html | 8 +- resources/todo-app/index.html | 10 +- resources/todo-app/lesson1/index.html | 14 +-- resources/todo-app/lesson2/index.html | 30 ++--- resources/todo-app/lesson3/index.html | 30 ++--- resources/todo-app/lesson4/index.html | 22 ++-- resources/todo-app/lesson5/index.html | 48 ++++---- resources/todo-app/lesson6/index.html | 40 +++---- resources/todo-app/requirements/index.html | 8 +- resources/todo-app/welldone/index.html | 8 +- .../index.html | 8 +- .../developers-live/deep-dive/index.html | 8 +- .../extend-experience-cloud/index.html | 8 +- resources/videos/exploring/ci-cd/index.html | 8 +- .../videos/exploring/custom-events/index.html | 8 +- .../exploring/dashboard-case-study/index.html | 8 +- .../videos/exploring/debugging/index.html | 8 +- .../exploring/deep-dive-use-cases/index.html | 8 +- .../exploring/learning-resources/index.html | 8 +- .../exploring/live-wired-sneak/index.html | 8 +- .../exploring/ode-case-study/index.html | 8 +- .../projects-and-workspaces/index.html | 8 +- .../exploring/react-spectrum/index.html | 8 +- .../exploring/softcrylic-showcase/index.html | 8 +- resources/videos/index.html | 8 +- .../videos/overview/architecture/index.html | 8 +- .../overview/e2e-user-journey/index.html | 8 +- .../overview/getting-started/index.html | 8 +- .../videos/overview/introduction/index.html | 8 +- resources/videos/overview/security/index.html | 8 +- ...=> webpack-runtime-7418cb25a3078baad60e.js | 4 +- ...ebpack-runtime-7418cb25a3078baad60e.js.map | 2 +- webpack.stats.json | 2 +- 205 files changed, 1132 insertions(+), 1105 deletions(-) create mode 100644 component---src-pages-getting-started-common-troubleshooting-md-3259bccd023c4b55277f.js rename component---src-pages-getting-started-common-troubleshooting-md-380a1fff950a126349b5.js.map => component---src-pages-getting-started-common-troubleshooting-md-3259bccd023c4b55277f.js.map (53%) delete mode 100644 component---src-pages-getting-started-common-troubleshooting-md-380a1fff950a126349b5.js rename component---src-pages-guides-configuration-index-md-7bc95ef25b3ec2459e8f.js => component---src-pages-guides-configuration-index-md-59201e843287f51ead6a.js (80%) create mode 100644 component---src-pages-guides-configuration-index-md-59201e843287f51ead6a.js.map delete mode 100644 component---src-pages-guides-configuration-index-md-7bc95ef25b3ec2459e8f.js.map delete mode 100644 component---src-pages-guides-tips-tricks-md-48f3f92f76d63450e5e6.js delete mode 100644 component---src-pages-guides-tips-tricks-md-48f3f92f76d63450e5e6.js.map create mode 100644 component---src-pages-guides-tips-tricks-md-76b2d98659179f02cb96.js create mode 100644 component---src-pages-guides-tips-tricks-md-76b2d98659179f02cb96.js.map create mode 100644 component---src-pages-resources-customer-dashboard-lesson-2-md-eefecb058a6ab28704fb.js create mode 100644 component---src-pages-resources-customer-dashboard-lesson-2-md-eefecb058a6ab28704fb.js.map delete mode 100644 component---src-pages-resources-customer-dashboard-lesson-2-md-f7bc173b5f67f81a1b33.js delete mode 100644 component---src-pages-resources-customer-dashboard-lesson-2-md-f7bc173b5f67f81a1b33.js.map create mode 100644 component---src-pages-resources-event-driven-lesson-3-md-85152016b2cedeb468df.js create mode 100644 component---src-pages-resources-event-driven-lesson-3-md-85152016b2cedeb468df.js.map delete mode 100644 component---src-pages-resources-event-driven-lesson-3-md-c82e875c5ffd8a8aaf7c.js delete mode 100644 component---src-pages-resources-event-driven-lesson-3-md-c82e875c5ffd8a8aaf7c.js.map delete mode 100644 component---src-pages-resources-event-driven-lesson-4-md-79ac71d0982a0dc526e3.js delete mode 100644 component---src-pages-resources-event-driven-lesson-4-md-79ac71d0982a0dc526e3.js.map create mode 100644 component---src-pages-resources-event-driven-lesson-4-md-7e789bf584551cda4578.js create mode 100644 component---src-pages-resources-event-driven-lesson-4-md-7e789bf584551cda4578.js.map create mode 100644 component---src-pages-resources-sample-apps-code-snippets-index-md-0bd5d2cbaed0f9e5560b.js create mode 100644 component---src-pages-resources-sample-apps-code-snippets-index-md-0bd5d2cbaed0f9e5560b.js.map delete mode 100644 component---src-pages-resources-sample-apps-code-snippets-index-md-15d357addb93f54e944f.js delete mode 100644 component---src-pages-resources-sample-apps-code-snippets-index-md-15d357addb93f54e944f.js.map rename webpack-runtime-1450f7544d7fdaacde47.js => webpack-runtime-7418cb25a3078baad60e.js (97%) rename webpack-runtime-1450f7544d7fdaacde47.js.map => webpack-runtime-7418cb25a3078baad60e.js.map (98%) diff --git a/404.html b/404.html index b1eee184f..2d9206894 100644 --- a/404.html +++ b/404.html @@ -108,4 +108,4 @@ );height:var(--spectrum-global-dimension-size-600);left:0;right:0;margin-left:0;margin-right:0;background-color:var(--spectrum-global-color-gray-50);border-bottom:var(--spectrum-global-dimension-size-10) solid var(--spectrum-global-color-gray-200);}}
Overview Getting Started Guides Resources

Error 404: Page not found

Sorry, that page can't be found.

  • Privacy
  • Terms of Use
  • Do not sell or share my personal information
  • AdChoices
Copyright © 2024 Adobe. All rights reserved.
\ No newline at end of file + );right:0;width:var(--spectrum-global-dimension-size-300);background:-webkit-linear-gradient(0deg, rgba(255, 255, 255, 0), white);z-index:1;}}
Overview Getting Started Guides Resources

Error 404: Page not found

Sorry, that page can't be found.

  • Privacy
  • Terms of Use
  • Do not sell or share my personal information
  • AdChoices
Copyright © 2024 Adobe. All rights reserved.
\ No newline at end of file diff --git a/404/index.html b/404/index.html index 8e1637540..7aa017aa4 100644 --- a/404/index.html +++ b/404/index.html @@ -108,4 +108,4 @@ );height:var(--spectrum-global-dimension-size-600);left:0;right:0;margin-left:0;margin-right:0;background-color:var(--spectrum-global-color-gray-50);border-bottom:var(--spectrum-global-dimension-size-10) solid var(--spectrum-global-color-gray-200);}}
Overview Getting Started Guides Resources

Error 404: Page not found

Sorry, that page can't be found.

  • Privacy
  • Terms of Use
  • Do not sell or share my personal information
  • AdChoices
Copyright © 2024 Adobe. All rights reserved.
\ No newline at end of file + );right:0;width:var(--spectrum-global-dimension-size-300);background:-webkit-linear-gradient(0deg, rgba(255, 255, 255, 0), white);z-index:1;}}
Overview Getting Started Guides Resources

Error 404: Page not found

Sorry, that page can't be found.

  • Privacy
  • Terms of Use
  • Do not sell or share my personal information
  • AdChoices
Copyright © 2024 Adobe. All rights reserved.
\ No newline at end of file diff --git a/chunk-map.json b/chunk-map.json index f5260b486..8f52a8ab0 100644 --- a/chunk-map.json +++ b/chunk-map.json @@ -1 +1 @@ -{"polyfill":["/polyfill-d3d3335b6bf2529ad347.js"],"app":["/app-dd2d487797dd3aafcf94.js"],"component---node-modules-adobe-gatsby-theme-aio-src-pages-404-md":["/component---node-modules-adobe-gatsby-theme-aio-src-pages-404-md-43c272de2ceb90407f66.js"],"component---src-pages-getting-started-common-troubleshooting-md":["/component---src-pages-getting-started-common-troubleshooting-md-380a1fff950a126349b5.js"],"component---src-pages-getting-started-first-app-md":["/component---src-pages-getting-started-first-app-md-47778bd1129b46dd51cd.js"],"component---src-pages-getting-started-index-md":["/component---src-pages-getting-started-index-md-1a082caab455c998ea31.js"],"component---src-pages-getting-started-publish-app-md":["/component---src-pages-getting-started-publish-app-md-68dd2ce1c57a3ed3d576.js"],"component---src-pages-guides-app-hooks-md":["/component---src-pages-guides-app-hooks-md-9117c4a5ae1fbac6f25f.js"],"component---src-pages-guides-application-logging-azure-log-analytics-md":["/component---src-pages-guides-application-logging-azure-log-analytics-md-708198e6b61e8710905a.js"],"component---src-pages-guides-application-logging-index-md":["/component---src-pages-guides-application-logging-index-md-dbdd1a2756548e65aa11.js"],"component---src-pages-guides-application-logging-new-relic-md":["/component---src-pages-guides-application-logging-new-relic-md-a3847bd9db09e57c6c23.js"],"component---src-pages-guides-application-logging-splunk-cloud-md":["/component---src-pages-guides-application-logging-splunk-cloud-md-621ac05d566eaf94d904.js"],"component---src-pages-guides-application-logging-splunk-enterprise-md":["/component---src-pages-guides-application-logging-splunk-enterprise-md-ec4bc71797bb3b05b204.js"],"component---src-pages-guides-application-state-md":["/component---src-pages-guides-application-state-md-77cc253033ca5df908cb.js"],"component---src-pages-guides-configuration-index-md":["/component---src-pages-guides-configuration-index-md-7bc95ef25b3ec2459e8f.js"],"component---src-pages-guides-configuration-webpack-configuration-md":["/component---src-pages-guides-configuration-webpack-configuration-md-e4ebfbf4a4078f469af5.js"],"component---src-pages-guides-contribution-guides-index-md":["/component---src-pages-guides-contribution-guides-index-md-0c4a67b8dd8f06259a09.js"],"component---src-pages-guides-credential-rotation-md":["/component---src-pages-guides-credential-rotation-md-fcf4e3adab39ed782e77.js"],"component---src-pages-guides-deployment-ci-cd-for-firefly-apps-md":["/component---src-pages-guides-deployment-ci-cd-for-firefly-apps-md-7b2c290332dd29f59954.js"],"component---src-pages-guides-deployment-index-md":["/component---src-pages-guides-deployment-index-md-154e158d13745bdafda5.js"],"component---src-pages-guides-events-custom-events-md":["/component---src-pages-guides-events-custom-events-md-83b7522287fcbdde7670.js"],"component---src-pages-guides-events-webhooks-md":["/component---src-pages-guides-events-webhooks-md-7fb657a05936dcb05567.js"],"component---src-pages-guides-exc-app-index-md":["/component---src-pages-guides-exc-app-index-md-44e0ede3eccb1fcbc2d0.js"],"component---src-pages-guides-exc-app-interfaces-index-md":["/component---src-pages-guides-exc-app-interfaces-index-md-945e636d8ac116bd5336.js"],"component---src-pages-guides-exc-app-interfaces-index-runtime-md":["/component---src-pages-guides-exc-app-interfaces-index-runtime-md-5fa1c5bf57fcf62ed00b.js"],"component---src-pages-guides-exc-app-interfaces-page-objectwithhref-md":["/component---src-pages-guides-exc-app-interfaces-page-objectwithhref-md-5214a94905be9adc9cdc.js"],"component---src-pages-guides-exc-app-interfaces-page-objectwithpath-md":["/component---src-pages-guides-exc-app-interfaces-page-objectwithpath-md-fb79db38898336b54844.js"],"component---src-pages-guides-exc-app-interfaces-page-pageapi-md":["/component---src-pages-guides-exc-app-interfaces-page-pageapi-md-3dc2af7e6cb003d88b59.js"],"component---src-pages-guides-exc-app-interfaces-page-pageapiproperties-md":["/component---src-pages-guides-exc-app-interfaces-page-pageapiproperties-md-78e8eee2ee0eb29c8bf9.js"],"component---src-pages-guides-exc-app-interfaces-topbar-callback-md":["/component---src-pages-guides-exc-app-interfaces-topbar-callback-md-8550c1c1497893b65d46.js"],"component---src-pages-guides-exc-app-interfaces-topbar-customfeedbackconfig-md":["/component---src-pages-guides-exc-app-interfaces-topbar-customfeedbackconfig-md-5e3960250629783d6a6b.js"],"component---src-pages-guides-exc-app-interfaces-topbar-customsearchconfig-md":["/component---src-pages-guides-exc-app-interfaces-topbar-customsearchconfig-md-9990c2a072f3dd07a188.js"],"component---src-pages-guides-exc-app-interfaces-topbar-externalfeedbackconfig-md":["/component---src-pages-guides-exc-app-interfaces-topbar-externalfeedbackconfig-md-c5ff49b9027905f47e3c.js"],"component---src-pages-guides-exc-app-interfaces-topbar-helpcenterfeedbackconfig-md":["/component---src-pages-guides-exc-app-interfaces-topbar-helpcenterfeedbackconfig-md-6efe518bfe23305ea847.js"],"component---src-pages-guides-exc-app-interfaces-topbar-solution-md":["/component---src-pages-guides-exc-app-interfaces-topbar-solution-md-b7668c4ad5fe6a8e3773.js"],"component---src-pages-guides-exc-app-interfaces-topbar-topbarapi-md":["/component---src-pages-guides-exc-app-interfaces-topbar-topbarapi-md-daf41745c02c6c70797d.js"],"component---src-pages-guides-exc-app-interfaces-topbar-topbarapiproperties-md":["/component---src-pages-guides-exc-app-interfaces-topbar-topbarapiproperties-md-6dcae10cea0c938e47df.js"],"component---src-pages-guides-exc-app-interfaces-user-userapi-md":["/component---src-pages-guides-exc-app-interfaces-user-userapi-md-e77e9fab5acdde677a5b.js"],"component---src-pages-guides-exc-app-interfaces-user-userinfo-md":["/component---src-pages-guides-exc-app-interfaces-user-userinfo-md-4c9e7958d3c6e5c11849.js"],"component---src-pages-guides-exc-app-modules-index-md":["/component---src-pages-guides-exc-app-modules-index-md-e4b933e43926e725fe5b.js"],"component---src-pages-guides-exc-app-modules-page-md":["/component---src-pages-guides-exc-app-modules-page-md-dcc7e16a8bd72cea704b.js"],"component---src-pages-guides-exc-app-modules-topbar-md":["/component---src-pages-guides-exc-app-modules-topbar-md-5e4621729113932cdad1.js"],"component---src-pages-guides-exc-app-modules-user-md":["/component---src-pages-guides-exc-app-modules-user-md-7600e8de1cb750ff4c73.js"],"component---src-pages-guides-extensions-extension-migration-guide-md":["/component---src-pages-guides-extensions-extension-migration-guide-md-86ddefea05e8c31e8756.js"],"component---src-pages-guides-extensions-index-md":["/component---src-pages-guides-extensions-index-md-5a32c6371e29668785cb.js"],"component---src-pages-guides-extensions-ui-extensibility-md":["/component---src-pages-guides-extensions-ui-extensibility-md-fc2d74977252620c02a9.js"],"component---src-pages-guides-index-md":["/component---src-pages-guides-index-md-a0f359ba47027280f343.js"],"component---src-pages-guides-introduction-to-react-spectrum-md":["/component---src-pages-guides-introduction-to-react-spectrum-md-227a43dc569265c3a5fb.js"],"component---src-pages-guides-migrations-standalone-to-dx-experience-cloud-spa-md":["/component---src-pages-guides-migrations-standalone-to-dx-experience-cloud-spa-md-26d749328c73b525e263.js"],"component---src-pages-guides-packaging-md":["/component---src-pages-guides-packaging-md-f08d2e3f03cfad07c8ee.js"],"component---src-pages-guides-reference-documentation-index-md":["/component---src-pages-guides-reference-documentation-index-md-6ad59210942d73a5a876.js"],"component---src-pages-guides-security-index-md":["/component---src-pages-guides-security-index-md-8a3b23a89f005fdf91cb.js"],"component---src-pages-guides-security-understanding-authentication-md":["/component---src-pages-guides-security-understanding-authentication-md-b81be80c387c46281d95.js"],"component---src-pages-guides-telemetry-md":["/component---src-pages-guides-telemetry-md-6497ccf33687c49ecd5f.js"],"component---src-pages-guides-tips-tricks-md":["/component---src-pages-guides-tips-tricks-md-48f3f92f76d63450e5e6.js"],"component---src-pages-guides-using-sdks-md":["/component---src-pages-guides-using-sdks-md-5c1b9ea1f02b5f7c0fe6.js"],"component---src-pages-overview-community-md":["/component---src-pages-overview-community-md-663ee2710e8f3fcbcbe0.js"],"component---src-pages-overview-faq-md":["/component---src-pages-overview-faq-md-0fc02e72a47383b4af82.js"],"component---src-pages-overview-firefly-and-runtime-md":["/component---src-pages-overview-firefly-and-runtime-md-befacf5609ae1ec58330.js"],"component---src-pages-overview-getting-access-md":["/component---src-pages-overview-getting-access-md-ef995cec51b19a02cc0c.js"],"component---src-pages-overview-how-it-works-md":["/component---src-pages-overview-how-it-works-md-d6e0a7b1a6b7fe15016f.js"],"component---src-pages-overview-index-md":["/component---src-pages-overview-index-md-fd59745289597e58c5e3.js"],"component---src-pages-resources-asset-compute-worker-ps-api-index-md":["/component---src-pages-resources-asset-compute-worker-ps-api-index-md-35fa690eaf41a877d86d.js"],"component---src-pages-resources-asset-compute-worker-ps-api-lesson-1-md":["/component---src-pages-resources-asset-compute-worker-ps-api-lesson-1-md-4478674325a2692ad2eb.js"],"component---src-pages-resources-asset-compute-worker-ps-api-lesson-2-md":["/component---src-pages-resources-asset-compute-worker-ps-api-lesson-2-md-aa629bb8f67fc12b19ee.js"],"component---src-pages-resources-asset-compute-worker-ps-api-lesson-3-md":["/component---src-pages-resources-asset-compute-worker-ps-api-lesson-3-md-caae9aa4f9bbcbc67220.js"],"component---src-pages-resources-asset-compute-worker-ps-api-lesson-4-md":["/component---src-pages-resources-asset-compute-worker-ps-api-lesson-4-md-ed0012f79b0f006a2fbe.js"],"component---src-pages-resources-asset-compute-worker-ps-api-requirements-md":["/component---src-pages-resources-asset-compute-worker-ps-api-requirements-md-6ed6219681f996da6d3f.js"],"component---src-pages-resources-asset-compute-worker-ps-api-welldone-md":["/component---src-pages-resources-asset-compute-worker-ps-api-welldone-md-3a63eec6b724e99fc45d.js"],"component---src-pages-resources-barcode-reader-barcode-md":["/component---src-pages-resources-barcode-reader-barcode-md-ed16d97acf4296c2c058.js"],"component---src-pages-resources-barcode-reader-bootstrap-md":["/component---src-pages-resources-barcode-reader-bootstrap-md-4bbcdf8c7add6a891d0f.js"],"component---src-pages-resources-barcode-reader-index-md":["/component---src-pages-resources-barcode-reader-index-md-5950aa3a5b82e84a61b7.js"],"component---src-pages-resources-barcode-reader-requirements-md":["/component---src-pages-resources-barcode-reader-requirements-md-7b5ccd574efa28fbd27f.js"],"component---src-pages-resources-barcode-reader-test-md":["/component---src-pages-resources-barcode-reader-test-md-dee5178a4cfd284c7dd0.js"],"component---src-pages-resources-barcode-reader-welldone-md":["/component---src-pages-resources-barcode-reader-welldone-md-6153acfe5ae19c0bd8b0.js"],"component---src-pages-resources-blog-articles-md":["/component---src-pages-resources-blog-articles-md-896fc309efa697b6b34b.js"],"component---src-pages-resources-ci-cd-index-md":["/component---src-pages-resources-ci-cd-index-md-9c1b730f88069c08fce9.js"],"component---src-pages-resources-ci-cd-lesson-1-md":["/component---src-pages-resources-ci-cd-lesson-1-md-429efd95409d744da6c0.js"],"component---src-pages-resources-ci-cd-lesson-2-md":["/component---src-pages-resources-ci-cd-lesson-2-md-eb702c8392b9bfbe0838.js"],"component---src-pages-resources-ci-cd-lesson-3-md":["/component---src-pages-resources-ci-cd-lesson-3-md-308ba985e6d380ede0b1.js"],"component---src-pages-resources-ci-cd-requirements-md":["/component---src-pages-resources-ci-cd-requirements-md-eb784fa1debab93f5e5c.js"],"component---src-pages-resources-ci-cd-welldone-md":["/component---src-pages-resources-ci-cd-welldone-md-207f172bebde33f497b3.js"],"component---src-pages-resources-cron-jobs-index-md":["/component---src-pages-resources-cron-jobs-index-md-7e715beb8f7a5c117ae6.js"],"component---src-pages-resources-cron-jobs-lesson-1-md":["/component---src-pages-resources-cron-jobs-lesson-1-md-266a89eee73931e07c80.js"],"component---src-pages-resources-cron-jobs-lesson-2-md":["/component---src-pages-resources-cron-jobs-lesson-2-md-d27999305fac85088dd9.js"],"component---src-pages-resources-cron-jobs-lesson-3-md":["/component---src-pages-resources-cron-jobs-lesson-3-md-36deb835e8a0a0faeb84.js"],"component---src-pages-resources-cron-jobs-requirements-md":["/component---src-pages-resources-cron-jobs-requirements-md-ba4f65f8883c1299d7f4.js"],"component---src-pages-resources-cron-jobs-welldone-md":["/component---src-pages-resources-cron-jobs-welldone-md-032013d20d3ea672a716.js"],"component---src-pages-resources-custom-asset-compute-worker-aem-cloud-assets-md":["/component---src-pages-resources-custom-asset-compute-worker-aem-cloud-assets-md-145ee5b66ad847433c13.js"],"component---src-pages-resources-custom-asset-compute-worker-index-md":["/component---src-pages-resources-custom-asset-compute-worker-index-md-d9c02c5508abeb84a37c.js"],"component---src-pages-resources-custom-asset-compute-worker-lesson-1-md":["/component---src-pages-resources-custom-asset-compute-worker-lesson-1-md-bbfbeddbd3565690f5c0.js"],"component---src-pages-resources-custom-asset-compute-worker-lesson-2-md":["/component---src-pages-resources-custom-asset-compute-worker-lesson-2-md-fb1ec221040f866c0159.js"],"component---src-pages-resources-custom-asset-compute-worker-lesson-3-md":["/component---src-pages-resources-custom-asset-compute-worker-lesson-3-md-6cae68a90b9ec1fdc048.js"],"component---src-pages-resources-custom-asset-compute-worker-lesson-4-md":["/component---src-pages-resources-custom-asset-compute-worker-lesson-4-md-25a4b6d820857848cd6b.js"],"component---src-pages-resources-custom-asset-compute-worker-lesson-5-md":["/component---src-pages-resources-custom-asset-compute-worker-lesson-5-md-73c9c16269319784f15a.js"],"component---src-pages-resources-custom-asset-compute-worker-our-worker-md":["/component---src-pages-resources-custom-asset-compute-worker-our-worker-md-d05237d77f6005508f2a.js"],"component---src-pages-resources-custom-asset-compute-worker-requirements-md":["/component---src-pages-resources-custom-asset-compute-worker-requirements-md-d4bef7e926fa04d45062.js"],"component---src-pages-resources-custom-asset-compute-worker-welldone-md":["/component---src-pages-resources-custom-asset-compute-worker-welldone-md-6d99f7b96f95b0b53599.js"],"component---src-pages-resources-customer-dashboard-index-md":["/component---src-pages-resources-customer-dashboard-index-md-927d7c47886cf77d2350.js"],"component---src-pages-resources-customer-dashboard-lesson-1-md":["/component---src-pages-resources-customer-dashboard-lesson-1-md-a6b1b91cf9df80e09dac.js"],"component---src-pages-resources-customer-dashboard-lesson-2-md":["/component---src-pages-resources-customer-dashboard-lesson-2-md-f7bc173b5f67f81a1b33.js"],"component---src-pages-resources-customer-dashboard-lesson-3-md":["/component---src-pages-resources-customer-dashboard-lesson-3-md-475d3431d7eb103cfb3e.js"],"component---src-pages-resources-customer-dashboard-lesson-4-md":["/component---src-pages-resources-customer-dashboard-lesson-4-md-acfbdaa9bf8f079cfefa.js"],"component---src-pages-resources-customer-dashboard-lesson-5-md":["/component---src-pages-resources-customer-dashboard-lesson-5-md-9046a08985904355d57c.js"],"component---src-pages-resources-customer-dashboard-requirements-md":["/component---src-pages-resources-customer-dashboard-requirements-md-fb389d3b04092b7141b9.js"],"component---src-pages-resources-customer-dashboard-welldone-md":["/component---src-pages-resources-customer-dashboard-welldone-md-b7525e8043a00cc8edd1.js"],"component---src-pages-resources-debugging-index-md":["/component---src-pages-resources-debugging-index-md-3a802b6f8e3a7725e761.js"],"component---src-pages-resources-debugging-lesson-1-md":["/component---src-pages-resources-debugging-lesson-1-md-1ee64ff32c82092c698c.js"],"component---src-pages-resources-debugging-lesson-2-md":["/component---src-pages-resources-debugging-lesson-2-md-00509118c3b691cfab43.js"],"component---src-pages-resources-debugging-lesson-3-md":["/component---src-pages-resources-debugging-lesson-3-md-f702b26559818f601185.js"],"component---src-pages-resources-debugging-requirements-md":["/component---src-pages-resources-debugging-requirements-md-cb711c8f80bb13fb16de.js"],"component---src-pages-resources-debugging-welldone-md":["/component---src-pages-resources-debugging-welldone-md-462bbbdaa2fdceccc333.js"],"component---src-pages-resources-event-driven-index-md":["/component---src-pages-resources-event-driven-index-md-9030ef36271915654898.js"],"component---src-pages-resources-event-driven-lesson-1-md":["/component---src-pages-resources-event-driven-lesson-1-md-072a4f5a03a5d22af309.js"],"component---src-pages-resources-event-driven-lesson-2-md":["/component---src-pages-resources-event-driven-lesson-2-md-d12a7febe2a747cab8c0.js"],"component---src-pages-resources-event-driven-lesson-3-md":["/component---src-pages-resources-event-driven-lesson-3-md-c82e875c5ffd8a8aaf7c.js"],"component---src-pages-resources-event-driven-lesson-4-md":["/component---src-pages-resources-event-driven-lesson-4-md-79ac71d0982a0dc526e3.js"],"component---src-pages-resources-event-driven-requirements-md":["/component---src-pages-resources-event-driven-requirements-md-3d58d0a69f40323984f5.js"],"component---src-pages-resources-event-driven-welldone-md":["/component---src-pages-resources-event-driven-welldone-md-714bd829451c66c98213.js"],"component---src-pages-resources-events-runtime-index-md":["/component---src-pages-resources-events-runtime-index-md-94e1d21ddc32b29e5a9d.js"],"component---src-pages-resources-events-runtime-lesson-1-md":["/component---src-pages-resources-events-runtime-lesson-1-md-159bccc51923f988d14a.js"],"component---src-pages-resources-events-runtime-lesson-2-md":["/component---src-pages-resources-events-runtime-lesson-2-md-8fc61a8663ed9972e799.js"],"component---src-pages-resources-events-runtime-requirements-md":["/component---src-pages-resources-events-runtime-requirements-md-48dd3e462c0cb18beedb.js"],"component---src-pages-resources-events-runtime-welldone-md":["/component---src-pages-resources-events-runtime-welldone-md-2f6c582377f5156529d6.js"],"component---src-pages-resources-index-md":["/component---src-pages-resources-index-md-77e2172e46dd2d66cdb3.js"],"component---src-pages-resources-journaling-events-index-md":["/component---src-pages-resources-journaling-events-index-md-72754f50cdf2eb71c7c2.js"],"component---src-pages-resources-journaling-events-lesson-1-md":["/component---src-pages-resources-journaling-events-lesson-1-md-c80e24709e3277bd8279.js"],"component---src-pages-resources-journaling-events-lesson-2-md":["/component---src-pages-resources-journaling-events-lesson-2-md-cdf684a93ca70d07842b.js"],"component---src-pages-resources-journaling-events-lesson-3-md":["/component---src-pages-resources-journaling-events-lesson-3-md-f6717cec4e45aea79920.js"],"component---src-pages-resources-journaling-events-requirements-md":["/component---src-pages-resources-journaling-events-requirements-md-aca5c9b8785441b7c95a.js"],"component---src-pages-resources-journaling-events-welldone-md":["/component---src-pages-resources-journaling-events-welldone-md-9f5233bcf64e87d309a4.js"],"component---src-pages-resources-sample-apps-code-snippets-analytics-md":["/component---src-pages-resources-sample-apps-code-snippets-analytics-md-86c83fe0ed29aeff149f.js"],"component---src-pages-resources-sample-apps-code-snippets-events-md":["/component---src-pages-resources-sample-apps-code-snippets-events-md-3f35659e526895312817.js"],"component---src-pages-resources-sample-apps-code-snippets-files-md":["/component---src-pages-resources-sample-apps-code-snippets-files-md-34d20753ada5e7a44f43.js"],"component---src-pages-resources-sample-apps-code-snippets-index-md":["/component---src-pages-resources-sample-apps-code-snippets-index-md-15d357addb93f54e944f.js"],"component---src-pages-resources-sample-apps-code-snippets-state-md":["/component---src-pages-resources-sample-apps-code-snippets-state-md-38ffab2722cd09737c7a.js"],"component---src-pages-resources-sample-apps-demo-md":["/component---src-pages-resources-sample-apps-demo-md-39135b16c61e63c7d008.js"],"component---src-pages-resources-sample-apps-index-md":["/component---src-pages-resources-sample-apps-index-md-c736a1510629484cdd72.js"],"component---src-pages-resources-spectrum-intro-index-md":["/component---src-pages-resources-spectrum-intro-index-md-1f7ab05cd396a182bbf3.js"],"component---src-pages-resources-spectrum-intro-lesson-1-md":["/component---src-pages-resources-spectrum-intro-lesson-1-md-1fddcbeb6db6567d95a6.js"],"component---src-pages-resources-spectrum-intro-lesson-2-md":["/component---src-pages-resources-spectrum-intro-lesson-2-md-c1c67de38cb6308e02a9.js"],"component---src-pages-resources-spectrum-intro-lesson-3-md":["/component---src-pages-resources-spectrum-intro-lesson-3-md-cf7d6b725c1b9d203ea8.js"],"component---src-pages-resources-spectrum-intro-lesson-4-md":["/component---src-pages-resources-spectrum-intro-lesson-4-md-18e815c8023e96979958.js"],"component---src-pages-resources-spectrum-intro-requirements-md":["/component---src-pages-resources-spectrum-intro-requirements-md-8903c0c370f825418fdb.js"],"component---src-pages-resources-spectrum-intro-welldone-md":["/component---src-pages-resources-spectrum-intro-welldone-md-992b11341be83df19759.js"],"component---src-pages-resources-todo-app-index-md":["/component---src-pages-resources-todo-app-index-md-98dc6b17458a700b0df9.js"],"component---src-pages-resources-todo-app-lesson-1-md":["/component---src-pages-resources-todo-app-lesson-1-md-719daffaa6ef0ce2f3dd.js"],"component---src-pages-resources-todo-app-lesson-2-md":["/component---src-pages-resources-todo-app-lesson-2-md-2880baee5af9fbe63fcc.js"],"component---src-pages-resources-todo-app-lesson-3-md":["/component---src-pages-resources-todo-app-lesson-3-md-7bfbd842a287a47a4889.js"],"component---src-pages-resources-todo-app-lesson-4-md":["/component---src-pages-resources-todo-app-lesson-4-md-a15602d411a5a94e68cb.js"],"component---src-pages-resources-todo-app-lesson-5-md":["/component---src-pages-resources-todo-app-lesson-5-md-d6df2c7cf0ad7cbc59ae.js"],"component---src-pages-resources-todo-app-lesson-6-md":["/component---src-pages-resources-todo-app-lesson-6-md-750e2a97b0de58af785c.js"],"component---src-pages-resources-todo-app-requirements-md":["/component---src-pages-resources-todo-app-requirements-md-72244552ebc2c9708db8.js"],"component---src-pages-resources-todo-app-welldone-md":["/component---src-pages-resources-todo-app-welldone-md-e9028f2e1866aad9464a.js"],"component---src-pages-resources-videos-developers-live-asset-compute-service-extensibility-md":["/component---src-pages-resources-videos-developers-live-asset-compute-service-extensibility-md-7de169fe8dea5db675f7.js"],"component---src-pages-resources-videos-developers-live-deep-dive-md":["/component---src-pages-resources-videos-developers-live-deep-dive-md-cde8b781ec4f5d43e2a0.js"],"component---src-pages-resources-videos-developers-live-extend-experience-cloud-md":["/component---src-pages-resources-videos-developers-live-extend-experience-cloud-md-6587c0cccd8b1b90c42f.js"],"component---src-pages-resources-videos-exploring-ci-cd-md":["/component---src-pages-resources-videos-exploring-ci-cd-md-f316cea9a2e4827ccfa4.js"],"component---src-pages-resources-videos-exploring-custom-events-md":["/component---src-pages-resources-videos-exploring-custom-events-md-4b20f3874d5d96b7b098.js"],"component---src-pages-resources-videos-exploring-dashboard-case-study-md":["/component---src-pages-resources-videos-exploring-dashboard-case-study-md-457f7259d078065a3bba.js"],"component---src-pages-resources-videos-exploring-debugging-md":["/component---src-pages-resources-videos-exploring-debugging-md-f10542de7bb7afa92f50.js"],"component---src-pages-resources-videos-exploring-deep-dive-use-cases-md":["/component---src-pages-resources-videos-exploring-deep-dive-use-cases-md-5783e554222ba5f61f43.js"],"component---src-pages-resources-videos-exploring-learning-resources-md":["/component---src-pages-resources-videos-exploring-learning-resources-md-b0a66ff40b332942c773.js"],"component---src-pages-resources-videos-exploring-live-wired-sneak-md":["/component---src-pages-resources-videos-exploring-live-wired-sneak-md-9c3ab3b55491582428cc.js"],"component---src-pages-resources-videos-exploring-ode-case-study-md":["/component---src-pages-resources-videos-exploring-ode-case-study-md-c825836baedd83f88cc0.js"],"component---src-pages-resources-videos-exploring-projects-and-workspaces-md":["/component---src-pages-resources-videos-exploring-projects-and-workspaces-md-0fe79a204343c600e23b.js"],"component---src-pages-resources-videos-exploring-react-spectrum-md":["/component---src-pages-resources-videos-exploring-react-spectrum-md-2b9782854436fdcd2e4e.js"],"component---src-pages-resources-videos-exploring-softcrylic-showcase-md":["/component---src-pages-resources-videos-exploring-softcrylic-showcase-md-6d431020c452ff49566d.js"],"component---src-pages-resources-videos-index-md":["/component---src-pages-resources-videos-index-md-f6426bf70d14696db10a.js"],"component---src-pages-resources-videos-overview-architecture-md":["/component---src-pages-resources-videos-overview-architecture-md-2ae5016e2387776e6fe3.js"],"component---src-pages-resources-videos-overview-e-2-e-user-journey-md":["/component---src-pages-resources-videos-overview-e-2-e-user-journey-md-bb2a388cbe114343921b.js"],"component---src-pages-resources-videos-overview-getting-started-md":["/component---src-pages-resources-videos-overview-getting-started-md-80fe5c06b0093caa9c4e.js"],"component---src-pages-resources-videos-overview-introduction-md":["/component---src-pages-resources-videos-overview-introduction-md-4840e1a7cd835cc6aedd.js"],"component---src-pages-resources-videos-overview-security-md":["/component---src-pages-resources-videos-overview-security-md-92d5bbe010de14f85b88.js"]} \ No newline at end of file +{"polyfill":["/polyfill-d3d3335b6bf2529ad347.js"],"app":["/app-dd2d487797dd3aafcf94.js"],"component---node-modules-adobe-gatsby-theme-aio-src-pages-404-md":["/component---node-modules-adobe-gatsby-theme-aio-src-pages-404-md-43c272de2ceb90407f66.js"],"component---src-pages-getting-started-common-troubleshooting-md":["/component---src-pages-getting-started-common-troubleshooting-md-3259bccd023c4b55277f.js"],"component---src-pages-getting-started-first-app-md":["/component---src-pages-getting-started-first-app-md-47778bd1129b46dd51cd.js"],"component---src-pages-getting-started-index-md":["/component---src-pages-getting-started-index-md-1a082caab455c998ea31.js"],"component---src-pages-getting-started-publish-app-md":["/component---src-pages-getting-started-publish-app-md-68dd2ce1c57a3ed3d576.js"],"component---src-pages-guides-app-hooks-md":["/component---src-pages-guides-app-hooks-md-9117c4a5ae1fbac6f25f.js"],"component---src-pages-guides-application-logging-azure-log-analytics-md":["/component---src-pages-guides-application-logging-azure-log-analytics-md-708198e6b61e8710905a.js"],"component---src-pages-guides-application-logging-index-md":["/component---src-pages-guides-application-logging-index-md-dbdd1a2756548e65aa11.js"],"component---src-pages-guides-application-logging-new-relic-md":["/component---src-pages-guides-application-logging-new-relic-md-a3847bd9db09e57c6c23.js"],"component---src-pages-guides-application-logging-splunk-cloud-md":["/component---src-pages-guides-application-logging-splunk-cloud-md-621ac05d566eaf94d904.js"],"component---src-pages-guides-application-logging-splunk-enterprise-md":["/component---src-pages-guides-application-logging-splunk-enterprise-md-ec4bc71797bb3b05b204.js"],"component---src-pages-guides-application-state-md":["/component---src-pages-guides-application-state-md-77cc253033ca5df908cb.js"],"component---src-pages-guides-configuration-index-md":["/component---src-pages-guides-configuration-index-md-59201e843287f51ead6a.js"],"component---src-pages-guides-configuration-webpack-configuration-md":["/component---src-pages-guides-configuration-webpack-configuration-md-e4ebfbf4a4078f469af5.js"],"component---src-pages-guides-contribution-guides-index-md":["/component---src-pages-guides-contribution-guides-index-md-0c4a67b8dd8f06259a09.js"],"component---src-pages-guides-credential-rotation-md":["/component---src-pages-guides-credential-rotation-md-fcf4e3adab39ed782e77.js"],"component---src-pages-guides-deployment-ci-cd-for-firefly-apps-md":["/component---src-pages-guides-deployment-ci-cd-for-firefly-apps-md-7b2c290332dd29f59954.js"],"component---src-pages-guides-deployment-index-md":["/component---src-pages-guides-deployment-index-md-154e158d13745bdafda5.js"],"component---src-pages-guides-events-custom-events-md":["/component---src-pages-guides-events-custom-events-md-83b7522287fcbdde7670.js"],"component---src-pages-guides-events-webhooks-md":["/component---src-pages-guides-events-webhooks-md-7fb657a05936dcb05567.js"],"component---src-pages-guides-exc-app-index-md":["/component---src-pages-guides-exc-app-index-md-44e0ede3eccb1fcbc2d0.js"],"component---src-pages-guides-exc-app-interfaces-index-md":["/component---src-pages-guides-exc-app-interfaces-index-md-945e636d8ac116bd5336.js"],"component---src-pages-guides-exc-app-interfaces-index-runtime-md":["/component---src-pages-guides-exc-app-interfaces-index-runtime-md-5fa1c5bf57fcf62ed00b.js"],"component---src-pages-guides-exc-app-interfaces-page-objectwithhref-md":["/component---src-pages-guides-exc-app-interfaces-page-objectwithhref-md-5214a94905be9adc9cdc.js"],"component---src-pages-guides-exc-app-interfaces-page-objectwithpath-md":["/component---src-pages-guides-exc-app-interfaces-page-objectwithpath-md-fb79db38898336b54844.js"],"component---src-pages-guides-exc-app-interfaces-page-pageapi-md":["/component---src-pages-guides-exc-app-interfaces-page-pageapi-md-3dc2af7e6cb003d88b59.js"],"component---src-pages-guides-exc-app-interfaces-page-pageapiproperties-md":["/component---src-pages-guides-exc-app-interfaces-page-pageapiproperties-md-78e8eee2ee0eb29c8bf9.js"],"component---src-pages-guides-exc-app-interfaces-topbar-callback-md":["/component---src-pages-guides-exc-app-interfaces-topbar-callback-md-8550c1c1497893b65d46.js"],"component---src-pages-guides-exc-app-interfaces-topbar-customfeedbackconfig-md":["/component---src-pages-guides-exc-app-interfaces-topbar-customfeedbackconfig-md-5e3960250629783d6a6b.js"],"component---src-pages-guides-exc-app-interfaces-topbar-customsearchconfig-md":["/component---src-pages-guides-exc-app-interfaces-topbar-customsearchconfig-md-9990c2a072f3dd07a188.js"],"component---src-pages-guides-exc-app-interfaces-topbar-externalfeedbackconfig-md":["/component---src-pages-guides-exc-app-interfaces-topbar-externalfeedbackconfig-md-c5ff49b9027905f47e3c.js"],"component---src-pages-guides-exc-app-interfaces-topbar-helpcenterfeedbackconfig-md":["/component---src-pages-guides-exc-app-interfaces-topbar-helpcenterfeedbackconfig-md-6efe518bfe23305ea847.js"],"component---src-pages-guides-exc-app-interfaces-topbar-solution-md":["/component---src-pages-guides-exc-app-interfaces-topbar-solution-md-b7668c4ad5fe6a8e3773.js"],"component---src-pages-guides-exc-app-interfaces-topbar-topbarapi-md":["/component---src-pages-guides-exc-app-interfaces-topbar-topbarapi-md-daf41745c02c6c70797d.js"],"component---src-pages-guides-exc-app-interfaces-topbar-topbarapiproperties-md":["/component---src-pages-guides-exc-app-interfaces-topbar-topbarapiproperties-md-6dcae10cea0c938e47df.js"],"component---src-pages-guides-exc-app-interfaces-user-userapi-md":["/component---src-pages-guides-exc-app-interfaces-user-userapi-md-e77e9fab5acdde677a5b.js"],"component---src-pages-guides-exc-app-interfaces-user-userinfo-md":["/component---src-pages-guides-exc-app-interfaces-user-userinfo-md-4c9e7958d3c6e5c11849.js"],"component---src-pages-guides-exc-app-modules-index-md":["/component---src-pages-guides-exc-app-modules-index-md-e4b933e43926e725fe5b.js"],"component---src-pages-guides-exc-app-modules-page-md":["/component---src-pages-guides-exc-app-modules-page-md-dcc7e16a8bd72cea704b.js"],"component---src-pages-guides-exc-app-modules-topbar-md":["/component---src-pages-guides-exc-app-modules-topbar-md-5e4621729113932cdad1.js"],"component---src-pages-guides-exc-app-modules-user-md":["/component---src-pages-guides-exc-app-modules-user-md-7600e8de1cb750ff4c73.js"],"component---src-pages-guides-extensions-extension-migration-guide-md":["/component---src-pages-guides-extensions-extension-migration-guide-md-86ddefea05e8c31e8756.js"],"component---src-pages-guides-extensions-index-md":["/component---src-pages-guides-extensions-index-md-5a32c6371e29668785cb.js"],"component---src-pages-guides-extensions-ui-extensibility-md":["/component---src-pages-guides-extensions-ui-extensibility-md-fc2d74977252620c02a9.js"],"component---src-pages-guides-index-md":["/component---src-pages-guides-index-md-a0f359ba47027280f343.js"],"component---src-pages-guides-introduction-to-react-spectrum-md":["/component---src-pages-guides-introduction-to-react-spectrum-md-227a43dc569265c3a5fb.js"],"component---src-pages-guides-migrations-standalone-to-dx-experience-cloud-spa-md":["/component---src-pages-guides-migrations-standalone-to-dx-experience-cloud-spa-md-26d749328c73b525e263.js"],"component---src-pages-guides-packaging-md":["/component---src-pages-guides-packaging-md-f08d2e3f03cfad07c8ee.js"],"component---src-pages-guides-reference-documentation-index-md":["/component---src-pages-guides-reference-documentation-index-md-6ad59210942d73a5a876.js"],"component---src-pages-guides-security-index-md":["/component---src-pages-guides-security-index-md-8a3b23a89f005fdf91cb.js"],"component---src-pages-guides-security-understanding-authentication-md":["/component---src-pages-guides-security-understanding-authentication-md-b81be80c387c46281d95.js"],"component---src-pages-guides-telemetry-md":["/component---src-pages-guides-telemetry-md-6497ccf33687c49ecd5f.js"],"component---src-pages-guides-tips-tricks-md":["/component---src-pages-guides-tips-tricks-md-76b2d98659179f02cb96.js"],"component---src-pages-guides-using-sdks-md":["/component---src-pages-guides-using-sdks-md-5c1b9ea1f02b5f7c0fe6.js"],"component---src-pages-overview-community-md":["/component---src-pages-overview-community-md-663ee2710e8f3fcbcbe0.js"],"component---src-pages-overview-faq-md":["/component---src-pages-overview-faq-md-0fc02e72a47383b4af82.js"],"component---src-pages-overview-firefly-and-runtime-md":["/component---src-pages-overview-firefly-and-runtime-md-befacf5609ae1ec58330.js"],"component---src-pages-overview-getting-access-md":["/component---src-pages-overview-getting-access-md-ef995cec51b19a02cc0c.js"],"component---src-pages-overview-how-it-works-md":["/component---src-pages-overview-how-it-works-md-d6e0a7b1a6b7fe15016f.js"],"component---src-pages-overview-index-md":["/component---src-pages-overview-index-md-fd59745289597e58c5e3.js"],"component---src-pages-resources-asset-compute-worker-ps-api-index-md":["/component---src-pages-resources-asset-compute-worker-ps-api-index-md-35fa690eaf41a877d86d.js"],"component---src-pages-resources-asset-compute-worker-ps-api-lesson-1-md":["/component---src-pages-resources-asset-compute-worker-ps-api-lesson-1-md-4478674325a2692ad2eb.js"],"component---src-pages-resources-asset-compute-worker-ps-api-lesson-2-md":["/component---src-pages-resources-asset-compute-worker-ps-api-lesson-2-md-aa629bb8f67fc12b19ee.js"],"component---src-pages-resources-asset-compute-worker-ps-api-lesson-3-md":["/component---src-pages-resources-asset-compute-worker-ps-api-lesson-3-md-caae9aa4f9bbcbc67220.js"],"component---src-pages-resources-asset-compute-worker-ps-api-lesson-4-md":["/component---src-pages-resources-asset-compute-worker-ps-api-lesson-4-md-ed0012f79b0f006a2fbe.js"],"component---src-pages-resources-asset-compute-worker-ps-api-requirements-md":["/component---src-pages-resources-asset-compute-worker-ps-api-requirements-md-6ed6219681f996da6d3f.js"],"component---src-pages-resources-asset-compute-worker-ps-api-welldone-md":["/component---src-pages-resources-asset-compute-worker-ps-api-welldone-md-3a63eec6b724e99fc45d.js"],"component---src-pages-resources-barcode-reader-barcode-md":["/component---src-pages-resources-barcode-reader-barcode-md-ed16d97acf4296c2c058.js"],"component---src-pages-resources-barcode-reader-bootstrap-md":["/component---src-pages-resources-barcode-reader-bootstrap-md-4bbcdf8c7add6a891d0f.js"],"component---src-pages-resources-barcode-reader-index-md":["/component---src-pages-resources-barcode-reader-index-md-5950aa3a5b82e84a61b7.js"],"component---src-pages-resources-barcode-reader-requirements-md":["/component---src-pages-resources-barcode-reader-requirements-md-7b5ccd574efa28fbd27f.js"],"component---src-pages-resources-barcode-reader-test-md":["/component---src-pages-resources-barcode-reader-test-md-dee5178a4cfd284c7dd0.js"],"component---src-pages-resources-barcode-reader-welldone-md":["/component---src-pages-resources-barcode-reader-welldone-md-6153acfe5ae19c0bd8b0.js"],"component---src-pages-resources-blog-articles-md":["/component---src-pages-resources-blog-articles-md-896fc309efa697b6b34b.js"],"component---src-pages-resources-ci-cd-index-md":["/component---src-pages-resources-ci-cd-index-md-9c1b730f88069c08fce9.js"],"component---src-pages-resources-ci-cd-lesson-1-md":["/component---src-pages-resources-ci-cd-lesson-1-md-429efd95409d744da6c0.js"],"component---src-pages-resources-ci-cd-lesson-2-md":["/component---src-pages-resources-ci-cd-lesson-2-md-eb702c8392b9bfbe0838.js"],"component---src-pages-resources-ci-cd-lesson-3-md":["/component---src-pages-resources-ci-cd-lesson-3-md-308ba985e6d380ede0b1.js"],"component---src-pages-resources-ci-cd-requirements-md":["/component---src-pages-resources-ci-cd-requirements-md-eb784fa1debab93f5e5c.js"],"component---src-pages-resources-ci-cd-welldone-md":["/component---src-pages-resources-ci-cd-welldone-md-207f172bebde33f497b3.js"],"component---src-pages-resources-cron-jobs-index-md":["/component---src-pages-resources-cron-jobs-index-md-7e715beb8f7a5c117ae6.js"],"component---src-pages-resources-cron-jobs-lesson-1-md":["/component---src-pages-resources-cron-jobs-lesson-1-md-266a89eee73931e07c80.js"],"component---src-pages-resources-cron-jobs-lesson-2-md":["/component---src-pages-resources-cron-jobs-lesson-2-md-d27999305fac85088dd9.js"],"component---src-pages-resources-cron-jobs-lesson-3-md":["/component---src-pages-resources-cron-jobs-lesson-3-md-36deb835e8a0a0faeb84.js"],"component---src-pages-resources-cron-jobs-requirements-md":["/component---src-pages-resources-cron-jobs-requirements-md-ba4f65f8883c1299d7f4.js"],"component---src-pages-resources-cron-jobs-welldone-md":["/component---src-pages-resources-cron-jobs-welldone-md-032013d20d3ea672a716.js"],"component---src-pages-resources-custom-asset-compute-worker-aem-cloud-assets-md":["/component---src-pages-resources-custom-asset-compute-worker-aem-cloud-assets-md-145ee5b66ad847433c13.js"],"component---src-pages-resources-custom-asset-compute-worker-index-md":["/component---src-pages-resources-custom-asset-compute-worker-index-md-d9c02c5508abeb84a37c.js"],"component---src-pages-resources-custom-asset-compute-worker-lesson-1-md":["/component---src-pages-resources-custom-asset-compute-worker-lesson-1-md-bbfbeddbd3565690f5c0.js"],"component---src-pages-resources-custom-asset-compute-worker-lesson-2-md":["/component---src-pages-resources-custom-asset-compute-worker-lesson-2-md-fb1ec221040f866c0159.js"],"component---src-pages-resources-custom-asset-compute-worker-lesson-3-md":["/component---src-pages-resources-custom-asset-compute-worker-lesson-3-md-6cae68a90b9ec1fdc048.js"],"component---src-pages-resources-custom-asset-compute-worker-lesson-4-md":["/component---src-pages-resources-custom-asset-compute-worker-lesson-4-md-25a4b6d820857848cd6b.js"],"component---src-pages-resources-custom-asset-compute-worker-lesson-5-md":["/component---src-pages-resources-custom-asset-compute-worker-lesson-5-md-73c9c16269319784f15a.js"],"component---src-pages-resources-custom-asset-compute-worker-our-worker-md":["/component---src-pages-resources-custom-asset-compute-worker-our-worker-md-d05237d77f6005508f2a.js"],"component---src-pages-resources-custom-asset-compute-worker-requirements-md":["/component---src-pages-resources-custom-asset-compute-worker-requirements-md-d4bef7e926fa04d45062.js"],"component---src-pages-resources-custom-asset-compute-worker-welldone-md":["/component---src-pages-resources-custom-asset-compute-worker-welldone-md-6d99f7b96f95b0b53599.js"],"component---src-pages-resources-customer-dashboard-index-md":["/component---src-pages-resources-customer-dashboard-index-md-927d7c47886cf77d2350.js"],"component---src-pages-resources-customer-dashboard-lesson-1-md":["/component---src-pages-resources-customer-dashboard-lesson-1-md-a6b1b91cf9df80e09dac.js"],"component---src-pages-resources-customer-dashboard-lesson-2-md":["/component---src-pages-resources-customer-dashboard-lesson-2-md-eefecb058a6ab28704fb.js"],"component---src-pages-resources-customer-dashboard-lesson-3-md":["/component---src-pages-resources-customer-dashboard-lesson-3-md-475d3431d7eb103cfb3e.js"],"component---src-pages-resources-customer-dashboard-lesson-4-md":["/component---src-pages-resources-customer-dashboard-lesson-4-md-acfbdaa9bf8f079cfefa.js"],"component---src-pages-resources-customer-dashboard-lesson-5-md":["/component---src-pages-resources-customer-dashboard-lesson-5-md-9046a08985904355d57c.js"],"component---src-pages-resources-customer-dashboard-requirements-md":["/component---src-pages-resources-customer-dashboard-requirements-md-fb389d3b04092b7141b9.js"],"component---src-pages-resources-customer-dashboard-welldone-md":["/component---src-pages-resources-customer-dashboard-welldone-md-b7525e8043a00cc8edd1.js"],"component---src-pages-resources-debugging-index-md":["/component---src-pages-resources-debugging-index-md-3a802b6f8e3a7725e761.js"],"component---src-pages-resources-debugging-lesson-1-md":["/component---src-pages-resources-debugging-lesson-1-md-1ee64ff32c82092c698c.js"],"component---src-pages-resources-debugging-lesson-2-md":["/component---src-pages-resources-debugging-lesson-2-md-00509118c3b691cfab43.js"],"component---src-pages-resources-debugging-lesson-3-md":["/component---src-pages-resources-debugging-lesson-3-md-f702b26559818f601185.js"],"component---src-pages-resources-debugging-requirements-md":["/component---src-pages-resources-debugging-requirements-md-cb711c8f80bb13fb16de.js"],"component---src-pages-resources-debugging-welldone-md":["/component---src-pages-resources-debugging-welldone-md-462bbbdaa2fdceccc333.js"],"component---src-pages-resources-event-driven-index-md":["/component---src-pages-resources-event-driven-index-md-9030ef36271915654898.js"],"component---src-pages-resources-event-driven-lesson-1-md":["/component---src-pages-resources-event-driven-lesson-1-md-072a4f5a03a5d22af309.js"],"component---src-pages-resources-event-driven-lesson-2-md":["/component---src-pages-resources-event-driven-lesson-2-md-d12a7febe2a747cab8c0.js"],"component---src-pages-resources-event-driven-lesson-3-md":["/component---src-pages-resources-event-driven-lesson-3-md-85152016b2cedeb468df.js"],"component---src-pages-resources-event-driven-lesson-4-md":["/component---src-pages-resources-event-driven-lesson-4-md-7e789bf584551cda4578.js"],"component---src-pages-resources-event-driven-requirements-md":["/component---src-pages-resources-event-driven-requirements-md-3d58d0a69f40323984f5.js"],"component---src-pages-resources-event-driven-welldone-md":["/component---src-pages-resources-event-driven-welldone-md-714bd829451c66c98213.js"],"component---src-pages-resources-events-runtime-index-md":["/component---src-pages-resources-events-runtime-index-md-94e1d21ddc32b29e5a9d.js"],"component---src-pages-resources-events-runtime-lesson-1-md":["/component---src-pages-resources-events-runtime-lesson-1-md-159bccc51923f988d14a.js"],"component---src-pages-resources-events-runtime-lesson-2-md":["/component---src-pages-resources-events-runtime-lesson-2-md-8fc61a8663ed9972e799.js"],"component---src-pages-resources-events-runtime-requirements-md":["/component---src-pages-resources-events-runtime-requirements-md-48dd3e462c0cb18beedb.js"],"component---src-pages-resources-events-runtime-welldone-md":["/component---src-pages-resources-events-runtime-welldone-md-2f6c582377f5156529d6.js"],"component---src-pages-resources-index-md":["/component---src-pages-resources-index-md-77e2172e46dd2d66cdb3.js"],"component---src-pages-resources-journaling-events-index-md":["/component---src-pages-resources-journaling-events-index-md-72754f50cdf2eb71c7c2.js"],"component---src-pages-resources-journaling-events-lesson-1-md":["/component---src-pages-resources-journaling-events-lesson-1-md-c80e24709e3277bd8279.js"],"component---src-pages-resources-journaling-events-lesson-2-md":["/component---src-pages-resources-journaling-events-lesson-2-md-cdf684a93ca70d07842b.js"],"component---src-pages-resources-journaling-events-lesson-3-md":["/component---src-pages-resources-journaling-events-lesson-3-md-f6717cec4e45aea79920.js"],"component---src-pages-resources-journaling-events-requirements-md":["/component---src-pages-resources-journaling-events-requirements-md-aca5c9b8785441b7c95a.js"],"component---src-pages-resources-journaling-events-welldone-md":["/component---src-pages-resources-journaling-events-welldone-md-9f5233bcf64e87d309a4.js"],"component---src-pages-resources-sample-apps-code-snippets-analytics-md":["/component---src-pages-resources-sample-apps-code-snippets-analytics-md-86c83fe0ed29aeff149f.js"],"component---src-pages-resources-sample-apps-code-snippets-events-md":["/component---src-pages-resources-sample-apps-code-snippets-events-md-3f35659e526895312817.js"],"component---src-pages-resources-sample-apps-code-snippets-files-md":["/component---src-pages-resources-sample-apps-code-snippets-files-md-34d20753ada5e7a44f43.js"],"component---src-pages-resources-sample-apps-code-snippets-index-md":["/component---src-pages-resources-sample-apps-code-snippets-index-md-0bd5d2cbaed0f9e5560b.js"],"component---src-pages-resources-sample-apps-code-snippets-state-md":["/component---src-pages-resources-sample-apps-code-snippets-state-md-38ffab2722cd09737c7a.js"],"component---src-pages-resources-sample-apps-demo-md":["/component---src-pages-resources-sample-apps-demo-md-39135b16c61e63c7d008.js"],"component---src-pages-resources-sample-apps-index-md":["/component---src-pages-resources-sample-apps-index-md-c736a1510629484cdd72.js"],"component---src-pages-resources-spectrum-intro-index-md":["/component---src-pages-resources-spectrum-intro-index-md-1f7ab05cd396a182bbf3.js"],"component---src-pages-resources-spectrum-intro-lesson-1-md":["/component---src-pages-resources-spectrum-intro-lesson-1-md-1fddcbeb6db6567d95a6.js"],"component---src-pages-resources-spectrum-intro-lesson-2-md":["/component---src-pages-resources-spectrum-intro-lesson-2-md-c1c67de38cb6308e02a9.js"],"component---src-pages-resources-spectrum-intro-lesson-3-md":["/component---src-pages-resources-spectrum-intro-lesson-3-md-cf7d6b725c1b9d203ea8.js"],"component---src-pages-resources-spectrum-intro-lesson-4-md":["/component---src-pages-resources-spectrum-intro-lesson-4-md-18e815c8023e96979958.js"],"component---src-pages-resources-spectrum-intro-requirements-md":["/component---src-pages-resources-spectrum-intro-requirements-md-8903c0c370f825418fdb.js"],"component---src-pages-resources-spectrum-intro-welldone-md":["/component---src-pages-resources-spectrum-intro-welldone-md-992b11341be83df19759.js"],"component---src-pages-resources-todo-app-index-md":["/component---src-pages-resources-todo-app-index-md-98dc6b17458a700b0df9.js"],"component---src-pages-resources-todo-app-lesson-1-md":["/component---src-pages-resources-todo-app-lesson-1-md-719daffaa6ef0ce2f3dd.js"],"component---src-pages-resources-todo-app-lesson-2-md":["/component---src-pages-resources-todo-app-lesson-2-md-2880baee5af9fbe63fcc.js"],"component---src-pages-resources-todo-app-lesson-3-md":["/component---src-pages-resources-todo-app-lesson-3-md-7bfbd842a287a47a4889.js"],"component---src-pages-resources-todo-app-lesson-4-md":["/component---src-pages-resources-todo-app-lesson-4-md-a15602d411a5a94e68cb.js"],"component---src-pages-resources-todo-app-lesson-5-md":["/component---src-pages-resources-todo-app-lesson-5-md-d6df2c7cf0ad7cbc59ae.js"],"component---src-pages-resources-todo-app-lesson-6-md":["/component---src-pages-resources-todo-app-lesson-6-md-750e2a97b0de58af785c.js"],"component---src-pages-resources-todo-app-requirements-md":["/component---src-pages-resources-todo-app-requirements-md-72244552ebc2c9708db8.js"],"component---src-pages-resources-todo-app-welldone-md":["/component---src-pages-resources-todo-app-welldone-md-e9028f2e1866aad9464a.js"],"component---src-pages-resources-videos-developers-live-asset-compute-service-extensibility-md":["/component---src-pages-resources-videos-developers-live-asset-compute-service-extensibility-md-7de169fe8dea5db675f7.js"],"component---src-pages-resources-videos-developers-live-deep-dive-md":["/component---src-pages-resources-videos-developers-live-deep-dive-md-cde8b781ec4f5d43e2a0.js"],"component---src-pages-resources-videos-developers-live-extend-experience-cloud-md":["/component---src-pages-resources-videos-developers-live-extend-experience-cloud-md-6587c0cccd8b1b90c42f.js"],"component---src-pages-resources-videos-exploring-ci-cd-md":["/component---src-pages-resources-videos-exploring-ci-cd-md-f316cea9a2e4827ccfa4.js"],"component---src-pages-resources-videos-exploring-custom-events-md":["/component---src-pages-resources-videos-exploring-custom-events-md-4b20f3874d5d96b7b098.js"],"component---src-pages-resources-videos-exploring-dashboard-case-study-md":["/component---src-pages-resources-videos-exploring-dashboard-case-study-md-457f7259d078065a3bba.js"],"component---src-pages-resources-videos-exploring-debugging-md":["/component---src-pages-resources-videos-exploring-debugging-md-f10542de7bb7afa92f50.js"],"component---src-pages-resources-videos-exploring-deep-dive-use-cases-md":["/component---src-pages-resources-videos-exploring-deep-dive-use-cases-md-5783e554222ba5f61f43.js"],"component---src-pages-resources-videos-exploring-learning-resources-md":["/component---src-pages-resources-videos-exploring-learning-resources-md-b0a66ff40b332942c773.js"],"component---src-pages-resources-videos-exploring-live-wired-sneak-md":["/component---src-pages-resources-videos-exploring-live-wired-sneak-md-9c3ab3b55491582428cc.js"],"component---src-pages-resources-videos-exploring-ode-case-study-md":["/component---src-pages-resources-videos-exploring-ode-case-study-md-c825836baedd83f88cc0.js"],"component---src-pages-resources-videos-exploring-projects-and-workspaces-md":["/component---src-pages-resources-videos-exploring-projects-and-workspaces-md-0fe79a204343c600e23b.js"],"component---src-pages-resources-videos-exploring-react-spectrum-md":["/component---src-pages-resources-videos-exploring-react-spectrum-md-2b9782854436fdcd2e4e.js"],"component---src-pages-resources-videos-exploring-softcrylic-showcase-md":["/component---src-pages-resources-videos-exploring-softcrylic-showcase-md-6d431020c452ff49566d.js"],"component---src-pages-resources-videos-index-md":["/component---src-pages-resources-videos-index-md-f6426bf70d14696db10a.js"],"component---src-pages-resources-videos-overview-architecture-md":["/component---src-pages-resources-videos-overview-architecture-md-2ae5016e2387776e6fe3.js"],"component---src-pages-resources-videos-overview-e-2-e-user-journey-md":["/component---src-pages-resources-videos-overview-e-2-e-user-journey-md-bb2a388cbe114343921b.js"],"component---src-pages-resources-videos-overview-getting-started-md":["/component---src-pages-resources-videos-overview-getting-started-md-80fe5c06b0093caa9c4e.js"],"component---src-pages-resources-videos-overview-introduction-md":["/component---src-pages-resources-videos-overview-introduction-md-4840e1a7cd835cc6aedd.js"],"component---src-pages-resources-videos-overview-security-md":["/component---src-pages-resources-videos-overview-security-md-92d5bbe010de14f85b88.js"]} \ No newline at end of file diff --git a/component---src-pages-getting-started-common-troubleshooting-md-3259bccd023c4b55277f.js b/component---src-pages-getting-started-common-troubleshooting-md-3259bccd023c4b55277f.js new file mode 100644 index 000000000..a1e284918 --- /dev/null +++ b/component---src-pages-getting-started-common-troubleshooting-md-3259bccd023c4b55277f.js @@ -0,0 +1,2 @@ +"use strict";(self.webpackChunkadobe_developer_app_builder=self.webpackChunkadobe_developer_app_builder||[]).push([[9439],{35013:function(e,t,a){a.r(t),a.d(t,{_frontmatter:function(){return d},default:function(){return m}});var o=a(87462),n=a(63366),i=(a(15007),a(64983)),r=a(91515),s=["components"],d={},l={_frontmatter:d},u=r.Z;function m(e){var t=e.components,a=(0,n.Z)(e,s);return(0,i.mdx)(u,(0,o.Z)({},l,a,{components:t,mdxType:"MDXLayout"}),(0,i.mdx)("h1",{id:"common-troubleshooting"},"Common Troubleshooting"),(0,i.mdx)("p",null,"Here are troubleshooting guides for some of the most common issues as you develop your first App Builder apps."),(0,i.mdx)("h2",{id:"before-you-proceed"},"Before you proceed"),(0,i.mdx)("ul",null,(0,i.mdx)("li",{parentName:"ul"},"Check your Node version and tool versions to ensure they are supported by App Builder and up-to-date. You can find the latest supported version ",(0,i.mdx)("a",{parentName:"li",href:"index.md"},"here"),"."),(0,i.mdx)("li",{parentName:"ul"},"Check if your application is on Dropbox or OneDrive as file watchers sometimes cause unexpected errors. ")),(0,i.mdx)("h2",{id:"general-debugging"},"General debugging"),(0,i.mdx)("p",null,"When your action code doesn't work as expected, you may want to investigate into what exactly went wrong. App Builder provides the ",(0,i.mdx)("a",{parentName:"p",href:"https://github.com/adobe/aio-lib-core-logging"},"Logging SDK"),", please check out ",(0,i.mdx)("a",{parentName:"p",href:"../guides/application_logging.md"},"App Builder's Application Logging")," for more details. "),(0,i.mdx)("p",null,"To see the latest activations of your project, run this command:"),(0,i.mdx)("pre",null,(0,i.mdx)("code",{parentName:"pre",className:"language-bash"},"aio runtime activation list\n")),(0,i.mdx)("p",null,"It lists the most recent activations and summary (ID, start / end time, duration, status, and so on). There are 4 most popular statuses of a finished activation:"),(0,i.mdx)("ul",null,(0,i.mdx)("li",{parentName:"ul"},(0,i.mdx)("inlineCode",{parentName:"li"},"success"),": the action was successfully executed and you can obtain it's result with ",(0,i.mdx)("inlineCode",{parentName:"li"},"aio runtime activation result activationID")),(0,i.mdx)("li",{parentName:"ul"},(0,i.mdx)("inlineCode",{parentName:"li"},"developer error"),": the most likely reasons of this are compilation errors (missing variables, module not found) and action time-out (due to an internal issue within the action or time-out of a backend service the action connects to). You can get the activation details to see what exact error causing this by running the command ",(0,i.mdx)("inlineCode",{parentName:"li"},"aio runtime activation get activationID")),(0,i.mdx)("li",{parentName:"ul"},(0,i.mdx)("inlineCode",{parentName:"li"},"application error"),": this error is usually due to some issues at runtime, such as thrown exceptions, getting value of an ",(0,i.mdx)("inlineCode",{parentName:"li"},"undefined")," variable. With appropriate try-catch blocks and logging, you can see what goes wrong from the logs ",(0,i.mdx)("inlineCode",{parentName:"li"},"aio runtime activation logs activationID")),(0,i.mdx)("li",{parentName:"ul"},(0,i.mdx)("inlineCode",{parentName:"li"},"internal error"),": this could be an error caused by an external factor unrelated to the action itself, e.g. not enough resources to run the action. I/O Runtime is a scalable platform, so you would never see it with default action settings. If you do, please let us know by ",(0,i.mdx)("a",{parentName:"li",href:"mailto:iodev@adobe.com"},"email")," so that we can help to troubleshoot what causes it.")),(0,i.mdx)("p",null,"You could also try ",(0,i.mdx)("a",{parentName:"p",href:"https://github.com/apache/openwhisk-wskdebug"},"openwhisk-wskdebug")," which offers extensive capabilities to develop and debug the I/O Runtime actions of your App Builder applications."),(0,i.mdx)("h2",{id:"action-logs"},"Action logs"),(0,i.mdx)("p",null,"When you have ",(0,i.mdx)("a",{parentName:"p",href:"/app-builder/runtime/docs/guides/using/creating_actions/#invoking-web-actions"},"web actions")," in your app, they are blocking requests and their activation results are not recorded if they are invoked successfully. To enforce the persistence of activation results, you need to pass the ",(0,i.mdx)("inlineCode",{parentName:"p"},"x-ow-extra-logging: on"),' flag in the request headers. In the development mode of an SPA, you can add this flag directly to the "invoking action" function so that you will have the activation results and logs recorded for all requests. Then they could be retrieved as demonstrated in the ',(0,i.mdx)("a",{parentName:"p",href:"#general-debugging"},"General debugging")," section above."),(0,i.mdx)("pre",null,(0,i.mdx)("code",{parentName:"pre",className:"language-javascript"},"headers['x-ow-extra-logging'] = 'on'\n")),(0,i.mdx)("h2",{id:"action-authentication-errors"},"Action authentication errors"),(0,i.mdx)("p",null,"When Adobe authentication and authorization checks are enabled for an action with the ",(0,i.mdx)("inlineCode",{parentName:"p"},"require-adobe-auth")," annotation set to ",(0,i.mdx)("inlineCode",{parentName:"p"},"true"),", you may see the following errors when making requests to the action:"),(0,i.mdx)("ol",null,(0,i.mdx)("li",{parentName:"ol"},(0,i.mdx)("inlineCode",{parentName:"li"},"request is invalid, failed authorization. Please use a valid user token for this SPA.")),(0,i.mdx)("li",{parentName:"ol"},(0,i.mdx)("inlineCode",{parentName:"li"},"request is invalid, failed authorization. Please use a valid JWT or user access token for this headless application."))),(0,i.mdx)("p",null,"An SPA is an application with web UI components (located in the ",(0,i.mdx)("inlineCode",{parentName:"p"},"web-src/")," folder). Headless app are back-end microservices without web UI.\nFor authentication and authorization checks, the back-end actions of an SPA are validated against a valid user token which is passed directly from Adobe Experience Cloud (ExC) Shell. "),(0,i.mdx)("p",null,"On the other hand, the actions of a headless app can be validated against a valid user token from ExC Shell or a valid access token generated with the ",(0,i.mdx)("a",{parentName:"p",href:"/app-builder/authentication/auth-methods#!AdobeDocs/adobeio-auth/master/JWT/JWT.md"},"JWT (Service Account) Authentication"),". Please go through the ",(0,i.mdx)("a",{parentName:"p",href:"../guides/security/index.md"},"App Builder Security Overview")," for more details about SPA vs. headless app authentication. "),(0,i.mdx)("p",null,"If you are developing a headless app but accidentally have the ",(0,i.mdx)("inlineCode",{parentName:"p"},"web-src/")," folder added during the app initialization process, you could remove it by executing the command ",(0,i.mdx)("inlineCode",{parentName:"p"},"aio app delete web-assets")," at the root of your application source code folder. This will also assure that your actions are validated against the appropriate JWT auth."),(0,i.mdx)("h2",{id:"debugging-errors-with-state-and-files-sdk"},"Debugging errors with State and Files SDK"),(0,i.mdx)("p",null,"If your code uses App Builder ",(0,i.mdx)("a",{parentName:"p",href:"https://github.com/adobe/aio-lib-state"},"State")," or ",(0,i.mdx)("a",{parentName:"p",href:"https://github.com/adobe/aio-lib-files"},"Files")," SDKs, you cannot use ",(0,i.mdx)("a",{parentName:"p",href:"https://github.com/apache/openwhisk-wskdebug"},"wskdebug")," to debug it. The reason is that ",(0,i.mdx)("inlineCode",{parentName:"p"},"wskdebug")," forwards the debugged action from the I/O Runtime system to a local container on your machine and executes it there. This local container is not authorized to access the out-of-the-box cloud storage behind State and Files SDKs, as this would be the case with an action deployed to I/O Runtime."),(0,i.mdx)("p",null,(0,i.mdx)("em",{parentName:"p"},"Note: This is not a problem if you configure the State or Files SDKs to connect to your own cloud storage (e.g. Cosmos DB).")),(0,i.mdx)("h2",{id:"nodejs-with-mac-m1-chip"},"NodeJS with Mac M1 chip"),(0,i.mdx)("p",null,"There are no pre-compiled NodeJS binaries for versions prior to 15.x for Apple's new M1 chip (arm64 architecture).\nOne solution is to change the architecture of your shell from arm64 to x86."),(0,i.mdx)("p",null,"We recommend using the ",(0,i.mdx)("a",{parentName:"p",href:"https://github.com/nvm-sh/nvm"},"Node Version Manager (nvm)")," over ",(0,i.mdx)("a",{parentName:"p",href:"https://brew.sh/"},"Homebrew")," and follow their ",(0,i.mdx)("a",{parentName:"p",href:"https://github.com/nvm-sh/nvm#macos-troubleshooting"},"troubleshooting guides for macOS")," (section ",(0,i.mdx)("strong",{parentName:"p"},"Macs with M1 chip"),"). "))}m.isMDXComponent=!0}}]); +//# sourceMappingURL=component---src-pages-getting-started-common-troubleshooting-md-3259bccd023c4b55277f.js.map \ No newline at end of file diff --git a/component---src-pages-getting-started-common-troubleshooting-md-380a1fff950a126349b5.js.map b/component---src-pages-getting-started-common-troubleshooting-md-3259bccd023c4b55277f.js.map similarity index 53% rename from component---src-pages-getting-started-common-troubleshooting-md-380a1fff950a126349b5.js.map rename to component---src-pages-getting-started-common-troubleshooting-md-3259bccd023c4b55277f.js.map index f2c06c27d..bcc5f8f10 100644 --- a/component---src-pages-getting-started-common-troubleshooting-md-380a1fff950a126349b5.js.map +++ b/component---src-pages-getting-started-common-troubleshooting-md-3259bccd023c4b55277f.js.map @@ -1 +1 @@ -{"version":3,"file":"component---src-pages-getting-started-common-troubleshooting-md-380a1fff950a126349b5.js","mappings":"4SAQaA,EAAe,CAAC,EACvBC,EAAc,CAClBD,aAAAA,GAEIE,EAAYC,EAAAA,EACH,SAASC,EAAT,GAGZ,IAFDC,EAEC,EAFDA,WACGC,GACF,YACD,OAAO,SAACJ,GAAD,UAAeD,EAAiBK,EAAhC,CAAuCD,WAAYA,EAAYE,QAAQ,eAG5E,eACE,GAAM,0BADR,2BAGA,qIACA,eACE,GAAM,sBADR,uBAGA,oBACE,eAAIC,WAAW,MAAf,oJAAwK,cAAGA,WAAW,KAClL,KAAQ,YAD4J,QAAxK,MAGA,eAAIA,WAAW,MAAf,8GAEF,eACE,GAAM,qBADR,sBAGA,yJAA0I,cAAGA,WAAW,IACpJ,KAAQ,iDAD8H,eAA1I,uBAE+C,cAAGA,WAAW,IACzD,KAAQ,oCADmC,qCAF/C,wBAKA,uFACA,qBAAK,iBAAMA,WAAW,MAClB,UAAa,iBADZ,mCAIL,wLACA,oBACE,eAAIA,WAAW,OAAK,uBAAYA,WAAW,MAAvB,WAApB,+EAAuJ,uBAAYA,WAAW,MAAvB,gDACvJ,eAAIA,WAAW,OAAK,uBAAYA,WAAW,MAAvB,mBAApB,4TAA4Y,uBAAYA,WAAW,MAAvB,6CAC5Y,eAAIA,WAAW,OAAK,uBAAYA,WAAW,MAAvB,qBAApB,0GAA4L,uBAAYA,WAAW,MAAvB,aAA5L,wGAA0V,uBAAYA,WAAW,MAAvB,8CAC1V,eAAIA,WAAW,OAAK,uBAAYA,WAAW,MAAvB,kBAApB,oQAAmV,cAAGA,WAAW,KAC7V,KAAQ,0BADuU,SAAnV,0DAIF,yCAA0B,cAAGA,WAAW,IACpC,KAAQ,gDADc,sBAA1B,wHAGA,eACE,GAAM,eADR,gBAGA,oCAAqB,cAAGA,WAAW,IAC/B,KAAQ,uIADS,eAArB,oMAE4N,uBAAYA,WAAW,KAAvB,0BAF5N,2QAEyiB,cAAGA,WAAW,IACnjB,KAAQ,sBAD6hB,qBAFziB,oBAKA,qBAAK,iBAAMA,WAAW,MAClB,UAAa,uBADZ,4CAIL,eACE,GAAM,gCADR,iCAGA,4GAA6F,uBAAYA,WAAW,KAAvB,sBAA7F,uBAAkL,uBAAYA,WAAW,KAAvB,QAAlL,2EACA,oBACE,eAAIA,WAAW,OAAK,uBAAYA,WAAW,MAAvB,2FACpB,eAAIA,WAAW,OAAK,uBAAYA,WAAW,MAAvB,2HAEtB,sFAAuE,uBAAYA,WAAW,KAAvB,YAAvE,+PAEA,6KAA8J,cAAGA,WAAW,IACxK,KAAQ,sFADkJ,wCAA9J,4BAE6E,cAAGA,WAAW,IACvF,KAAQ,+BADiE,iCAF7E,kEAKA,qFAAsE,uBAAYA,WAAW,KAAvB,YAAtE,sGAAgO,uBAAYA,WAAW,KAAvB,6BAAhO,iJACA,eACE,GAAM,6CADR,8CAGA,oDAAqC,cAAGA,WAAW,IAC/C,KAAQ,0CADyB,SAArC,QAE0B,cAAGA,WAAW,IACpC,KAAQ,0CADc,SAF1B,0BAI4C,cAAGA,WAAW,IACtD,KAAQ,gDADgC,YAJ5C,qCAM0D,uBAAYA,WAAW,KAAvB,YAN1D,2SAOA,mBAAG,eAAIA,WAAW,KAAf,iIACH,eACE,GAAM,2BADR,4BAGA,sNAEA,6CAA8B,cAAGA,WAAW,IACxC,KAAQ,iCADkB,8BAA9B,UAEiD,cAAGA,WAAW,IAC3D,KAAQ,oBADqC,YAFjD,sBAI2C,cAAGA,WAAW,IACrD,KAAQ,uDAD+B,oCAJ3C,cAM2D,mBAAQA,WAAW,KAAnB,qBAN3D,OASH,CAEDJ,EAAWK,gBAAiB,C","sources":["webpack://adobe-developer-app-builder/./src/pages/getting_started/common_troubleshooting.md"],"sourcesContent":["import * as React from 'react'\n /* @jsx mdx */\nimport { mdx } from '@mdx-js/react';\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\n\nimport DefaultLayout from \"/home/runner/work/app-builder/app-builder/node_modules/@adobe/gatsby-theme-aio/src/components/MDXFilter/index.js\";\nexport const _frontmatter = {};\nconst layoutProps = {\n _frontmatter\n};\nconst MDXLayout = DefaultLayout;\nexport default function MDXContent({\n components,\n ...props\n}) {\n return \n\n\n

{`Common Troubleshooting`}

\n

{`Here are troubleshooting guides for some of the most common issues as you develop your first App Builder apps.`}

\n

{`Before you proceed`}

\n \n

{`General debugging`}

\n

{`When your action code doesn't work as expected, you may want to investigate into what exactly went wrong. App Builder provides the `}{`Logging SDK`}{`, please check out `}{`App Builder's Application Logging`}{` for more details. `}

\n

{`To see the latest activations of your project, run this command:`}

\n
{`aio runtime activation list\n`}
\n

{`It lists the most recent activations and summary (ID, start / end time, duration, status, and so on). There are 4 most popular statuses of a finished activation:`}

\n \n

{`You could also try `}{`openwhisk-wskdebug`}{` which offers extensive capabilities to develop and debug the I/O Runtime actions of your App Builder applications.`}

\n

{`Action logs`}

\n

{`When you have `}{`web actions`}{` in your app, they are blocking requests and their activation results are not recorded if they are invoked successfully. To enforce the persistence of activation results, you need to pass the `}{`x-ow-extra-logging: on`}{` flag in the request headers. In the development mode of an SPA, you can add this flag directly to the \"invoking action\" function so that you will have the activation results and logs recorded for all requests. Then they could be retrieved as demonstrated in the `}{`General debugging`}{` section above.`}

\n
{`headers['x-ow-extra-logging'] = 'on'\n`}
\n

{`Action authentication errors`}

\n

{`When Adobe authentication and authorization checks are enabled for an action with the `}{`require-adobe-auth`}{` annotation set to `}{`true`}{`, you may see the following errors when making requests to the action:`}

\n
    \n
  1. {`request is invalid, failed authorization. Please use a valid user token for this SPA.`}
  2. \n
  3. {`request is invalid, failed authorization. Please use a valid JWT or user access token for this headless application.`}
  4. \n
\n

{`An SPA is an application with web UI components (located in the `}{`web-src/`}{` folder). Headless app are back-end microservices without web UI.\nFor authentication and authorization checks, the back-end actions of an SPA are validated against a valid user token which is passed directly from Adobe Experience Cloud (ExC) Shell. `}

\n

{`On the other hand, the actions of a headless app can be validated against a valid user token from ExC Shell or a valid access token generated with the `}{`JWT (Service Account) Authentication`}{`. Please go through the `}{`App Builder Security Overview`}{` for more details about SPA vs. headless app authentication. `}

\n

{`If you are developing a headless app but accidentally have the `}{`web-src/`}{` folder added during the app initialization process, you could remove it by executing the command `}{`aio app delete web-assets`}{` at the root of your application source code folder. This will also assure that your actions are validated against the appropriate JWT auth.`}

\n

{`Debugging errors with State and Files SDK`}

\n

{`If your code uses App Builder `}{`State`}{` or `}{`Files`}{` SDKs, you cannot use `}{`wskdebug`}{` to debug it. The reason is that `}{`wskdebug`}{` forwards the debugged action from the I/O Runtime system to a local container on your machine and executes it there. This local container is not authorized to access the out-of-the-box cloud storage behind State and Files SDKs, as this would be the case with an action deployed to I/O Runtime.`}

\n

{`Note: This is not a problem if you configure the State or Files SDKs to connect to your own cloud storage (e.g. Cosmos DB).`}

\n

{`NodeJS with Mac M1 chip`}

\n

{`There are no pre-compiled NodeJS binaries for versions prior to 15.x for Apple's new M1 chip (arm64 architecture).\nOne solution is to change the architecture of your shell from arm64 to x86.`}

\n

{`We recommend using the `}{`Node Version Manager (nvm)`}{` over `}{`Homebrew`}{` and follow their `}{`troubleshooting guides for macOS`}{` (section `}{`Macs with M1 chip`}{`). `}

\n\n
;\n}\n;\nMDXContent.isMDXComponent = true;\n "],"names":["_frontmatter","layoutProps","MDXLayout","DefaultLayout","MDXContent","components","props","mdxType","parentName","isMDXComponent"],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"component---src-pages-getting-started-common-troubleshooting-md-3259bccd023c4b55277f.js","mappings":"4SAQaA,EAAe,CAAC,EACvBC,EAAc,CAClBD,aAAAA,GAEIE,EAAYC,EAAAA,EACH,SAASC,EAAT,GAGZ,IAFDC,EAEC,EAFDA,WACGC,GACF,YACD,OAAO,SAACJ,GAAD,UAAeD,EAAiBK,EAAhC,CAAuCD,WAAYA,EAAYE,QAAQ,eAG5E,eACE,GAAM,0BADR,2BAGA,qIACA,eACE,GAAM,sBADR,uBAGA,oBACE,eAAIC,WAAW,MAAf,oJAAwK,cAAGA,WAAW,KAClL,KAAQ,YAD4J,QAAxK,MAGA,eAAIA,WAAW,MAAf,8GAEF,eACE,GAAM,qBADR,sBAGA,yJAA0I,cAAGA,WAAW,IACpJ,KAAQ,iDAD8H,eAA1I,uBAE+C,cAAGA,WAAW,IACzD,KAAQ,oCADmC,qCAF/C,wBAKA,uFACA,qBAAK,iBAAMA,WAAW,MAClB,UAAa,iBADZ,mCAIL,wLACA,oBACE,eAAIA,WAAW,OAAK,uBAAYA,WAAW,MAAvB,WAApB,+EAAuJ,uBAAYA,WAAW,MAAvB,gDACvJ,eAAIA,WAAW,OAAK,uBAAYA,WAAW,MAAvB,mBAApB,4TAA4Y,uBAAYA,WAAW,MAAvB,6CAC5Y,eAAIA,WAAW,OAAK,uBAAYA,WAAW,MAAvB,qBAApB,0GAA4L,uBAAYA,WAAW,MAAvB,aAA5L,wGAA0V,uBAAYA,WAAW,MAAvB,8CAC1V,eAAIA,WAAW,OAAK,uBAAYA,WAAW,MAAvB,kBAApB,oQAAmV,cAAGA,WAAW,KAC7V,KAAQ,0BADuU,SAAnV,0DAIF,yCAA0B,cAAGA,WAAW,IACpC,KAAQ,gDADc,sBAA1B,wHAGA,eACE,GAAM,eADR,gBAGA,oCAAqB,cAAGA,WAAW,IAC/B,KAAQ,iFADS,eAArB,oMAE4N,uBAAYA,WAAW,KAAvB,0BAF5N,2QAEyiB,cAAGA,WAAW,IACnjB,KAAQ,sBAD6hB,qBAFziB,oBAKA,qBAAK,iBAAMA,WAAW,MAClB,UAAa,uBADZ,4CAIL,eACE,GAAM,gCADR,iCAGA,4GAA6F,uBAAYA,WAAW,KAAvB,sBAA7F,uBAAkL,uBAAYA,WAAW,KAAvB,QAAlL,2EACA,oBACE,eAAIA,WAAW,OAAK,uBAAYA,WAAW,MAAvB,2FACpB,eAAIA,WAAW,OAAK,uBAAYA,WAAW,MAAvB,2HAEtB,sFAAuE,uBAAYA,WAAW,KAAvB,YAAvE,+PAEA,6KAA8J,cAAGA,WAAW,IACxK,KAAQ,sFADkJ,wCAA9J,4BAE6E,cAAGA,WAAW,IACvF,KAAQ,+BADiE,iCAF7E,kEAKA,qFAAsE,uBAAYA,WAAW,KAAvB,YAAtE,sGAAgO,uBAAYA,WAAW,KAAvB,6BAAhO,iJACA,eACE,GAAM,6CADR,8CAGA,oDAAqC,cAAGA,WAAW,IAC/C,KAAQ,0CADyB,SAArC,QAE0B,cAAGA,WAAW,IACpC,KAAQ,0CADc,SAF1B,0BAI4C,cAAGA,WAAW,IACtD,KAAQ,gDADgC,YAJ5C,qCAM0D,uBAAYA,WAAW,KAAvB,YAN1D,2SAOA,mBAAG,eAAIA,WAAW,KAAf,iIACH,eACE,GAAM,2BADR,4BAGA,sNAEA,6CAA8B,cAAGA,WAAW,IACxC,KAAQ,iCADkB,8BAA9B,UAEiD,cAAGA,WAAW,IAC3D,KAAQ,oBADqC,YAFjD,sBAI2C,cAAGA,WAAW,IACrD,KAAQ,uDAD+B,oCAJ3C,cAM2D,mBAAQA,WAAW,KAAnB,qBAN3D,OASH,CAEDJ,EAAWK,gBAAiB,C","sources":["webpack://adobe-developer-app-builder/./src/pages/getting_started/common_troubleshooting.md"],"sourcesContent":["import * as React from 'react'\n /* @jsx mdx */\nimport { mdx } from '@mdx-js/react';\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\n\nimport DefaultLayout from \"/home/runner/work/app-builder/app-builder/node_modules/@adobe/gatsby-theme-aio/src/components/MDXFilter/index.js\";\nexport const _frontmatter = {};\nconst layoutProps = {\n _frontmatter\n};\nconst MDXLayout = DefaultLayout;\nexport default function MDXContent({\n components,\n ...props\n}) {\n return \n\n\n

{`Common Troubleshooting`}

\n

{`Here are troubleshooting guides for some of the most common issues as you develop your first App Builder apps.`}

\n

{`Before you proceed`}

\n \n

{`General debugging`}

\n

{`When your action code doesn't work as expected, you may want to investigate into what exactly went wrong. App Builder provides the `}{`Logging SDK`}{`, please check out `}{`App Builder's Application Logging`}{` for more details. `}

\n

{`To see the latest activations of your project, run this command:`}

\n
{`aio runtime activation list\n`}
\n

{`It lists the most recent activations and summary (ID, start / end time, duration, status, and so on). There are 4 most popular statuses of a finished activation:`}

\n \n

{`You could also try `}{`openwhisk-wskdebug`}{` which offers extensive capabilities to develop and debug the I/O Runtime actions of your App Builder applications.`}

\n

{`Action logs`}

\n

{`When you have `}{`web actions`}{` in your app, they are blocking requests and their activation results are not recorded if they are invoked successfully. To enforce the persistence of activation results, you need to pass the `}{`x-ow-extra-logging: on`}{` flag in the request headers. In the development mode of an SPA, you can add this flag directly to the \"invoking action\" function so that you will have the activation results and logs recorded for all requests. Then they could be retrieved as demonstrated in the `}{`General debugging`}{` section above.`}

\n
{`headers['x-ow-extra-logging'] = 'on'\n`}
\n

{`Action authentication errors`}

\n

{`When Adobe authentication and authorization checks are enabled for an action with the `}{`require-adobe-auth`}{` annotation set to `}{`true`}{`, you may see the following errors when making requests to the action:`}

\n
    \n
  1. {`request is invalid, failed authorization. Please use a valid user token for this SPA.`}
  2. \n
  3. {`request is invalid, failed authorization. Please use a valid JWT or user access token for this headless application.`}
  4. \n
\n

{`An SPA is an application with web UI components (located in the `}{`web-src/`}{` folder). Headless app are back-end microservices without web UI.\nFor authentication and authorization checks, the back-end actions of an SPA are validated against a valid user token which is passed directly from Adobe Experience Cloud (ExC) Shell. `}

\n

{`On the other hand, the actions of a headless app can be validated against a valid user token from ExC Shell or a valid access token generated with the `}{`JWT (Service Account) Authentication`}{`. Please go through the `}{`App Builder Security Overview`}{` for more details about SPA vs. headless app authentication. `}

\n

{`If you are developing a headless app but accidentally have the `}{`web-src/`}{` folder added during the app initialization process, you could remove it by executing the command `}{`aio app delete web-assets`}{` at the root of your application source code folder. This will also assure that your actions are validated against the appropriate JWT auth.`}

\n

{`Debugging errors with State and Files SDK`}

\n

{`If your code uses App Builder `}{`State`}{` or `}{`Files`}{` SDKs, you cannot use `}{`wskdebug`}{` to debug it. The reason is that `}{`wskdebug`}{` forwards the debugged action from the I/O Runtime system to a local container on your machine and executes it there. This local container is not authorized to access the out-of-the-box cloud storage behind State and Files SDKs, as this would be the case with an action deployed to I/O Runtime.`}

\n

{`Note: This is not a problem if you configure the State or Files SDKs to connect to your own cloud storage (e.g. Cosmos DB).`}

\n

{`NodeJS with Mac M1 chip`}

\n

{`There are no pre-compiled NodeJS binaries for versions prior to 15.x for Apple's new M1 chip (arm64 architecture).\nOne solution is to change the architecture of your shell from arm64 to x86.`}

\n

{`We recommend using the `}{`Node Version Manager (nvm)`}{` over `}{`Homebrew`}{` and follow their `}{`troubleshooting guides for macOS`}{` (section `}{`Macs with M1 chip`}{`). `}

\n\n
;\n}\n;\nMDXContent.isMDXComponent = true;\n "],"names":["_frontmatter","layoutProps","MDXLayout","DefaultLayout","MDXContent","components","props","mdxType","parentName","isMDXComponent"],"sourceRoot":""} \ No newline at end of file diff --git a/component---src-pages-getting-started-common-troubleshooting-md-380a1fff950a126349b5.js b/component---src-pages-getting-started-common-troubleshooting-md-380a1fff950a126349b5.js deleted file mode 100644 index 9f629d560..000000000 --- a/component---src-pages-getting-started-common-troubleshooting-md-380a1fff950a126349b5.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict";(self.webpackChunkadobe_developer_app_builder=self.webpackChunkadobe_developer_app_builder||[]).push([[9439],{35013:function(e,t,a){a.r(t),a.d(t,{_frontmatter:function(){return d},default:function(){return m}});var o=a(87462),i=a(63366),n=(a(15007),a(64983)),r=a(91515),s=["components"],d={},l={_frontmatter:d},u=r.Z;function m(e){var t=e.components,a=(0,i.Z)(e,s);return(0,n.mdx)(u,(0,o.Z)({},l,a,{components:t,mdxType:"MDXLayout"}),(0,n.mdx)("h1",{id:"common-troubleshooting"},"Common Troubleshooting"),(0,n.mdx)("p",null,"Here are troubleshooting guides for some of the most common issues as you develop your first App Builder apps."),(0,n.mdx)("h2",{id:"before-you-proceed"},"Before you proceed"),(0,n.mdx)("ul",null,(0,n.mdx)("li",{parentName:"ul"},"Check your Node version and tool versions to ensure they are supported by App Builder and up-to-date. You can find the latest supported version ",(0,n.mdx)("a",{parentName:"li",href:"index.md"},"here"),"."),(0,n.mdx)("li",{parentName:"ul"},"Check if your application is on Dropbox or OneDrive as file watchers sometimes cause unexpected errors. ")),(0,n.mdx)("h2",{id:"general-debugging"},"General debugging"),(0,n.mdx)("p",null,"When your action code doesn't work as expected, you may want to investigate into what exactly went wrong. App Builder provides the ",(0,n.mdx)("a",{parentName:"p",href:"https://github.com/adobe/aio-lib-core-logging"},"Logging SDK"),", please check out ",(0,n.mdx)("a",{parentName:"p",href:"../guides/application_logging.md"},"App Builder's Application Logging")," for more details. "),(0,n.mdx)("p",null,"To see the latest activations of your project, run this command:"),(0,n.mdx)("pre",null,(0,n.mdx)("code",{parentName:"pre",className:"language-bash"},"aio runtime activation list\n")),(0,n.mdx)("p",null,"It lists the most recent activations and summary (ID, start / end time, duration, status, and so on). There are 4 most popular statuses of a finished activation:"),(0,n.mdx)("ul",null,(0,n.mdx)("li",{parentName:"ul"},(0,n.mdx)("inlineCode",{parentName:"li"},"success"),": the action was successfully executed and you can obtain it's result with ",(0,n.mdx)("inlineCode",{parentName:"li"},"aio runtime activation result activationID")),(0,n.mdx)("li",{parentName:"ul"},(0,n.mdx)("inlineCode",{parentName:"li"},"developer error"),": the most likely reasons of this are compilation errors (missing variables, module not found) and action time-out (due to an internal issue within the action or time-out of a backend service the action connects to). You can get the activation details to see what exact error causing this by running the command ",(0,n.mdx)("inlineCode",{parentName:"li"},"aio runtime activation get activationID")),(0,n.mdx)("li",{parentName:"ul"},(0,n.mdx)("inlineCode",{parentName:"li"},"application error"),": this error is usually due to some issues at runtime, such as thrown exceptions, getting value of an ",(0,n.mdx)("inlineCode",{parentName:"li"},"undefined")," variable. With appropriate try-catch blocks and logging, you can see what goes wrong from the logs ",(0,n.mdx)("inlineCode",{parentName:"li"},"aio runtime activation logs activationID")),(0,n.mdx)("li",{parentName:"ul"},(0,n.mdx)("inlineCode",{parentName:"li"},"internal error"),": this could be an error caused by an external factor unrelated to the action itself, e.g. not enough resources to run the action. I/O Runtime is a scalable platform, so you would never see it with default action settings. If you do, please let us know by ",(0,n.mdx)("a",{parentName:"li",href:"mailto:iodev@adobe.com"},"email")," so that we can help to troubleshoot what causes it.")),(0,n.mdx)("p",null,"You could also try ",(0,n.mdx)("a",{parentName:"p",href:"https://github.com/apache/openwhisk-wskdebug"},"openwhisk-wskdebug")," which offers extensive capabilities to develop and debug the I/O Runtime actions of your App Builder applications."),(0,n.mdx)("h2",{id:"action-logs"},"Action logs"),(0,n.mdx)("p",null,"When you have ",(0,n.mdx)("a",{parentName:"p",href:"/app-builder/apis/experienceplatform/runtime/docs#!adobedocs/adobeio-runtime/master/guides/creating_actions.md#invoking-web-actions"},"web actions")," in your app, they are blocking requests and their activation results are not recorded if they are invoked successfully. To enforce the persistence of activation results, you need to pass the ",(0,n.mdx)("inlineCode",{parentName:"p"},"x-ow-extra-logging: on"),' flag in the request headers. In the development mode of an SPA, you can add this flag directly to the "invoking action" function so that you will have the activation results and logs recorded for all requests. Then they could be retrieved as demonstrated in the ',(0,n.mdx)("a",{parentName:"p",href:"#general-debugging"},"General debugging")," section above."),(0,n.mdx)("pre",null,(0,n.mdx)("code",{parentName:"pre",className:"language-javascript"},"headers['x-ow-extra-logging'] = 'on'\n")),(0,n.mdx)("h2",{id:"action-authentication-errors"},"Action authentication errors"),(0,n.mdx)("p",null,"When Adobe authentication and authorization checks are enabled for an action with the ",(0,n.mdx)("inlineCode",{parentName:"p"},"require-adobe-auth")," annotation set to ",(0,n.mdx)("inlineCode",{parentName:"p"},"true"),", you may see the following errors when making requests to the action:"),(0,n.mdx)("ol",null,(0,n.mdx)("li",{parentName:"ol"},(0,n.mdx)("inlineCode",{parentName:"li"},"request is invalid, failed authorization. Please use a valid user token for this SPA.")),(0,n.mdx)("li",{parentName:"ol"},(0,n.mdx)("inlineCode",{parentName:"li"},"request is invalid, failed authorization. Please use a valid JWT or user access token for this headless application."))),(0,n.mdx)("p",null,"An SPA is an application with web UI components (located in the ",(0,n.mdx)("inlineCode",{parentName:"p"},"web-src/")," folder). Headless app are back-end microservices without web UI.\nFor authentication and authorization checks, the back-end actions of an SPA are validated against a valid user token which is passed directly from Adobe Experience Cloud (ExC) Shell. "),(0,n.mdx)("p",null,"On the other hand, the actions of a headless app can be validated against a valid user token from ExC Shell or a valid access token generated with the ",(0,n.mdx)("a",{parentName:"p",href:"/app-builder/authentication/auth-methods#!AdobeDocs/adobeio-auth/master/JWT/JWT.md"},"JWT (Service Account) Authentication"),". Please go through the ",(0,n.mdx)("a",{parentName:"p",href:"../guides/security/index.md"},"App Builder Security Overview")," for more details about SPA vs. headless app authentication. "),(0,n.mdx)("p",null,"If you are developing a headless app but accidentally have the ",(0,n.mdx)("inlineCode",{parentName:"p"},"web-src/")," folder added during the app initialization process, you could remove it by executing the command ",(0,n.mdx)("inlineCode",{parentName:"p"},"aio app delete web-assets")," at the root of your application source code folder. This will also assure that your actions are validated against the appropriate JWT auth."),(0,n.mdx)("h2",{id:"debugging-errors-with-state-and-files-sdk"},"Debugging errors with State and Files SDK"),(0,n.mdx)("p",null,"If your code uses App Builder ",(0,n.mdx)("a",{parentName:"p",href:"https://github.com/adobe/aio-lib-state"},"State")," or ",(0,n.mdx)("a",{parentName:"p",href:"https://github.com/adobe/aio-lib-files"},"Files")," SDKs, you cannot use ",(0,n.mdx)("a",{parentName:"p",href:"https://github.com/apache/openwhisk-wskdebug"},"wskdebug")," to debug it. The reason is that ",(0,n.mdx)("inlineCode",{parentName:"p"},"wskdebug")," forwards the debugged action from the I/O Runtime system to a local container on your machine and executes it there. This local container is not authorized to access the out-of-the-box cloud storage behind State and Files SDKs, as this would be the case with an action deployed to I/O Runtime."),(0,n.mdx)("p",null,(0,n.mdx)("em",{parentName:"p"},"Note: This is not a problem if you configure the State or Files SDKs to connect to your own cloud storage (e.g. Cosmos DB).")),(0,n.mdx)("h2",{id:"nodejs-with-mac-m1-chip"},"NodeJS with Mac M1 chip"),(0,n.mdx)("p",null,"There are no pre-compiled NodeJS binaries for versions prior to 15.x for Apple's new M1 chip (arm64 architecture).\nOne solution is to change the architecture of your shell from arm64 to x86."),(0,n.mdx)("p",null,"We recommend using the ",(0,n.mdx)("a",{parentName:"p",href:"https://github.com/nvm-sh/nvm"},"Node Version Manager (nvm)")," over ",(0,n.mdx)("a",{parentName:"p",href:"https://brew.sh/"},"Homebrew")," and follow their ",(0,n.mdx)("a",{parentName:"p",href:"https://github.com/nvm-sh/nvm#macos-troubleshooting"},"troubleshooting guides for macOS")," (section ",(0,n.mdx)("strong",{parentName:"p"},"Macs with M1 chip"),"). "))}m.isMDXComponent=!0}}]); -//# sourceMappingURL=component---src-pages-getting-started-common-troubleshooting-md-380a1fff950a126349b5.js.map \ No newline at end of file diff --git a/component---src-pages-guides-configuration-index-md-7bc95ef25b3ec2459e8f.js b/component---src-pages-guides-configuration-index-md-59201e843287f51ead6a.js similarity index 80% rename from component---src-pages-guides-configuration-index-md-7bc95ef25b3ec2459e8f.js rename to component---src-pages-guides-configuration-index-md-59201e843287f51ead6a.js index fb977c900..c58d13a00 100644 --- a/component---src-pages-guides-configuration-index-md-7bc95ef25b3ec2459e8f.js +++ b/component---src-pages-guides-configuration-index-md-59201e843287f51ead6a.js @@ -1,2 +1,2 @@ -"use strict";(self.webpackChunkadobe_developer_app_builder=self.webpackChunkadobe_developer_app_builder||[]).push([[6208],{52268:function(e,n,t){t.r(n),t.d(n,{_frontmatter:function(){return d},default:function(){return p}});var a=t(87462),i=t(63366),o=(t(15007),t(64983)),l=t(91515),m=["components"],d={},s={_frontmatter:d},r=l.Z;function p(e){var n=e.components,t=(0,i.Z)(e,m);return(0,o.mdx)(r,(0,a.Z)({},s,t,{components:n,mdxType:"MDXLayout"}),(0,o.mdx)("h1",{id:"app-builder-configuration-files"},"App Builder Configuration Files"),(0,o.mdx)("h2",{id:"overview"},"Overview"),(0,o.mdx)("p",null,"An app has three configuration files, ",(0,o.mdx)("strong",{parentName:"p"},"defined in the root of the project folder"),":"),(0,o.mdx)("ul",null,(0,o.mdx)("li",{parentName:"ul"},(0,o.mdx)("inlineCode",{parentName:"li"},"app.config.yaml")," is the main configuration file, defining the application's behavior and implementation."),(0,o.mdx)("li",{parentName:"ul"},(0,o.mdx)("inlineCode",{parentName:"li"},".env")," is used to store secrets and environment variables available during build time."),(0,o.mdx)("li",{parentName:"ul"},(0,o.mdx)("inlineCode",{parentName:"li"},".aio")," is populated by the ",(0,o.mdx)("inlineCode",{parentName:"li"},"aio")," CLI to store the current Developer Console Workspace details.")),(0,o.mdx)("p",null,"Note: ",(0,o.mdx)("inlineCode",{parentName:"p"},".env")," and ",(0,o.mdx)("inlineCode",{parentName:"p"},".aio")," files ",(0,o.mdx)("strong",{parentName:"p"},"should not be committed to version control"),"."),(0,o.mdx)("h2",{id:"appconfigyaml"},(0,o.mdx)("inlineCode",{parentName:"h2"},"app.config.yaml")),(0,o.mdx)("h3",{id:"tldr-give-me-a-full-example"},"Tl;dr: give me a full example:"),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre",className:"language-yaml"},"# standalone application config\napplication:\n hostname: 'customhost'\n runtimeManifest:\n packages:\n application-pkg:\n actions:\n count-apples:\n function: actions/count-apples/index.js\n web: 'yes'\n runtime: nodejs:18\n annotations:\n require-adobe-auth: true\n hooks:\n post-app-build: 'echo hook'\n\n# extension points config\nextensions:\n dx/excshell/1:\n # $include directive stores config in a separate file\n $include: ./dx-excshell-1/ext.config.yaml\n dx/asset-compute/worker/1:\n operations:\n workerProcess:\n - type: action\n impl: dx-asset-compute-worker-1/myworker\n runtimeManifest:\n packages:\n dx-asset-compute-worker-1:\n actions:\n myworker:\n function: actions/worker/index.js\n web: 'yes'\n runtime: nodejs:18\n")),(0,o.mdx)("h3",{id:"standalone-application-and-extensions"},"Standalone application and extensions"),(0,o.mdx)("p",null,"The ",(0,o.mdx)("inlineCode",{parentName:"p"},"app.config.yaml")," file can contain two top level fields: ",(0,o.mdx)("inlineCode",{parentName:"p"},"application")," and ",(0,o.mdx)("inlineCode",{parentName:"p"},"extensions"),".\nOnly one is required."),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre",className:"language-yaml"},"# app.config.yaml\n\napplication:\n \nextensions:\n :\n \n \n")),(0,o.mdx)("p",null,"A project can implement a standalone application and N extensions."),(0,o.mdx)("h3",{id:"common-configuration"},"Common configuration"),(0,o.mdx)("p",null,"Extensions and the standalone application behave in a similar way.\nBoth can contain a UI and actions and both support a common configuration.\nThe common configuration contains following fields:"),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre",className:"language-yaml"},"# \n\nruntimeManifest:\n \nhooks:\n \nactions: \nweb: \nunitTest: \ne2eTest: \ndist: \nhtmlCacheDuration: \njsCacheDuration: \ncssCacheDuration: \nimageCacheDuration: \ntvmurl: \nawsaccesskeyid: \nawssecretaccesskey: \ns3bucket: \nhostname: \n")),(0,o.mdx)("h4",{id:"runtime-manifest"},"Runtime Manifest"),(0,o.mdx)("p",null,"The ",(0,o.mdx)("inlineCode",{parentName:"p"},"runtimeManifest")," field holds the backend configuration deployed into Adobe I/O Runtime.\nThe full spec can be found ",(0,o.mdx)("a",{parentName:"p",href:"https://github.com/apache/openwhisk-wskdeploy/tree/master/specification/html"},"here"),". Acceptable values for the ",(0,o.mdx)("inlineCode",{parentName:"p"},"limits")," fields below can be found on the ",(0,o.mdx)("a",{parentName:"p",href:"https://developer.adobe.com/runtime/docs/guides/using/system_settings/"},"Runtime System Settings")," page.\nHere is an example to get started:"),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre",className:"language-yaml"},"runtimeManifest\n packages:\n myapp:\n license: Apache-2.0\n actions:\n generic:\n # path relative to the configuration file\n function: src/myapp/actions/generic/index.js\n web: 'yes'\n runtime: nodejs:18\n annotations:\n require-adobe-auth: true\n target:\n function: src/myapp/actions/target/index.js\n web: 'yes'\n runtime: nodejs:18\n limits:\n timeout: 60000\n memory: 512\n concurrency: 1\n logs: 10\n include:\n - [\"myfilestoinclude/*.txt\", \"text/\"] \n")),(0,o.mdx)("blockquote",null,(0,o.mdx)("p",{parentName:"blockquote"},"Note that the above example also demonstrates the 'include' field of an action. In some cases you may want to have a file deployed with your action code, and available to your code when it runs.\nThe example will copy all .txt files from the ",(0,o.mdx)("inlineCode",{parentName:"p"},"myfilestoinclude/")," directory and place it in a new dir ",(0,o.mdx)("inlineCode",{parentName:"p"},"text/")," that is available via ",(0,o.mdx)("inlineCode",{parentName:"p"},"fs.readFile('text/somefile.txt', 'utf8', callback);")," when your action is invoked.")),(0,o.mdx)("blockquote",null,(0,o.mdx)("p",{parentName:"blockquote"},"Note the above sets limit values. Limits are defined as:"),(0,o.mdx)("ul",{parentName:"blockquote"},(0,o.mdx)("li",{parentName:"ul"},(0,o.mdx)("inlineCode",{parentName:"li"},"concurrency"),": the maximum number of action invocations to send to the same container in parallel (default 200, min: 1,max: 500)"),(0,o.mdx)("li",{parentName:"ul"},(0,o.mdx)("inlineCode",{parentName:"li"},"logs"),": the maximum log size LIMIT in MB for the action (default 10, min: 0, max: 10)"),(0,o.mdx)("li",{parentName:"ul"},(0,o.mdx)("inlineCode",{parentName:"li"},"timeout"),": the timeout LIMIT in milliseconds after which the action is terminated (default 60000, min: 100, max: 3600000)",(0,o.mdx)("ul",{parentName:"li"},(0,o.mdx)("li",{parentName:"ul"},(0,o.mdx)("em",{parentName:"li"},"for web actions served from cdn there is a hard limit of 30 seconds for timeout")))),(0,o.mdx)("li",{parentName:"ul"},(0,o.mdx)("inlineCode",{parentName:"li"},"memory"),": the maximum memory LIMIT in MB for the action (default 256, min: 128, max: 4096)",(0,o.mdx)("ul",{parentName:"li"},(0,o.mdx)("li",{parentName:"ul"},(0,o.mdx)("em",{parentName:"li"},"setting distinct values (ex. 671) can impact cold starts as Runtime keeps a number of pre-warmed containers, but only for common memory sizes (128, 256, 512, 1024, etc.)"))))),(0,o.mdx)("p",{parentName:"blockquote"},"More info on ",(0,o.mdx)("inlineCode",{parentName:"p"},"limits")," can be found on the ",(0,o.mdx)("a",{parentName:"p",href:"https://developer.adobe.com/runtime/docs/guides/using/system_settings/"},"Runtime System Settings")," page.")),(0,o.mdx)("h5",{id:"annotations"},"Annotations"),(0,o.mdx)("p",null,"Runtime actions can be decorated with annotations to enhance or modify action behavior. "),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre",className:"language-yaml"},"runtimeManifest:\n packages:\n myapp:\n license: Apache-2.0\n actions:\n generic:\n annotations:\n require-adobe-auth: true\n disable-download: true \n")),(0,o.mdx)("p",null,"In addition to the base annotations provided by Runtime (See ",(0,o.mdx)("a",{parentName:"p",href:"https://github.com/adobe-apiplatform/incubator-openwhisk/blob/master/docs/annotations.md"},"here"),"), there are a few special annotations: "),(0,o.mdx)("ul",null,(0,o.mdx)("li",{parentName:"ul"},(0,o.mdx)("strong",{parentName:"li"},"disable-download")," (Default: false) - Determines whether action code can be downloaded. Once this annotation is set to true, it cannot be set back to false. "),(0,o.mdx)("li",{parentName:"ul"},(0,o.mdx)("strong",{parentName:"li"},"require-adobe-auth")," (Default: false) - Determines whether the action will require Adobe authentication to invoke. See ",(0,o.mdx)("a",{parentName:"li",href:"https://developer.adobe.com/app-builder/docs/guides/security/#authentication-and-authorization-handling"},"here")," for more.")),(0,o.mdx)("h5",{id:"api-gateway-configuration"},"API Gateway Configuration"),(0,o.mdx)("p",null,"A Runtime API Gateway configuration can be added to expose web actions over specific paths and HTTP verbs. "),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre",className:"language-yaml"},"runtimeManifest:\n packages:\n petsapp:\n license: Apache-2.0\n actions:\n get-pets: # Note the name of the action\n function: actions/get-pets/index.js\n web: 'yes'\n runtime: nodejs:18\n get-pet: # Note the name of the action\n function: actions/get-pet/index.js\n web: 'yes'\n runtime: nodejs:18\n apis: \n get-pets: # API Name\n v1: # Base Path\n pets: # Relative Path\n get-pets: # Name of the action to connect this path to\n method: get\n response: http\n get-pet: # API Name\n v1: # Base Path\n pets/{petName}: # Relative Path, with a path parameter\n get-pet: # Name of the action to connect this path to\n method: get\n response: http\n")),(0,o.mdx)("blockquote",null,(0,o.mdx)("p",{parentName:"blockquote"},"Note: The configuration above will result in the following: "),(0,o.mdx)("ul",{parentName:"blockquote"},(0,o.mdx)("li",{parentName:"ul"},(0,o.mdx)("inlineCode",{parentName:"li"},"GET https://adobeioruntime.net/apis/[namespace]/v1/pets")),(0,o.mdx)("li",{parentName:"ul"},(0,o.mdx)("inlineCode",{parentName:"li"},"GET https://adobeioruntime.net/apis/[namespace]/v1/pets/{petName}")))),(0,o.mdx)("blockquote",null,(0,o.mdx)("p",{parentName:"blockquote"},"Note: The second API above defines a path parameter in the relative path by using curly braces, i.e ",(0,o.mdx)("inlineCode",{parentName:"p"},"pets/{petName}")),(0,o.mdx)("ul",{parentName:"blockquote"},(0,o.mdx)("li",{parentName:"ul"},"APIs using path parameters must use the ",(0,o.mdx)("inlineCode",{parentName:"li"},"http")," response type"))),(0,o.mdx)("ul",null,(0,o.mdx)("li",{parentName:"ul"},"The following options are available for ",(0,o.mdx)("inlineCode",{parentName:"li"},"method"),": get, post, put, delete, patch"),(0,o.mdx)("li",{parentName:"ul"},"The following options are available for ",(0,o.mdx)("inlineCode",{parentName:"li"},"response"),": http (default), json, text, or html")),(0,o.mdx)("p",null,"Learn more about API Gateway Configuration with the ",(0,o.mdx)("a",{parentName:"p",href:"https://github.com/adobe/appbuilder-quickstarts/tree/master/action-apis"},"Action APIs QuickStart")),(0,o.mdx)("h4",{id:"hooks-to-customize-the-tooling"},"Hooks to customize the tooling"),(0,o.mdx)("p",null,"Hooks can be used to customize ",(0,o.mdx)("inlineCode",{parentName:"p"},"aio app")," commands. Hooks are documented ",(0,o.mdx)("a",{parentName:"p",href:"https://github.com/AdobeDocs/project-firefly/blob/main/src/pages/guides/app-hooks.md"},"here"),"."),(0,o.mdx)("h3",{id:"extension-specific-configuration"},"Extension specific configuration"),(0,o.mdx)("h4",{id:"extension-types"},"Extension types"),(0,o.mdx)("p",null,"The ",(0,o.mdx)("inlineCode",{parentName:"p"},"")," indicates which product the extension is extending, currently we support the following product extensions:"),(0,o.mdx)("ol",null,(0,o.mdx)("li",{parentName:"ol"},(0,o.mdx)("inlineCode",{parentName:"li"},"dx/excshell/1")," to implement an Experience Cloud Shell single page application."),(0,o.mdx)("li",{parentName:"ol"},(0,o.mdx)("inlineCode",{parentName:"li"},"dx/asset-compute/worker/1")," to implement an AEM Asset Compute worker.")),(0,o.mdx)("h4",{id:"dxexcshell1-definition"},(0,o.mdx)("inlineCode",{parentName:"h4"},"dx/excshell/1")," definition"),(0,o.mdx)("p",null,"The Experience Cloud Shell extension supports a ",(0,o.mdx)("inlineCode",{parentName:"p"},"view")," operation that points to the entry html file of the SPA.\nIn the following example the ",(0,o.mdx)("inlineCode",{parentName:"p"},"impl")," field points to an ",(0,o.mdx)("inlineCode",{parentName:"p"},"index.html")," file stored in the ",(0,o.mdx)("inlineCode",{parentName:"p"},"web/")," folder of the extension."),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre",className:"language-yaml"},"extensions\n dx/excshell/1:\n operations:\n view:\n - type: web\n impl: index.html\n web-src: web/\n")),(0,o.mdx)("h4",{id:"dxasset-computeworker1-definition"},(0,o.mdx)("inlineCode",{parentName:"h4"},"dx/asset-compute/worker/1")," definition"),(0,o.mdx)("p",null,"The AEM Asset Compute worker extension supports a ",(0,o.mdx)("inlineCode",{parentName:"p"},"workerProcess")," operation that points to the backend Adobe I/O Runtime action implementing the worker logic.\nIn the following example the ",(0,o.mdx)("inlineCode",{parentName:"p"},"impl")," field points to the ",(0,o.mdx)("inlineCode",{parentName:"p"},"dx-asset-compute-worker-1/worker")," action defined in the ",(0,o.mdx)("inlineCode",{parentName:"p"},"runtimeManifest"),"."),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre",className:"language-yaml"},"extensions\n dx/asset-compute/worker/1:\n operations:\n workerProcess:\n - type: action\n impl: dx-asset-compute-worker-1/myworker\n runtimeManifest:\n packages:\n dx-asset-compute-worker-1:\n actions:\n myworker:\n function: actions/worker/index.js\n web: 'yes'\n runtime: nodejs:18\n")),(0,o.mdx)("h3",{id:"the-include-directive"},"The ",(0,o.mdx)("inlineCode",{parentName:"h3"},"$include")," directive"),(0,o.mdx)("p",null,"The ",(0,o.mdx)("inlineCode",{parentName:"p"},"$include")," directive allows to defer any part of the ",(0,o.mdx)("inlineCode",{parentName:"p"},"app.config.yaml")," to another file.\nIn the following example, the ",(0,o.mdx)("inlineCode",{parentName:"p"},"dx/excshell/1")," configuration is stored in another ",(0,o.mdx)("inlineCode",{parentName:"p"},"./src/dx-excshell-1/ext.config.yaml")," file."),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre",className:"language-yaml"},"extensions:\n dx/excshell/1:\n $include: ./src/dx-excshell-1/ext.config.yaml\n")),(0,o.mdx)("p",null,"Configuration paths defined in ",(0,o.mdx)("inlineCode",{parentName:"p"},"./src/dx-excshell-1/ext.config.yaml")," must be relative to that file."),(0,o.mdx)("h2",{id:"env"},(0,o.mdx)("inlineCode",{parentName:"h2"},".env")),(0,o.mdx)("p",null,"The ",(0,o.mdx)("inlineCode",{parentName:"p"},".env")," file is used to store:"),(0,o.mdx)("ol",null,(0,o.mdx)("li",{parentName:"ol"},"secrets to be injected into I/O Runtime Actions."),(0,o.mdx)("li",{parentName:"ol"},"environment variables available to ",(0,o.mdx)("inlineCode",{parentName:"li"},"hooks"),"."),(0,o.mdx)("li",{parentName:"ol"},"auto generated secrets used by the ",(0,o.mdx)("inlineCode",{parentName:"li"},"aio")," CLI, prefixed by ",(0,o.mdx)("inlineCode",{parentName:"li"},"AIO_"),", those should not be edited.")),(0,o.mdx)("h2",{id:"aio"},(0,o.mdx)("inlineCode",{parentName:"h2"},".aio")),(0,o.mdx)("p",null,"The ",(0,o.mdx)("inlineCode",{parentName:"p"},".aio")," file is auto generated and contains Developer Console specific configuration.\nThis file is updated via the ",(0,o.mdx)("inlineCode",{parentName:"p"},"aio app use")," command and should not be edited manually."),(0,o.mdx)("h2",{id:"legacy-configuration-system"},"Legacy configuration system"),(0,o.mdx)("p",null,"Apps initialized using a ",(0,o.mdx)("inlineCode",{parentName:"p"},"@adobe/aio-cli")," CLI version prior to 8.x use a legacy configuration system that we still support in newer CLI versions.\nThose apps do not support extensions, and only get deployed as standalone applications."),(0,o.mdx)("p",null,"The legacy configuration system does not have an ",(0,o.mdx)("inlineCode",{parentName:"p"},"app.config.yaml")," and instead uses:"),(0,o.mdx)("ol",null,(0,o.mdx)("li",{parentName:"ol"},(0,o.mdx)("inlineCode",{parentName:"li"},".aio")," to store common configuration bits, but hooks and Runtime Manifest, such as ",(0,o.mdx)("inlineCode",{parentName:"li"},"actions")," path."),(0,o.mdx)("li",{parentName:"ol"},(0,o.mdx)("inlineCode",{parentName:"li"},"manifest.yaml")," to stores the Runtime Manifest."),(0,o.mdx)("li",{parentName:"ol"},(0,o.mdx)("inlineCode",{parentName:"li"},"package.json")," to store hooks."),(0,o.mdx)("li",{parentName:"ol"},(0,o.mdx)("inlineCode",{parentName:"li"},".env")," behaves the same.")),(0,o.mdx)("h2",{id:"migrating-between-standalone-application-and-dx-experience-cloud-spa-v1"},"Migrating between Standalone Application and DX Experience Cloud SPA v1"),(0,o.mdx)("ul",null,(0,o.mdx)("li",{parentName:"ul"},(0,o.mdx)("a",{parentName:"li",href:"migrations/standalone_to_dx_experience_cloud_spa.md"},"Standalone Application to DX Experience Cloud SPA v1")," - Useful if you can't seem to view your application in the App Builder Catalog in Adobe Experience Cloud.")))}p.isMDXComponent=!0}}]); -//# sourceMappingURL=component---src-pages-guides-configuration-index-md-7bc95ef25b3ec2459e8f.js.map \ No newline at end of file +"use strict";(self.webpackChunkadobe_developer_app_builder=self.webpackChunkadobe_developer_app_builder||[]).push([[6208],{52268:function(e,n,a){a.r(n),a.d(n,{_frontmatter:function(){return d},default:function(){return p}});var t=a(87462),i=a(63366),o=(a(15007),a(64983)),l=a(91515),m=["components"],d={},s={_frontmatter:d},r=l.Z;function p(e){var n=e.components,a=(0,i.Z)(e,m);return(0,o.mdx)(r,(0,t.Z)({},s,a,{components:n,mdxType:"MDXLayout"}),(0,o.mdx)("h1",{id:"app-builder-configuration-files"},"App Builder Configuration Files"),(0,o.mdx)("h2",{id:"overview"},"Overview"),(0,o.mdx)("p",null,"An app has three configuration files, ",(0,o.mdx)("strong",{parentName:"p"},"defined in the root of the project folder"),":"),(0,o.mdx)("ul",null,(0,o.mdx)("li",{parentName:"ul"},(0,o.mdx)("inlineCode",{parentName:"li"},"app.config.yaml")," is the main configuration file, defining the application's behavior and implementation."),(0,o.mdx)("li",{parentName:"ul"},(0,o.mdx)("inlineCode",{parentName:"li"},".env")," is used to store secrets and environment variables available during build time."),(0,o.mdx)("li",{parentName:"ul"},(0,o.mdx)("inlineCode",{parentName:"li"},".aio")," is populated by the ",(0,o.mdx)("inlineCode",{parentName:"li"},"aio")," CLI to store the current Developer Console Workspace details.")),(0,o.mdx)("p",null,"Note: ",(0,o.mdx)("inlineCode",{parentName:"p"},".env")," and ",(0,o.mdx)("inlineCode",{parentName:"p"},".aio")," files ",(0,o.mdx)("strong",{parentName:"p"},"should not be committed to version control"),"."),(0,o.mdx)("h2",{id:"appconfigyaml"},(0,o.mdx)("inlineCode",{parentName:"h2"},"app.config.yaml")),(0,o.mdx)("h3",{id:"tldr-give-me-a-full-example"},"Tl;dr: give me a full example:"),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre",className:"language-yaml"},"# standalone application config\napplication:\n hostname: 'customhost'\n runtimeManifest:\n packages:\n application-pkg:\n actions:\n count-apples:\n function: actions/count-apples/index.js\n web: 'yes'\n runtime: nodejs:18\n annotations:\n require-adobe-auth: true\n hooks:\n post-app-build: 'echo hook'\n\n# extension points config\nextensions:\n dx/excshell/1:\n # $include directive stores config in a separate file\n $include: ./dx-excshell-1/ext.config.yaml\n dx/asset-compute/worker/1:\n operations:\n workerProcess:\n - type: action\n impl: dx-asset-compute-worker-1/myworker\n runtimeManifest:\n packages:\n dx-asset-compute-worker-1:\n actions:\n myworker:\n function: actions/worker/index.js\n web: 'yes'\n runtime: nodejs:18\n")),(0,o.mdx)("h3",{id:"standalone-application-and-extensions"},"Standalone application and extensions"),(0,o.mdx)("p",null,"The ",(0,o.mdx)("inlineCode",{parentName:"p"},"app.config.yaml")," file can contain two top level fields: ",(0,o.mdx)("inlineCode",{parentName:"p"},"application")," and ",(0,o.mdx)("inlineCode",{parentName:"p"},"extensions"),".\nOnly one is required."),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre",className:"language-yaml"},"# app.config.yaml\n\napplication:\n \nextensions:\n :\n \n \n")),(0,o.mdx)("p",null,"A project can implement a standalone application and N extensions."),(0,o.mdx)("h3",{id:"common-configuration"},"Common configuration"),(0,o.mdx)("p",null,"Extensions and the standalone application behave in a similar way.\nBoth can contain a UI and actions and both support a common configuration.\nThe common configuration contains following fields:"),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre",className:"language-yaml"},"# \n\nruntimeManifest:\n \nhooks:\n \nactions: \nweb: \nunitTest: \ne2eTest: \ndist: \nhtmlCacheDuration: \njsCacheDuration: \ncssCacheDuration: \nimageCacheDuration: \ntvmurl: \nawsaccesskeyid: \nawssecretaccesskey: \ns3bucket: \nhostname: \n")),(0,o.mdx)("h4",{id:"runtime-manifest"},"Runtime Manifest"),(0,o.mdx)("p",null,"The ",(0,o.mdx)("inlineCode",{parentName:"p"},"runtimeManifest")," field holds the backend configuration deployed into Adobe I/O Runtime.\nThe full spec can be found ",(0,o.mdx)("a",{parentName:"p",href:"https://github.com/apache/openwhisk-wskdeploy/tree/master/specification/html"},"here"),". Acceptable values for the ",(0,o.mdx)("inlineCode",{parentName:"p"},"limits")," fields below can be found on the ",(0,o.mdx)("a",{parentName:"p",href:"https://developer.adobe.com/runtime/docs/guides/using/system_settings/"},"Runtime System Settings")," page.\nHere is an example to get started:"),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre",className:"language-yaml"},"runtimeManifest\n packages:\n myapp:\n license: Apache-2.0\n actions:\n generic:\n # path relative to the configuration file\n function: src/myapp/actions/generic/index.js\n web: 'yes'\n runtime: nodejs:18\n annotations:\n require-adobe-auth: true\n target:\n function: src/myapp/actions/target/index.js\n web: 'yes'\n runtime: nodejs:18\n limits:\n timeout: 60000\n memory: 512\n concurrency: 1\n logs: 10\n include:\n - [\"myfilestoinclude/*.txt\", \"text/\"] \n")),(0,o.mdx)("blockquote",null,(0,o.mdx)("p",{parentName:"blockquote"},"Note that the above example also demonstrates the 'include' field of an action. In some cases you may want to have a file deployed with your action code, and available to your code when it runs.\nThe example will copy all .txt files from the ",(0,o.mdx)("inlineCode",{parentName:"p"},"myfilestoinclude/")," directory and place it in a new dir ",(0,o.mdx)("inlineCode",{parentName:"p"},"text/")," that is available via ",(0,o.mdx)("inlineCode",{parentName:"p"},"fs.readFile('text/somefile.txt', 'utf8', callback);")," when your action is invoked.")),(0,o.mdx)("blockquote",null,(0,o.mdx)("p",{parentName:"blockquote"},"Note the above sets limit values. Limits are defined as:"),(0,o.mdx)("ul",{parentName:"blockquote"},(0,o.mdx)("li",{parentName:"ul"},(0,o.mdx)("inlineCode",{parentName:"li"},"concurrency"),": the maximum number of action invocations to send to the same container in parallel (default 200, min: 1,max: 500)"),(0,o.mdx)("li",{parentName:"ul"},(0,o.mdx)("inlineCode",{parentName:"li"},"logs"),": the maximum log size LIMIT in MB for the action (default 10, min: 0, max: 10)"),(0,o.mdx)("li",{parentName:"ul"},(0,o.mdx)("inlineCode",{parentName:"li"},"timeout"),": the timeout LIMIT in milliseconds after which the action is terminated (default 60000, min: 100, max: 3600000)",(0,o.mdx)("ul",{parentName:"li"},(0,o.mdx)("li",{parentName:"ul"},(0,o.mdx)("em",{parentName:"li"},"for web actions served from cdn there is a hard limit of 30 seconds for timeout")))),(0,o.mdx)("li",{parentName:"ul"},(0,o.mdx)("inlineCode",{parentName:"li"},"memory"),": the maximum memory LIMIT in MB for the action (default 256, min: 128, max: 4096)",(0,o.mdx)("ul",{parentName:"li"},(0,o.mdx)("li",{parentName:"ul"},(0,o.mdx)("em",{parentName:"li"},"setting distinct values (ex. 671) can impact cold starts as Runtime keeps a number of pre-warmed containers, but only for common memory sizes (128, 256, 512, 1024, etc.)"))))),(0,o.mdx)("p",{parentName:"blockquote"},"More info on ",(0,o.mdx)("inlineCode",{parentName:"p"},"limits")," can be found on the ",(0,o.mdx)("a",{parentName:"p",href:"https://developer.adobe.com/runtime/docs/guides/using/system_settings/"},"Runtime System Settings")," page.")),(0,o.mdx)("h5",{id:"annotations"},"Annotations"),(0,o.mdx)("p",null,"Runtime actions can be decorated with annotations to enhance or modify action behavior. "),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre",className:"language-yaml"},"runtimeManifest:\n packages:\n myapp:\n license: Apache-2.0\n actions:\n generic:\n annotations:\n require-adobe-auth: true\n disable-download: true \n")),(0,o.mdx)("p",null,"In addition to the base annotations provided by Runtime (See ",(0,o.mdx)("a",{parentName:"p",href:"https://github.com/adobe-apiplatform/incubator-openwhisk/blob/master/docs/annotations.md"},"here"),"), there are a few special annotations: "),(0,o.mdx)("ul",null,(0,o.mdx)("li",{parentName:"ul"},(0,o.mdx)("strong",{parentName:"li"},"disable-download")," (Default: false) - Determines whether action code can be downloaded. Once this annotation is set to true, it cannot be set back to false. "),(0,o.mdx)("li",{parentName:"ul"},(0,o.mdx)("strong",{parentName:"li"},"require-adobe-auth")," (Default: false) - Determines whether the action will require Adobe authentication to invoke. See ",(0,o.mdx)("a",{parentName:"li",href:"https://developer.adobe.com/app-builder/docs/guides/security/#authentication-and-authorization-handling"},"here")," for more.")),(0,o.mdx)("h5",{id:"api-gateway-configuration"},"API Gateway Configuration"),(0,o.mdx)("p",null,"A Runtime API Gateway configuration can be added to expose web actions over specific paths and HTTP verbs. "),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre",className:"language-yaml"},"runtimeManifest:\n packages:\n petsapp:\n license: Apache-2.0\n actions:\n get-pets: # Note the name of the action\n function: actions/get-pets/index.js\n web: 'yes'\n runtime: nodejs:18\n get-pet: # Note the name of the action\n function: actions/get-pet/index.js\n web: 'yes'\n runtime: nodejs:18\n apis: \n get-pets: # API Name\n v1: # Base Path\n pets: # Relative Path\n get-pets: # Name of the action to connect this path to\n method: get\n response: http\n get-pet: # API Name\n v1: # Base Path\n pets/{petName}: # Relative Path, with a path parameter\n get-pet: # Name of the action to connect this path to\n method: get\n response: http\n")),(0,o.mdx)("blockquote",null,(0,o.mdx)("p",{parentName:"blockquote"},"Note: The configuration above will result in the following: "),(0,o.mdx)("ul",{parentName:"blockquote"},(0,o.mdx)("li",{parentName:"ul"},(0,o.mdx)("inlineCode",{parentName:"li"},"GET https://adobeioruntime.net/apis/[namespace]/v1/pets")),(0,o.mdx)("li",{parentName:"ul"},(0,o.mdx)("inlineCode",{parentName:"li"},"GET https://adobeioruntime.net/apis/[namespace]/v1/pets/{petName}")))),(0,o.mdx)("blockquote",null,(0,o.mdx)("p",{parentName:"blockquote"},"Note: The second API above defines a path parameter in the relative path by using curly braces, i.e ",(0,o.mdx)("inlineCode",{parentName:"p"},"pets/{petName}")),(0,o.mdx)("ul",{parentName:"blockquote"},(0,o.mdx)("li",{parentName:"ul"},"APIs using path parameters must use the ",(0,o.mdx)("inlineCode",{parentName:"li"},"http")," response type"))),(0,o.mdx)("ul",null,(0,o.mdx)("li",{parentName:"ul"},"The following options are available for ",(0,o.mdx)("inlineCode",{parentName:"li"},"method"),": get, post, put, delete, patch"),(0,o.mdx)("li",{parentName:"ul"},"The following options are available for ",(0,o.mdx)("inlineCode",{parentName:"li"},"response"),": http (default), json, text, or html")),(0,o.mdx)("p",null,"Learn more about API Gateway Configuration with the ",(0,o.mdx)("a",{parentName:"p",href:"https://github.com/adobe/appbuilder-quickstarts/tree/master/action-apis"},"Action APIs QuickStart")),(0,o.mdx)("h4",{id:"hooks-to-customize-the-tooling"},"Hooks to customize the tooling"),(0,o.mdx)("p",null,"Hooks can be used to customize ",(0,o.mdx)("inlineCode",{parentName:"p"},"aio app")," commands. Hooks are documented ",(0,o.mdx)("a",{parentName:"p",href:"https://github.com/AdobeDocs/project-firefly/blob/main/src/pages/guides/app-hooks.md"},"here"),"."),(0,o.mdx)("h3",{id:"extension-specific-configuration"},"Extension specific configuration"),(0,o.mdx)("h4",{id:"extension-types"},"Extension types"),(0,o.mdx)("p",null,"The ",(0,o.mdx)("inlineCode",{parentName:"p"},"")," indicates which product the extension is extending, currently we support the following product extensions:"),(0,o.mdx)("ol",null,(0,o.mdx)("li",{parentName:"ol"},(0,o.mdx)("inlineCode",{parentName:"li"},"dx/excshell/1")," to implement an Experience Cloud Shell single page application."),(0,o.mdx)("li",{parentName:"ol"},(0,o.mdx)("inlineCode",{parentName:"li"},"dx/asset-compute/worker/1")," to implement an AEM Asset Compute worker.")),(0,o.mdx)("h4",{id:"dxexcshell1-definition"},(0,o.mdx)("inlineCode",{parentName:"h4"},"dx/excshell/1")," definition"),(0,o.mdx)("p",null,"The Experience Cloud Shell extension supports a ",(0,o.mdx)("inlineCode",{parentName:"p"},"view")," operation that points to the entry html file of the SPA.\nIn the following example the ",(0,o.mdx)("inlineCode",{parentName:"p"},"impl")," field points to an ",(0,o.mdx)("inlineCode",{parentName:"p"},"index.html")," file stored in the ",(0,o.mdx)("inlineCode",{parentName:"p"},"web/")," folder of the extension."),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre",className:"language-yaml"},"extensions\n dx/excshell/1:\n operations:\n view:\n - type: web\n impl: index.html\n web-src: web/\n")),(0,o.mdx)("h4",{id:"dxasset-computeworker1-definition"},(0,o.mdx)("inlineCode",{parentName:"h4"},"dx/asset-compute/worker/1")," definition"),(0,o.mdx)("p",null,"The AEM Asset Compute worker extension supports a ",(0,o.mdx)("inlineCode",{parentName:"p"},"workerProcess")," operation that points to the backend Adobe I/O Runtime action implementing the worker logic.\nIn the following example the ",(0,o.mdx)("inlineCode",{parentName:"p"},"impl")," field points to the ",(0,o.mdx)("inlineCode",{parentName:"p"},"dx-asset-compute-worker-1/worker")," action defined in the ",(0,o.mdx)("inlineCode",{parentName:"p"},"runtimeManifest"),"."),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre",className:"language-yaml"},"extensions\n dx/asset-compute/worker/1:\n operations:\n workerProcess:\n - type: action\n impl: dx-asset-compute-worker-1/myworker\n runtimeManifest:\n packages:\n dx-asset-compute-worker-1:\n actions:\n myworker:\n function: actions/worker/index.js\n web: 'yes'\n runtime: nodejs:18\n")),(0,o.mdx)("h3",{id:"the-include-directive"},"The ",(0,o.mdx)("inlineCode",{parentName:"h3"},"$include")," directive"),(0,o.mdx)("p",null,"The ",(0,o.mdx)("inlineCode",{parentName:"p"},"$include")," directive allows to defer any part of the ",(0,o.mdx)("inlineCode",{parentName:"p"},"app.config.yaml")," to another file.\nIn the following example, the ",(0,o.mdx)("inlineCode",{parentName:"p"},"dx/excshell/1")," configuration is stored in another ",(0,o.mdx)("inlineCode",{parentName:"p"},"./src/dx-excshell-1/ext.config.yaml")," file."),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre",className:"language-yaml"},"extensions:\n dx/excshell/1:\n $include: ./src/dx-excshell-1/ext.config.yaml\n")),(0,o.mdx)("p",null,"Configuration paths defined in ",(0,o.mdx)("inlineCode",{parentName:"p"},"./src/dx-excshell-1/ext.config.yaml")," must be relative to that file."),(0,o.mdx)("h2",{id:"env"},(0,o.mdx)("inlineCode",{parentName:"h2"},".env")),(0,o.mdx)("p",null,"The ",(0,o.mdx)("inlineCode",{parentName:"p"},".env")," file is used to store:"),(0,o.mdx)("ol",null,(0,o.mdx)("li",{parentName:"ol"},"secrets to be injected into I/O Runtime Actions."),(0,o.mdx)("li",{parentName:"ol"},"environment variables available to ",(0,o.mdx)("inlineCode",{parentName:"li"},"hooks"),"."),(0,o.mdx)("li",{parentName:"ol"},"auto generated secrets used by the ",(0,o.mdx)("inlineCode",{parentName:"li"},"aio")," CLI, prefixed by ",(0,o.mdx)("inlineCode",{parentName:"li"},"AIO_"),", those should not be edited.")),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre"},"# User secrets\nENABLE_DEV_DEBUG=true\n\n# Auto-generated secrets\nAIO_runtime_namespace=\nAIO_runtime_auth=\nAIO_runtime_apihost=\n")),(0,o.mdx)("h3",{id:"using-environment-variables-in-frontend"},"Using environment variables in frontend"),(0,o.mdx)("p",null,"Environment variables set in .env can be accessed directly via ",(0,o.mdx)("inlineCode",{parentName:"p"},"process.env"),":"),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre",className:"language-jsx"},"\n")),(0,o.mdx)("h3",{id:"using-environment-variables-in-runtime-actions"},"Using environment variables in Runtime actions"),(0,o.mdx)("p",null,"Environment variables set in .env need to be passed as inputs to an action and then are available via the action parameters."),(0,o.mdx)("h4",{id:"appconfigyaml-1"},"app.config.yaml"),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre",className:"language-yaml"},"runtimeManifest:\n packages:\n myapp:\n actions:\n generic:\n function: src/myapp/actions/generic/index.js\n web: 'yes'\n runtime: nodejs:18\n inputs:\n ENABLE_DEV_DEBUG: $ENABLE_DEV_DEBUG\n")),(0,o.mdx)("h4",{id:"action-code"},"Action code"),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre",className:"language-javascript"},'async function main (params) {\n if (params.ENABLE_DEV_DEBUG) {\n console.debug("Enabling dev tools, extra usage data will be captured...")\n }\n}\n\nexports.main = main\n')),(0,o.mdx)("h2",{id:"aio"},(0,o.mdx)("inlineCode",{parentName:"h2"},".aio")),(0,o.mdx)("p",null,"The ",(0,o.mdx)("inlineCode",{parentName:"p"},".aio")," file is auto generated and contains Developer Console specific configuration.\nThis file is updated via the ",(0,o.mdx)("inlineCode",{parentName:"p"},"aio app use")," command and should not be edited manually."),(0,o.mdx)("h2",{id:"legacy-configuration-system"},"Legacy configuration system"),(0,o.mdx)("p",null,"Apps initialized using a ",(0,o.mdx)("inlineCode",{parentName:"p"},"@adobe/aio-cli")," CLI version prior to 8.x use a legacy configuration system that we still support in newer CLI versions.\nThose apps do not support extensions, and only get deployed as standalone applications."),(0,o.mdx)("p",null,"The legacy configuration system does not have an ",(0,o.mdx)("inlineCode",{parentName:"p"},"app.config.yaml")," and instead uses:"),(0,o.mdx)("ol",null,(0,o.mdx)("li",{parentName:"ol"},(0,o.mdx)("inlineCode",{parentName:"li"},".aio")," to store common configuration bits, but hooks and Runtime Manifest, such as ",(0,o.mdx)("inlineCode",{parentName:"li"},"actions")," path."),(0,o.mdx)("li",{parentName:"ol"},(0,o.mdx)("inlineCode",{parentName:"li"},"manifest.yaml")," to stores the Runtime Manifest."),(0,o.mdx)("li",{parentName:"ol"},(0,o.mdx)("inlineCode",{parentName:"li"},"package.json")," to store hooks."),(0,o.mdx)("li",{parentName:"ol"},(0,o.mdx)("inlineCode",{parentName:"li"},".env")," behaves the same.")),(0,o.mdx)("h2",{id:"migrating-between-standalone-application-and-dx-experience-cloud-spa-v1"},"Migrating between Standalone Application and DX Experience Cloud SPA v1"),(0,o.mdx)("ul",null,(0,o.mdx)("li",{parentName:"ul"},(0,o.mdx)("a",{parentName:"li",href:"migrations/standalone_to_dx_experience_cloud_spa.md"},"Standalone Application to DX Experience Cloud SPA v1")," - Useful if you can't seem to view your application in the App Builder Catalog in Adobe Experience Cloud.")))}p.isMDXComponent=!0}}]); +//# sourceMappingURL=component---src-pages-guides-configuration-index-md-59201e843287f51ead6a.js.map \ No newline at end of file diff --git a/component---src-pages-guides-configuration-index-md-59201e843287f51ead6a.js.map b/component---src-pages-guides-configuration-index-md-59201e843287f51ead6a.js.map new file mode 100644 index 000000000..336621929 --- /dev/null +++ b/component---src-pages-guides-configuration-index-md-59201e843287f51ead6a.js.map @@ -0,0 +1 @@ +{"version":3,"file":"component---src-pages-guides-configuration-index-md-59201e843287f51ead6a.js","mappings":"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","sources":["webpack://adobe-developer-app-builder/./src/pages/guides/configuration/index.md"],"sourcesContent":["import * as React from 'react'\n /* @jsx mdx */\nimport { mdx } from '@mdx-js/react';\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\n\nimport DefaultLayout from \"/home/runner/work/app-builder/app-builder/node_modules/@adobe/gatsby-theme-aio/src/components/MDXFilter/index.js\";\nexport const _frontmatter = {};\nconst layoutProps = {\n _frontmatter\n};\nconst MDXLayout = DefaultLayout;\nexport default function MDXContent({\n components,\n ...props\n}) {\n return \n\n\n

{`App Builder Configuration Files`}

\n

{`Overview`}

\n

{`An app has three configuration files, `}{`defined in the root of the project folder`}{`:`}

\n
    \n
  • {`app.config.yaml`}{` is the main configuration file, defining the application's behavior and implementation.`}
  • \n
  • {`.env`}{` is used to store secrets and environment variables available during build time.`}
  • \n
  • {`.aio`}{` is populated by the `}{`aio`}{` CLI to store the current Developer Console Workspace details.`}
  • \n
\n

{`Note: `}{`.env`}{` and `}{`.aio`}{` files `}{`should not be committed to version control`}{`.`}

\n

{`app.config.yaml`}

\n

{`Tl;dr: give me a full example:`}

\n
{`# standalone application config\napplication:\n  hostname: 'customhost'\n  runtimeManifest:\n    packages:\n      application-pkg:\n        actions:\n          count-apples:\n            function: actions/count-apples/index.js\n            web: 'yes'\n            runtime: nodejs:18\n            annotations:\n              require-adobe-auth: true\n  hooks:\n    post-app-build: 'echo hook'\n\n# extension points config\nextensions:\n  dx/excshell/1:\n    # $include directive stores config in a separate file\n    $include: ./dx-excshell-1/ext.config.yaml\n  dx/asset-compute/worker/1:\n    operations:\n      workerProcess:\n        - type: action\n          impl: dx-asset-compute-worker-1/myworker\n    runtimeManifest:\n      packages:\n        dx-asset-compute-worker-1:\n          actions:\n            myworker:\n              function: actions/worker/index.js\n              web: 'yes'\n              runtime: nodejs:18\n`}
\n

{`Standalone application and extensions`}

\n

{`The `}{`app.config.yaml`}{` file can contain two top level fields: `}{`application`}{` and `}{`extensions`}{`.\nOnly one is required.`}

\n
{`# app.config.yaml\n\napplication:\n  \nextensions:\n  :\n    \n    \n`}
\n

{`A project can implement a standalone application and N extensions.`}

\n

{`Common configuration`}

\n

{`Extensions and the standalone application behave in a similar way.\nBoth can contain a UI and actions and both support a common configuration.\nThe common configuration contains following fields:`}

\n
{`# \n\nruntimeManifest:\n  \nhooks:\n  \nactions: \nweb: \nunitTest: \ne2eTest: \ndist: \nhtmlCacheDuration: \njsCacheDuration: \ncssCacheDuration: \nimageCacheDuration: \ntvmurl: \nawsaccesskeyid: \nawssecretaccesskey: \ns3bucket: \nhostname: \n`}
\n

{`Runtime Manifest`}

\n

{`The `}{`runtimeManifest`}{` field holds the backend configuration deployed into Adobe I/O Runtime.\nThe full spec can be found `}{`here`}{`. Acceptable values for the `}{`limits`}{` fields below can be found on the `}{`Runtime System Settings`}{` page.\nHere is an example to get started:`}

\n
{`runtimeManifest\n   packages:\n     myapp:\n       license: Apache-2.0\n       actions:\n         generic:\n           # path relative to the configuration file\n           function: src/myapp/actions/generic/index.js\n           web: 'yes'\n           runtime: nodejs:18\n           annotations:\n            require-adobe-auth: true\n         target:\n           function: src/myapp/actions/target/index.js\n           web: 'yes'\n           runtime: nodejs:18\n           limits:\n             timeout: 60000\n             memory: 512\n             concurrency: 1\n             logs: 10\n           include:\n              - [\"myfilestoinclude/*.txt\", \"text/\"]        \n`}
\n
\n

{`Note that the above example also demonstrates the 'include' field of an action. In some cases you may want to have a file deployed with your action code, and available to your code when it runs.\nThe example will copy all .txt files from the `}{`myfilestoinclude/`}{` directory and place it in a new dir `}{`text/`}{` that is available via `}{`fs.readFile('text/somefile.txt', 'utf8', callback);`}{` when your action is invoked.`}

\n
\n
\n

{`Note the above sets limit values. Limits are defined as:`}

\n
    \n
  • {`concurrency`}{`: the maximum number of action invocations to send to the same container in parallel (default 200, min: 1,max: 500)`}
  • \n
  • {`logs`}{`: the maximum log size LIMIT in MB for the action (default 10, min: 0, max: 10)`}
  • \n
  • {`timeout`}{`: the timeout LIMIT in milliseconds after which the action is terminated (default 60000, min: 100, max: 3600000)`}\n
      \n
    • {`for web actions served from cdn there is a hard limit of 30 seconds for timeout`}
    • \n
    \n
  • \n
  • {`memory`}{`: the maximum memory LIMIT in MB for the action (default 256, min: 128, max: 4096)`}\n
      \n
    • {`setting distinct values (ex. 671) can impact cold starts as Runtime keeps a number of pre-warmed containers, but only for common memory sizes (128, 256, 512, 1024, etc.)`}
    • \n
    \n
  • \n
\n

{`More info on `}{`limits`}{` can be found on the `}{`Runtime System Settings`}{` page.`}

\n
\n
{`Annotations`}
\n

{`Runtime actions can be decorated with annotations to enhance or modify action behavior. `}

\n
{`runtimeManifest:\n   packages:\n     myapp:\n       license: Apache-2.0\n       actions:\n         generic:\n           annotations:\n             require-adobe-auth: true\n             disable-download: true  \n`}
\n

{`In addition to the base annotations provided by Runtime (See `}{`here`}{`), there are a few special annotations: `}

\n
    \n
  • {`disable-download`}{` (Default: false) - Determines whether action code can be downloaded. Once this annotation is set to true, it cannot be set back to false. `}
  • \n
  • {`require-adobe-auth`}{` (Default: false) - Determines whether the action will require Adobe authentication to invoke. See `}{`here`}{` for more.`}
  • \n
\n
{`API Gateway Configuration`}
\n

{`A Runtime API Gateway configuration can be added to expose web actions over specific paths and HTTP verbs. `}

\n
{`runtimeManifest:\n   packages:\n     petsapp:\n       license: Apache-2.0\n       actions:\n         get-pets: # Note the name of the action\n           function: actions/get-pets/index.js\n           web: 'yes'\n           runtime: nodejs:18\n         get-pet: # Note the name of the action\n           function: actions/get-pet/index.js\n           web: 'yes'\n           runtime: nodejs:18\n       apis: \n        get-pets: # API Name\n          v1: # Base Path\n            pets: # Relative Path\n              get-pets: # Name of the action to connect this path to\n                method: get\n                response: http\n        get-pet: # API Name\n          v1: # Base Path\n            pets/{petName}: # Relative Path, with a path parameter\n              get-pet: # Name of the action to connect this path to\n                method: get\n                response: http\n`}
\n
\n

{`Note: The configuration above will result in the following: `}

\n
    \n
  • {`GET https://adobeioruntime.net/apis/[namespace]/v1/pets`}
  • \n
  • {`GET https://adobeioruntime.net/apis/[namespace]/v1/pets/{petName}`}
  • \n
\n
\n
\n

{`Note: The second API above defines a path parameter in the relative path by using curly braces, i.e `}{`pets/{petName}`}

\n
    \n
  • {`APIs using path parameters must use the `}{`http`}{` response type`}
  • \n
\n
\n
    \n
  • {`The following options are available for `}{`method`}{`: get, post, put, delete, patch`}
  • \n
  • {`The following options are available for `}{`response`}{`: http (default), json, text, or html`}
  • \n
\n

{`Learn more about API Gateway Configuration with the `}{`Action APIs QuickStart`}

\n

{`Hooks to customize the tooling`}

\n

{`Hooks can be used to customize `}{`aio app`}{` commands. Hooks are documented `}{`here`}{`.`}

\n

{`Extension specific configuration`}

\n

{`Extension types`}

\n

{`The `}{``}{` indicates which product the extension is extending, currently we support the following product extensions:`}

\n
    \n
  1. {`dx/excshell/1`}{` to implement an Experience Cloud Shell single page application.`}
  2. \n
  3. {`dx/asset-compute/worker/1`}{` to implement an AEM Asset Compute worker.`}
  4. \n
\n

{`dx/excshell/1`}{` definition`}

\n

{`The Experience Cloud Shell extension supports a `}{`view`}{` operation that points to the entry html file of the SPA.\nIn the following example the `}{`impl`}{` field points to an `}{`index.html`}{` file stored in the `}{`web/`}{` folder of the extension.`}

\n
{`extensions\n  dx/excshell/1:\n    operations:\n      view:\n        - type: web\n          impl: index.html\n     web-src: web/\n`}
\n

{`dx/asset-compute/worker/1`}{` definition`}

\n

{`The AEM Asset Compute worker extension supports a `}{`workerProcess`}{` operation that points to the backend Adobe I/O Runtime action implementing the worker logic.\nIn the following example the `}{`impl`}{` field points to the `}{`dx-asset-compute-worker-1/worker`}{` action defined in the `}{`runtimeManifest`}{`.`}

\n
{`extensions\n  dx/asset-compute/worker/1:\n    operations:\n      workerProcess:\n        - type: action\n          impl: dx-asset-compute-worker-1/myworker\n    runtimeManifest:\n      packages:\n        dx-asset-compute-worker-1:\n          actions:\n            myworker:\n              function: actions/worker/index.js\n              web: 'yes'\n              runtime: nodejs:18\n`}
\n

{`The `}{`$include`}{` directive`}

\n

{`The `}{`$include`}{` directive allows to defer any part of the `}{`app.config.yaml`}{` to another file.\nIn the following example, the `}{`dx/excshell/1`}{` configuration is stored in another `}{`./src/dx-excshell-1/ext.config.yaml`}{` file.`}

\n
{`extensions:\n  dx/excshell/1:\n    $include: ./src/dx-excshell-1/ext.config.yaml\n`}
\n

{`Configuration paths defined in `}{`./src/dx-excshell-1/ext.config.yaml`}{` must be relative to that file.`}

\n

{`.env`}

\n

{`The `}{`.env`}{` file is used to store:`}

\n
    \n
  1. {`secrets to be injected into I/O Runtime Actions.`}
  2. \n
  3. {`environment variables available to `}{`hooks`}{`.`}
  4. \n
  5. {`auto generated secrets used by the `}{`aio`}{` CLI, prefixed by `}{`AIO_`}{`, those should not be edited.`}
  6. \n
\n
{`# User secrets\nENABLE_DEV_DEBUG=true\n\n# Auto-generated secrets\nAIO_runtime_namespace=\nAIO_runtime_auth=\nAIO_runtime_apihost=\n`}
\n

{`Using environment variables in frontend`}

\n

{`Environment variables set in .env can be accessed directly via `}{`process.env`}{`:`}

\n
{`\n`}
\n

{`Using environment variables in Runtime actions`}

\n

{`Environment variables set in .env need to be passed as inputs to an action and then are available via the action parameters.`}

\n

{`app.config.yaml`}

\n
{`runtimeManifest:\n   packages:\n     myapp:\n       actions:\n         generic:\n           function: src/myapp/actions/generic/index.js\n           web: 'yes'\n           runtime: nodejs:18\n           inputs:\n               ENABLE_DEV_DEBUG: $ENABLE_DEV_DEBUG\n`}
\n

{`Action code`}

\n
{`async function main (params) {\n  if (params.ENABLE_DEV_DEBUG) {\n    console.debug(\"Enabling dev tools, extra usage data will be captured...\")\n  }\n}\n\nexports.main = main\n`}
\n

{`.aio`}

\n

{`The `}{`.aio`}{` file is auto generated and contains Developer Console specific configuration.\nThis file is updated via the `}{`aio app use`}{` command and should not be edited manually.`}

\n

{`Legacy configuration system`}

\n

{`Apps initialized using a `}{`@adobe/aio-cli`}{` CLI version prior to 8.x use a legacy configuration system that we still support in newer CLI versions.\nThose apps do not support extensions, and only get deployed as standalone applications.`}

\n

{`The legacy configuration system does not have an `}{`app.config.yaml`}{` and instead uses:`}

\n
    \n
  1. {`.aio`}{` to store common configuration bits, but hooks and Runtime Manifest, such as `}{`actions`}{` path.`}
  2. \n
  3. {`manifest.yaml`}{` to stores the Runtime Manifest.`}
  4. \n
  5. {`package.json`}{` to store hooks.`}
  6. \n
  7. {`.env`}{` behaves the same.`}
  8. \n
\n

{`Migrating between Standalone Application and DX Experience Cloud SPA v1`}

\n \n\n
;\n}\n;\nMDXContent.isMDXComponent = true;\n "],"names":["_frontmatter","layoutProps","MDXLayout","DefaultLayout","MDXContent","components","props","mdxType","parentName","isMDXComponent"],"sourceRoot":""} \ No newline at end of file diff --git a/component---src-pages-guides-configuration-index-md-7bc95ef25b3ec2459e8f.js.map b/component---src-pages-guides-configuration-index-md-7bc95ef25b3ec2459e8f.js.map deleted file mode 100644 index b23192ee1..000000000 --- a/component---src-pages-guides-configuration-index-md-7bc95ef25b3ec2459e8f.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"component---src-pages-guides-configuration-index-md-7bc95ef25b3ec2459e8f.js","mappings":"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","sources":["webpack://adobe-developer-app-builder/./src/pages/guides/configuration/index.md"],"sourcesContent":["import * as React from 'react'\n /* @jsx mdx */\nimport { mdx } from '@mdx-js/react';\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\n\nimport DefaultLayout from \"/home/runner/work/app-builder/app-builder/node_modules/@adobe/gatsby-theme-aio/src/components/MDXFilter/index.js\";\nexport const _frontmatter = {};\nconst layoutProps = {\n _frontmatter\n};\nconst MDXLayout = DefaultLayout;\nexport default function MDXContent({\n components,\n ...props\n}) {\n return \n\n\n

{`App Builder Configuration Files`}

\n

{`Overview`}

\n

{`An app has three configuration files, `}{`defined in the root of the project folder`}{`:`}

\n
    \n
  • {`app.config.yaml`}{` is the main configuration file, defining the application's behavior and implementation.`}
  • \n
  • {`.env`}{` is used to store secrets and environment variables available during build time.`}
  • \n
  • {`.aio`}{` is populated by the `}{`aio`}{` CLI to store the current Developer Console Workspace details.`}
  • \n
\n

{`Note: `}{`.env`}{` and `}{`.aio`}{` files `}{`should not be committed to version control`}{`.`}

\n

{`app.config.yaml`}

\n

{`Tl;dr: give me a full example:`}

\n
{`# standalone application config\napplication:\n  hostname: 'customhost'\n  runtimeManifest:\n    packages:\n      application-pkg:\n        actions:\n          count-apples:\n            function: actions/count-apples/index.js\n            web: 'yes'\n            runtime: nodejs:18\n            annotations:\n              require-adobe-auth: true\n  hooks:\n    post-app-build: 'echo hook'\n\n# extension points config\nextensions:\n  dx/excshell/1:\n    # $include directive stores config in a separate file\n    $include: ./dx-excshell-1/ext.config.yaml\n  dx/asset-compute/worker/1:\n    operations:\n      workerProcess:\n        - type: action\n          impl: dx-asset-compute-worker-1/myworker\n    runtimeManifest:\n      packages:\n        dx-asset-compute-worker-1:\n          actions:\n            myworker:\n              function: actions/worker/index.js\n              web: 'yes'\n              runtime: nodejs:18\n`}
\n

{`Standalone application and extensions`}

\n

{`The `}{`app.config.yaml`}{` file can contain two top level fields: `}{`application`}{` and `}{`extensions`}{`.\nOnly one is required.`}

\n
{`# app.config.yaml\n\napplication:\n  \nextensions:\n  :\n    \n    \n`}
\n

{`A project can implement a standalone application and N extensions.`}

\n

{`Common configuration`}

\n

{`Extensions and the standalone application behave in a similar way.\nBoth can contain a UI and actions and both support a common configuration.\nThe common configuration contains following fields:`}

\n
{`# \n\nruntimeManifest:\n  \nhooks:\n  \nactions: \nweb: \nunitTest: \ne2eTest: \ndist: \nhtmlCacheDuration: \njsCacheDuration: \ncssCacheDuration: \nimageCacheDuration: \ntvmurl: \nawsaccesskeyid: \nawssecretaccesskey: \ns3bucket: \nhostname: \n`}
\n

{`Runtime Manifest`}

\n

{`The `}{`runtimeManifest`}{` field holds the backend configuration deployed into Adobe I/O Runtime.\nThe full spec can be found `}{`here`}{`. Acceptable values for the `}{`limits`}{` fields below can be found on the `}{`Runtime System Settings`}{` page.\nHere is an example to get started:`}

\n
{`runtimeManifest\n   packages:\n     myapp:\n       license: Apache-2.0\n       actions:\n         generic:\n           # path relative to the configuration file\n           function: src/myapp/actions/generic/index.js\n           web: 'yes'\n           runtime: nodejs:18\n           annotations:\n            require-adobe-auth: true\n         target:\n           function: src/myapp/actions/target/index.js\n           web: 'yes'\n           runtime: nodejs:18\n           limits:\n             timeout: 60000\n             memory: 512\n             concurrency: 1\n             logs: 10\n           include:\n              - [\"myfilestoinclude/*.txt\", \"text/\"]        \n`}
\n
\n

{`Note that the above example also demonstrates the 'include' field of an action. In some cases you may want to have a file deployed with your action code, and available to your code when it runs.\nThe example will copy all .txt files from the `}{`myfilestoinclude/`}{` directory and place it in a new dir `}{`text/`}{` that is available via `}{`fs.readFile('text/somefile.txt', 'utf8', callback);`}{` when your action is invoked.`}

\n
\n
\n

{`Note the above sets limit values. Limits are defined as:`}

\n
    \n
  • {`concurrency`}{`: the maximum number of action invocations to send to the same container in parallel (default 200, min: 1,max: 500)`}
  • \n
  • {`logs`}{`: the maximum log size LIMIT in MB for the action (default 10, min: 0, max: 10)`}
  • \n
  • {`timeout`}{`: the timeout LIMIT in milliseconds after which the action is terminated (default 60000, min: 100, max: 3600000)`}\n
      \n
    • {`for web actions served from cdn there is a hard limit of 30 seconds for timeout`}
    • \n
    \n
  • \n
  • {`memory`}{`: the maximum memory LIMIT in MB for the action (default 256, min: 128, max: 4096)`}\n
      \n
    • {`setting distinct values (ex. 671) can impact cold starts as Runtime keeps a number of pre-warmed containers, but only for common memory sizes (128, 256, 512, 1024, etc.)`}
    • \n
    \n
  • \n
\n

{`More info on `}{`limits`}{` can be found on the `}{`Runtime System Settings`}{` page.`}

\n
\n
{`Annotations`}
\n

{`Runtime actions can be decorated with annotations to enhance or modify action behavior. `}

\n
{`runtimeManifest:\n   packages:\n     myapp:\n       license: Apache-2.0\n       actions:\n         generic:\n           annotations:\n             require-adobe-auth: true\n             disable-download: true  \n`}
\n

{`In addition to the base annotations provided by Runtime (See `}{`here`}{`), there are a few special annotations: `}

\n
    \n
  • {`disable-download`}{` (Default: false) - Determines whether action code can be downloaded. Once this annotation is set to true, it cannot be set back to false. `}
  • \n
  • {`require-adobe-auth`}{` (Default: false) - Determines whether the action will require Adobe authentication to invoke. See `}{`here`}{` for more.`}
  • \n
\n
{`API Gateway Configuration`}
\n

{`A Runtime API Gateway configuration can be added to expose web actions over specific paths and HTTP verbs. `}

\n
{`runtimeManifest:\n   packages:\n     petsapp:\n       license: Apache-2.0\n       actions:\n         get-pets: # Note the name of the action\n           function: actions/get-pets/index.js\n           web: 'yes'\n           runtime: nodejs:18\n         get-pet: # Note the name of the action\n           function: actions/get-pet/index.js\n           web: 'yes'\n           runtime: nodejs:18\n       apis: \n        get-pets: # API Name\n          v1: # Base Path\n            pets: # Relative Path\n              get-pets: # Name of the action to connect this path to\n                method: get\n                response: http\n        get-pet: # API Name\n          v1: # Base Path\n            pets/{petName}: # Relative Path, with a path parameter\n              get-pet: # Name of the action to connect this path to\n                method: get\n                response: http\n`}
\n
\n

{`Note: The configuration above will result in the following: `}

\n
    \n
  • {`GET https://adobeioruntime.net/apis/[namespace]/v1/pets`}
  • \n
  • {`GET https://adobeioruntime.net/apis/[namespace]/v1/pets/{petName}`}
  • \n
\n
\n
\n

{`Note: The second API above defines a path parameter in the relative path by using curly braces, i.e `}{`pets/{petName}`}

\n
    \n
  • {`APIs using path parameters must use the `}{`http`}{` response type`}
  • \n
\n
\n
    \n
  • {`The following options are available for `}{`method`}{`: get, post, put, delete, patch`}
  • \n
  • {`The following options are available for `}{`response`}{`: http (default), json, text, or html`}
  • \n
\n

{`Learn more about API Gateway Configuration with the `}{`Action APIs QuickStart`}

\n

{`Hooks to customize the tooling`}

\n

{`Hooks can be used to customize `}{`aio app`}{` commands. Hooks are documented `}{`here`}{`.`}

\n

{`Extension specific configuration`}

\n

{`Extension types`}

\n

{`The `}{``}{` indicates which product the extension is extending, currently we support the following product extensions:`}

\n
    \n
  1. {`dx/excshell/1`}{` to implement an Experience Cloud Shell single page application.`}
  2. \n
  3. {`dx/asset-compute/worker/1`}{` to implement an AEM Asset Compute worker.`}
  4. \n
\n

{`dx/excshell/1`}{` definition`}

\n

{`The Experience Cloud Shell extension supports a `}{`view`}{` operation that points to the entry html file of the SPA.\nIn the following example the `}{`impl`}{` field points to an `}{`index.html`}{` file stored in the `}{`web/`}{` folder of the extension.`}

\n
{`extensions\n  dx/excshell/1:\n    operations:\n      view:\n        - type: web\n          impl: index.html\n     web-src: web/\n`}
\n

{`dx/asset-compute/worker/1`}{` definition`}

\n

{`The AEM Asset Compute worker extension supports a `}{`workerProcess`}{` operation that points to the backend Adobe I/O Runtime action implementing the worker logic.\nIn the following example the `}{`impl`}{` field points to the `}{`dx-asset-compute-worker-1/worker`}{` action defined in the `}{`runtimeManifest`}{`.`}

\n
{`extensions\n  dx/asset-compute/worker/1:\n    operations:\n      workerProcess:\n        - type: action\n          impl: dx-asset-compute-worker-1/myworker\n    runtimeManifest:\n      packages:\n        dx-asset-compute-worker-1:\n          actions:\n            myworker:\n              function: actions/worker/index.js\n              web: 'yes'\n              runtime: nodejs:18\n`}
\n

{`The `}{`$include`}{` directive`}

\n

{`The `}{`$include`}{` directive allows to defer any part of the `}{`app.config.yaml`}{` to another file.\nIn the following example, the `}{`dx/excshell/1`}{` configuration is stored in another `}{`./src/dx-excshell-1/ext.config.yaml`}{` file.`}

\n
{`extensions:\n  dx/excshell/1:\n    $include: ./src/dx-excshell-1/ext.config.yaml\n`}
\n

{`Configuration paths defined in `}{`./src/dx-excshell-1/ext.config.yaml`}{` must be relative to that file.`}

\n

{`.env`}

\n

{`The `}{`.env`}{` file is used to store:`}

\n
    \n
  1. {`secrets to be injected into I/O Runtime Actions.`}
  2. \n
  3. {`environment variables available to `}{`hooks`}{`.`}
  4. \n
  5. {`auto generated secrets used by the `}{`aio`}{` CLI, prefixed by `}{`AIO_`}{`, those should not be edited.`}
  6. \n
\n

{`.aio`}

\n

{`The `}{`.aio`}{` file is auto generated and contains Developer Console specific configuration.\nThis file is updated via the `}{`aio app use`}{` command and should not be edited manually.`}

\n

{`Legacy configuration system`}

\n

{`Apps initialized using a `}{`@adobe/aio-cli`}{` CLI version prior to 8.x use a legacy configuration system that we still support in newer CLI versions.\nThose apps do not support extensions, and only get deployed as standalone applications.`}

\n

{`The legacy configuration system does not have an `}{`app.config.yaml`}{` and instead uses:`}

\n
    \n
  1. {`.aio`}{` to store common configuration bits, but hooks and Runtime Manifest, such as `}{`actions`}{` path.`}
  2. \n
  3. {`manifest.yaml`}{` to stores the Runtime Manifest.`}
  4. \n
  5. {`package.json`}{` to store hooks.`}
  6. \n
  7. {`.env`}{` behaves the same.`}
  8. \n
\n

{`Migrating between Standalone Application and DX Experience Cloud SPA v1`}

\n \n\n
;\n}\n;\nMDXContent.isMDXComponent = true;\n "],"names":["_frontmatter","layoutProps","MDXLayout","DefaultLayout","MDXContent","components","props","mdxType","parentName","isMDXComponent"],"sourceRoot":""} \ No newline at end of file diff --git a/component---src-pages-guides-tips-tricks-md-48f3f92f76d63450e5e6.js b/component---src-pages-guides-tips-tricks-md-48f3f92f76d63450e5e6.js deleted file mode 100644 index 78a6174d1..000000000 --- a/component---src-pages-guides-tips-tricks-md-48f3f92f76d63450e5e6.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict";(self.webpackChunkadobe_developer_app_builder=self.webpackChunkadobe_developer_app_builder||[]).push([[1834],{14001:function(e,t,a){a.r(t),a.d(t,{_frontmatter:function(){return l},default:function(){return d}});var o=a(87462),n=a(63366),i=(a(15007),a(64983)),r=a(91515),s=["components"],l={},m={_frontmatter:l},p=r.Z;function d(e){var t=e.components,a=(0,n.Z)(e,s);return(0,i.mdx)(p,(0,o.Z)({},m,a,{components:t,mdxType:"MDXLayout"}),(0,i.mdx)("h1",{id:"tips-and-tricks-for-optimizing-app-builder-apps"},"Tips and Tricks for optimizing App Builder Apps"),(0,i.mdx)("p",null,"There are many areas in a web app where you could optimize the way it works, such as security, performance, and operational cost, to name a few. Here are some tips and tricks to help you gain the most out of your App Builder applications."),(0,i.mdx)("h2",{id:"caching-http-responses"},"Caching HTTP Responses"),(0,i.mdx)("p",null,"This method works extremely well if your action returns some results based on repeated user inputs as query params, e.g. details about an item on a webshop, or visualization of static data. In these cases, your backend action would be invoked once only, and then subsequent requests receive the results directly from the cache by the expiry time. Serving results from cache is not only fast, but also saves the cost of action invocations."),(0,i.mdx)("p",null,"In order to configure the cache, you use the ",(0,i.mdx)("inlineCode",{parentName:"p"},"Cache-Control")," directive. Below is an example of an action that sets the cache with a TTL of 30 minutes. In the response object you will find an entry with ",(0,i.mdx)("inlineCode",{parentName:"p"},"X-GW-Cache: HIT")," or ",(0,i.mdx)("inlineCode",{parentName:"p"},"X-GW-Cache: MISS")," (depending on the answer being returned from cache or not)."),(0,i.mdx)("pre",null,(0,i.mdx)("code",{parentName:"pre",className:"language-javascript"},"async function main (params) {\n return {\n headers: {\n 'Cache-Control': 'max-age=1800'\n },\n statusCode: 200,\n body: { message: 'I am cached for 30 minutes.' }\n }\n}\n")),(0,i.mdx)("p",null,"When you test this functionality for web action using Postman or web browser with developer tools opened, make sure that ",(0,i.mdx)("inlineCode",{parentName:"p"},"Cache-Control")," is not automatically set for all the requests."),(0,i.mdx)("h2",{id:"returning-large-response-payload"},"Returning Large Response Payload"),(0,i.mdx)("p",null,"You can return a ",(0,i.mdx)("a",{parentName:"p",href:"/app-builder/apis/experienceplatform/runtime/docs#!adobedocs/adobeio-runtime/master/guides/system_settings.md"},"response payload of max 1MB")," in an Adobe I/O Runtime action. That is more than enough for the majority of the use cases we have seen so far. However, if your action would return a larger payload than the 1MB limit, we provide a scalable solution with ",(0,i.mdx)("a",{parentName:"p",href:"https://github.com/adobe/aio-lib-files"},"App Builder Files SDK"),". It allows you to ",(0,i.mdx)("a",{parentName:"p",href:"https://github.com/adobe/aio-lib-files/blob/master/doc/api.md#Files+write"},"persist a binary file to the blob storage"),", obtain ",(0,i.mdx)("a",{parentName:"p",href:"https://github.com/adobe/aio-lib-files/blob/master/doc/api.md#Files+generatePresignURL"},"a temporary downloadable URL")," and return an ",(0,i.mdx)("a",{parentName:"p",href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/302"},"HTTP Redirect response")," to the file with this URL. Below is a simple code snippet to demonstrate that."),(0,i.mdx)("pre",null,(0,i.mdx)("code",{parentName:"pre",className:"language-javascript"},"const fileLocation = '/private-dir/large-image.png'\nconst files = await Files.init()\nawait files.write(fileLocation, fileContent)\n\n// Generate a presigned URL of the file that is valid for 60 seconds only\nconst presignUrl = await files.generatePresignURL(fileLocation, { expiryInSeconds: 60 })\n\nreturn {\n headers: { location: presignUrl }, \n statusCode: 302\n}\n")),(0,i.mdx)("h2",{id:"implementing-a-move-operation-for-the-app-builder-files-sdk"},"Implementing a move operation for the App Builder Files SDK"),(0,i.mdx)("p",null,"While handling large files within a Runtime action using ",(0,i.mdx)("a",{parentName:"p",href:"https://github.com/adobe/aio-lib-files"},"App Builder Files SDK"),", you might have the need to move those files to another location in the underlying cloud storage, e.g. for archiving purpose when computing is over."),(0,i.mdx)("p",null,"We have decided until now to not expose a move operation in our abstraction, for the two main following reasons:"),(0,i.mdx)("ul",null,(0,i.mdx)("li",{parentName:"ul"},"Some cloud storage APIs do not provide an atomic move operation, meaning that there is a tradeoff between abstraction and consistency. Users might expect that files operations on single files are atomic. Operations on folders are not atomic neither."),(0,i.mdx)("li",{parentName:"ul"},"The implementation of such a feature is a two-liner, which makes it simple enough to implement and test the abstraction at application level")),(0,i.mdx)("p",null,"This is our recommendation to implement the move operation at application level by using the ",(0,i.mdx)("a",{parentName:"p",href:"https://github.com/adobe/aio-lib-files"},"App Builder Files SDK")," primitives:"),(0,i.mdx)("pre",null,(0,i.mdx)("code",{parentName:"pre",className:"language-javascript"},"/**\n * Note: this operation is not atomic.\n * Moves files from one location to another in the remote storage. \n * \n * @param {Files} files the files instance\n * @param {string} src source file/folder\n * @param {string} dest destination file/folder\n * @param {object} [options={}] move options\n * @param {Function} [options.progressCallback] a function that will be called every\n * time the operation completes on a single file, the srcPath and destPath to the moved\n * file are passed as argument to the callback `progressCallback(srcPath, destPath)`\n */\nasync function move (files, src, dest, options = {}) {\n try {\n const res = await files.copy(src, dest, { progressCallback: options.progressCallback })\n await files.delete(src)\n return res\n } catch (e) {\n e.message = `Move operation failed, reason: ${e.message}`\n throw e\n }\n}\n")),(0,i.mdx)("p",null,"Here are some usage examples:"),(0,i.mdx)("pre",null,(0,i.mdx)("code",{parentName:"pre",className:"language-javascript"},"const files = await Files.init()\nawait move(files, 'my/remote/src/folder/', 'my/remote/dest/')\nawait move(files, 'my/remote/src/folder/file.txt', 'my/remote/dest/file2.md') // will move and rename the file\nawait move(files, 'my/remote/src/folder/file.txt', 'my/remote/dest/') // will move file.txt to dest folder\nawait move(files, 'my/remote/src/folder/', 'my/remote/dest/') // move folder to the dest folder\nawait move(files, 'my/remote/folder/', 'my/remote/dest') // will rename folder to dest\n")))}d.isMDXComponent=!0}}]); -//# sourceMappingURL=component---src-pages-guides-tips-tricks-md-48f3f92f76d63450e5e6.js.map \ No newline at end of file diff --git a/component---src-pages-guides-tips-tricks-md-48f3f92f76d63450e5e6.js.map b/component---src-pages-guides-tips-tricks-md-48f3f92f76d63450e5e6.js.map deleted file mode 100644 index 44d69de67..000000000 --- a/component---src-pages-guides-tips-tricks-md-48f3f92f76d63450e5e6.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"component---src-pages-guides-tips-tricks-md-48f3f92f76d63450e5e6.js","mappings":"4SAQaA,EAAe,CAAC,EACvBC,EAAc,CAClBD,aAAAA,GAEIE,EAAYC,EAAAA,EACH,SAASC,EAAT,GAGZ,IAFDC,EAEC,EAFDA,WACGC,GACF,YACD,OAAO,SAACJ,GAAD,UAAeD,EAAiBK,EAAhC,CAAuCD,WAAYA,EAAYE,QAAQ,eAG5E,eACE,GAAM,mDADR,oDAGA,qQACA,eACE,GAAM,0BADR,2BAGA,8cACA,mEAAoD,uBAAYC,WAAW,KAAvB,iBAApD,kJAA+P,uBAAYA,WAAW,KAAvB,mBAA/P,QAAkU,uBAAYA,WAAW,KAAvB,oBAAlU,iEACA,qBAAK,iBAAMA,WAAW,MAClB,UAAa,uBADZ,+MAYL,+IAAgI,uBAAYA,WAAW,KAAvB,iBAAhI,oDACA,eACE,GAAM,oCADR,qCAGA,uCAAwB,cAAGA,WAAW,IAClC,KAAQ,iHADY,+BAAxB,mOAE2Q,cAAGA,WAAW,IACrR,KAAQ,0CAD+P,yBAF3Q,uBAIyD,cAAGA,WAAW,IACnE,KAAQ,6EAD6C,6CAJzD,aAMmE,cAAGA,WAAW,IAC7E,KAAQ,0FADuD,gCANnE,mBAQ4D,cAAGA,WAAW,IACtE,KAAQ,gEADgD,0BAR5D,oFAWA,qBAAK,iBAAMA,WAAW,MAClB,UAAa,uBADZ,2XAcL,eACE,GAAM,+DADR,gEAGA,+EAAgE,cAAGA,WAAW,IAC1E,KAAQ,0CADoD,yBAAhE,0JAGA,uIACA,oBACE,eAAIA,WAAW,MAAf,8PACA,eAAIA,WAAW,MAAf,kJAEF,mHAAoG,cAAGA,WAAW,IAC9G,KAAQ,0CADwF,yBAApG,iBAGA,qBAAK,iBAAMA,WAAW,MAClB,UAAa,uBADZ,k3BAyBL,oDACA,qBAAK,iBAAMA,WAAW,MAClB,UAAa,uBADZ,2fAWR,CAEDJ,EAAWK,gBAAiB,C","sources":["webpack://adobe-developer-app-builder/./src/pages/guides/tips_tricks.md"],"sourcesContent":["import * as React from 'react'\n /* @jsx mdx */\nimport { mdx } from '@mdx-js/react';\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\n\nimport DefaultLayout from \"/home/runner/work/app-builder/app-builder/node_modules/@adobe/gatsby-theme-aio/src/components/MDXFilter/index.js\";\nexport const _frontmatter = {};\nconst layoutProps = {\n _frontmatter\n};\nconst MDXLayout = DefaultLayout;\nexport default function MDXContent({\n components,\n ...props\n}) {\n return \n\n\n

{`Tips and Tricks for optimizing App Builder Apps`}

\n

{`There are many areas in a web app where you could optimize the way it works, such as security, performance, and operational cost, to name a few. Here are some tips and tricks to help you gain the most out of your App Builder applications.`}

\n

{`Caching HTTP Responses`}

\n

{`This method works extremely well if your action returns some results based on repeated user inputs as query params, e.g. details about an item on a webshop, or visualization of static data. In these cases, your backend action would be invoked once only, and then subsequent requests receive the results directly from the cache by the expiry time. Serving results from cache is not only fast, but also saves the cost of action invocations.`}

\n

{`In order to configure the cache, you use the `}{`Cache-Control`}{` directive. Below is an example of an action that sets the cache with a TTL of 30 minutes. In the response object you will find an entry with `}{`X-GW-Cache: HIT`}{` or `}{`X-GW-Cache: MISS`}{` (depending on the answer being returned from cache or not).`}

\n
{`async function main (params) {\n  return {\n      headers: {\n        'Cache-Control': 'max-age=1800'\n      },\n      statusCode: 200,\n      body: { message: 'I am cached for 30 minutes.' }\n  }\n}\n`}
\n

{`When you test this functionality for web action using Postman or web browser with developer tools opened, make sure that `}{`Cache-Control`}{` is not automatically set for all the requests.`}

\n

{`Returning Large Response Payload`}

\n

{`You can return a `}{`response payload of max 1MB`}{` in an Adobe I/O Runtime action. That is more than enough for the majority of the use cases we have seen so far. However, if your action would return a larger payload than the 1MB limit, we provide a scalable solution with `}{`App Builder Files SDK`}{`. It allows you to `}{`persist a binary file to the blob storage`}{`, obtain `}{`a temporary downloadable URL`}{` and return an `}{`HTTP Redirect response`}{` to the file with this URL. Below is a simple code snippet to demonstrate that.`}

\n
{`const fileLocation = '/private-dir/large-image.png'\nconst files = await Files.init()\nawait files.write(fileLocation, fileContent)\n\n// Generate a presigned URL of the file that is valid for 60 seconds only\nconst presignUrl = await files.generatePresignURL(fileLocation, { expiryInSeconds: 60 })\n\nreturn {\n  headers: { location: presignUrl }, \n  statusCode: 302\n}\n`}
\n

{`Implementing a move operation for the App Builder Files SDK`}

\n

{`While handling large files within a Runtime action using `}{`App Builder Files SDK`}{`, you might have the need to move those files to another location in the underlying cloud storage, e.g. for archiving purpose when computing is over.`}

\n

{`We have decided until now to not expose a move operation in our abstraction, for the two main following reasons:`}

\n
    \n
  • {`Some cloud storage APIs do not provide an atomic move operation, meaning that there is a tradeoff between abstraction and consistency. Users might expect that files operations on single files are atomic. Operations on folders are not atomic neither.`}
  • \n
  • {`The implementation of such a feature is a two-liner, which makes it simple enough to implement and test the abstraction at application level`}
  • \n
\n

{`This is our recommendation to implement the move operation at application level by using the `}{`App Builder Files SDK`}{` primitives:`}

\n
{`/**\n * Note: this operation is not atomic.\n * Moves files from one location to another in the remote storage. \n *  \n * @param {Files} files the files instance\n * @param {string} src source file/folder\n * @param {string} dest destination file/folder\n * @param {object} [options={}] move options\n * @param {Function} [options.progressCallback] a function that will be called every\n *   time the operation completes on a single file, the srcPath and destPath to the moved\n *   file are passed as argument to the callback \\`progressCallback(srcPath, destPath)\\`\n */\nasync function move (files, src, dest, options = {}) {\n  try {\n    const res = await files.copy(src, dest, { progressCallback: options.progressCallback })\n    await files.delete(src)\n    return res\n  } catch (e) {\n    e.message = \\`Move operation failed, reason: \\${e.message}\\`\n    throw e\n  }\n}\n`}
\n

{`Here are some usage examples:`}

\n
{`const files = await Files.init()\nawait move(files, 'my/remote/src/folder/', 'my/remote/dest/')\nawait move(files, 'my/remote/src/folder/file.txt', 'my/remote/dest/file2.md') // will move and rename the file\nawait move(files, 'my/remote/src/folder/file.txt', 'my/remote/dest/') // will move file.txt to dest folder\nawait move(files, 'my/remote/src/folder/', 'my/remote/dest/') // move folder to the dest folder\nawait move(files, 'my/remote/folder/', 'my/remote/dest') // will rename folder to dest\n`}
\n\n
;\n}\n;\nMDXContent.isMDXComponent = true;\n "],"names":["_frontmatter","layoutProps","MDXLayout","DefaultLayout","MDXContent","components","props","mdxType","parentName","isMDXComponent"],"sourceRoot":""} \ No newline at end of file diff --git a/component---src-pages-guides-tips-tricks-md-76b2d98659179f02cb96.js b/component---src-pages-guides-tips-tricks-md-76b2d98659179f02cb96.js new file mode 100644 index 000000000..0bd51833e --- /dev/null +++ b/component---src-pages-guides-tips-tricks-md-76b2d98659179f02cb96.js @@ -0,0 +1,2 @@ +"use strict";(self.webpackChunkadobe_developer_app_builder=self.webpackChunkadobe_developer_app_builder||[]).push([[1834],{14001:function(e,t,a){a.r(t),a.d(t,{_frontmatter:function(){return l},default:function(){return d}});var o=a(87462),n=a(63366),i=(a(15007),a(64983)),r=a(91515),s=["components"],l={},m={_frontmatter:l},p=r.Z;function d(e){var t=e.components,a=(0,n.Z)(e,s);return(0,i.mdx)(p,(0,o.Z)({},m,a,{components:t,mdxType:"MDXLayout"}),(0,i.mdx)("h1",{id:"tips-and-tricks-for-optimizing-app-builder-apps"},"Tips and Tricks for optimizing App Builder Apps"),(0,i.mdx)("p",null,"There are many areas in a web app where you could optimize the way it works, such as security, performance, and operational cost, to name a few. Here are some tips and tricks to help you gain the most out of your App Builder applications."),(0,i.mdx)("h2",{id:"caching-http-responses"},"Caching HTTP Responses"),(0,i.mdx)("p",null,"This method works extremely well if your action returns some results based on repeated user inputs as query params, e.g. details about an item on a webshop, or visualization of static data. In these cases, your backend action would be invoked once only, and then subsequent requests receive the results directly from the cache by the expiry time. Serving results from cache is not only fast, but also saves the cost of action invocations."),(0,i.mdx)("p",null,"In order to configure the cache, you use the ",(0,i.mdx)("inlineCode",{parentName:"p"},"Cache-Control")," directive. Below is an example of an action that sets the cache with a TTL of 30 minutes. In the response object you will find an entry with ",(0,i.mdx)("inlineCode",{parentName:"p"},"X-GW-Cache: HIT")," or ",(0,i.mdx)("inlineCode",{parentName:"p"},"X-GW-Cache: MISS")," (depending on the answer being returned from cache or not)."),(0,i.mdx)("pre",null,(0,i.mdx)("code",{parentName:"pre",className:"language-javascript"},"async function main (params) {\n return {\n headers: {\n 'Cache-Control': 'max-age=1800'\n },\n statusCode: 200,\n body: { message: 'I am cached for 30 minutes.' }\n }\n}\n")),(0,i.mdx)("p",null,"When you test this functionality for web action using Postman or web browser with developer tools opened, make sure that ",(0,i.mdx)("inlineCode",{parentName:"p"},"Cache-Control")," is not automatically set for all the requests."),(0,i.mdx)("h2",{id:"returning-large-response-payload"},"Returning Large Response Payload"),(0,i.mdx)("p",null,"You can return a ",(0,i.mdx)("a",{parentName:"p",href:"/app-builder/runtime/docs/guides/using/system_settings/"},"response payload of max 1MB")," in an Adobe I/O Runtime action. That is more than enough for the majority of the use cases we have seen so far. However, if your action would return a larger payload than the 1MB limit, we provide a scalable solution with ",(0,i.mdx)("a",{parentName:"p",href:"https://github.com/adobe/aio-lib-files"},"App Builder Files SDK"),". It allows you to ",(0,i.mdx)("a",{parentName:"p",href:"https://github.com/adobe/aio-lib-files/blob/master/doc/api.md#Files+write"},"persist a binary file to the blob storage"),", obtain ",(0,i.mdx)("a",{parentName:"p",href:"https://github.com/adobe/aio-lib-files/blob/master/doc/api.md#Files+generatePresignURL"},"a temporary downloadable URL")," and return an ",(0,i.mdx)("a",{parentName:"p",href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/302"},"HTTP Redirect response")," to the file with this URL. Below is a simple code snippet to demonstrate that."),(0,i.mdx)("pre",null,(0,i.mdx)("code",{parentName:"pre",className:"language-javascript"},"const fileLocation = '/private-dir/large-image.png'\nconst files = await Files.init()\nawait files.write(fileLocation, fileContent)\n\n// Generate a presigned URL of the file that is valid for 60 seconds only\nconst presignUrl = await files.generatePresignURL(fileLocation, { expiryInSeconds: 60 })\n\nreturn {\n headers: { location: presignUrl }, \n statusCode: 302\n}\n")),(0,i.mdx)("h2",{id:"implementing-a-move-operation-for-the-app-builder-files-sdk"},"Implementing a move operation for the App Builder Files SDK"),(0,i.mdx)("p",null,"While handling large files within a Runtime action using ",(0,i.mdx)("a",{parentName:"p",href:"https://github.com/adobe/aio-lib-files"},"App Builder Files SDK"),", you might have the need to move those files to another location in the underlying cloud storage, e.g. for archiving purpose when computing is over."),(0,i.mdx)("p",null,"We have decided until now to not expose a move operation in our abstraction, for the two main following reasons:"),(0,i.mdx)("ul",null,(0,i.mdx)("li",{parentName:"ul"},"Some cloud storage APIs do not provide an atomic move operation, meaning that there is a tradeoff between abstraction and consistency. Users might expect that files operations on single files are atomic. Operations on folders are not atomic neither."),(0,i.mdx)("li",{parentName:"ul"},"The implementation of such a feature is a two-liner, which makes it simple enough to implement and test the abstraction at application level")),(0,i.mdx)("p",null,"This is our recommendation to implement the move operation at application level by using the ",(0,i.mdx)("a",{parentName:"p",href:"https://github.com/adobe/aio-lib-files"},"App Builder Files SDK")," primitives:"),(0,i.mdx)("pre",null,(0,i.mdx)("code",{parentName:"pre",className:"language-javascript"},"/**\n * Note: this operation is not atomic.\n * Moves files from one location to another in the remote storage. \n * \n * @param {Files} files the files instance\n * @param {string} src source file/folder\n * @param {string} dest destination file/folder\n * @param {object} [options={}] move options\n * @param {Function} [options.progressCallback] a function that will be called every\n * time the operation completes on a single file, the srcPath and destPath to the moved\n * file are passed as argument to the callback `progressCallback(srcPath, destPath)`\n */\nasync function move (files, src, dest, options = {}) {\n try {\n const res = await files.copy(src, dest, { progressCallback: options.progressCallback })\n await files.delete(src)\n return res\n } catch (e) {\n e.message = `Move operation failed, reason: ${e.message}`\n throw e\n }\n}\n")),(0,i.mdx)("p",null,"Here are some usage examples:"),(0,i.mdx)("pre",null,(0,i.mdx)("code",{parentName:"pre",className:"language-javascript"},"const files = await Files.init()\nawait move(files, 'my/remote/src/folder/', 'my/remote/dest/')\nawait move(files, 'my/remote/src/folder/file.txt', 'my/remote/dest/file2.md') // will move and rename the file\nawait move(files, 'my/remote/src/folder/file.txt', 'my/remote/dest/') // will move file.txt to dest folder\nawait move(files, 'my/remote/src/folder/', 'my/remote/dest/') // move folder to the dest folder\nawait move(files, 'my/remote/folder/', 'my/remote/dest') // will rename folder to dest\n")))}d.isMDXComponent=!0}}]); +//# sourceMappingURL=component---src-pages-guides-tips-tricks-md-76b2d98659179f02cb96.js.map \ No newline at end of file diff --git a/component---src-pages-guides-tips-tricks-md-76b2d98659179f02cb96.js.map b/component---src-pages-guides-tips-tricks-md-76b2d98659179f02cb96.js.map new file mode 100644 index 000000000..861c8a3b8 --- /dev/null +++ b/component---src-pages-guides-tips-tricks-md-76b2d98659179f02cb96.js.map @@ -0,0 +1 @@ +{"version":3,"file":"component---src-pages-guides-tips-tricks-md-76b2d98659179f02cb96.js","mappings":"4SAQaA,EAAe,CAAC,EACvBC,EAAc,CAClBD,aAAAA,GAEIE,EAAYC,EAAAA,EACH,SAASC,EAAT,GAGZ,IAFDC,EAEC,EAFDA,WACGC,GACF,YACD,OAAO,SAACJ,GAAD,UAAeD,EAAiBK,EAAhC,CAAuCD,WAAYA,EAAYE,QAAQ,eAG5E,eACE,GAAM,mDADR,oDAGA,qQACA,eACE,GAAM,0BADR,2BAGA,8cACA,mEAAoD,uBAAYC,WAAW,KAAvB,iBAApD,kJAA+P,uBAAYA,WAAW,KAAvB,mBAA/P,QAAkU,uBAAYA,WAAW,KAAvB,oBAAlU,iEACA,qBAAK,iBAAMA,WAAW,MAClB,UAAa,uBADZ,+MAYL,+IAAgI,uBAAYA,WAAW,KAAvB,iBAAhI,oDACA,eACE,GAAM,oCADR,qCAGA,uCAAwB,cAAGA,WAAW,IAClC,KAAQ,2DADY,+BAAxB,mOAE2Q,cAAGA,WAAW,IACrR,KAAQ,0CAD+P,yBAF3Q,uBAIyD,cAAGA,WAAW,IACnE,KAAQ,6EAD6C,6CAJzD,aAMmE,cAAGA,WAAW,IAC7E,KAAQ,0FADuD,gCANnE,mBAQ4D,cAAGA,WAAW,IACtE,KAAQ,gEADgD,0BAR5D,oFAWA,qBAAK,iBAAMA,WAAW,MAClB,UAAa,uBADZ,2XAcL,eACE,GAAM,+DADR,gEAGA,+EAAgE,cAAGA,WAAW,IAC1E,KAAQ,0CADoD,yBAAhE,0JAGA,uIACA,oBACE,eAAIA,WAAW,MAAf,8PACA,eAAIA,WAAW,MAAf,kJAEF,mHAAoG,cAAGA,WAAW,IAC9G,KAAQ,0CADwF,yBAApG,iBAGA,qBAAK,iBAAMA,WAAW,MAClB,UAAa,uBADZ,k3BAyBL,oDACA,qBAAK,iBAAMA,WAAW,MAClB,UAAa,uBADZ,2fAWR,CAEDJ,EAAWK,gBAAiB,C","sources":["webpack://adobe-developer-app-builder/./src/pages/guides/tips_tricks.md"],"sourcesContent":["import * as React from 'react'\n /* @jsx mdx */\nimport { mdx } from '@mdx-js/react';\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\n\nimport DefaultLayout from \"/home/runner/work/app-builder/app-builder/node_modules/@adobe/gatsby-theme-aio/src/components/MDXFilter/index.js\";\nexport const _frontmatter = {};\nconst layoutProps = {\n _frontmatter\n};\nconst MDXLayout = DefaultLayout;\nexport default function MDXContent({\n components,\n ...props\n}) {\n return \n\n\n

{`Tips and Tricks for optimizing App Builder Apps`}

\n

{`There are many areas in a web app where you could optimize the way it works, such as security, performance, and operational cost, to name a few. Here are some tips and tricks to help you gain the most out of your App Builder applications.`}

\n

{`Caching HTTP Responses`}

\n

{`This method works extremely well if your action returns some results based on repeated user inputs as query params, e.g. details about an item on a webshop, or visualization of static data. In these cases, your backend action would be invoked once only, and then subsequent requests receive the results directly from the cache by the expiry time. Serving results from cache is not only fast, but also saves the cost of action invocations.`}

\n

{`In order to configure the cache, you use the `}{`Cache-Control`}{` directive. Below is an example of an action that sets the cache with a TTL of 30 minutes. In the response object you will find an entry with `}{`X-GW-Cache: HIT`}{` or `}{`X-GW-Cache: MISS`}{` (depending on the answer being returned from cache or not).`}

\n
{`async function main (params) {\n  return {\n      headers: {\n        'Cache-Control': 'max-age=1800'\n      },\n      statusCode: 200,\n      body: { message: 'I am cached for 30 minutes.' }\n  }\n}\n`}
\n

{`When you test this functionality for web action using Postman or web browser with developer tools opened, make sure that `}{`Cache-Control`}{` is not automatically set for all the requests.`}

\n

{`Returning Large Response Payload`}

\n

{`You can return a `}{`response payload of max 1MB`}{` in an Adobe I/O Runtime action. That is more than enough for the majority of the use cases we have seen so far. However, if your action would return a larger payload than the 1MB limit, we provide a scalable solution with `}{`App Builder Files SDK`}{`. It allows you to `}{`persist a binary file to the blob storage`}{`, obtain `}{`a temporary downloadable URL`}{` and return an `}{`HTTP Redirect response`}{` to the file with this URL. Below is a simple code snippet to demonstrate that.`}

\n
{`const fileLocation = '/private-dir/large-image.png'\nconst files = await Files.init()\nawait files.write(fileLocation, fileContent)\n\n// Generate a presigned URL of the file that is valid for 60 seconds only\nconst presignUrl = await files.generatePresignURL(fileLocation, { expiryInSeconds: 60 })\n\nreturn {\n  headers: { location: presignUrl }, \n  statusCode: 302\n}\n`}
\n

{`Implementing a move operation for the App Builder Files SDK`}

\n

{`While handling large files within a Runtime action using `}{`App Builder Files SDK`}{`, you might have the need to move those files to another location in the underlying cloud storage, e.g. for archiving purpose when computing is over.`}

\n

{`We have decided until now to not expose a move operation in our abstraction, for the two main following reasons:`}

\n
    \n
  • {`Some cloud storage APIs do not provide an atomic move operation, meaning that there is a tradeoff between abstraction and consistency. Users might expect that files operations on single files are atomic. Operations on folders are not atomic neither.`}
  • \n
  • {`The implementation of such a feature is a two-liner, which makes it simple enough to implement and test the abstraction at application level`}
  • \n
\n

{`This is our recommendation to implement the move operation at application level by using the `}{`App Builder Files SDK`}{` primitives:`}

\n
{`/**\n * Note: this operation is not atomic.\n * Moves files from one location to another in the remote storage. \n *  \n * @param {Files} files the files instance\n * @param {string} src source file/folder\n * @param {string} dest destination file/folder\n * @param {object} [options={}] move options\n * @param {Function} [options.progressCallback] a function that will be called every\n *   time the operation completes on a single file, the srcPath and destPath to the moved\n *   file are passed as argument to the callback \\`progressCallback(srcPath, destPath)\\`\n */\nasync function move (files, src, dest, options = {}) {\n  try {\n    const res = await files.copy(src, dest, { progressCallback: options.progressCallback })\n    await files.delete(src)\n    return res\n  } catch (e) {\n    e.message = \\`Move operation failed, reason: \\${e.message}\\`\n    throw e\n  }\n}\n`}
\n

{`Here are some usage examples:`}

\n
{`const files = await Files.init()\nawait move(files, 'my/remote/src/folder/', 'my/remote/dest/')\nawait move(files, 'my/remote/src/folder/file.txt', 'my/remote/dest/file2.md') // will move and rename the file\nawait move(files, 'my/remote/src/folder/file.txt', 'my/remote/dest/') // will move file.txt to dest folder\nawait move(files, 'my/remote/src/folder/', 'my/remote/dest/') // move folder to the dest folder\nawait move(files, 'my/remote/folder/', 'my/remote/dest') // will rename folder to dest\n`}
\n\n
;\n}\n;\nMDXContent.isMDXComponent = true;\n "],"names":["_frontmatter","layoutProps","MDXLayout","DefaultLayout","MDXContent","components","props","mdxType","parentName","isMDXComponent"],"sourceRoot":""} \ No newline at end of file diff --git a/component---src-pages-resources-customer-dashboard-lesson-2-md-eefecb058a6ab28704fb.js b/component---src-pages-resources-customer-dashboard-lesson-2-md-eefecb058a6ab28704fb.js new file mode 100644 index 000000000..55f2a224e --- /dev/null +++ b/component---src-pages-resources-customer-dashboard-lesson-2-md-eefecb058a6ab28704fb.js @@ -0,0 +1,2 @@ +"use strict";(self.webpackChunkadobe_developer_app_builder=self.webpackChunkadobe_developer_app_builder||[]).push([[2009],{91852:function(e,n,t){t.r(n),t.d(n,{_frontmatter:function(){return l},default:function(){return m}});var a=t(87462),r=t(63366),i=(t(15007),t(64983)),o=t(91515),s=["components"],l={},p={_frontmatter:l},d=o.Z;function m(e){var n=e.components,t=(0,r.Z)(e,s);return(0,i.mdx)(d,(0,a.Z)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,i.mdx)("h1",{id:"lesson-2-explore-the-app-builder-app"},"Lesson 2: Explore the App Builder App"),(0,i.mdx)("p",null,"Within the newly created app, you have seen the ",(0,i.mdx)("inlineCode",{parentName:"p"},".env")," file which contains your credentials for running the app. Let's explore further."),(0,i.mdx)("p",null,"Firstly, ",(0,i.mdx)("inlineCode",{parentName:"p"},"package.json")," is the ",(0,i.mdx)("a",{parentName:"p",href:"https://docs.npmjs.com/creating-a-package-json-file"},"crucial part")," of almost every NodeJS project. It contains the list of dependencies, version, reproducible builds, etc."),(0,i.mdx)("p",null,"Then ",(0,i.mdx)("inlineCode",{parentName:"p"},"ext.config.yaml")," in the ",(0,i.mdx)("inlineCode",{parentName:"p"},"src/dx-excshell-1/")," folder is the cockpit of your App Builder app backend. It lists the declaration of serverless actions including name, source files, runtime kind, default params, annotations, and so on. You can find the grammar of writing manifest ",(0,i.mdx)("a",{parentName:"p",href:"https://github.com/apache/openwhisk-wskdeploy/blob/master/docs/programming_guide.md#wskdeploy-utility-by-example"},"here"),"."),(0,i.mdx)("pre",null,(0,i.mdx)("code",{parentName:"pre",className:"language-yaml"},"operations:\n workerProcess:\n - type: action\n impl: dx-asset-compute-worker-1/worker\nhooks:\n post-app-run: adobe-asset-compute devtool\n test: adobe-asset-compute test-worker\nactions: actions\nruntimeManifest:\n packages:\n dx-asset-compute-worker-1:\n license: Apache-2.0\n actions:\n get-profiles:\n function: actions/get-profiles/index.js\n web: 'yes'\n runtime: 'nodejs:18'\n inputs:\n LOG_LEVEL: debug\n tenant: $CAMPAIGN_STANDARD_TENANT\n apiKey: $SERVICE_API_KEY\n annotations:\n require-adobe-auth: true\n final: true\n")),(0,i.mdx)("p",null,"Currently your app only has one action ",(0,i.mdx)("inlineCode",{parentName:"p"},"get-profiles"),"."),(0,i.mdx)("ul",null,(0,i.mdx)("li",{parentName:"ul"},"Source code is at ",(0,i.mdx)("inlineCode",{parentName:"li"},"src/dx-excshell-1/actions/get-profiles/index.js")),(0,i.mdx)("li",{parentName:"ul"},"It is a ",(0,i.mdx)("a",{parentName:"li",href:"/app-builder/runtime/docs/guides/using/creating_actions/#invoking-web-actions"},"web action")),(0,i.mdx)("li",{parentName:"ul"},"The action will be run in the ",(0,i.mdx)("inlineCode",{parentName:"li"},"nodejs:18")," ",(0,i.mdx)("a",{parentName:"li",href:"/app-builder/runtime/docs/guides/reference/runtimes"},"runtime container on I/O Runtime")),(0,i.mdx)("li",{parentName:"ul"},"It has some ",(0,i.mdx)("a",{parentName:"li",href:"/app-builder/runtime/docs/guides/using/creating_actions/#working-with-parameters"},"default params")," such as ",(0,i.mdx)("inlineCode",{parentName:"li"},"LOG_LEVEL"),", ",(0,i.mdx)("inlineCode",{parentName:"li"},"tenant"),", ",(0,i.mdx)("inlineCode",{parentName:"li"},"apiKey"),", which are automatically available in the ",(0,i.mdx)("inlineCode",{parentName:"li"},"params")," object of the action without passing it to the action for every invocation. The ",(0,i.mdx)("inlineCode",{parentName:"li"},"final")," annotation set as ",(0,i.mdx)("inlineCode",{parentName:"li"},"true")," tells that those params are immutable."),(0,i.mdx)("li",{parentName:"ul"},"Setting the ",(0,i.mdx)("inlineCode",{parentName:"li"},"require-adobe-auth")," annotation as ",(0,i.mdx)("inlineCode",{parentName:"li"},"true")," enables this action to be protected by Adobe IMS user token in the request header. Without it, the action will return ",(0,i.mdx)("inlineCode",{parentName:"li"},"401 Unauthorized")," error.")),(0,i.mdx)("p",null,"Now let's have a deeper look at the action's source code."),(0,i.mdx)("pre",null,(0,i.mdx)("code",{parentName:"pre",className:"language-javascript"},"/**\n * This action gets a list of customer profiles the Adobe Campaign Standard API\n */\n\nconst { Core } = require('@adobe/aio-sdk')\nconst { CampaignStandard } = require('@adobe/aio-sdk')\nconst { errorResponse, getBearerToken, stringParameters, checkMissingRequestInputs } = require('../utils')\n\n// main function that will be executed by Adobe I/O Runtime\nasync function main (params) {\n // create a Logger\n const logger = Core.Logger('main', { level: params.LOG_LEVEL || 'info' })\n\n try {\n // 'info' is the default level if not set\n logger.info('Calling the main action')\n\n // log parameters, only if params.LOG_LEVEL === 'debug'\n logger.debug(stringParameters(params))\n\n // check for missing request input parameters and headers\n const requiredParams = ['apiKey', 'tenant']\n const errorMessage = checkMissingRequestInputs(params, requiredParams, ['Authorization'])\n if (errorMessage) {\n // return and log client errors\n return errorResponse(400, errorMessage, logger)\n }\n\n // extract the user Bearer token from the input request parameters\n const token = getBearerToken(params)\n\n // initialize the sdk\n const campaignClient = await CampaignStandard.init(params.tenant, params.apiKey, token)\n\n // get profiles from Campaign Standard\n const profiles = await campaignClient.getAllProfiles()\n logger.debug('profiles = ' + JSON.stringify(profiles, null, 2))\n const response = {\n statusCode: 200,\n body: profiles\n }\n\n // log the response status code\n logger.info(`${response.statusCode}: successful request`)\n return response\n } catch (error) {\n // log any server errors\n logger.error(error)\n // return with 500\n return errorResponse(500, 'server error', logger)\n }\n}\n\nexports.main = main\n")),(0,i.mdx)("p",null,"What happens here, is that the ",(0,i.mdx)("a",{parentName:"p",href:"https://github.com/apache/openwhisk/blob/master/docs/actions-nodejs.md"},"action")," exposes a ",(0,i.mdx)("inlineCode",{parentName:"p"},"main")," function, which accepts a list of params from the client. It checks that required params for using the Campaign Standard SDK are present in this list, including the ",(0,i.mdx)("inlineCode",{parentName:"p"},"Authorization")," header for authentication against Adobe IMS.",(0,i.mdx)("br",{parentName:"p"}),"\n","An access token is retrieved to initiate the SDK client instance, which is then used to retrieve the list of customer profiles using the ",(0,i.mdx)("a",{parentName:"p",href:"https://docs.adobe.com/content/help/en/campaign-standard/using/working-with-apis/managing-profiles/retrieving-profiles.html"},"getAllProfiles()")," function. Finally the profiles are returned to the client. This whole execution is wrapped within a try-catch block, so that errors are handled appropriately."),(0,i.mdx)("p",null,"Next, let's see how the web UI communicates with the backend. All web assets are placed in the ",(0,i.mdx)("inlineCode",{parentName:"p"},"src/dx-excshell-1/web-src")," folder.",(0,i.mdx)("br",{parentName:"p"}),"\n","Beside a few auto-generated files that are useful for running your app on Adobe Experience Cloud (ExC) Shell, ",(0,i.mdx)("inlineCode",{parentName:"p"},"App.js")," is the extension point of your UI.",(0,i.mdx)("br",{parentName:"p"}),"\n",'By default, it contains 3 pages: Home and About are just static pages showing listing reference docs, and ActionsForm lists all available backend actions, allows you to select the action to be invoke, and once you click on the "invoke" button, it shows the invocation results in the browser console.'),(0,i.mdx)("pre",null,(0,i.mdx)("code",{parentName:"pre",className:"language-javascript"},"\n \n \n \n \n \n \n \n \n \n \n \n\n")))}m.isMDXComponent=!0}}]); +//# sourceMappingURL=component---src-pages-resources-customer-dashboard-lesson-2-md-eefecb058a6ab28704fb.js.map \ No newline at end of file diff --git a/component---src-pages-resources-customer-dashboard-lesson-2-md-eefecb058a6ab28704fb.js.map b/component---src-pages-resources-customer-dashboard-lesson-2-md-eefecb058a6ab28704fb.js.map new file mode 100644 index 000000000..aa88e1b2f --- /dev/null +++ b/component---src-pages-resources-customer-dashboard-lesson-2-md-eefecb058a6ab28704fb.js.map @@ -0,0 +1 @@ +{"version":3,"file":"component---src-pages-resources-customer-dashboard-lesson-2-md-eefecb058a6ab28704fb.js","mappings":"4SAQaA,EAAe,CAAC,EACvBC,EAAc,CAClBD,aAAAA,GAEIE,EAAYC,EAAAA,EACH,SAASC,EAAT,GAGZ,IAFDC,EAEC,EAFDA,WACGC,GACF,YACD,OAAO,SAACJ,GAAD,UAAeD,EAAiBK,EAAhC,CAAuCD,WAAYA,EAAYE,QAAQ,eAG5E,eACE,GAAM,wCADR,0CAGA,sEAAuD,uBAAYC,WAAW,KAAvB,QAAvD,sFACA,+BAAgB,uBAAYA,WAAW,KAAvB,gBAAhB,YAAoF,cAAGA,WAAW,IAC9F,KAAQ,uDADwE,gBAApF,8GAGA,2BAAY,uBAAYA,WAAW,KAAvB,mBAAZ,YAAmF,uBAAYA,WAAW,KAAvB,sBAAnF,4OAA6X,cAAGA,WAAW,IACvY,KAAQ,oHADiX,QAA7X,MAGA,qBAAK,iBAAMA,WAAW,MAClB,UAAa,iBADZ,oqBA2BL,6DAA8C,uBAAYA,WAAW,KAAvB,gBAA9C,MACA,oBACE,eAAIA,WAAW,MAAf,sBAA0C,uBAAYA,WAAW,MAAvB,qDAC1C,eAAIA,WAAW,MAAf,YAAgC,cAAGA,WAAW,KAC1C,KAAQ,iFADoB,gBAGhC,eAAIA,WAAW,MAAf,kCAAsD,uBAAYA,WAAW,MAAvB,aAAtD,KAAiH,cAAGA,WAAW,KAC3H,KAAQ,uDADqG,sCAGjH,eAAIA,WAAW,MAAf,gBAAoC,cAAGA,WAAW,KAC9C,KAAQ,oFADwB,kBAApC,aAEwC,uBAAYA,WAAW,MAAvB,aAFxC,MAEoG,uBAAYA,WAAW,MAAvB,UAFpG,MAE6J,uBAAYA,WAAW,MAAvB,UAF7J,+CAE+P,uBAAYA,WAAW,MAAvB,UAF/P,qFAEuY,uBAAYA,WAAW,MAAvB,SAFvY,uBAEgd,uBAAYA,WAAW,MAAvB,QAFhd,4CAGA,eAAIA,WAAW,MAAf,gBAAoC,uBAAYA,WAAW,MAAvB,sBAApC,mBAAsH,uBAAYA,WAAW,MAAvB,QAAtH,2HAAkS,uBAAYA,WAAW,MAAvB,oBAAlS,aAEF,gFACA,qBAAK,iBAAMA,WAAW,MAClB,UAAa,uBADZ,ozDAyDL,qDAAsC,cAAGA,WAAW,IAChD,KAAQ,0EAD0B,UAAtC,eAEkC,uBAAYA,WAAW,KAAvB,QAFlC,0KAE4P,uBAAYA,WAAW,KAAvB,iBAF5P,iDAEsW,eAAIA,WAAW,MAFrX,kJAG2I,cAAGA,WAAW,IACrJ,KAAQ,+HAD+H,oBAH3I,oKAMA,qHAAsG,uBAAYA,WAAW,KAAvB,6BAAtG,YAAuL,eAAIA,WAAW,MAAtM,uHACgH,uBAAYA,WAAW,KAAvB,UADhH,uCACyM,eAAIA,WAAW,MADxN,qTAGA,qBAAK,iBAAMA,WAAW,MAClB,UAAa,uBADZ,8TAkBR,CAEDJ,EAAWK,gBAAiB,C","sources":["webpack://adobe-developer-app-builder/./src/pages/resources/customer-dashboard/lesson2.md"],"sourcesContent":["import * as React from 'react'\n /* @jsx mdx */\nimport { mdx } from '@mdx-js/react';\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\n\nimport DefaultLayout from \"/home/runner/work/app-builder/app-builder/node_modules/@adobe/gatsby-theme-aio/src/components/MDXFilter/index.js\";\nexport const _frontmatter = {};\nconst layoutProps = {\n _frontmatter\n};\nconst MDXLayout = DefaultLayout;\nexport default function MDXContent({\n components,\n ...props\n}) {\n return \n\n\n

{`Lesson 2: Explore the App Builder App`}

\n

{`Within the newly created app, you have seen the `}{`.env`}{` file which contains your credentials for running the app. Let's explore further.`}

\n

{`Firstly, `}{`package.json`}{` is the `}{`crucial part`}{` of almost every NodeJS project. It contains the list of dependencies, version, reproducible builds, etc.`}

\n

{`Then `}{`ext.config.yaml`}{` in the `}{`src/dx-excshell-1/`}{` folder is the cockpit of your App Builder app backend. It lists the declaration of serverless actions including name, source files, runtime kind, default params, annotations, and so on. You can find the grammar of writing manifest `}{`here`}{`.`}

\n
{`operations:\n  workerProcess:\n    - type: action\n      impl: dx-asset-compute-worker-1/worker\nhooks:\n  post-app-run: adobe-asset-compute devtool\n  test: adobe-asset-compute test-worker\nactions: actions\nruntimeManifest:\n  packages:\n    dx-asset-compute-worker-1:\n      license: Apache-2.0\n      actions:\n        get-profiles:\n          function: actions/get-profiles/index.js\n          web: 'yes'\n          runtime: 'nodejs:18'\n          inputs:\n              LOG_LEVEL: debug\n              tenant: $CAMPAIGN_STANDARD_TENANT\n              apiKey: $SERVICE_API_KEY\n          annotations:\n            require-adobe-auth: true\n            final: true\n`}
\n

{`Currently your app only has one action `}{`get-profiles`}{`.`}

\n
    \n
  • {`Source code is at `}{`src/dx-excshell-1/actions/get-profiles/index.js`}
  • \n
  • {`It is a `}{`web action`}
  • \n
  • {`The action will be run in the `}{`nodejs:18`}{` `}{`runtime container on I/O Runtime`}
  • \n
  • {`It has some `}{`default params`}{` such as `}{`LOG_LEVEL`}{`, `}{`tenant`}{`, `}{`apiKey`}{`, which are automatically available in the `}{`params`}{` object of the action without passing it to the action for every invocation. The `}{`final`}{` annotation set as `}{`true`}{` tells that those params are immutable.`}
  • \n
  • {`Setting the `}{`require-adobe-auth`}{` annotation as `}{`true`}{` enables this action to be protected by Adobe IMS user token in the request header. Without it, the action will return `}{`401 Unauthorized`}{` error.`}
  • \n
\n

{`Now let's have a deeper look at the action's source code.`}

\n
{`/**\n * This action gets a list of customer profiles the Adobe Campaign Standard API\n */\n\nconst { Core } = require('@adobe/aio-sdk')\nconst { CampaignStandard } = require('@adobe/aio-sdk')\nconst { errorResponse, getBearerToken, stringParameters, checkMissingRequestInputs } = require('../utils')\n\n// main function that will be executed by Adobe I/O Runtime\nasync function main (params) {\n  // create a Logger\n  const logger = Core.Logger('main', { level: params.LOG_LEVEL || 'info' })\n\n  try {\n    // 'info' is the default level if not set\n    logger.info('Calling the main action')\n\n    // log parameters, only if params.LOG_LEVEL === 'debug'\n    logger.debug(stringParameters(params))\n\n    // check for missing request input parameters and headers\n    const requiredParams = ['apiKey', 'tenant']\n    const errorMessage = checkMissingRequestInputs(params, requiredParams, ['Authorization'])\n    if (errorMessage) {\n      // return and log client errors\n      return errorResponse(400, errorMessage, logger)\n    }\n\n    // extract the user Bearer token from the input request parameters\n    const token = getBearerToken(params)\n\n    // initialize the sdk\n    const campaignClient = await CampaignStandard.init(params.tenant, params.apiKey, token)\n\n    // get profiles from Campaign Standard\n    const profiles = await campaignClient.getAllProfiles()\n    logger.debug('profiles = ' + JSON.stringify(profiles, null, 2))\n    const response = {\n      statusCode: 200,\n      body: profiles\n    }\n\n    // log the response status code\n    logger.info(\\`\\${response.statusCode}: successful request\\`)\n    return response\n  } catch (error) {\n    // log any server errors\n    logger.error(error)\n    // return with 500\n    return errorResponse(500, 'server error', logger)\n  }\n}\n\nexports.main = main\n`}
\n

{`What happens here, is that the `}{`action`}{` exposes a `}{`main`}{` function, which accepts a list of params from the client. It checks that required params for using the Campaign Standard SDK are present in this list, including the `}{`Authorization`}{` header for authentication against Adobe IMS.`}

{`\n`}{`An access token is retrieved to initiate the SDK client instance, which is then used to retrieve the list of customer profiles using the `}{`getAllProfiles()`}{` function. Finally the profiles are returned to the client. This whole execution is wrapped within a try-catch block, so that errors are handled appropriately.`}

\n

{`Next, let's see how the web UI communicates with the backend. All web assets are placed in the `}{`src/dx-excshell-1/web-src`}{` folder.`}

{`\n`}{`Beside a few auto-generated files that are useful for running your app on Adobe Experience Cloud (ExC) Shell, `}{`App.js`}{` is the extension point of your UI.`}

{`\n`}{`By default, it contains 3 pages: Home and About are just static pages showing listing reference docs, and ActionsForm lists all available backend actions, allows you to select the action to be invoke, and once you click on the \"invoke\" button, it shows the invocation results in the browser console.`}

\n
{`\n  \n    \n      \n    \n    \n      \n    \n    \n      \n    \n  \n\n`}
\n\n
;\n}\n;\nMDXContent.isMDXComponent = true;\n "],"names":["_frontmatter","layoutProps","MDXLayout","DefaultLayout","MDXContent","components","props","mdxType","parentName","isMDXComponent"],"sourceRoot":""} \ No newline at end of file diff --git a/component---src-pages-resources-customer-dashboard-lesson-2-md-f7bc173b5f67f81a1b33.js b/component---src-pages-resources-customer-dashboard-lesson-2-md-f7bc173b5f67f81a1b33.js deleted file mode 100644 index fa4c7dafd..000000000 --- a/component---src-pages-resources-customer-dashboard-lesson-2-md-f7bc173b5f67f81a1b33.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict";(self.webpackChunkadobe_developer_app_builder=self.webpackChunkadobe_developer_app_builder||[]).push([[2009],{91852:function(e,n,t){t.r(n),t.d(n,{_frontmatter:function(){return p},default:function(){return m}});var a=t(87462),r=t(63366),i=(t(15007),t(64983)),o=t(91515),s=["components"],p={},l={_frontmatter:p},d=o.Z;function m(e){var n=e.components,t=(0,r.Z)(e,s);return(0,i.mdx)(d,(0,a.Z)({},l,t,{components:n,mdxType:"MDXLayout"}),(0,i.mdx)("h1",{id:"lesson-2-explore-the-app-builder-app"},"Lesson 2: Explore the App Builder App"),(0,i.mdx)("p",null,"Within the newly created app, you have seen the ",(0,i.mdx)("inlineCode",{parentName:"p"},".env")," file which contains your credentials for running the app. Let's explore further."),(0,i.mdx)("p",null,"Firstly, ",(0,i.mdx)("inlineCode",{parentName:"p"},"package.json")," is the ",(0,i.mdx)("a",{parentName:"p",href:"https://docs.npmjs.com/creating-a-package-json-file"},"crucial part")," of almost every NodeJS project. It contains the list of dependencies, version, reproducible builds, etc."),(0,i.mdx)("p",null,"Then ",(0,i.mdx)("inlineCode",{parentName:"p"},"ext.config.yaml")," in the ",(0,i.mdx)("inlineCode",{parentName:"p"},"src/dx-excshell-1/")," folder is the cockpit of your App Builder app backend. It lists the declaration of serverless actions including name, source files, runtime kind, default params, annotations, and so on. You can find the grammar of writing manifest ",(0,i.mdx)("a",{parentName:"p",href:"https://github.com/apache/openwhisk-wskdeploy/blob/master/docs/programming_guide.md#wskdeploy-utility-by-example"},"here"),"."),(0,i.mdx)("pre",null,(0,i.mdx)("code",{parentName:"pre",className:"language-yaml"},"operations:\n workerProcess:\n - type: action\n impl: dx-asset-compute-worker-1/worker\nhooks:\n post-app-run: adobe-asset-compute devtool\n test: adobe-asset-compute test-worker\nactions: actions\nruntimeManifest:\n packages:\n dx-asset-compute-worker-1:\n license: Apache-2.0\n actions:\n get-profiles:\n function: actions/get-profiles/index.js\n web: 'yes'\n runtime: 'nodejs:14'\n inputs:\n LOG_LEVEL: debug\n tenant: $CAMPAIGN_STANDARD_TENANT\n apiKey: $SERVICE_API_KEY\n annotations:\n require-adobe-auth: true\n final: true\n")),(0,i.mdx)("p",null,"Currently your app only has one action ",(0,i.mdx)("inlineCode",{parentName:"p"},"get-profiles"),"."),(0,i.mdx)("ul",null,(0,i.mdx)("li",{parentName:"ul"},"Source code is at ",(0,i.mdx)("inlineCode",{parentName:"li"},"src/dx-excshell-1/actions/get-profiles/index.js")),(0,i.mdx)("li",{parentName:"ul"},"It is a ",(0,i.mdx)("a",{parentName:"li",href:"/app-builder/apis/experienceplatform/runtime/docs.html#!adobedocs/adobeio-runtime/master/guides/creating_actions.md#invoking-actions"},"web action")),(0,i.mdx)("li",{parentName:"ul"},"The action will be run in the ",(0,i.mdx)("inlineCode",{parentName:"li"},"nodejs:12")," ",(0,i.mdx)("a",{parentName:"li",href:"/app-builder/apis/experienceplatform/runtime/docs.html#!adobedocs/adobeio-runtime/master/reference/runtimes.md"},"runtime container on I/O Runtime")),(0,i.mdx)("li",{parentName:"ul"},"It has some ",(0,i.mdx)("a",{parentName:"li",href:"/app-builder/apis/experienceplatform/runtime/docs.html#!adobedocs/adobeio-runtime/master/guides/creating_actions.md#working-with-parameters"},"default params")," such as ",(0,i.mdx)("inlineCode",{parentName:"li"},"LOG_LEVEL"),", ",(0,i.mdx)("inlineCode",{parentName:"li"},"tenant"),", ",(0,i.mdx)("inlineCode",{parentName:"li"},"apiKey"),", which are automatically available in the ",(0,i.mdx)("inlineCode",{parentName:"li"},"params")," object of the action without passing it to the action for every invocation. The ",(0,i.mdx)("inlineCode",{parentName:"li"},"final")," annotation set as ",(0,i.mdx)("inlineCode",{parentName:"li"},"true")," tells that those params are immutable."),(0,i.mdx)("li",{parentName:"ul"},"Setting the ",(0,i.mdx)("inlineCode",{parentName:"li"},"require-adobe-auth")," annotation as ",(0,i.mdx)("inlineCode",{parentName:"li"},"true")," enables this action to be protected by Adobe IMS user token in the request header. Without it, the action will return ",(0,i.mdx)("inlineCode",{parentName:"li"},"401 Unauthorized")," error.")),(0,i.mdx)("p",null,"Now let's have a deeper look at the action's source code."),(0,i.mdx)("pre",null,(0,i.mdx)("code",{parentName:"pre",className:"language-javascript"},"/**\n * This action gets a list of customer profiles the Adobe Campaign Standard API\n */\n\nconst { Core } = require('@adobe/aio-sdk')\nconst { CampaignStandard } = require('@adobe/aio-sdk')\nconst { errorResponse, getBearerToken, stringParameters, checkMissingRequestInputs } = require('../utils')\n\n// main function that will be executed by Adobe I/O Runtime\nasync function main (params) {\n // create a Logger\n const logger = Core.Logger('main', { level: params.LOG_LEVEL || 'info' })\n\n try {\n // 'info' is the default level if not set\n logger.info('Calling the main action')\n\n // log parameters, only if params.LOG_LEVEL === 'debug'\n logger.debug(stringParameters(params))\n\n // check for missing request input parameters and headers\n const requiredParams = ['apiKey', 'tenant']\n const errorMessage = checkMissingRequestInputs(params, requiredParams, ['Authorization'])\n if (errorMessage) {\n // return and log client errors\n return errorResponse(400, errorMessage, logger)\n }\n\n // extract the user Bearer token from the input request parameters\n const token = getBearerToken(params)\n\n // initialize the sdk\n const campaignClient = await CampaignStandard.init(params.tenant, params.apiKey, token)\n\n // get profiles from Campaign Standard\n const profiles = await campaignClient.getAllProfiles()\n logger.debug('profiles = ' + JSON.stringify(profiles, null, 2))\n const response = {\n statusCode: 200,\n body: profiles\n }\n\n // log the response status code\n logger.info(`${response.statusCode}: successful request`)\n return response\n } catch (error) {\n // log any server errors\n logger.error(error)\n // return with 500\n return errorResponse(500, 'server error', logger)\n }\n}\n\nexports.main = main\n")),(0,i.mdx)("p",null,"What happens here, is that the ",(0,i.mdx)("a",{parentName:"p",href:"https://github.com/apache/openwhisk/blob/master/docs/actions-nodejs.md"},"action")," exposes a ",(0,i.mdx)("inlineCode",{parentName:"p"},"main")," function, which accepts a list of params from the client. It checks that required params for using the Campaign Standard SDK are present in this list, including the ",(0,i.mdx)("inlineCode",{parentName:"p"},"Authorization")," header for authentication against Adobe IMS.",(0,i.mdx)("br",{parentName:"p"}),"\n","An access token is retrieved to initiate the SDK client instance, which is then used to retrieve the list of customer profiles using the ",(0,i.mdx)("a",{parentName:"p",href:"https://docs.adobe.com/content/help/en/campaign-standard/using/working-with-apis/managing-profiles/retrieving-profiles.html"},"getAllProfiles()")," function. Finally the profiles are returned to the client. This whole execution is wrapped within a try-catch block, so that errors are handled appropriately."),(0,i.mdx)("p",null,"Next, let's see how the web UI communicates with the backend. All web assets are placed in the ",(0,i.mdx)("inlineCode",{parentName:"p"},"src/dx-excshell-1/web-src")," folder.",(0,i.mdx)("br",{parentName:"p"}),"\n","Beside a few auto-generated files that are useful for running your app on Adobe Experience Cloud (ExC) Shell, ",(0,i.mdx)("inlineCode",{parentName:"p"},"App.js")," is the extension point of your UI.",(0,i.mdx)("br",{parentName:"p"}),"\n",'By default, it contains 3 pages: Home and About are just static pages showing listing reference docs, and ActionsForm lists all available backend actions, allows you to select the action to be invoke, and once you click on the "invoke" button, it shows the invocation results in the browser console.'),(0,i.mdx)("pre",null,(0,i.mdx)("code",{parentName:"pre",className:"language-javascript"},"\n \n \n \n \n \n \n \n \n \n \n \n\n")))}m.isMDXComponent=!0}}]); -//# sourceMappingURL=component---src-pages-resources-customer-dashboard-lesson-2-md-f7bc173b5f67f81a1b33.js.map \ No newline at end of file diff --git a/component---src-pages-resources-customer-dashboard-lesson-2-md-f7bc173b5f67f81a1b33.js.map b/component---src-pages-resources-customer-dashboard-lesson-2-md-f7bc173b5f67f81a1b33.js.map deleted file mode 100644 index 2a4fc2e67..000000000 --- a/component---src-pages-resources-customer-dashboard-lesson-2-md-f7bc173b5f67f81a1b33.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"component---src-pages-resources-customer-dashboard-lesson-2-md-f7bc173b5f67f81a1b33.js","mappings":"4SAQaA,EAAe,CAAC,EACvBC,EAAc,CAClBD,aAAAA,GAEIE,EAAYC,EAAAA,EACH,SAASC,EAAT,GAGZ,IAFDC,EAEC,EAFDA,WACGC,GACF,YACD,OAAO,SAACJ,GAAD,UAAeD,EAAiBK,EAAhC,CAAuCD,WAAYA,EAAYE,QAAQ,eAG5E,eACE,GAAM,wCADR,0CAGA,sEAAuD,uBAAYC,WAAW,KAAvB,QAAvD,sFACA,+BAAgB,uBAAYA,WAAW,KAAvB,gBAAhB,YAAoF,cAAGA,WAAW,IAC9F,KAAQ,uDADwE,gBAApF,8GAGA,2BAAY,uBAAYA,WAAW,KAAvB,mBAAZ,YAAmF,uBAAYA,WAAW,KAAvB,sBAAnF,4OAA6X,cAAGA,WAAW,IACvY,KAAQ,oHADiX,QAA7X,MAGA,qBAAK,iBAAMA,WAAW,MAClB,UAAa,iBADZ,oqBA2BL,6DAA8C,uBAAYA,WAAW,KAAvB,gBAA9C,MACA,oBACE,eAAIA,WAAW,MAAf,sBAA0C,uBAAYA,WAAW,MAAvB,qDAC1C,eAAIA,WAAW,MAAf,YAAgC,cAAGA,WAAW,KAC1C,KAAQ,wIADoB,gBAGhC,eAAIA,WAAW,MAAf,kCAAsD,uBAAYA,WAAW,MAAvB,aAAtD,KAAiH,cAAGA,WAAW,KAC3H,KAAQ,kHADqG,sCAGjH,eAAIA,WAAW,MAAf,gBAAoC,cAAGA,WAAW,KAC9C,KAAQ,+IADwB,kBAApC,aAEwC,uBAAYA,WAAW,MAAvB,aAFxC,MAEoG,uBAAYA,WAAW,MAAvB,UAFpG,MAE6J,uBAAYA,WAAW,MAAvB,UAF7J,+CAE+P,uBAAYA,WAAW,MAAvB,UAF/P,qFAEuY,uBAAYA,WAAW,MAAvB,SAFvY,uBAEgd,uBAAYA,WAAW,MAAvB,QAFhd,4CAGA,eAAIA,WAAW,MAAf,gBAAoC,uBAAYA,WAAW,MAAvB,sBAApC,mBAAsH,uBAAYA,WAAW,MAAvB,QAAtH,2HAAkS,uBAAYA,WAAW,MAAvB,oBAAlS,aAEF,gFACA,qBAAK,iBAAMA,WAAW,MAClB,UAAa,uBADZ,ozDAyDL,qDAAsC,cAAGA,WAAW,IAChD,KAAQ,0EAD0B,UAAtC,eAEkC,uBAAYA,WAAW,KAAvB,QAFlC,0KAE4P,uBAAYA,WAAW,KAAvB,iBAF5P,iDAEsW,eAAIA,WAAW,MAFrX,kJAG2I,cAAGA,WAAW,IACrJ,KAAQ,+HAD+H,oBAH3I,oKAMA,qHAAsG,uBAAYA,WAAW,KAAvB,6BAAtG,YAAuL,eAAIA,WAAW,MAAtM,uHACgH,uBAAYA,WAAW,KAAvB,UADhH,uCACyM,eAAIA,WAAW,MADxN,qTAGA,qBAAK,iBAAMA,WAAW,MAClB,UAAa,uBADZ,8TAkBR,CAEDJ,EAAWK,gBAAiB,C","sources":["webpack://adobe-developer-app-builder/./src/pages/resources/customer-dashboard/lesson2.md"],"sourcesContent":["import * as React from 'react'\n /* @jsx mdx */\nimport { mdx } from '@mdx-js/react';\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\n\nimport DefaultLayout from \"/home/runner/work/app-builder/app-builder/node_modules/@adobe/gatsby-theme-aio/src/components/MDXFilter/index.js\";\nexport const _frontmatter = {};\nconst layoutProps = {\n _frontmatter\n};\nconst MDXLayout = DefaultLayout;\nexport default function MDXContent({\n components,\n ...props\n}) {\n return \n\n\n

{`Lesson 2: Explore the App Builder App`}

\n

{`Within the newly created app, you have seen the `}{`.env`}{` file which contains your credentials for running the app. Let's explore further.`}

\n

{`Firstly, `}{`package.json`}{` is the `}{`crucial part`}{` of almost every NodeJS project. It contains the list of dependencies, version, reproducible builds, etc.`}

\n

{`Then `}{`ext.config.yaml`}{` in the `}{`src/dx-excshell-1/`}{` folder is the cockpit of your App Builder app backend. It lists the declaration of serverless actions including name, source files, runtime kind, default params, annotations, and so on. You can find the grammar of writing manifest `}{`here`}{`.`}

\n
{`operations:\n  workerProcess:\n    - type: action\n      impl: dx-asset-compute-worker-1/worker\nhooks:\n  post-app-run: adobe-asset-compute devtool\n  test: adobe-asset-compute test-worker\nactions: actions\nruntimeManifest:\n  packages:\n    dx-asset-compute-worker-1:\n      license: Apache-2.0\n      actions:\n        get-profiles:\n          function: actions/get-profiles/index.js\n          web: 'yes'\n          runtime: 'nodejs:14'\n          inputs:\n              LOG_LEVEL: debug\n              tenant: $CAMPAIGN_STANDARD_TENANT\n              apiKey: $SERVICE_API_KEY\n          annotations:\n            require-adobe-auth: true\n            final: true\n`}
\n

{`Currently your app only has one action `}{`get-profiles`}{`.`}

\n
    \n
  • {`Source code is at `}{`src/dx-excshell-1/actions/get-profiles/index.js`}
  • \n
  • {`It is a `}{`web action`}
  • \n
  • {`The action will be run in the `}{`nodejs:12`}{` `}{`runtime container on I/O Runtime`}
  • \n
  • {`It has some `}{`default params`}{` such as `}{`LOG_LEVEL`}{`, `}{`tenant`}{`, `}{`apiKey`}{`, which are automatically available in the `}{`params`}{` object of the action without passing it to the action for every invocation. The `}{`final`}{` annotation set as `}{`true`}{` tells that those params are immutable.`}
  • \n
  • {`Setting the `}{`require-adobe-auth`}{` annotation as `}{`true`}{` enables this action to be protected by Adobe IMS user token in the request header. Without it, the action will return `}{`401 Unauthorized`}{` error.`}
  • \n
\n

{`Now let's have a deeper look at the action's source code.`}

\n
{`/**\n * This action gets a list of customer profiles the Adobe Campaign Standard API\n */\n\nconst { Core } = require('@adobe/aio-sdk')\nconst { CampaignStandard } = require('@adobe/aio-sdk')\nconst { errorResponse, getBearerToken, stringParameters, checkMissingRequestInputs } = require('../utils')\n\n// main function that will be executed by Adobe I/O Runtime\nasync function main (params) {\n  // create a Logger\n  const logger = Core.Logger('main', { level: params.LOG_LEVEL || 'info' })\n\n  try {\n    // 'info' is the default level if not set\n    logger.info('Calling the main action')\n\n    // log parameters, only if params.LOG_LEVEL === 'debug'\n    logger.debug(stringParameters(params))\n\n    // check for missing request input parameters and headers\n    const requiredParams = ['apiKey', 'tenant']\n    const errorMessage = checkMissingRequestInputs(params, requiredParams, ['Authorization'])\n    if (errorMessage) {\n      // return and log client errors\n      return errorResponse(400, errorMessage, logger)\n    }\n\n    // extract the user Bearer token from the input request parameters\n    const token = getBearerToken(params)\n\n    // initialize the sdk\n    const campaignClient = await CampaignStandard.init(params.tenant, params.apiKey, token)\n\n    // get profiles from Campaign Standard\n    const profiles = await campaignClient.getAllProfiles()\n    logger.debug('profiles = ' + JSON.stringify(profiles, null, 2))\n    const response = {\n      statusCode: 200,\n      body: profiles\n    }\n\n    // log the response status code\n    logger.info(\\`\\${response.statusCode}: successful request\\`)\n    return response\n  } catch (error) {\n    // log any server errors\n    logger.error(error)\n    // return with 500\n    return errorResponse(500, 'server error', logger)\n  }\n}\n\nexports.main = main\n`}
\n

{`What happens here, is that the `}{`action`}{` exposes a `}{`main`}{` function, which accepts a list of params from the client. It checks that required params for using the Campaign Standard SDK are present in this list, including the `}{`Authorization`}{` header for authentication against Adobe IMS.`}

{`\n`}{`An access token is retrieved to initiate the SDK client instance, which is then used to retrieve the list of customer profiles using the `}{`getAllProfiles()`}{` function. Finally the profiles are returned to the client. This whole execution is wrapped within a try-catch block, so that errors are handled appropriately.`}

\n

{`Next, let's see how the web UI communicates with the backend. All web assets are placed in the `}{`src/dx-excshell-1/web-src`}{` folder.`}

{`\n`}{`Beside a few auto-generated files that are useful for running your app on Adobe Experience Cloud (ExC) Shell, `}{`App.js`}{` is the extension point of your UI.`}

{`\n`}{`By default, it contains 3 pages: Home and About are just static pages showing listing reference docs, and ActionsForm lists all available backend actions, allows you to select the action to be invoke, and once you click on the \"invoke\" button, it shows the invocation results in the browser console.`}

\n
{`\n  \n    \n      \n    \n    \n      \n    \n    \n      \n    \n  \n\n`}
\n\n
;\n}\n;\nMDXContent.isMDXComponent = true;\n "],"names":["_frontmatter","layoutProps","MDXLayout","DefaultLayout","MDXContent","components","props","mdxType","parentName","isMDXComponent"],"sourceRoot":""} \ No newline at end of file diff --git a/component---src-pages-resources-event-driven-lesson-3-md-85152016b2cedeb468df.js b/component---src-pages-resources-event-driven-lesson-3-md-85152016b2cedeb468df.js new file mode 100644 index 000000000..860973a7f --- /dev/null +++ b/component---src-pages-resources-event-driven-lesson-3-md-85152016b2cedeb468df.js @@ -0,0 +1,2 @@ +"use strict";(self.webpackChunkadobe_developer_app_builder=self.webpackChunkadobe_developer_app_builder||[]).push([[6580],{40796:function(e,n,a){a.r(n),a.d(n,{_frontmatter:function(){return p},default:function(){return m}});var t=a(87462),i=a(63366),o=(a(15007),a(64983)),s=a(91515),r=["components"],p={},d={_frontmatter:p},l=s.Z;function m(e){var n=e.components,a=(0,i.Z)(e,r);return(0,o.mdx)(l,(0,t.Z)({},d,a,{components:n,mdxType:"MDXLayout"}),(0,o.mdx)("h1",{id:"lesson-3-fire-an-event"},"Lesson 3: Fire an Event"),(0,o.mdx)("h2",{id:"fire-event"},"Fire Event"),(0,o.mdx)("p",null,"Once you set up the app and register the event provider, now you can make user click ",(0,o.mdx)("inlineCode",{parentName:"p"},"invoke")," button as fire event, this lesson will walk through the code in ",(0,o.mdx)("inlineCode",{parentName:"p"},"publish-event"),' template, test it on the UI with "invoke" button and see the success response (in this lession using webhook)'),(0,o.mdx)("p",null,"You can choose to use this template code at ",(0,o.mdx)("inlineCode",{parentName:"p"},"/actions/publish-events/index.js")," or create your own code.\nWithin the newly created app, Firstly, set up ",(0,o.mdx)("inlineCode",{parentName:"p"},"package.json")," with the lists of dependencies, version, etc.\nThen ",(0,o.mdx)("inlineCode",{parentName:"p"},"manifest.yml")," lists the declaration of serverless actions including name, source files, runtime kind, default params, annotations, and so on. In this lesson, we will choose to use this template to modify the code to our need."),(0,o.mdx)("p",null,"Note: here put in the ",(0,o.mdx)("inlineCode",{parentName:"p"},"providerId"),",",(0,o.mdx)("inlineCode",{parentName:"p"},"apiKey")," and ",(0,o.mdx)("inlineCode",{parentName:"p"},"eventCode"),"from lesson 2 in the ",(0,o.mdx)("inlineCode",{parentName:"p"},"manifest.yml")," and ",(0,o.mdx)("inlineCode",{parentName:"p"},"orgId"),",",(0,o.mdx)("inlineCode",{parentName:"p"},"accessToken"),"can be passed through ",(0,o.mdx)("inlineCode",{parentName:"p"},"headers")),(0,o.mdx)("p",null,"Below is a sample ",(0,o.mdx)("inlineCode",{parentName:"p"},"app.config.yaml")," "),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre",className:"language-javascript"},"application:\n actions: actions\n web: web-src\n runtimeManifest:\n packages:\n my-app:\n license: Apache-2.0\n actions:\n generic:\n function: actions/generic/index.js\n web: 'yes'\n runtime: 'nodejs:18'\n inputs:\n LOG_LEVEL: debug\n annotations:\n require-adobe-auth: true\n final: true\n publish-events:\n function: actions/publish-events/index.js\n web: 'yes'\n runtime: 'nodejs:18'\n inputs:\n LOG_LEVEL: debug\n apiKey: \n providerId: \n eventCode: \n annotations:\n final: true\n")),(0,o.mdx)("p",null,"Now let's start to take a deeper look the template code: "),(0,o.mdx)("ul",null,(0,o.mdx)("li",{parentName:"ul"},"Source code is at ",(0,o.mdx)("inlineCode",{parentName:"li"},"actions/publish-events/index.js")),(0,o.mdx)("li",{parentName:"ul"},"It is a ",(0,o.mdx)("a",{parentName:"li",href:"/app-builder/runtime/docs/guides/using/creating_actions/#invoking-web-actions"},"web action")),(0,o.mdx)("li",{parentName:"ul"},"The action will be run in the ",(0,o.mdx)("inlineCode",{parentName:"li"},"nodejs:18")," ",(0,o.mdx)("a",{parentName:"li",href:"/app-builder/runtime/docs/guides/reference/runtimes"},"runtime container on I/O Runtime")),(0,o.mdx)("li",{parentName:"ul"},"It has some ",(0,o.mdx)("a",{parentName:"li",href:"/app-builder/runtime/docs/guides/using/creating_actions/#working-with-parameters"},"default params")," such as ",(0,o.mdx)("inlineCode",{parentName:"li"},"LOG_LEVEL"),", you can pass in your ",(0,o.mdx)("inlineCode",{parentName:"li"},"params")," like ",(0,o.mdx)("inlineCode",{parentName:"li"},"apiKey"),", ",(0,o.mdx)("inlineCode",{parentName:"li"},"provideId")," and ",(0,o.mdx)("inlineCode",{parentName:"li"},"eventCode"),"from ",(0,o.mdx)("inlineCode",{parentName:"li"},"manifest.yml"))),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre",className:"language-javascript"},"const { Core, Events } = require('@adobe/aio-sdk')\nconst uuid = require('uuid')\nconst cloudEventV1 = require('cloudevents-sdk/v1')\nconst { errorResponse, getBearerToken, stringParameters, checkMissingRequestInputs } = require('../utils')\n\n// main function that will be executed by Adobe I/O Runtime\nasync function main (params) {\n // create a Logger\n const logger = Core.Logger('main', { level: params.LOG_LEVEL || 'info' })\n\n try {\n // 'info' is the default level if not set\n logger.info('Calling the main action')\n\n // log parameters, only if params.LOG_LEVEL === 'debug'\n logger.debug(stringParameters(params))\n\n // check for missing request input parameters and headers\n const requiredParams = ['apiKey', 'providerId', 'eventCode', 'payload']\n const requiredHeaders = ['Authorization', 'x-gw-ims-org-id']\n const errorMessage = checkMissingRequestInputs(params, requiredParams, requiredHeaders)\n if (errorMessage) {\n // return and log client errors\n return errorResponse(400, errorMessage, logger)\n }\n\n // extract the user Bearer token from the Authorization header\n const token = getBearerToken(params)\n\n \n // initialize the client\n const orgId = params.__ow_headers['x-gw-ims-org-id']\n const eventsClient = await Events.init(orgId, params.apiKey, token)\n\n // Create cloud event for the given payload\n const cloudEvent = createCloudEvent(params.providerId, params.eventCode, params.payload)\n\n // Publish to I/O Events\n const published = await eventsClient.publishEvent(cloudEvent)\n let statusCode = 200\n if (published === 'OK') {\n logger.info('Published successfully to I/O Events')\n } else if (published === undefined) {\n logger.info('Published to I/O Events but there were not interested registrations')\n statusCode = 204\n }\n const response = {\n statusCode: statusCode,\n }\n\n // log the response status code\n logger.info(`${response.statusCode}: successful request`)\n return response\n } catch (error) {\n // log any server errors\n logger.error(error)\n // return with 500\n return errorResponse(500, 'server error', logger)\n }\n}\n\nfunction createCloudEvent(providerId, eventCode, payload) {\n let cloudevent = cloudEventV1.event()\n .data(payload)\n .source('urn:uuid:' + providerId)\n .type(eventCode)\n .id(uuid.v4())\n return cloudevent.format()\n}\nexports.main = main\n\n")),(0,o.mdx)("p",null,"What happens here is that the action exposes a ",(0,o.mdx)("inlineCode",{parentName:"p"},"main")," function, which accepts a list of params from the client. It checks the required params for using the ",(0,o.mdx)("inlineCode",{parentName:"p"},"cloudevents-sdk"),". "),(0,o.mdx)("p",null,"You can run the App Builder app locally by execute the below command with AIO CLI:"),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre",className:"language-bash"},"aio app run\n")),(0,o.mdx)("p",null,"This command will deploy the ",(0,o.mdx)("inlineCode",{parentName:"p"},"publish-event")," action into I/O Runtime, and spins up a local instance for the UI. When the app is up and running, it can be seen at ",(0,o.mdx)("inlineCode",{parentName:"p"},"https://localhost:9080"),". You should be able to see the UI of the app and it is also possible to access the app from ExC Shell: ",(0,o.mdx)("inlineCode",{parentName:"p"},"https://experience.adobe.com/?devMode=true#/apps/?localDevUrl=https://localhost:9080"),". You might be asked to log in using your Adobe ID. When the website is opened, the UI is almost similar to what you see when deployed on localhost, except the ExC Shell on top of the UI."),(0,o.mdx)("p",null,"Once you are satisfied with your app, you can deploy your app by run below command:"),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre",className:"language-bash"},"aio app deploy\n")),(0,o.mdx)("p",null,"This command will deploy the app to your namespace, you will get the URL like\n",(0,o.mdx)("inlineCode",{parentName:"p"},"https://.adobeio-static.net/-0.0.1/index.html"),"\nand you will see your deployed link in the terminal"),(0,o.mdx)("p",null,"Next, let's see how the web UI communicates with the backend. In ",(0,o.mdx)("inlineCode",{parentName:"p"},"web-src/src/components")," we already provide a template of UI.\nAfter you select the actions to ",(0,o.mdx)("inlineCode",{parentName:"p"},"publish-events")," and then click the ",(0,o.mdx)("inlineCode",{parentName:"p"},"invoke")," button, it will invoke the action. In the action, it will send out the event. When you invoke, you could also add actual params, in this example, we add ",(0,o.mdx)("inlineCode",{parentName:"p"},'{"payload": "you got a like"}'),", in the webhook result, you will see the payload showed in ",(0,o.mdx)("inlineCode",{parentName:"p"},'{"data": "you got a like"}'),"."),(0,o.mdx)("p",null,"Note: Here I use the webhook tool ",(0,o.mdx)("a",{parentName:"p",href:"https://io-webhook.herokuapp.com/"},"here")," to generate a webhook link and put this webhook to the console integration. You can use other webhook tool as discussed in lession 4. "),(0,o.mdx)("p",null,(0,o.mdx)("span",{parentName:"p",className:"gatsby-resp-image-wrapper",style:{position:"relative",display:"block",marginLeft:"auto",marginRight:"auto",maxWidth:"859px"}},"\n ",(0,o.mdx)("span",{parentName:"span",className:"gatsby-resp-image-background-image",style:{paddingBottom:"66.25%",position:"relative",bottom:"0",left:"0",display:"block",transition:"opacity 0.5s 0.5s",pointerEvents:"none"}}),"\n ",(0,o.mdx)("picture",{parentName:"span"},"\n ",(0,o.mdx)("source",{parentName:"picture",srcSet:["/app-builder/static/8ea42fdde5505baa31fd8567f1de86f6/5530d/template-ui.webp 320w","/app-builder/static/8ea42fdde5505baa31fd8567f1de86f6/0c8fb/template-ui.webp 640w","/app-builder/static/8ea42fdde5505baa31fd8567f1de86f6/56b7d/template-ui.webp 859w"],sizes:"(max-width: 859px) 100vw, 859px",type:"image/webp"}),"\n ",(0,o.mdx)("source",{parentName:"picture",srcSet:["/app-builder/static/8ea42fdde5505baa31fd8567f1de86f6/dd4a7/template-ui.png 320w","/app-builder/static/8ea42fdde5505baa31fd8567f1de86f6/0f09e/template-ui.png 640w","/app-builder/static/8ea42fdde5505baa31fd8567f1de86f6/757fa/template-ui.png 859w"],sizes:"(max-width: 859px) 100vw, 859px",type:"image/png"}),"\n ",(0,o.mdx)("img",{parentName:"picture",className:"gatsby-resp-image-image",src:"/app-builder/static/8ea42fdde5505baa31fd8567f1de86f6/757fa/template-ui.png",alt:"templateui",title:"templateui",loading:"lazy",style:{width:"100%",height:"100%",margin:"0",verticalAlign:"middle",position:"absolute",opacity:"0",transition:"opacity 0.5s",color:"inherit",boxShadow:"inset 0px 0px 0px 400px none",top:"0",left:"0"}}),"\n "),"\n ")),(0,o.mdx)("p",null,(0,o.mdx)("span",{parentName:"p",className:"gatsby-resp-image-wrapper",style:{position:"relative",display:"block",marginLeft:"auto",marginRight:"auto",maxWidth:"1227px"}},"\n ",(0,o.mdx)("span",{parentName:"span",className:"gatsby-resp-image-background-image",style:{paddingBottom:"87.1875%",position:"relative",bottom:"0",left:"0",display:"block",transition:"opacity 0.5s 0.5s",pointerEvents:"none"}}),"\n ",(0,o.mdx)("picture",{parentName:"span"},"\n ",(0,o.mdx)("source",{parentName:"picture",srcSet:["/app-builder/static/9aa637622ca2f5a894adc08479ce48d9/5530d/event-webhook-result.webp 320w","/app-builder/static/9aa637622ca2f5a894adc08479ce48d9/0c8fb/event-webhook-result.webp 640w","/app-builder/static/9aa637622ca2f5a894adc08479ce48d9/4c2fa/event-webhook-result.webp 1227w"],sizes:"(max-width: 1227px) 100vw, 1227px",type:"image/webp"}),"\n ",(0,o.mdx)("source",{parentName:"picture",srcSet:["/app-builder/static/9aa637622ca2f5a894adc08479ce48d9/dd4a7/event-webhook-result.png 320w","/app-builder/static/9aa637622ca2f5a894adc08479ce48d9/0f09e/event-webhook-result.png 640w","/app-builder/static/9aa637622ca2f5a894adc08479ce48d9/b00dd/event-webhook-result.png 1227w"],sizes:"(max-width: 1227px) 100vw, 1227px",type:"image/png"}),"\n ",(0,o.mdx)("img",{parentName:"picture",className:"gatsby-resp-image-image",src:"/app-builder/static/9aa637622ca2f5a894adc08479ce48d9/b00dd/event-webhook-result.png",alt:"eventresult",title:"eventresult",loading:"lazy",style:{width:"100%",height:"100%",margin:"0",verticalAlign:"middle",position:"absolute",opacity:"0",transition:"opacity 0.5s",color:"inherit",boxShadow:"inset 0px 0px 0px 400px none",top:"0",left:"0"}}),"\n "),"\n ")))}m.isMDXComponent=!0}}]); +//# sourceMappingURL=component---src-pages-resources-event-driven-lesson-3-md-85152016b2cedeb468df.js.map \ No newline at end of file diff --git a/component---src-pages-resources-event-driven-lesson-3-md-85152016b2cedeb468df.js.map b/component---src-pages-resources-event-driven-lesson-3-md-85152016b2cedeb468df.js.map new file mode 100644 index 000000000..365dfc1a6 --- /dev/null +++ b/component---src-pages-resources-event-driven-lesson-3-md-85152016b2cedeb468df.js.map @@ -0,0 +1 @@ +{"version":3,"file":"component---src-pages-resources-event-driven-lesson-3-md-85152016b2cedeb468df.js","mappings":"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","sources":["webpack://adobe-developer-app-builder/./src/pages/resources/event-driven/lesson3.md"],"sourcesContent":["import * as React from 'react'\n /* @jsx mdx */\nimport { mdx } from '@mdx-js/react';\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\n\nimport DefaultLayout from \"/home/runner/work/app-builder/app-builder/node_modules/@adobe/gatsby-theme-aio/src/components/MDXFilter/index.js\";\nexport const _frontmatter = {};\nconst layoutProps = {\n _frontmatter\n};\nconst MDXLayout = DefaultLayout;\nexport default function MDXContent({\n components,\n ...props\n}) {\n return \n\n\n

{`Lesson 3: Fire an Event`}

\n

{`Fire Event`}

\n

{`Once you set up the app and register the event provider, now you can make user click `}{`invoke`}{` button as fire event, this lesson will walk through the code in `}{`publish-event`}{` template, test it on the UI with \"invoke\" button and see the success response (in this lession using webhook)`}

\n

{`You can choose to use this template code at `}{`/actions/publish-events/index.js`}{` or create your own code.\nWithin the newly created app, Firstly, set up `}{`package.json`}{` with the lists of dependencies, version, etc.\nThen `}{`manifest.yml`}{` lists the declaration of serverless actions including name, source files, runtime kind, default params, annotations, and so on. In this lesson, we will choose to use this template to modify the code to our need.`}

\n

{`Note: here put in the `}{`providerId`}{`,`}{`apiKey`}{` and `}{`eventCode`}{`from lesson 2 in the `}{`manifest.yml`}{` and `}{`orgId`}{`,`}{`accessToken`}{`can be passed through `}{`headers`}

\n

{`Below is a sample `}{`app.config.yaml`}{` `}

\n
{`application:\n  actions: actions\n  web: web-src\n  runtimeManifest:\n    packages:\n      my-app:\n        license: Apache-2.0\n        actions:\n          generic:\n            function: actions/generic/index.js\n            web: 'yes'\n            runtime: 'nodejs:18'\n            inputs:\n              LOG_LEVEL: debug\n            annotations:\n              require-adobe-auth: true\n              final: true\n      publish-events:\n        function: actions/publish-events/index.js\n        web: 'yes'\n        runtime: 'nodejs:18'\n        inputs:\n          LOG_LEVEL: debug\n          apiKey: \n          providerId: \n          eventCode: \n        annotations:\n          final: true\n`}
\n

{`Now let's start to take a deeper look the template code: `}

\n
    \n
  • {`Source code is at `}{`actions/publish-events/index.js`}
  • \n
  • {`It is a `}{`web action`}
  • \n
  • {`The action will be run in the `}{`nodejs:18`}{` `}{`runtime container on I/O Runtime`}
  • \n
  • {`It has some `}{`default params`}{` such as `}{`LOG_LEVEL`}{`, you can pass in your `}{`params`}{` like `}{`apiKey`}{`, `}{`provideId`}{` and `}{`eventCode`}{`from `}{`manifest.yml`}
  • \n
\n
{`const { Core, Events } = require('@adobe/aio-sdk')\nconst uuid = require('uuid')\nconst cloudEventV1 = require('cloudevents-sdk/v1')\nconst { errorResponse, getBearerToken, stringParameters, checkMissingRequestInputs } = require('../utils')\n\n// main function that will be executed by Adobe I/O Runtime\nasync function main (params) {\n  // create a Logger\n  const logger = Core.Logger('main', { level: params.LOG_LEVEL || 'info' })\n\n  try {\n    // 'info' is the default level if not set\n    logger.info('Calling the main action')\n\n    // log parameters, only if params.LOG_LEVEL === 'debug'\n    logger.debug(stringParameters(params))\n\n    // check for missing request input parameters and headers\n    const requiredParams = ['apiKey', 'providerId', 'eventCode', 'payload']\n    const requiredHeaders = ['Authorization', 'x-gw-ims-org-id']\n    const errorMessage = checkMissingRequestInputs(params, requiredParams, requiredHeaders)\n    if (errorMessage) {\n      // return and log client errors\n      return errorResponse(400, errorMessage, logger)\n    }\n\n    // extract the user Bearer token from the Authorization header\n    const token = getBearerToken(params)\n\n    \n    // initialize the client\n    const orgId = params.__ow_headers['x-gw-ims-org-id']\n    const eventsClient = await Events.init(orgId, params.apiKey, token)\n\n    // Create cloud event for the given payload\n    const cloudEvent = createCloudEvent(params.providerId, params.eventCode, params.payload)\n\n    // Publish to I/O Events\n    const published = await eventsClient.publishEvent(cloudEvent)\n    let statusCode = 200\n    if (published === 'OK') {\n      logger.info('Published successfully to I/O Events')\n    } else if (published === undefined) {\n      logger.info('Published to I/O Events but there were not interested registrations')\n      statusCode = 204\n    }\n    const response = {\n      statusCode: statusCode,\n    }\n\n    // log the response status code\n    logger.info(\\`\\${response.statusCode}: successful request\\`)\n    return response\n  } catch (error) {\n    // log any server errors\n    logger.error(error)\n    // return with 500\n    return errorResponse(500, 'server error', logger)\n  }\n}\n\nfunction createCloudEvent(providerId, eventCode, payload) {\n  let cloudevent = cloudEventV1.event()\n    .data(payload)\n    .source('urn:uuid:' + providerId)\n    .type(eventCode)\n    .id(uuid.v4())\n  return cloudevent.format()\n}\nexports.main = main\n\n`}
\n

{`What happens here is that the action exposes a `}{`main`}{` function, which accepts a list of params from the client. It checks the required params for using the `}{`cloudevents-sdk`}{`. `}

\n

{`You can run the App Builder app locally by execute the below command with AIO CLI:`}

\n
{`aio app run\n`}
\n

{`This command will deploy the `}{`publish-event`}{` action into I/O Runtime, and spins up a local instance for the UI. When the app is up and running, it can be seen at `}{`https://localhost:9080`}{`. You should be able to see the UI of the app and it is also possible to access the app from ExC Shell: `}{`https://experience.adobe.com/?devMode=true#/apps/?localDevUrl=https://localhost:9080`}{`. You might be asked to log in using your Adobe ID. When the website is opened, the UI is almost similar to what you see when deployed on localhost, except the ExC Shell on top of the UI.`}

\n

{`Once you are satisfied with your app, you can deploy your app by run below command:`}

\n
{`aio app deploy\n`}
\n

{`This command will deploy the app to your namespace, you will get the URL like\n`}{`https://.adobeio-static.net/-0.0.1/index.html`}{`\nand you will see your deployed link in the terminal`}

\n

{`Next, let's see how the web UI communicates with the backend. In `}{`web-src/src/components`}{` we already provide a template of UI.\nAfter you select the actions to `}{`publish-events`}{` and then click the `}{`invoke`}{` button, it will invoke the action. In the action, it will send out the event. When you invoke, you could also add actual params, in this example, we add `}{`{\"payload\": \"you got a like\"}`}{`, in the webhook result, you will see the payload showed in `}{`{\"data\": \"you got a like\"}`}{`.`}

\n

{`Note: Here I use the webhook tool `}{`here`}{` to generate a webhook link and put this webhook to the console integration. You can use other webhook tool as discussed in lession 4. `}

\n

{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}

\n

{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}

\n\n
;\n}\n;\nMDXContent.isMDXComponent = true;\n "],"names":["_frontmatter","layoutProps","MDXLayout","DefaultLayout","MDXContent","components","props","mdxType","parentName","isMDXComponent"],"sourceRoot":""} \ No newline at end of file diff --git a/component---src-pages-resources-event-driven-lesson-3-md-c82e875c5ffd8a8aaf7c.js b/component---src-pages-resources-event-driven-lesson-3-md-c82e875c5ffd8a8aaf7c.js deleted file mode 100644 index 2416b7c46..000000000 --- a/component---src-pages-resources-event-driven-lesson-3-md-c82e875c5ffd8a8aaf7c.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict";(self.webpackChunkadobe_developer_app_builder=self.webpackChunkadobe_developer_app_builder||[]).push([[6580],{40796:function(e,n,a){a.r(n),a.d(n,{_frontmatter:function(){return p},default:function(){return m}});var t=a(87462),i=a(63366),o=(a(15007),a(64983)),s=a(91515),r=["components"],p={},d={_frontmatter:p},l=s.Z;function m(e){var n=e.components,a=(0,i.Z)(e,r);return(0,o.mdx)(l,(0,t.Z)({},d,a,{components:n,mdxType:"MDXLayout"}),(0,o.mdx)("h1",{id:"lesson-3-fire-an-event"},"Lesson 3: Fire an Event"),(0,o.mdx)("h2",{id:"fire-event"},"Fire Event"),(0,o.mdx)("p",null,"Once you set up the app and register the event provider, now you can make user click ",(0,o.mdx)("inlineCode",{parentName:"p"},"invoke")," button as fire event, this lesson will walk through the code in ",(0,o.mdx)("inlineCode",{parentName:"p"},"publish-event"),' template, test it on the UI with "invoke" button and see the success response (in this lession using webhook)'),(0,o.mdx)("p",null,"You can choose to use this template code at ",(0,o.mdx)("inlineCode",{parentName:"p"},"/actions/publish-events/index.js")," or create your own code.\nWithin the newly created app, Firstly, set up ",(0,o.mdx)("inlineCode",{parentName:"p"},"package.json")," with the lists of dependencies, version, etc.\nThen ",(0,o.mdx)("inlineCode",{parentName:"p"},"manifest.yml")," lists the declaration of serverless actions including name, source files, runtime kind, default params, annotations, and so on. In this lesson, we will choose to use this template to modify the code to our need."),(0,o.mdx)("p",null,"Note: here put in the ",(0,o.mdx)("inlineCode",{parentName:"p"},"providerId"),",",(0,o.mdx)("inlineCode",{parentName:"p"},"apiKey")," and ",(0,o.mdx)("inlineCode",{parentName:"p"},"eventCode"),"from lesson 2 in the ",(0,o.mdx)("inlineCode",{parentName:"p"},"manifest.yml")," and ",(0,o.mdx)("inlineCode",{parentName:"p"},"orgId"),",",(0,o.mdx)("inlineCode",{parentName:"p"},"accessToken"),"can be passed through ",(0,o.mdx)("inlineCode",{parentName:"p"},"headers")),(0,o.mdx)("p",null,"Below is a sample ",(0,o.mdx)("inlineCode",{parentName:"p"},"app.config.yaml")," "),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre",className:"language-javascript"},"application:\n actions: actions\n web: web-src\n runtimeManifest:\n packages:\n my-app:\n license: Apache-2.0\n actions:\n generic:\n function: actions/generic/index.js\n web: 'yes'\n runtime: 'nodejs:14'\n inputs:\n LOG_LEVEL: debug\n annotations:\n require-adobe-auth: true\n final: true\n publish-events:\n function: actions/publish-events/index.js\n web: 'yes'\n runtime: 'nodejs:14'\n inputs:\n LOG_LEVEL: debug\n apiKey: \n providerId: \n eventCode: \n annotations:\n final: true\n")),(0,o.mdx)("p",null,"Now let's start to take a deeper look the template code: "),(0,o.mdx)("ul",null,(0,o.mdx)("li",{parentName:"ul"},"Source code is at ",(0,o.mdx)("inlineCode",{parentName:"li"},"actions/publish-events/index.js")),(0,o.mdx)("li",{parentName:"ul"},"It is a ",(0,o.mdx)("a",{parentName:"li",href:"/app-builder/apis/experienceplatform/runtime/docs.html#!adobedocs/adobeio-runtime/master/guides/creating_actions.md#invoking-actions"},"web action")),(0,o.mdx)("li",{parentName:"ul"},"The action will be run in the ",(0,o.mdx)("inlineCode",{parentName:"li"},"nodejs:12")," ",(0,o.mdx)("a",{parentName:"li",href:"/app-builder/apis/experienceplatform/runtime/docs.html#!adobedocs/adobeio-runtime/master/reference/runtimes.md"},"runtime container on I/O Runtime")),(0,o.mdx)("li",{parentName:"ul"},"It has some ",(0,o.mdx)("a",{parentName:"li",href:"/app-builder/apis/experienceplatform/runtime/docs.html#!adobedocs/adobeio-runtime/master/guides/creating_actions.md#working-with-parameters"},"default params")," such as ",(0,o.mdx)("inlineCode",{parentName:"li"},"LOG_LEVEL"),", you can pass in your ",(0,o.mdx)("inlineCode",{parentName:"li"},"params")," like ",(0,o.mdx)("inlineCode",{parentName:"li"},"apiKey"),", ",(0,o.mdx)("inlineCode",{parentName:"li"},"provideId")," and ",(0,o.mdx)("inlineCode",{parentName:"li"},"eventCode"),"from ",(0,o.mdx)("inlineCode",{parentName:"li"},"manifest.yml"))),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre",className:"language-javascript"},"const { Core, Events } = require('@adobe/aio-sdk')\nconst uuid = require('uuid')\nconst cloudEventV1 = require('cloudevents-sdk/v1')\nconst { errorResponse, getBearerToken, stringParameters, checkMissingRequestInputs } = require('../utils')\n\n// main function that will be executed by Adobe I/O Runtime\nasync function main (params) {\n // create a Logger\n const logger = Core.Logger('main', { level: params.LOG_LEVEL || 'info' })\n\n try {\n // 'info' is the default level if not set\n logger.info('Calling the main action')\n\n // log parameters, only if params.LOG_LEVEL === 'debug'\n logger.debug(stringParameters(params))\n\n // check for missing request input parameters and headers\n const requiredParams = ['apiKey', 'providerId', 'eventCode', 'payload']\n const requiredHeaders = ['Authorization', 'x-gw-ims-org-id']\n const errorMessage = checkMissingRequestInputs(params, requiredParams, requiredHeaders)\n if (errorMessage) {\n // return and log client errors\n return errorResponse(400, errorMessage, logger)\n }\n\n // extract the user Bearer token from the Authorization header\n const token = getBearerToken(params)\n\n \n // initialize the client\n const orgId = params.__ow_headers['x-gw-ims-org-id']\n const eventsClient = await Events.init(orgId, params.apiKey, token)\n\n // Create cloud event for the given payload\n const cloudEvent = createCloudEvent(params.providerId, params.eventCode, params.payload)\n\n // Publish to I/O Events\n const published = await eventsClient.publishEvent(cloudEvent)\n let statusCode = 200\n if (published === 'OK') {\n logger.info('Published successfully to I/O Events')\n } else if (published === undefined) {\n logger.info('Published to I/O Events but there were not interested registrations')\n statusCode = 204\n }\n const response = {\n statusCode: statusCode,\n }\n\n // log the response status code\n logger.info(`${response.statusCode}: successful request`)\n return response\n } catch (error) {\n // log any server errors\n logger.error(error)\n // return with 500\n return errorResponse(500, 'server error', logger)\n }\n}\n\nfunction createCloudEvent(providerId, eventCode, payload) {\n let cloudevent = cloudEventV1.event()\n .data(payload)\n .source('urn:uuid:' + providerId)\n .type(eventCode)\n .id(uuid.v4())\n return cloudevent.format()\n}\nexports.main = main\n\n")),(0,o.mdx)("p",null,"What happens here is that the action exposes a ",(0,o.mdx)("inlineCode",{parentName:"p"},"main")," function, which accepts a list of params from the client. It checks the required params for using the ",(0,o.mdx)("inlineCode",{parentName:"p"},"cloudevents-sdk"),". "),(0,o.mdx)("p",null,"You can run the App Builder app locally by execute the below command with AIO CLI:"),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre",className:"language-bash"},"aio app run\n")),(0,o.mdx)("p",null,"This command will deploy the ",(0,o.mdx)("inlineCode",{parentName:"p"},"publish-event")," action into I/O Runtime, and spins up a local instance for the UI. When the app is up and running, it can be seen at ",(0,o.mdx)("inlineCode",{parentName:"p"},"https://localhost:9080"),". You should be able to see the UI of the app and it is also possible to access the app from ExC Shell: ",(0,o.mdx)("inlineCode",{parentName:"p"},"https://experience.adobe.com/?devMode=true#/apps/?localDevUrl=https://localhost:9080"),". You might be asked to log in using your Adobe ID. When the website is opened, the UI is almost similar to what you see when deployed on localhost, except the ExC Shell on top of the UI."),(0,o.mdx)("p",null,"Once you are satisfied with your app, you can deploy your app by run below command:"),(0,o.mdx)("pre",null,(0,o.mdx)("code",{parentName:"pre",className:"language-bash"},"aio app deploy\n")),(0,o.mdx)("p",null,"This command will deploy the app to your namespace, you will get the URL like\n",(0,o.mdx)("inlineCode",{parentName:"p"},"https://.adobeio-static.net/-0.0.1/index.html"),"\nand you will see your deployed link in the terminal"),(0,o.mdx)("p",null,"Next, let's see how the web UI communicates with the backend. In ",(0,o.mdx)("inlineCode",{parentName:"p"},"web-src/src/components")," we already provide a template of UI.\nAfter you select the actions to ",(0,o.mdx)("inlineCode",{parentName:"p"},"publish-events")," and then click the ",(0,o.mdx)("inlineCode",{parentName:"p"},"invoke")," button, it will invoke the action. In the action, it will send out the event. When you invoke, you could also add actual params, in this example, we add ",(0,o.mdx)("inlineCode",{parentName:"p"},'{"payload": "you got a like"}'),", in the webhook result, you will see the payload showed in ",(0,o.mdx)("inlineCode",{parentName:"p"},'{"data": "you got a like"}'),"."),(0,o.mdx)("p",null,"Note: Here I use the webhook tool ",(0,o.mdx)("a",{parentName:"p",href:"https://io-webhook.herokuapp.com/"},"here")," to generate a webhook link and put this webhook to the console integration. You can use other webhook tool as discussed in lession 4. "),(0,o.mdx)("p",null,(0,o.mdx)("span",{parentName:"p",className:"gatsby-resp-image-wrapper",style:{position:"relative",display:"block",marginLeft:"auto",marginRight:"auto",maxWidth:"859px"}},"\n ",(0,o.mdx)("span",{parentName:"span",className:"gatsby-resp-image-background-image",style:{paddingBottom:"66.25%",position:"relative",bottom:"0",left:"0",display:"block",transition:"opacity 0.5s 0.5s",pointerEvents:"none"}}),"\n ",(0,o.mdx)("picture",{parentName:"span"},"\n ",(0,o.mdx)("source",{parentName:"picture",srcSet:["/app-builder/static/8ea42fdde5505baa31fd8567f1de86f6/5530d/template-ui.webp 320w","/app-builder/static/8ea42fdde5505baa31fd8567f1de86f6/0c8fb/template-ui.webp 640w","/app-builder/static/8ea42fdde5505baa31fd8567f1de86f6/56b7d/template-ui.webp 859w"],sizes:"(max-width: 859px) 100vw, 859px",type:"image/webp"}),"\n ",(0,o.mdx)("source",{parentName:"picture",srcSet:["/app-builder/static/8ea42fdde5505baa31fd8567f1de86f6/dd4a7/template-ui.png 320w","/app-builder/static/8ea42fdde5505baa31fd8567f1de86f6/0f09e/template-ui.png 640w","/app-builder/static/8ea42fdde5505baa31fd8567f1de86f6/757fa/template-ui.png 859w"],sizes:"(max-width: 859px) 100vw, 859px",type:"image/png"}),"\n ",(0,o.mdx)("img",{parentName:"picture",className:"gatsby-resp-image-image",src:"/app-builder/static/8ea42fdde5505baa31fd8567f1de86f6/757fa/template-ui.png",alt:"templateui",title:"templateui",loading:"lazy",style:{width:"100%",height:"100%",margin:"0",verticalAlign:"middle",position:"absolute",opacity:"0",transition:"opacity 0.5s",color:"inherit",boxShadow:"inset 0px 0px 0px 400px none",top:"0",left:"0"}}),"\n "),"\n ")),(0,o.mdx)("p",null,(0,o.mdx)("span",{parentName:"p",className:"gatsby-resp-image-wrapper",style:{position:"relative",display:"block",marginLeft:"auto",marginRight:"auto",maxWidth:"1227px"}},"\n ",(0,o.mdx)("span",{parentName:"span",className:"gatsby-resp-image-background-image",style:{paddingBottom:"87.1875%",position:"relative",bottom:"0",left:"0",display:"block",transition:"opacity 0.5s 0.5s",pointerEvents:"none"}}),"\n ",(0,o.mdx)("picture",{parentName:"span"},"\n ",(0,o.mdx)("source",{parentName:"picture",srcSet:["/app-builder/static/9aa637622ca2f5a894adc08479ce48d9/5530d/event-webhook-result.webp 320w","/app-builder/static/9aa637622ca2f5a894adc08479ce48d9/0c8fb/event-webhook-result.webp 640w","/app-builder/static/9aa637622ca2f5a894adc08479ce48d9/4c2fa/event-webhook-result.webp 1227w"],sizes:"(max-width: 1227px) 100vw, 1227px",type:"image/webp"}),"\n ",(0,o.mdx)("source",{parentName:"picture",srcSet:["/app-builder/static/9aa637622ca2f5a894adc08479ce48d9/dd4a7/event-webhook-result.png 320w","/app-builder/static/9aa637622ca2f5a894adc08479ce48d9/0f09e/event-webhook-result.png 640w","/app-builder/static/9aa637622ca2f5a894adc08479ce48d9/b00dd/event-webhook-result.png 1227w"],sizes:"(max-width: 1227px) 100vw, 1227px",type:"image/png"}),"\n ",(0,o.mdx)("img",{parentName:"picture",className:"gatsby-resp-image-image",src:"/app-builder/static/9aa637622ca2f5a894adc08479ce48d9/b00dd/event-webhook-result.png",alt:"eventresult",title:"eventresult",loading:"lazy",style:{width:"100%",height:"100%",margin:"0",verticalAlign:"middle",position:"absolute",opacity:"0",transition:"opacity 0.5s",color:"inherit",boxShadow:"inset 0px 0px 0px 400px none",top:"0",left:"0"}}),"\n "),"\n ")))}m.isMDXComponent=!0}}]); -//# sourceMappingURL=component---src-pages-resources-event-driven-lesson-3-md-c82e875c5ffd8a8aaf7c.js.map \ No newline at end of file diff --git a/component---src-pages-resources-event-driven-lesson-3-md-c82e875c5ffd8a8aaf7c.js.map b/component---src-pages-resources-event-driven-lesson-3-md-c82e875c5ffd8a8aaf7c.js.map deleted file mode 100644 index d5ec2e3a3..000000000 --- a/component---src-pages-resources-event-driven-lesson-3-md-c82e875c5ffd8a8aaf7c.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"component---src-pages-resources-event-driven-lesson-3-md-c82e875c5ffd8a8aaf7c.js","mappings":"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","sources":["webpack://adobe-developer-app-builder/./src/pages/resources/event-driven/lesson3.md"],"sourcesContent":["import * as React from 'react'\n /* @jsx mdx */\nimport { mdx } from '@mdx-js/react';\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\n\nimport DefaultLayout from \"/home/runner/work/app-builder/app-builder/node_modules/@adobe/gatsby-theme-aio/src/components/MDXFilter/index.js\";\nexport const _frontmatter = {};\nconst layoutProps = {\n _frontmatter\n};\nconst MDXLayout = DefaultLayout;\nexport default function MDXContent({\n components,\n ...props\n}) {\n return \n\n\n

{`Lesson 3: Fire an Event`}

\n

{`Fire Event`}

\n

{`Once you set up the app and register the event provider, now you can make user click `}{`invoke`}{` button as fire event, this lesson will walk through the code in `}{`publish-event`}{` template, test it on the UI with \"invoke\" button and see the success response (in this lession using webhook)`}

\n

{`You can choose to use this template code at `}{`/actions/publish-events/index.js`}{` or create your own code.\nWithin the newly created app, Firstly, set up `}{`package.json`}{` with the lists of dependencies, version, etc.\nThen `}{`manifest.yml`}{` lists the declaration of serverless actions including name, source files, runtime kind, default params, annotations, and so on. In this lesson, we will choose to use this template to modify the code to our need.`}

\n

{`Note: here put in the `}{`providerId`}{`,`}{`apiKey`}{` and `}{`eventCode`}{`from lesson 2 in the `}{`manifest.yml`}{` and `}{`orgId`}{`,`}{`accessToken`}{`can be passed through `}{`headers`}

\n

{`Below is a sample `}{`app.config.yaml`}{` `}

\n
{`application:\n  actions: actions\n  web: web-src\n  runtimeManifest:\n    packages:\n      my-app:\n        license: Apache-2.0\n        actions:\n          generic:\n            function: actions/generic/index.js\n            web: 'yes'\n            runtime: 'nodejs:14'\n            inputs:\n              LOG_LEVEL: debug\n            annotations:\n              require-adobe-auth: true\n              final: true\n      publish-events:\n        function: actions/publish-events/index.js\n        web: 'yes'\n        runtime: 'nodejs:14'\n        inputs:\n          LOG_LEVEL: debug\n          apiKey: \n          providerId: \n          eventCode: \n        annotations:\n          final: true\n`}
\n

{`Now let's start to take a deeper look the template code: `}

\n
    \n
  • {`Source code is at `}{`actions/publish-events/index.js`}
  • \n
  • {`It is a `}{`web action`}
  • \n
  • {`The action will be run in the `}{`nodejs:12`}{` `}{`runtime container on I/O Runtime`}
  • \n
  • {`It has some `}{`default params`}{` such as `}{`LOG_LEVEL`}{`, you can pass in your `}{`params`}{` like `}{`apiKey`}{`, `}{`provideId`}{` and `}{`eventCode`}{`from `}{`manifest.yml`}
  • \n
\n
{`const { Core, Events } = require('@adobe/aio-sdk')\nconst uuid = require('uuid')\nconst cloudEventV1 = require('cloudevents-sdk/v1')\nconst { errorResponse, getBearerToken, stringParameters, checkMissingRequestInputs } = require('../utils')\n\n// main function that will be executed by Adobe I/O Runtime\nasync function main (params) {\n  // create a Logger\n  const logger = Core.Logger('main', { level: params.LOG_LEVEL || 'info' })\n\n  try {\n    // 'info' is the default level if not set\n    logger.info('Calling the main action')\n\n    // log parameters, only if params.LOG_LEVEL === 'debug'\n    logger.debug(stringParameters(params))\n\n    // check for missing request input parameters and headers\n    const requiredParams = ['apiKey', 'providerId', 'eventCode', 'payload']\n    const requiredHeaders = ['Authorization', 'x-gw-ims-org-id']\n    const errorMessage = checkMissingRequestInputs(params, requiredParams, requiredHeaders)\n    if (errorMessage) {\n      // return and log client errors\n      return errorResponse(400, errorMessage, logger)\n    }\n\n    // extract the user Bearer token from the Authorization header\n    const token = getBearerToken(params)\n\n    \n    // initialize the client\n    const orgId = params.__ow_headers['x-gw-ims-org-id']\n    const eventsClient = await Events.init(orgId, params.apiKey, token)\n\n    // Create cloud event for the given payload\n    const cloudEvent = createCloudEvent(params.providerId, params.eventCode, params.payload)\n\n    // Publish to I/O Events\n    const published = await eventsClient.publishEvent(cloudEvent)\n    let statusCode = 200\n    if (published === 'OK') {\n      logger.info('Published successfully to I/O Events')\n    } else if (published === undefined) {\n      logger.info('Published to I/O Events but there were not interested registrations')\n      statusCode = 204\n    }\n    const response = {\n      statusCode: statusCode,\n    }\n\n    // log the response status code\n    logger.info(\\`\\${response.statusCode}: successful request\\`)\n    return response\n  } catch (error) {\n    // log any server errors\n    logger.error(error)\n    // return with 500\n    return errorResponse(500, 'server error', logger)\n  }\n}\n\nfunction createCloudEvent(providerId, eventCode, payload) {\n  let cloudevent = cloudEventV1.event()\n    .data(payload)\n    .source('urn:uuid:' + providerId)\n    .type(eventCode)\n    .id(uuid.v4())\n  return cloudevent.format()\n}\nexports.main = main\n\n`}
\n

{`What happens here is that the action exposes a `}{`main`}{` function, which accepts a list of params from the client. It checks the required params for using the `}{`cloudevents-sdk`}{`. `}

\n

{`You can run the App Builder app locally by execute the below command with AIO CLI:`}

\n
{`aio app run\n`}
\n

{`This command will deploy the `}{`publish-event`}{` action into I/O Runtime, and spins up a local instance for the UI. When the app is up and running, it can be seen at `}{`https://localhost:9080`}{`. You should be able to see the UI of the app and it is also possible to access the app from ExC Shell: `}{`https://experience.adobe.com/?devMode=true#/apps/?localDevUrl=https://localhost:9080`}{`. You might be asked to log in using your Adobe ID. When the website is opened, the UI is almost similar to what you see when deployed on localhost, except the ExC Shell on top of the UI.`}

\n

{`Once you are satisfied with your app, you can deploy your app by run below command:`}

\n
{`aio app deploy\n`}
\n

{`This command will deploy the app to your namespace, you will get the URL like\n`}{`https://.adobeio-static.net/-0.0.1/index.html`}{`\nand you will see your deployed link in the terminal`}

\n

{`Next, let's see how the web UI communicates with the backend. In `}{`web-src/src/components`}{` we already provide a template of UI.\nAfter you select the actions to `}{`publish-events`}{` and then click the `}{`invoke`}{` button, it will invoke the action. In the action, it will send out the event. When you invoke, you could also add actual params, in this example, we add `}{`{\"payload\": \"you got a like\"}`}{`, in the webhook result, you will see the payload showed in `}{`{\"data\": \"you got a like\"}`}{`.`}

\n

{`Note: Here I use the webhook tool `}{`here`}{` to generate a webhook link and put this webhook to the console integration. You can use other webhook tool as discussed in lession 4. `}

\n

{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}

\n

{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}

\n\n
;\n}\n;\nMDXContent.isMDXComponent = true;\n "],"names":["_frontmatter","layoutProps","MDXLayout","DefaultLayout","MDXContent","components","props","mdxType","parentName","isMDXComponent"],"sourceRoot":""} \ No newline at end of file diff --git a/component---src-pages-resources-event-driven-lesson-4-md-79ac71d0982a0dc526e3.js b/component---src-pages-resources-event-driven-lesson-4-md-79ac71d0982a0dc526e3.js deleted file mode 100644 index 70c0940f1..000000000 --- a/component---src-pages-resources-event-driven-lesson-4-md-79ac71d0982a0dc526e3.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict";(self.webpackChunkadobe_developer_app_builder=self.webpackChunkadobe_developer_app_builder||[]).push([[7735],{66785:function(e,a,n){n.r(a),n.d(a,{_frontmatter:function(){return l},default:function(){return c}});var t=n(87462),o=n(63366),i=(n(15007),n(64983)),s=n(91515),r=["components"],l={},p={_frontmatter:l},d=s.Z;function c(e){var a=e.components,n=(0,o.Z)(e,r);return(0,i.mdx)(d,(0,t.Z)({},p,n,{components:a,mdxType:"MDXLayout"}),(0,i.mdx)("h1",{id:"lesson-4-consume-events"},"Lesson 4: Consume Events"),(0,i.mdx)("p",null,"There are three ways one can consume event:"),(0,i.mdx)("ul",null,(0,i.mdx)("li",{parentName:"ul"},"Using Journaling API "),(0,i.mdx)("li",{parentName:"ul"},"Using runtime action "),(0,i.mdx)("li",{parentName:"ul"},"Using webhook URL")),(0,i.mdx)("h2",{id:"option-1-using-journaling-api-to-consume-events"},"Option 1: Using Journaling API to consume events"),(0,i.mdx)("p",null,"For enterprise developers, Adobe offers journaling to consume events. The Adobe I/O Events Journaling API enables enterprise integrations to consume events according to their own cadence and process them in bulk. Unlike webhooks, no additional registration or other configuration is required; every enterprise integration that is registered for events is automatically enabled for journaling. Journaling data is retained for 7 days. "),(0,i.mdx)("p",null,"After you fire event, you should be able to verify your event through journaling ",(0,i.mdx)("inlineCode",{parentName:"p"},"UNIQUE API ENDPOINT")," you get from console by follow below instruction\n",(0,i.mdx)("a",{parentName:"p",href:"/app-builder/events/docs/guides/api/journaling_api/"},"Journaling api"),"\nyou could use ",(0,i.mdx)("inlineCode",{parentName:"p"},"Curl")," command or ",(0,i.mdx)("inlineCode",{parentName:"p"},"POSTMAN")," to call this journaling ",(0,i.mdx)("inlineCode",{parentName:"p"},"UNIQUE API ENDPOINT")," to see your fired event.\nOr you can use ",(0,i.mdx)("a",{parentName:"p",href:"https://github.com/adobe/aio-lib-events/"},"Custom event SDK")," to call Journaling API to retrieve your event."),(0,i.mdx)("h2",{id:"option-2-using-runtime-action"},"Option 2: Using runtime action"),(0,i.mdx)("p",null,"Once you have access to ",(0,i.mdx)("a",{parentName:"p",href:"/app-builder/apis/experienceplatform/runtime.html"},"Adobe I/O Runtime")," (in our case you already have) and you have your ",(0,i.mdx)("a",{parentName:"p",href:"https://api.slack.com/incoming-webhooks"},"slack webhook url defined")," :"),(0,i.mdx)("ul",null,(0,i.mdx)("li",{parentName:"ul"},"Edit the ",(0,i.mdx)("inlineCode",{parentName:"li"},"app.config.yaml")," to add an action called slack ")),(0,i.mdx)("pre",null,(0,i.mdx)("code",{parentName:"pre",className:"language-javascript"}," slack:\n function: actions/slack/index.js\n web: 'yes'\n runtime: 'nodejs:14'\n inputs:\n LOG_LEVEL: debug\n annotations:\n final: true\n")),(0,i.mdx)("p",null,"Add in the actions folder with ",(0,i.mdx)("inlineCode",{parentName:"p"},"actions/slack/index.js")," with below sample code"),(0,i.mdx)("pre",null,(0,i.mdx)("code",{parentName:"pre",className:"language-javascript"},' var request = require(\'request\');\n\n/* default slackwebhook and channel add yours here and replace the TODO below */\n/* this is a sample action for how to receive event and sent a message to slack */\nvar request = require(\'request\');\n\n/* default slackwebhook and channel add yours here and replace the TODO below */\nvar slackWebhook = "";\nvar slackChannel = "";\n\nasync function main (params) {\n \n /* print event detail */\n console.log(\'in main + event detail: \', params.event);\n\n var returnObject = {\n statusCode: 200,\n headers: {\n \'Content-Type\': \'application/json\'\n },\n body: ""\n };\n\n /* handle the challenge */\n if (params.challenge) {\n\n console.log(\'Returning challenge: \' + params.challenge);\n\n returnObject.body = new Buffer(JSON.stringify({\n "challenge": params.challenge\n })).toString(\'base64\');\n\n return returnObject;\n\n } else {\n\n /* we need it to run asynchronously, so we are returning a Promise */\n return new Promise(function (resolve, reject) {\n\n var slackMessage = " Event received: " + JSON.stringify(params);\n\n var payload = {\n "channel": slackChannel,\n "username": "incoming-webhook",\n "text": slackMessage,\n "mrkdwn": true,\n };\n\n var options = {\n method: \'POST\',\n url: slackWebhook,\n headers:\n { \'Content-type\': \'application/json\' },\n body: JSON.stringify(payload)\n };\n\n request(options, function (error, response, body) {\n if (error) {\n\n console.log("ERROR: fail to post " + response);\n\n reject(error);\n\n } else {\n\n console.log ("SUCCESS: posted to slack " + slackMessage);\n\n returnObject.body = new Buffer(JSON.stringify({\n "slackMessage": slackMessage\n })).toString(\'base64\');\n\n resolve(returnObject);\n }\n\n });\n\n });\n\n }\n}\n\nexports.main = main\n')),(0,i.mdx)("p",null,"After you deployed your runtime action, you can verfiy the webhook is working by "),(0,i.mdx)("pre",null,(0,i.mdx)("code",{parentName:"pre",className:"language-bash"},"curl -X POST -H 'Content-type: application/json' --data '{\"text\":\"Hello, World!\"}' https://.adobeio-static.net/api/v1/web/event-demo-0.0.1/slack\n")),(0,i.mdx)("p",null,"In addtion, in developer console, you will be able to see ",(0,i.mdx)("span",{parentName:"p",className:"gatsby-resp-image-wrapper",style:{position:"relative",display:"block",marginLeft:"auto",marginRight:"auto",maxWidth:"1162px"}},"\n ",(0,i.mdx)("span",{parentName:"span",className:"gatsby-resp-image-background-image",style:{paddingBottom:"95.9375%",position:"relative",bottom:"0",left:"0",display:"block",transition:"opacity 0.5s 0.5s",pointerEvents:"none"}}),"\n ",(0,i.mdx)("picture",{parentName:"span"},"\n ",(0,i.mdx)("source",{parentName:"picture",srcSet:["/app-builder/static/05650b02a223dff979b8f998e5627a32/5530d/slack-webhook.webp 320w","/app-builder/static/05650b02a223dff979b8f998e5627a32/0c8fb/slack-webhook.webp 640w","/app-builder/static/05650b02a223dff979b8f998e5627a32/38baa/slack-webhook.webp 1162w"],sizes:"(max-width: 1162px) 100vw, 1162px",type:"image/webp"}),"\n ",(0,i.mdx)("source",{parentName:"picture",srcSet:["/app-builder/static/05650b02a223dff979b8f998e5627a32/dd4a7/slack-webhook.png 320w","/app-builder/static/05650b02a223dff979b8f998e5627a32/0f09e/slack-webhook.png 640w","/app-builder/static/05650b02a223dff979b8f998e5627a32/8283d/slack-webhook.png 1162w"],sizes:"(max-width: 1162px) 100vw, 1162px",type:"image/png"}),"\n ",(0,i.mdx)("img",{parentName:"picture",className:"gatsby-resp-image-image",src:"/app-builder/static/05650b02a223dff979b8f998e5627a32/8283d/slack-webhook.png",alt:"slack webhook",title:"slack webhook",loading:"lazy",style:{width:"100%",height:"100%",margin:"0",verticalAlign:"middle",position:"absolute",opacity:"0",transition:"opacity 0.5s",color:"inherit",boxShadow:"inset 0px 0px 0px 400px none",top:"0",left:"0"}}),"\n "),"\n "),"\nSelect the slack one and save it. Now when you fire event, you should be able to receive a slack message every time people click the like button\n",(0,i.mdx)("span",{parentName:"p",className:"gatsby-resp-image-wrapper",style:{position:"relative",display:"block",marginLeft:"auto",marginRight:"auto",maxWidth:"1059px"}},"\n ",(0,i.mdx)("span",{parentName:"span",className:"gatsby-resp-image-background-image",style:{paddingBottom:"44.375%",position:"relative",bottom:"0",left:"0",display:"block",transition:"opacity 0.5s 0.5s",pointerEvents:"none"}}),"\n ",(0,i.mdx)("picture",{parentName:"span"},"\n ",(0,i.mdx)("source",{parentName:"picture",srcSet:["/app-builder/static/060d428a5cfff6a17a1856c78c7006c0/5530d/slack-message.webp 320w","/app-builder/static/060d428a5cfff6a17a1856c78c7006c0/0c8fb/slack-message.webp 640w","/app-builder/static/060d428a5cfff6a17a1856c78c7006c0/cb660/slack-message.webp 1059w"],sizes:"(max-width: 1059px) 100vw, 1059px",type:"image/webp"}),"\n ",(0,i.mdx)("source",{parentName:"picture",srcSet:["/app-builder/static/060d428a5cfff6a17a1856c78c7006c0/dd4a7/slack-message.png 320w","/app-builder/static/060d428a5cfff6a17a1856c78c7006c0/0f09e/slack-message.png 640w","/app-builder/static/060d428a5cfff6a17a1856c78c7006c0/604b4/slack-message.png 1059w"],sizes:"(max-width: 1059px) 100vw, 1059px",type:"image/png"}),"\n ",(0,i.mdx)("img",{parentName:"picture",className:"gatsby-resp-image-image",src:"/app-builder/static/060d428a5cfff6a17a1856c78c7006c0/604b4/slack-message.png",alt:"slack message",title:"slack message",loading:"lazy",style:{width:"100%",height:"100%",margin:"0",verticalAlign:"middle",position:"absolute",opacity:"0",transition:"opacity 0.5s",color:"inherit",boxShadow:"inset 0px 0px 0px 400px none",top:"0",left:"0"}}),"\n "),"\n ")),(0,i.mdx)("h2",{id:"option-3-using-webhook-to-consume-events"},"Option 3: Using webhook to consume events"),(0,i.mdx)("p",null,"You could configure another event delivery method through console by ",(0,i.mdx)("inlineCode",{parentName:"p"},"Edit Events Registration")," and add webhook "),(0,i.mdx)("p",null,(0,i.mdx)("span",{parentName:"p",className:"gatsby-resp-image-wrapper",style:{position:"relative",display:"block",marginLeft:"auto",marginRight:"auto",maxWidth:"1280px"}},"\n ",(0,i.mdx)("span",{parentName:"span",className:"gatsby-resp-image-background-image",style:{paddingBottom:"56.25%",position:"relative",bottom:"0",left:"0",display:"block",transition:"opacity 0.5s 0.5s",pointerEvents:"none"}}),"\n ",(0,i.mdx)("picture",{parentName:"span"},"\n ",(0,i.mdx)("source",{parentName:"picture",srcSet:["/app-builder/static/c058ebdf894e13c2678d1ebbbaed3e6d/5530d/webhook.webp 320w","/app-builder/static/c058ebdf894e13c2678d1ebbbaed3e6d/0c8fb/webhook.webp 640w","/app-builder/static/c058ebdf894e13c2678d1ebbbaed3e6d/94b1e/webhook.webp 1280w","/app-builder/static/c058ebdf894e13c2678d1ebbbaed3e6d/6e30a/webhook.webp 1549w"],sizes:"(max-width: 1280px) 100vw, 1280px",type:"image/webp"}),"\n ",(0,i.mdx)("source",{parentName:"picture",srcSet:["/app-builder/static/c058ebdf894e13c2678d1ebbbaed3e6d/dd4a7/webhook.png 320w","/app-builder/static/c058ebdf894e13c2678d1ebbbaed3e6d/0f09e/webhook.png 640w","/app-builder/static/c058ebdf894e13c2678d1ebbbaed3e6d/bbbf7/webhook.png 1280w","/app-builder/static/c058ebdf894e13c2678d1ebbbaed3e6d/4596f/webhook.png 1549w"],sizes:"(max-width: 1280px) 100vw, 1280px",type:"image/png"}),"\n ",(0,i.mdx)("img",{parentName:"picture",className:"gatsby-resp-image-image",src:"/app-builder/static/c058ebdf894e13c2678d1ebbbaed3e6d/bbbf7/webhook.png",alt:"webhook",title:"webhook",loading:"lazy",style:{width:"100%",height:"100%",margin:"0",verticalAlign:"middle",position:"absolute",opacity:"0",transition:"opacity 0.5s",color:"inherit",boxShadow:"inset 0px 0px 0px 400px none",top:"0",left:"0"}}),"\n "),"\n ")),(0,i.mdx)("p",null,"Before you can register a webhook, the webhook needs to be online and operational. If not, then the registration will fail. So you need to take care of setting that up first. Your webhook must be hosted on a server. For development, you may use localhost along with a tool like ",(0,i.mdx)("a",{parentName:"p",href:"https://ngrok.com/"},"Ngrok"),"."),(0,i.mdx)("p",null,"Your webhook needs to"),(0,i.mdx)("ul",null,(0,i.mdx)("li",{parentName:"ul"},"be accessible from the internet (localhost won't work)"),(0,i.mdx)("li",{parentName:"ul"},"be reachable over HTTPS"),(0,i.mdx)("li",{parentName:"ul"},'correctly respond to a "challenge" request\nFor more details, follow the link below:\n',(0,i.mdx)("a",{parentName:"li",href:"/app-builder/events/docs/guides/"},"how to use webhook"))),(0,i.mdx)("h2",{id:"lets-test-it-and-fire-events"},"Let's test it, and fire events"),(0,i.mdx)("p",null,"With that,once you fire the event (in our codelab case, click the invoke button) you should see them appearing in above three options:"),(0,i.mdx)("ul",null,(0,i.mdx)("li",{parentName:"ul"},"Through Adobe I/O Journaling API "),(0,i.mdx)("li",{parentName:"ul"},"Get slack message - through slack runtime action webhook"),(0,i.mdx)("li",{parentName:"ul"},"Through webhook URL")))}c.isMDXComponent=!0}}]); -//# sourceMappingURL=component---src-pages-resources-event-driven-lesson-4-md-79ac71d0982a0dc526e3.js.map \ No newline at end of file diff --git a/component---src-pages-resources-event-driven-lesson-4-md-79ac71d0982a0dc526e3.js.map b/component---src-pages-resources-event-driven-lesson-4-md-79ac71d0982a0dc526e3.js.map deleted file mode 100644 index 009f8bf88..000000000 --- a/component---src-pages-resources-event-driven-lesson-4-md-79ac71d0982a0dc526e3.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"component---src-pages-resources-event-driven-lesson-4-md-79ac71d0982a0dc526e3.js","mappings":"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","sources":["webpack://adobe-developer-app-builder/./src/pages/resources/event-driven/lesson4.md"],"sourcesContent":["import * as React from 'react'\n /* @jsx mdx */\nimport { mdx } from '@mdx-js/react';\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\n\nimport DefaultLayout from \"/home/runner/work/app-builder/app-builder/node_modules/@adobe/gatsby-theme-aio/src/components/MDXFilter/index.js\";\nexport const _frontmatter = {};\nconst layoutProps = {\n _frontmatter\n};\nconst MDXLayout = DefaultLayout;\nexport default function MDXContent({\n components,\n ...props\n}) {\n return \n\n\n

{`Lesson 4: Consume Events`}

\n

{`There are three ways one can consume event:`}

\n
    \n
  • {`Using Journaling API `}
  • \n
  • {`Using runtime action `}
  • \n
  • {`Using webhook URL`}
  • \n
\n

{`Option 1: Using Journaling API to consume events`}

\n

{`For enterprise developers, Adobe offers journaling to consume events. The Adobe I/O Events Journaling API enables enterprise integrations to consume events according to their own cadence and process them in bulk. Unlike webhooks, no additional registration or other configuration is required; every enterprise integration that is registered for events is automatically enabled for journaling. Journaling data is retained for 7 days. `}

\n

{`After you fire event, you should be able to verify your event through journaling `}{`UNIQUE API ENDPOINT`}{` you get from console by follow below instruction\n`}{`Journaling api`}{`\nyou could use `}{`Curl`}{` command or `}{`POSTMAN`}{` to call this journaling `}{`UNIQUE API ENDPOINT`}{` to see your fired event.\nOr you can use `}{`Custom event SDK`}{` to call Journaling API to retrieve your event.`}

\n

{`Option 2: Using runtime action`}

\n

{`Once you have access to `}{`Adobe I/O Runtime`}{` (in our case you already have) and you have your `}{`slack webhook url defined`}{` :`}

\n
    \n
  • {`Edit the `}{`app.config.yaml`}{` to add an action called slack `}
  • \n
\n
{` slack:\n        function: actions/slack/index.js\n        web: 'yes'\n        runtime: 'nodejs:14'\n        inputs:\n          LOG_LEVEL: debug\n        annotations:\n          final: true\n`}
\n

{`Add in the actions folder with `}{`actions/slack/index.js`}{` with below sample code`}

\n
{` var request = require('request');\n\n/* default slackwebhook and channel add yours here and replace the TODO below */\n/* this is a sample action for how to receive event and sent a message to slack */\nvar request = require('request');\n\n/* default slackwebhook and channel add yours here and replace the TODO below */\nvar slackWebhook = \"\";\nvar slackChannel = \"\";\n\nasync function main (params) {\n  \n  /* print event detail */\n  console.log('in main + event detail: ', params.event);\n\n  var returnObject = {\n    statusCode: 200,\n    headers: {\n      'Content-Type': 'application/json'\n    },\n    body: \"\"\n  };\n\n  /* handle the challenge */\n  if (params.challenge) {\n\n    console.log('Returning challenge: ' + params.challenge);\n\n    returnObject.body = new Buffer(JSON.stringify({\n      \"challenge\": params.challenge\n    })).toString('base64');\n\n    return returnObject;\n\n  } else {\n\n    /* we need it to run asynchronously, so we are returning a Promise */\n    return new Promise(function (resolve, reject) {\n\n      var slackMessage = \" Event received: \" + JSON.stringify(params);\n\n      var payload = {\n        \"channel\": slackChannel,\n        \"username\": \"incoming-webhook\",\n        \"text\": slackMessage,\n        \"mrkdwn\": true,\n      };\n\n      var options = {\n        method: 'POST',\n        url: slackWebhook,\n        headers:\n            { 'Content-type': 'application/json' },\n        body: JSON.stringify(payload)\n      };\n\n      request(options, function (error, response, body) {\n        if (error) {\n\n          console.log(\"ERROR: fail to post \" + response);\n\n          reject(error);\n\n        } else {\n\n          console.log (\"SUCCESS: posted to slack \" + slackMessage);\n\n          returnObject.body = new Buffer(JSON.stringify({\n            \"slackMessage\": slackMessage\n          })).toString('base64');\n\n          resolve(returnObject);\n        }\n\n      });\n\n    });\n\n  }\n}\n\nexports.main = main\n`}
\n

{`After you deployed your runtime action, you can verfiy the webhook is working by `}

\n
{`curl -X POST -H 'Content-type: application/json' --data '{\"text\":\"Hello, World!\"}' https://.adobeio-static.net/api/v1/web/event-demo-0.0.1/slack\n`}
\n

{`In addtion, in developer console, you will be able to see `}{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}{`\nSelect the slack one and save it. Now when you fire event, you should be able to receive a slack message every time people click the like button\n`}{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}

\n

{`Option 3: Using webhook to consume events`}

\n

{`You could configure another event delivery method through console by `}{`Edit Events Registration`}{` and add webhook `}

\n

{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}

\n

{`Before you can register a webhook, the webhook needs to be online and operational. If not, then the registration will fail. So you need to take care of setting that up first. Your webhook must be hosted on a server. For development, you may use localhost along with a tool like `}{`Ngrok`}{`.`}

\n

{`Your webhook needs to`}

\n
    \n
  • {`be accessible from the internet (localhost won't work)`}
  • \n
  • {`be reachable over HTTPS`}
  • \n
  • {`correctly respond to a \"challenge\" request\nFor more details, follow the link below:\n`}{`how to use webhook`}
  • \n
\n

{`Let's test it, and fire events`}

\n

{`With that,once you fire the event (in our codelab case, click the invoke button) you should see them appearing in above three options:`}

\n
    \n
  • {`Through Adobe I/O Journaling API `}
  • \n
  • {`Get slack message - through slack runtime action webhook`}
  • \n
  • {`Through webhook URL`}
  • \n
\n\n
;\n}\n;\nMDXContent.isMDXComponent = true;\n "],"names":["_frontmatter","layoutProps","MDXLayout","DefaultLayout","MDXContent","components","props","mdxType","parentName","isMDXComponent"],"sourceRoot":""} \ No newline at end of file diff --git a/component---src-pages-resources-event-driven-lesson-4-md-7e789bf584551cda4578.js b/component---src-pages-resources-event-driven-lesson-4-md-7e789bf584551cda4578.js new file mode 100644 index 000000000..ae0769f9b --- /dev/null +++ b/component---src-pages-resources-event-driven-lesson-4-md-7e789bf584551cda4578.js @@ -0,0 +1,2 @@ +"use strict";(self.webpackChunkadobe_developer_app_builder=self.webpackChunkadobe_developer_app_builder||[]).push([[7735],{66785:function(e,a,n){n.r(a),n.d(a,{_frontmatter:function(){return l},default:function(){return c}});var t=n(87462),o=n(63366),i=(n(15007),n(64983)),s=n(91515),r=["components"],l={},p={_frontmatter:l},d=s.Z;function c(e){var a=e.components,n=(0,o.Z)(e,r);return(0,i.mdx)(d,(0,t.Z)({},p,n,{components:a,mdxType:"MDXLayout"}),(0,i.mdx)("h1",{id:"lesson-4-consume-events"},"Lesson 4: Consume Events"),(0,i.mdx)("p",null,"There are three ways one can consume event:"),(0,i.mdx)("ul",null,(0,i.mdx)("li",{parentName:"ul"},"Using Journaling API "),(0,i.mdx)("li",{parentName:"ul"},"Using runtime action "),(0,i.mdx)("li",{parentName:"ul"},"Using webhook URL")),(0,i.mdx)("h2",{id:"option-1-using-journaling-api-to-consume-events"},"Option 1: Using Journaling API to consume events"),(0,i.mdx)("p",null,"For enterprise developers, Adobe offers journaling to consume events. The Adobe I/O Events Journaling API enables enterprise integrations to consume events according to their own cadence and process them in bulk. Unlike webhooks, no additional registration or other configuration is required; every enterprise integration that is registered for events is automatically enabled for journaling. Journaling data is retained for 7 days. "),(0,i.mdx)("p",null,"After you fire event, you should be able to verify your event through journaling ",(0,i.mdx)("inlineCode",{parentName:"p"},"UNIQUE API ENDPOINT")," you get from console by follow below instruction\n",(0,i.mdx)("a",{parentName:"p",href:"/app-builder/events/docs/guides/api/journaling_api/"},"Journaling api"),"\nyou could use ",(0,i.mdx)("inlineCode",{parentName:"p"},"Curl")," command or ",(0,i.mdx)("inlineCode",{parentName:"p"},"POSTMAN")," to call this journaling ",(0,i.mdx)("inlineCode",{parentName:"p"},"UNIQUE API ENDPOINT")," to see your fired event.\nOr you can use ",(0,i.mdx)("a",{parentName:"p",href:"https://github.com/adobe/aio-lib-events/"},"Custom event SDK")," to call Journaling API to retrieve your event."),(0,i.mdx)("h2",{id:"option-2-using-runtime-action"},"Option 2: Using runtime action"),(0,i.mdx)("p",null,"Once you have access to ",(0,i.mdx)("a",{parentName:"p",href:"/app-builder/runtime"},"Adobe I/O Runtime")," (in our case you already have) and you have your ",(0,i.mdx)("a",{parentName:"p",href:"https://api.slack.com/incoming-webhooks"},"slack webhook url defined")," :"),(0,i.mdx)("ul",null,(0,i.mdx)("li",{parentName:"ul"},"Edit the ",(0,i.mdx)("inlineCode",{parentName:"li"},"app.config.yaml")," to add an action called slack ")),(0,i.mdx)("pre",null,(0,i.mdx)("code",{parentName:"pre",className:"language-javascript"}," slack:\n function: actions/slack/index.js\n web: 'yes'\n runtime: 'nodejs:14'\n inputs:\n LOG_LEVEL: debug\n annotations:\n final: true\n")),(0,i.mdx)("p",null,"Add in the actions folder with ",(0,i.mdx)("inlineCode",{parentName:"p"},"actions/slack/index.js")," with below sample code"),(0,i.mdx)("pre",null,(0,i.mdx)("code",{parentName:"pre",className:"language-javascript"},' var request = require(\'request\');\n\n/* default slackwebhook and channel add yours here and replace the TODO below */\n/* this is a sample action for how to receive event and sent a message to slack */\nvar request = require(\'request\');\n\n/* default slackwebhook and channel add yours here and replace the TODO below */\nvar slackWebhook = "";\nvar slackChannel = "";\n\nasync function main (params) {\n \n /* print event detail */\n console.log(\'in main + event detail: \', params.event);\n\n var returnObject = {\n statusCode: 200,\n headers: {\n \'Content-Type\': \'application/json\'\n },\n body: ""\n };\n\n /* handle the challenge */\n if (params.challenge) {\n\n console.log(\'Returning challenge: \' + params.challenge);\n\n returnObject.body = new Buffer(JSON.stringify({\n "challenge": params.challenge\n })).toString(\'base64\');\n\n return returnObject;\n\n } else {\n\n /* we need it to run asynchronously, so we are returning a Promise */\n return new Promise(function (resolve, reject) {\n\n var slackMessage = " Event received: " + JSON.stringify(params);\n\n var payload = {\n "channel": slackChannel,\n "username": "incoming-webhook",\n "text": slackMessage,\n "mrkdwn": true,\n };\n\n var options = {\n method: \'POST\',\n url: slackWebhook,\n headers:\n { \'Content-type\': \'application/json\' },\n body: JSON.stringify(payload)\n };\n\n request(options, function (error, response, body) {\n if (error) {\n\n console.log("ERROR: fail to post " + response);\n\n reject(error);\n\n } else {\n\n console.log ("SUCCESS: posted to slack " + slackMessage);\n\n returnObject.body = new Buffer(JSON.stringify({\n "slackMessage": slackMessage\n })).toString(\'base64\');\n\n resolve(returnObject);\n }\n\n });\n\n });\n\n }\n}\n\nexports.main = main\n')),(0,i.mdx)("p",null,"After you deployed your runtime action, you can verfiy the webhook is working by "),(0,i.mdx)("pre",null,(0,i.mdx)("code",{parentName:"pre",className:"language-bash"},"curl -X POST -H 'Content-type: application/json' --data '{\"text\":\"Hello, World!\"}' https://.adobeio-static.net/api/v1/web/event-demo-0.0.1/slack\n")),(0,i.mdx)("p",null,"In addtion, in developer console, you will be able to see ",(0,i.mdx)("span",{parentName:"p",className:"gatsby-resp-image-wrapper",style:{position:"relative",display:"block",marginLeft:"auto",marginRight:"auto",maxWidth:"1162px"}},"\n ",(0,i.mdx)("span",{parentName:"span",className:"gatsby-resp-image-background-image",style:{paddingBottom:"95.9375%",position:"relative",bottom:"0",left:"0",display:"block",transition:"opacity 0.5s 0.5s",pointerEvents:"none"}}),"\n ",(0,i.mdx)("picture",{parentName:"span"},"\n ",(0,i.mdx)("source",{parentName:"picture",srcSet:["/app-builder/static/05650b02a223dff979b8f998e5627a32/5530d/slack-webhook.webp 320w","/app-builder/static/05650b02a223dff979b8f998e5627a32/0c8fb/slack-webhook.webp 640w","/app-builder/static/05650b02a223dff979b8f998e5627a32/38baa/slack-webhook.webp 1162w"],sizes:"(max-width: 1162px) 100vw, 1162px",type:"image/webp"}),"\n ",(0,i.mdx)("source",{parentName:"picture",srcSet:["/app-builder/static/05650b02a223dff979b8f998e5627a32/dd4a7/slack-webhook.png 320w","/app-builder/static/05650b02a223dff979b8f998e5627a32/0f09e/slack-webhook.png 640w","/app-builder/static/05650b02a223dff979b8f998e5627a32/8283d/slack-webhook.png 1162w"],sizes:"(max-width: 1162px) 100vw, 1162px",type:"image/png"}),"\n ",(0,i.mdx)("img",{parentName:"picture",className:"gatsby-resp-image-image",src:"/app-builder/static/05650b02a223dff979b8f998e5627a32/8283d/slack-webhook.png",alt:"slack webhook",title:"slack webhook",loading:"lazy",style:{width:"100%",height:"100%",margin:"0",verticalAlign:"middle",position:"absolute",opacity:"0",transition:"opacity 0.5s",color:"inherit",boxShadow:"inset 0px 0px 0px 400px none",top:"0",left:"0"}}),"\n "),"\n "),"\nSelect the slack one and save it. Now when you fire event, you should be able to receive a slack message every time people click the like button\n",(0,i.mdx)("span",{parentName:"p",className:"gatsby-resp-image-wrapper",style:{position:"relative",display:"block",marginLeft:"auto",marginRight:"auto",maxWidth:"1059px"}},"\n ",(0,i.mdx)("span",{parentName:"span",className:"gatsby-resp-image-background-image",style:{paddingBottom:"44.375%",position:"relative",bottom:"0",left:"0",display:"block",transition:"opacity 0.5s 0.5s",pointerEvents:"none"}}),"\n ",(0,i.mdx)("picture",{parentName:"span"},"\n ",(0,i.mdx)("source",{parentName:"picture",srcSet:["/app-builder/static/060d428a5cfff6a17a1856c78c7006c0/5530d/slack-message.webp 320w","/app-builder/static/060d428a5cfff6a17a1856c78c7006c0/0c8fb/slack-message.webp 640w","/app-builder/static/060d428a5cfff6a17a1856c78c7006c0/cb660/slack-message.webp 1059w"],sizes:"(max-width: 1059px) 100vw, 1059px",type:"image/webp"}),"\n ",(0,i.mdx)("source",{parentName:"picture",srcSet:["/app-builder/static/060d428a5cfff6a17a1856c78c7006c0/dd4a7/slack-message.png 320w","/app-builder/static/060d428a5cfff6a17a1856c78c7006c0/0f09e/slack-message.png 640w","/app-builder/static/060d428a5cfff6a17a1856c78c7006c0/604b4/slack-message.png 1059w"],sizes:"(max-width: 1059px) 100vw, 1059px",type:"image/png"}),"\n ",(0,i.mdx)("img",{parentName:"picture",className:"gatsby-resp-image-image",src:"/app-builder/static/060d428a5cfff6a17a1856c78c7006c0/604b4/slack-message.png",alt:"slack message",title:"slack message",loading:"lazy",style:{width:"100%",height:"100%",margin:"0",verticalAlign:"middle",position:"absolute",opacity:"0",transition:"opacity 0.5s",color:"inherit",boxShadow:"inset 0px 0px 0px 400px none",top:"0",left:"0"}}),"\n "),"\n ")),(0,i.mdx)("h2",{id:"option-3-using-webhook-to-consume-events"},"Option 3: Using webhook to consume events"),(0,i.mdx)("p",null,"You could configure another event delivery method through console by ",(0,i.mdx)("inlineCode",{parentName:"p"},"Edit Events Registration")," and add webhook "),(0,i.mdx)("p",null,(0,i.mdx)("span",{parentName:"p",className:"gatsby-resp-image-wrapper",style:{position:"relative",display:"block",marginLeft:"auto",marginRight:"auto",maxWidth:"1280px"}},"\n ",(0,i.mdx)("span",{parentName:"span",className:"gatsby-resp-image-background-image",style:{paddingBottom:"56.25%",position:"relative",bottom:"0",left:"0",display:"block",transition:"opacity 0.5s 0.5s",pointerEvents:"none"}}),"\n ",(0,i.mdx)("picture",{parentName:"span"},"\n ",(0,i.mdx)("source",{parentName:"picture",srcSet:["/app-builder/static/c058ebdf894e13c2678d1ebbbaed3e6d/5530d/webhook.webp 320w","/app-builder/static/c058ebdf894e13c2678d1ebbbaed3e6d/0c8fb/webhook.webp 640w","/app-builder/static/c058ebdf894e13c2678d1ebbbaed3e6d/94b1e/webhook.webp 1280w","/app-builder/static/c058ebdf894e13c2678d1ebbbaed3e6d/6e30a/webhook.webp 1549w"],sizes:"(max-width: 1280px) 100vw, 1280px",type:"image/webp"}),"\n ",(0,i.mdx)("source",{parentName:"picture",srcSet:["/app-builder/static/c058ebdf894e13c2678d1ebbbaed3e6d/dd4a7/webhook.png 320w","/app-builder/static/c058ebdf894e13c2678d1ebbbaed3e6d/0f09e/webhook.png 640w","/app-builder/static/c058ebdf894e13c2678d1ebbbaed3e6d/bbbf7/webhook.png 1280w","/app-builder/static/c058ebdf894e13c2678d1ebbbaed3e6d/4596f/webhook.png 1549w"],sizes:"(max-width: 1280px) 100vw, 1280px",type:"image/png"}),"\n ",(0,i.mdx)("img",{parentName:"picture",className:"gatsby-resp-image-image",src:"/app-builder/static/c058ebdf894e13c2678d1ebbbaed3e6d/bbbf7/webhook.png",alt:"webhook",title:"webhook",loading:"lazy",style:{width:"100%",height:"100%",margin:"0",verticalAlign:"middle",position:"absolute",opacity:"0",transition:"opacity 0.5s",color:"inherit",boxShadow:"inset 0px 0px 0px 400px none",top:"0",left:"0"}}),"\n "),"\n ")),(0,i.mdx)("p",null,"Before you can register a webhook, the webhook needs to be online and operational. If not, then the registration will fail. So you need to take care of setting that up first. Your webhook must be hosted on a server. For development, you may use localhost along with a tool like ",(0,i.mdx)("a",{parentName:"p",href:"https://ngrok.com/"},"Ngrok"),"."),(0,i.mdx)("p",null,"Your webhook needs to"),(0,i.mdx)("ul",null,(0,i.mdx)("li",{parentName:"ul"},"be accessible from the internet (localhost won't work)"),(0,i.mdx)("li",{parentName:"ul"},"be reachable over HTTPS"),(0,i.mdx)("li",{parentName:"ul"},'correctly respond to a "challenge" request\nFor more details, follow the link below:\n',(0,i.mdx)("a",{parentName:"li",href:"/app-builder/events/docs/guides/"},"how to use webhook"))),(0,i.mdx)("h2",{id:"lets-test-it-and-fire-events"},"Let's test it, and fire events"),(0,i.mdx)("p",null,"With that,once you fire the event (in our codelab case, click the invoke button) you should see them appearing in above three options:"),(0,i.mdx)("ul",null,(0,i.mdx)("li",{parentName:"ul"},"Through Adobe I/O Journaling API "),(0,i.mdx)("li",{parentName:"ul"},"Get slack message - through slack runtime action webhook"),(0,i.mdx)("li",{parentName:"ul"},"Through webhook URL")))}c.isMDXComponent=!0}}]); +//# sourceMappingURL=component---src-pages-resources-event-driven-lesson-4-md-7e789bf584551cda4578.js.map \ No newline at end of file diff --git a/component---src-pages-resources-event-driven-lesson-4-md-7e789bf584551cda4578.js.map b/component---src-pages-resources-event-driven-lesson-4-md-7e789bf584551cda4578.js.map new file mode 100644 index 000000000..c01aa845b --- /dev/null +++ b/component---src-pages-resources-event-driven-lesson-4-md-7e789bf584551cda4578.js.map @@ -0,0 +1 @@ +{"version":3,"file":"component---src-pages-resources-event-driven-lesson-4-md-7e789bf584551cda4578.js","mappings":"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","sources":["webpack://adobe-developer-app-builder/./src/pages/resources/event-driven/lesson4.md"],"sourcesContent":["import * as React from 'react'\n /* @jsx mdx */\nimport { mdx } from '@mdx-js/react';\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\n\nimport DefaultLayout from \"/home/runner/work/app-builder/app-builder/node_modules/@adobe/gatsby-theme-aio/src/components/MDXFilter/index.js\";\nexport const _frontmatter = {};\nconst layoutProps = {\n _frontmatter\n};\nconst MDXLayout = DefaultLayout;\nexport default function MDXContent({\n components,\n ...props\n}) {\n return \n\n\n

{`Lesson 4: Consume Events`}

\n

{`There are three ways one can consume event:`}

\n
    \n
  • {`Using Journaling API `}
  • \n
  • {`Using runtime action `}
  • \n
  • {`Using webhook URL`}
  • \n
\n

{`Option 1: Using Journaling API to consume events`}

\n

{`For enterprise developers, Adobe offers journaling to consume events. The Adobe I/O Events Journaling API enables enterprise integrations to consume events according to their own cadence and process them in bulk. Unlike webhooks, no additional registration or other configuration is required; every enterprise integration that is registered for events is automatically enabled for journaling. Journaling data is retained for 7 days. `}

\n

{`After you fire event, you should be able to verify your event through journaling `}{`UNIQUE API ENDPOINT`}{` you get from console by follow below instruction\n`}{`Journaling api`}{`\nyou could use `}{`Curl`}{` command or `}{`POSTMAN`}{` to call this journaling `}{`UNIQUE API ENDPOINT`}{` to see your fired event.\nOr you can use `}{`Custom event SDK`}{` to call Journaling API to retrieve your event.`}

\n

{`Option 2: Using runtime action`}

\n

{`Once you have access to `}{`Adobe I/O Runtime`}{` (in our case you already have) and you have your `}{`slack webhook url defined`}{` :`}

\n
    \n
  • {`Edit the `}{`app.config.yaml`}{` to add an action called slack `}
  • \n
\n
{` slack:\n        function: actions/slack/index.js\n        web: 'yes'\n        runtime: 'nodejs:14'\n        inputs:\n          LOG_LEVEL: debug\n        annotations:\n          final: true\n`}
\n

{`Add in the actions folder with `}{`actions/slack/index.js`}{` with below sample code`}

\n
{` var request = require('request');\n\n/* default slackwebhook and channel add yours here and replace the TODO below */\n/* this is a sample action for how to receive event and sent a message to slack */\nvar request = require('request');\n\n/* default slackwebhook and channel add yours here and replace the TODO below */\nvar slackWebhook = \"\";\nvar slackChannel = \"\";\n\nasync function main (params) {\n  \n  /* print event detail */\n  console.log('in main + event detail: ', params.event);\n\n  var returnObject = {\n    statusCode: 200,\n    headers: {\n      'Content-Type': 'application/json'\n    },\n    body: \"\"\n  };\n\n  /* handle the challenge */\n  if (params.challenge) {\n\n    console.log('Returning challenge: ' + params.challenge);\n\n    returnObject.body = new Buffer(JSON.stringify({\n      \"challenge\": params.challenge\n    })).toString('base64');\n\n    return returnObject;\n\n  } else {\n\n    /* we need it to run asynchronously, so we are returning a Promise */\n    return new Promise(function (resolve, reject) {\n\n      var slackMessage = \" Event received: \" + JSON.stringify(params);\n\n      var payload = {\n        \"channel\": slackChannel,\n        \"username\": \"incoming-webhook\",\n        \"text\": slackMessage,\n        \"mrkdwn\": true,\n      };\n\n      var options = {\n        method: 'POST',\n        url: slackWebhook,\n        headers:\n            { 'Content-type': 'application/json' },\n        body: JSON.stringify(payload)\n      };\n\n      request(options, function (error, response, body) {\n        if (error) {\n\n          console.log(\"ERROR: fail to post \" + response);\n\n          reject(error);\n\n        } else {\n\n          console.log (\"SUCCESS: posted to slack \" + slackMessage);\n\n          returnObject.body = new Buffer(JSON.stringify({\n            \"slackMessage\": slackMessage\n          })).toString('base64');\n\n          resolve(returnObject);\n        }\n\n      });\n\n    });\n\n  }\n}\n\nexports.main = main\n`}
\n

{`After you deployed your runtime action, you can verfiy the webhook is working by `}

\n
{`curl -X POST -H 'Content-type: application/json' --data '{\"text\":\"Hello, World!\"}' https://.adobeio-static.net/api/v1/web/event-demo-0.0.1/slack\n`}
\n

{`In addtion, in developer console, you will be able to see `}{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}{`\nSelect the slack one and save it. Now when you fire event, you should be able to receive a slack message every time people click the like button\n`}{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}

\n

{`Option 3: Using webhook to consume events`}

\n

{`You could configure another event delivery method through console by `}{`Edit Events Registration`}{` and add webhook `}

\n

{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}{`\n `}

\n

{`Before you can register a webhook, the webhook needs to be online and operational. If not, then the registration will fail. So you need to take care of setting that up first. Your webhook must be hosted on a server. For development, you may use localhost along with a tool like `}{`Ngrok`}{`.`}

\n

{`Your webhook needs to`}

\n
    \n
  • {`be accessible from the internet (localhost won't work)`}
  • \n
  • {`be reachable over HTTPS`}
  • \n
  • {`correctly respond to a \"challenge\" request\nFor more details, follow the link below:\n`}{`how to use webhook`}
  • \n
\n

{`Let's test it, and fire events`}

\n

{`With that,once you fire the event (in our codelab case, click the invoke button) you should see them appearing in above three options:`}

\n
    \n
  • {`Through Adobe I/O Journaling API `}
  • \n
  • {`Get slack message - through slack runtime action webhook`}
  • \n
  • {`Through webhook URL`}
  • \n
\n\n
;\n}\n;\nMDXContent.isMDXComponent = true;\n "],"names":["_frontmatter","layoutProps","MDXLayout","DefaultLayout","MDXContent","components","props","mdxType","parentName","isMDXComponent"],"sourceRoot":""} \ No newline at end of file diff --git a/component---src-pages-resources-sample-apps-code-snippets-index-md-0bd5d2cbaed0f9e5560b.js b/component---src-pages-resources-sample-apps-code-snippets-index-md-0bd5d2cbaed0f9e5560b.js new file mode 100644 index 000000000..6c8074132 --- /dev/null +++ b/component---src-pages-resources-sample-apps-code-snippets-index-md-0bd5d2cbaed0f9e5560b.js @@ -0,0 +1,2 @@ +"use strict";(self.webpackChunkadobe_developer_app_builder=self.webpackChunkadobe_developer_app_builder||[]).push([[7696],{30073:function(e,n,r){r.r(n),r.d(n,{_frontmatter:function(){return u},default:function(){return l}});var s=r(87462),o=r(63366),a=(r(15007),r(64983)),t=r(91515),i=["components"],u={},c={_frontmatter:u},p=t.Z;function l(e){var n=e.components,r=(0,o.Z)(e,i);return(0,a.mdx)(p,(0,s.Z)({},c,r,{components:n,mdxType:"MDXLayout"}),(0,a.mdx)("h1",{id:"caching-http-responses"},"Caching HTTP responses"),(0,a.mdx)("p",null,"Demonstrating how to cache response of an action at Gateway level. To test this functionality, make sure that the Cache-Control header in your HTTP request is not set to ",(0,a.mdx)("inlineCode",{parentName:"p"},"no-cache"),"\n(which is by default if you use Postman or browser's developer tools). More info ",(0,a.mdx)("a",{parentName:"p",href:"/app-builder/runtime/docs/guides/using/throughput_tuning/#caching-responses"},"here"),". "),(0,a.mdx)("pre",null,(0,a.mdx)("code",{parentName:"pre",className:"language-javascript"},"const { Core } = require('@adobe/aio-sdk')\nconst { errorResponse, stringParameters, checkMissingRequestInputs } = require('../utils')\n\n// main function that will be executed by Adobe I/O Runtime\nasync function main (params) {\n // create a Logger\n const logger = Core.Logger('main', { level: params.LOG_LEVEL || 'info' })\n\n try {\n // 'info' is the default level if not set\n logger.info('Calling the main action')\n\n // log parameters, only if params.LOG_LEVEL === 'debug'\n logger.debug(stringParameters(params))\n\n // check for missing request input parameters and headers\n const requiredParams = ['name']\n const requiredHeaders = []\n const errorMessage = checkMissingRequestInputs(params, requiredParams, requiredHeaders)\n if (errorMessage) {\n // return and log client errors\n return errorResponse(400, errorMessage, logger)\n }\n\n // sleeping 2 secs to simulate an outgoing server call\n await new Promise(r => setTimeout(r, 2000))\n\n const response = {\n headers: {\n 'Cache-Control': 'max-age=300' // cached 5 min\n },\n statusCode: 200,\n body: { message: `Hi ${params.name}, I am ready!` }\n }\n\n // log the response status code\n logger.info(`${response.statusCode}: successful request`)\n return response\n } catch (error) {\n // log any server errors\n logger.error(error)\n // return with 500\n return errorResponse(500, 'server error', logger)\n }\n}\n\nexports.main = main\n")))}l.isMDXComponent=!0}}]); +//# sourceMappingURL=component---src-pages-resources-sample-apps-code-snippets-index-md-0bd5d2cbaed0f9e5560b.js.map \ No newline at end of file diff --git a/component---src-pages-resources-sample-apps-code-snippets-index-md-0bd5d2cbaed0f9e5560b.js.map b/component---src-pages-resources-sample-apps-code-snippets-index-md-0bd5d2cbaed0f9e5560b.js.map new file mode 100644 index 000000000..98058d3fa --- /dev/null +++ b/component---src-pages-resources-sample-apps-code-snippets-index-md-0bd5d2cbaed0f9e5560b.js.map @@ -0,0 +1 @@ +{"version":3,"file":"component---src-pages-resources-sample-apps-code-snippets-index-md-0bd5d2cbaed0f9e5560b.js","mappings":"4SAQaA,EAAe,CAAC,EACvBC,EAAc,CAClBD,aAAAA,GAEIE,EAAYC,EAAAA,EACH,SAASC,EAAT,GAGZ,IAFDC,EAEC,EAFDA,WACGC,GACF,YACD,OAAO,SAACJ,GAAD,UAAeD,EAAiBK,EAAhC,CAAuCD,WAAYA,EAAYE,QAAQ,eAG5E,eACE,GAAM,0BADR,2BAGA,gMAAiL,uBAAYC,WAAW,KAAvB,YAAjL,uFAC+E,cAAGA,WAAW,IACzF,KAAQ,+EADmE,QAD/E,OAIA,qBAAK,iBAAMA,WAAW,MAClB,UAAa,uBADZ,6+CAoDR,CAEDJ,EAAWK,gBAAiB,C","sources":["webpack://adobe-developer-app-builder/./src/pages/resources/sample_apps/code_snippets/index.md"],"sourcesContent":["import * as React from 'react'\n /* @jsx mdx */\nimport { mdx } from '@mdx-js/react';\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\n\nimport DefaultLayout from \"/home/runner/work/app-builder/app-builder/node_modules/@adobe/gatsby-theme-aio/src/components/MDXFilter/index.js\";\nexport const _frontmatter = {};\nconst layoutProps = {\n _frontmatter\n};\nconst MDXLayout = DefaultLayout;\nexport default function MDXContent({\n components,\n ...props\n}) {\n return \n\n\n

{`Caching HTTP responses`}

\n

{`Demonstrating how to cache response of an action at Gateway level. To test this functionality, make sure that the Cache-Control header in your HTTP request is not set to `}{`no-cache`}{`\n(which is by default if you use Postman or browser's developer tools). More info `}{`here`}{`. `}

\n
{`const { Core } = require('@adobe/aio-sdk')\nconst { errorResponse, stringParameters, checkMissingRequestInputs } = require('../utils')\n\n// main function that will be executed by Adobe I/O Runtime\nasync function main (params) {\n  // create a Logger\n  const logger = Core.Logger('main', { level: params.LOG_LEVEL || 'info' })\n\n  try {\n    // 'info' is the default level if not set\n    logger.info('Calling the main action')\n\n    // log parameters, only if params.LOG_LEVEL === 'debug'\n    logger.debug(stringParameters(params))\n\n    // check for missing request input parameters and headers\n    const requiredParams = ['name']\n    const requiredHeaders = []\n    const errorMessage = checkMissingRequestInputs(params, requiredParams, requiredHeaders)\n    if (errorMessage) {\n      // return and log client errors\n      return errorResponse(400, errorMessage, logger)\n    }\n\n    // sleeping 2 secs to simulate an outgoing server call\n    await new Promise(r => setTimeout(r, 2000))\n\n    const response = {\n      headers: {\n        'Cache-Control': 'max-age=300' // cached 5 min\n      },\n      statusCode: 200,\n      body: { message: \\`Hi \\${params.name}, I am ready!\\` }\n    }\n\n    // log the response status code\n    logger.info(\\`\\${response.statusCode}: successful request\\`)\n    return response\n  } catch (error) {\n    // log any server errors\n    logger.error(error)\n    // return with 500\n    return errorResponse(500, 'server error', logger)\n  }\n}\n\nexports.main = main\n`}
\n\n
;\n}\n;\nMDXContent.isMDXComponent = true;\n "],"names":["_frontmatter","layoutProps","MDXLayout","DefaultLayout","MDXContent","components","props","mdxType","parentName","isMDXComponent"],"sourceRoot":""} \ No newline at end of file diff --git a/component---src-pages-resources-sample-apps-code-snippets-index-md-15d357addb93f54e944f.js b/component---src-pages-resources-sample-apps-code-snippets-index-md-15d357addb93f54e944f.js deleted file mode 100644 index 0b7b0d53a..000000000 --- a/component---src-pages-resources-sample-apps-code-snippets-index-md-15d357addb93f54e944f.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict";(self.webpackChunkadobe_developer_app_builder=self.webpackChunkadobe_developer_app_builder||[]).push([[7696],{30073:function(e,n,r){r.r(n),r.d(n,{_frontmatter:function(){return u},default:function(){return p}});var s=r(87462),o=r(63366),a=(r(15007),r(64983)),t=r(91515),i=["components"],u={},c={_frontmatter:u},m=t.Z;function p(e){var n=e.components,r=(0,o.Z)(e,i);return(0,a.mdx)(m,(0,s.Z)({},c,r,{components:n,mdxType:"MDXLayout"}),(0,a.mdx)("h1",{id:"caching-http-responses"},"Caching HTTP responses"),(0,a.mdx)("p",null,"Demonstrating how to cache response of an action at Gateway level. To test this functionality, make sure that the Cache-Control header in your HTTP request is not set to ",(0,a.mdx)("inlineCode",{parentName:"p"},"no-cache"),"\n(which is by default if you use Postman or browser's developer tools). More info ",(0,a.mdx)("a",{parentName:"p",href:"/app-builder/apis/experienceplatform/runtime/docs.html#!adobedocs/adobeio-runtime/master/guides/throughput_tuning.md#caching-responses"},"here"),". "),(0,a.mdx)("pre",null,(0,a.mdx)("code",{parentName:"pre",className:"language-javascript"},"const { Core } = require('@adobe/aio-sdk')\nconst { errorResponse, stringParameters, checkMissingRequestInputs } = require('../utils')\n\n// main function that will be executed by Adobe I/O Runtime\nasync function main (params) {\n // create a Logger\n const logger = Core.Logger('main', { level: params.LOG_LEVEL || 'info' })\n\n try {\n // 'info' is the default level if not set\n logger.info('Calling the main action')\n\n // log parameters, only if params.LOG_LEVEL === 'debug'\n logger.debug(stringParameters(params))\n\n // check for missing request input parameters and headers\n const requiredParams = ['name']\n const requiredHeaders = []\n const errorMessage = checkMissingRequestInputs(params, requiredParams, requiredHeaders)\n if (errorMessage) {\n // return and log client errors\n return errorResponse(400, errorMessage, logger)\n }\n\n // sleeping 2 secs to simulate an outgoing server call\n await new Promise(r => setTimeout(r, 2000))\n\n const response = {\n headers: {\n 'Cache-Control': 'max-age=300' // cached 5 min\n },\n statusCode: 200,\n body: { message: `Hi ${params.name}, I am ready!` }\n }\n\n // log the response status code\n logger.info(`${response.statusCode}: successful request`)\n return response\n } catch (error) {\n // log any server errors\n logger.error(error)\n // return with 500\n return errorResponse(500, 'server error', logger)\n }\n}\n\nexports.main = main\n")))}p.isMDXComponent=!0}}]); -//# sourceMappingURL=component---src-pages-resources-sample-apps-code-snippets-index-md-15d357addb93f54e944f.js.map \ No newline at end of file diff --git a/component---src-pages-resources-sample-apps-code-snippets-index-md-15d357addb93f54e944f.js.map b/component---src-pages-resources-sample-apps-code-snippets-index-md-15d357addb93f54e944f.js.map deleted file mode 100644 index f3ac69444..000000000 --- a/component---src-pages-resources-sample-apps-code-snippets-index-md-15d357addb93f54e944f.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"component---src-pages-resources-sample-apps-code-snippets-index-md-15d357addb93f54e944f.js","mappings":"4SAQaA,EAAe,CAAC,EACvBC,EAAc,CAClBD,aAAAA,GAEIE,EAAYC,EAAAA,EACH,SAASC,EAAT,GAGZ,IAFDC,EAEC,EAFDA,WACGC,GACF,YACD,OAAO,SAACJ,GAAD,UAAeD,EAAiBK,EAAhC,CAAuCD,WAAYA,EAAYE,QAAQ,eAG5E,eACE,GAAM,0BADR,2BAGA,gMAAiL,uBAAYC,WAAW,KAAvB,YAAjL,uFAC+E,cAAGA,WAAW,IACzF,KAAQ,0IADmE,QAD/E,OAIA,qBAAK,iBAAMA,WAAW,MAClB,UAAa,uBADZ,6+CAoDR,CAEDJ,EAAWK,gBAAiB,C","sources":["webpack://adobe-developer-app-builder/./src/pages/resources/sample_apps/code_snippets/index.md"],"sourcesContent":["import * as React from 'react'\n /* @jsx mdx */\nimport { mdx } from '@mdx-js/react';\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\n\nimport DefaultLayout from \"/home/runner/work/app-builder/app-builder/node_modules/@adobe/gatsby-theme-aio/src/components/MDXFilter/index.js\";\nexport const _frontmatter = {};\nconst layoutProps = {\n _frontmatter\n};\nconst MDXLayout = DefaultLayout;\nexport default function MDXContent({\n components,\n ...props\n}) {\n return \n\n\n

{`Caching HTTP responses`}

\n

{`Demonstrating how to cache response of an action at Gateway level. To test this functionality, make sure that the Cache-Control header in your HTTP request is not set to `}{`no-cache`}{`\n(which is by default if you use Postman or browser's developer tools). More info `}{`here`}{`. `}

\n
{`const { Core } = require('@adobe/aio-sdk')\nconst { errorResponse, stringParameters, checkMissingRequestInputs } = require('../utils')\n\n// main function that will be executed by Adobe I/O Runtime\nasync function main (params) {\n  // create a Logger\n  const logger = Core.Logger('main', { level: params.LOG_LEVEL || 'info' })\n\n  try {\n    // 'info' is the default level if not set\n    logger.info('Calling the main action')\n\n    // log parameters, only if params.LOG_LEVEL === 'debug'\n    logger.debug(stringParameters(params))\n\n    // check for missing request input parameters and headers\n    const requiredParams = ['name']\n    const requiredHeaders = []\n    const errorMessage = checkMissingRequestInputs(params, requiredParams, requiredHeaders)\n    if (errorMessage) {\n      // return and log client errors\n      return errorResponse(400, errorMessage, logger)\n    }\n\n    // sleeping 2 secs to simulate an outgoing server call\n    await new Promise(r => setTimeout(r, 2000))\n\n    const response = {\n      headers: {\n        'Cache-Control': 'max-age=300' // cached 5 min\n      },\n      statusCode: 200,\n      body: { message: \\`Hi \\${params.name}, I am ready!\\` }\n    }\n\n    // log the response status code\n    logger.info(\\`\\${response.statusCode}: successful request\\`)\n    return response\n  } catch (error) {\n    // log any server errors\n    logger.error(error)\n    // return with 500\n    return errorResponse(500, 'server error', logger)\n  }\n}\n\nexports.main = main\n`}
\n\n
;\n}\n;\nMDXContent.isMDXComponent = true;\n "],"names":["_frontmatter","layoutProps","MDXLayout","DefaultLayout","MDXContent","components","props","mdxType","parentName","isMDXComponent"],"sourceRoot":""} \ No newline at end of file diff --git a/getting_started/common_troubleshooting/index.html b/getting_started/common_troubleshooting/index.html index 26d7b1066..67c08ec35 100644 --- a/getting_started/common_troubleshooting/index.html +++ b/getting_started/common_troubleshooting/index.html @@ -52,11 +52,11 @@ --spectrum-dialog-confirm-buttongroup-padding-top )}.spectrum-Dialog--fullscreen .spectrum-Dialog-heading,.spectrum-Dialog--fullscreenTakeover .spectrum-Dialog-heading{font-size:var(--spectrum-dialog-confirm-title-text-size)}}@media (forced-colors:active){.spectrum-Dialog{border:solid}}.spectrum-Dialog-heading{color:var(--spectrum-dialog-confirm-title-text-color,var(--spectrum-alias-heading-text-color))}.spectrum-Dialog-content,.spectrum-Dialog-footer{color:var(--spectrum-dialog-confirm-description-text-color,var(--spectrum-global-color-gray-800))}.spectrum-Dialog-typeIcon{color:var(--spectrum-dialog-confirm-icon-color,var(--spectrum-global-color-gray-900))}.spectrum-Dialog--error .spectrum-Dialog-typeIcon{color:var(--spectrum-dialog-error-icon-color,var(--spectrum-semantic-negative-icon-color))}