@tnldotdev/tnl 0.1.0-rc.15 → 0.1.0-rc.20
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/NOTICE +6 -0
- package/README.md +176 -14
- package/THIRD_PARTY_LICENSES.txt +6597 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +4 -0
- package/dist/internal/dev.d.ts +41 -0
- package/dist/internal/dev.js +387 -0
- package/dist/internal/runtime.d.ts +22 -0
- package/dist/internal/runtime.js +118 -0
- package/dist/next.d.ts +10 -0
- package/dist/next.js +75 -0
- package/dist/vite.d.ts +3 -0
- package/dist/vite.js +98 -0
- package/lib/config.d.ts +69 -0
- package/lib/config.mjs +3 -0
- package/lib/launcher.mjs +7 -6
- package/lib/native-targets.mjs +12 -0
- package/package.json +57 -9
package/NOTICE
ADDED
package/README.md
CHANGED
|
@@ -1,34 +1,196 @@
|
|
|
1
1
|
# `@tnldotdev/tnl`
|
|
2
2
|
|
|
3
|
-
This package installs the `tnl` client for macOS or Linux on arm64 or x64
|
|
4
|
-
|
|
3
|
+
This package installs the `tnl` client for macOS or Linux on arm64 or x64 and
|
|
4
|
+
provides its browser-safe project runtime plus official Next.js and Vite
|
|
5
|
+
integrations. It does not include the `tnld` server process.
|
|
5
6
|
|
|
6
7
|
## Install
|
|
7
8
|
|
|
8
|
-
Install the client:
|
|
9
|
-
|
|
10
9
|
```console
|
|
11
10
|
pnpm add --save-dev @tnldotdev/tnl@next
|
|
12
11
|
```
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
The package selects an exact-version native optional dependency for the current
|
|
14
|
+
platform. It has no install script and does not download executable code from a
|
|
15
|
+
third-party host. Node.js 22.18 or newer is required by the launcher,
|
|
16
|
+
integrations, and TypeScript configuration loader.
|
|
17
|
+
|
|
18
|
+
The native CLI enables pseudonymous telemetry by default. Use
|
|
19
|
+
`TNL_NO_TELEMETRY=true` or `--no-telemetry` to disable it; see the
|
|
20
|
+
[telemetry disclosure](../../README.md#telemetry).
|
|
21
|
+
|
|
22
|
+
## Configuration
|
|
23
|
+
|
|
24
|
+
Run `tnl init` to add the package and missing project/framework configuration.
|
|
25
|
+
It preserves existing Next.js, Vite, and TypeScript configuration and reports
|
|
26
|
+
remaining integration actions. Configure an integration below before starting
|
|
27
|
+
a framework-discovered tunnel.
|
|
28
|
+
|
|
29
|
+
For a project with existing `apps/api` and `apps/web` directories:
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
// tnl.config.ts
|
|
33
|
+
import { defineConfig } from "@tnldotdev/tnl/config";
|
|
34
|
+
|
|
35
|
+
export default defineConfig({
|
|
36
|
+
dev: { command: ["pnpm", "dev"] },
|
|
37
|
+
services: {
|
|
38
|
+
api: { directory: "apps/api", publish: { target: 3001 } },
|
|
39
|
+
web: { directory: "apps/web" },
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Each service overrides root defaults. Commands run in the service directory,
|
|
45
|
+
which must exist within the project root. Choose explicitly when several
|
|
46
|
+
services exist: `tnl dev web` or `tnl publish api`. A single service is selected
|
|
47
|
+
automatically. Service names are 1-32 lowercase ASCII letters/digits/hyphens,
|
|
48
|
+
begin with a letter, and cannot end with a hyphen; at most 32 services are allowed.
|
|
49
|
+
|
|
50
|
+
`defineConfig` also accepts a synchronous or asynchronous factory:
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
export default defineConfig(({ worktree }) => ({
|
|
54
|
+
tunnel: { subdomain: worktree.label },
|
|
55
|
+
dev: { command: ["pnpm", "dev"], startupTimeout: "90s" },
|
|
56
|
+
}));
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`worktree.label` combines a readable name with an eight-character hash, stable
|
|
60
|
+
for one client state directory but distinct across worktrees and installations.
|
|
61
|
+
Its private random input is not exposed. Factories receive deeply frozen
|
|
62
|
+
`cwd`, `env`, and `worktree` context. `cwd` is the invocation directory; Node
|
|
63
|
+
executes from the configuration directory. Both the loader environment and
|
|
64
|
+
`context.env` omit `TNL_*` and `TNLD_*`, not arbitrary application secrets.
|
|
65
|
+
|
|
66
|
+
Configuration executes trusted project code, not a sandbox. `defineConfig` is
|
|
67
|
+
type assistance, not runtime validation; the native client validates the result.
|
|
68
|
+
TypeScript uses camel-case fields and implicitly version 1. Static YAML/JSON
|
|
69
|
+
requires `version: 1` and snake-case fields; see
|
|
70
|
+
[discovery and precedence](../../README.md#project-configuration) and the
|
|
71
|
+
[JSON Schema](https://tnl.dev/schema/v1.json).
|
|
72
|
+
|
|
73
|
+
`tunnel.host` and `tunnel.subdomain` are alternatives, as are `public: true` and
|
|
74
|
+
`allowIP`. Service overrides replace the corresponding inherited alternative.
|
|
75
|
+
`dev.port` forces the exact listener port. `dev.startupTimeout` defaults to two
|
|
76
|
+
minutes and must be positive and at most ten minutes. `dev.command` is an
|
|
77
|
+
argument array, not a shell command string.
|
|
78
|
+
|
|
79
|
+
## Project Runtime
|
|
80
|
+
|
|
81
|
+
Authenticate to the configured server, then generate metadata from the project
|
|
82
|
+
root:
|
|
83
|
+
|
|
84
|
+
```console
|
|
85
|
+
tnl login https://control.tnl.example.com --token
|
|
86
|
+
tnl config generate
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Generation resolves the authenticated membership and ready domain for the root
|
|
90
|
+
and every service, including services with server/team overrides. It writes
|
|
91
|
+
`.tnl/project.json` and `.tnl/project.d.ts`. Regenerate after changing service,
|
|
92
|
+
server, team, or domain configuration; `tnl dev` also generates metadata when
|
|
93
|
+
project configuration is present. Keep `.tnl` ignored by Git.
|
|
15
94
|
|
|
16
|
-
|
|
95
|
+
Add the declaration to the application's existing TypeScript `include` list.
|
|
96
|
+
For an app at the project root, include `.tnl/project.d.ts`; for the example's
|
|
97
|
+
`apps/web/tsconfig.json`, include `../../.tnl/project.d.ts`:
|
|
17
98
|
|
|
18
99
|
```json
|
|
19
100
|
{
|
|
20
|
-
"
|
|
21
|
-
"dev:public": "tnl dev -- pnpm dev"
|
|
22
|
-
}
|
|
101
|
+
"include": ["**/*.ts", "**/*.tsx", "../../.tnl/project.d.ts"]
|
|
23
102
|
}
|
|
24
103
|
```
|
|
25
104
|
|
|
26
|
-
|
|
27
|
-
|
|
105
|
+
Preserve other framework-required includes. The augmentation gives exact
|
|
106
|
+
service keys and literal hostname/URL types. Without it, types remain broad;
|
|
107
|
+
check that a service exists before accessing it.
|
|
28
108
|
|
|
29
|
-
The
|
|
30
|
-
|
|
31
|
-
|
|
109
|
+
The integrations expose this browser-safe runtime during development:
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
import { tnl } from "@tnldotdev/tnl";
|
|
113
|
+
|
|
114
|
+
if (tnl) {
|
|
115
|
+
tnl.memberNamespace;
|
|
116
|
+
tnl.services.api.hostname;
|
|
117
|
+
tnl.services.api.url;
|
|
118
|
+
tnl.runningUnderTnlDev;
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
The `tnl` value is undefined during builds, previews, and production. During
|
|
123
|
+
development, behavior depends on discovery:
|
|
124
|
+
|
|
125
|
+
| Development context | Runtime and network behavior |
|
|
126
|
+
| ---------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
|
|
127
|
+
| No generated metadata or explicit bootstrap | `tnl` is undefined; no tunnel configuration |
|
|
128
|
+
| Metadata without a matching development socket | Frozen metadata, `runningUnderTnlDev: false`; no tunnel configuration |
|
|
129
|
+
| Explicit bootstrap or discovered matching `tnl dev` socket | Assigned metadata, `runningUnderTnlDev: true`; configure and register the actual listener |
|
|
130
|
+
|
|
131
|
+
Socket discovery supports starting `tnl dev web` first and the framework from
|
|
132
|
+
its service directory in another terminal. Discovery happens when framework
|
|
133
|
+
configuration loads, not continuously. Metadata is a snapshot, not route
|
|
134
|
+
readiness or service health. Values are deeply frozen; malformed metadata throws
|
|
135
|
+
rather than silently becoming undefined. `tnl publish` cannot inject metadata
|
|
136
|
+
into an already-running application.
|
|
137
|
+
|
|
138
|
+
## Next.js
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
// next.config.ts
|
|
142
|
+
import { withTnl } from "@tnldotdev/tnl/next";
|
|
143
|
+
|
|
144
|
+
export default withTnl({
|
|
145
|
+
reactStrictMode: true,
|
|
146
|
+
});
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
`withTnl` preserves object, promised, synchronous-function, and
|
|
150
|
+
asynchronous-function configuration. During `tnl dev`, it adds the assigned
|
|
151
|
+
hostname to `allowedDevOrigins`, injects the project runtime, and registers the
|
|
152
|
+
actual listener target reported by Next.js after it binds. Existing host and
|
|
153
|
+
port choices, including Next.js defaults and custom values, are preserved. An
|
|
154
|
+
unforced port may use Next.js's normal occupied-port retry behavior without
|
|
155
|
+
tunneling a different process on the preferred port. A port forced by
|
|
156
|
+
`tnl dev --port` remains exact. Host settings remain independent, so a project
|
|
157
|
+
can intentionally expose its development server on the LAN as well as through
|
|
158
|
+
tnl.
|
|
159
|
+
|
|
160
|
+
Next.js 16.3.4 or newer is supported.
|
|
161
|
+
|
|
162
|
+
## Vite
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
// vite.config.ts
|
|
166
|
+
import { defineConfig } from "vite";
|
|
167
|
+
import tnl from "@tnldotdev/tnl/vite";
|
|
168
|
+
|
|
169
|
+
export default defineConfig({
|
|
170
|
+
plugins: [tnl()],
|
|
171
|
+
});
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
During `tnl dev`, the plugin allows the assigned hostname, injects the project
|
|
175
|
+
runtime, and registers Vite's actual post-bind target. It preserves Vite's
|
|
176
|
+
default or configured host and port behavior, including occupied-port retries;
|
|
177
|
+
a port forced by `tnl dev --port` remains exact. User host settings can
|
|
178
|
+
independently expose Vite on the LAN. Without a development socket the plugin
|
|
179
|
+
only injects generated metadata. Builds and previews remain inert. Vite 6.0.9
|
|
180
|
+
or newer is supported.
|
|
181
|
+
|
|
182
|
+
Next.js and Vite are optional peers, so only the framework already used by the
|
|
183
|
+
project is required. Keep hostname, policy, server, service, and command
|
|
184
|
+
settings in project configuration rather than passing integration options.
|
|
185
|
+
|
|
186
|
+
### Listener Requirements
|
|
187
|
+
|
|
188
|
+
The target must be loopback HTTP. Wildcard bindings (`0.0.0.0` or `::`) allow
|
|
189
|
+
LAN exposure while tnl connects through loopback; binding only a specific LAN
|
|
190
|
+
address is rejected. Vite middleware mode has no supported listening target.
|
|
191
|
+
Next.js must report an HTTP listener origin. Forced ports are checked against
|
|
192
|
+
the actual listener, not assumed from configuration. Vite's `allowedHosts: true`
|
|
193
|
+
is preserved; the integration does not re-enable host filtering you disabled.
|
|
32
194
|
|
|
33
195
|
Deploy `tnld` with the release container or install it from Homebrew or a
|
|
34
196
|
release archive.
|