@promptbook/cli 0.98.0-9 → 0.99.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/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.98.0-9';
50
+ const PROMPTBOOK_ENGINE_VERSION = '0.99.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 = 7 * 1000;
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
- resolve(socket);
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
- // TODO: [💩] Better timeout handling
2567
- setTimeout(() => {
2568
- reject(new Error(`Timeout while connecting to ${remoteServerUrl}`));
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
- const socket = await createRemoteClient(this.options);
2599
- socket.disconnect();
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
  }
@@ -3729,9 +3783,10 @@ function createLlmToolsFromConfiguration(configuration, options = {}) {
3729
3783
  .list()
3730
3784
  .find(({ packageName, className }) => llmConfiguration.packageName === packageName && llmConfiguration.className === className);
3731
3785
  if (registeredItem === undefined) {
3732
- console.log('!!! $llmToolsRegister.list()', $llmToolsRegister.list());
3786
+ // console.log('$llmToolsRegister.list()', $llmToolsRegister.list());
3733
3787
  throw new Error(spaceTrim((block) => `
3734
3788
  There is no constructor for LLM provider \`${llmConfiguration.className}\` from \`${llmConfiguration.packageName}\`
3789
+ Running in ${!$isRunningInBrowser() ? '' : 'browser environment'}${!$isRunningInNode() ? '' : 'node environment'}${!$isRunningInWebWorker() ? '' : 'worker environment'}
3735
3790
 
3736
3791
  You have probably forgotten install and import the provider package.
3737
3792
  To fix this issue, you can:
@@ -14628,6 +14683,152 @@ function startRemoteServer(options) {
14628
14683
  response.status(400).send({ error: serializeError(error) });
14629
14684
  }
14630
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
+ });
14631
14832
  app.get(`/books`, async (request, response) => {
14632
14833
  if (collection === null) {
14633
14834
  response.status(500).send('No collection available');
@@ -14871,7 +15072,6 @@ function startRemoteServer(options) {
14871
15072
  catch (error) {
14872
15073
  assertsError(error);
14873
15074
  socket.emit('error', serializeError(error));
14874
- // <- TODO: [🚋] There is a problem with the remote server handling errors and sending them back to the client
14875
15075
  }
14876
15076
  finally {
14877
15077
  socket.disconnect();
@@ -18164,6 +18364,7 @@ const _OpenAiCompatibleMetadataRegistration = $llmToolsMetadataRegister.register
18164
18364
  options: {
18165
18365
  apiKey: 'sk-',
18166
18366
  baseURL: 'https://api.openai.com/v1',
18367
+ defaultModelName: 'gpt-4-turbo',
18167
18368
  isProxied: false,
18168
18369
  remoteServerUrl: DEFAULT_REMOTE_SERVER_URL,
18169
18370
  maxRequestsPerMinute: DEFAULT_MAX_REQUESTS_PER_MINUTE,