@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,201 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const fs = require("fs/promises");
5
+ const path = require("path");
6
+ const os = require("os");
7
+ const readline = require("readline");
8
+ const base_flags_1 = require("../../base-flags");
9
+ const errors_1 = require("../../errors");
10
+ const token_validator_1 = require("../../utils/token-validator");
11
+ class ConfigSetToken extends core_1.Command {
12
+ async run() {
13
+ const { args, flags } = await this.parse(ConfigSetToken);
14
+ try {
15
+ // Get token from args or prompt
16
+ let token = args.token;
17
+ if (!token) {
18
+ if (flags.json) {
19
+ throw new errors_1.NotionCLIError(errors_1.NotionCLIErrorCode.TOKEN_MISSING, "Token required in JSON mode", [
20
+ {
21
+ description: "Provide the token as an argument",
22
+ command: "notion-cli config set-token ntn_your_token_here --json",
23
+ },
24
+ ]);
25
+ }
26
+ // Interactive prompt
27
+ const rl = readline.createInterface({
28
+ input: process.stdin,
29
+ output: process.stdout,
30
+ });
31
+ token = await new Promise((resolve) => {
32
+ rl.question("Enter your Notion integration token: ", (answer) => {
33
+ rl.close();
34
+ resolve(answer.trim());
35
+ });
36
+ });
37
+ }
38
+ // Validate token format (accepts secret_ and ntn_ prefixes)
39
+ if (!token || !(0, token_validator_1.hasValidTokenPrefix)(token)) {
40
+ throw new errors_1.NotionCLIError(errors_1.NotionCLIErrorCode.TOKEN_INVALID, 'Invalid token format - Notion tokens must start with "secret_" or "ntn_"', [
41
+ {
42
+ description: "Get your integration token from Notion",
43
+ link: "https://developers.notion.com/docs/create-a-notion-integration",
44
+ },
45
+ {
46
+ description: "Tokens should look like: ntn_abc123... or secret_abc123...",
47
+ },
48
+ ], {
49
+ userInput: token,
50
+ metadata: { tokenFormat: "invalid" },
51
+ });
52
+ }
53
+ // Detect shell and rc file
54
+ const shell = this.detectShell();
55
+ const rcFile = this.getRcFilePath(shell);
56
+ // Read existing rc file
57
+ let rcContent = "";
58
+ try {
59
+ rcContent = await fs.readFile(rcFile, "utf-8");
60
+ }
61
+ catch (error) {
62
+ if (error &&
63
+ typeof error === "object" &&
64
+ "code" in error &&
65
+ error.code !== "ENOENT") {
66
+ throw error;
67
+ }
68
+ // File doesn't exist, will create it
69
+ }
70
+ // Check if NOTION_TOKEN already exists
71
+ const tokenLineRegex = /^export\s+NOTION_TOKEN=.*/gm;
72
+ const newTokenLine = `export NOTION_TOKEN="${token}"`;
73
+ let updatedContent;
74
+ if (tokenLineRegex.test(rcContent)) {
75
+ // Replace existing token
76
+ updatedContent = rcContent.replace(tokenLineRegex, newTokenLine);
77
+ }
78
+ else {
79
+ // Add new token
80
+ updatedContent =
81
+ rcContent.trim() + "\n\n# Notion CLI Token\n" + newTokenLine + "\n";
82
+ }
83
+ // Write updated rc file
84
+ await fs.writeFile(rcFile, updatedContent, "utf-8");
85
+ if (flags.json) {
86
+ this.log(JSON.stringify({
87
+ success: true,
88
+ message: "Token saved successfully",
89
+ rcFile,
90
+ shell,
91
+ nextSteps: [
92
+ `Reload your shell: source ${rcFile}`,
93
+ "Run: notion-cli sync",
94
+ ],
95
+ }, null, 2));
96
+ }
97
+ else {
98
+ this.log(`\n✓ Token saved to ${rcFile}`);
99
+ this.log("\nNext steps:");
100
+ this.log(` 1. Reload your shell: source ${rcFile}`);
101
+ this.log(` 2. Or restart your terminal`);
102
+ this.log(` 3. Run: notion-cli sync`);
103
+ this.log("\nWould you like to sync your workspace now? (y/n)");
104
+ const rl = readline.createInterface({
105
+ input: process.stdin,
106
+ output: process.stdout,
107
+ });
108
+ const answer = await new Promise((resolve) => {
109
+ rl.question("> ", (answer) => {
110
+ rl.close();
111
+ resolve(answer.trim().toLowerCase());
112
+ });
113
+ });
114
+ if (answer === "y" || answer === "yes") {
115
+ // Set token in current process
116
+ process.env.NOTION_TOKEN = token;
117
+ // Run sync command - dynamic import to avoid circular dependencies
118
+ this.log("\nRunning sync...\n");
119
+ const { default: Sync } = await Promise.resolve().then(() => require("../sync.js"));
120
+ await Sync.run([]);
121
+ }
122
+ else {
123
+ this.log("\nSkipping sync. You can run it manually with: notion-cli sync");
124
+ }
125
+ }
126
+ process.exit(0);
127
+ }
128
+ catch (error) {
129
+ const cliError = error instanceof errors_1.NotionCLIError
130
+ ? error
131
+ : (0, errors_1.wrapNotionError)(error instanceof Error ? error : new Error(String(error)), {
132
+ endpoint: "config.set-token",
133
+ });
134
+ if (flags.json) {
135
+ this.log(JSON.stringify(cliError.toJSON(), null, 2));
136
+ }
137
+ else {
138
+ this.error(cliError.toHumanString());
139
+ }
140
+ process.exit(1);
141
+ }
142
+ }
143
+ /**
144
+ * Detect the current shell
145
+ */
146
+ detectShell() {
147
+ const shell = process.env.SHELL || "";
148
+ if (shell.includes("zsh"))
149
+ return "zsh";
150
+ if (shell.includes("bash"))
151
+ return "bash";
152
+ if (shell.includes("fish"))
153
+ return "fish";
154
+ // Default to bash on Unix, powershell on Windows
155
+ return process.platform === "win32" ? "powershell" : "bash";
156
+ }
157
+ /**
158
+ * Get the rc file path for the detected shell
159
+ */
160
+ getRcFilePath(shell) {
161
+ const home = os.homedir();
162
+ switch (shell) {
163
+ case "zsh":
164
+ return path.join(home, ".zshrc");
165
+ case "bash":
166
+ return path.join(home, ".bashrc");
167
+ case "fish":
168
+ return path.join(home, ".config", "fish", "config.fish");
169
+ case "powershell":
170
+ return path.join(home, "Documents", "PowerShell", "Microsoft.PowerShell_profile.ps1");
171
+ default:
172
+ return path.join(home, ".bashrc");
173
+ }
174
+ }
175
+ }
176
+ ConfigSetToken.description = "Set NOTION_TOKEN in your shell configuration file";
177
+ ConfigSetToken.aliases = ["config:token"];
178
+ ConfigSetToken.examples = [
179
+ {
180
+ description: "Set Notion token interactively",
181
+ command: "notion-cli config set-token",
182
+ },
183
+ {
184
+ description: "Set Notion token directly",
185
+ command: "notion-cli config set-token ntn_abc123...",
186
+ },
187
+ {
188
+ description: "Set token with JSON output",
189
+ command: "notion-cli config set-token ntn_abc123... --json",
190
+ },
191
+ ];
192
+ ConfigSetToken.args = {
193
+ token: core_1.Args.string({
194
+ description: 'Notion integration token (starts with "secret_" or "ntn_")',
195
+ required: false,
196
+ }),
197
+ };
198
+ ConfigSetToken.flags = {
199
+ ...base_flags_1.AutomationFlags,
200
+ };
201
+ exports.default = ConfigSetToken;
@@ -0,0 +1,31 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class DbCreate extends Command {
3
+ static description: string;
4
+ static aliases: string[];
5
+ static examples: {
6
+ description: string;
7
+ command: string;
8
+ }[];
9
+ static args: {
10
+ page_id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
11
+ };
12
+ static flags: {
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
+ title: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
28
+ raw: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
29
+ };
30
+ run(): Promise<void>;
31
+ }
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const table_formatter_1 = require("../../utils/table-formatter");
5
+ const notion = require("../../notion");
6
+ const helper_1 = require("../../helper");
7
+ const base_flags_1 = require("../../base-flags");
8
+ const errors_1 = require("../../errors");
9
+ const notion_resolver_1 = require("../../utils/notion-resolver");
10
+ class DbCreate extends core_1.Command {
11
+ async run() {
12
+ const { args, flags } = await this.parse(DbCreate);
13
+ try {
14
+ // Resolve ID from URL, direct ID, or name (future)
15
+ const pageId = await (0, notion_resolver_1.resolveNotionId)(args.page_id, 'page');
16
+ console.log(`Creating a database in page ${pageId}`);
17
+ const dbTitle = flags.title;
18
+ // TODO: support other properties
19
+ const dbProps = {
20
+ parent: {
21
+ type: 'page_id',
22
+ page_id: pageId,
23
+ },
24
+ title: [
25
+ {
26
+ type: 'text',
27
+ text: {
28
+ content: dbTitle,
29
+ },
30
+ },
31
+ ],
32
+ initial_data_source: {
33
+ properties: {
34
+ Name: {
35
+ title: {},
36
+ },
37
+ },
38
+ },
39
+ };
40
+ const res = await notion.createDb(dbProps);
41
+ // Handle JSON output for automation
42
+ if (flags.json) {
43
+ this.log(JSON.stringify({
44
+ success: true,
45
+ data: res,
46
+ timestamp: new Date().toISOString()
47
+ }, null, 2));
48
+ process.exit(0);
49
+ return;
50
+ }
51
+ // Handle raw JSON output (legacy)
52
+ if (flags.raw) {
53
+ (0, helper_1.outputRawJson)(res);
54
+ process.exit(0);
55
+ return;
56
+ }
57
+ // Handle table output
58
+ const columns = {
59
+ title: {
60
+ get: (row) => {
61
+ return (0, helper_1.getDbTitle)(row);
62
+ },
63
+ },
64
+ object: {},
65
+ id: {},
66
+ url: {},
67
+ };
68
+ const options = {
69
+ printLine: this.log.bind(this),
70
+ ...flags,
71
+ };
72
+ (0, table_formatter_1.formatTable)([res], columns, options);
73
+ process.exit(0);
74
+ }
75
+ catch (error) {
76
+ const cliError = error instanceof errors_1.NotionCLIError
77
+ ? error
78
+ : (0, errors_1.wrapNotionError)(error, {
79
+ resourceType: 'database',
80
+ endpoint: 'databases.create'
81
+ });
82
+ if (flags.json) {
83
+ this.log(JSON.stringify(cliError.toJSON(), null, 2));
84
+ }
85
+ else {
86
+ this.error(cliError.toHumanString());
87
+ }
88
+ process.exit(1);
89
+ }
90
+ }
91
+ }
92
+ DbCreate.description = 'Create a database with an initial data source (table)';
93
+ DbCreate.aliases = ['db:c'];
94
+ DbCreate.examples = [
95
+ {
96
+ description: 'Create a database with an initial data source',
97
+ command: `$ notion-cli db create PAGE_ID -t 'My Database'`,
98
+ },
99
+ {
100
+ description: 'Create a database using page URL',
101
+ command: `$ notion-cli db create https://notion.so/PAGE_ID -t 'My Database'`,
102
+ },
103
+ {
104
+ description: 'Create a database with an initial data source and output raw json',
105
+ command: `$ notion-cli db create PAGE_ID -t 'My Database' -r`,
106
+ },
107
+ ];
108
+ DbCreate.args = {
109
+ page_id: core_1.Args.string({ required: true, description: 'Parent page ID or URL where the database will be created' }),
110
+ };
111
+ DbCreate.flags = {
112
+ title: core_1.Flags.string({
113
+ char: 't',
114
+ description: 'Title for the database (and initial data source)',
115
+ required: true,
116
+ }),
117
+ raw: core_1.Flags.boolean({
118
+ char: 'r',
119
+ description: 'output raw json',
120
+ }),
121
+ ...table_formatter_1.tableFlags,
122
+ ...base_flags_1.AutomationFlags,
123
+ };
124
+ exports.default = DbCreate;
@@ -0,0 +1,41 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class DbQuery extends Command {
3
+ static description: string;
4
+ static aliases: string[];
5
+ static examples: {
6
+ description: string;
7
+ command: string;
8
+ }[];
9
+ static args: {
10
+ database_id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
11
+ };
12
+ static flags: {
13
+ filter: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
14
+ 'file-filter': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
15
+ search: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
16
+ select: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
17
+ rawFilter: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
18
+ fileFilter: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
19
+ markdown: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
20
+ 'compact-json': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
21
+ pretty: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
22
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
23
+ 'page-size': import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
24
+ retry: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
25
+ timeout: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
26
+ 'no-cache': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
27
+ verbose: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
28
+ minimal: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
29
+ columns: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
30
+ sort: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
31
+ csv: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
32
+ extended: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
33
+ 'no-truncate': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
34
+ 'no-header': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
35
+ 'page-all': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
36
+ 'sort-property': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
37
+ 'sort-direction': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
38
+ raw: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
39
+ };
40
+ run(): Promise<void>;
41
+ }