@bffless/skills 1.7.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,7 +5,7 @@
5
5
  },
6
6
  "metadata": {
7
7
  "description": "BFFless platform skills",
8
- "version": "1.7.0"
8
+ "version": "1.8.0"
9
9
  },
10
10
  "plugins": [
11
11
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bffless/skills",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "BFFless platform skills — usable with Claude Code or any agent via the `skills` CLI",
5
5
  "keywords": [
6
6
  "skills",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bffless",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "BFFless platform skills for Claude Code — deployments, pipelines, proxy rules, chat, traffic splitting, and more",
5
5
  "author": {
6
6
  "name": "BFFless"
@@ -102,11 +102,13 @@ You can upload multiple artifacts in the same workflow:
102
102
  | `branch` | no | auto | Branch name |
103
103
  | `is-public` | no | `'true'` | Public visibility |
104
104
  | `alias` | no | -- | Deployment alias (e.g., `production`) |
105
- | `base-path` | no | `/<path>` | Path prefix in zip |
105
+ | `base-path` | no | `/<path>` | URL prefix the alias serves under. See [Base path and URL shape](#base-path-and-url-shape). |
106
106
  | `committed-at` | no | auto | ISO 8601 commit timestamp |
107
107
  | `description` | no | -- | Human-readable description |
108
- | `proxy-rule-set-name` | no | -- | Proxy rule set name |
109
- | `proxy-rule-set-id` | no | -- | Proxy rule set ID |
108
+ | `proxy-rule-set-name` | no | -- | Single proxy rule set name (legacy — prefer `proxy-rule-set-names`) |
109
+ | `proxy-rule-set-id` | no | -- | Single proxy rule set ID (legacy — prefer `proxy-rule-set-ids`) |
110
+ | `proxy-rule-set-names` | no | -- | Comma-separated proxy rule set names. Appended idempotently — re-deploying with the same names is a no-op. See [Attaching multiple proxy rule sets](#attaching-multiple-proxy-rule-sets). |
111
+ | `proxy-rule-set-ids` | no | -- | Comma-separated proxy rule set IDs. Same append-and-dedupe semantics as `proxy-rule-set-names`. |
110
112
  | `tags` | no | -- | Comma-separated tags |
111
113
  | `summary` | no | `'true'` | Write GitHub Step Summary |
112
114
  | `summary-title` | no | `'Deployment Summary'` | Summary heading |
@@ -147,7 +149,60 @@ The action automatically detects:
147
149
  - **Commit SHA**: PR head SHA or push SHA
148
150
  - **Branch**: PR head ref or push ref
149
151
  - **Committed At**: via `git log` (requires `fetch-depth: 0`)
150
- - **Base Path**: derived from `path` input as `/<path>`
152
+ - **Base Path**: derived from `path` input as `/<path>` — chosen so files appear at the auto-alias root. See [Base path and URL shape](#base-path-and-url-shape) for what this means and when to override.
153
+
154
+ ## Base path and URL shape
155
+
156
+ `base-path` controls the URL prefix the deployment's alias serves files under. It does **not** rewrite the zip — the action always zips the contents of `path` with the source folder name preserved (e.g. `path: coverage` produces a zip containing `coverage/index.html`). At serve time, the alias's `basePath` is prepended to the incoming request URL before the lookup against stored asset keys.
157
+
158
+ Combined with the default `base-path: /<path>`, this produces a useful sleight of hand: the prefix on the URL cancels the folder name on the stored path, so files appear at the **auto-alias root**.
159
+
160
+ Example: `path: coverage`, default `base-path`
161
+
162
+ | Request URL | `basePath` prepended | Resolves to stored | Result |
163
+ |---|---|---|---|
164
+ | `/index.html` | `coverage/index.html` | `coverage/index.html` | ✅ served |
165
+ | `/coverage/index.html` | `coverage/coverage/index.html` | — | ❌ 404 |
166
+
167
+ If you'd rather the source folder be **visible** in the URL (e.g. `/coverage/index.html`), set `base-path: /` so the alias's prefix is empty:
168
+
169
+ | Request URL | `basePath` prepended | Resolves to stored | Result |
170
+ |---|---|---|---|
171
+ | `/coverage/index.html` | `coverage/index.html` | `coverage/index.html` | ✅ served |
172
+ | `/index.html` | `index.html` | — | ❌ 404 |
173
+
174
+ Rule of thumb:
175
+
176
+ - **Want files at auto-alias root** (`<auto-alias>/file.png`) → leave `base-path` unset (default).
177
+ - **Want folder visible in URL** (`<auto-alias>/srcfolder/file.png`) → set `base-path: /`.
178
+ - **Want a different sub-path** → set `base-path: /custom-prefix`. The serving lookup will prepend `custom-prefix/` to incoming requests, so this only works if the zip contents are under a folder of the same name (i.e. `path: custom-prefix`).
179
+
180
+ ### Pitfalls
181
+
182
+ - **Do not use `base-path: ./`** — the backend normalization only strips leading/trailing slashes, so `./` becomes the literal segment `.` and gets prepended to every lookup, breaking all requests. Use `/` instead.
183
+ - Empty / whitespace values are also unsafe; pass exactly `/` to mean "no prefix."
184
+
185
+ ## Attaching multiple proxy rule sets
186
+
187
+ Use `proxy-rule-set-names` (or `proxy-rule-set-ids`) when the deployment's auto-preview alias needs to chain more than one proxy rule set — for example a Stripe webhook rule set followed by an AI proxy rule set:
188
+
189
+ ```yaml
190
+ - uses: bffless/upload-artifact@v1
191
+ with:
192
+ path: dist
193
+ api-url: ${{ vars.ASSET_HOST_URL }}
194
+ api-key: ${{ secrets.ASSET_HOST_KEY }}
195
+ proxy-rule-set-names: stripe-webhook,ai-proxy
196
+ ```
197
+
198
+ Semantics:
199
+
200
+ - **Append + idempotent.** Each name/id is appended to whatever the alias already has. Re-running the workflow with the same list is a no-op — no duplicate join rows, no rule reordering.
201
+ - **Order preserved on first attach.** The list order is the priority order in the rule merge — earlier entries win when two rule sets match the same request.
202
+ - **Names resolve per-project.** Unknown names fail the deploy with a `400`; existing IDs that don't belong to the project are silently ignored at the rule-merge layer.
203
+ - **Singular still works.** `proxy-rule-set-name` / `proxy-rule-set-id` remain supported as a back-compat shim. If both singular and plural are provided, the plural list wins and the singular value is ignored.
204
+
205
+ If you need full replacement (drop all existing rule sets and set exactly this list), do not use the action — use the `update_alias` API with the `proxyRuleSetIds` array instead. The action's deploy path is intentionally append-only so that rule sets added through other channels (admin UI, scripts) are never silently dropped by a workflow run.
151
206
 
152
207
  ## PR Comments
153
208
 
@@ -183,9 +238,15 @@ permissions:
183
238
  pull-requests: write # Required for comments
184
239
  ```
185
240
 
241
+ ### Files 404 at the auto-alias root
242
+
243
+ If `https://<auto-alias>/<file>` returns 404 but `https://<auto-alias>/<srcfolder>/<file>` works (or vice versa), `base-path` is the wrong shape. See [Base path and URL shape](#base-path-and-url-shape).
244
+
245
+ Common cause: setting `base-path: ./` instead of `base-path: /`. The backend doesn't normalize `./`, so it gets prepended literally and breaks every lookup.
246
+
186
247
  ### Custom base path
187
248
 
188
- If your app expects to be served from a subdirectory:
249
+ If your app expects to be served from a subdirectory (and the zip contents live under that directory):
189
250
 
190
251
  ```yaml
191
252
  - uses: bffless/upload-artifact@v1
@@ -193,3 +254,5 @@ If your app expects to be served from a subdirectory:
193
254
  path: build
194
255
  base-path: /docs/build # Served at /docs/build/*
195
256
  ```
257
+
258
+ See [Base path and URL shape](#base-path-and-url-shape) for the full mental model.