@assembly-js/app-foundation 0.2.5 → 0.2.6

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.
package/CHANGELOG.md CHANGED
@@ -19,6 +19,9 @@ A patch release never changes what an app's build requires; a minor release may
19
19
  not by hand; see `changes/README.md`. CI fails a PR that changes a check script without a
20
20
  `bump: minor` change file.
21
21
 
22
+ ## 0.2.6
23
+ - [fix] The app keeps connecting to a portal on a custom domain, and keeps telling the editor when it has loaded, without relying on a platform setting that is being retired. Nothing visible changes.
24
+
22
25
  ## 0.2.5
23
26
  - [new] The client-call scan no longer reports reading the session's token details, a client's allowed fetch routes, or a harmless local namespace import as breaking; nothing in the app changes.
24
27
 
@@ -30,7 +30,7 @@ export const NON_CLIENT_EXPORTS = new Set([
30
30
  'InternalUserAccess', 'LEGACY_APP_IDS', 'MintFailure', 'MintOutcome', 'MintSessionOptions', 'MintedAppBearer',
31
31
  'MintedBearer', 'NETWORK_CAPTURE_MESSAGE_TYPE', 'NetworkCaptureHeaderFingerprint',
32
32
  'NetworkCaptureRecord', 'PAINTED_BEACON_EVENT', 'PAINTED_BEACON_PATH',
33
- 'PORTAL_ORIGIN_COOKIE_NAME', 'PREVIEW_V2_FLAG', 'PdfText', 'PrincipalAllow', 'PrincipalKind',
33
+ 'PORTAL_ORIGIN_COOKIE_NAME', 'PdfText', 'PrincipalAllow', 'PrincipalKind',
34
34
  'Provider', 'ProxyOpts', 'RENEW_OUTCOME_EVENT', 'RenewOutcome', 'ReplaceChildRowsResult',
35
35
  'RequestSource', 'ResolveResourceOpts', 'ResourceError', 'ResourceFieldMap',
36
36
  'ResourceOption', 'ResourcePage', 'ScheduleCadence', 'SlackChannel',
@@ -1,6 +1,5 @@
1
1
  export declare const PORTAL_ORIGIN_COOKIE_NAME = "assembly-portal-origin";
2
2
  export declare const CLIENT_FLAGS_COOKIE_NAME = "assembly-flags";
3
- export declare const PREVIEW_V2_FLAG = "app-builder-preview-v2";
4
3
  /**
5
4
  * Reads a single cookie by name from a cookie string (defaults to
6
5
  * `document.cookie`). Shared by every module that reads a proxy-mirrored
@@ -9,14 +8,13 @@ export declare const PREVIEW_V2_FLAG = "app-builder-preview-v2";
9
8
  export declare function readCookie(name: string, cookieString?: string): string | null;
10
9
  /**
11
10
  * Whether the given flag key is present in the proxy-mirrored flags cookie.
12
- * Exported for other vNext modules (e.g. the paint beacon) to check the same
13
- * cookie without re-parsing it themselves.
11
+ * Exported so client modules can gate on a flag without re-parsing the cookie.
14
12
  */
15
13
  export declare function hasClientFlag(key: string, cookieString?: string): boolean;
16
14
  /**
17
15
  * Register the workspace's portal origin with the bridge allowlist — from the
18
- * proxy-set cookie when the preview-v2 flag is on, from the legacy framing
19
- * origin otherwise. Returns the origin it registered, or null when there was
20
- * nothing to do. Exported for tests; runs once at module load in the browser.
16
+ * proxy-set cookie when it is readable, from the framing origin otherwise.
17
+ * Returns the origin it registered, or null when there was nothing to do.
18
+ * Exported for tests; runs once at module load in the browser.
21
19
  */
22
20
  export declare function bootstrapPortalOrigin(cookieString?: string): string | null;
@@ -2,20 +2,18 @@
2
2
  // evaluation precedes hydration — so the workspace's portal origin joins the
3
3
  // bridge allowlist before any component's first header/session-token call.
4
4
  //
5
- // The preview-v2 flag selects WHICH trust source registers the origin — it
6
- // never selects whether anything registers at all (flag-off must keep custom
7
- // portal domains working exactly as pre-vNext package versions did):
5
+ // Two trust sources, in order:
8
6
  //
9
- // - flag ON: the proxy-set cookie. The value is platform-resolved, never
10
- // inferred client-side — the proxy already fetches workspace.portalUrl for
11
- // its CSP frame-ancestors header and mirrors it into this client-readable
12
- // cookie. Immune to the navigation-state poisoning below.
13
- // - flag OFF (or flags cookie unreadable): the legacy browser-reported
14
- // framing origin (ancestorOrigins, referrer fallback). Trusting it is
15
- // sound because the proxy's CSP frame-ancestors already gates who may
16
- // frame the app, but it rides navigation state — strip-able by privacy
17
- // modes and poisoned by in-iframe reloads — which is why the cookie path
18
- // replaces it.
7
+ // - the proxy-set cookie. The value is platform-resolved, never inferred
8
+ // client-side — the proxy already fetches workspace.portalUrl for its CSP
9
+ // frame-ancestors header and mirrors it into this client-readable cookie.
10
+ // Immune to the navigation-state poisoning below.
11
+ // - when that cookie is unreadable (a browser blocking the app's cookies):
12
+ // the browser-reported framing origin (ancestorOrigins, referrer
13
+ // fallback). Trusting it is sound because the proxy's CSP frame-ancestors
14
+ // already gates who may frame the app, but it rides navigation state —
15
+ // strip-able by privacy modes and poisoned by in-iframe reloads — which is
16
+ // why the cookie comes first.
19
17
  //
20
18
  // The bridge has no trust bypass, so one of these registrations is the only
21
19
  // way a custom portal domain becomes a valid parent (dashboard/platform
@@ -29,7 +27,6 @@ export const PORTAL_ORIGIN_COOKIE_NAME = 'assembly-portal-origin';
29
27
  // plain, comma-separated cookie on every request (set or cleared, never
30
28
  // left stale).
31
29
  export const CLIENT_FLAGS_COOKIE_NAME = 'assembly-flags';
32
- export const PREVIEW_V2_FLAG = 'app-builder-preview-v2';
33
30
  /**
34
31
  * Reads a single cookie by name from a cookie string (defaults to
35
32
  * `document.cookie`). Shared by every module that reads a proxy-mirrored
@@ -51,8 +48,7 @@ export function readCookie(name, cookieString) {
51
48
  }
52
49
  /**
53
50
  * Whether the given flag key is present in the proxy-mirrored flags cookie.
54
- * Exported for other vNext modules (e.g. the paint beacon) to check the same
55
- * cookie without re-parsing it themselves.
51
+ * Exported so client modules can gate on a flag without re-parsing the cookie.
56
52
  */
57
53
  export function hasClientFlag(key, cookieString) {
58
54
  const raw = readCookie(CLIENT_FLAGS_COOKIE_NAME, cookieString);
@@ -61,11 +57,11 @@ export function hasClientFlag(key, cookieString) {
61
57
  return raw.split(',').includes(key);
62
58
  }
63
59
  /**
64
- * Legacy (pre-vNext) framing-origin resolution: `location.ancestorOrigins`
60
+ * Framing-origin resolution for when the portal-origin cookie is unreadable: `location.ancestorOrigins`
65
61
  * (browser-attested; Chromium/WebKit), falling back to `document.referrer`
66
62
  * (Firefox). Null outside an iframe or when neither source is available.
67
63
  */
68
- function resolveLegacyParentOrigin() {
64
+ function resolveFramingOrigin() {
69
65
  if (typeof window === 'undefined')
70
66
  return null;
71
67
  if (window.parent === window)
@@ -85,25 +81,20 @@ function resolveLegacyParentOrigin() {
85
81
  }
86
82
  /**
87
83
  * Register the workspace's portal origin with the bridge allowlist — from the
88
- * proxy-set cookie when the preview-v2 flag is on, from the legacy framing
89
- * origin otherwise. Returns the origin it registered, or null when there was
90
- * nothing to do. Exported for tests; runs once at module load in the browser.
84
+ * proxy-set cookie when it is readable, from the framing origin otherwise.
85
+ * Returns the origin it registered, or null when there was nothing to do.
86
+ * Exported for tests; runs once at module load in the browser.
91
87
  */
92
88
  export function bootstrapPortalOrigin(cookieString) {
93
- if (!hasClientFlag(PREVIEW_V2_FLAG, cookieString)) {
94
- // Flag off: behave exactly like pre-vNext package versions so custom
95
- // portal domains keep a working bridge — and so turning the flag OFF is
96
- // a true rollback, not a third state. Https-only: local dev origins are
97
- // already on the default allowlist.
98
- const origin = resolveLegacyParentOrigin();
89
+ const record = readCookie(PORTAL_ORIGIN_COOKIE_NAME, cookieString);
90
+ if (!record) {
91
+ // Https-only: local dev origins are already on the default allowlist.
92
+ const origin = resolveFramingOrigin();
99
93
  if (!origin || !origin.startsWith('https://'))
100
94
  return null;
101
95
  AssemblyBridge.configure({ additionalOrigins: [origin] });
102
96
  return origin;
103
97
  }
104
- const record = readCookie(PORTAL_ORIGIN_COOKIE_NAME, cookieString);
105
- if (!record)
106
- return null;
107
98
  // Accept only a bare https origin — anything else (paths, http, garbage)
108
99
  // is not a value the proxy writes and must not reach the allowlist.
109
100
  try {
@@ -6,13 +6,7 @@
6
6
  // The HTTP route is handled in proxy.ts via the helpers below (same
7
7
  // package-delegation pattern as session-exchange). The bridge post rides
8
8
  // buffer-until-learned, so a paint that beats the parent's hello is not lost.
9
- //
10
- // Gated on the preview-v2 flag (see origin-bootstrap.ts's hasClientFlag):
11
- // installPaintBeacon() no-ops for a flag-off workspace, so the client never
12
- // calls sendBeacon and the proxy's route never sees a request — no need to
13
- // separately gate handlePaintedBeacon() below.
14
9
  import { AssemblyBridge } from '@assembly-js/app-bridge';
15
- import { hasClientFlag, PREVIEW_V2_FLAG } from './origin-bootstrap.js';
16
10
  export const PAINTED_BEACON_PATH = '/__assembly/painted';
17
11
  export const PAINTED_BEACON_EVENT = 'assembly.painted';
18
12
  let scheduled = false;
@@ -46,9 +40,7 @@ function firePaintBeacon() {
46
40
  * hydration + rAF wins. Does nothing on the server.
47
41
  */
48
42
  export function installPaintBeacon() {
49
- if (typeof window === 'undefined' || scheduled)
50
- return;
51
- if (!hasClientFlag(PREVIEW_V2_FLAG))
43
+ if (typeof window === 'undefined' || typeof document === 'undefined' || scheduled)
52
44
  return;
53
45
  scheduled = true;
54
46
  const afterPaint = () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assembly-js/app-foundation",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "description": "Versioned foundation helpers and build context for Assembly generated apps",
5
5
  "type": "module",
6
6
  "files": [