Skip to content

Commit 4c8bc60

Browse files
committed
feat: new release working to have a <script /> version of the widget
1 parent 5d8574f commit 4c8bc60

6 files changed

Lines changed: 152 additions & 111 deletions

File tree

.github/workflows/release.yml

Lines changed: 118 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ jobs:
2626
S3_CDN_BASE_URL: ${{ vars.S3_CDN_BASE_URL }}
2727
S3_REGION: ${{ vars.S3_REGION }}
2828
WIDGET_CDN_PREFIX: widget
29+
WIDGET_S3_PREFIX: cdn/widget
2930
steps:
3031
- name: Checkout
3132
uses: actions/checkout@v4
@@ -65,97 +66,123 @@ jobs:
6566
NPM_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }}
6667
NODE_AUTH_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }}
6768

68-
# Temporarily disabled while we pause widget JS/CDN release automation.
69-
# - name: Resolve published browser package
70-
# if: steps.changesets.outputs.published == 'true'
71-
# id: browser_package
72-
# uses: actions/github-script@v7
73-
# env:
74-
# PACKAGES: ${{ steps.changesets.outputs.publishedPackages }}
75-
# with:
76-
# script: |
77-
# const packages = JSON.parse(process.env.PACKAGES ?? "[]");
78-
# const browser = packages.find((pkg) => pkg.name === "@cossistant/browser");
79-
# core.setOutput("published", browser ? "true" : "false");
80-
# core.setOutput("version", browser?.version ?? "");
81-
#
82-
# if (browser) {
83-
# core.info(`Published @cossistant/browser@${browser.version}`);
84-
# } else {
85-
# core.notice("Browser package was not published in this release run.");
86-
# }
87-
#
88-
# - name: Validate widget CDN configuration
89-
# if: steps.browser_package.outputs.published == 'true'
90-
# shell: bash
91-
# run: |
92-
# required_vars=(
93-
# AWS_ROLE_ARN
94-
# CLOUDFRONT_DISTRIBUTION_ID
95-
# S3_BUCKET_NAME
96-
# S3_CDN_BASE_URL
97-
# S3_REGION
98-
# )
99-
#
100-
# for name in "${required_vars[@]}"; do
101-
# if [ -z "${!name}" ]; then
102-
# echo "::error::Missing required workflow variable: ${name}"
103-
# exit 1
104-
# fi
105-
# done
106-
#
107-
# - name: Configure AWS credentials
108-
# if: steps.browser_package.outputs.published == 'true'
109-
# uses: aws-actions/configure-aws-credentials@v4
110-
# with:
111-
# aws-region: ${{ env.S3_REGION }}
112-
# role-to-assume: ${{ env.AWS_ROLE_ARN }}
113-
#
114-
# - name: Build browser CDN assets
115-
# if: steps.browser_package.outputs.published == 'true'
116-
# run: bun run --filter @cossistant/browser build:embed
117-
#
118-
# - name: Upload browser CDN assets
119-
# if: steps.browser_package.outputs.published == 'true'
120-
# shell: bash
121-
# env:
122-
# BROWSER_VERSION: ${{ steps.browser_package.outputs.version }}
123-
# run: |
124-
# version_prefix="s3://${S3_BUCKET_NAME}/${WIDGET_CDN_PREFIX}/${BROWSER_VERSION}"
125-
# latest_prefix="s3://${S3_BUCKET_NAME}/${WIDGET_CDN_PREFIX}/latest"
126-
#
127-
# for file in loader.js widget.js widget.css; do
128-
# local_path="packages/browser/dist/embed/${file}"
129-
#
130-
# if [[ "${file}" == *.css ]]; then
131-
# content_type="text/css; charset=utf-8"
132-
# else
133-
# content_type="text/javascript; charset=utf-8"
134-
# fi
135-
#
136-
# aws s3 cp "${local_path}" "${version_prefix}/${file}" \
137-
# --cache-control "public, max-age=31536000, immutable" \
138-
# --content-type "${content_type}"
139-
#
140-
# aws s3 cp "${local_path}" "${latest_prefix}/${file}" \
141-
# --cache-control "public, max-age=300, must-revalidate" \
142-
# --content-type "${content_type}"
143-
# done
144-
#
145-
# cdn_base_url="${S3_CDN_BASE_URL%/}"
146-
# {
147-
# echo "## Browser Widget CDN"
148-
# echo ""
149-
# echo "- Versioned loader: ${cdn_base_url}/${WIDGET_CDN_PREFIX}/${BROWSER_VERSION}/loader.js"
150-
# echo "- Latest loader: ${cdn_base_url}/${WIDGET_CDN_PREFIX}/latest/loader.js"
151-
# } >> "${GITHUB_STEP_SUMMARY}"
152-
#
153-
# - name: Invalidate latest widget assets
154-
# if: steps.browser_package.outputs.published == 'true'
155-
# run: |
156-
# aws cloudfront create-invalidation \
157-
# --distribution-id "${CLOUDFRONT_DISTRIBUTION_ID}" \
158-
# --paths "/${WIDGET_CDN_PREFIX}/latest/*"
69+
- name: Resolve published React/browser packages
70+
if: steps.changesets.outputs.published == 'true'
71+
id: browser_package
72+
uses: actions/github-script@v7
73+
env:
74+
PACKAGES: ${{ steps.changesets.outputs.publishedPackages }}
75+
with:
76+
script: |
77+
const packages = JSON.parse(process.env.PACKAGES ?? "[]");
78+
const react = packages.find((pkg) => pkg.name === "@cossistant/react");
79+
const browser = packages.find((pkg) => pkg.name === "@cossistant/browser");
80+
81+
if (react && browser && react.version !== browser.version) {
82+
core.setFailed(
83+
`Expected @cossistant/react and @cossistant/browser to share a version, got ${react.version} and ${browser.version}.`
84+
);
85+
return;
86+
}
87+
88+
const shouldUploadWidget = Boolean(react && browser);
89+
90+
core.setOutput("published", shouldUploadWidget ? "true" : "false");
91+
core.setOutput("version", browser?.version ?? "");
92+
93+
if (shouldUploadWidget) {
94+
core.info(
95+
`Published @cossistant/react@${react.version} and @cossistant/browser@${browser.version}; widget CDN upload enabled.`
96+
);
97+
} else if (react && !browser) {
98+
core.setFailed(
99+
"Published @cossistant/react without @cossistant/browser. Widget CDN upload requires both packages in the same release."
100+
);
101+
} else if (!react && browser) {
102+
core.setFailed(
103+
"Published @cossistant/browser without @cossistant/react. Widget CDN upload requires the React package to be published."
104+
);
105+
} else {
106+
core.notice(
107+
"React package was not published in this release run; skipping widget CDN upload."
108+
);
109+
}
110+
111+
- name: Validate widget CDN configuration
112+
if: steps.browser_package.outputs.published == 'true'
113+
shell: bash
114+
run: |
115+
required_vars=(
116+
AWS_ROLE_ARN
117+
CLOUDFRONT_DISTRIBUTION_ID
118+
S3_BUCKET_NAME
119+
S3_CDN_BASE_URL
120+
S3_REGION
121+
)
122+
123+
for name in "${required_vars[@]}"; do
124+
if [ -z "${!name}" ]; then
125+
echo "::error::Missing required workflow variable: ${name}"
126+
exit 1
127+
fi
128+
done
129+
130+
- name: Configure AWS credentials
131+
if: steps.browser_package.outputs.published == 'true'
132+
uses: aws-actions/configure-aws-credentials@v4
133+
with:
134+
aws-region: ${{ env.S3_REGION }}
135+
role-to-assume: ${{ env.AWS_ROLE_ARN }}
136+
137+
- name: Build browser CDN assets
138+
if: steps.browser_package.outputs.published == 'true'
139+
run: bun run --filter @cossistant/browser build:embed
140+
141+
- name: Check browser embed size
142+
if: steps.browser_package.outputs.published == 'true'
143+
run: bun run check:browser-embed-size
144+
145+
- name: Upload browser CDN assets
146+
if: steps.browser_package.outputs.published == 'true'
147+
shell: bash
148+
env:
149+
BROWSER_VERSION: ${{ steps.browser_package.outputs.version }}
150+
run: |
151+
version_prefix="s3://${S3_BUCKET_NAME}/${WIDGET_S3_PREFIX}/${BROWSER_VERSION}"
152+
latest_prefix="s3://${S3_BUCKET_NAME}/${WIDGET_S3_PREFIX}/latest"
153+
154+
for file in loader.js widget.js widget.css; do
155+
local_path="packages/browser/dist/embed/${file}"
156+
157+
if [[ "${file}" == *.css ]]; then
158+
content_type="text/css; charset=utf-8"
159+
else
160+
content_type="text/javascript; charset=utf-8"
161+
fi
162+
163+
aws s3 cp "${local_path}" "${version_prefix}/${file}" \
164+
--cache-control "public, max-age=31536000, immutable" \
165+
--content-type "${content_type}"
166+
167+
aws s3 cp "${local_path}" "${latest_prefix}/${file}" \
168+
--cache-control "public, max-age=300, must-revalidate" \
169+
--content-type "${content_type}"
170+
done
171+
172+
cdn_base_url="${S3_CDN_BASE_URL%/}"
173+
{
174+
echo "## Browser Widget CDN"
175+
echo ""
176+
echo "- Versioned loader: ${cdn_base_url}/${WIDGET_CDN_PREFIX}/${BROWSER_VERSION}/loader.js"
177+
echo "- Latest loader: ${cdn_base_url}/${WIDGET_CDN_PREFIX}/latest/loader.js"
178+
} >> "${GITHUB_STEP_SUMMARY}"
179+
180+
- name: Invalidate latest widget assets
181+
if: steps.browser_package.outputs.published == 'true'
182+
run: |
183+
aws cloudfront create-invalidation \
184+
--distribution-id "${CLOUDFRONT_DISTRIBUTION_ID}" \
185+
--paths "/${WIDGET_CDN_PREFIX}/latest/*"
159186
160187
- name: Create GitHub releases
161188
if: steps.changesets.outputs.published == 'true'

packages/browser/README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,26 @@ release.
2929
- exposes `window.Cossistant.init()`, `show()`, `hide()`, `toggle()`,
3030
`identify()`, `updateConfig()`, `destroy()`, `on()`, and `off()`
3131

32+
## CDN usage
33+
34+
Load the latest widget from the CDN with:
35+
36+
```html
37+
<script async src="https://cdn.cossistant.com/widget/latest/loader.js"></script>
38+
<script>
39+
window.Cossistant.init({
40+
publicKey: "pk_live_..."
41+
});
42+
</script>
43+
```
44+
45+
The loader derives `widget.js` and `widget.css` from its own URL, so the
46+
versioned form works the same way:
47+
48+
```html
49+
<script async src="https://cdn.cossistant.com/widget/0.1.2/loader.js"></script>
50+
```
51+
3252
## Release model
3353

3454
- `@cossistant/browser` is in the same Changesets fixed-version group as

0 commit comments

Comments
 (0)