@tnldotdev/tnl 0.1.0-rc.24 → 0.1.0-rc.26
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/README.md +78 -62
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/internal/dev.d.ts +1 -1
- package/dist/internal/dev.js +1 -1
- package/dist/internal/runtime.d.ts +2 -2
- package/dist/internal/runtime.js +2 -2
- package/dist/next.d.ts +1 -1
- package/dist/next.js +1 -1
- package/dist/vite.d.ts +1 -1
- package/dist/vite.js +1 -1
- package/lib/config.d.ts +4 -4
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -41,11 +41,14 @@ export default defineConfig({
|
|
|
41
41
|
});
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
Each service
|
|
45
|
-
which must
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
Each project service inherits the root settings and can override them. Commands
|
|
45
|
+
run in the service directory, which must be inside the project root. If the
|
|
46
|
+
project has several services, choose one with a command such as `tnl dev web` or
|
|
47
|
+
`tnl publish api`. A project with one service selects it automatically.
|
|
48
|
+
|
|
49
|
+
Service names must start with a lowercase ASCII letter. They may contain
|
|
50
|
+
lowercase letters, digits, and hyphens, cannot end with a hyphen, and may be up
|
|
51
|
+
to 32 characters long. A project may define up to 32 services.
|
|
49
52
|
|
|
50
53
|
`defineConfig` also accepts a synchronous or asynchronous factory:
|
|
51
54
|
|
|
@@ -56,25 +59,27 @@ export default defineConfig(({ worktree }) => ({
|
|
|
56
59
|
}));
|
|
57
60
|
```
|
|
58
61
|
|
|
59
|
-
`worktree.label` combines a readable name with an eight-character hash
|
|
60
|
-
for
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
TypeScript
|
|
69
|
-
|
|
62
|
+
`worktree.label` combines a readable name with an eight-character hash. It stays
|
|
63
|
+
the same for a worktree and client state directory, but differs across worktrees
|
|
64
|
+
and installations. The private value used to create the hash is not exposed.
|
|
65
|
+
|
|
66
|
+
Factories receive read-only `cwd`, `env`, and `worktree` values. `cwd` is the
|
|
67
|
+
directory where the command started. Node runs the configuration file from its
|
|
68
|
+
own directory. The loader and `context.env` omit `TNL_*` and `TNLD_*` variables,
|
|
69
|
+
but they do not remove other application secrets.
|
|
70
|
+
|
|
71
|
+
TypeScript configuration runs as trusted project code. It is not sandboxed.
|
|
72
|
+
`defineConfig` provides type checking; the native client still validates the
|
|
73
|
+
result at runtime. TypeScript uses camel-case fields and is always version 1.
|
|
74
|
+
Static YAML and JSON require `version: 1` and snake-case fields; see
|
|
70
75
|
[discovery and precedence](../../README.md#project-configuration) and the
|
|
71
76
|
[JSON Schema](https://tnl.dev/schema/v1.json).
|
|
72
77
|
|
|
73
|
-
`tunnel.host`
|
|
74
|
-
`allowIP`.
|
|
75
|
-
`dev.port`
|
|
76
|
-
minutes and must be
|
|
77
|
-
argument array, not a shell command string.
|
|
78
|
+
Choose either `tunnel.host` or `tunnel.subdomain`. Choose either `public: true`
|
|
79
|
+
or `allowIP`. A project-service override replaces the other inherited choice.
|
|
80
|
+
`dev.port` requires the local service to use that port. `dev.startupTimeout`
|
|
81
|
+
defaults to two minutes and must be greater than zero and no more than ten
|
|
82
|
+
minutes. `dev.command` is an argument array, not a shell command string.
|
|
78
83
|
|
|
79
84
|
## Project Runtime
|
|
80
85
|
|
|
@@ -86,11 +91,13 @@ tnl login https://control.tnl.example.com --token
|
|
|
86
91
|
tnl config generate
|
|
87
92
|
```
|
|
88
93
|
|
|
89
|
-
Generation
|
|
90
|
-
|
|
91
|
-
`.tnl/project.json` and `.tnl/project.d.ts`.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
+
Generation selects the current membership and a ready domain for the project and
|
|
95
|
+
each service. It also respects service-specific server and team settings. The
|
|
96
|
+
command writes `.tnl/project.json` and `.tnl/project.d.ts`.
|
|
97
|
+
|
|
98
|
+
Regenerate after changing project services, servers, teams, or domains. The
|
|
99
|
+
`tnl dev` command also generates metadata when the project has a configuration
|
|
100
|
+
file. Keep `.tnl` ignored by Git.
|
|
94
101
|
|
|
95
102
|
Add the declaration to the application's existing TypeScript `include` list.
|
|
96
103
|
For an app at the project root, include `.tnl/project.d.ts`; for the example's
|
|
@@ -102,9 +109,10 @@ For an app at the project root, include `.tnl/project.d.ts`; for the example's
|
|
|
102
109
|
}
|
|
103
110
|
```
|
|
104
111
|
|
|
105
|
-
|
|
106
|
-
service
|
|
107
|
-
check that a service exists
|
|
112
|
+
Keep any other entries required by the framework. The generated declaration
|
|
113
|
+
adds the configured service names and their exact hostname and URL types. Without
|
|
114
|
+
it, service names use a general string type, so check that a service exists
|
|
115
|
+
before reading it.
|
|
108
116
|
|
|
109
117
|
The integrations expose this browser-safe runtime during development:
|
|
110
118
|
|
|
@@ -122,18 +130,20 @@ if (tnl) {
|
|
|
122
130
|
The `tnl` value is undefined during builds, previews, and production. During
|
|
123
131
|
development, behavior depends on discovery:
|
|
124
132
|
|
|
125
|
-
| Development context
|
|
126
|
-
|
|
|
127
|
-
| No generated metadata or
|
|
128
|
-
| Metadata without a matching development socket
|
|
129
|
-
|
|
|
133
|
+
| Development context | Runtime and network behavior |
|
|
134
|
+
| --------------------------------------------------- | ----------------------------------------------------------------------------------------- |
|
|
135
|
+
| No generated metadata or `tnl dev` environment | `tnl` is undefined; no tunnel configuration |
|
|
136
|
+
| Metadata without a matching development socket | Frozen metadata, `runningUnderTnlDev: false`; no tunnel configuration |
|
|
137
|
+
| `tnl dev` environment or discovered matching socket | Assigned metadata, `runningUnderTnlDev: true`; configure and register the actual listener |
|
|
138
|
+
|
|
139
|
+
You can start `tnl dev web` in one terminal and start the framework from the
|
|
140
|
+
service directory in another. The integration looks for the development socket
|
|
141
|
+
when the framework configuration loads; it does not keep searching afterward.
|
|
130
142
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
rather than silently becoming undefined. `tnl publish` cannot inject metadata
|
|
136
|
-
into an already-running application.
|
|
143
|
+
Project metadata is a snapshot. It does not show whether the route or local
|
|
144
|
+
service is healthy. The values are read-only, and malformed metadata causes an
|
|
145
|
+
error. `tnl publish` cannot add metadata to an application that is already
|
|
146
|
+
running.
|
|
137
147
|
|
|
138
148
|
## Next.js
|
|
139
149
|
|
|
@@ -146,16 +156,18 @@ export default withTnl({
|
|
|
146
156
|
});
|
|
147
157
|
```
|
|
148
158
|
|
|
149
|
-
`withTnl`
|
|
150
|
-
asynchronous
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
can
|
|
158
|
-
|
|
159
|
+
`withTnl` accepts every Next.js configuration form: an object, a promise, or a
|
|
160
|
+
synchronous or asynchronous function. During `tnl dev`, it:
|
|
161
|
+
|
|
162
|
+
- Adds the assigned hostname to `allowedDevOrigins`.
|
|
163
|
+
- Injects the project runtime.
|
|
164
|
+
- Registers the listener after Next.js reports the port it actually used.
|
|
165
|
+
|
|
166
|
+
The integration preserves existing host and port settings. If no port was
|
|
167
|
+
forced, Next.js can retry when its preferred port is occupied. `tnl` waits for
|
|
168
|
+
the port Next.js chooses instead of forwarding to another process. A port set by
|
|
169
|
+
`tnl dev --port` must match exactly. Host settings remain independent, so the
|
|
170
|
+
development server can still be exposed on the LAN.
|
|
159
171
|
|
|
160
172
|
Next.js 16.3.4 or newer is supported.
|
|
161
173
|
|
|
@@ -172,12 +184,14 @@ export default defineConfig({
|
|
|
172
184
|
```
|
|
173
185
|
|
|
174
186
|
During `tnl dev`, the plugin allows the assigned hostname, injects the project
|
|
175
|
-
runtime, and registers Vite
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
187
|
+
runtime, and registers the listener after Vite chooses its port. Vite keeps its
|
|
188
|
+
normal host and port behavior, including retries when a port is occupied. A port
|
|
189
|
+
set by `tnl dev --port` must match exactly. Host settings can still expose Vite
|
|
190
|
+
on the LAN.
|
|
191
|
+
|
|
192
|
+
Without a development socket, the plugin only injects generated project
|
|
193
|
+
metadata. It does nothing during builds and previews. Vite 6.0.9 or newer is
|
|
194
|
+
supported.
|
|
181
195
|
|
|
182
196
|
Next.js and Vite are optional peers, so only the framework already used by the
|
|
183
197
|
project is required. Keep hostname, policy, server, service, and command
|
|
@@ -185,12 +199,14 @@ settings in project configuration rather than passing integration options.
|
|
|
185
199
|
|
|
186
200
|
### Listener Requirements
|
|
187
201
|
|
|
188
|
-
The target must
|
|
189
|
-
|
|
190
|
-
address is
|
|
191
|
-
Next.js must report an HTTP listener
|
|
192
|
-
|
|
193
|
-
is
|
|
202
|
+
The target must use HTTP over loopback. A wildcard binding (`0.0.0.0` or `::`)
|
|
203
|
+
is allowed because tnl can still connect through loopback. Binding only to a
|
|
204
|
+
specific LAN address is not supported. Vite middleware mode does not provide a
|
|
205
|
+
supported listener. Next.js must report an HTTP listener URL.
|
|
206
|
+
|
|
207
|
+
When a port is forced, the integration checks the actual listener instead of
|
|
208
|
+
trusting configuration alone. The integration preserves Vite's
|
|
209
|
+
`allowedHosts: true` and will not re-enable host filtering.
|
|
194
210
|
|
|
195
211
|
Deploy `tnld` with the release container or install it from Homebrew or a
|
|
196
212
|
release archive.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { type ProjectMetadata } from "./internal/runtime.js";
|
|
2
|
-
/**
|
|
2
|
+
/** Extended with service types from the generated `.tnl/project.d.ts` file. */
|
|
3
3
|
export interface TnlProjectMetadata {
|
|
4
4
|
}
|
|
5
5
|
type RegisteredTnlProject = keyof TnlProjectMetadata extends never ? ProjectMetadata : Readonly<TnlProjectMetadata>;
|
|
6
6
|
type TnlProject = RegisteredTnlProject & {
|
|
7
7
|
readonly runningUnderTnlDev: boolean;
|
|
8
8
|
};
|
|
9
|
-
/**
|
|
9
|
+
/** Project metadata added by a tnl framework integration during development. */
|
|
10
10
|
export declare const tnl: TnlProject | undefined;
|
|
11
11
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { parseRuntimePayload } from "./internal/runtime.js";
|
|
2
2
|
const serializedRuntime = typeof process === "undefined" ? undefined : process.env?.TNL_PROJECT_RUNTIME;
|
|
3
|
-
/**
|
|
3
|
+
/** Project metadata added by a tnl framework integration during development. */
|
|
4
4
|
export const tnl = parseRuntimePayload(serializedRuntime);
|
package/dist/internal/dev.d.ts
CHANGED
|
@@ -37,5 +37,5 @@ export declare function registerLocalTarget(assignment: TnlTunnelAssignment, tar
|
|
|
37
37
|
export declare function runtimePayload(project: ProjectMetadata, runningUnderTnlDev: boolean): string;
|
|
38
38
|
export declare function discoverProject(cwd: string): ProjectDiscovery | null;
|
|
39
39
|
export declare function socketIdentity(projectRoot: string, service: string | null): string;
|
|
40
|
-
/** Parses
|
|
40
|
+
/** Parses a decimal listener port from 1 through 65535. */
|
|
41
41
|
export declare function parseListenerPort(value: string, source: string): number;
|
package/dist/internal/dev.js
CHANGED
|
@@ -359,7 +359,7 @@ function absoluteNormalizedPath(value, description) {
|
|
|
359
359
|
}
|
|
360
360
|
return value;
|
|
361
361
|
}
|
|
362
|
-
/** Parses
|
|
362
|
+
/** Parses a decimal listener port from 1 through 65535. */
|
|
363
363
|
export function parseListenerPort(value, source) {
|
|
364
364
|
if (!/^[0-9]+$/.test(value)) {
|
|
365
365
|
throw new Error(`${source} must be a port between 1 and 65535`);
|
|
@@ -10,9 +10,9 @@ export interface ProjectMetadata {
|
|
|
10
10
|
export interface ProjectRuntime extends ProjectMetadata {
|
|
11
11
|
readonly runningUnderTnlDev: boolean;
|
|
12
12
|
}
|
|
13
|
-
/**
|
|
13
|
+
/** Checks browser-safe project metadata and makes it read-only. */
|
|
14
14
|
export declare function parseProjectMetadata(value: unknown, description: string): ProjectMetadata;
|
|
15
|
-
/**
|
|
15
|
+
/** Reports whether a value is a valid 1-32 character ASCII service name. */
|
|
16
16
|
export declare function validServiceName(value: unknown): value is string;
|
|
17
17
|
export declare function parseRuntimePayload(serialized: string | undefined): ProjectRuntime | undefined;
|
|
18
18
|
export declare function parseProjectRuntime(value: unknown, description: string): ProjectRuntime;
|
package/dist/internal/runtime.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const maximumRuntimeBytes = 64 * 1024;
|
|
2
2
|
const maximumServices = 32;
|
|
3
3
|
const serviceNamePattern = /^[a-z](?:[a-z0-9-]{0,30}[a-z0-9])?$/;
|
|
4
|
-
/**
|
|
4
|
+
/** Checks browser-safe project metadata and makes it read-only. */
|
|
5
5
|
export function parseProjectMetadata(value, description) {
|
|
6
6
|
const object = record(value, description);
|
|
7
7
|
exactKeys(object, ["memberNamespace", "services"], description);
|
|
@@ -39,7 +39,7 @@ export function parseProjectMetadata(value, description) {
|
|
|
39
39
|
services: Object.freeze(services),
|
|
40
40
|
});
|
|
41
41
|
}
|
|
42
|
-
/**
|
|
42
|
+
/** Reports whether a value is a valid 1-32 character ASCII service name. */
|
|
43
43
|
export function validServiceName(value) {
|
|
44
44
|
return typeof value === "string" && serviceNamePattern.test(value);
|
|
45
45
|
}
|
package/dist/next.d.ts
CHANGED
|
@@ -6,5 +6,5 @@ export interface NextConfigContext {
|
|
|
6
6
|
/** A function that returns Next.js configuration. */
|
|
7
7
|
export type NextConfigFactory = (phase: string, context: NextConfigContext) => NextConfig | Promise<NextConfig>;
|
|
8
8
|
export type NextConfigInput = NextConfig | Promise<NextConfig> | NextConfigFactory;
|
|
9
|
-
/**
|
|
9
|
+
/** Configures a Next.js development server for `tnl dev` and adds project metadata. */
|
|
10
10
|
export declare function withTnl(config?: NextConfigInput, ...extra: never[]): NextConfigFactory;
|
package/dist/next.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { canonicalLoopbackTarget, parseListenerPort, readDevelopmentContext, registerLocalTarget, requestTunnelAssignment, runtimePayload, } from "./internal/dev.js";
|
|
2
2
|
const developmentServerPhase = "phase-development-server";
|
|
3
3
|
const runtimeEnvironmentName = "TNL_PROJECT_RUNTIME";
|
|
4
|
-
/**
|
|
4
|
+
/** Configures a Next.js development server for `tnl dev` and adds project metadata. */
|
|
5
5
|
export function withTnl(config = {}, ...extra) {
|
|
6
6
|
if (extra.length !== 0) {
|
|
7
7
|
throw new Error("withTnl() does not accept tunnel options; use project configuration");
|
package/dist/vite.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { Plugin } from "vite";
|
|
2
|
-
/**
|
|
2
|
+
/** Configures a Vite development server for `tnl dev` and adds project metadata. */
|
|
3
3
|
export default function tnl(...arguments_: never[]): Plugin;
|
package/dist/vite.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { canonicalLoopbackTarget, readDevelopmentContext, registerLocalTarget, requestTunnelAssignment, runtimePayload, } from "./internal/dev.js";
|
|
2
2
|
const runtimeDefineName = "process.env.TNL_PROJECT_RUNTIME";
|
|
3
|
-
/**
|
|
3
|
+
/** Configures a Vite development server for `tnl dev` and adds project metadata. */
|
|
4
4
|
export default function tnl(...arguments_) {
|
|
5
5
|
if (arguments_.length !== 0) {
|
|
6
6
|
throw new Error("tnl() does not accept tunnel options; use project configuration");
|
package/lib/config.d.ts
CHANGED
|
@@ -45,16 +45,16 @@ export interface Dev {
|
|
|
45
45
|
startupTimeout?: string;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
/**
|
|
48
|
+
/** The Git worktree or project directory that contains tnl.config.ts. */
|
|
49
49
|
export interface TnlWorktree {
|
|
50
50
|
readonly isGit: boolean;
|
|
51
|
-
/** DNS-safe
|
|
51
|
+
/** DNS-safe worktree label derived from this worktree and client state. */
|
|
52
52
|
readonly label: string;
|
|
53
53
|
readonly name: string;
|
|
54
54
|
readonly root: string;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
/** Values
|
|
57
|
+
/** Values passed to a tnl.config.ts configuration factory. */
|
|
58
58
|
export interface TnlConfigContext {
|
|
59
59
|
readonly cwd: string;
|
|
60
60
|
readonly env: Readonly<Record<string, string>>;
|
|
@@ -65,5 +65,5 @@ export type TnlConfigFactory = (context: TnlConfigContext) => TNL | Promise<TNL>
|
|
|
65
65
|
|
|
66
66
|
export type TnlConfigInput = TNL | TnlConfigFactory;
|
|
67
67
|
|
|
68
|
-
/**
|
|
68
|
+
/** Adds type checking to a version-1 tnl.config.ts configuration. */
|
|
69
69
|
export declare function defineConfig<const Config extends TnlConfigInput>(config: Config): Config;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tnldotdev/tnl",
|
|
3
|
-
"version": "0.1.0-rc.
|
|
3
|
+
"version": "0.1.0-rc.26",
|
|
4
4
|
"description": "The tnl client and framework integrations for project-local development.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -71,12 +71,12 @@
|
|
|
71
71
|
"node": ">=22.18"
|
|
72
72
|
},
|
|
73
73
|
"optionalDependencies": {
|
|
74
|
-
"@tnldotdev/tnl-darwin-arm64": "0.1.0-rc.
|
|
75
|
-
"@tnldotdev/tnl-darwin-x64": "0.1.0-rc.
|
|
76
|
-
"@tnldotdev/tnl-linux-arm64": "0.1.0-rc.
|
|
77
|
-
"@tnldotdev/tnl-linux-x64": "0.1.0-rc.
|
|
74
|
+
"@tnldotdev/tnl-darwin-arm64": "0.1.0-rc.26",
|
|
75
|
+
"@tnldotdev/tnl-darwin-x64": "0.1.0-rc.26",
|
|
76
|
+
"@tnldotdev/tnl-linux-arm64": "0.1.0-rc.26",
|
|
77
|
+
"@tnldotdev/tnl-linux-x64": "0.1.0-rc.26"
|
|
78
78
|
},
|
|
79
79
|
"tnl": {
|
|
80
|
-
"commit": "
|
|
80
|
+
"commit": "d6e8318fb2738a4377e67856e9eb6fe017e6097a"
|
|
81
81
|
}
|
|
82
82
|
}
|