neon 2.43.0 → 2.45.0
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 +111 -15
- package/dist/_shared/auth_selection.js +86 -0
- package/dist/_shared/credentials.js +209 -0
- package/dist/_shared/paths.js +149 -0
- package/dist/{profiles.js → _shared/profiles.js} +121 -35
- package/dist/_shared/secure_file.js +43 -0
- package/dist/analytics.js +16 -6
- package/dist/auth_context.js +53 -8
- package/dist/commands/api_keys.js +8 -56
- package/dist/commands/auth.js +131 -59
- package/dist/commands/bootstrap.js +16 -3
- package/dist/commands/init.js +17 -0
- package/dist/commands/profile.js +835 -45
- package/dist/config.js +1 -22
- package/dist/context.js +7 -0
- package/dist/dev/runtime.js +45 -1
- package/dist/dev/websocket.js +1031 -0
- package/dist/index.js +16 -9
- package/dist/profile_keys.js +55 -0
- package/dist/utils/flags.js +52 -0
- package/dist/utils/middlewares.js +16 -2
- package/dist/utils/package_manager.js +8 -1
- package/package.json +12 -12
package/dist/config.js
CHANGED
|
@@ -1,27 +1,6 @@
|
|
|
1
1
|
import { existsSync, mkdirSync } from "node:fs";
|
|
2
|
-
import { configDir, resolveConfigFile } from "@neon/config/paths";
|
|
3
2
|
import { isCi } from "./env.js";
|
|
4
|
-
export
|
|
5
|
-
/**
|
|
6
|
-
* Default for `--config-dir`: `$XDG_CONFIG_HOME/neon`, else `~/.config/neon`.
|
|
7
|
-
*
|
|
8
|
-
* The directory was called `neonctl` until the CLI was renamed. An existing one is still
|
|
9
|
-
* read — see {@link credentialsPath} — but it is never written to, moved, or deleted.
|
|
10
|
-
*/
|
|
11
|
-
export const defaultDir = configDir();
|
|
12
|
-
/**
|
|
13
|
-
* Where this invocation's `credentials.json` lives.
|
|
14
|
-
*
|
|
15
|
-
* When `--config-dir` was left at its default, an existing file in the legacy `neonctl`
|
|
16
|
-
* directory is used **in place**: an install that predates the rename keeps working, and
|
|
17
|
-
* its credentials are never duplicated into a second location where one copy could go
|
|
18
|
-
* stale while another tool still reads it.
|
|
19
|
-
*
|
|
20
|
-
* A `--config-dir` the user actually passed is used exactly as given. Falling back out of
|
|
21
|
-
* an explicitly chosen directory would defeat the reason for choosing it — a CI run
|
|
22
|
-
* pointed at a scratch directory must never pick up a developer's real credentials.
|
|
23
|
-
*/
|
|
24
|
-
export const credentialsPath = (dir) => resolveConfigFile(CREDENTIALS_FILE, dir === defaultDir ? {} : { dir }).path;
|
|
3
|
+
export { CREDENTIALS_FILE, credentialsPath, defaultDir, isInsideConfigDir, isOwnedCredentialPath, } from "./_shared/paths.js";
|
|
25
4
|
export const ensureConfigDir = ({ "config-dir": configDirArg, "force-auth": forceAuth, }) => {
|
|
26
5
|
if (!existsSync(configDirArg) && (!isCi() || forceAuth)) {
|
|
27
6
|
mkdirSync(configDirArg, { recursive: true });
|
package/dist/context.js
CHANGED
|
@@ -128,6 +128,13 @@ export const enrichFromContext = (args) => {
|
|
|
128
128
|
if (isApiKeysCommand(args)) {
|
|
129
129
|
return;
|
|
130
130
|
}
|
|
131
|
+
// `profile create --mint` mints one too, and for the same reason must take its scope only
|
|
132
|
+
// from what was typed: enriched here, running it inside a linked directory would quietly
|
|
133
|
+
// produce a key scoped to that project rather than the account or organization asked for.
|
|
134
|
+
// No `profile` subcommand has any use for a project or branch.
|
|
135
|
+
if (isProfileCommand(args)) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
131
138
|
const context = readContextFile(args.contextFile);
|
|
132
139
|
if (!args.orgId) {
|
|
133
140
|
args.orgId = context.orgId;
|
package/dist/dev/runtime.js
CHANGED
|
@@ -2,6 +2,7 @@ import { createServer } from "node:http";
|
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { pathToFileURL } from "node:url";
|
|
4
4
|
import { getRequestListener } from "@hono/node-server";
|
|
5
|
+
import { createUpgradeListener, installWebSocketBridge, } from "./websocket.js";
|
|
5
6
|
const isFunction = (value) => typeof value === "function";
|
|
6
7
|
const hasFetchMethod = (value) => typeof value === "object" &&
|
|
7
8
|
value !== null &&
|
|
@@ -27,6 +28,30 @@ export const resolveFetchHandler = (mod) => {
|
|
|
27
28
|
" export default { fetch(req) { /* ... */ } }\n" +
|
|
28
29
|
" export default function (req) { /* ... */ }");
|
|
29
30
|
};
|
|
31
|
+
const hasUpgradeMethod = (value) => typeof value === "object" &&
|
|
32
|
+
value !== null &&
|
|
33
|
+
"upgrade" in value &&
|
|
34
|
+
typeof value.upgrade === "function";
|
|
35
|
+
/**
|
|
36
|
+
* Resolve the user's optional WebSocket entrypoint: a named `export function upgrade`,
|
|
37
|
+
* or an `upgrade` method on the default export. `undefined` when the module has
|
|
38
|
+
* neither, which is the common case — a function without one either uses
|
|
39
|
+
* `upgradeWebSocket()` inside `fetch` or serves no WebSockets at all.
|
|
40
|
+
*
|
|
41
|
+
* Resolution order matches the deployed runtime exactly (named export first, then the
|
|
42
|
+
* default-export method), so a module that resolves one way locally cannot resolve the
|
|
43
|
+
* other way once deployed.
|
|
44
|
+
*/
|
|
45
|
+
export const resolveUpgradeHandler = (mod) => {
|
|
46
|
+
if (typeof mod.upgrade === "function")
|
|
47
|
+
return mod.upgrade;
|
|
48
|
+
const defaultExport = mod.default;
|
|
49
|
+
if (hasUpgradeMethod(defaultExport)) {
|
|
50
|
+
const target = defaultExport;
|
|
51
|
+
return (req, socket, head) => target.upgrade(req, socket, head);
|
|
52
|
+
}
|
|
53
|
+
return undefined;
|
|
54
|
+
};
|
|
30
55
|
/**
|
|
31
56
|
* Wrap a fetch handler so user errors become a 500 response (with the message
|
|
32
57
|
* in the body during dev) instead of crashing the child process.
|
|
@@ -87,11 +112,30 @@ const listen = (server, port, hostname) => new Promise((resolveListen, rejectLis
|
|
|
87
112
|
export const startRuntime = async ({ source, port, hostname, }) => {
|
|
88
113
|
const absoluteSource = resolve(process.cwd(), source);
|
|
89
114
|
const mod = (await import(pathToFileURL(absoluteSource).href));
|
|
90
|
-
const
|
|
115
|
+
const fetchHandler = resolveFetchHandler(mod);
|
|
116
|
+
const handler = withErrorBoundary(fetchHandler);
|
|
117
|
+
// Publish the bridge `upgradeWebSocket()` reads before the user module can serve a
|
|
118
|
+
// request, so the helper resolves locally exactly as it does when deployed.
|
|
119
|
+
installWebSocketBridge();
|
|
91
120
|
const listener = getRequestListener(handler, { hostname });
|
|
92
121
|
const server = createServer((incoming, outgoing) => {
|
|
93
122
|
void listener(incoming, outgoing);
|
|
94
123
|
});
|
|
124
|
+
// Node emits 'upgrade' rather than 'request' for a WebSocket handshake. Without
|
|
125
|
+
// this listener Node hands the handshake to the ordinary request handler, which
|
|
126
|
+
// answers 200 on a connection the client expects to be a 101 — so a function's
|
|
127
|
+
// WebSocket code silently never ran under `neon dev`.
|
|
128
|
+
//
|
|
129
|
+
// The upgrade path takes the RAW handler, not the error-boundary-wrapped one. The
|
|
130
|
+
// boundary turns a throw into a 500 Response, which on this path is
|
|
131
|
+
// indistinguishable from a handler that deliberately declined the upgrade — so a
|
|
132
|
+
// crashing handler would answer 501 ("no WebSocket support") instead of surfacing
|
|
133
|
+
// the error. The upgrade listener has its own equivalent boundary, and reports a
|
|
134
|
+
// throw as the 502 the deployed runtime returns.
|
|
135
|
+
server.on("upgrade", createUpgradeListener({
|
|
136
|
+
fetch: fetchHandler,
|
|
137
|
+
upgrade: resolveUpgradeHandler(mod),
|
|
138
|
+
}));
|
|
95
139
|
const boundPort = await bindPort(server, port, hostname);
|
|
96
140
|
process.stdout.write(`neon-dev:ready ${boundPort}\n`);
|
|
97
141
|
return boundPort;
|