@assembly-js/app-foundation 0.0.25-rc.0 → 0.0.25-rc.1

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.
@@ -18,8 +18,8 @@ let renewalInFlight = null;
18
18
  // for the freshest session token (the parent keeps it alive) and posts it to the
19
19
  // re-exchange route, which mints a new bearer and sets the HttpOnly cookie — no
20
20
  // page reload. Returns true iff a fresh bearer was set. This is the only place
21
- // app code touches the raw session token, and only to re-mint; it is never sent
22
- // to the platform API.
21
+ // app code touches the raw session token, to re-mint and keep the URL aligned
22
+ // with the cookie; it is never sent to the platform API.
23
23
  export function reexchangeBearer() {
24
24
  if (renewalInFlight)
25
25
  return renewalInFlight;
@@ -30,6 +30,9 @@ export function reexchangeBearer() {
30
30
  return renewal;
31
31
  }
32
32
  async function renewBearer() {
33
+ const previousUrlToken = typeof window === 'undefined'
34
+ ? null
35
+ : new URL(window.location.href).searchParams.get('token');
33
36
  let token = AssemblyBridge.sessionToken.getCurrent()?.token ?? '';
34
37
  // Proactively refresh: we're recovering from an expiry, so avoid re-minting
35
38
  // from a session token that may itself be stale.
@@ -55,6 +58,19 @@ async function renewBearer() {
55
58
  bridgeRefreshFailed,
56
59
  status: res.status,
57
60
  });
61
+ if (res.ok && previousUrlToken !== null) {
62
+ try {
63
+ const url = new URL(window.location.href);
64
+ // Don't overwrite a new preview session opened while renewal was in flight.
65
+ if (url.searchParams.get('token') === previousUrlToken) {
66
+ url.searchParams.set('token', token);
67
+ window.history.replaceState(window.history.state, '', url.href);
68
+ }
69
+ }
70
+ catch {
71
+ // A history update failure must not invalidate the cookie just renewed.
72
+ }
73
+ }
58
74
  return res.ok;
59
75
  }
60
76
  catch {
@@ -55,7 +55,13 @@ export async function mintBearerFromSessionToken(token, options) {
55
55
  try {
56
56
  const resp = await assembly.fetch('/v1/session', {
57
57
  method: 'POST',
58
- headers: { 'Content-Type': 'application/json' },
58
+ headers: {
59
+ 'Content-Type': 'application/json',
60
+ // Let /session validate the token in the body. The SDK's three-part
61
+ // key makes the authorizer reject expired tokens with a generic 403
62
+ // before the handler can distinguish a replay from an outage.
63
+ 'X-API-Key': `${payload.workspaceId}/${process.env.ASSEMBLY_API_KEY ?? ''}`,
64
+ },
59
65
  body: JSON.stringify({
60
66
  sessionId: payload.tokenId,
61
67
  ...(options?.cookieSessionId
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assembly-js/app-foundation",
3
- "version": "0.0.25-rc.0",
3
+ "version": "0.0.25-rc.1",
4
4
  "description": "Versioned foundation helpers and build context for Assembly generated apps",
5
5
  "type": "module",
6
6
  "files": [