@assembly-js/app-foundation 0.5.0 → 0.5.2
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 +6 -0
- package/CLAUDE.md +2 -1
- package/dist/paint-beacon.js +5 -1
- package/package.json +1 -1
- package/skills/assembly-storage/SKILL.md +20 -1
package/CHANGELOG.md
CHANGED
|
@@ -19,6 +19,12 @@ 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.5.2
|
|
23
|
+
- [fix] The builder preview no longer counts a page marked as an error document in its server HTML as the app having painted, even when it streams in before the page finishes hydrating.
|
|
24
|
+
|
|
25
|
+
## 0.5.1
|
|
26
|
+
- [guidance] The build agent now detects PDF form fields with `detectPdfFields` and gives XFA, text-only and empty PDFs their own UI instead of reporting "no fields".
|
|
27
|
+
|
|
22
28
|
## 0.5.0
|
|
23
29
|
- [new] `detectPdfFields` from `@assembly-js/app-foundation/server` finds the fields on a PDF form: AcroForm fields with their page, kind and options; an XFA form reported as such; or, for a PDF with only text, fields suggested by Assembly AI when an Assembly client is passed, with the page text returned either way. A file that is not a PDF throws `PdfUnreadableError`.
|
|
24
30
|
|
package/CLAUDE.md
CHANGED
|
@@ -657,7 +657,7 @@ Server components, route handlers, and server actions run in **Node on Vercel**
|
|
|
657
657
|
|
|
658
658
|
- **Visual work** (draw a chart, render on a canvas) is **client** work — load the library with `next/dynamic` + `ssr: false`, never in server code.
|
|
659
659
|
- **Fuzzy extraction** (pull fields from a document, classify, summarize) is usually better done through the **AI proxy** (see `assembly-ai`) than a parsing lib — no native binding, no serverless hazard.
|
|
660
|
-
- **Genuine server-side data work** (transform an image, parse bytes) must use a Node-native library: add native/CommonJS packages (e.g. `sharp`) to `serverExternalPackages` in `app.config.ts` (bundling breaks the binding). A library that locates files at runtime — a worker script, a native binding, font data — by a path computed from its own location breaks after deploy: the bundler relocates its code and the deployed function only has the files reachable from literal imports, so the lookup fails even though preview has the full `node_modules`. Prefer a self-contained server build. **PDF text: `extractPdfText` from `@assembly-js/app-foundation/server`** — never `pdf-parse` or `pdfjs-dist` on the server; both look their worker and canvas up this way and fail on every deployed upload.
|
|
660
|
+
- **Genuine server-side data work** (transform an image, parse bytes) must use a Node-native library: add native/CommonJS packages (e.g. `sharp`) to `serverExternalPackages` in `app.config.ts` (bundling breaks the binding). A library that locates files at runtime — a worker script, a native binding, font data — by a path computed from its own location breaks after deploy: the bundler relocates its code and the deployed function only has the files reachable from literal imports, so the lookup fails even though preview has the full `node_modules`. Prefer a self-contained server build. **PDF text and form fields: `extractPdfText` and `detectPdfFields` from `@assembly-js/app-foundation/server`** — never `pdf-parse` or `pdfjs-dist` on the server; both look their worker and canvas up this way and fail on every deployed upload. Detect fields on the server, not with pdf-lib or pdfjs in the browser: the helper already covers XFA forms and text-only PDFs, which a browser-side AcroForm read reports as "no fields".
|
|
661
661
|
- **Browser-only packages** (touch `window`/`document`/`DOMMatrix`/`HTMLCanvasElement` at import *or during operations*) can't run server-side at all — `serverExternalPackages` doesn't help and dynamic `import()` only defers the crash. Use a Node-native alternative or move the work client-side.
|
|
662
662
|
|
|
663
663
|
---
|
|
@@ -1506,6 +1506,7 @@ Use `AssemblyBridge.header.*` for breadcrumbs, CTAs, and actions menu. See `.cla
|
|
|
1506
1506
|
- ❌ Don't edit `next.config.ts` — it's the platform-owned wrapper that keeps the preview working (cross-origin hydration, WebSocket-blocked networks), and `bun run build` fails if it's rewritten. Your Next configuration belongs in `app.config.ts`.
|
|
1507
1507
|
- ❌ Don't import a native or browser-only library into server code without the serverless setup — `bun run build` passes but the deployed route crashes at request time. Decide the layer first per "Server runs in serverless Node" above.
|
|
1508
1508
|
- ❌ Don't preview a PDF (or any file) in an `<iframe>`, `<embed>` or `<object>` — the portal frame is sandboxed and Chrome won't run its PDF viewer inside it, so the preview renders blank while the build passes. Open the pre-signed URL in a new tab (`assembly-storage` Pattern A) or render pages to a canvas client-side with `next/dynamic` + `ssr: false`.
|
|
1509
|
+
- ❌ Don't build a PDF-to-form feature on AcroForm fields alone. Call `detectPdfFields` and branch on `method`: `none` and `xfa` need a visible explanation plus a manual add-field path, and `text` fields are suggestions the user must be able to edit before saving. Plenty of real forms are Word exports, scans or XFA, so an AcroForm-only app tells those users their form is empty.
|
|
1509
1510
|
- ❌ Don't call a change verified, working, or safe to publish because `tsc --noEmit` and `bun run build` passed — name the checks that ran and the signed-in screens left unopened. See "What a passing build proves" above.
|
|
1510
1511
|
- ❌ Don't pass a function — or an object that holds one, like a question/field config with `visibleWhen`, `validate`, `render`, or `format` callbacks — as a prop from a server component or page into a `'use client'` component. Props cross that boundary as serialized data, so the render throws `Functions cannot be passed directly to Client Components` and the page 500s for every visitor no matter what the record holds. `tsc --noEmit` and `bun run build` both pass. Keep such a config in a shared module the client component imports itself, or express the logic as data (`{ showWhen: { field: 'entityType', equals: 'llc' } }`) and interpret it client-side.
|
|
1511
1512
|
- ❌ Don't call a function imported from a `'use client'` file from a server component, layout, or server action — e.g. an answer formatter defined in the client component file that the `/n` notification page also renders. The server gets a client reference, not the function, so the render throws and the route 500s for every visitor; `tsc --noEmit` passes. A `'use client'` file should export only components and hooks; put a shared helper in a plain module (`lib/…`) both sides import. `bun run build` fails on this (`check:client-boundary`).
|
package/dist/paint-beacon.js
CHANGED
|
@@ -17,8 +17,12 @@ let fired = false;
|
|
|
17
17
|
// the schedule latch, so the boundary can re-install it once the app has
|
|
18
18
|
// rendered in its place.
|
|
19
19
|
const ERROR_DOCUMENT_FLAG = '__assemblyErrorDocument';
|
|
20
|
+
// The same pages also carry this attribute in their server HTML. A page streamed
|
|
21
|
+
// in under Suspense can reach load before React hydrates it and sets the flag.
|
|
22
|
+
const ERROR_DOCUMENT_SELECTOR = '[data-assembly-error-document]';
|
|
20
23
|
function isErrorDocument() {
|
|
21
|
-
return window[ERROR_DOCUMENT_FLAG] === true
|
|
24
|
+
return (window[ERROR_DOCUMENT_FLAG] === true ||
|
|
25
|
+
document.querySelector(ERROR_DOCUMENT_SELECTOR) !== null);
|
|
22
26
|
}
|
|
23
27
|
function firePaintBeacon() {
|
|
24
28
|
if (fired)
|
package/package.json
CHANGED
|
@@ -151,7 +151,9 @@ export async function POST(request: NextRequest) {
|
|
|
151
151
|
if (!res.ok) throw new Error('S3 fetch failed: ' + res.status);
|
|
152
152
|
const buffer = Buffer.from(await res.arrayBuffer());
|
|
153
153
|
// ...process the buffer here; the file is already stored, no second upload.
|
|
154
|
-
// PDF text: const { text } = await extractPdfText(buffer)
|
|
154
|
+
// PDF text: const { text } = await extractPdfText(buffer) (empty text = scanned PDF, no text layer).
|
|
155
|
+
// PDF form fields: const detection = await detectPdfFields(buffer, { assembly }) — see below.
|
|
156
|
+
// Both come from '@assembly-js/app-foundation/server'.
|
|
155
157
|
return NextResponse.json({ ok: true });
|
|
156
158
|
} catch (err) {
|
|
157
159
|
return handleRouteError(err, 'Processing failed');
|
|
@@ -163,6 +165,23 @@ The bytes still cross the network into your function (the cap is on the inbound
|
|
|
163
165
|
`fetch`), but they arrive via S3 GET, which has no Lambda payload limit. You also get the stored `key` for
|
|
164
166
|
free — no second upload.
|
|
165
167
|
|
|
168
|
+
### Detecting form fields in an uploaded PDF
|
|
169
|
+
|
|
170
|
+
A PDF-to-form feature calls the helper in the processing route and lets `method` decide the UI. Passing
|
|
171
|
+
`assembly` (from `getAssemblyForRequest(request)`) lets a text-only PDF get AI-suggested fields; without
|
|
172
|
+
it, `text` comes back with no fields. A file that is not a PDF throws `PdfUnreadableError`, whose message
|
|
173
|
+
is safe to show.
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
const detection = await detectPdfFields(buffer, { assembly });
|
|
177
|
+
switch (detection.method) {
|
|
178
|
+
case 'acroform': break; // prefill the form from detection.fields
|
|
179
|
+
case 'text': break; // show detection.fields as editable suggestions the user confirms before saving; if empty, say none were suggested and offer manual add-field
|
|
180
|
+
case 'xfa': break; // say this form type can't be read automatically, then offer manual add-field
|
|
181
|
+
case 'none': break; // say no fields or text were found (likely a scan), then offer manual add-field
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
166
185
|
## What NOT to do
|
|
167
186
|
|
|
168
187
|
- Do NOT add `Authorization`/`X-API-Key` to the S3 PUT — extra headers cause `SignatureDoesNotMatch`.
|