@slates/cli 1.0.0-rc.5 → 1.0.0-rc.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slates/cli",
3
- "version": "1.0.0-rc.5",
3
+ "version": "1.0.0-rc.9",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -20,14 +20,14 @@
20
20
  },
21
21
  "scripts": {
22
22
  "test": "vitest run --passWithNoTests",
23
- "lint": "prettier src/**/*.ts --check",
24
- "typecheck": "tsc --noEmit"
23
+ "typecheck": "tsc --noEmit",
24
+ "biome:check": "biome check --write src"
25
25
  },
26
26
  "dependencies": {
27
27
  "@inquirer/prompts": "^7.4.0",
28
- "@slates/client": "1.0.0-rc.7",
29
- "@slates/oauth-microsoft": "1.0.0-rc.2",
30
- "@slates/profiles": "1.0.0-rc.5",
28
+ "@slates/client": "1.0.0-rc.11",
29
+ "@slates/oauth-microsoft": "1.0.0-rc.4",
30
+ "@slates/profiles": "1.0.0-rc.9",
31
31
  "sade": "^1.8.1"
32
32
  },
33
33
  "devDependencies": {
@@ -8,6 +8,30 @@ describe('normalizeCallbackRedirectUriForIntegration', () => {
8
8
  ).toBe('http://localhost:45873/callback');
9
9
  });
10
10
 
11
+ it('normalizes Intercom loopback redirects to localhost', () => {
12
+ expect(
13
+ normalizeCallbackRedirectUriForIntegration('intercom', 'http://127.0.0.1:45873/callback')
14
+ ).toBe('http://localhost:45873/callback');
15
+ });
16
+
17
+ it('normalizes Typeform loopback redirects to localhost', () => {
18
+ expect(
19
+ normalizeCallbackRedirectUriForIntegration('typeform', 'http://127.0.0.1:45873/callback')
20
+ ).toBe('http://localhost:45873/callback');
21
+ });
22
+
23
+ it('normalizes Xero loopback redirects to localhost', () => {
24
+ expect(
25
+ normalizeCallbackRedirectUriForIntegration('xero', 'http://127.0.0.1:45873/callback')
26
+ ).toBe('http://localhost:45873/callback');
27
+ });
28
+
29
+ it('normalizes Zendesk loopback redirects to localhost', () => {
30
+ expect(
31
+ normalizeCallbackRedirectUriForIntegration('zendesk', 'http://127.0.0.1:45873/callback')
32
+ ).toBe('http://localhost:45873/callback');
33
+ });
34
+
11
35
  it('leaves unrelated integration redirects unchanged', () => {
12
36
  expect(
13
37
  normalizeCallbackRedirectUriForIntegration('attio', 'http://127.0.0.1:45873/callback')
@@ -3,7 +3,7 @@ import {
3
3
  normalizeMicrosoftRedirectUri,
4
4
  normalizeMicrosoftRedirectUriForIntegration
5
5
  } from '@slates/oauth-microsoft';
6
- import { SlatesOAuthCredentialRecord, SlatesStoredAuth } from '@slates/profiles';
6
+ import type { SlatesOAuthCredentialRecord, SlatesStoredAuth } from '@slates/profiles';
7
7
  import {
8
8
  chooseAuthMethod,
9
9
  createClientContext,
@@ -17,16 +17,24 @@ import {
17
17
  promptForObjectSchema,
18
18
  promptForString
19
19
  } from '../lib/prompts';
20
- import { JsonInput, WithProfile } from '../lib/types';
20
+ import type { JsonInput, WithProfile } from '../lib/types';
21
21
 
22
22
  type JsonObject = Record<string, any>;
23
23
  let NOTION_INTEGRATION_KEY = 'notion';
24
24
  let SALESFORCE_INTEGRATION_KEY = 'salesforce';
25
+ let INTERCOM_INTEGRATION_KEY = 'intercom';
26
+ let TYPEFORM_INTEGRATION_KEY = 'typeform';
27
+ let XERO_INTEGRATION_KEY = 'xero';
28
+ let ZENDESK_INTEGRATION_KEY = 'zendesk';
25
29
  let HUBSPOT_INTEGRATION_KEY = 'hubspot';
26
30
  let HUBSPOT_DEVELOPER_PLATFORM_OAUTH_METHOD_ID = 'developer_platform_oauth';
27
31
  let LOOPBACK_REDIRECT_NORMALIZED_INTEGRATIONS = new Set([
32
+ INTERCOM_INTEGRATION_KEY,
28
33
  NOTION_INTEGRATION_KEY,
29
- SALESFORCE_INTEGRATION_KEY
34
+ SALESFORCE_INTEGRATION_KEY,
35
+ TYPEFORM_INTEGRATION_KEY,
36
+ XERO_INTEGRATION_KEY,
37
+ ZENDESK_INTEGRATION_KEY
30
38
  ]);
31
39
 
32
40
  type AuthSetupOptions = WithProfile &
@@ -345,6 +353,7 @@ let runAuthSetup = async (opts: AuthSetupOptions): Promise<SlatesStoredAuth> =>
345
353
  clientId,
346
354
  clientSecret,
347
355
  scopes,
356
+ callbackParams: callbackResult.callbackParams,
348
357
  callbackState: callbackState ?? undefined
349
358
  });
350
359
 
@@ -1,6 +1,6 @@
1
1
  import { createClientContext } from '../lib/context';
2
2
  import { parseJsonObject, promptForObjectSchema } from '../lib/prompts';
3
- import { JsonInput, WithProfile } from '../lib/types';
3
+ import type { JsonInput, WithProfile } from '../lib/types';
4
4
 
5
5
  export let getConfig = async (opts: WithProfile) => {
6
6
  let { profile } = await createClientContext(opts);
@@ -1,8 +1,8 @@
1
1
  import { input } from '@inquirer/prompts';
2
- import { createSlatesClientFromProfile, openSlatesCliStore } from '@slates/profiles';
2
+ import { createSlatesClientFromProfile, type openSlatesCliStore } from '@slates/profiles';
3
3
  import path from 'path';
4
4
  import { chooseProfile, openIntegrationStore, syncProfileMetadata } from '../lib/context';
5
- import { WithProfile } from '../lib/types';
5
+ import type { WithProfile } from '../lib/types';
6
6
 
7
7
  let normalizeEntry = (rootDir: string, entry: string) => {
8
8
  let absolute = path.isAbsolute(entry) ? entry : path.resolve(process.cwd(), entry);
@@ -12,7 +12,9 @@ let normalizeEntry = (rootDir: string, entry: string) => {
12
12
  : absolute;
13
13
  };
14
14
 
15
- let getNextSetupProfileName = async (store: Awaited<ReturnType<typeof openSlatesCliStore>>) => {
15
+ let getNextSetupProfileName = async (
16
+ store: Awaited<ReturnType<typeof openSlatesCliStore>>
17
+ ) => {
16
18
  let names = new Set(store.listProfiles().map(profile => profile.name));
17
19
  if (!names.has('default')) {
18
20
  return 'default';
@@ -41,10 +43,14 @@ let createProfile = async (
41
43
 
42
44
  let defaultName =
43
45
  opts.name ??
44
- (opts.initializeConfig ? await getNextSetupProfileName(store) : `profile-${store.listProfiles().length + 1}`);
46
+ (opts.initializeConfig
47
+ ? await getNextSetupProfileName(store)
48
+ : `profile-${store.listProfiles().length + 1}`);
45
49
  let name =
46
50
  opts.name ??
47
- (interactive ? await input({ message: 'Profile name', default: defaultName }) : defaultName);
51
+ (interactive
52
+ ? await input({ message: 'Profile name', default: defaultName })
53
+ : defaultName);
48
54
  let defaultEntry = opts.entry ?? integration.entry;
49
55
  let entry =
50
56
  opts.entry ??
@@ -56,7 +62,9 @@ let createProfile = async (
56
62
  : defaultEntry);
57
63
  let exportName =
58
64
  opts.exportName ??
59
- (interactive ? await input({ message: 'Export name (optional)', default: 'provider' }) : 'provider');
65
+ (interactive
66
+ ? await input({ message: 'Export name (optional)', default: 'provider' })
67
+ : 'provider');
60
68
 
61
69
  let profile = store.upsertProfile({
62
70
  name,
@@ -1,6 +1,6 @@
1
1
  import { input } from '@inquirer/prompts';
2
2
  import { print } from '../lib/prompts';
3
- import { WithProfile } from '../lib/types';
3
+ import type { WithProfile } from '../lib/types';
4
4
  import { listAuth, setupAuth } from './auth';
5
5
  import { getConfig, setConfig } from './config';
6
6
  import { getProfile } from './profiles';
@@ -3,7 +3,7 @@ import { writeFile } from 'fs/promises';
3
3
  import path from 'path';
4
4
  import { chooseProfile } from '../lib/context';
5
5
  import { listWorkspaceIntegrations } from '../lib/integration';
6
- import { WithProfile } from '../lib/types';
6
+ import type { WithProfile } from '../lib/types';
7
7
 
8
8
  let runVitest = async (opts: {
9
9
  cwd: string;
@@ -43,7 +43,7 @@ export let runVitestWithProfile = async (opts: WithProfile & { vitestArgs: strin
43
43
 
44
44
  await writeFile(
45
45
  contextPath,
46
- JSON.stringify(
46
+ `${JSON.stringify(
47
47
  {
48
48
  integration: integration.relativeDir,
49
49
  profileId: profile.id,
@@ -53,7 +53,7 @@ export let runVitestWithProfile = async (opts: WithProfile & { vitestArgs: strin
53
53
  },
54
54
  null,
55
55
  2
56
- ) + '\n',
56
+ )}\n`,
57
57
  'utf-8'
58
58
  );
59
59
 
@@ -5,7 +5,7 @@ import {
5
5
  syncProfileMetadata
6
6
  } from '../lib/context';
7
7
  import { parseJsonObject, promptForObjectSchema } from '../lib/prompts';
8
- import { JsonInput, WithProfile } from '../lib/types';
8
+ import type { JsonInput, WithProfile } from '../lib/types';
9
9
 
10
10
  export let listTools = async (opts: WithProfile) => {
11
11
  let { store, profile, client } = await createClientContext(opts);
@@ -1,10 +1,10 @@
1
1
  import { select } from '@inquirer/prompts';
2
- import { SlatesProtocolClient } from '@slates/client';
2
+ import type { SlatesProtocolClient } from '@slates/client';
3
3
  import {
4
4
  createSlatesClientFromProfile,
5
5
  openSlatesCliStore,
6
- SlatesProfileRecord,
7
- type SlatesCliStore
6
+ type SlatesCliStore,
7
+ type SlatesProfileRecord
8
8
  } from '@slates/profiles';
9
9
  import { resolveIntegration } from './integration';
10
10
  import { promptForObjectSchema } from './prompts';
@@ -26,7 +26,11 @@ describe('resolveIntegration', () => {
26
26
  JSON.stringify({ main: 'src/index.ts' }, null, 2),
27
27
  'utf-8'
28
28
  );
29
- await writeFile(path.join(integrationDir, 'src', 'index.ts'), 'export let provider = {};\n', 'utf-8');
29
+ await writeFile(
30
+ path.join(integrationDir, 'src', 'index.ts'),
31
+ 'export let provider = {};\n',
32
+ 'utf-8'
33
+ );
30
34
 
31
35
  let resolved = await resolveIntegration('demo', { cwd });
32
36
 
@@ -44,7 +48,11 @@ describe('resolveIntegration', () => {
44
48
  JSON.stringify({ source: 'src/index.ts' }, null, 2),
45
49
  'utf-8'
46
50
  );
47
- await writeFile(path.join(integrationDir, 'src', 'index.ts'), 'export let provider = {};\n', 'utf-8');
51
+ await writeFile(
52
+ path.join(integrationDir, 'src', 'index.ts'),
53
+ 'export let provider = {};\n',
54
+ 'utf-8'
55
+ );
48
56
 
49
57
  let resolved = await resolveIntegration('./custom/demo', { cwd });
50
58
 
@@ -1,6 +1,6 @@
1
- import { access, readFile, readdir } from 'fs/promises';
2
- import path from 'path';
3
1
  import { resolveSlatesCliRoot } from '@slates/profiles';
2
+ import { access, readdir, readFile } from 'fs/promises';
3
+ import path from 'path';
4
4
 
5
5
  export interface ResolvedIntegration {
6
6
  input: string;
@@ -142,7 +142,9 @@ export let listWorkspaceIntegrations = async (opts: { cwd?: string } = {}) => {
142
142
  );
143
143
 
144
144
  integrations.push(
145
- ...chunk.filter((integration): integration is WorkspaceIntegrationSummary => integration !== null)
145
+ ...chunk.filter(
146
+ (integration): integration is WorkspaceIntegrationSummary => integration !== null
147
+ )
146
148
  );
147
149
  }
148
150
 
package/src/lib/oauth.ts CHANGED
@@ -34,7 +34,11 @@ export let createOAuthCallbackListener = async () => {
34
34
  return new Promise<{
35
35
  redirectUri: string;
36
36
  state: string;
37
- wait: () => Promise<{ code: string; state: string }>;
37
+ wait: () => Promise<{
38
+ code: string;
39
+ state: string;
40
+ callbackParams: Record<string, string>;
41
+ }>;
38
42
  }>((resolve, reject) => {
39
43
  let expectedState = randomUUID();
40
44
  let settled = false;
@@ -79,7 +83,11 @@ export let createOAuthCallbackListener = async () => {
79
83
  res.end('Authentication complete. You can close this window.');
80
84
  server.close();
81
85
  settled = true;
82
- waiter.resolve({ code, state });
86
+ waiter.resolve({
87
+ code,
88
+ state,
89
+ callbackParams: Object.fromEntries(url.searchParams.entries())
90
+ });
83
91
  } catch (error) {
84
92
  server.close();
85
93
  settled = true;
@@ -88,9 +96,17 @@ export let createOAuthCallbackListener = async () => {
88
96
  });
89
97
 
90
98
  let waiter = (() => {
91
- let resolvePromise!: (value: { code: string; state: string }) => void;
99
+ let resolvePromise!: (value: {
100
+ code: string;
101
+ state: string;
102
+ callbackParams: Record<string, string>;
103
+ }) => void;
92
104
  let rejectPromise!: (error: unknown) => void;
93
- let promise = new Promise<{ code: string; state: string }>((resolveFn, rejectFn) => {
105
+ let promise = new Promise<{
106
+ code: string;
107
+ state: string;
108
+ callbackParams: Record<string, string>;
109
+ }>((resolveFn, rejectFn) => {
94
110
  resolvePromise = resolveFn;
95
111
  rejectPromise = rejectFn;
96
112
  });
@@ -1,5 +1,5 @@
1
1
  import { checkbox, confirm, input, password, select } from '@inquirer/prompts';
2
- import { JsonObject } from './types';
2
+ import type { JsonObject } from './types';
3
3
 
4
4
  export let prettyJson = (value: unknown) => JSON.stringify(value, null, 2);
5
5