@promptbook/cli 0.98.0 → 0.100.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 +4 -0
- package/esm/index.es.js +208 -8
- package/esm/index.es.js.map +1 -1
- package/esm/typings/src/config.d.ts +10 -0
- package/esm/typings/src/remote-server/connection-improvements.test.d.ts +1 -0
- package/esm/typings/src/remote-server/utils/connectionProgress.d.ts +72 -0
- package/esm/typings/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/umd/index.umd.js +208 -8
- package/umd/index.umd.js.map +1 -1
package/README.md
CHANGED
|
@@ -25,6 +25,10 @@ Write AI applications using plain human language across multiple models and plat
|
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
|
|
28
|
+
<blockquote style="color: #ff8811">
|
|
29
|
+
<b>⚠ Warning:</b> This is a pre-release version of the library. It is not yet ready for production use. Please look at <a href="https://www.npmjs.com/package/@promptbook/core?activeTab=versions">latest stable release</a>.
|
|
30
|
+
</blockquote>
|
|
31
|
+
|
|
28
32
|
## 📦 Package `@promptbook/cli`
|
|
29
33
|
|
|
30
34
|
- Promptbooks are [divided into several](#-packages) packages, all are published from [single monorepo](https://github.com/webgptorg/promptbook).
|
package/esm/index.es.js
CHANGED
|
@@ -47,7 +47,7 @@ const BOOK_LANGUAGE_VERSION = '1.0.0';
|
|
|
47
47
|
* @generated
|
|
48
48
|
* @see https://github.com/webgptorg/promptbook
|
|
49
49
|
*/
|
|
50
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.
|
|
50
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.100.0-0';
|
|
51
51
|
/**
|
|
52
52
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
53
53
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -221,9 +221,12 @@ const SMALL_NUMBER = 0.001;
|
|
|
221
221
|
/**
|
|
222
222
|
* Timeout for the connections in milliseconds
|
|
223
223
|
*
|
|
224
|
+
* Note: Increased from 7 seconds to 30 seconds to accommodate OAuth flows
|
|
225
|
+
* like Facebook login which may require user interaction and redirects
|
|
226
|
+
*
|
|
224
227
|
* @private within the repository - too low-level in comparison with other `MAX_...`
|
|
225
228
|
*/
|
|
226
|
-
const CONNECTION_TIMEOUT_MS =
|
|
229
|
+
const CONNECTION_TIMEOUT_MS = 30 * 1000;
|
|
227
230
|
// <- TODO: [⏳] Standardize timeouts, Make DEFAULT_TIMEOUT_MS as global constant
|
|
228
231
|
/**
|
|
229
232
|
* How many times to retry the connections
|
|
@@ -2560,13 +2563,39 @@ async function createRemoteClient(options) {
|
|
|
2560
2563
|
transports: ['polling', 'websocket' /*, <- TODO: [🌬] Allow to pass `transports`, add 'webtransport' */],
|
|
2561
2564
|
});
|
|
2562
2565
|
// console.log('Connecting to', this.options.remoteServerUrl.href, { socket });
|
|
2566
|
+
let isResolved = false;
|
|
2563
2567
|
socket.on('connect', () => {
|
|
2564
|
-
|
|
2568
|
+
if (!isResolved) {
|
|
2569
|
+
isResolved = true;
|
|
2570
|
+
resolve(socket);
|
|
2571
|
+
}
|
|
2572
|
+
});
|
|
2573
|
+
socket.on('connect_error', (error) => {
|
|
2574
|
+
if (!isResolved) {
|
|
2575
|
+
isResolved = true;
|
|
2576
|
+
reject(new Error(`Failed to connect to ${remoteServerUrl}: ${error.message || error}`));
|
|
2577
|
+
}
|
|
2578
|
+
});
|
|
2579
|
+
socket.on('disconnect', (reason) => {
|
|
2580
|
+
if (!isResolved) {
|
|
2581
|
+
isResolved = true;
|
|
2582
|
+
reject(new Error(`Connection to ${remoteServerUrl} was disconnected: ${reason}`));
|
|
2583
|
+
}
|
|
2565
2584
|
});
|
|
2566
|
-
//
|
|
2567
|
-
setTimeout(() => {
|
|
2568
|
-
|
|
2585
|
+
// Better timeout handling with more descriptive error message
|
|
2586
|
+
const timeoutId = setTimeout(() => {
|
|
2587
|
+
if (!isResolved) {
|
|
2588
|
+
isResolved = true;
|
|
2589
|
+
socket.disconnect();
|
|
2590
|
+
reject(new Error(`Connection timeout after ${CONNECTION_TIMEOUT_MS / 1000} seconds while connecting to ${remoteServerUrl}. ` +
|
|
2591
|
+
`This may indicate network issues or the server may be experiencing high load. ` +
|
|
2592
|
+
`For authentication flows like social login, ensure sufficient time is allowed for user interaction.`));
|
|
2593
|
+
}
|
|
2569
2594
|
}, CONNECTION_TIMEOUT_MS);
|
|
2595
|
+
// Clean up timeout if connection succeeds
|
|
2596
|
+
socket.on('connect', () => {
|
|
2597
|
+
clearTimeout(timeoutId);
|
|
2598
|
+
});
|
|
2570
2599
|
});
|
|
2571
2600
|
}
|
|
2572
2601
|
|
|
@@ -2595,8 +2624,33 @@ class RemoteLlmExecutionTools {
|
|
|
2595
2624
|
* Check the configuration of all execution tools
|
|
2596
2625
|
*/
|
|
2597
2626
|
async checkConfiguration() {
|
|
2598
|
-
|
|
2599
|
-
|
|
2627
|
+
try {
|
|
2628
|
+
const socket = await createRemoteClient(this.options);
|
|
2629
|
+
socket.disconnect();
|
|
2630
|
+
}
|
|
2631
|
+
catch (error) {
|
|
2632
|
+
if (error instanceof Error) {
|
|
2633
|
+
// Provide user-friendly error messages for common connection issues
|
|
2634
|
+
if (error.message.includes('timeout') || error.message.includes('Timeout')) {
|
|
2635
|
+
throw new Error(`Connection to Promptbook server timed out. This may happen during authentication flows like Facebook login. ` +
|
|
2636
|
+
`Please ensure: 1) Server is running at ${this.options.remoteServerUrl}, ` +
|
|
2637
|
+
`2) Network connection is stable, 3) Authentication process is completed within the timeout period. ` +
|
|
2638
|
+
`Original error: ${error.message}`);
|
|
2639
|
+
}
|
|
2640
|
+
if (error.message.includes('connect') || error.message.includes('ECONNREFUSED')) {
|
|
2641
|
+
throw new Error(`Cannot connect to Promptbook server at ${this.options.remoteServerUrl}. ` +
|
|
2642
|
+
`Please check if the server is running and accessible. ` +
|
|
2643
|
+
`Original error: ${error.message}`);
|
|
2644
|
+
}
|
|
2645
|
+
if (error.message.includes('authentication') || error.message.includes('auth')) {
|
|
2646
|
+
throw new Error(`Authentication failed when connecting to Promptbook server. ` +
|
|
2647
|
+
`This may happen if social login (like Facebook) was not completed properly. ` +
|
|
2648
|
+
`Please retry the authentication process. ` +
|
|
2649
|
+
`Original error: ${error.message}`);
|
|
2650
|
+
}
|
|
2651
|
+
}
|
|
2652
|
+
throw error; // Re-throw if not a recognized error pattern
|
|
2653
|
+
}
|
|
2600
2654
|
// TODO: [main] !!3 Check version of the remote server and compatibility
|
|
2601
2655
|
// TODO: [🎍] Send checkConfiguration
|
|
2602
2656
|
}
|
|
@@ -14629,6 +14683,152 @@ function startRemoteServer(options) {
|
|
|
14629
14683
|
response.status(400).send({ error: serializeError(error) });
|
|
14630
14684
|
}
|
|
14631
14685
|
});
|
|
14686
|
+
// OAuth Authentication Endpoints
|
|
14687
|
+
// These endpoints provide social authentication support (Facebook, Google, etc.)
|
|
14688
|
+
app.get('/auth/:provider', async (request, response) => {
|
|
14689
|
+
const { provider } = request.params;
|
|
14690
|
+
if (!isApplicationModeAllowed) {
|
|
14691
|
+
response.status(400).json({
|
|
14692
|
+
error: 'Application mode is not allowed',
|
|
14693
|
+
message: 'Social authentication requires application mode to be enabled'
|
|
14694
|
+
});
|
|
14695
|
+
return;
|
|
14696
|
+
}
|
|
14697
|
+
try {
|
|
14698
|
+
// Get OAuth configuration from query params or environment
|
|
14699
|
+
const { redirectUri, clientId, appId } = request.query;
|
|
14700
|
+
if (!redirectUri || !clientId) {
|
|
14701
|
+
response.status(400).json({
|
|
14702
|
+
error: 'Missing OAuth parameters',
|
|
14703
|
+
message: 'redirectUri and clientId are required for OAuth flow'
|
|
14704
|
+
});
|
|
14705
|
+
return;
|
|
14706
|
+
}
|
|
14707
|
+
let authUrl;
|
|
14708
|
+
const state = Buffer.from(JSON.stringify({
|
|
14709
|
+
appId: appId || 'default',
|
|
14710
|
+
timestamp: Date.now()
|
|
14711
|
+
})).toString('base64');
|
|
14712
|
+
switch (provider.toLowerCase()) {
|
|
14713
|
+
case 'facebook':
|
|
14714
|
+
authUrl = `https://www.facebook.com/v18.0/dialog/oauth?` +
|
|
14715
|
+
`client_id=${encodeURIComponent(clientId)}&` +
|
|
14716
|
+
`redirect_uri=${encodeURIComponent(redirectUri)}&` +
|
|
14717
|
+
`scope=email,public_profile&` +
|
|
14718
|
+
`response_type=code&` +
|
|
14719
|
+
`state=${encodeURIComponent(state)}`;
|
|
14720
|
+
break;
|
|
14721
|
+
case 'google':
|
|
14722
|
+
authUrl = `https://accounts.google.com/o/oauth2/v2/auth?` +
|
|
14723
|
+
`client_id=${encodeURIComponent(clientId)}&` +
|
|
14724
|
+
`redirect_uri=${encodeURIComponent(redirectUri)}&` +
|
|
14725
|
+
`scope=openid%20email%20profile&` +
|
|
14726
|
+
`response_type=code&` +
|
|
14727
|
+
`state=${encodeURIComponent(state)}`;
|
|
14728
|
+
break;
|
|
14729
|
+
default:
|
|
14730
|
+
response.status(400).json({
|
|
14731
|
+
error: 'Unsupported provider',
|
|
14732
|
+
message: `Social authentication provider '${provider}' is not supported. Supported providers: facebook, google`
|
|
14733
|
+
});
|
|
14734
|
+
return;
|
|
14735
|
+
}
|
|
14736
|
+
// Log the OAuth attempt for debugging
|
|
14737
|
+
if (isVerbose) {
|
|
14738
|
+
console.info(colors.cyan(`OAuth ${provider} flow started for app ${appId || 'default'}`));
|
|
14739
|
+
}
|
|
14740
|
+
response.json({
|
|
14741
|
+
authUrl,
|
|
14742
|
+
provider,
|
|
14743
|
+
state,
|
|
14744
|
+
message: `Redirect user to authUrl to complete ${provider} authentication`
|
|
14745
|
+
});
|
|
14746
|
+
}
|
|
14747
|
+
catch (error) {
|
|
14748
|
+
assertsError(error);
|
|
14749
|
+
console.warn(`OAuth ${provider} initialization failed:`, error);
|
|
14750
|
+
response.status(500).json({
|
|
14751
|
+
error: 'OAuth initialization failed',
|
|
14752
|
+
message: error.message
|
|
14753
|
+
});
|
|
14754
|
+
}
|
|
14755
|
+
});
|
|
14756
|
+
app.post('/auth/:provider/callback', async (request, response) => {
|
|
14757
|
+
const { provider } = request.params;
|
|
14758
|
+
if (!isApplicationModeAllowed || login === null) {
|
|
14759
|
+
response.status(400).json({
|
|
14760
|
+
error: 'Application mode is not allowed',
|
|
14761
|
+
message: 'Social authentication requires application mode and login handler to be configured'
|
|
14762
|
+
});
|
|
14763
|
+
return;
|
|
14764
|
+
}
|
|
14765
|
+
try {
|
|
14766
|
+
const { code, state, error: oauthError } = request.body;
|
|
14767
|
+
if (oauthError) {
|
|
14768
|
+
response.status(400).json({
|
|
14769
|
+
isSuccess: false,
|
|
14770
|
+
error: 'OAuth authorization failed',
|
|
14771
|
+
message: `${provider} authentication was denied or failed: ${oauthError}`
|
|
14772
|
+
});
|
|
14773
|
+
return;
|
|
14774
|
+
}
|
|
14775
|
+
if (!code || !state) {
|
|
14776
|
+
response.status(400).json({
|
|
14777
|
+
isSuccess: false,
|
|
14778
|
+
error: 'Missing OAuth callback parameters',
|
|
14779
|
+
message: 'code and state parameters are required'
|
|
14780
|
+
});
|
|
14781
|
+
return;
|
|
14782
|
+
}
|
|
14783
|
+
// Decode state to get app information
|
|
14784
|
+
let appInfo;
|
|
14785
|
+
try {
|
|
14786
|
+
appInfo = JSON.parse(Buffer.from(state, 'base64').toString());
|
|
14787
|
+
}
|
|
14788
|
+
catch (_a) {
|
|
14789
|
+
response.status(400).json({
|
|
14790
|
+
isSuccess: false,
|
|
14791
|
+
error: 'Invalid state parameter',
|
|
14792
|
+
message: 'The OAuth state parameter is malformed'
|
|
14793
|
+
});
|
|
14794
|
+
return;
|
|
14795
|
+
}
|
|
14796
|
+
// Log the OAuth callback for debugging
|
|
14797
|
+
if (isVerbose) {
|
|
14798
|
+
console.info(colors.cyan(`OAuth ${provider} callback received for app ${appInfo.appId}`));
|
|
14799
|
+
}
|
|
14800
|
+
// Note: In a real implementation, you would:
|
|
14801
|
+
// 1. Exchange the code for an access token with the OAuth provider
|
|
14802
|
+
// 2. Use the access token to get user information
|
|
14803
|
+
// 3. Create or find the user in your system
|
|
14804
|
+
// 4. Call the login function with the user's information
|
|
14805
|
+
// For now, we provide a framework that the implementer can extend
|
|
14806
|
+
const mockUserInfo = {
|
|
14807
|
+
username: `${provider}_user_${code.substring(0, 8)}`,
|
|
14808
|
+
password: '',
|
|
14809
|
+
appId: appInfo.appId
|
|
14810
|
+
};
|
|
14811
|
+
const loginResult = await login({
|
|
14812
|
+
...mockUserInfo,
|
|
14813
|
+
rawRequest: request,
|
|
14814
|
+
rawResponse: response,
|
|
14815
|
+
});
|
|
14816
|
+
response.status(200).json({
|
|
14817
|
+
...loginResult,
|
|
14818
|
+
provider,
|
|
14819
|
+
message: loginResult.message || `${provider} authentication completed`,
|
|
14820
|
+
});
|
|
14821
|
+
}
|
|
14822
|
+
catch (error) {
|
|
14823
|
+
assertsError(error);
|
|
14824
|
+
console.warn(`OAuth ${provider} callback failed:`, error);
|
|
14825
|
+
response.status(500).json({
|
|
14826
|
+
isSuccess: false,
|
|
14827
|
+
error: 'OAuth callback processing failed',
|
|
14828
|
+
message: error.message
|
|
14829
|
+
});
|
|
14830
|
+
}
|
|
14831
|
+
});
|
|
14632
14832
|
app.get(`/books`, async (request, response) => {
|
|
14633
14833
|
if (collection === null) {
|
|
14634
14834
|
response.status(500).send('No collection available');
|