@zerotal/client 1.7.0 → 1.7.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 +29 -0
- package/package.json +8 -4
- package/src/CircuitBreaker.ts +1 -1
- package/src/Socket.ts +3 -3
- package/src/browser.ts +54 -0
- package/src/config.ts +1 -1
- package/src/createApiClient.ts +36 -0
- package/src/errors.ts +1 -1
- package/src/index.ts +1 -30
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,35 @@ follows the Zerotal monorepo's unified versioning.
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **The documented import could not be bundled for a browser.** `import { Socket } from
|
|
14
|
+
"@zerotal/client"` — the line the broadcasting guide taught — failed with `Browser build cannot
|
|
15
|
+
import() Bun builtin: "bun"`. The root entry also exports `ClientProvider`, which extends core's
|
|
16
|
+
`ServiceProvider`, which reaches `CommandRunner`, which reaches the built-in CLI commands, one of
|
|
17
|
+
which does `await import("bun")`. That is a *resolution*-time error, so tree-shaking never got the
|
|
18
|
+
chance to drop the half nobody in a browser wanted: one server-only export made the whole package
|
|
19
|
+
unusable in the environment it exists for.
|
|
20
|
+
|
|
21
|
+
`@zerotal/client` now resolves to a browser-safe entry under the `browser` export condition —
|
|
22
|
+
`Socket`, `ApiClient`, `CircuitBreaker`, `createApiClient` and their types, and none of the
|
|
23
|
+
server-side exports. Bun and Node consumers still get the full barrel, `ClientProvider` included,
|
|
24
|
+
so nothing about registering the package changes. `@zerotal/client/Socket` still works and is
|
|
25
|
+
still the leanest import when `Socket` is all you need; `ClientProvider` also gained an explicit
|
|
26
|
+
`./provider` subpath.
|
|
27
|
+
|
|
28
|
+
Two supporting changes: `createApiClient` moved out of `index.ts` into its own module, because a
|
|
29
|
+
browser entry re-exporting it from the barrel pulls the barrel back in — the first attempt at this
|
|
30
|
+
fix did exactly that and bundled straight back into the same error. And the modules a browser can
|
|
31
|
+
reach now import from narrow core subpaths (`@zerotal/core/errors`, `@zerotal/core/helpers`)
|
|
32
|
+
rather than the root, because importing *anything at all* from core's root is enough to poison a
|
|
33
|
+
browser bundle.
|
|
34
|
+
|
|
35
|
+
Guarded by a test that runs `Bun.build` with `target: "browser"` — no unit test can see this,
|
|
36
|
+
since every module imports fine under Bun — plus one that holds the browser entry in step with
|
|
37
|
+
the barrel, since two entry points means two places to remember to add an export to.
|
|
38
|
+
|
|
39
|
+
|
|
11
40
|
## [1.0.3] — 2026-08-07
|
|
12
41
|
|
|
13
42
|
### Changed
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zerotal/client",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"maturity": "stable",
|
|
6
6
|
"private": false,
|
|
@@ -8,8 +8,12 @@
|
|
|
8
8
|
"main": "./src/index.ts",
|
|
9
9
|
"types": "./src/index.ts",
|
|
10
10
|
"exports": {
|
|
11
|
-
".":
|
|
12
|
-
|
|
11
|
+
".": {
|
|
12
|
+
"browser": "./src/browser.ts",
|
|
13
|
+
"default": "./src/index.ts"
|
|
14
|
+
},
|
|
15
|
+
"./Socket": "./src/Socket.ts",
|
|
16
|
+
"./provider": "./src/provider/ClientProvider.ts"
|
|
13
17
|
},
|
|
14
18
|
"files": [
|
|
15
19
|
"CHANGELOG.md",
|
|
@@ -31,7 +35,7 @@
|
|
|
31
35
|
"typecheck": "tsc --noEmit"
|
|
32
36
|
},
|
|
33
37
|
"dependencies": {
|
|
34
|
-
"@zerotal/core": "1.7.
|
|
38
|
+
"@zerotal/core": "1.7.2"
|
|
35
39
|
},
|
|
36
40
|
"devDependencies": {
|
|
37
41
|
"typescript": "^5.8.0"
|
package/src/CircuitBreaker.ts
CHANGED
package/src/Socket.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// broadcasting protocol (the `ws` / `redis` drivers) and exposes a familiar
|
|
5
5
|
// realtime-client API — the same `channel()/private()/join()/leave()` +
|
|
6
6
|
// `listen()/here()/joining()/leaving()` surface — so it works with `@zerotal/flow`'s
|
|
7
|
-
// `@on('
|
|
7
|
+
// `@on('socket:…')` listeners with zero external dependencies.
|
|
8
8
|
//
|
|
9
9
|
// import { Socket } from "@zerotal/client";
|
|
10
10
|
//
|
|
@@ -335,14 +335,14 @@ export class Socket {
|
|
|
335
335
|
return this._subscribe(wire, () => new PresenceChannel(wire, this)) as PresenceChannel;
|
|
336
336
|
}
|
|
337
337
|
|
|
338
|
-
/**
|
|
338
|
+
/** Alias for {@link presence} (`window.Socket.join(...)`). */
|
|
339
339
|
join(name: string): PresenceChannel {
|
|
340
340
|
return this.presence(name);
|
|
341
341
|
}
|
|
342
342
|
|
|
343
343
|
/**
|
|
344
344
|
* Leave a channel by its base name — unsubscribes the public, `private-`, and `presence-`
|
|
345
|
-
* variants
|
|
345
|
+
* variants, which is what `leave()` means here.
|
|
346
346
|
*/
|
|
347
347
|
leave(name: string): void {
|
|
348
348
|
this.leaveChannel(name);
|
package/src/browser.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The browser-safe half of this package.
|
|
3
|
+
*
|
|
4
|
+
* Resolved for `import … from "@zerotal/client"` under the `browser` export
|
|
5
|
+
* condition, so a bundler targeting a browser gets this file and a Bun/Node
|
|
6
|
+
* import gets `index.ts` unchanged. Nobody has to know: the documented import
|
|
7
|
+
* is the same either way.
|
|
8
|
+
*
|
|
9
|
+
* What it leaves out is `ClientProvider` and `ClientConfig` — the two things
|
|
10
|
+
* here that are genuinely server-side. `ClientProvider` extends core's
|
|
11
|
+
* `ServiceProvider`, which reaches `CommandRunner`, which reaches the built-in
|
|
12
|
+
* CLI commands, one of which does `await import("bun")`. That is a hard error in
|
|
13
|
+
* a browser build and it happens during *resolution*, so tree-shaking never gets
|
|
14
|
+
* a chance to drop the unused half. The whole package became unbundleable
|
|
15
|
+
* because of one export nobody in a browser wanted.
|
|
16
|
+
*
|
|
17
|
+
* The rule this encodes: `@zerotal/core`'s root entry is server-only. A module
|
|
18
|
+
* that can run in a browser imports from a narrow subpath — `@zerotal/core/errors`,
|
|
19
|
+
* `@zerotal/core/helpers` — and never from the root.
|
|
20
|
+
*/
|
|
21
|
+
export type {
|
|
22
|
+
ApiRouteMap,
|
|
23
|
+
RouteShape,
|
|
24
|
+
HttpMethod,
|
|
25
|
+
PathParams,
|
|
26
|
+
ParamRecord,
|
|
27
|
+
PathsFor,
|
|
28
|
+
ResponseOf,
|
|
29
|
+
BodyOf,
|
|
30
|
+
QueryOf,
|
|
31
|
+
} from "./types.ts";
|
|
32
|
+
|
|
33
|
+
export { ApiClient, ApiClientError, ValidationError } from "./ApiClient.ts";
|
|
34
|
+
export type {
|
|
35
|
+
ApiClientConfig,
|
|
36
|
+
RequestConfig,
|
|
37
|
+
RequestInterceptor,
|
|
38
|
+
ResponseContext,
|
|
39
|
+
ResponseInterceptor,
|
|
40
|
+
ResponseMeta,
|
|
41
|
+
RequestOptions,
|
|
42
|
+
GetOptions,
|
|
43
|
+
MutationOptions,
|
|
44
|
+
TokenSource,
|
|
45
|
+
RetryOptions,
|
|
46
|
+
} from "./ApiClient.ts";
|
|
47
|
+
|
|
48
|
+
export { CircuitBreaker, CircuitBreakerOpenError } from "./CircuitBreaker.ts";
|
|
49
|
+
export type { CircuitBreakerOptions, CircuitState } from "./CircuitBreaker.ts";
|
|
50
|
+
|
|
51
|
+
export { Socket, Channel, PresenceChannel } from "./Socket.ts";
|
|
52
|
+
export type { SocketOptions, SocketState, SocketLike, PresenceMember } from "./Socket.ts";
|
|
53
|
+
|
|
54
|
+
export { createApiClient } from "./createApiClient.ts";
|
package/src/config.ts
CHANGED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// ── Factory function ──────────────────────────────────────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// Its own module rather than a member of `index.ts`, so the browser entry can
|
|
4
|
+
// re-export it without pulling the server half of the barrel back in. That is
|
|
5
|
+
// not hypothetical tidiness: `browser.ts` originally took it from `index.ts`,
|
|
6
|
+
// which re-imported `ClientProvider` and put the bundle straight back into the
|
|
7
|
+
// error this split exists to remove.
|
|
8
|
+
|
|
9
|
+
import { ApiClient } from "./ApiClient.ts";
|
|
10
|
+
import type { ApiRouteMap } from "./types.ts";
|
|
11
|
+
import type { ApiClientConfig } from "./ApiClient.ts";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Create a type-safe API client bound to your route map.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* // frontend/api.ts
|
|
18
|
+
* import { createApiClient } from '@zerotal/client';
|
|
19
|
+
* import type { Routes } from './routes';
|
|
20
|
+
*
|
|
21
|
+
* export const api = createApiClient<Routes>({
|
|
22
|
+
* baseUrl: '/api',
|
|
23
|
+
* headers: { 'X-Requested-With': 'XMLHttpRequest' },
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* // Anywhere in your UI:
|
|
27
|
+
* const user = await api.get('/users/{id}', { id: 1 });
|
|
28
|
+
* // ^? UserResource (inferred from Routes)
|
|
29
|
+
*
|
|
30
|
+
* const newUser = await api.post('/users', { name: 'Alice', email: 'alice@ex.com' });
|
|
31
|
+
*/
|
|
32
|
+
export function createApiClient<Routes extends ApiRouteMap>(
|
|
33
|
+
config: ApiClientConfig = {},
|
|
34
|
+
): ApiClient<Routes> {
|
|
35
|
+
return new ApiClient<Routes>(config);
|
|
36
|
+
}
|
package/src/errors.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -36,33 +36,4 @@ export { ClientProvider, Client } from "./provider/ClientProvider.ts";
|
|
|
36
36
|
export { ClientConfig } from "./config.ts";
|
|
37
37
|
export type { ClientConfigShape } from "./config.ts";
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
import { ApiClient } from "./ApiClient.ts";
|
|
42
|
-
import type { ApiRouteMap } from "./types.ts";
|
|
43
|
-
import type { ApiClientConfig } from "./ApiClient.ts";
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Create a type-safe API client bound to your route map.
|
|
47
|
-
*
|
|
48
|
-
* @example
|
|
49
|
-
* // frontend/api.ts
|
|
50
|
-
* import { createApiClient } from '@zerotal/client';
|
|
51
|
-
* import type { Routes } from './routes';
|
|
52
|
-
*
|
|
53
|
-
* export const api = createApiClient<Routes>({
|
|
54
|
-
* baseUrl: '/api',
|
|
55
|
-
* headers: { 'X-Requested-With': 'XMLHttpRequest' },
|
|
56
|
-
* });
|
|
57
|
-
*
|
|
58
|
-
* // Anywhere in your UI:
|
|
59
|
-
* const user = await api.get('/users/{id}', { id: 1 });
|
|
60
|
-
* // ^? UserResource (inferred from Routes)
|
|
61
|
-
*
|
|
62
|
-
* const newUser = await api.post('/users', { name: 'Alice', email: 'alice@ex.com' });
|
|
63
|
-
*/
|
|
64
|
-
export function createApiClient<Routes extends ApiRouteMap>(
|
|
65
|
-
config: ApiClientConfig = {},
|
|
66
|
-
): ApiClient<Routes> {
|
|
67
|
-
return new ApiClient<Routes>(config);
|
|
68
|
-
}
|
|
39
|
+
export { createApiClient } from "./createApiClient.ts";
|