You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
pull:PullClient.sendMessage() and sendMessageToChannels() reject where they used to resolve, and resolve true after the transport accepts the frame rather than undefined or a boolean immediately. A caller with no catch sees a rejection where it previously saw a silent no-op — in a timer that can now end the process under Node 15+. See 3.within-2x.md.
actions: stop a walk whose cursor cycles or runs backwards, and check it before calling a short page the end (#538)
tools:getEnvironment() gains a fourth member, Environment.WORKER, and returns it for a scope that is a worker scope and reports no Node version — Web, Shared and Service Workers previously fell through to Environment.UNKNOWN. Node is tested first, so a runtime that reports a Node version stays Environment.NODE even when it models itself on the Worker API (a Deno worker, a Cloudflare Worker with nodejs_compat): those are servers, and a webhook belongs there. A branch on === Environment.BROWSE is unaffected — a worker has no DOM and is deliberately not BROWSE — but a default: or === Environment.UNKNOWN arm that was catching workers no longer does. For anything that is not the DOM, use the new isBrowserLikeRuntime(), true for BROWSE and WORKER alike.
http: axios settings passed at construction are filtered against TypeHttpOptions instead of forwarded whole. This narrows one surface that did ship: HttpV2 and HttpV3 are exported and their second constructor argument is typed object, so a direct new HttpV2(auth, { baseURL, responseType, … }) used to reach axios untouched and now loses those keys, with the dropped names logged. Set them on getHttpClient(version).ajaxClient.defaults instead. headers still merges as before. A refused redirect on a request whose effective maxRedirects is 0 now fails with JSSDK_HTTP_REDIRECT_BLOCKED and is not retried.
http: in a browser or worker the SDK asks axios for the fetch adapter instead of letting it pick XHR by list order. A blocked redirect on a restApi:v3 batch from a non-hook transport now fails with JSSDK_HTTP_REDIRECT_BLOCKED where it used to complete the hop silently; a test double stubbing XMLHttpRequest under jsdom stops intercepting SDK traffic; and onUploadProgress on your own requests through ajaxClient degrades outside Chromium. Pass httpOptions: { adapter: 'xhr' } at construction to opt out. The SDK also states Content-Type: application/json per request, so ajaxClient.defaults.headers no longer changes the encoding of SDK traffic.
frame:placement.options is Readonly<Record<string, unknown>> instead of any, and MessageInitData.PLACEMENT_OPTIONS is unknown instead of Record<string, any>. Reading a key still compiles and yields unknown; what stops compiling is reaching through it (options.payload.id), assigning it to a concrete type, or passing options where a narrower record is expected. Narrow before use. One change fails only at run time: a JSON string is parsed for you now, so code that called JSON.parse on the value itself throws SyntaxError. See docs/getting-started/migration/v3.
actions: keyset walks now stop after 10 000 pages by default. A walk that legitimately reads more — 500 000 rows at the default page size of 50 — used to complete and now stops with JSSDK_ACTION_MAX_PAGES_EXCEEDED. The eager walkers (callList / callTail) resolve with the rows they read and the error attached, so check isSuccess; the streaming walkers (fetchList / fetchTail) throw after yielding every page they read. Pass a higher maxPages to restore the previous reach. See docs/getting-started/migration/within-2x.
http:classifyV3ErrorsByCategory is removed from RestrictionParams, and the classification it enabled is now unconditional. On restApi:v3, an error in the v3 error envelope carrying a 4xx other than 401, 408 or 429 is delivered inside AjaxResult instead of being thrown. If you passed the parameter, delete the line — the behaviour you asked for is the default. If you never passed it, nothing fails to compile and some v3 errors stop throwing: check isSuccess rather than relying on try / catch. To keep one code throwing, add it to hardErrorCodes. See
types:Result<T> and IResult<T> default to unknown rather than any, and TypeCallParams's index signature, nested params and filter are narrowed to match. Code that wrote Result without a type argument and then read a field off it no longer compiles — pass the payload type to the action (call.make<T>, batch.make<T>, callList.make<T>) or narrow once at the point of reading. Separately, batch.make's return type is now chosen by overload instead of being the union CallBatchResult<T>: a cast written to work around that union may need removing, and a generic that named the whole collection has to name one command's payload instead. A returnAjaxResult that is not a literal still resolves to the union. See
platform: Node 20 is no longer supported. engines.node is >=22.0.0. On Node 22 or newer nothing changes; on Node 20, npm install prints an EBADENGINE warning and, under engine-strict=true (pnpm's default inside a workspace), fails outright. This is a packaging floor, not an API change — no source has to change, only the Node version you run on.
core:b24.callMethod, b24.callListMethod, b24.fetchListMethod, b24.callBatch, b24.callBatchByChunk, AbstractB24.batchSize, LoggerBrowser and LoggerType are removed. Replace them with b24.actions.v{2,3}.{call,callList,fetchList,batch,batchByChunk}.make(options), the literal 50, and LoggerFactory.createForBrowser(title, isDev); LoggerType has no replacement — drop the import. Four of the five methods are a mechanical swap. callListMethod is not: callList.make has no progress callback, does not accept order, and pages by a keyset cursor, so idKey / cursorIdKey must match the method. See
core: the request body of a restApi:v3 batch changes shape for every transport, B24Hook included, where the batch already worked. It is now a bare JSON array [{…},{…}] instead of an object with numeric keys {"0":{…},"1":{…}}, and a server-side B24OAuth batch carries an Authorization: Bearer header it did not carry before. No caller code changes — the action arguments, the return shape and AjaxError.requestInfo.params are all unchanged — but anything that inspects the request rather than making it needs attention: a reverse proxy, a WAF body rule, an egress gateway, a recorded HTTP fixture, or a test asserting on the request body. Re-record fixtures, and let Authorization through the proxy.
Features
actions: add actions.v3.deferredBatch for background batches (#572) (846562b)
actions: bound every keyset walk with maxPages, signal and progress (#522) (29a4fad), closes #484
actions: stop a walk whose cursor cycles or runs backwards, and check it before calling a short page the end (#538) (d445cb7)
batch: warn when a batch command's arguments are lost to an unread key (#536) (55348ab)
core: let a browser batch on v3, with the token in the query string (#507) (e6ef9de)
core: remove the deprecated legacy REST surface (#509) (dfb11d1)
core: send a v3 batch as a bare array, with the OAuth token in a Bearer header (#491) (487eb40)
core: support Idempotency-Key on restApi:v3 calls (#475) (d6f81c8), closes #462
frame: add an opt-in token keep-alive and coalesce refreshAuth (#543) (580b87a), closes #532
frame: type placement.options, and normalise the shapes the portal sends (#528) (9f90acf), closes #485
http: carry httpOptions through initializeB24Frame, and enforce the allowlist at runtime (#535) (528a73e)
http: classify restApi:v3 errors by response category, behind a flag (#478) (db7f7d7), closes #460
http: classify restApi:v3 errors by response category, without a flag (#517) (41db85a)
http: state the JSON content type, and ask for the fetch adapter in a browser (#534) (a011ea9)
platform: drop Node 20, which has been EOL since April (#512) (5023a5b)
playground: add a Pull lab for exercising the two protobuf codecs against a portal (#554) (282c3b0)
pull: add a hand-written protobuf codec behind an opt-in switch (#552) (d7e5c4e)
pull: name the push server's refusal codes, and record them in the lab (#560) (f937c02)
scripts: check the API Reference index against itself (#458) (5c53c9e), closes #384
scripts: compile the ts fences in the contributing guides (#448) (6e8c85f), closes #435
scripts: hold v3 method names against a portal's own OpenAPI document (#471) (36dd2e6), closes #463#464
scripts: report how stale a v3 snapshot is, measured per portal kind (#550) (43a4ba1), closes #472
scripts: type-check the JSDoc @example blocks in the SDK source (#443) (f5e6a76), closes #439
tools: name the worker environment, and treat it as browser-like rather than as a server (#537) (22d9b4c)
types: default Result to unknown, and overload batch.make on its arguments (#516) (6069301)
Bug Fixes
actions: bound the filter walk by work, not only by depth (#494) (e7106bb)
actions: measure the v3 aggregate contract and correct the type it returns (#498) (fed0ebb)
actions: reject the v2 object filter dialect in callTail and fetchTail too (#489) (507d49f)
actions: report the v2 list params the cursor injection collides with (#521) (054a330), closes #483
actions: stop a list or tail walk when the cursor stops advancing (#493) (fc71689)
core: keep a response without a time block from throwing (#456) (1f90b2b)
core: mask the webhook secret when it appears in a URL path (#468) (4601238)
core: wrap a response body that has no result key into result (#469) (d917cee)
docs: stop README-AI.md teaching the removed LoggerBrowser, and gate it (#446) (dfc115a), closes #277
frame: new frame after destroy; document openSliderAppPage settling (#575) (18218a9), closes #486
http: keep the OAuth token out of the body of an idempotent v3 call (#571) (5501dbf)
http: refuse idempotencyKey in a browser before sending (#574) (d186d50), closes #573
http: walk a top-level array or string in the redactor (#488) (c4d8306), closes #487
limiters: charge a batch to the operating budget the portal actually bills (#539) (eb13ee6)
limiters: keep the parameters a partial update does not mention (#481) (66f4554), closes #479
playground: show the error CODE in the Pull lab, and drop the credentials that do not exist (#556) (2566ba5)
playground: subscribe the Pull lab to client-published messages (#557) (2f69d47)
pull: a malformed message no longer drops the rest of its batch (#565) (367a973), closes #564
pull: fuzz both codecs, and stop one bad message dropping the batch (#561) (4dda2f8)
pull: merge user_params into a non-object params without throwing (#567) (cad9aa8), closes #566
pull: report every way a send can fail, instead of hiding four of them (#555) (2fb18a9)
pull: skip a message body that is JSON but not an object (#563) (e98dad0), closes #562
recipes: make the v3 tasks.task.add calls in recipes 03 and 08 actually work (#477) (f126e34), closes #476
recipes: treat member_id as the untrusted string it is (#545) (598ac3a), closes #454
recipes: validate the portal URLs an install event carries (#452) (5b1bf78), closes #389
scripts: anchor the fence pattern, which was miscounting an inline marker (#442) (638c977), closes #441
scripts: docs-lint must not read a shallow boundary as a file's last change (#544) (503c8c7), closes #524
test: install browser globals by descriptor, so the unit suite stops depending on file order (#523) (9a46fa3)
Dependencies
bump dotenv from 17.4.2 to 18.0.4 (#580) (21d9503)
bump grammy and openai in the recipes package (#444) (5bbfefd)
bump openai from 7.10.0 to 7.18.0 in /skills/b24jssdk-recipes (#540) (6f1fcf4)
bump openai from 7.18.0 to 7.23.0 in the recipes skill (#576) (07e3000)
bump openai to 7.10.0 in the recipes skill (#502) (dec071b)
bump the npm-minor-patch group across 1 directory with 13 updates (#577) (24a1bbd)
bump the npm-minor-patch group across 1 directory with 18 updates (#553) (4ad1e15)
raise the audit floor that a new smol-toml advisory moved past (#526) (966400d)
raise the audit floors that new advisories moved past (#453) (67a11b9)
raise the audit floors that three new advisories moved past (#510) (7f6aec5)
raise the devalue override floor to the patched line (#548) (369d5eb)
raise the js-yaml floor to the version the manifest already asks for (#529) (904ad2f)
raise the undici and ip-address floors past three new advisories (#581) (022a202)
take the tooling half of the grouped bump, leave the docs app alone (#470) (2abf5fc), closes #457
Changed
ci: drop the typecheck pass the measurement showed was redundant (#436) (778ba82), closes #419
config: extract a shared tsconfig base, and pin the copy that cannot use it (#547) (63a922d), closes #396
scripts: one directory walk, with the symlink guard the copies lacked (#437) (576c365), closes #418
scripts: one reporter, and GitHub annotations for every check (#450) (134e820), closes #418
Docs
actions: add CallTail and FetchTail pages for REST API v3 (#542) (8df5112)
actions: move the list-walker options onto their types (#546) (23809df), closes #420
contributing: re-measure the typecheck coverage table and point AGENTS.md at it (#447) (33ef7df), closes #419
contributing: record what the raw-frame tap measured on the encode side (#558) (931e79d)
contributing: retire the argument #439 disproved, and refresh the counts (#451) (ea6f38c)
core: agree where a JSDoc block ends, and cut the two longest (#440) (cbdb6fe), closes #420
core: measure the Filterable rule aggregate needs, and ask the portal about availability (#525) (cfa5038), closes #467
core: say on getData() that next and total are not in it (#513) (9ec9f45)
frame: state the portal-side contract for closing a slider app (#449) (dd04808), closes #328
give restApi:v3 its own REST error-code table (#499) (527a010)
migration: cover the openSliderAppPage type change and the destroy fix in the v3 guide (#583) (df3954b)
refresh the audited stamps the #494 merge left behind (#504) (b6c0452)
refresh the audited stamps the #522 merge left behind (#527) (8271772)
releasing: decide the release body does not mirror the changelog (#434) (c339d75)
releasing: write the community post about the reader, not about us (#432) (8206b6e)
skills: point the filtering and recipes skills at the field-list guide (#474) (a33d654)
the OpenAPI document follows installed modules, not granted scopes (#490) (5ff774d)
v3: correct the page-size cap and the batch ceiling, and re-measure the write shape (#531) (75d73d2), closes #465
v3: document *.field.list, and state the camelCase rule once (#473) (9a70742), closes #466