@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
package/bin/dev ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+
3
+ const oclif = require('@oclif/core')
4
+
5
+ const path = require('path')
6
+ const project = path.join(__dirname, '..', 'tsconfig.json')
7
+
8
+ // In dev mode -> use ts-node and dev plugins
9
+ process.env.NODE_ENV = 'development'
10
+
11
+ require('ts-node').register({project})
12
+
13
+ // In dev mode, always show stack traces
14
+ oclif.settings.debug = true;
15
+
16
+ // Start the CLI
17
+ oclif.run().then(oclif.flush).catch(oclif.Errors.handle)
package/bin/dev.cmd ADDED
@@ -0,0 +1,3 @@
1
+ @echo off
2
+
3
+ node "%~dp0\dev" %*
package/bin/run ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+
3
+ const oclif = require('@oclif/core')
4
+
5
+ // Check for updates asynchronously (doesn't block CLI execution)
6
+ // This will notify users once per day if a new version is available
7
+ try {
8
+ const { checkForUpdates } = require('../dist/utils/update-notifier')
9
+ checkForUpdates()
10
+ } catch (error) {
11
+ // Silently fail if update check fails (e.g., during development)
12
+ }
13
+
14
+ oclif.run().then(require('@oclif/core/flush')).catch(require('@oclif/core/handle'))
package/bin/run.cmd ADDED
@@ -0,0 +1,3 @@
1
+ @echo off
2
+
3
+ node "%~dp0\run" %*
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Base Command with Envelope Support
3
+ *
4
+ * Extends oclif Command with automatic envelope wrapping for consistent JSON output.
5
+ * All commands should extend this class to get automatic envelope support.
6
+ */
7
+ import { Command, Interfaces } from '@oclif/core';
8
+ import { EnvelopeFormatter, OutputFlags } from './envelope';
9
+ import { NotionCLIError } from './errors/index';
10
+ /**
11
+ * Base command configuration
12
+ */
13
+ export type CommandConfig = Interfaces.Config;
14
+ /**
15
+ * BaseCommand - Extends oclif Command with envelope support
16
+ *
17
+ * Features:
18
+ * - Automatic envelope wrapping for JSON output
19
+ * - Consistent error handling
20
+ * - Execution time tracking
21
+ * - Version metadata injection
22
+ * - Stdout/stderr separation
23
+ */
24
+ export declare abstract class BaseCommand extends Command {
25
+ protected envelope: EnvelopeFormatter;
26
+ protected shouldUseEnvelope: boolean;
27
+ /**
28
+ * Initialize command and create envelope formatter
29
+ */
30
+ init(): Promise<void>;
31
+ /**
32
+ * Cleanup hook - flushes disk cache and destroys HTTP agents before exit
33
+ */
34
+ finally(error?: Error): Promise<void>;
35
+ /**
36
+ * Determine if envelope should be used based on flags
37
+ */
38
+ protected checkEnvelopeUsage(flags: Record<string, unknown>): boolean;
39
+ /**
40
+ * Output success response with automatic envelope wrapping
41
+ *
42
+ * @param data - Response data
43
+ * @param flags - Command flags
44
+ * @param additionalMetadata - Optional metadata to include
45
+ */
46
+ protected outputSuccess<T>(data: T, flags: OutputFlags & Record<string, unknown>, additionalMetadata?: Record<string, unknown>): never;
47
+ /**
48
+ * Output error response with automatic envelope wrapping
49
+ *
50
+ * @param error - Error object
51
+ * @param flags - Command flags
52
+ * @param additionalContext - Optional error context
53
+ */
54
+ protected outputError(error: Error | NotionCLIError, flags: OutputFlags & Record<string, unknown>, additionalContext?: Record<string, unknown>): never;
55
+ /**
56
+ * Get appropriate exit code for error
57
+ */
58
+ private getExitCodeForError;
59
+ /**
60
+ * Catch handler that ensures proper envelope error output
61
+ */
62
+ catch(error: Error & {
63
+ exitCode?: number;
64
+ }): Promise<void>;
65
+ }
66
+ /**
67
+ * Standard flags that all envelope-enabled commands should include
68
+ */
69
+ export declare const EnvelopeFlags: {
70
+ json: Interfaces.BooleanFlag<boolean>;
71
+ 'compact-json': Interfaces.BooleanFlag<boolean>;
72
+ raw: Interfaces.BooleanFlag<boolean>;
73
+ };
@@ -0,0 +1,179 @@
1
+ "use strict";
2
+ /**
3
+ * Base Command with Envelope Support
4
+ *
5
+ * Extends oclif Command with automatic envelope wrapping for consistent JSON output.
6
+ * All commands should extend this class to get automatic envelope support.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.EnvelopeFlags = exports.BaseCommand = void 0;
10
+ const core_1 = require("@oclif/core");
11
+ const envelope_1 = require("./envelope");
12
+ const index_1 = require("./errors/index");
13
+ const disk_cache_1 = require("./utils/disk-cache");
14
+ const http_agent_1 = require("./http-agent");
15
+ /**
16
+ * BaseCommand - Extends oclif Command with envelope support
17
+ *
18
+ * Features:
19
+ * - Automatic envelope wrapping for JSON output
20
+ * - Consistent error handling
21
+ * - Execution time tracking
22
+ * - Version metadata injection
23
+ * - Stdout/stderr separation
24
+ */
25
+ class BaseCommand extends core_1.Command {
26
+ constructor() {
27
+ super(...arguments);
28
+ this.shouldUseEnvelope = false;
29
+ }
30
+ /**
31
+ * Initialize command and create envelope formatter
32
+ */
33
+ async init() {
34
+ var _a;
35
+ await super.init();
36
+ // Initialize disk cache (load from disk)
37
+ const diskCacheEnabled = process.env.NOTION_CLI_DISK_CACHE_ENABLED !== 'false';
38
+ if (diskCacheEnabled) {
39
+ try {
40
+ await disk_cache_1.diskCacheManager.initialize();
41
+ }
42
+ catch (error) {
43
+ // Silently ignore disk cache initialization errors
44
+ if (process.env.DEBUG) {
45
+ console.error('Failed to initialize disk cache:', error);
46
+ }
47
+ }
48
+ }
49
+ // Get command name from ID (e.g., "page:retrieve" -> "page retrieve")
50
+ const commandName = ((_a = this.id) === null || _a === void 0 ? void 0 : _a.replace(/:/g, ' ')) || 'unknown';
51
+ // Get version from config
52
+ const version = this.config.version;
53
+ // Initialize envelope formatter
54
+ this.envelope = new envelope_1.EnvelopeFormatter(commandName, version);
55
+ }
56
+ /**
57
+ * Cleanup hook - flushes disk cache and destroys HTTP agents before exit
58
+ */
59
+ async finally(error) {
60
+ // Destroy HTTP agents to close all connections
61
+ try {
62
+ (0, http_agent_1.destroyAgents)();
63
+ }
64
+ catch (agentError) {
65
+ // Silently ignore agent cleanup errors
66
+ if (process.env.DEBUG) {
67
+ console.error('Failed to destroy HTTP agents:', agentError);
68
+ }
69
+ }
70
+ // Flush disk cache before exit
71
+ const diskCacheEnabled = process.env.NOTION_CLI_DISK_CACHE_ENABLED !== 'false';
72
+ if (diskCacheEnabled) {
73
+ try {
74
+ await disk_cache_1.diskCacheManager.shutdown();
75
+ }
76
+ catch (shutdownError) {
77
+ // Silently ignore shutdown errors
78
+ if (process.env.DEBUG) {
79
+ console.error('Failed to shutdown disk cache:', shutdownError);
80
+ }
81
+ }
82
+ }
83
+ await super.finally(error);
84
+ }
85
+ /**
86
+ * Determine if envelope should be used based on flags
87
+ */
88
+ checkEnvelopeUsage(flags) {
89
+ return !!(flags.json || flags['compact-json']);
90
+ }
91
+ /**
92
+ * Output success response with automatic envelope wrapping
93
+ *
94
+ * @param data - Response data
95
+ * @param flags - Command flags
96
+ * @param additionalMetadata - Optional metadata to include
97
+ */
98
+ outputSuccess(data, flags, additionalMetadata) {
99
+ // Check if we should use envelope
100
+ this.shouldUseEnvelope = this.checkEnvelopeUsage(flags);
101
+ if (this.shouldUseEnvelope) {
102
+ const envelope = this.envelope.wrapSuccess(data, additionalMetadata);
103
+ this.envelope.outputEnvelope(envelope, flags, this.log.bind(this));
104
+ process.exit(this.envelope.getExitCode(envelope));
105
+ }
106
+ else {
107
+ // Non-envelope output (table, markdown, etc.) - handled by caller
108
+ // This path should not normally be reached as caller handles non-JSON output
109
+ throw new Error('outputSuccess should only be called for JSON output');
110
+ }
111
+ }
112
+ /**
113
+ * Output error response with automatic envelope wrapping
114
+ *
115
+ * @param error - Error object
116
+ * @param flags - Command flags
117
+ * @param additionalContext - Optional error context
118
+ */
119
+ outputError(error, flags, additionalContext) {
120
+ // Wrap raw errors in NotionCLIError
121
+ const cliError = error instanceof index_1.NotionCLIError ? error : (0, index_1.wrapNotionError)(error);
122
+ // Check if we should use envelope
123
+ this.shouldUseEnvelope = this.checkEnvelopeUsage(flags);
124
+ if (this.shouldUseEnvelope) {
125
+ const envelope = this.envelope.wrapError(cliError, additionalContext);
126
+ this.envelope.outputEnvelope(envelope, flags, this.log.bind(this));
127
+ process.exit(this.envelope.getExitCode(envelope));
128
+ }
129
+ else {
130
+ // Non-JSON mode - use oclif's error handling
131
+ this.error(cliError.message, { exit: this.getExitCodeForError(cliError) });
132
+ }
133
+ }
134
+ /**
135
+ * Get appropriate exit code for error
136
+ */
137
+ getExitCodeForError(error) {
138
+ // CLI validation errors
139
+ if (error.code === 'VALIDATION_ERROR') {
140
+ return envelope_1.ExitCode.CLI_ERROR;
141
+ }
142
+ // API errors (default)
143
+ return envelope_1.ExitCode.API_ERROR;
144
+ }
145
+ /**
146
+ * Catch handler that ensures proper envelope error output
147
+ */
148
+ async catch(error) {
149
+ // If command has already handled the error via outputError, just propagate
150
+ if (error.exitCode !== undefined) {
151
+ throw error;
152
+ }
153
+ // Otherwise, wrap and handle the error
154
+ const cliError = (0, index_1.wrapNotionError)(error);
155
+ this.error(cliError.message, { exit: this.getExitCodeForError(cliError) });
156
+ }
157
+ }
158
+ exports.BaseCommand = BaseCommand;
159
+ /**
160
+ * Standard flags that all envelope-enabled commands should include
161
+ */
162
+ exports.EnvelopeFlags = {
163
+ json: core_1.Flags.boolean({
164
+ char: 'j',
165
+ description: 'Output as JSON envelope (recommended for automation)',
166
+ default: false,
167
+ }),
168
+ 'compact-json': core_1.Flags.boolean({
169
+ char: 'c',
170
+ description: 'Output as compact JSON envelope (single-line, ideal for piping)',
171
+ default: false,
172
+ exclusive: ['markdown', 'pretty'],
173
+ }),
174
+ raw: core_1.Flags.boolean({
175
+ char: 'r',
176
+ description: 'Output raw API response without envelope (legacy mode)',
177
+ default: false,
178
+ }),
179
+ };
@@ -0,0 +1,14 @@
1
+ export declare const AutomationFlags: {
2
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
3
+ 'page-size': import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
4
+ retry: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
5
+ timeout: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
6
+ 'no-cache': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
7
+ verbose: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
8
+ minimal: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
9
+ };
10
+ export declare const OutputFormatFlags: {
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
+ };
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OutputFormatFlags = exports.AutomationFlags = void 0;
4
+ const core_1 = require("@oclif/core");
5
+ exports.AutomationFlags = {
6
+ json: core_1.Flags.boolean({
7
+ char: 'j',
8
+ description: 'Output as JSON (recommended for automation)',
9
+ default: false,
10
+ }),
11
+ 'page-size': core_1.Flags.integer({
12
+ description: 'Items per page (1-100, default: 100 for automation)',
13
+ min: 1,
14
+ max: 100,
15
+ default: 100,
16
+ }),
17
+ retry: core_1.Flags.boolean({
18
+ description: 'Auto-retry on rate limit (respects Retry-After header)',
19
+ default: true,
20
+ }),
21
+ timeout: core_1.Flags.integer({
22
+ description: 'Request timeout in milliseconds',
23
+ default: 30000,
24
+ }),
25
+ 'no-cache': core_1.Flags.boolean({
26
+ description: 'Bypass cache and force fresh API calls',
27
+ default: false,
28
+ }),
29
+ verbose: core_1.Flags.boolean({
30
+ char: 'v',
31
+ description: 'Enable verbose logging to stderr (retry events, cache stats) - never pollutes stdout',
32
+ default: false,
33
+ env: 'NOTION_CLI_VERBOSE',
34
+ }),
35
+ minimal: core_1.Flags.boolean({
36
+ description: 'Strip unnecessary metadata (created_by, last_edited_by, object fields, request_id, etc.) - reduces response size by ~40%',
37
+ default: false,
38
+ }),
39
+ };
40
+ exports.OutputFormatFlags = {
41
+ markdown: core_1.Flags.boolean({
42
+ char: 'm',
43
+ description: 'Output as markdown table (GitHub-flavored)',
44
+ default: false,
45
+ exclusive: ['compact-json', 'pretty'],
46
+ }),
47
+ 'compact-json': core_1.Flags.boolean({
48
+ char: 'c',
49
+ description: 'Output as compact JSON (single-line, ideal for piping)',
50
+ default: false,
51
+ exclusive: ['markdown', 'pretty'],
52
+ }),
53
+ pretty: core_1.Flags.boolean({
54
+ char: 'P',
55
+ description: 'Output as pretty table with borders',
56
+ default: false,
57
+ exclusive: ['markdown', 'compact-json'],
58
+ }),
59
+ };
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Simple in-memory caching layer for Notion API responses
3
+ * Supports TTL (time-to-live) and cache invalidation
4
+ * Integrated with disk cache for persistence across CLI invocations
5
+ */
6
+ export interface CacheEntry<T> {
7
+ data: T;
8
+ timestamp: number;
9
+ ttl: number;
10
+ }
11
+ export interface CacheStats {
12
+ hits: number;
13
+ misses: number;
14
+ sets: number;
15
+ evictions: number;
16
+ size: number;
17
+ }
18
+ export interface CacheConfig {
19
+ enabled: boolean;
20
+ defaultTtl: number;
21
+ maxSize: number;
22
+ ttlByType: {
23
+ dataSource: number;
24
+ database: number;
25
+ user: number;
26
+ page: number;
27
+ block: number;
28
+ };
29
+ }
30
+ export declare class CacheManager {
31
+ private cache;
32
+ private stats;
33
+ private config;
34
+ constructor(config?: Partial<CacheConfig>);
35
+ /**
36
+ * Generate a cache key from resource type and identifiers
37
+ */
38
+ private generateKey;
39
+ /**
40
+ * Check if a cache entry is still valid
41
+ */
42
+ private isValid;
43
+ /**
44
+ * Evict expired entries
45
+ */
46
+ private evictExpired;
47
+ /**
48
+ * Evict oldest entries if cache is full
49
+ */
50
+ private evictOldest;
51
+ /**
52
+ * Get a value from cache (checks memory, then disk)
53
+ */
54
+ get<T>(type: string, ...identifiers: Array<string | number | object>): Promise<T | null>;
55
+ /**
56
+ * Set a value in cache with optional custom TTL (writes to memory and disk)
57
+ */
58
+ set<T>(type: string, data: T, customTtl?: number, ...identifiers: Array<string | number | object>): void;
59
+ /**
60
+ * Invalidate specific cache entries by type and optional identifiers
61
+ */
62
+ invalidate(type: string, ...identifiers: Array<string | number | object>): void;
63
+ /**
64
+ * Clear all cache entries (memory and disk)
65
+ */
66
+ clear(): void;
67
+ /**
68
+ * Get cache statistics
69
+ */
70
+ getStats(): CacheStats;
71
+ /**
72
+ * Get cache hit rate
73
+ */
74
+ getHitRate(): number;
75
+ /**
76
+ * Check if cache is enabled
77
+ */
78
+ isEnabled(): boolean;
79
+ /**
80
+ * Get current configuration
81
+ */
82
+ getConfig(): CacheConfig;
83
+ }
84
+ export declare const cacheManager: CacheManager;