@vrdmr/fnx-test 0.2.0 → 0.3.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 +16 -4
- package/lib/azurite-manager.js +16 -15
- package/lib/cli.js +411 -135
- package/lib/colors.js +34 -0
- package/lib/host-launcher.js +34 -15
- package/lib/host-manager.js +150 -25
- package/lib/live-mcp-server.js +3 -2
- package/lib/pack.js +140 -0
- package/lib/profile-resolver.js +44 -35
- package/lib/warmup.js +12 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ npm install -g @vrdmr/fnx-test
|
|
|
11
11
|
Or run without installing:
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
npx @vrdmr/fnx-test start --sku flex --
|
|
14
|
+
npx @vrdmr/fnx-test start --sku flex --app-path ./my-app
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
## Quick Start
|
|
@@ -21,10 +21,10 @@ npx @vrdmr/fnx-test start --sku flex --scriptroot ./my-app
|
|
|
21
21
|
fnx start --sku list
|
|
22
22
|
|
|
23
23
|
# Run your function app with the Flex Consumption host
|
|
24
|
-
fnx start --sku flex --
|
|
24
|
+
fnx start --sku flex --app-path ./my-function-app
|
|
25
25
|
|
|
26
26
|
# Run with Windows Consumption host
|
|
27
|
-
fnx start --sku windows-consumption --
|
|
27
|
+
fnx start --sku windows-consumption --app-path ./my-function-app
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
## What It Does
|
|
@@ -53,12 +53,24 @@ fnx start --sku flex
|
|
|
53
53
|
## Commands
|
|
54
54
|
|
|
55
55
|
```bash
|
|
56
|
-
fnx start --sku <sku> --
|
|
56
|
+
fnx start --sku <sku> --app-path <path> # Run function app
|
|
57
57
|
fnx start --sku list # List available SKUs
|
|
58
58
|
fnx warmup [--sku <sku>] [--all] # Pre-download host + bundle
|
|
59
|
+
fnx sync [host|extensions] [--sku <sku>] # Reconcile cache with latest catalog / rollback
|
|
59
60
|
fnx templates-mcp # Start MCP server for AI agents
|
|
61
|
+
fnx pack --app-path <path> # Package function app as deployment zip
|
|
60
62
|
```
|
|
61
63
|
|
|
64
|
+
|
|
65
|
+
## Upgrades, Rollbacks, and Cache Retention
|
|
66
|
+
|
|
67
|
+
- On `fnx start`, `fnx warmup`, and `fnx sync`, fnx attempts to refresh the SKU catalog from CDN first.
|
|
68
|
+
- If catalog host version is newer than your local cache, fnx highlights that and recommends `fnx sync` (or `fnx sync host`).
|
|
69
|
+
- If catalog host version is lower than a locally cached version (service rollback), fnx warns and recommends syncing back to the supported host.
|
|
70
|
+
- `fnx sync` defaults to keeping only the latest 2 host and bundle versions to avoid cache bloat (`--keep <n>` to override).
|
|
71
|
+
- fnx also checks npm for newer fnx CLI releases and prints an upgrade tip when available.
|
|
72
|
+
- Version comparisons use numeric dot-segment precedence (e.g. `4.1047.100 > 4.1046.999`) with support for `v` prefixes and pre-release suffixes.
|
|
73
|
+
|
|
62
74
|
## MCP Server (for AI Agents)
|
|
63
75
|
|
|
64
76
|
fnx includes an MCP server that exposes Azure Functions templates to AI coding assistants:
|
package/lib/azurite-manager.js
CHANGED
|
@@ -3,6 +3,7 @@ import { createConnection } from 'node:net';
|
|
|
3
3
|
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
5
|
import { homedir } from 'node:os';
|
|
6
|
+
import { info, url as urlColor, warning, error as errorColor } from './colors.js';
|
|
6
7
|
|
|
7
8
|
const BLOB_PORT = 10000;
|
|
8
9
|
const QUEUE_PORT = 10001;
|
|
@@ -75,7 +76,7 @@ function findAzurite() {
|
|
|
75
76
|
* Install azurite into ~/.fnx/tools/azurite/ if not already present.
|
|
76
77
|
*/
|
|
77
78
|
function installAzurite() {
|
|
78
|
-
console.log('[fnx] Installing Azurite to ~/.fnx/tools/azurite/ (first-time only)...');
|
|
79
|
+
console.log(info('[fnx] Installing Azurite to ~/.fnx/tools/azurite/ (first-time only)...'));
|
|
79
80
|
mkdirSync(AZURITE_INSTALL_DIR, { recursive: true });
|
|
80
81
|
|
|
81
82
|
// Initialize a minimal package.json if missing so npm install works
|
|
@@ -91,14 +92,14 @@ function installAzurite() {
|
|
|
91
92
|
timeout: 120_000,
|
|
92
93
|
});
|
|
93
94
|
} catch (err) {
|
|
94
|
-
console.error('[fnx] Failed to install Azurite. Install manually: npm install -g azurite');
|
|
95
|
-
console.error(` ${err.message}`);
|
|
95
|
+
console.error(errorColor('[fnx] Failed to install Azurite. Install manually: npm install -g azurite'));
|
|
96
|
+
console.error(warning(` ${err.message}`));
|
|
96
97
|
return null;
|
|
97
98
|
}
|
|
98
99
|
|
|
99
100
|
const installed = join(AZURITE_INSTALL_DIR, 'node_modules', '.bin', 'azurite');
|
|
100
101
|
if (existsSync(installed)) {
|
|
101
|
-
console.log('[fnx] Azurite installed successfully.');
|
|
102
|
+
console.log(info('[fnx] Azurite installed successfully.'));
|
|
102
103
|
return installed;
|
|
103
104
|
}
|
|
104
105
|
return null;
|
|
@@ -127,23 +128,23 @@ export async function ensureAzurite(mergedValues, opts = {}) {
|
|
|
127
128
|
}
|
|
128
129
|
|
|
129
130
|
const storageVal = mergedValues?.AzureWebJobsStorage || '(empty)';
|
|
130
|
-
console.log(`[fnx] Detected AzureWebJobsStorage=${storageVal}`);
|
|
131
|
+
console.log(info(`[fnx] Detected AzureWebJobsStorage=${storageVal}`));
|
|
131
132
|
|
|
132
133
|
// Check if Azurite is already running
|
|
133
134
|
if (await isAzuriteRunning()) {
|
|
134
|
-
console.log('[fnx] Using existing Azurite instance on default ports.');
|
|
135
|
+
console.log(info('[fnx] Using existing Azurite instance on default ports.'));
|
|
135
136
|
return null;
|
|
136
137
|
}
|
|
137
138
|
|
|
138
139
|
// Find or install azurite
|
|
139
140
|
const azuriteBin = findOrInstallAzurite();
|
|
140
141
|
if (!azuriteBin) {
|
|
141
|
-
console.error('[fnx] ⚠️ Azurite not available. Storage triggers may fail.');
|
|
142
|
-
console.error(' Install with: npm install -g azurite');
|
|
142
|
+
console.error(warning('[fnx] ⚠️ Azurite not available. Storage triggers may fail.'));
|
|
143
|
+
console.error(warning(' Install with: npm install -g azurite'));
|
|
143
144
|
return null;
|
|
144
145
|
}
|
|
145
146
|
|
|
146
|
-
console.log('[fnx] Starting Azurite storage emulator...');
|
|
147
|
+
console.log(info('[fnx] Starting Azurite storage emulator...'));
|
|
147
148
|
|
|
148
149
|
const azuriteArgs = [
|
|
149
150
|
'--blobHost', '127.0.0.1', '--blobPort', String(BLOB_PORT),
|
|
@@ -161,13 +162,13 @@ export async function ensureAzurite(mergedValues, opts = {}) {
|
|
|
161
162
|
});
|
|
162
163
|
|
|
163
164
|
azuriteProcess.on('error', (err) => {
|
|
164
|
-
console.error(`[fnx] Azurite failed to start: ${err.message}`);
|
|
165
|
+
console.error(errorColor(`[fnx] Azurite failed to start: ${err.message}`));
|
|
165
166
|
azuriteProcess = null;
|
|
166
167
|
});
|
|
167
168
|
|
|
168
169
|
azuriteProcess.on('exit', (code) => {
|
|
169
170
|
if (code && code !== 0) {
|
|
170
|
-
console.error(`[fnx] Azurite exited unexpectedly with code ${code}.`);
|
|
171
|
+
console.error(errorColor(`[fnx] Azurite exited unexpectedly with code ${code}.`));
|
|
171
172
|
}
|
|
172
173
|
azuriteProcess = null;
|
|
173
174
|
});
|
|
@@ -175,13 +176,13 @@ export async function ensureAzurite(mergedValues, opts = {}) {
|
|
|
175
176
|
// Wait for Azurite to be ready
|
|
176
177
|
const ready = await waitForTcp(BLOB_PORT, { timeoutMs: 15000 });
|
|
177
178
|
if (!ready) {
|
|
178
|
-
console.error('[fnx] ⚠️ Azurite did not become ready in time. Storage triggers may fail.');
|
|
179
|
+
console.error(warning('[fnx] ⚠️ Azurite did not become ready in time. Storage triggers may fail.'));
|
|
179
180
|
return azuriteProcess;
|
|
180
181
|
}
|
|
181
182
|
|
|
182
|
-
console.log(`[fnx] Azurite Blob → http://127.0.0.1:${BLOB_PORT}`);
|
|
183
|
-
console.log(`[fnx] Azurite Queue → http://127.0.0.1:${QUEUE_PORT}`);
|
|
184
|
-
console.log(`[fnx] Azurite Table → http://127.0.0.1:${TABLE_PORT}`);
|
|
183
|
+
console.log(info(`[fnx] Azurite Blob → ${urlColor(`http://127.0.0.1:${BLOB_PORT}`)}`));
|
|
184
|
+
console.log(info(`[fnx] Azurite Queue → ${urlColor(`http://127.0.0.1:${QUEUE_PORT}`)}`));
|
|
185
|
+
console.log(info(`[fnx] Azurite Table → ${urlColor(`http://127.0.0.1:${TABLE_PORT}`)}`));
|
|
185
186
|
|
|
186
187
|
return azuriteProcess;
|
|
187
188
|
}
|