ugly-app 0.1.933 → 0.1.934

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.
@@ -75,6 +75,16 @@ export declare function ensureR2CustomDomain(args: StaticDomainArgs): Promise<vo
75
75
  * this, COEP `require-corp` blocks every `fetch()` of a static asset.
76
76
  */
77
77
  export declare function putR2BucketCors(args: StaticDomainArgs): Promise<void>;
78
+ /**
79
+ * Rule ref — stable per HOST, so re-running updates in place instead of
80
+ * stacking.
81
+ *
82
+ * It must be per-host, not a constant: a zone is SHARED by every app on it
83
+ * (~22 live on `ugly.bot`). With one fixed ref, the second app to provision
84
+ * would filter out the first app's rule and replace it with its own, silently
85
+ * un-CORP-ing that app and breaking its no-CORS assets.
86
+ */
87
+ export declare function corpRuleRef(domain: string): string;
78
88
  /**
79
89
  * Add `Cross-Origin-Resource-Policy: cross-origin` to responses on the static
80
90
  * host, so plain no-CORS subresources (`<img src>`, `<audio src>`) are not
@@ -1 +1 @@
1
- {"version":3,"file":"staticDomain.d.ts","sourceRoot":"","sources":["../../../src/cli/publish/staticDomain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAMH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB;;;;;;;;;OASG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAWzE;AAgCD;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CAcjB;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,IAAI,CAAC,CAmCf;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CA4B3E;AAKD;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,IAAI,CAAC,CA8Cf;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,gBAAgB,EACtB,GAAG,GAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAGrB,GACA,OAAO,CAAC,IAAI,CAAC,CAgBf"}
1
+ {"version":3,"file":"staticDomain.d.ts","sourceRoot":"","sources":["../../../src/cli/publish/staticDomain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAMH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB;;;;;;;;;OASG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAWzE;AAgCD;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CAcjB;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,IAAI,CAAC,CAmCf;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CA4B3E;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAElD;AAWD;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,IAAI,CAAC,CAuDf;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,gBAAgB,EACtB,GAAG,GAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAGrB,GACA,OAAO,CAAC,IAAI,CAAC,CAgBf"}
@@ -147,8 +147,26 @@ export async function putR2BucketCors(args) {
147
147
  }),
148
148
  }, 'putR2BucketCors');
149
149
  }
150
- /** Rule name — stable so re-running updates in place instead of stacking. */
151
- const CORP_RULE_REF = 'ugly_app_static_corp';
150
+ /**
151
+ * Rule ref — stable per HOST, so re-running updates in place instead of
152
+ * stacking.
153
+ *
154
+ * It must be per-host, not a constant: a zone is SHARED by every app on it
155
+ * (~22 live on `ugly.bot`). With one fixed ref, the second app to provision
156
+ * would filter out the first app's rule and replace it with its own, silently
157
+ * un-CORP-ing that app and breaking its no-CORS assets.
158
+ */
159
+ export function corpRuleRef(domain) {
160
+ return `ugly_app_static_corp__${domain.toLowerCase().replace(/[^a-z0-9]+/g, '_')}`;
161
+ }
162
+ /**
163
+ * The ref used before refs were per-host. Rules written under it are still out
164
+ * there (world3, ugly.chat), so provisioning drops the legacy rule when it
165
+ * targets the host we're about to write — otherwise the old and new rules sit
166
+ * side by side forever and nothing ever cleans the old one up. A legacy rule
167
+ * pointing at a DIFFERENT host belongs to another app and is left alone.
168
+ */
169
+ const LEGACY_CORP_RULE_REF = 'ugly_app_static_corp';
152
170
  /**
153
171
  * Add `Cross-Origin-Resource-Policy: cross-origin` to responses on the static
154
172
  * host, so plain no-CORS subresources (`<img src>`, `<audio src>`) are not
@@ -160,6 +178,7 @@ const CORP_RULE_REF = 'ugly_app_static_corp';
160
178
  */
161
179
  export async function ensureCorpHeaderRule(args) {
162
180
  const { token, rulesetToken, zoneId, domain } = args;
181
+ const ruleRef = corpRuleRef(domain);
163
182
  const headers = {
164
183
  'Authorization': `Bearer ${rulesetToken ?? token}`,
165
184
  'Content-Type': 'application/json',
@@ -170,7 +189,7 @@ export async function ensureCorpHeaderRule(args) {
170
189
  const existing = listed?.result
171
190
  ?.rules ?? [];
172
191
  const corpRule = {
173
- ref: CORP_RULE_REF,
192
+ ref: ruleRef,
174
193
  action: 'rewrite',
175
194
  description: 'ugly-app: CORP for static assets (COEP require-corp)',
176
195
  expression: `http.host eq "${domain}"`,
@@ -184,7 +203,12 @@ export async function ensureCorpHeaderRule(args) {
184
203
  },
185
204
  };
186
205
  // Keep every rule that isn't ours, then append the current definition.
187
- const rules = [...existing.filter((r) => r.ref !== CORP_RULE_REF), corpRule];
206
+ const expression = corpRule.expression;
207
+ const rules = [
208
+ ...existing.filter((r) => r.ref !== ruleRef &&
209
+ !(r.ref === LEGACY_CORP_RULE_REF && r.expression === expression)),
210
+ corpRule,
211
+ ];
188
212
  await cf(`${base}/phases/http_response_headers_transform/entrypoint`, {
189
213
  method: 'PUT',
190
214
  headers,
@@ -1 +1 @@
1
- {"version":3,"file":"staticDomain.js","sourceRoot":"","sources":["../../../src/cli/publish/staticDomain.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"staticDomain.js","sourceRoot":"","sources":["../../../src/cli/publish/staticDomain.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- export declare const CLI_VERSION = "0.1.933";
1
+ export declare const CLI_VERSION = "0.1.934";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // Auto-generated by prebuild — do not edit manually
2
- export const CLI_VERSION = "0.1.933";
2
+ export const CLI_VERSION = "0.1.934";
3
3
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ugly-app",
3
3
  "packageManager": "pnpm@10.34.5",
4
- "version": "0.1.933",
4
+ "version": "0.1.934",
5
5
  "type": "module",
6
6
  "comment:files": "Allowlist what ships to npm. dist = runtime; src = sourcemap targets (dist/*.js.map reference ../../src/); templates = CLI scaffold. Everything else at repo root (.pgdata local Postgres, coverage, assets/icons sources, test/, test-results/) is excluded by omission. The !negations strip the scaffold's installed deps + cruft (templates/node_modules is 200MB+ and must never ship). package.json/README/LICENSE ship automatically.",
7
7
  "files": [
@@ -1,5 +1,6 @@
1
1
  import { afterEach, describe, expect, it, vi } from 'vitest';
2
2
  import {
3
+ corpRuleRef,
3
4
  ensureCorpHeaderRule,
4
5
  ensureR2CustomDomain,
5
6
  ensureStaticDomain,
@@ -180,6 +181,7 @@ describe('ensureCorpHeaderRule', () => {
180
181
  });
181
182
 
182
183
  it('replaces its own prior rule instead of stacking duplicates', async () => {
184
+ const mine = corpRuleRef('static.myapp.com');
183
185
  const fetchMock = vi
184
186
  .fn()
185
187
  .mockResolvedValueOnce(
@@ -187,7 +189,7 @@ describe('ensureCorpHeaderRule', () => {
187
189
  success: true,
188
190
  result: {
189
191
  rules: [
190
- { ref: 'ugly_app_static_corp', description: 'stale version' },
192
+ { ref: mine, description: 'stale version' },
191
193
  { ref: 'someone_elses_rule', description: 'keep me' },
192
194
  ],
193
195
  },
@@ -200,7 +202,59 @@ describe('ensureCorpHeaderRule', () => {
200
202
  const [, init] = fetchMock.mock.calls[1]!;
201
203
  const body = JSON.parse((init as RequestInit).body as string);
202
204
  const refs = body.rules.map((r: { ref: string }) => r.ref);
203
- expect(refs).toEqual(['someone_elses_rule', 'ugly_app_static_corp']);
205
+ expect(refs).toEqual(['someone_elses_rule', mine]);
206
+ expect(body.rules).toHaveLength(2);
207
+ });
208
+
209
+ // Rules written before refs were per-host must be cleaned up, not doubled.
210
+ it('drops a legacy-ref rule that targets the same host', async () => {
211
+ const fetchMock = vi
212
+ .fn()
213
+ .mockResolvedValueOnce(
214
+ ok({
215
+ success: true,
216
+ result: {
217
+ rules: [
218
+ {
219
+ ref: 'ugly_app_static_corp',
220
+ expression: 'http.host eq "static.myapp.com"',
221
+ },
222
+ ],
223
+ },
224
+ }),
225
+ )
226
+ .mockResolvedValueOnce(ok());
227
+ vi.stubGlobal('fetch', fetchMock);
228
+ await ensureCorpHeaderRule(ARGS);
229
+ const body = JSON.parse(
230
+ (fetchMock.mock.calls[1]![1] as RequestInit).body as string,
231
+ );
232
+ expect(body.rules).toHaveLength(1);
233
+ expect(body.rules[0].ref).toBe(corpRuleRef('static.myapp.com'));
234
+ });
235
+
236
+ it('leaves a legacy-ref rule that targets a DIFFERENT host', async () => {
237
+ const fetchMock = vi
238
+ .fn()
239
+ .mockResolvedValueOnce(
240
+ ok({
241
+ success: true,
242
+ result: {
243
+ rules: [
244
+ {
245
+ ref: 'ugly_app_static_corp',
246
+ expression: 'http.host eq "other-static.ugly.bot"',
247
+ },
248
+ ],
249
+ },
250
+ }),
251
+ )
252
+ .mockResolvedValueOnce(ok());
253
+ vi.stubGlobal('fetch', fetchMock);
254
+ await ensureCorpHeaderRule(ARGS);
255
+ const body = JSON.parse(
256
+ (fetchMock.mock.calls[1]![1] as RequestInit).body as string,
257
+ );
204
258
  expect(body.rules).toHaveLength(2);
205
259
  });
206
260
 
@@ -323,3 +377,54 @@ describe('ensureCorpHeaderRule — credential selection', () => {
323
377
  );
324
378
  });
325
379
  });
380
+
381
+ describe('corpRuleRef — a shared zone must not have one app clobber another', () => {
382
+ it('is distinct per host', () => {
383
+ expect(corpRuleRef('world3-static.ugly.bot')).not.toBe(
384
+ corpRuleRef('game-demo-static.ugly.bot'),
385
+ );
386
+ });
387
+
388
+ it('is stable for the same host so re-publishing updates in place', () => {
389
+ expect(corpRuleRef('world3-static.ugly.bot')).toBe(
390
+ corpRuleRef('world3-static.ugly.bot'),
391
+ );
392
+ });
393
+
394
+ it('contains only ref-safe characters', () => {
395
+ expect(corpRuleRef('world3-static.ugly.bot')).toMatch(/^[a-z0-9_]+$/);
396
+ });
397
+
398
+ // The bug this guards: ~22 apps share the ugly.bot zone. With a constant
399
+ // ref, app B's provisioning filtered out app A's rule and replaced it,
400
+ // silently un-CORP-ing app A.
401
+ it('preserves another app rule on the same zone', async () => {
402
+ const other = corpRuleRef('game-demo-static.ugly.bot');
403
+ const fetchMock = vi
404
+ .fn()
405
+ .mockResolvedValueOnce(
406
+ ok({
407
+ success: true,
408
+ result: {
409
+ rules: [
410
+ {
411
+ ref: other,
412
+ expression: 'http.host eq "game-demo-static.ugly.bot"',
413
+ },
414
+ ],
415
+ },
416
+ }),
417
+ )
418
+ .mockResolvedValueOnce(ok());
419
+ vi.stubGlobal('fetch', fetchMock);
420
+ await ensureCorpHeaderRule({ ...ARGS, domain: 'world3-static.ugly.bot' });
421
+
422
+ const body = JSON.parse(
423
+ (fetchMock.mock.calls[1]![1] as RequestInit).body as string,
424
+ );
425
+ const refs = body.rules.map((r: { ref: string }) => r.ref);
426
+ expect(refs).toContain(other);
427
+ expect(refs).toContain(corpRuleRef('world3-static.ugly.bot'));
428
+ expect(body.rules).toHaveLength(2);
429
+ });
430
+ });
@@ -208,8 +208,27 @@ export async function putR2BucketCors(args: StaticDomainArgs): Promise<void> {
208
208
  );
209
209
  }
210
210
 
211
- /** Rule name — stable so re-running updates in place instead of stacking. */
212
- const CORP_RULE_REF = 'ugly_app_static_corp';
211
+ /**
212
+ * Rule ref — stable per HOST, so re-running updates in place instead of
213
+ * stacking.
214
+ *
215
+ * It must be per-host, not a constant: a zone is SHARED by every app on it
216
+ * (~22 live on `ugly.bot`). With one fixed ref, the second app to provision
217
+ * would filter out the first app's rule and replace it with its own, silently
218
+ * un-CORP-ing that app and breaking its no-CORS assets.
219
+ */
220
+ export function corpRuleRef(domain: string): string {
221
+ return `ugly_app_static_corp__${domain.toLowerCase().replace(/[^a-z0-9]+/g, '_')}`;
222
+ }
223
+
224
+ /**
225
+ * The ref used before refs were per-host. Rules written under it are still out
226
+ * there (world3, ugly.chat), so provisioning drops the legacy rule when it
227
+ * targets the host we're about to write — otherwise the old and new rules sit
228
+ * side by side forever and nothing ever cleans the old one up. A legacy rule
229
+ * pointing at a DIFFERENT host belongs to another app and is left alone.
230
+ */
231
+ const LEGACY_CORP_RULE_REF = 'ugly_app_static_corp';
213
232
 
214
233
  /**
215
234
  * Add `Cross-Origin-Resource-Policy: cross-origin` to responses on the static
@@ -224,6 +243,7 @@ export async function ensureCorpHeaderRule(
224
243
  args: StaticDomainArgs,
225
244
  ): Promise<void> {
226
245
  const { token, rulesetToken, zoneId, domain } = args;
246
+ const ruleRef = corpRuleRef(domain);
227
247
  const headers = {
228
248
  'Authorization': `Bearer ${rulesetToken ?? token}`,
229
249
  'Content-Type': 'application/json',
@@ -242,7 +262,7 @@ export async function ensureCorpHeaderRule(
242
262
  ?.rules ?? [];
243
263
 
244
264
  const corpRule = {
245
- ref: CORP_RULE_REF,
265
+ ref: ruleRef,
246
266
  action: 'rewrite',
247
267
  description: 'ugly-app: CORP for static assets (COEP require-corp)',
248
268
  expression: `http.host eq "${domain}"`,
@@ -257,7 +277,15 @@ export async function ensureCorpHeaderRule(
257
277
  };
258
278
 
259
279
  // Keep every rule that isn't ours, then append the current definition.
260
- const rules = [...existing.filter((r) => r.ref !== CORP_RULE_REF), corpRule];
280
+ const expression = corpRule.expression;
281
+ const rules = [
282
+ ...existing.filter(
283
+ (r) =>
284
+ r.ref !== ruleRef &&
285
+ !(r.ref === LEGACY_CORP_RULE_REF && r.expression === expression),
286
+ ),
287
+ corpRule,
288
+ ];
261
289
 
262
290
  await cf(
263
291
  `${base}/phases/http_response_headers_transform/entrypoint`,
@@ -1,2 +1,2 @@
1
1
  // Auto-generated by prebuild — do not edit manually
2
- export const CLI_VERSION = "0.1.933";
2
+ export const CLI_VERSION = "0.1.934";