@catafal/notion-cli 5.9.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/LICENSE +21 -0
- package/README.md +552 -0
- package/bin/dev +17 -0
- package/bin/dev.cmd +3 -0
- package/bin/run +14 -0
- package/bin/run.cmd +3 -0
- package/dist/base-command.d.ts +73 -0
- package/dist/base-command.js +179 -0
- package/dist/base-flags.d.ts +14 -0
- package/dist/base-flags.js +59 -0
- package/dist/cache.d.ts +84 -0
- package/dist/cache.js +351 -0
- package/dist/commands/append.d.ts +37 -0
- package/dist/commands/append.js +120 -0
- package/dist/commands/batch/delete.d.ts +42 -0
- package/dist/commands/batch/delete.js +199 -0
- package/dist/commands/batch/retrieve.d.ts +43 -0
- package/dist/commands/batch/retrieve.js +272 -0
- package/dist/commands/block/append.d.ts +42 -0
- package/dist/commands/block/append.js +219 -0
- package/dist/commands/block/delete.d.ts +30 -0
- package/dist/commands/block/delete.js +97 -0
- package/dist/commands/block/retrieve/children.d.ts +31 -0
- package/dist/commands/block/retrieve/children.js +177 -0
- package/dist/commands/block/retrieve.d.ts +30 -0
- package/dist/commands/block/retrieve.js +101 -0
- package/dist/commands/block/update.d.ts +45 -0
- package/dist/commands/block/update.js +242 -0
- package/dist/commands/bookmark/list.d.ts +30 -0
- package/dist/commands/bookmark/list.js +60 -0
- package/dist/commands/bookmark/remove.d.ts +26 -0
- package/dist/commands/bookmark/remove.js +47 -0
- package/dist/commands/bookmark/set.d.ts +29 -0
- package/dist/commands/bookmark/set.js +96 -0
- package/dist/commands/browse.d.ts +13 -0
- package/dist/commands/browse.js +44 -0
- package/dist/commands/cache/info.d.ts +19 -0
- package/dist/commands/cache/info.js +145 -0
- package/dist/commands/config/set-token.d.ts +22 -0
- package/dist/commands/config/set-token.js +137 -0
- package/dist/commands/daily/index.d.ts +32 -0
- package/dist/commands/daily/index.js +135 -0
- package/dist/commands/daily/setup.d.ts +42 -0
- package/dist/commands/daily/setup.js +149 -0
- package/dist/commands/db/create.d.ts +31 -0
- package/dist/commands/db/create.js +124 -0
- package/dist/commands/db/query.d.ts +41 -0
- package/dist/commands/db/query.js +360 -0
- package/dist/commands/db/retrieve.d.ts +33 -0
- package/dist/commands/db/retrieve.js +134 -0
- package/dist/commands/db/schema.d.ts +32 -0
- package/dist/commands/db/schema.js +308 -0
- package/dist/commands/db/update.d.ts +31 -0
- package/dist/commands/db/update.js +117 -0
- package/dist/commands/doctor.d.ts +50 -0
- package/dist/commands/doctor.js +420 -0
- package/dist/commands/init.d.ts +65 -0
- package/dist/commands/init.js +479 -0
- package/dist/commands/list.d.ts +29 -0
- package/dist/commands/list.js +219 -0
- package/dist/commands/open.d.ts +29 -0
- package/dist/commands/open.js +100 -0
- package/dist/commands/page/create.d.ts +33 -0
- package/dist/commands/page/create.js +261 -0
- package/dist/commands/page/delete.d.ts +36 -0
- package/dist/commands/page/delete.js +107 -0
- package/dist/commands/page/export.d.ts +38 -0
- package/dist/commands/page/export.js +120 -0
- package/dist/commands/page/retrieve/property_item.d.ts +24 -0
- package/dist/commands/page/retrieve/property_item.js +75 -0
- package/dist/commands/page/retrieve.d.ts +36 -0
- package/dist/commands/page/retrieve.js +244 -0
- package/dist/commands/page/update.d.ts +34 -0
- package/dist/commands/page/update.js +184 -0
- package/dist/commands/quick.d.ts +35 -0
- package/dist/commands/quick.js +168 -0
- package/dist/commands/search.d.ts +43 -0
- package/dist/commands/search.js +361 -0
- package/dist/commands/stats.d.ts +35 -0
- package/dist/commands/stats.js +274 -0
- package/dist/commands/sync.d.ts +24 -0
- package/dist/commands/sync.js +183 -0
- package/dist/commands/template/get.d.ts +28 -0
- package/dist/commands/template/get.js +59 -0
- package/dist/commands/template/list.d.ts +32 -0
- package/dist/commands/template/list.js +62 -0
- package/dist/commands/template/remove.d.ts +27 -0
- package/dist/commands/template/remove.js +48 -0
- package/dist/commands/template/save.d.ts +32 -0
- package/dist/commands/template/save.js +92 -0
- package/dist/commands/template/use.d.ts +34 -0
- package/dist/commands/template/use.js +142 -0
- package/dist/commands/user/list.d.ts +27 -0
- package/dist/commands/user/list.js +99 -0
- package/dist/commands/user/retrieve/bot.d.ts +28 -0
- package/dist/commands/user/retrieve/bot.js +96 -0
- package/dist/commands/user/retrieve.d.ts +30 -0
- package/dist/commands/user/retrieve.js +103 -0
- package/dist/commands/whoami.d.ts +19 -0
- package/dist/commands/whoami.js +175 -0
- package/dist/deduplication.d.ts +41 -0
- package/dist/deduplication.js +71 -0
- package/dist/envelope.d.ts +169 -0
- package/dist/envelope.js +257 -0
- package/dist/errors/enhanced-errors.d.ts +168 -0
- package/dist/errors/enhanced-errors.js +567 -0
- package/dist/errors/index.d.ts +18 -0
- package/dist/errors/index.js +33 -0
- package/dist/examples/cache-retry-examples.d.ts +64 -0
- package/dist/examples/cache-retry-examples.js +375 -0
- package/dist/helper.d.ts +102 -0
- package/dist/helper.js +885 -0
- package/dist/http-agent.d.ts +38 -0
- package/dist/http-agent.js +60 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4 -0
- package/dist/interface.d.ts +4 -0
- package/dist/interface.js +2 -0
- package/dist/notion.d.ts +144 -0
- package/dist/notion.js +547 -0
- package/dist/retry.d.ts +72 -0
- package/dist/retry.js +381 -0
- package/dist/utils/bookmarks.d.ts +32 -0
- package/dist/utils/bookmarks.js +98 -0
- package/dist/utils/daily-config.d.ts +22 -0
- package/dist/utils/daily-config.js +60 -0
- package/dist/utils/disk-cache.d.ts +80 -0
- package/dist/utils/disk-cache.js +291 -0
- package/dist/utils/fuzzy.d.ts +36 -0
- package/dist/utils/fuzzy.js +69 -0
- package/dist/utils/interactive-navigator.d.ts +63 -0
- package/dist/utils/interactive-navigator.js +123 -0
- package/dist/utils/markdown-to-blocks.d.ts +21 -0
- package/dist/utils/markdown-to-blocks.js +333 -0
- package/dist/utils/notion-resolver.d.ts +49 -0
- package/dist/utils/notion-resolver.js +278 -0
- package/dist/utils/notion-url-parser.d.ts +48 -0
- package/dist/utils/notion-url-parser.js +121 -0
- package/dist/utils/property-expander.d.ts +45 -0
- package/dist/utils/property-expander.js +323 -0
- package/dist/utils/schema-examples.d.ts +40 -0
- package/dist/utils/schema-examples.js +359 -0
- package/dist/utils/schema-extractor.d.ts +65 -0
- package/dist/utils/schema-extractor.js +235 -0
- package/dist/utils/shell-config.d.ts +30 -0
- package/dist/utils/shell-config.js +84 -0
- package/dist/utils/table-formatter.d.ts +36 -0
- package/dist/utils/table-formatter.js +125 -0
- package/dist/utils/templates.d.ts +30 -0
- package/dist/utils/templates.js +82 -0
- package/dist/utils/terminal-banner.d.ts +24 -0
- package/dist/utils/terminal-banner.js +34 -0
- package/dist/utils/token-validator.d.ts +42 -0
- package/dist/utils/token-validator.js +66 -0
- package/dist/utils/update-notifier.d.ts +26 -0
- package/dist/utils/update-notifier.js +54 -0
- package/dist/utils/workspace-cache.d.ts +58 -0
- package/dist/utils/workspace-cache.js +185 -0
- package/oclif.manifest.json +6471 -0
- package/package.json +118 -0
- package/scripts/banner.js +38 -0
- package/scripts/postinstall.js +44 -0
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const readline = require("readline");
|
|
5
|
+
const base_flags_1 = require("../base-flags");
|
|
6
|
+
const errors_1 = require("../errors");
|
|
7
|
+
const client_1 = require("@notionhq/client");
|
|
8
|
+
const token_validator_1 = require("../utils/token-validator");
|
|
9
|
+
const shell_config_1 = require("../utils/shell-config");
|
|
10
|
+
const notion_1 = require("../notion");
|
|
11
|
+
const workspace_cache_1 = require("../utils/workspace-cache");
|
|
12
|
+
const terminal_banner_1 = require("../utils/terminal-banner");
|
|
13
|
+
/**
|
|
14
|
+
* Interactive first-time setup wizard for Notion CLI
|
|
15
|
+
*
|
|
16
|
+
* Guides new users through:
|
|
17
|
+
* 1. Token configuration
|
|
18
|
+
* 2. Connection testing
|
|
19
|
+
* 3. Workspace synchronization
|
|
20
|
+
*
|
|
21
|
+
* Designed to provide a welcoming, educational experience that sets users up for success.
|
|
22
|
+
*/
|
|
23
|
+
class Init extends core_1.Command {
|
|
24
|
+
constructor() {
|
|
25
|
+
super(...arguments);
|
|
26
|
+
this.isJsonMode = false;
|
|
27
|
+
}
|
|
28
|
+
async run() {
|
|
29
|
+
const { args, flags } = await this.parse(Init);
|
|
30
|
+
this.isJsonMode = flags.json;
|
|
31
|
+
try {
|
|
32
|
+
// Check if already configured
|
|
33
|
+
const alreadyConfigured = await this.checkExistingSetup();
|
|
34
|
+
if (alreadyConfigured && !this.isJsonMode) {
|
|
35
|
+
const shouldReconfigure = await this.promptReconfigure();
|
|
36
|
+
if (!shouldReconfigure) {
|
|
37
|
+
this.log('\nSetup cancelled. Your existing configuration is unchanged.');
|
|
38
|
+
process.exit(0);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Welcome message
|
|
42
|
+
if (!this.isJsonMode) {
|
|
43
|
+
this.showWelcome();
|
|
44
|
+
}
|
|
45
|
+
// Step 1: Configure token (use arg if provided, otherwise prompt interactively)
|
|
46
|
+
const tokenResult = await this.setupToken(args.token);
|
|
47
|
+
// Step 2: Test connection
|
|
48
|
+
const connectionResult = await this.testConnection();
|
|
49
|
+
// Step 3: Sync workspace
|
|
50
|
+
const syncResult = await this.syncWorkspace();
|
|
51
|
+
// Success summary
|
|
52
|
+
await this.showSuccess(tokenResult, connectionResult, syncResult);
|
|
53
|
+
process.exit(0);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
const cliError = error instanceof errors_1.NotionCLIError
|
|
57
|
+
? error
|
|
58
|
+
: (0, errors_1.wrapNotionError)(error, {
|
|
59
|
+
endpoint: 'init'
|
|
60
|
+
});
|
|
61
|
+
if (this.isJsonMode) {
|
|
62
|
+
this.log(JSON.stringify(cliError.toJSON(), null, 2));
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
this.error(cliError.toHumanString());
|
|
66
|
+
}
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Check if user already has a configured token
|
|
72
|
+
*/
|
|
73
|
+
async checkExistingSetup() {
|
|
74
|
+
if (!process.env.NOTION_TOKEN) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
// Try to validate token
|
|
79
|
+
(0, token_validator_1.validateNotionToken)();
|
|
80
|
+
await (0, notion_1.botUser)();
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
// Token exists but is invalid
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Prompt user if they want to reconfigure
|
|
90
|
+
*/
|
|
91
|
+
async promptReconfigure() {
|
|
92
|
+
this.log('\nYou already have a configured Notion token.');
|
|
93
|
+
this.log('Running init again will update your configuration.');
|
|
94
|
+
this.log('');
|
|
95
|
+
const rl = readline.createInterface({
|
|
96
|
+
input: process.stdin,
|
|
97
|
+
output: process.stdout,
|
|
98
|
+
});
|
|
99
|
+
const answer = await new Promise((resolve) => {
|
|
100
|
+
rl.question('Do you want to reconfigure? (y/n): ', (answer) => {
|
|
101
|
+
rl.close();
|
|
102
|
+
resolve(answer.trim().toLowerCase());
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
return answer === 'y' || answer === 'yes';
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Show welcome message
|
|
109
|
+
*/
|
|
110
|
+
showWelcome() {
|
|
111
|
+
this.log(terminal_banner_1.ASCII_BANNER);
|
|
112
|
+
this.log(`${terminal_banner_1.colors.blue}Welcome to Notion CLI Setup!${terminal_banner_1.colors.reset}\n`);
|
|
113
|
+
this.log('This wizard will help you set up your Notion CLI in 3 steps:');
|
|
114
|
+
this.log(` ${terminal_banner_1.colors.dim}1.${terminal_banner_1.colors.reset} Configure your Notion integration token`);
|
|
115
|
+
this.log(` ${terminal_banner_1.colors.dim}2.${terminal_banner_1.colors.reset} Test the connection to Notion API`);
|
|
116
|
+
this.log(` ${terminal_banner_1.colors.dim}3.${terminal_banner_1.colors.reset} Sync your workspace databases`);
|
|
117
|
+
this.log('');
|
|
118
|
+
this.log('Let\'s get started!');
|
|
119
|
+
this.log('');
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Step 1: Setup token
|
|
123
|
+
* Accepts an optional token argument — if provided, skips interactive prompt.
|
|
124
|
+
*/
|
|
125
|
+
async setupToken(tokenArg) {
|
|
126
|
+
const stepNum = 1;
|
|
127
|
+
const stepTotal = 3;
|
|
128
|
+
if (!this.isJsonMode) {
|
|
129
|
+
this.log('='.repeat(60));
|
|
130
|
+
this.log(`Step ${stepNum}/${stepTotal}: Set your Notion token`);
|
|
131
|
+
this.log('='.repeat(60));
|
|
132
|
+
this.log('');
|
|
133
|
+
}
|
|
134
|
+
// Determine token source: argument > environment > interactive prompt
|
|
135
|
+
let token;
|
|
136
|
+
if (tokenArg) {
|
|
137
|
+
// Token provided as CLI argument — no prompting needed
|
|
138
|
+
token = tokenArg;
|
|
139
|
+
}
|
|
140
|
+
else if (this.isJsonMode) {
|
|
141
|
+
// JSON mode: token must be in environment or argument
|
|
142
|
+
if (!process.env.NOTION_TOKEN) {
|
|
143
|
+
throw new errors_1.NotionCLIError(errors_1.NotionCLIErrorCode.TOKEN_MISSING, 'Token required - pass as argument or set NOTION_TOKEN', [
|
|
144
|
+
{
|
|
145
|
+
description: 'Pass token as argument',
|
|
146
|
+
command: 'notion-cli init ntn_your_token_here --json'
|
|
147
|
+
}
|
|
148
|
+
]);
|
|
149
|
+
}
|
|
150
|
+
token = process.env.NOTION_TOKEN;
|
|
151
|
+
}
|
|
152
|
+
else if (process.env.NOTION_TOKEN) {
|
|
153
|
+
// Token exists in env — ask if user wants to keep it
|
|
154
|
+
this.log('Found existing NOTION_TOKEN in environment.');
|
|
155
|
+
const rl = readline.createInterface({
|
|
156
|
+
input: process.stdin,
|
|
157
|
+
output: process.stdout,
|
|
158
|
+
});
|
|
159
|
+
const useExisting = await new Promise((resolve) => {
|
|
160
|
+
rl.question('Use existing token? (y/n): ', (answer) => {
|
|
161
|
+
rl.close();
|
|
162
|
+
resolve(answer.trim().toLowerCase());
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
if (useExisting === 'y' || useExisting === 'yes') {
|
|
166
|
+
this.log('Using existing token from environment.');
|
|
167
|
+
this.log('');
|
|
168
|
+
return {
|
|
169
|
+
source: 'environment',
|
|
170
|
+
updated: false
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
// User wants a new token — prompt for it
|
|
174
|
+
token = await this.promptForToken();
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
// No token anywhere — show instructions and prompt
|
|
178
|
+
this.log('You need a Notion integration token to use this CLI.');
|
|
179
|
+
this.log('Get one at: https://www.notion.so/my-integrations');
|
|
180
|
+
this.log('');
|
|
181
|
+
token = await this.promptForToken();
|
|
182
|
+
}
|
|
183
|
+
// Validate token is not empty
|
|
184
|
+
if (!token) {
|
|
185
|
+
throw new errors_1.NotionCLIError(errors_1.NotionCLIErrorCode.TOKEN_INVALID, 'Token cannot be empty', [
|
|
186
|
+
{
|
|
187
|
+
description: 'Get your integration token from Notion',
|
|
188
|
+
link: 'https://developers.notion.com/docs/create-a-notion-integration'
|
|
189
|
+
}
|
|
190
|
+
]);
|
|
191
|
+
}
|
|
192
|
+
// Accept tokens with or without "secret_" prefix — auto-prepend if needed
|
|
193
|
+
// Notion tokens can start with "secret_" (legacy) or "ntn_" (current)
|
|
194
|
+
if (!token.startsWith('secret_') && !token.startsWith('ntn_')) {
|
|
195
|
+
token = `secret_${token}`;
|
|
196
|
+
if (!this.isJsonMode) {
|
|
197
|
+
this.log(`${terminal_banner_1.colors.dim}Note: Automatically added "secret_" prefix to token${terminal_banner_1.colors.reset}`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// Validate token length (Notion tokens are typically 50+ chars)
|
|
201
|
+
if (token.length < 20) {
|
|
202
|
+
throw new errors_1.NotionCLIError(errors_1.NotionCLIErrorCode.TOKEN_INVALID, 'Token appears to be too short', [
|
|
203
|
+
{
|
|
204
|
+
description: 'Notion integration tokens are typically 50+ characters',
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
description: 'Please verify you copied the complete token from Notion',
|
|
208
|
+
link: 'https://www.notion.so/my-integrations'
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
description: 'Token should look like: ntn_abc123... or secret_abc123... (40+ more characters)',
|
|
212
|
+
}
|
|
213
|
+
]);
|
|
214
|
+
}
|
|
215
|
+
// Set token in current process for subsequent steps
|
|
216
|
+
process.env.NOTION_TOKEN = token;
|
|
217
|
+
// Persist token to shell rc file so it's available in future sessions
|
|
218
|
+
const { rcFile } = await (0, shell_config_1.persistToken)(token);
|
|
219
|
+
if (!this.isJsonMode) {
|
|
220
|
+
this.log('');
|
|
221
|
+
this.log(`Token saved to ${rcFile}`);
|
|
222
|
+
this.log(`Reload other terminal tabs with: source ${rcFile}`);
|
|
223
|
+
this.log('');
|
|
224
|
+
this.log('Step 1 complete!');
|
|
225
|
+
this.log('');
|
|
226
|
+
}
|
|
227
|
+
return {
|
|
228
|
+
source: 'user_input',
|
|
229
|
+
updated: true,
|
|
230
|
+
tokenLength: token.length
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Prompt user for token via interactive readline
|
|
235
|
+
*/
|
|
236
|
+
async promptForToken() {
|
|
237
|
+
const rl = readline.createInterface({
|
|
238
|
+
input: process.stdin,
|
|
239
|
+
output: process.stdout,
|
|
240
|
+
});
|
|
241
|
+
const token = await new Promise((resolve) => {
|
|
242
|
+
rl.question('Enter your Notion integration token: ', (answer) => {
|
|
243
|
+
rl.close();
|
|
244
|
+
resolve(answer.trim());
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
return token;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Step 2: Test connection
|
|
251
|
+
*/
|
|
252
|
+
async testConnection() {
|
|
253
|
+
const stepNum = 2;
|
|
254
|
+
const stepTotal = 3;
|
|
255
|
+
if (!this.isJsonMode) {
|
|
256
|
+
this.log('='.repeat(60));
|
|
257
|
+
this.log(`Step ${stepNum}/${stepTotal}: Test connection`);
|
|
258
|
+
this.log('='.repeat(60));
|
|
259
|
+
this.log('');
|
|
260
|
+
core_1.ux.action.start('Connecting to Notion API');
|
|
261
|
+
}
|
|
262
|
+
const startTime = Date.now();
|
|
263
|
+
try {
|
|
264
|
+
// Validate token and fetch bot info
|
|
265
|
+
(0, token_validator_1.validateNotionToken)();
|
|
266
|
+
// Use a fresh client — the module-level client may have been created
|
|
267
|
+
// before process.env.NOTION_TOKEN was set (e.g., during init flow)
|
|
268
|
+
const freshClient = new client_1.Client({ auth: process.env.NOTION_TOKEN });
|
|
269
|
+
const userResponse = await freshClient.users.me({});
|
|
270
|
+
const user = userResponse;
|
|
271
|
+
const latency = Date.now() - startTime;
|
|
272
|
+
// Extract bot info
|
|
273
|
+
const botInfo = {
|
|
274
|
+
id: user.id,
|
|
275
|
+
name: user.name || 'Unnamed Bot',
|
|
276
|
+
type: user.type
|
|
277
|
+
};
|
|
278
|
+
let workspaceInfo = null;
|
|
279
|
+
if (user.type === 'bot') {
|
|
280
|
+
const botUser = user;
|
|
281
|
+
if (botUser.bot && typeof botUser.bot === 'object' && 'owner' in botUser.bot) {
|
|
282
|
+
if (botUser.bot.workspace_name) {
|
|
283
|
+
workspaceInfo = {
|
|
284
|
+
name: botUser.bot.workspace_name,
|
|
285
|
+
id: botUser.bot.workspace_id,
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
if (!this.isJsonMode) {
|
|
291
|
+
core_1.ux.action.stop('connected');
|
|
292
|
+
this.log('');
|
|
293
|
+
this.log(`Bot Name: ${botInfo.name}`);
|
|
294
|
+
this.log(`Bot ID: ${botInfo.id}`);
|
|
295
|
+
if (workspaceInfo) {
|
|
296
|
+
this.log(`Workspace: ${workspaceInfo.name}`);
|
|
297
|
+
}
|
|
298
|
+
this.log(`Connection latency: ${latency}ms`);
|
|
299
|
+
this.log('');
|
|
300
|
+
this.log('Step 2 complete!');
|
|
301
|
+
this.log('');
|
|
302
|
+
}
|
|
303
|
+
return {
|
|
304
|
+
success: true,
|
|
305
|
+
bot: botInfo,
|
|
306
|
+
workspace: workspaceInfo,
|
|
307
|
+
latency_ms: latency
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
catch (error) {
|
|
311
|
+
if (!this.isJsonMode) {
|
|
312
|
+
core_1.ux.action.stop('failed');
|
|
313
|
+
}
|
|
314
|
+
throw (0, errors_1.wrapNotionError)(error, {
|
|
315
|
+
endpoint: 'users.botUser',
|
|
316
|
+
resourceType: 'user'
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Step 3: Sync workspace
|
|
322
|
+
*/
|
|
323
|
+
async syncWorkspace() {
|
|
324
|
+
var _a;
|
|
325
|
+
const stepNum = 3;
|
|
326
|
+
const stepTotal = 3;
|
|
327
|
+
if (!this.isJsonMode) {
|
|
328
|
+
this.log('='.repeat(60));
|
|
329
|
+
this.log(`Step ${stepNum}/${stepTotal}: Sync workspace`);
|
|
330
|
+
this.log('='.repeat(60));
|
|
331
|
+
this.log('');
|
|
332
|
+
this.log('This will index all databases your integration can access.');
|
|
333
|
+
this.log('');
|
|
334
|
+
core_1.ux.action.start('Syncing databases');
|
|
335
|
+
}
|
|
336
|
+
const startTime = Date.now();
|
|
337
|
+
try {
|
|
338
|
+
// Use fresh client (same reason as testConnection — token may have been set mid-process)
|
|
339
|
+
const freshClient = new client_1.Client({ auth: process.env.NOTION_TOKEN });
|
|
340
|
+
// Fetch all databases
|
|
341
|
+
const databases = [];
|
|
342
|
+
let cursor = undefined;
|
|
343
|
+
while (true) {
|
|
344
|
+
const response = await freshClient.search({
|
|
345
|
+
filter: {
|
|
346
|
+
value: 'data_source',
|
|
347
|
+
property: 'object',
|
|
348
|
+
},
|
|
349
|
+
start_cursor: cursor,
|
|
350
|
+
page_size: 100,
|
|
351
|
+
});
|
|
352
|
+
databases.push(...response.results);
|
|
353
|
+
if (!this.isJsonMode && response.has_more) {
|
|
354
|
+
core_1.ux.action.start(`Syncing databases (found ${databases.length} so far)`);
|
|
355
|
+
}
|
|
356
|
+
if (!response.has_more || !response.next_cursor) {
|
|
357
|
+
break;
|
|
358
|
+
}
|
|
359
|
+
cursor = response.next_cursor;
|
|
360
|
+
}
|
|
361
|
+
const syncTime = Date.now() - startTime;
|
|
362
|
+
if (!this.isJsonMode) {
|
|
363
|
+
core_1.ux.action.stop(`found ${databases.length}`);
|
|
364
|
+
this.log('');
|
|
365
|
+
this.log(`Synced ${databases.length} database${databases.length === 1 ? '' : 's'} in ${(syncTime / 1000).toFixed(2)}s`);
|
|
366
|
+
this.log('');
|
|
367
|
+
if (databases.length > 0) {
|
|
368
|
+
this.log('Your integration has access to these databases:');
|
|
369
|
+
databases.slice(0, 5).forEach((db) => {
|
|
370
|
+
var _a, _b;
|
|
371
|
+
const title = ((_b = (_a = db.title) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.plain_text) || 'Untitled';
|
|
372
|
+
this.log(` - ${title}`);
|
|
373
|
+
});
|
|
374
|
+
if (databases.length > 5) {
|
|
375
|
+
this.log(` ... and ${databases.length - 5} more`);
|
|
376
|
+
}
|
|
377
|
+
this.log('');
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
this.log('No databases found.');
|
|
381
|
+
this.log('Make sure you\'ve shared databases with your integration.');
|
|
382
|
+
this.log('Learn more: https://developers.notion.com/docs/create-a-notion-integration#give-your-integration-page-permissions');
|
|
383
|
+
this.log('');
|
|
384
|
+
}
|
|
385
|
+
this.log('Step 3 complete!');
|
|
386
|
+
this.log('');
|
|
387
|
+
}
|
|
388
|
+
// Try to load cache to show it's working
|
|
389
|
+
const cache = await (0, workspace_cache_1.loadCache)();
|
|
390
|
+
return {
|
|
391
|
+
success: true,
|
|
392
|
+
databases_found: databases.length,
|
|
393
|
+
sync_time_ms: syncTime,
|
|
394
|
+
cached: ((_a = cache === null || cache === void 0 ? void 0 : cache.databases) === null || _a === void 0 ? void 0 : _a.length) || 0
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
catch (error) {
|
|
398
|
+
if (!this.isJsonMode) {
|
|
399
|
+
core_1.ux.action.stop('failed');
|
|
400
|
+
}
|
|
401
|
+
throw (0, errors_1.wrapNotionError)(error, {
|
|
402
|
+
endpoint: 'search',
|
|
403
|
+
resourceType: 'database'
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Show success summary
|
|
409
|
+
*/
|
|
410
|
+
async showSuccess(tokenResult, connectionResult, syncResult) {
|
|
411
|
+
if (this.isJsonMode) {
|
|
412
|
+
this.log(JSON.stringify({
|
|
413
|
+
success: true,
|
|
414
|
+
message: 'Notion CLI setup complete',
|
|
415
|
+
data: {
|
|
416
|
+
token: tokenResult,
|
|
417
|
+
connection: connectionResult,
|
|
418
|
+
sync: syncResult
|
|
419
|
+
},
|
|
420
|
+
next_steps: [
|
|
421
|
+
'notion-cli list - List all databases',
|
|
422
|
+
'notion-cli db query <name-or-id> - Query a database',
|
|
423
|
+
'notion-cli whoami - Check connection status',
|
|
424
|
+
'notion-cli sync - Refresh workspace cache',
|
|
425
|
+
],
|
|
426
|
+
metadata: {
|
|
427
|
+
timestamp: new Date().toISOString(),
|
|
428
|
+
command: 'init'
|
|
429
|
+
}
|
|
430
|
+
}, null, 2));
|
|
431
|
+
}
|
|
432
|
+
else {
|
|
433
|
+
this.log('='.repeat(60));
|
|
434
|
+
this.log(' Setup Complete!');
|
|
435
|
+
this.log('='.repeat(60));
|
|
436
|
+
this.log('');
|
|
437
|
+
this.log('Your Notion CLI is ready to use!');
|
|
438
|
+
this.log('');
|
|
439
|
+
this.log('Quick Start Commands:');
|
|
440
|
+
this.log(' notion-cli list - List all databases');
|
|
441
|
+
this.log(' notion-cli db query <name> - Query a database');
|
|
442
|
+
this.log(' notion-cli whoami - Check connection status');
|
|
443
|
+
this.log(' notion-cli sync - Refresh workspace cache');
|
|
444
|
+
this.log('');
|
|
445
|
+
this.log('Documentation:');
|
|
446
|
+
this.log(' https://github.com/Catafal/notion-cli');
|
|
447
|
+
this.log('');
|
|
448
|
+
this.log('Need help? Run any command with --help flag');
|
|
449
|
+
this.log('');
|
|
450
|
+
this.log('Happy building with Notion!');
|
|
451
|
+
this.log('');
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
Init.description = 'Interactive first-time setup wizard for Notion CLI';
|
|
456
|
+
Init.args = {
|
|
457
|
+
token: core_1.Args.string({
|
|
458
|
+
description: 'Notion integration token (starts with secret_ or ntn_)',
|
|
459
|
+
required: false,
|
|
460
|
+
}),
|
|
461
|
+
};
|
|
462
|
+
Init.examples = [
|
|
463
|
+
{
|
|
464
|
+
description: 'Set up with token directly',
|
|
465
|
+
command: '$ notion-cli init ntn_your_token_here',
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
description: 'Run interactive setup wizard',
|
|
469
|
+
command: '$ notion-cli init',
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
description: 'Run setup with automated JSON output',
|
|
473
|
+
command: '$ notion-cli init --json',
|
|
474
|
+
},
|
|
475
|
+
];
|
|
476
|
+
Init.flags = {
|
|
477
|
+
...base_flags_1.AutomationFlags,
|
|
478
|
+
};
|
|
479
|
+
exports.default = Init;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class List extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static aliases: string[];
|
|
5
|
+
static examples: {
|
|
6
|
+
description: string;
|
|
7
|
+
command: string;
|
|
8
|
+
}[];
|
|
9
|
+
static flags: {
|
|
10
|
+
filter: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
11
|
+
markdown: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
12
|
+
'compact-json': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
pretty: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
14
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
15
|
+
'page-size': import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
16
|
+
retry: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
17
|
+
timeout: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
18
|
+
'no-cache': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
19
|
+
verbose: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
20
|
+
minimal: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
21
|
+
columns: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
22
|
+
sort: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
23
|
+
csv: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
24
|
+
extended: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
25
|
+
'no-truncate': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
26
|
+
'no-header': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
27
|
+
};
|
|
28
|
+
run(): Promise<void>;
|
|
29
|
+
}
|