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