@assembly-js/app-foundation 0.0.49 → 0.0.51

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
@@ -14,6 +14,12 @@ A foundation update reads the sections between an app's version and the target:
14
14
  from every bullet except `[guidance]`, agent work from the check scripts those `[action]`
15
15
  bullets ship. Write `[fix]`, `[behavior]` and `[action]` bullets for the app's owner.
16
16
 
17
+ ## 0.0.51
18
+ - [guidance] The build agent is told that its preview is `localhost:3000` and that the public sandbox host is unreachable from inside the sandbox.
19
+
20
+ ## 0.0.50
21
+ - [guidance] The build agent is no longer told to reinstall packages that come pre-installed, offered a toast library the platform bans, or shown a secret type the manifest rejects, and its header guidance no longer contradicts itself when the app owns its header. It is also told why the dashboard and client surfaces take separate routes and to detect the viewer with `getSessionIdentity()`.
22
+
17
23
  ## 0.0.49
18
24
  - [fix] Scheduled-work wiring, proxy, and session-token problems are now caught when the platform updates the app, not only when the app's own change touches them.
19
25
 
package/CLAUDE.md CHANGED
@@ -41,7 +41,9 @@ Assembly-specific gotchas live in `.claude/skills/<name>/SKILL.md`. Invoke them
41
41
  - `assembly-automations` — REQUIRED when the request asks for a platform-side effect in reaction to an in-app event (a message, a CRM field, a contract, a form, a file — not the app's own tables), even if the user never says "automation": declare the app's API contract in `.assembly/api-resources.json` (a separate file from `app.json`) — domain events that become automation triggers + workspace webhooks, and staff-invokable operations that become automation actions. Declared events must also be emitted at runtime — inside `after()`, reporting the acting user on the documented headers — declaring alone never fires anything. Read it before adding either.
42
42
  <!-- /feature:api-resources -->
43
43
  - `assembly-app-surfaces` — REQUIRED before writing `.assembly/app.json`: declare which surfaces (dashboard, client portal, notification) the app exposes; omitting the client surface keeps the app off client portal nav entirely
44
+ <!-- !feature:app-owned-header -->
44
45
  - `assembly-app-bridge-header` — breadcrumbs (don't include app name), CTAs
46
+ <!-- /feature:app-owned-header -->
45
47
  - `assembly-app-bridge-toast` — show toast notifications in the parent dashboard
46
48
  <!-- feature:deep-link-bridge-nav -->
47
49
  - `assembly-platform-links` — link platform records (client, company, invoice, contract, form, file) to their portal detail page via `linkTo()`; never hand-build a host URL. Also links between workspace apps by install id. Check the app's installed app-bridge first (see the skill) — `navigateTo` doesn't exist on older peers — and only link staff-only destinations (client, company, form, etc.) from the dashboard surface, never the client portal.
@@ -62,6 +64,7 @@ Assembly-specific gotchas live in `.claude/skills/<name>/SKILL.md`. Invoke them
62
64
  - `assembly-route-errors` — REQUIRED in every route handler: use `handleRouteError` from `@assembly-js/app-foundation/server` in catch blocks — never return `err.message`. Validate values before they hit typed DB columns (e.g. `parseUuid` before a uuid-column lookup).
63
65
  - `assembly-action-results` — REQUIRED when a server action refuses work the UI should explain (validation, permission, not ready to send): return `{ ok: false, message }` instead of throwing. A thrown message is redacted in production.
64
66
  - `assembly-dev-server-logs` — the dev server's stdout/stderr (server-side errors, stack traces, console output) is readable at `/tmp/dev-server.log`; check it before guessing at a 500 or broken preview.
67
+ - Your own preview is `localhost:3000`; never fetch the public `sb-*.vercel.run` host from inside the sandbox (egress to it is blocked).
65
68
 
66
69
  ---
67
70
 
@@ -457,9 +460,9 @@ Because the app runs in an iframe inside the parent dashboard, several normal Ne
457
460
  - **Cookies must be `sameSite: 'none'` and `secure: true`.** Anything else is dropped silently in cross-origin iframes.
458
461
  - **No top-level navigation.** Don't use `window.location = '...'` to go to external URLs — it'll either break out of the iframe or be blocked. For external links use `<a target="_blank" rel="noreferrer">`.
459
462
  - **No `window.open(..., '_self')`.** Same issue.
463
+ <!-- !feature:app-owned-header -->
460
464
  - **The portal owns the chrome (header, sidebar).** Don't render your own breadcrumbs or page titles via DOM. Use `@assembly-js/app-bridge` to set them.
461
465
  - **Never put the app name in breadcrumbs.** The parent portal *automatically* prepends the app's name as breadcrumb 0. If you also pass `{ label: 'MyApp' }` as the first entry of `setBreadcrumbs`, it renders twice ("MyApp / MyApp / Reports"). For a flat one-page app pass `[]` (or skip `setBreadcrumbs` entirely). For a multi-level app pass only the sub-pages: `setBreadcrumbs([{ label: 'Reports' }, { label: 'Q4 2026' }])`. Read `.claude/skills/assembly-app-bridge-header/SKILL.md` for full examples.
462
- <!-- !feature:app-owned-header -->
463
466
  - **Action buttons go in the header — set via the `useAssemblyHeader` hook.** Submit, Save, Edit, Create — any primary page-level action MUST live in the header (`primaryCta`), not a `<Button>` in the page body. Secondary actions use `secondaryCta`; overflow/tertiary actions use `actionsMenu`. Drive all of it through the `useAssemblyHeader` hook (`app/components/use-assembly-header.ts`) — **never call `AssemblyBridge.header.set*` from your own `useEffect`** (that hand-rolling is what makes header buttons vanish after a re-render). See `.claude/skills/assembly-app-bridge-header/SKILL.md` for the full API.
464
467
  **Exception: the notification surface (`/n`).** The Notification Center embeds the `/n` route in a plain `<iframe>` without app bridge header support. `useAssemblyHeader` calls are silently ignored — header CTAs never appear. On the notification surface, render primary actions as inline `<Button>` elements in the page body. Detect the notification surface by the route — code under `app/n/` IS the surface; for a shared component pass an explicit prop from the `/n` page rather than inferring from `payload.notificationId`, which is best-effort under the session-exchange flow. This exception applies ONLY to the `/n` route; all other surfaces MUST use the header. **Do not reuse a component that calls `useAssemblyHeader` on the `/n` surface** — if it also has an inline action button, both the header CTA and the inline button will render on non-notification surfaces (duplicate CTAs). Either create a separate component for `/n` or accept a prop that switches between header and inline CTAs.
465
468
  <!-- /feature:app-owned-header -->
@@ -528,7 +531,7 @@ Two paths, decided by whether an `assembly-integrations` skill is present and, i
528
531
  "key": "SENDGRID_API_KEY",
529
532
  "label": "SendGrid API key",
530
533
  "description": "Used to send ticket-submitted emails. Create one under SendGrid Settings > API Keys.",
531
- "type": "password",
534
+ "type": "api_key",
532
535
  "docsUrl": "https://docs.sendgrid.com/ui/account-and-settings/api-keys"
533
536
  }
534
537
  ]
@@ -642,9 +645,11 @@ If you forget this, `bun`/`bunx` commands will fail with "command not found". Th
642
645
  ### Install (use bun)
643
646
 
644
647
  ```bash
645
- export PATH="$HOME/.bun/bin:$PATH" && bun add @assembly-js/node-sdk @assembly-js/app-bridge
648
+ export PATH="$HOME/.bun/bin:$PATH" && bun add <extra-package>
646
649
  ```
647
650
 
651
+ `@assembly-js/node-sdk` and `@assembly-js/app-bridge` are already installed, so don't `bun add` them. Use `bun add` only for an extra package the task needs.
652
+
648
653
  ### Inner verification loop — type-check, don't full-build
649
654
 
650
655
  Use `bunx tsc --noEmit` to verify your changes while iterating. It runs in 2–3s and gives you the full, untruncated type errors. Reserve `bun run build` (~15–20s for a full Next build) for the **final** check at the end of the task, not after every edit. Running `bun run build` between trivial edits adds ~15s of dead time per cycle.
@@ -807,7 +812,7 @@ This app uses the **Assembly UI** component registry (`@assembly-ui` namespace i
807
812
 
808
813
  **shadcn drop-in replacements** — same composition patterns, same sub-component names, same imports. Built on `@base-ui/react` — root props differ from Radix/shadcn (see documented differences above; check `components/ui/<name>.tsx` if you hit a type error):
809
814
 
810
- accordion, alert, alert-dialog, avatar, badge, breadcrumb, button, button-group, calendar, card, checkbox, collapsible, combobox, dialog, dropdown-menu, field, input, input-group, item, label, popover, progress, radio-group, select, separator, skeleton, slider, sonner, spinner, switch, table, tabs, textarea, toggle, toggle-group, tooltip
815
+ accordion, alert, alert-dialog, avatar, badge, breadcrumb, button, button-group, calendar, card, checkbox, collapsible, combobox, dialog, dropdown-menu, field, input, input-group, item, label, popover, progress, radio-group, select, separator, skeleton, slider, spinner, switch, table, tabs, textarea, toggle, toggle-group, tooltip
811
816
 
812
817
  **Custom Assembly components** — these are NOT shadcn drop-ins. They have their own unique APIs and do not follow standard shadcn composition patterns. Read the usage instructions below before using them:
813
818
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assembly-js/app-foundation",
3
- "version": "0.0.49",
3
+ "version": "0.0.51",
4
4
  "description": "Versioned foundation helpers and build context for Assembly generated apps",
5
5
  "type": "module",
6
6
  "files": [
@@ -75,5 +75,5 @@ interface ToastShowPayload {
75
75
  ## Rules
76
76
 
77
77
  - **Client components only.** `AssemblyBridge` posts messages to the parent window — call it in `'use client'` components only.
78
- - **Don't build toast UI inside the iframe.** The parent dashboard renders the toast in its own chrome; your iframe should have no toast component.
78
+ - **Don't build toast UI inside the iframe.** The parent dashboard renders the toast in its own chrome; your iframe should have no toast component, so don't install or import `sonner` or `react-hot-toast`.
79
79
  - **Don't stack multiple toasts for one action.** Show one toast per user action.
@@ -26,7 +26,7 @@ If you are unsure, default to **internal-only**. Do not add a client surface unl
26
26
  ```
27
27
 
28
28
  - `internal` is **required** — every Vibe app must have a dashboard surface. `client` is optional; omit it for internal-only apps. `notification` is optional; declare it when opening a notification should land on a specific record (see below).
29
- - `path` is the route within your app for that surface. Must start with `/`. Use `/` for the surface's root; use distinct sub-paths if both surfaces share one Next.js app.
29
+ - `path` is the route within your app for that surface. Must start with `/`. Use `/` for the surface's root; use a distinct sub-path (`/c` for the client surface) for each other surface. Two routes, because the same path can't tell the dashboard viewer from the client viewer without branching on the token, and each surface needs its own layout and its own access rules.
30
30
  - Generate the corresponding routes in your app code. E.g. if you declare `client.path = "/c"`, you must have a `/c` page in the app.
31
31
 
32
32
  <!-- !feature:notification-settings -->
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: assembly-client-users
3
- description: Use when the app needs to read, list, create, or update client users — the customers of the business that owns the Assembly workspace. Clients sign into the branded Client Portal and see only their own data. Detect via tokenPayload.clientId.
3
+ description: Use when the app needs to read, list, create, or update client users — the customers of the business that owns the Assembly workspace. Clients sign into the branded Client Portal and see only their own data. Detect via getSessionIdentity().
4
4
  ---
5
5
 
6
6
  Client users are **customers of the business** that owns the Assembly workspace. They sign into the branded Client Portal at the workspace's domain. They see only their own data — their own messages, their own files, their own invoices.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: assembly-internal-users
3
- description: Use when the app reads/lists internal users, gates a feature to workspace admins (role is "admin" or "staff"), or an internal viewer browses clients/companies in the Dashboard. Covers Client Access (isClientAccessLimited, companyAccessList) scoping. Internal users sign into the Dashboard only. Detect via tokenPayload.internalUserId.
3
+ description: Use when the app reads/lists internal users, gates a feature to workspace admins (role is "admin" or "staff"), or an internal viewer browses clients/companies in the Dashboard. Covers Client Access (isClientAccessLimited, companyAccessList) scoping. Internal users sign into the Dashboard only. Detect via getSessionIdentity().
4
4
  ---
5
5
 
6
6
  Internal users are the **business team** running the Assembly workspace. They sign into the Dashboard at the workspace's domain, never the branded Client Portal. They have full read/write power over clients, companies, files, etc. — **within their Client Access scope** (see below).