@assembly-js/app-foundation 0.0.42 → 0.0.45
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 +178 -0
- package/CLAUDE.md +268 -24
- package/fixes.json +64 -0
- package/package.json +4 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@assembly-js/app-foundation`, newest first. Each `## <version>` section
|
|
4
|
+
lists what that version means for an app that already exists, one kind per bullet:
|
|
5
|
+
|
|
6
|
+
- `[fix]` — fixed on install; the app's code doesn't change.
|
|
7
|
+
- `[behavior]` — the app behaves differently on install with no code change; its owner should know.
|
|
8
|
+
- `[action: <id>]` — the app's own code must change; `<id>` names the `fixes.json` entry that
|
|
9
|
+
detects the gap and tells the update agent how to close it.
|
|
10
|
+
- `[new]` — something the app can adopt; nothing changes until it does.
|
|
11
|
+
- `[guidance]` — changes what the build agent is taught for future work, not existing code.
|
|
12
|
+
|
|
13
|
+
A foundation update reads the sections between an app's version and the target: owner-facing copy
|
|
14
|
+
from every bullet except `[guidance]`, agent work from the `fixes.json` entries those `[action]`
|
|
15
|
+
bullets name. Write `[fix]`, `[behavior]` and `[action]` bullets for the app's owner.
|
|
16
|
+
|
|
17
|
+
## 0.0.45
|
|
18
|
+
- [guidance] The generated SDK method tables no longer list the session and token methods the foundation calls itself, and the module notes name each module's SDK groups.
|
|
19
|
+
|
|
20
|
+
## 0.0.43
|
|
21
|
+
- [guidance] The build agent's SDK method tables are now generated from the SDK instead of hand-written.
|
|
22
|
+
|
|
23
|
+
## 0.0.42
|
|
24
|
+
- [action: package-proxy] Sign-in and cross-site request protection now come from the package instead of code the app owns, and are checked by sending real requests through the app.
|
|
25
|
+
|
|
26
|
+
## 0.0.41
|
|
27
|
+
- [guidance] Tell the build agent where an owner updates an API key that has expired or been rejected (App secrets in the builder chat, then republish), instead of sending them to support.
|
|
28
|
+
|
|
29
|
+
## 0.0.40
|
|
30
|
+
- [behavior] Confirm each viewer's session with the platform instead of trusting the token alone, cached briefly per server. If the platform can't be reached, the app fails closed instead of guessing who is signed in.
|
|
31
|
+
- [action: identity-outage-states] Show a retry screen when the platform can't confirm the viewer instead of an error page, and stop a failing app from renewing its session over and over.
|
|
32
|
+
|
|
33
|
+
## 0.0.39
|
|
34
|
+
- [fix] Let an app keep a scheduled job it already runs more often than every 30 minutes: the cron check now warns about that schedule instead of failing the build.
|
|
35
|
+
|
|
36
|
+
## 0.0.38
|
|
37
|
+
- [guidance] Keep a usage-threshold alert going to the person whose own action crossed the threshold, and only record the alert as sent once it actually was, so a failed send can retry.
|
|
38
|
+
|
|
39
|
+
## 0.0.37
|
|
40
|
+
- [fix] Fix saves of records with nested rows (a proposal's packages, a retainer's allowances) failing with a 500 and leaving the parent without its children.
|
|
41
|
+
- [action: inlined-child-rows-batch] Apps that copied the child-row helper into their own code carry the same bug and need the package's helper instead.
|
|
42
|
+
|
|
43
|
+
## 0.0.36
|
|
44
|
+
- [fix] Accept notification category ids with underscores (`past_due`), so a build no longer fails on the id the user asked for.
|
|
45
|
+
|
|
46
|
+
## 0.0.35
|
|
47
|
+
- [guidance] Tell the build agent which modules every workspace has (clients, companies, custom fields, notifications) and which it must confirm are installed before planning around them (forms, files, tasks, billing and the rest).
|
|
48
|
+
- [new] Add `replaceChildRows`, a helper that replaces a record's child rows safely, so saving a form can't drop rows the user just added.
|
|
49
|
+
|
|
50
|
+
## 0.0.34
|
|
51
|
+
- [guidance] Teach the build agent to link to platform records (a client, a company, an invoice, another app) with `linkTo()` instead of hand-building host URLs.
|
|
52
|
+
|
|
53
|
+
## 0.0.33
|
|
54
|
+
- [fix] Report the right in-app location for apps whose client or internal surface lives at a custom path, not only `/c` and `/n`.
|
|
55
|
+
|
|
56
|
+
## 0.0.32
|
|
57
|
+
- [guidance] Teach the AI skill speech-to-text: record compressed audio in the browser and transcribe it on the server, within the request-size cap.
|
|
58
|
+
|
|
59
|
+
## 0.0.31
|
|
60
|
+
- [fix] Fix file downloads breaking under bearer-only auth: a partitioned cookie wasn't sent when the download opened in a new tab.
|
|
61
|
+
|
|
62
|
+
## 0.0.30
|
|
63
|
+
- [fix] Accept `privateRoutes` in the manifest validator.
|
|
64
|
+
|
|
65
|
+
## 0.0.29
|
|
66
|
+
- [guidance] Give generated apps the workspace admin role by default instead of leaving them to guess it.
|
|
67
|
+
|
|
68
|
+
## 0.0.28
|
|
69
|
+
- [guidance] Fix draft creation dropping fields the user had already submitted.
|
|
70
|
+
|
|
71
|
+
## 0.0.27
|
|
72
|
+
- [guidance] Let the build agent ask the user structured questions instead of free-text chat.
|
|
73
|
+
|
|
74
|
+
## 0.0.27-rc.0
|
|
75
|
+
- [guidance] Tell the build agent what a passing build actually proves, and what it still has to disclose to the user.
|
|
76
|
+
|
|
77
|
+
## 0.0.26
|
|
78
|
+
- [guidance] Warn the build agent that props passed into client components must be serializable.
|
|
79
|
+
|
|
80
|
+
## 0.0.25-rc.6
|
|
81
|
+
- [guidance] Teach server actions to return a refusal as data instead of throwing, so the UI can explain it.
|
|
82
|
+
|
|
83
|
+
## 0.0.25-rc.5
|
|
84
|
+
- [new] Alert Slack when one of an app's scheduled jobs fails.
|
|
85
|
+
|
|
86
|
+
## 0.0.25-rc.4
|
|
87
|
+
- [fix] Fix generated apps breaking in Safari, which refuses the bearer cookie under its default tracking protection.
|
|
88
|
+
|
|
89
|
+
## 0.0.25-rc.3
|
|
90
|
+
- [guidance] Add flag-gated guidance for apps that own their own header instead of the app bridge header.
|
|
91
|
+
|
|
92
|
+
## 0.0.25-rc.2
|
|
93
|
+
- [fix] Grandfather pre-existing cron wiring and declare `CRON_SECRET` from `vercel.json` automatically.
|
|
94
|
+
|
|
95
|
+
## 0.0.25-rc.0
|
|
96
|
+
- [guidance] Teach generated apps to run scheduled work on a Vercel cron.
|
|
97
|
+
|
|
98
|
+
## 0.0.24
|
|
99
|
+
- [fix] Fix Slack mention tokens not resolving to real names in built apps.
|
|
100
|
+
|
|
101
|
+
## 0.0.23
|
|
102
|
+
- [guidance] Update Slack guidance across all Nango-backed actions.
|
|
103
|
+
|
|
104
|
+
## 0.0.22
|
|
105
|
+
- [new] Ship vNext content: origin bootstrap and a cookie-outcome log line.
|
|
106
|
+
- [action: paint-beacon] The builder preview now tells a page that rendered from one that only loaded, which needs the paint beacon in the app.
|
|
107
|
+
|
|
108
|
+
## 0.0.21
|
|
109
|
+
- [new] Add Slack error-code and channel-list helpers, and a tripwire against an accidental `useServerAction` fetch loop, ahead of connector GA.
|
|
110
|
+
|
|
111
|
+
## 0.0.20
|
|
112
|
+
- [action: next-config-wrapper] The live preview no longer hangs on networks that block its dev connection, which needs the app's Next config split into the platform wrapper and the app's own settings.
|
|
113
|
+
|
|
114
|
+
## 0.0.19
|
|
115
|
+
- [guidance] Align the connector action catalog's signatures with the vendored scripts' actual behavior.
|
|
116
|
+
|
|
117
|
+
## 0.0.18
|
|
118
|
+
- [guidance] Fill vendored-action and doc gaps for exposed connectors, plus spreadsheet metadata.
|
|
119
|
+
|
|
120
|
+
## 0.0.17
|
|
121
|
+
- [guidance] Revert: restore the pre-slim app-builder context. 0.0.11's slimmed-down context regressed build quality, so this release reverts it wholesale.
|
|
122
|
+
|
|
123
|
+
## 0.0.16
|
|
124
|
+
- [new] Deepen exposed-provider docs and add a `gmailSendEmail` foundation helper.
|
|
125
|
+
|
|
126
|
+
## 0.0.15
|
|
127
|
+
- [guidance] Tell the build agent not to promise Slack DMs the app can't actually send.
|
|
128
|
+
|
|
129
|
+
## 0.0.14
|
|
130
|
+
- [new] Add Airtable record labels and column formatting, with a matching provider doc and foundation helper.
|
|
131
|
+
|
|
132
|
+
## 0.0.13
|
|
133
|
+
- [guidance] Add per-provider doc rendering for the assembly-integrations skill.
|
|
134
|
+
|
|
135
|
+
## 0.0.12
|
|
136
|
+
- [behavior] Namespace each app's automation triggers and actions with a per-app `~<appId>.` prefix.
|
|
137
|
+
|
|
138
|
+
## 0.0.11
|
|
139
|
+
- [guidance] Release a slimmed-down build-agent context to migrated apps. (Reverted at 0.0.17.)
|
|
140
|
+
|
|
141
|
+
## 0.0.10
|
|
142
|
+
- [new] Add deterministic notification-clear and deferred-auth helper utilities.
|
|
143
|
+
|
|
144
|
+
## 0.0.9
|
|
145
|
+
- [fix] Fix custom-domain portals failing to frame the app by registering the framing origin with the app-bridge allowlist.
|
|
146
|
+
|
|
147
|
+
## 0.0.8-rc.0
|
|
148
|
+
- [new] Add sandbox bindings for the scoped platform MCP.
|
|
149
|
+
|
|
150
|
+
## 0.0.7
|
|
151
|
+
- [fix] Fix invalid YAML in skill frontmatter.
|
|
152
|
+
|
|
153
|
+
## 0.0.6
|
|
154
|
+
- [fix] Add identity-aware session-exchange rejection and single-flight, marker-gated bearer renewal.
|
|
155
|
+
|
|
156
|
+
## 0.0.5
|
|
157
|
+
- [guidance] Fix automation events firing from more than one code path by emitting them only inside `after()`.
|
|
158
|
+
|
|
159
|
+
## 0.0.4
|
|
160
|
+
- [guidance] Teach the build agent to reach for automations when a request describes a workflow.
|
|
161
|
+
|
|
162
|
+
## 0.0.3
|
|
163
|
+
- [guidance] Move the build guards into the app-foundation package tree.
|
|
164
|
+
|
|
165
|
+
## 0.0.2
|
|
166
|
+
- [guidance] Release the context package as 0.0.2.
|
|
167
|
+
|
|
168
|
+
## 0.0.2-rc.2
|
|
169
|
+
- [guidance] Render context prose in the sandbox so the package owns every skill.
|
|
170
|
+
|
|
171
|
+
## 0.0.1
|
|
172
|
+
- [new] First stable release of `@assembly-js/app-foundation`.
|
|
173
|
+
|
|
174
|
+
## 0.0.1-rc.2
|
|
175
|
+
- [fix] Fix the published package being unimportable by Node; drop `.js` extensions from `src` and add them back on emit.
|
|
176
|
+
|
|
177
|
+
## 0.0.1-rc.1
|
|
178
|
+
- [new] First published version, under the `rc` dist-tag.
|
package/CLAUDE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Assembly App Guide
|
|
2
2
|
|
|
3
|
-
You are an expert frontend engineer building a custom app that runs **inside an Assembly portal as an iframe**. You create beautiful, performant, mobile-first applications that follow UI/UX and shadcn best practices and provide clear user feedback. **Design mobile-first: every component and layout must start from a single-column, narrow-viewport base (down to 320px) and scale up using `sm:`, `md:`, and `lg:` breakpoints.** This applies to grids, padding, typography, tabs, and any horizontal arrangement. If a task description gives you non-responsive CSS, adapt it to be mobile-first yourself. Read this whole file before writing any code — it contains the platform model, the data model, the SDK surface, and the iframe constraints. The information here is more current than your training data. **
|
|
3
|
+
You are an expert frontend engineer building a custom app that runs **inside an Assembly portal as an iframe**. You create beautiful, performant, mobile-first applications that follow UI/UX and shadcn best practices and provide clear user feedback. **Design mobile-first: every component and layout must start from a single-column, narrow-viewport base (down to 320px) and scale up using `sm:`, `md:`, and `lg:` breakpoints.** This applies to grids, padding, typography, tabs, and any horizontal arrangement. If a task description gives you non-responsive CSS, adapt it to be mobile-first yourself. Read this whole file before writing any code — it contains the platform model, the data model, the SDK surface, and the iframe constraints. The information here is more current than your training data. **The SDK method tables below are generated from the SDK's type definitions.**
|
|
4
4
|
|
|
5
5
|
## Communication rules
|
|
6
6
|
|
|
@@ -164,17 +164,14 @@ Before adding a feature, check whether Assembly already covers it. If it does, *
|
|
|
164
164
|
|
|
165
165
|
**Optional modules (may or may not be installed in this workspace):** Messages, Files, Contracts, Forms, Billing, Knowledge Base, Tasks, and Notes. Before suggesting one or calling its SDK, confirm it is installed — call `listAppInstalls`. If it is installed, use it through the SDK; do not rebuild it. If it is not installed, do not suggest it, do not plan the app around it, and do not ask the user to install it.
|
|
166
166
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
| Knowledge Base | Help articles / docs | (no SDK methods today; render-only) |
|
|
176
|
-
| Tasks | Assign tasks to clients/team | `retrieveTasks`, `createTask`, `retrieveTask`, `updateTask`, `deleteTask`, `listTaskTemplates`, `retrieveTaskTemplate` |
|
|
177
|
-
| Notes | Per-client/company internal notes | `createNote`, `listNotes`, `retrieveNote`, `updateNote`, `deleteNote` |
|
|
167
|
+
- **Messages** — Direct messaging between staff and clients. SDK groups: Messages, MessageChannels.
|
|
168
|
+
- **Files** — Secure file/folder sharing. *For app-private uploads (attachments, exports) use the storage helpers from `@assembly-js/app-foundation/server` (see the `assembly-storage` skill) instead — Files is only for files the user wants in the portal Files tab.* SDK groups: Files, FileChannels.
|
|
169
|
+
- **Contracts** — eSignature contracts. SDK groups: Contracts, ContractTemplates.
|
|
170
|
+
- **Forms** — Intake forms / surveys (6 question types). SDK groups: Forms, FormResponses.
|
|
171
|
+
- **Billing** — Invoices, subscriptions, payments. SDK groups: Invoices, InvoiceTemplates, Subscriptions, SubscriptionTemplates, Products, Prices, Payments, Refunds.
|
|
172
|
+
- **Knowledge Base** — Help articles / docs (no SDK methods; render-only).
|
|
173
|
+
- **Tasks** — Assign tasks to clients/team. SDK groups: Tasks, TaskTemplates, Comments (task comments).
|
|
174
|
+
- **Notes** — Per-client/company internal notes. SDK groups: Notes.
|
|
178
175
|
|
|
179
176
|
If the user's prompt says "build a CRM," the answer is mostly **wire up the existing Clients + Companies** (and any optional modules that are actually installed) **in a custom view** — not invent your own.
|
|
180
177
|
|
|
@@ -182,14 +179,261 @@ If the user's prompt says "build a CRM," the answer is mostly **wire up the exis
|
|
|
182
179
|
|
|
183
180
|
## The data model
|
|
184
181
|
|
|
185
|
-
|
|
182
|
+
- **Workspace** — The portal itself (one per Assembly account)
|
|
183
|
+
- **Internal user** — Staff at the business
|
|
184
|
+
- **Client** — A client user — represents a person, has email/name
|
|
185
|
+
- **Company** — A business that a Client belongs to (groups clients by org)
|
|
186
|
+
- **Custom field** — Workspace-defined extra fields on Client/Company records
|
|
187
|
+
- **App install** — Reference to your app + others installed in the portal
|
|
188
|
+
|
|
189
|
+
**SDK methods** (every service, not only the resources above):
|
|
190
|
+
|
|
191
|
+
<!-- generated: sdk-methods -->
|
|
192
|
+
Generated from the SDK's service classes. Methods are called flat (`assembly.listClients(...)`); every method takes a single object of the named parameters (`?` = optional). Read the `.d.ts` only for nested parameter shapes. Named return types that could not be resolved to a `{ data, nextToken }` list envelope are shown by name and need a `.d.ts` lookup.
|
|
193
|
+
|
|
194
|
+
**Clients**
|
|
195
|
+
|
|
196
|
+
| Method | Parameters | Returns |
|
|
197
|
+
|---|---|---|
|
|
198
|
+
| `listClients` | `limit?`, `nextToken?`, `companyId?`, `givenName?`, `familyName?`, `email?`, `customFields?` | `{ data: Array<api_ClientItem>, nextToken }` |
|
|
199
|
+
| `createClient` | `requestBody`, `sendInvite?` | `api_ClientItem` |
|
|
200
|
+
| `deleteClient` | `id` | `api_ClientItem` |
|
|
201
|
+
| `retrieveClient` | `id` | `api_ClientItem` |
|
|
202
|
+
| `updateClient` | `id`, `requestBody`, `sendInvite?` | `api_ClientItem` |
|
|
203
|
+
| `retrieveClientAppVisibility` | `id` | `api_ClientItem` |
|
|
204
|
+
|
|
205
|
+
**Comments**
|
|
206
|
+
|
|
207
|
+
| Method | Parameters | Returns |
|
|
208
|
+
|---|---|---|
|
|
209
|
+
| `getV1Comments` | `limit?`, `nextToken?`, `taskId?` | `{ data?: Array<marketplace_application_TaskComment>, nextToken }` |
|
|
210
|
+
| `deleteV1CommentsCommentid` | `commentId` | `marketplace_application_TaskComment` |
|
|
211
|
+
| `getV1CommentsCommentid` | `commentId` | `marketplace_application_TaskComment` |
|
|
212
|
+
|
|
213
|
+
**Companies**
|
|
214
|
+
|
|
215
|
+
| Method | Parameters | Returns |
|
|
216
|
+
|---|---|---|
|
|
217
|
+
| `listCompanies` | `limit?`, `nextToken?`, `name?`, `isPlaceholder?` | `{ data: Array<api_CompanyItem>, nextToken }` |
|
|
218
|
+
| `createCompany` | `requestBody` | `api_CompanyItem` |
|
|
219
|
+
| `deleteCompany` | `id` | `api_ItemFields` |
|
|
220
|
+
| `retrieveCompany` | `id` | `api_CompanyItem` |
|
|
221
|
+
| `updateCompany` | `id`, `requestBody` | `api_CompanyItem` |
|
|
222
|
+
| `addClientsToCompany` | `id`, `requestBody`, `confirmPromotePlaceholder?` | `company_addClientToCompanyResponse` |
|
|
223
|
+
|
|
224
|
+
**ContractTemplates**
|
|
225
|
+
|
|
226
|
+
| Method | Parameters | Returns |
|
|
227
|
+
|---|---|---|
|
|
228
|
+
| `listContractTemplates` | `name?`, `limit?`, `nextToken?` | `{ data: Array<contracts_ContractTemplate>, nextToken }` |
|
|
229
|
+
| `retrieveContractTemplate` | `id` | `contracts_ContractTemplate` |
|
|
230
|
+
|
|
231
|
+
**Contracts**
|
|
232
|
+
|
|
233
|
+
| Method | Parameters | Returns |
|
|
234
|
+
|---|---|---|
|
|
235
|
+
| `listContracts` | `status?`, `contractTemplateId?`, `recipientId?`, `clientId?`, `name?`, `limit?`, `nextToken?` | `{ data: Array<contracts_Contract>, nextToken }` |
|
|
236
|
+
| `sendContract` | `requestBody` | `contracts_Contract` |
|
|
237
|
+
| `retrieveContract` | `id` | `contracts_Contract` |
|
|
238
|
+
|
|
239
|
+
**CustomFields**
|
|
240
|
+
|
|
241
|
+
| Method | Parameters | Returns |
|
|
242
|
+
|---|---|---|
|
|
243
|
+
| `listCustomFields` | `name?`, `entityType?` | `{ data: Array<customfields_ClientCustomField>, nextToken }` |
|
|
244
|
+
| `createCustomField` | `requestBody` | `customfields_createCustomFieldsResponse` |
|
|
245
|
+
| `listCustomFieldOptions` | `id`, `label?` | `{ data: Array<customfields_ClientCustomFieldOption>, nextToken }` |
|
|
246
|
+
|
|
247
|
+
**Events**
|
|
248
|
+
|
|
249
|
+
| Method | Parameters | Returns |
|
|
250
|
+
|---|---|---|
|
|
251
|
+
| `listEvents` | `startDate?`, `endDate?`, `eventType?`, `actorId?`, `nextToken?`, `limit?` | `{ data: Array<audit_log_AuditLog>, nextToken }` |
|
|
252
|
+
| `createEvent` | `requestBody` | `audit_log_AuditLog` |
|
|
253
|
+
| `retrieveEvent` | `id` | `audit_log_AuditLog` |
|
|
254
|
+
|
|
255
|
+
**FileChannels**
|
|
256
|
+
|
|
257
|
+
| Method | Parameters | Returns |
|
|
258
|
+
|---|---|---|
|
|
259
|
+
| `listFileChannels` | `companyId?`, `clientId?`, `membershipType?`, `memberId?`, `membershipEntityId?`, `limit?`, `nextToken?` | `{ data: Array<filechannels_FileChannel>, nextToken }` |
|
|
260
|
+
| `createFileChannel` | `requestBody` | `filechannels_FileChannel` |
|
|
261
|
+
| `retrieveFileChannel` | `id` | `filechannels_FileChannel` |
|
|
262
|
+
|
|
263
|
+
**Files**
|
|
264
|
+
|
|
265
|
+
| Method | Parameters | Returns |
|
|
266
|
+
|---|---|---|
|
|
267
|
+
| `listFiles` | `channelId`, `path?`, `limit?`, `nextToken?` | `{ data: Array<files_File>, nextToken }` |
|
|
268
|
+
| `updateRootFolderPermissions` | `requestBody` | `handler_SuccessResponse` |
|
|
269
|
+
| `createFile` | `fileType`, `requestBody` | `files_File` |
|
|
270
|
+
| `deleteFile` | `id` | `api_ItemFields` |
|
|
271
|
+
| `retrieveFile` | `id` | `files_File` |
|
|
272
|
+
| `downloadAFile` | `id` | `Blob` |
|
|
273
|
+
| `retrieveDownloadUrlOfAFile` | `id` | `files_FilePresignedDownload` |
|
|
274
|
+
| `putV1FilesIdPermissions` | `id`, `requestBody` | `handler_SuccessResponse` |
|
|
275
|
+
|
|
276
|
+
**FormResponses**
|
|
277
|
+
|
|
278
|
+
| Method | Parameters | Returns |
|
|
279
|
+
|---|---|---|
|
|
280
|
+
| `requestFormResponse` | `requestBody` | `{ data: Array<forms_FormResponse> \| null, nextToken }` |
|
|
281
|
+
|
|
282
|
+
**Forms**
|
|
283
|
+
|
|
284
|
+
| Method | Parameters | Returns |
|
|
285
|
+
|---|---|---|
|
|
286
|
+
| `listForms` | `limit?`, `nextToken?` | `{ data: Array<forms_Form>, nextToken }` |
|
|
287
|
+
| `createForm` | `requestBody` | `forms_Form` |
|
|
288
|
+
| `retrieveForm` | `id` | `forms_Form` |
|
|
289
|
+
| `listFormResponses` | `id`, `status?`, `limit?`, `nextToken?` | `{ data: Array<forms_FormResponse> \| null, nextToken }` |
|
|
290
|
+
|
|
291
|
+
**Installs**
|
|
292
|
+
|
|
293
|
+
| Method | Parameters | Returns |
|
|
294
|
+
|---|---|---|
|
|
295
|
+
| `listAppInstalls` | `previewAsClient?` | `Array<app_instance_AppInstall>` |
|
|
296
|
+
| `retrieveAppInstall` | `installId` | `app_instance_AppInstall` |
|
|
297
|
+
| `listAppConnections` | `installId`, `companyId?`, `clientId?` | `Array<appConnection_AppConnection>` |
|
|
298
|
+
| `createAppConnection` | `installId`, `requestBody` | `appConnection_AppConnection` |
|
|
299
|
+
| `retrieveInstallNotificationSettings` | `installId` | `app_instance_InstallNotificationSettings` |
|
|
300
|
+
| `updateInstallNotificationSettings` | `installId`, `requestBody` | `app_instance_InstallNotificationSettings` |
|
|
301
|
+
| `createInstallNotificationSettings` | `installId`, `requestBody` | `app_instance_InstallNotificationSettings` |
|
|
302
|
+
|
|
303
|
+
**InternalUsers**
|
|
304
|
+
|
|
305
|
+
| Method | Parameters | Returns |
|
|
306
|
+
|---|---|---|
|
|
307
|
+
| `listInternalUsers` | `limit?`, `nextToken?` | `{ data: Array<api_InternalUserItem>, nextToken }` |
|
|
308
|
+
| `retrieveInternalUser` | `id` | `api_InternalUserItem` |
|
|
309
|
+
| `updateInternalUser` | `id`, `requestBody` | `api_InternalUserItem` |
|
|
310
|
+
| `retrieveInternalUserNotificationSettings` | `id` | `notificationsettings_InternalUserNotificationSettings` |
|
|
311
|
+
|
|
312
|
+
**InvoiceTemplates**
|
|
313
|
+
|
|
314
|
+
| Method | Parameters | Returns |
|
|
315
|
+
|---|---|---|
|
|
316
|
+
| `listInvoiceTemplates` | `limit?`, `nextToken?` | `{ data: Array<invoiceTemplate_InvoiceTemplate> \| null, nextToken }` |
|
|
317
|
+
|
|
318
|
+
**Invoices**
|
|
319
|
+
|
|
320
|
+
| Method | Parameters | Returns |
|
|
321
|
+
|---|---|---|
|
|
322
|
+
| `listInvoices` | `clientId?`, `companyId?`, `includeCompanyInvoices?`, `subscriptionId?`, `limit?`, `nextToken?` | `{ data: Array<invoice_Invoice> \| null, nextToken }` |
|
|
323
|
+
| `createInvoice` | `requestBody` | `invoice_Invoice` |
|
|
324
|
+
| `retrieveInvoice` | `id` | `invoice_Invoice` |
|
|
325
|
+
|
|
326
|
+
**Me**
|
|
327
|
+
|
|
328
|
+
| Method | Parameters | Returns |
|
|
329
|
+
|---|---|---|
|
|
330
|
+
| `retrieveMe` | — | `me_MeResponse` |
|
|
331
|
+
|
|
332
|
+
**MessageChannels**
|
|
333
|
+
|
|
334
|
+
| Method | Parameters | Returns |
|
|
335
|
+
|---|---|---|
|
|
336
|
+
| `listMessageChannels` | `clientId?`, `membershipEntityId?`, `companyId?`, `memberId?`, `membershipType?`, `includeUnread? = false`, `limit?`, `nextToken?` | `{ data: Array<any> \| null, nextToken }` |
|
|
337
|
+
| `createMessageChannel` | `requestBody` | `messagechannel_MessageChannel` |
|
|
338
|
+
| `listUnreadMessageChannels` | `userId?` | `messagechannel_UnreadSummary` |
|
|
339
|
+
| `retrieveMessageChannel` | `id` | `messagechannel_MessageChannel` |
|
|
340
|
+
|
|
341
|
+
**Messages**
|
|
342
|
+
|
|
343
|
+
| Method | Parameters | Returns |
|
|
344
|
+
|---|---|---|
|
|
345
|
+
| `listMessages` | `channelId`, `limit?`, `nextToken?` | `{ data: Array<messages_Message>, nextToken }` |
|
|
346
|
+
| `sendMessage` | `requestBody` | `messages_Message` |
|
|
347
|
+
|
|
348
|
+
**Notes**
|
|
349
|
+
|
|
350
|
+
| Method | Parameters | Returns |
|
|
351
|
+
|---|---|---|
|
|
352
|
+
| `listNotes` | `entityId?`, `entityType?`, `limit? = 20`, `nextToken?` | `{ data: Array<internal_notes_Note>, nextToken }` |
|
|
353
|
+
| `createNote` | `requestBody` | `internal_notes_Note` |
|
|
354
|
+
| `deleteNote` | `id` | `api_ItemFields` |
|
|
355
|
+
| `retrieveNote` | `id` | `internal_notes_Note` |
|
|
356
|
+
| `updateNote` | `id`, `requestBody` | `internal_notes_Note` |
|
|
357
|
+
|
|
358
|
+
**Notifications**
|
|
359
|
+
|
|
360
|
+
| Method | Parameters | Returns |
|
|
361
|
+
|---|---|---|
|
|
362
|
+
| `listNotifications` | `recipientId?`, `recipientClientId?`, `recipientInternalUserId?`, `includeRead? = false`, `recipientCompanyId?`, `limit?`, `nextToken?` | `{ data: Array<notifications_Notification>, nextToken }` |
|
|
363
|
+
| `createNotification` | `requestBody` | `notifications_Notification \| notifications_NotificationSuppressedResponse` |
|
|
364
|
+
| `deleteNotification` | `id` | `api_DeleteItemResponse` |
|
|
365
|
+
| `retrieveNotification` | `id` | `notifications_Notification` |
|
|
366
|
+
| `markNotificationRead` | `id` | `notifications_Notification` |
|
|
367
|
+
| `markNotificationUnread` | `id` | `notifications_Notification` |
|
|
368
|
+
|
|
369
|
+
**Payments**
|
|
370
|
+
|
|
371
|
+
| Method | Parameters | Returns |
|
|
372
|
+
|---|---|---|
|
|
373
|
+
| `listPayments` | `invoiceId?`, `limit?`, `nextToken?` | `{ data: Array<payment_Payment> \| null, nextToken }` |
|
|
374
|
+
|
|
375
|
+
**Prices**
|
|
376
|
+
|
|
377
|
+
| Method | Parameters | Returns |
|
|
186
378
|
|---|---|---|
|
|
187
|
-
|
|
|
188
|
-
|
|
|
189
|
-
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
379
|
+
| `listPrices` | `productId?`, `limit?`, `nextToken?` | `{ data: Array<price_Price> \| null, nextToken }` |
|
|
380
|
+
| `createAPrice` | `requestBody` | `price_Price` |
|
|
381
|
+
| `retrievePrice` | `id` | `price_Price` |
|
|
382
|
+
|
|
383
|
+
**Products**
|
|
384
|
+
|
|
385
|
+
| Method | Parameters | Returns |
|
|
386
|
+
|---|---|---|
|
|
387
|
+
| `listProducts` | `name?`, `limit?`, `nextToken?` | `{ data: Array<product_Product> \| null, nextToken }` |
|
|
388
|
+
| `createAProduct` | `requestBody` | `product_Product` |
|
|
389
|
+
| `retrieveProduct` | `id` | `product_Product` |
|
|
390
|
+
|
|
391
|
+
**Refunds**
|
|
392
|
+
|
|
393
|
+
| Method | Parameters | Returns |
|
|
394
|
+
|---|---|---|
|
|
395
|
+
| `listRefunds` | `invoiceId`, `limit?`, `nextToken?` | `{ data?: Array<refund_Refund>, nextToken }` |
|
|
396
|
+
| `createRefund` | `requestBody` | `refund_Refund` |
|
|
397
|
+
|
|
398
|
+
**SubscriptionTemplates**
|
|
399
|
+
|
|
400
|
+
| Method | Parameters | Returns |
|
|
401
|
+
|---|---|---|
|
|
402
|
+
| `listSubscriptionTemplates` | `limit?`, `nextToken?` | `{ data: Array<billing_Template> \| null, nextToken }` |
|
|
403
|
+
|
|
404
|
+
**Subscriptions**
|
|
405
|
+
|
|
406
|
+
| Method | Parameters | Returns |
|
|
407
|
+
|---|---|---|
|
|
408
|
+
| `listSubscriptions` | `clientId?`, `companyId?`, `recipientId?`, `limit?`, `nextToken?` | `{ data: Array<subscription_Subscription> \| null, nextToken }` |
|
|
409
|
+
| `createSubscription` | `requestBody` | `subscription_Subscription` |
|
|
410
|
+
| `retrieveSubscription` | `id` | `subscription_Subscription` |
|
|
411
|
+
| `cancelSubscription` | `id` | `subscription_Subscription` |
|
|
412
|
+
|
|
413
|
+
**TaskTemplates**
|
|
414
|
+
|
|
415
|
+
| Method | Parameters | Returns |
|
|
416
|
+
|---|---|---|
|
|
417
|
+
| `listTaskTemplates` | `limit?`, `nextToken?` | `{ data?: Array<marketplace_application_TaskTemplate>, nextToken }` |
|
|
418
|
+
| `retrieveTaskTemplate` | `id` | `marketplace_application_TaskTemplate` |
|
|
419
|
+
|
|
420
|
+
**Tasks**
|
|
421
|
+
|
|
422
|
+
| Method | Parameters | Returns |
|
|
423
|
+
|---|---|---|
|
|
424
|
+
| `retrieveTasks` | `limit?`, `nextToken?`, `createdBy?`, `parentTaskId?`, `status?`, `clientId?`, `internalUserId?`, `companyId?` | `{ data?: Array<marketplace_application_Task>, nextToken }` |
|
|
425
|
+
| `createTask` | `requestBody` | `marketplace_application_Task` |
|
|
426
|
+
| `deleteTask` | `id` | `marketplace_application_Task` |
|
|
427
|
+
| `retrieveTask` | `id` | `marketplace_application_Task` |
|
|
428
|
+
| `updateTask` | `id`, `requestBody` | `marketplace_application_Task` |
|
|
429
|
+
|
|
430
|
+
**Workspaces**
|
|
431
|
+
|
|
432
|
+
| Method | Parameters | Returns |
|
|
433
|
+
|---|---|---|
|
|
434
|
+
| `retrieveWorkspace` | — | `workspace_Workspace` |
|
|
435
|
+
|
|
436
|
+
<!-- /generated -->
|
|
193
437
|
|
|
194
438
|
Relationships:
|
|
195
439
|
- A `Client` belongs to many `Company`s (`client.companyIds[] → Company.id`) — many-to-many; `client.companyId` is the deprecated legacy single-value field
|
|
@@ -956,10 +1200,10 @@ Method naming convention from the OpenAPI codegen:
|
|
|
956
1200
|
|
|
957
1201
|
### Confirming method names + shapes
|
|
958
1202
|
|
|
959
|
-
|
|
1203
|
+
Every method, its parameter names, and its return shape are in the generated tables under "The data model"; they come from the codegen types in `node_modules/@assembly-js/node-sdk/dist/codegen/api/`, so don't guess a method that isn't listed. Read the `.d.ts` only for nested parameter shapes. Two files, two jobs:
|
|
960
1204
|
|
|
961
|
-
- **`index.d.ts` — the map.** Re-exports all 31 services and every model type,
|
|
962
|
-
- **`services/<Resource>Service.d.ts` — the
|
|
1205
|
+
- **`index.d.ts` — the map.** Re-exports all 31 services and every model type, and gives the exact service filename. The names are not always the obvious singular/plural (`FormResponsesService`, `TaskTemplatesService`, `SubscriptionTemplatesService`, `MeService`).
|
|
1206
|
+
- **`services/<Resource>Service.d.ts` — the parameter fields.** Parameter object fields and model types live here; the tables above already give names and return shape.
|
|
963
1207
|
|
|
964
1208
|
The client flattens every service onto one object, so a method declared in `TasksService.d.ts` is still called as `assembly.retrieveTasks(...)`.
|
|
965
1209
|
|
|
@@ -1231,10 +1475,10 @@ Use `AssemblyBridge.header.*` for breadcrumbs, CTAs, and actions menu. See `.cla
|
|
|
1231
1475
|
|
|
1232
1476
|
## TL;DR
|
|
1233
1477
|
|
|
1234
|
-
1. **Read this whole file before writing any code.** Especially the data model, "What's already built in," and the
|
|
1478
|
+
1. **Read this whole file before writing any code.** Especially the data model, "What's already built in," and the generated method tables.
|
|
1235
1479
|
2. **The middleware exchanges `?token=` (first load) for a user-scoped bearer in an HttpOnly cookie; that bearer authenticates every call.** You never handle the token.
|
|
1236
1480
|
3. **Call `getAssembly()` — no token argument, ever.** `getAssembly()` (RSC/server actions) and `getAssemblyForRequest(req)` (route handlers) read the bearer cookie. Identity via `getSessionIdentity()` / `useAssembly()`. Never read `searchParams.token`, thread a token, or set `x-assembly-token`.
|
|
1237
|
-
4. **The SDK is flat: `assembly.listClients(...)`, not `assembly.clients.list()`.**
|
|
1481
|
+
4. **The SDK is flat: `assembly.listClients(...)`, not `assembly.clients.list()`.** The generated method tables list every method;
|
|
1238
1482
|
5. **The bearer expires in 60 min; `useServerAction`/`authFetch` re-exchange it silently and retry.** You don't refresh anything or touch `AssemblyBridge.sessionToken`.
|
|
1239
1483
|
<!-- !feature:app-owned-header -->
|
|
1240
1484
|
6. **Use `AssemblyBridge.header.*`** for breadcrumbs/CTAs in client components. Don't render your own. (Exception: the notification surface `/n` has no header — render CTAs as inline buttons there.)
|
package/fixes.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"id": "next-config-wrapper",
|
|
4
|
+
"version": "0.0.20",
|
|
5
|
+
"title": "Your app's live preview no longer hangs on networks that block its dev connection.",
|
|
6
|
+
"check": "Your app's Next config must be split so next.config.ts is the platform-owned wrapper and your own settings live in app.config.ts. The end state: next.config.ts contains exactly:\n\nimport { withAssemblyDev } from \"@assembly-js/app-foundation/next\";\nimport appConfig from \"./app.config\";\n\nexport default withAssemblyDev(appConfig);\n\nTo get there: create app.config.ts and move whatever next.config.ts currently exports (serverExternalPackages, experimental flags, redirects, headers, etc.) into it verbatim, keeping the export shape the app already used (e.g. `export default { ... }` or `export default appConfig satisfies NextConfig`). Then replace next.config.ts's contents with the wrapper above. If a sibling next.config.js or next.config.mjs exists, delete it — Next loads whichever config file it finds first, and a leftover unwrapped copy would silently run instead of the wrapper. Do not add new Next options while you're at it, and do not touch anything outside these two files — this fix is a relocation, not a config change.",
|
|
7
|
+
"detector": {
|
|
8
|
+
"absent": ["next.config.js", "next.config.mjs"],
|
|
9
|
+
"present": [
|
|
10
|
+
{ "path": "next.config.ts", "contains": ["withAssemblyDev("] },
|
|
11
|
+
{ "path": "app.config.ts" }
|
|
12
|
+
]
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"id": "paint-beacon",
|
|
17
|
+
"version": "0.0.22",
|
|
18
|
+
"title": "Your app's preview now accurately reports when a page has finished rendering, not just loaded.",
|
|
19
|
+
"check": "Your app is missing the post-paint beacon the builder preview uses to tell \"the page executed\" from \"the page actually rendered.\" Add the component exactly as the foundation ships it, at app/components/paint-beacon.tsx:\n\n'use client';\n\nimport { useEffect } from 'react';\nimport { installPaintBeacon } from '@assembly-js/app-foundation/client';\n\nexport default function PaintBeacon(): null {\n useEffect(() => {\n installPaintBeacon();\n }, []);\n return null;\n}\n\nRender it once, self-closing and prop-less, in the root layout's <body> (app/layout.tsx): import it as `import PaintBeacon from '@/app/components/paint-beacon';` and add `<PaintBeacon />` alongside the other foundation-owned providers already rendered there.\n\nThe beacon's POST must be routed before any CSRF or session-exchange handling, because sendBeacon is a headerless POST that 403s on the normal path. The platform sign-in proxy already does this, so proxy.ts's proxy export should be the package's:\n\nimport { createAssemblyProxy } from '@assembly-js/app-foundation/server';\n\nexport const proxy = createAssemblyProxy();\n\nIf proxy.ts has been rewritten away from that, restore that export (keep the file's `config` matcher as it is) rather than adding a beacon route by hand. Make sure @assembly-js/app-foundation is a declared dependency (it should already be installed). Do not post app.painted or hit /__assembly/painted yourself — the component already does both.",
|
|
20
|
+
"detector": {
|
|
21
|
+
"present": [
|
|
22
|
+
{ "path": "app/components/paint-beacon.tsx" },
|
|
23
|
+
{ "path": "app/layout.tsx", "contains": ["<PaintBeacon"] }
|
|
24
|
+
],
|
|
25
|
+
"dependencies": ["@assembly-js/app-foundation"],
|
|
26
|
+
"checks": [{ "of": "@assembly-js/app-foundation", "script": "check-paint-beacon.mjs" }]
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"id": "inlined-child-rows-batch",
|
|
31
|
+
"version": "0.0.37",
|
|
32
|
+
"title": "Saving a record with nested rows no longer fails and drops the rows.",
|
|
33
|
+
"check": "Your app has its own copy of the child-row replace helper, and that copy calls drizzle's batch detached from db (`const batch = db.batch …; await batch([...])`). drizzle's batch reads this.session, so in a deployed app every save that writes nested rows (a proposal's packages, a retainer's allowances) fails with a 500 and leaves the parent without its children.\n\nDelete the app's copy and import the package's helper instead: `import { replaceChildRows } from '@assembly-js/app-foundation/server';`. Its signature is the one the copy was made from, so call sites keep their arguments. If the copy has drifted from the original and can't be swapped cleanly, keep it and change only the call to `await batch.call(db, [first, ...rest]);`. Do not change what the helper writes or the order it writes in.",
|
|
34
|
+
"detector": {
|
|
35
|
+
"forbidden": [{ "id": "detached-db-batch", "pattern": "(^|[^.\\w])batch\\(\\[" }]
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"id": "identity-outage-states",
|
|
40
|
+
"version": "0.0.40",
|
|
41
|
+
"title": "If Assembly can't confirm who is signed in, your app now shows a retry screen instead of an error.",
|
|
42
|
+
"check": "Since 0.0.40, getSessionIdentity() asks the platform who the viewer is and throws an AuthUnavailableError when the platform can't be reached. Your root layout calls it without a catch, so during an outage every page fails instead of showing a retry screen, and every failed action renews the session without a bound. Bring three app-owned files to the foundation's current shape:\n\n1. Create app/components/auth-unavailable.tsx:\n\n'use client';\n\nexport default function AuthUnavailable() {\n return (\n <main className=\"flex min-h-screen flex-col items-center justify-center gap-3 px-4 text-center\">\n <p className=\"text-sm text-muted-foreground\">\n We couldn't load this right now. Please try again.\n </p>\n <button\n type=\"button\"\n className=\"rounded-md border px-3 py-1.5 text-sm\"\n onClick={() => window.location.reload()}\n >\n Try again\n </button>\n </main>\n );\n}\n\n2. In app/layout.tsx, import it (`import AuthUnavailable from '@/app/components/auth-unavailable';`) and replace `const identity = await getSessionIdentity();` with:\n\nlet identity: Awaited<ReturnType<typeof getSessionIdentity>> = null;\nlet authUnavailable = false;\ntry {\n identity = await getSessionIdentity();\n} catch (err) {\n if (!(err instanceof Error && err.name === 'AuthUnavailableError')) throw err;\n authUnavailable = true;\n}\nif (authUnavailable) {\n return (\n <html lang=\"en\" style={{ colorScheme: 'light' }}>\n <body className=\"font-sans antialiased\">\n <AuthUnavailable />\n </body>\n </html>\n );\n}\n\nKeep everything else in the layout as it is.\n\n3. Create app/components/renewal-gate.ts:\n\nexport function createRenewalGate(\n renew: () => Promise<boolean>,\n windowMs: number,\n now: () => number = Date.now,\n): () => Promise<boolean> {\n let inFlight: Promise<boolean> | null = null;\n let lastStartedAt = Number.NEGATIVE_INFINITY;\n return () => {\n if (inFlight) return inFlight;\n if (now() - lastStartedAt < windowMs) return Promise.resolve(false);\n lastStartedAt = now();\n inFlight = renew().finally(() => {\n inFlight = null;\n });\n return inFlight;\n };\n}\n\nThen in app/components/assembly-context.tsx add `import { createRenewalGate } from './renewal-gate';`, define `const renewOnce = createRenewalGate(reexchangeBearer, 30_000);` at module scope, and change the retry path's `await reexchangeBearer()` to `await renewOnce()`. Change nothing else in that file.",
|
|
43
|
+
"detector": {
|
|
44
|
+
"present": [
|
|
45
|
+
{ "path": "app/components/auth-unavailable.tsx" },
|
|
46
|
+
{ "path": "app/layout.tsx", "contains": ["AuthUnavailableError"] },
|
|
47
|
+
{ "path": "app/components/renewal-gate.ts" },
|
|
48
|
+
{ "path": "app/components/assembly-context.tsx", "contains": ["createRenewalGate("] }
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"id": "package-proxy",
|
|
54
|
+
"version": "0.0.42",
|
|
55
|
+
"title": "Your app's sign-in and cross-site request protection now come from Assembly and are tested by it.",
|
|
56
|
+
"check": "Your app's sign-in proxy is still code the app owns. Since 0.0.42 the package provides all of it — the token exchange, the bearer cookie, the CSRF gate and the re-exchange pass-through — and proxy.ts only calls it:\n\nimport { createAssemblyProxy } from '@assembly-js/app-foundation/server';\n\nexport const proxy = createAssemblyProxy();\n\nReplace the proxy function in proxy.ts with that export and delete a root middleware.ts if one exists. Keep the file's `config` matcher, including any exclusions the app added for its own paths; `api/assembly-reexchange` must stay excluded. Carry over only what the app added on top of the foundation's proxy: request headers it set for its own pages go in `createAssemblyProxy({ onForward({ request, headers, session }) { headers.set(…) } })`. Do not keep, port or rewrite any token, cookie or CSRF handling. Verify with `node node_modules/@assembly-js/app-foundation/bin/check-proxy-csrf.mjs --strict`; if it fails, the fix is the file above, not a change to request handling.",
|
|
57
|
+
"detector": {
|
|
58
|
+
"absent": ["middleware.ts"],
|
|
59
|
+
"present": [{ "path": "proxy.ts", "contains": ["@assembly-js/app-foundation/server", "createAssemblyProxy("] }],
|
|
60
|
+
"dependencies": ["@assembly-js/app-foundation"],
|
|
61
|
+
"checks": [{ "of": "@assembly-js/app-foundation", "script": "check-proxy-csrf.mjs" }]
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assembly-js/app-foundation",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.45",
|
|
4
4
|
"description": "Versioned foundation helpers and build context for Assembly generated apps",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
"bin",
|
|
9
9
|
"skills",
|
|
10
10
|
"CLAUDE.md",
|
|
11
|
-
"render-context.mjs"
|
|
11
|
+
"render-context.mjs",
|
|
12
|
+
"fixes.json",
|
|
13
|
+
"CHANGELOG.md"
|
|
12
14
|
],
|
|
13
15
|
"exports": {
|
|
14
16
|
"./server": {
|