fastmode-mcp 1.0.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 +561 -0
- package/bin/run.js +50 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +802 -0
- package/dist/lib/api-client.d.ts +81 -0
- package/dist/lib/api-client.d.ts.map +1 -0
- package/dist/lib/api-client.js +237 -0
- package/dist/lib/auth-state.d.ts +13 -0
- package/dist/lib/auth-state.d.ts.map +1 -0
- package/dist/lib/auth-state.js +24 -0
- package/dist/lib/context-fetcher.d.ts +67 -0
- package/dist/lib/context-fetcher.d.ts.map +1 -0
- package/dist/lib/context-fetcher.js +190 -0
- package/dist/lib/credentials.d.ts +52 -0
- package/dist/lib/credentials.d.ts.map +1 -0
- package/dist/lib/credentials.js +196 -0
- package/dist/lib/device-flow.d.ts +14 -0
- package/dist/lib/device-flow.d.ts.map +1 -0
- package/dist/lib/device-flow.js +244 -0
- package/dist/tools/cms-items.d.ts +56 -0
- package/dist/tools/cms-items.d.ts.map +1 -0
- package/dist/tools/cms-items.js +376 -0
- package/dist/tools/create-site.d.ts +9 -0
- package/dist/tools/create-site.d.ts.map +1 -0
- package/dist/tools/create-site.js +202 -0
- package/dist/tools/deploy-package.d.ts +9 -0
- package/dist/tools/deploy-package.d.ts.map +1 -0
- package/dist/tools/deploy-package.js +434 -0
- package/dist/tools/generate-samples.d.ts +19 -0
- package/dist/tools/generate-samples.d.ts.map +1 -0
- package/dist/tools/generate-samples.js +272 -0
- package/dist/tools/get-conversion-guide.d.ts +7 -0
- package/dist/tools/get-conversion-guide.d.ts.map +1 -0
- package/dist/tools/get-conversion-guide.js +1323 -0
- package/dist/tools/get-example.d.ts +7 -0
- package/dist/tools/get-example.d.ts.map +1 -0
- package/dist/tools/get-example.js +1568 -0
- package/dist/tools/get-field-types.d.ts +30 -0
- package/dist/tools/get-field-types.d.ts.map +1 -0
- package/dist/tools/get-field-types.js +154 -0
- package/dist/tools/get-schema.d.ts +5 -0
- package/dist/tools/get-schema.d.ts.map +1 -0
- package/dist/tools/get-schema.js +320 -0
- package/dist/tools/get-started.d.ts +21 -0
- package/dist/tools/get-started.d.ts.map +1 -0
- package/dist/tools/get-started.js +624 -0
- package/dist/tools/get-tenant-schema.d.ts +18 -0
- package/dist/tools/get-tenant-schema.d.ts.map +1 -0
- package/dist/tools/get-tenant-schema.js +158 -0
- package/dist/tools/list-projects.d.ts +5 -0
- package/dist/tools/list-projects.d.ts.map +1 -0
- package/dist/tools/list-projects.js +101 -0
- package/dist/tools/sync-schema.d.ts +41 -0
- package/dist/tools/sync-schema.d.ts.map +1 -0
- package/dist/tools/sync-schema.js +483 -0
- package/dist/tools/validate-manifest.d.ts +5 -0
- package/dist/tools/validate-manifest.d.ts.map +1 -0
- package/dist/tools/validate-manifest.js +311 -0
- package/dist/tools/validate-package.d.ts +5 -0
- package/dist/tools/validate-package.d.ts.map +1 -0
- package/dist/tools/validate-package.js +337 -0
- package/dist/tools/validate-template.d.ts +12 -0
- package/dist/tools/validate-template.d.ts.map +1 -0
- package/dist/tools/validate-template.js +790 -0
- package/package.json +54 -0
- package/scripts/postinstall.js +129 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.getCredentialsPath = getCredentialsPath;
|
|
37
|
+
exports.loadCredentials = loadCredentials;
|
|
38
|
+
exports.saveCredentials = saveCredentials;
|
|
39
|
+
exports.deleteCredentials = deleteCredentials;
|
|
40
|
+
exports.hasCredentials = hasCredentials;
|
|
41
|
+
exports.isTokenExpired = isTokenExpired;
|
|
42
|
+
exports.getApiUrl = getApiUrl;
|
|
43
|
+
exports.refreshAccessToken = refreshAccessToken;
|
|
44
|
+
exports.getValidCredentials = getValidCredentials;
|
|
45
|
+
exports.getAuthToken = getAuthToken;
|
|
46
|
+
const fs = __importStar(require("fs"));
|
|
47
|
+
const path = __importStar(require("path"));
|
|
48
|
+
const os = __importStar(require("os"));
|
|
49
|
+
/**
|
|
50
|
+
* Get the path to the credentials file
|
|
51
|
+
*/
|
|
52
|
+
function getCredentialsPath() {
|
|
53
|
+
const configDir = path.join(os.homedir(), '.fastmode');
|
|
54
|
+
return path.join(configDir, 'credentials.json');
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Ensure the config directory exists
|
|
58
|
+
*/
|
|
59
|
+
function ensureConfigDir() {
|
|
60
|
+
const configDir = path.dirname(getCredentialsPath());
|
|
61
|
+
if (!fs.existsSync(configDir)) {
|
|
62
|
+
fs.mkdirSync(configDir, { recursive: true, mode: 0o700 });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Load stored credentials from disk
|
|
67
|
+
*/
|
|
68
|
+
function loadCredentials() {
|
|
69
|
+
const credentialsPath = getCredentialsPath();
|
|
70
|
+
try {
|
|
71
|
+
if (!fs.existsSync(credentialsPath)) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
const content = fs.readFileSync(credentialsPath, 'utf-8');
|
|
75
|
+
const credentials = JSON.parse(content);
|
|
76
|
+
// Validate required fields
|
|
77
|
+
if (!credentials.accessToken || !credentials.refreshToken || !credentials.expiresAt || !credentials.email) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
return credentials;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Save credentials to disk
|
|
88
|
+
*/
|
|
89
|
+
function saveCredentials(credentials) {
|
|
90
|
+
ensureConfigDir();
|
|
91
|
+
const credentialsPath = getCredentialsPath();
|
|
92
|
+
// Write with restricted permissions (owner read/write only)
|
|
93
|
+
fs.writeFileSync(credentialsPath, JSON.stringify(credentials, null, 2), { mode: 0o600 });
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Delete stored credentials
|
|
97
|
+
*/
|
|
98
|
+
function deleteCredentials() {
|
|
99
|
+
const credentialsPath = getCredentialsPath();
|
|
100
|
+
try {
|
|
101
|
+
if (fs.existsSync(credentialsPath)) {
|
|
102
|
+
fs.unlinkSync(credentialsPath);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
// Ignore errors
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Check if credentials exist
|
|
111
|
+
*/
|
|
112
|
+
function hasCredentials() {
|
|
113
|
+
return loadCredentials() !== null;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Check if the access token is expired or about to expire
|
|
117
|
+
*/
|
|
118
|
+
function isTokenExpired(credentials, bufferMinutes = 5) {
|
|
119
|
+
const expiresAt = new Date(credentials.expiresAt);
|
|
120
|
+
const bufferMs = bufferMinutes * 60 * 1000;
|
|
121
|
+
return Date.now() >= expiresAt.getTime() - bufferMs;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Get the API URL from environment or default
|
|
125
|
+
*/
|
|
126
|
+
function getApiUrl() {
|
|
127
|
+
return process.env.FASTMODE_API_URL || 'https://api.fastmode.ai';
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Refresh the access token using the refresh token
|
|
131
|
+
*/
|
|
132
|
+
async function refreshAccessToken(credentials) {
|
|
133
|
+
const apiUrl = getApiUrl();
|
|
134
|
+
try {
|
|
135
|
+
const response = await fetch(`${apiUrl}/api/auth/device/refresh`, {
|
|
136
|
+
method: 'POST',
|
|
137
|
+
headers: {
|
|
138
|
+
'Content-Type': 'application/json',
|
|
139
|
+
},
|
|
140
|
+
body: JSON.stringify({
|
|
141
|
+
refresh_token: credentials.refreshToken,
|
|
142
|
+
grant_type: 'refresh_token',
|
|
143
|
+
}),
|
|
144
|
+
});
|
|
145
|
+
if (!response.ok) {
|
|
146
|
+
// Refresh token is invalid or expired - need to re-authenticate
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
const data = await response.json();
|
|
150
|
+
if (!data.success || !data.data) {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
const newCredentials = {
|
|
154
|
+
accessToken: data.data.access_token,
|
|
155
|
+
refreshToken: data.data.refresh_token,
|
|
156
|
+
expiresAt: new Date(Date.now() + data.data.expires_in * 1000).toISOString(),
|
|
157
|
+
email: data.data.email,
|
|
158
|
+
name: data.data.name,
|
|
159
|
+
};
|
|
160
|
+
// Save the new credentials
|
|
161
|
+
saveCredentials(newCredentials);
|
|
162
|
+
return newCredentials;
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Get valid credentials, refreshing if needed
|
|
170
|
+
* Returns null if no credentials or refresh fails
|
|
171
|
+
*/
|
|
172
|
+
async function getValidCredentials() {
|
|
173
|
+
const credentials = loadCredentials();
|
|
174
|
+
if (!credentials) {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
// Check if token is expired or about to expire
|
|
178
|
+
if (isTokenExpired(credentials)) {
|
|
179
|
+
// Try to refresh
|
|
180
|
+
const newCredentials = await refreshAccessToken(credentials);
|
|
181
|
+
if (!newCredentials) {
|
|
182
|
+
// Refresh failed - credentials are invalid
|
|
183
|
+
deleteCredentials();
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
return newCredentials;
|
|
187
|
+
}
|
|
188
|
+
return credentials;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Get the current auth token (access token) if available and valid
|
|
192
|
+
*/
|
|
193
|
+
async function getAuthToken() {
|
|
194
|
+
const credentials = await getValidCredentials();
|
|
195
|
+
return credentials?.accessToken || null;
|
|
196
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Start the device authorization flow
|
|
3
|
+
* Returns a message describing the flow status
|
|
4
|
+
*/
|
|
5
|
+
export declare function startDeviceFlow(): Promise<string>;
|
|
6
|
+
/**
|
|
7
|
+
* Check if device flow authentication is needed and perform it if so
|
|
8
|
+
* Returns the authentication result message
|
|
9
|
+
*/
|
|
10
|
+
export declare function ensureAuthenticated(): Promise<{
|
|
11
|
+
authenticated: boolean;
|
|
12
|
+
message: string;
|
|
13
|
+
}>;
|
|
14
|
+
//# sourceMappingURL=device-flow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-flow.d.ts","sourceRoot":"","sources":["../../src/lib/device-flow.ts"],"names":[],"mappings":"AA0DA;;;GAGG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC,CAqGvD;AA0ED;;;GAGG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC;IAAE,aAAa,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CA2BhG"}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.startDeviceFlow = startDeviceFlow;
|
|
37
|
+
exports.ensureAuthenticated = ensureAuthenticated;
|
|
38
|
+
const child_process_1 = require("child_process");
|
|
39
|
+
const credentials_1 = require("./credentials");
|
|
40
|
+
/**
|
|
41
|
+
* Open a URL in the default browser
|
|
42
|
+
*/
|
|
43
|
+
function openBrowser(url) {
|
|
44
|
+
return new Promise((resolve) => {
|
|
45
|
+
// Determine the command based on platform
|
|
46
|
+
let command;
|
|
47
|
+
switch (process.platform) {
|
|
48
|
+
case 'darwin':
|
|
49
|
+
command = `open "${url}"`;
|
|
50
|
+
break;
|
|
51
|
+
case 'win32':
|
|
52
|
+
command = `start "" "${url}"`;
|
|
53
|
+
break;
|
|
54
|
+
default:
|
|
55
|
+
// Linux and others
|
|
56
|
+
command = `xdg-open "${url}"`;
|
|
57
|
+
}
|
|
58
|
+
(0, child_process_1.exec)(command, (error) => {
|
|
59
|
+
if (error) {
|
|
60
|
+
// Don't fail if browser can't open - user can manually navigate
|
|
61
|
+
resolve();
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
resolve();
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Start the device authorization flow
|
|
71
|
+
* Returns a message describing the flow status
|
|
72
|
+
*/
|
|
73
|
+
async function startDeviceFlow() {
|
|
74
|
+
const apiUrl = (0, credentials_1.getApiUrl)();
|
|
75
|
+
// Step 1: Request device authorization
|
|
76
|
+
let authResponse;
|
|
77
|
+
try {
|
|
78
|
+
const response = await fetch(`${apiUrl}/api/auth/device/authorize`, {
|
|
79
|
+
method: 'POST',
|
|
80
|
+
headers: {
|
|
81
|
+
'Content-Type': 'application/json',
|
|
82
|
+
},
|
|
83
|
+
body: JSON.stringify({
|
|
84
|
+
clientName: 'FastMode MCP',
|
|
85
|
+
}),
|
|
86
|
+
});
|
|
87
|
+
if (!response.ok) {
|
|
88
|
+
const error = await response.json().catch(() => ({ error: 'Unknown error' }));
|
|
89
|
+
return `# Authentication Error
|
|
90
|
+
|
|
91
|
+
Failed to start device authorization: ${error.error || response.statusText}
|
|
92
|
+
|
|
93
|
+
Please check:
|
|
94
|
+
1. Your network connection
|
|
95
|
+
2. The API URL is correct (${apiUrl})
|
|
96
|
+
`;
|
|
97
|
+
}
|
|
98
|
+
const data = await response.json();
|
|
99
|
+
authResponse = data.data;
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
return `# Network Error
|
|
103
|
+
|
|
104
|
+
Unable to connect to FastMode API.
|
|
105
|
+
|
|
106
|
+
**API URL:** ${apiUrl}
|
|
107
|
+
**Error:** ${error instanceof Error ? error.message : 'Unknown error'}
|
|
108
|
+
|
|
109
|
+
Please check your network connection and try again.
|
|
110
|
+
`;
|
|
111
|
+
}
|
|
112
|
+
// Step 2: Open browser for user authorization
|
|
113
|
+
try {
|
|
114
|
+
await openBrowser(authResponse.verification_uri_complete);
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// Browser failed to open - user will need to navigate manually
|
|
118
|
+
}
|
|
119
|
+
// Step 3: Poll for authorization
|
|
120
|
+
const pollInterval = (authResponse.interval || 5) * 1000; // seconds to ms
|
|
121
|
+
const expiresAt = Date.now() + authResponse.expires_in * 1000;
|
|
122
|
+
// Log instructions to stderr for user visibility
|
|
123
|
+
console.error(`
|
|
124
|
+
# Device Authorization
|
|
125
|
+
|
|
126
|
+
A browser window should open automatically.
|
|
127
|
+
|
|
128
|
+
If it doesn't, please visit:
|
|
129
|
+
${authResponse.verification_uri}
|
|
130
|
+
|
|
131
|
+
And enter this code: ${authResponse.user_code}
|
|
132
|
+
|
|
133
|
+
**Don't have a Fast Mode account?**
|
|
134
|
+
Sign up at https://fastmode.ai first, then return here.
|
|
135
|
+
|
|
136
|
+
Waiting for authorization...
|
|
137
|
+
`);
|
|
138
|
+
// Start polling
|
|
139
|
+
const pollResult = await pollForToken(apiUrl, authResponse.device_code, pollInterval, expiresAt);
|
|
140
|
+
if (pollResult.success && pollResult.credentials) {
|
|
141
|
+
// Save credentials
|
|
142
|
+
(0, credentials_1.saveCredentials)(pollResult.credentials);
|
|
143
|
+
return `# Authentication Successful
|
|
144
|
+
|
|
145
|
+
Logged in as: **${pollResult.credentials.email}**${pollResult.credentials.name ? ` (${pollResult.credentials.name})` : ''}
|
|
146
|
+
|
|
147
|
+
Credentials saved to ~/.fastmode/credentials.json
|
|
148
|
+
|
|
149
|
+
You can now use FastMode MCP tools.
|
|
150
|
+
`;
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
return `# Authentication Failed
|
|
154
|
+
|
|
155
|
+
${pollResult.error || 'Authorization timed out or was denied.'}
|
|
156
|
+
|
|
157
|
+
**Don't have an account?**
|
|
158
|
+
Sign up at https://fastmode.ai and then try again.
|
|
159
|
+
|
|
160
|
+
**To retry:** Call any authenticated tool like \`list_projects\` to start a new auth flow.
|
|
161
|
+
`;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Poll the token endpoint until authorization is complete or timeout
|
|
166
|
+
*/
|
|
167
|
+
async function pollForToken(apiUrl, deviceCode, interval, expiresAt) {
|
|
168
|
+
while (Date.now() < expiresAt) {
|
|
169
|
+
// Wait for the polling interval
|
|
170
|
+
await new Promise(resolve => setTimeout(resolve, interval));
|
|
171
|
+
try {
|
|
172
|
+
const response = await fetch(`${apiUrl}/api/auth/device/token`, {
|
|
173
|
+
method: 'POST',
|
|
174
|
+
headers: {
|
|
175
|
+
'Content-Type': 'application/json',
|
|
176
|
+
},
|
|
177
|
+
body: JSON.stringify({
|
|
178
|
+
device_code: deviceCode,
|
|
179
|
+
grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
|
|
180
|
+
}),
|
|
181
|
+
});
|
|
182
|
+
const data = await response.json();
|
|
183
|
+
if (response.ok && data.success && data.data) {
|
|
184
|
+
// Authorization successful!
|
|
185
|
+
const tokenData = data.data;
|
|
186
|
+
const credentials = {
|
|
187
|
+
accessToken: tokenData.access_token,
|
|
188
|
+
refreshToken: tokenData.refresh_token,
|
|
189
|
+
expiresAt: new Date(Date.now() + tokenData.expires_in * 1000).toISOString(),
|
|
190
|
+
email: tokenData.email,
|
|
191
|
+
name: tokenData.name,
|
|
192
|
+
};
|
|
193
|
+
return { success: true, credentials };
|
|
194
|
+
}
|
|
195
|
+
// Check for specific error codes
|
|
196
|
+
if (data.error === 'authorization_pending') {
|
|
197
|
+
// User hasn't authorized yet - keep polling
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
if (data.error === 'slow_down') {
|
|
201
|
+
// Server is asking us to slow down
|
|
202
|
+
interval = Math.min(interval * 2, 30000); // Max 30 seconds
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
if (data.error === 'expired_token') {
|
|
206
|
+
return { success: false, error: 'The authorization request expired. Please try again.' };
|
|
207
|
+
}
|
|
208
|
+
if (data.error === 'access_denied') {
|
|
209
|
+
return { success: false, error: 'Authorization was denied. Please try again.' };
|
|
210
|
+
}
|
|
211
|
+
// Unknown error - keep polling
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
// Network error - keep trying
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return { success: false, error: 'Authorization timed out. Please try again.' };
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Check if device flow authentication is needed and perform it if so
|
|
221
|
+
* Returns the authentication result message
|
|
222
|
+
*/
|
|
223
|
+
async function ensureAuthenticated() {
|
|
224
|
+
// Import here to avoid circular dependency
|
|
225
|
+
const { getValidCredentials } = await Promise.resolve().then(() => __importStar(require('./credentials')));
|
|
226
|
+
const { waitForAuth } = await Promise.resolve().then(() => __importStar(require('./auth-state')));
|
|
227
|
+
// Wait for any startup auth that might be in progress
|
|
228
|
+
await waitForAuth();
|
|
229
|
+
const credentials = await getValidCredentials();
|
|
230
|
+
if (credentials) {
|
|
231
|
+
return {
|
|
232
|
+
authenticated: true,
|
|
233
|
+
message: `Authenticated as ${credentials.email}`,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
// Need to authenticate
|
|
237
|
+
const result = await startDeviceFlow();
|
|
238
|
+
// Check if authentication was successful
|
|
239
|
+
const newCredentials = await getValidCredentials();
|
|
240
|
+
return {
|
|
241
|
+
authenticated: !!newCredentials,
|
|
242
|
+
message: result,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CMS Item Management Tools
|
|
3
|
+
*
|
|
4
|
+
* CRUD operations for managing items in CMS collections via the dashboard API.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Create a new item in a CMS collection
|
|
8
|
+
*/
|
|
9
|
+
export declare function createCmsItem(params: {
|
|
10
|
+
projectId: string;
|
|
11
|
+
collectionSlug: string;
|
|
12
|
+
name: string;
|
|
13
|
+
slug?: string;
|
|
14
|
+
data: Record<string, unknown>;
|
|
15
|
+
publishedAt?: string;
|
|
16
|
+
}): Promise<string>;
|
|
17
|
+
/**
|
|
18
|
+
* List items in a CMS collection
|
|
19
|
+
*/
|
|
20
|
+
export declare function listCmsItems(params: {
|
|
21
|
+
projectId: string;
|
|
22
|
+
collectionSlug: string;
|
|
23
|
+
limit?: number;
|
|
24
|
+
sort?: string;
|
|
25
|
+
order?: 'asc' | 'desc';
|
|
26
|
+
}): Promise<string>;
|
|
27
|
+
/**
|
|
28
|
+
* Get a single item by slug
|
|
29
|
+
*/
|
|
30
|
+
export declare function getCmsItem(params: {
|
|
31
|
+
projectId: string;
|
|
32
|
+
collectionSlug: string;
|
|
33
|
+
itemSlug: string;
|
|
34
|
+
}): Promise<string>;
|
|
35
|
+
/**
|
|
36
|
+
* Update an existing item
|
|
37
|
+
*/
|
|
38
|
+
export declare function updateCmsItem(params: {
|
|
39
|
+
projectId: string;
|
|
40
|
+
collectionSlug: string;
|
|
41
|
+
itemSlug: string;
|
|
42
|
+
name?: string;
|
|
43
|
+
data?: Record<string, unknown>;
|
|
44
|
+
publishedAt?: string | null;
|
|
45
|
+
}): Promise<string>;
|
|
46
|
+
/**
|
|
47
|
+
* Delete an item from a collection
|
|
48
|
+
* REQUIRES confirmDelete: true to execute
|
|
49
|
+
*/
|
|
50
|
+
export declare function deleteCmsItem(params: {
|
|
51
|
+
projectId: string;
|
|
52
|
+
collectionSlug: string;
|
|
53
|
+
itemSlug: string;
|
|
54
|
+
confirmDelete: boolean;
|
|
55
|
+
}): Promise<string>;
|
|
56
|
+
//# sourceMappingURL=cms-items.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cms-items.d.ts","sourceRoot":"","sources":["../../src/tools/cms-items.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAqFH;;GAEG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC,MAAM,CAAC,CAuDlB;AAkBD;;GAEG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;CACxB,GAAG,OAAO,CAAC,MAAM,CAAC,CA6ClB;AA4CD;;GAEG;AACH,wBAAsB,UAAU,CAAC,MAAM,EAAE;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC,MAAM,CAAC,CA6ClB;AAoBD;;GAEG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,GAAG,OAAO,CAAC,MAAM,CAAC,CA6ElB;AAkBD;;;GAGG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,OAAO,CAAC;CACxB,GAAG,OAAO,CAAC,MAAM,CAAC,CAwElB"}
|