@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,34 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class PageUpdate 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
+ archived: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
28
+ unarchive: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
29
+ properties: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
30
+ 'simple-properties': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
31
+ raw: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
32
+ };
33
+ run(): Promise<void>;
34
+ }
@@ -0,0 +1,184 @@
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 notion_resolver_1 = require("../../utils/notion-resolver");
8
+ const base_flags_1 = require("../../base-flags");
9
+ const errors_1 = require("../../errors");
10
+ const property_expander_1 = require("../../utils/property-expander");
11
+ class PageUpdate extends core_1.Command {
12
+ async run() {
13
+ const { args, flags } = await this.parse(PageUpdate);
14
+ try {
15
+ // Resolve ID from URL, direct ID, or name (future)
16
+ const pageId = await (0, notion_resolver_1.resolveNotionId)(args.page_id, 'page');
17
+ const pageProps = {
18
+ page_id: pageId,
19
+ };
20
+ // Handle archived flags
21
+ if (flags.archived) {
22
+ pageProps.archived = true;
23
+ }
24
+ if (flags.unarchive) {
25
+ pageProps.archived = false;
26
+ }
27
+ // Handle properties update
28
+ if (flags.properties) {
29
+ try {
30
+ const parsedProps = JSON.parse(flags.properties);
31
+ if (flags['simple-properties']) {
32
+ // User provided simple format - expand to Notion format
33
+ // Need to get the page first to find its parent database
34
+ const page = await notion.retrievePage({ page_id: pageId });
35
+ // Check if page is in a database
36
+ if (!('parent' in page) || !('data_source_id' in page.parent)) {
37
+ throw new Error('The --simple-properties flag can only be used with pages in a database. ' +
38
+ 'This page does not have a parent database.');
39
+ }
40
+ // Get the database schema
41
+ const parentDataSourceId = page.parent.data_source_id;
42
+ const dbSchema = await notion.retrieveDataSource(parentDataSourceId);
43
+ // Expand simple properties to Notion format
44
+ pageProps.properties = await (0, property_expander_1.expandSimpleProperties)(parsedProps, dbSchema.properties);
45
+ }
46
+ else {
47
+ // Use raw Notion format
48
+ pageProps.properties = parsedProps;
49
+ }
50
+ }
51
+ catch (error) {
52
+ if (error.message.includes('Unexpected token') || error.message.includes('JSON')) {
53
+ throw new Error(`Invalid JSON in --properties flag: ${error.message}\n` +
54
+ `Example: --properties '{"Status": "Done", "Priority": "High"}'`);
55
+ }
56
+ throw error;
57
+ }
58
+ }
59
+ const res = await notion.updatePageProps(pageProps);
60
+ // Handle JSON output for automation
61
+ if (flags.json) {
62
+ this.log(JSON.stringify({
63
+ success: true,
64
+ data: res,
65
+ timestamp: new Date().toISOString()
66
+ }, null, 2));
67
+ process.exit(0);
68
+ return;
69
+ }
70
+ // Handle raw JSON output (legacy)
71
+ if (flags.raw) {
72
+ (0, helper_1.outputRawJson)(res);
73
+ process.exit(0);
74
+ return;
75
+ }
76
+ // Handle table output
77
+ const columns = {
78
+ title: {
79
+ get: (row) => {
80
+ return (0, helper_1.getPageTitle)(row);
81
+ },
82
+ },
83
+ object: {},
84
+ id: {},
85
+ url: {},
86
+ };
87
+ const options = {
88
+ printLine: this.log.bind(this),
89
+ ...flags,
90
+ };
91
+ (0, table_formatter_1.formatTable)([res], columns, options);
92
+ process.exit(0);
93
+ }
94
+ catch (error) {
95
+ const cliError = error instanceof errors_1.NotionCLIError
96
+ ? error
97
+ : (0, errors_1.wrapNotionError)(error, {
98
+ resourceType: 'page',
99
+ attemptedId: args.page_id,
100
+ endpoint: 'pages.update'
101
+ });
102
+ if (flags.json) {
103
+ this.log(JSON.stringify(cliError.toJSON(), null, 2));
104
+ }
105
+ else {
106
+ this.error(cliError.toHumanString());
107
+ }
108
+ process.exit(1);
109
+ }
110
+ }
111
+ }
112
+ PageUpdate.description = 'Update a page';
113
+ PageUpdate.aliases = ['page:u'];
114
+ PageUpdate.examples = [
115
+ {
116
+ description: 'Update a page and output table',
117
+ command: `$ notion-cli page update PAGE_ID`,
118
+ },
119
+ {
120
+ description: 'Update a page via URL',
121
+ command: `$ notion-cli page update https://notion.so/PAGE_ID -a`,
122
+ },
123
+ {
124
+ description: 'Update page properties with simple format (recommended for AI agents)',
125
+ command: `$ notion-cli page update PAGE_ID -S --properties '{"Status": "Done", "Priority": "High"}'`,
126
+ },
127
+ {
128
+ description: 'Update page properties with relative date',
129
+ command: `$ notion-cli page update PAGE_ID -S --properties '{"Due Date": "tomorrow", "Status": "In Progress"}'`,
130
+ },
131
+ {
132
+ description: 'Update page with multi-select tags',
133
+ command: `$ notion-cli page update PAGE_ID -S --properties '{"Tags": ["urgent", "bug"], "Status": "Done"}'`,
134
+ },
135
+ {
136
+ description: 'Update a page and output raw json',
137
+ command: `$ notion-cli page update PAGE_ID -r`,
138
+ },
139
+ {
140
+ description: 'Update a page and archive',
141
+ command: `$ notion-cli page update PAGE_ID -a`,
142
+ },
143
+ {
144
+ description: 'Update a page and unarchive',
145
+ command: `$ notion-cli page update PAGE_ID -u`,
146
+ },
147
+ {
148
+ description: 'Update a page and archive and output raw json',
149
+ command: `$ notion-cli page update PAGE_ID -a -r`,
150
+ },
151
+ {
152
+ description: 'Update a page and unarchive and output raw json',
153
+ command: `$ notion-cli page update PAGE_ID -u -r`,
154
+ },
155
+ {
156
+ description: 'Update a page and output JSON for automation',
157
+ command: `$ notion-cli page update PAGE_ID -a --json`,
158
+ },
159
+ ];
160
+ PageUpdate.args = {
161
+ page_id: core_1.Args.string({
162
+ required: true,
163
+ description: 'Page ID or full Notion URL (e.g., https://notion.so/...)',
164
+ }),
165
+ };
166
+ PageUpdate.flags = {
167
+ archived: core_1.Flags.boolean({ char: 'a', description: 'Archive the page' }),
168
+ unarchive: core_1.Flags.boolean({ char: 'u', description: 'Unarchive the page' }),
169
+ properties: core_1.Flags.string({
170
+ description: 'Page properties to update as JSON string',
171
+ }),
172
+ 'simple-properties': core_1.Flags.boolean({
173
+ char: 'S',
174
+ description: 'Use simplified property format (flat key-value pairs, recommended for AI agents)',
175
+ default: false,
176
+ }),
177
+ raw: core_1.Flags.boolean({
178
+ char: 'r',
179
+ description: 'output raw json',
180
+ }),
181
+ ...table_formatter_1.tableFlags,
182
+ ...base_flags_1.AutomationFlags,
183
+ };
184
+ exports.default = PageUpdate;
@@ -0,0 +1,40 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class Search extends Command {
3
+ static description: string;
4
+ static examples: {
5
+ description: string;
6
+ command: string;
7
+ }[];
8
+ static flags: {
9
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
+ 'page-size': import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
11
+ retry: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
12
+ timeout: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
13
+ 'no-cache': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
14
+ verbose: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
15
+ minimal: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
16
+ markdown: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
17
+ 'compact-json': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
18
+ pretty: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
19
+ columns: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
20
+ sort: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
21
+ filter: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
22
+ csv: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
23
+ extended: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
24
+ 'no-truncate': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
25
+ 'no-header': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
26
+ query: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
27
+ sort_direction: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
28
+ property: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
29
+ start_cursor: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
30
+ page_size: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
31
+ database: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
32
+ 'created-after': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
33
+ 'created-before': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
34
+ 'edited-after': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
35
+ 'edited-before': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
36
+ limit: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
37
+ raw: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
38
+ };
39
+ run(): Promise<void>;
40
+ }
@@ -0,0 +1,348 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const notion = require("../notion");
5
+ const client_1 = require("@notionhq/client");
6
+ const helper_1 = require("../helper");
7
+ const base_flags_1 = require("../base-flags");
8
+ const errors_1 = require("../errors");
9
+ const dayjs = require("dayjs");
10
+ const table_formatter_1 = require("../utils/table-formatter");
11
+ class Search extends core_1.Command {
12
+ async run() {
13
+ const { flags } = await this.parse(Search);
14
+ try {
15
+ // Validate date filters
16
+ if (flags['created-after'] && !dayjs(flags['created-after']).isValid()) {
17
+ throw new errors_1.NotionCLIError(errors_1.NotionCLIErrorCode.VALIDATION_ERROR, `Invalid date format for --created-after: ${flags['created-after']}. Use ISO 8601 format (YYYY-MM-DD).`, [], { userInput: flags['created-after'] });
18
+ }
19
+ if (flags['created-before'] && !dayjs(flags['created-before']).isValid()) {
20
+ throw new errors_1.NotionCLIError(errors_1.NotionCLIErrorCode.VALIDATION_ERROR, `Invalid date format for --created-before: ${flags['created-before']}. Use ISO 8601 format (YYYY-MM-DD).`, [], { userInput: flags['created-before'] });
21
+ }
22
+ if (flags['edited-after'] && !dayjs(flags['edited-after']).isValid()) {
23
+ throw new errors_1.NotionCLIError(errors_1.NotionCLIErrorCode.VALIDATION_ERROR, `Invalid date format for --edited-after: ${flags['edited-after']}. Use ISO 8601 format (YYYY-MM-DD).`, [], { userInput: flags['edited-after'] });
24
+ }
25
+ if (flags['edited-before'] && !dayjs(flags['edited-before']).isValid()) {
26
+ throw new errors_1.NotionCLIError(errors_1.NotionCLIErrorCode.VALIDATION_ERROR, `Invalid date format for --edited-before: ${flags['edited-before']}. Use ISO 8601 format (YYYY-MM-DD).`, [], { userInput: flags['edited-before'] });
27
+ }
28
+ const params = {};
29
+ if (flags.query) {
30
+ params.query = flags.query;
31
+ }
32
+ if (flags.sort_direction) {
33
+ let direction;
34
+ if (flags.sort_direction == 'asc') {
35
+ direction = 'ascending';
36
+ }
37
+ else {
38
+ direction = 'descending';
39
+ }
40
+ params.sort = {
41
+ direction: direction,
42
+ timestamp: 'last_edited_time',
43
+ };
44
+ }
45
+ if (flags.property == 'data_source' || flags.property == 'page') {
46
+ params.filter = {
47
+ value: flags.property,
48
+ property: 'object',
49
+ };
50
+ }
51
+ if (flags.start_cursor) {
52
+ params.start_cursor = flags.start_cursor;
53
+ }
54
+ // Increase page_size if we need to apply client-side filters
55
+ // This ensures we get enough results before filtering
56
+ const hasClientSideFilters = flags.database || flags['created-after'] ||
57
+ flags['created-before'] || flags['edited-after'] || flags['edited-before'];
58
+ if (hasClientSideFilters) {
59
+ // Use 100 (max) to get more results for filtering
60
+ params.page_size = 100;
61
+ }
62
+ else if (flags.page_size) {
63
+ params.page_size = flags.page_size;
64
+ }
65
+ if (process.env.DEBUG) {
66
+ console.log(params);
67
+ }
68
+ let res = await notion.search(params);
69
+ // Apply minimal flag to strip metadata
70
+ if (flags.minimal) {
71
+ res = (0, helper_1.stripMetadata)(res);
72
+ }
73
+ // Apply client-side filters (Notion API doesn't support these natively in search)
74
+ let filteredResults = res.results;
75
+ // Filter by database (parent)
76
+ if (flags.database) {
77
+ filteredResults = filteredResults.filter((result) => {
78
+ if ((0, client_1.isFullPage)(result) && result.parent) {
79
+ if ('database_id' in result.parent) {
80
+ return result.parent.database_id === flags.database;
81
+ }
82
+ }
83
+ return false;
84
+ });
85
+ }
86
+ // Filter by created date
87
+ if (flags['created-after']) {
88
+ const afterDate = dayjs(flags['created-after']);
89
+ filteredResults = filteredResults.filter((result) => {
90
+ if ('created_time' in result) {
91
+ return dayjs(result.created_time).isAfter(afterDate) ||
92
+ dayjs(result.created_time).isSame(afterDate, 'day');
93
+ }
94
+ return false;
95
+ });
96
+ }
97
+ if (flags['created-before']) {
98
+ const beforeDate = dayjs(flags['created-before']);
99
+ filteredResults = filteredResults.filter((result) => {
100
+ if ('created_time' in result) {
101
+ return dayjs(result.created_time).isBefore(beforeDate) ||
102
+ dayjs(result.created_time).isSame(beforeDate, 'day');
103
+ }
104
+ return false;
105
+ });
106
+ }
107
+ // Filter by edited date
108
+ if (flags['edited-after']) {
109
+ const afterDate = dayjs(flags['edited-after']);
110
+ filteredResults = filteredResults.filter((result) => {
111
+ if ('last_edited_time' in result) {
112
+ return dayjs(result.last_edited_time).isAfter(afterDate) ||
113
+ dayjs(result.last_edited_time).isSame(afterDate, 'day');
114
+ }
115
+ return false;
116
+ });
117
+ }
118
+ if (flags['edited-before']) {
119
+ const beforeDate = dayjs(flags['edited-before']);
120
+ filteredResults = filteredResults.filter((result) => {
121
+ if ('last_edited_time' in result) {
122
+ return dayjs(result.last_edited_time).isBefore(beforeDate) ||
123
+ dayjs(result.last_edited_time).isSame(beforeDate, 'day');
124
+ }
125
+ return false;
126
+ });
127
+ }
128
+ // Apply limit after all filters
129
+ if (flags.limit) {
130
+ filteredResults = filteredResults.slice(0, flags.limit);
131
+ }
132
+ // Update res.results with filtered results
133
+ res.results = filteredResults;
134
+ // Handle JSON output for automation (takes precedence)
135
+ if (flags.json) {
136
+ this.log(JSON.stringify({
137
+ success: true,
138
+ data: res,
139
+ timestamp: new Date().toISOString()
140
+ }, null, 2));
141
+ process.exit(0);
142
+ return;
143
+ }
144
+ // Define columns for table output
145
+ const columns = {
146
+ title: {
147
+ get: (row) => {
148
+ if (row.object == 'database' && (0, client_1.isFullDatabase)(row)) {
149
+ return (0, helper_1.getDbTitle)(row);
150
+ }
151
+ if (row.object == 'data_source' && (0, client_1.isFullDataSource)(row)) {
152
+ return (0, helper_1.getDataSourceTitle)(row);
153
+ }
154
+ if (row.object == 'page' && (0, client_1.isFullPage)(row)) {
155
+ return (0, helper_1.getPageTitle)(row);
156
+ }
157
+ return 'Untitled';
158
+ },
159
+ },
160
+ object: {},
161
+ id: {},
162
+ url: {},
163
+ };
164
+ // Handle compact JSON output
165
+ if (flags['compact-json']) {
166
+ (0, helper_1.outputCompactJson)(res.results);
167
+ process.exit(0);
168
+ return;
169
+ }
170
+ // Handle markdown table output
171
+ if (flags.markdown) {
172
+ (0, helper_1.outputMarkdownTable)(res.results, columns);
173
+ process.exit(0);
174
+ return;
175
+ }
176
+ // Handle pretty table output
177
+ if (flags.pretty) {
178
+ (0, helper_1.outputPrettyTable)(res.results, columns);
179
+ // Show hint after table output (use first result as sample)
180
+ if (res.results.length > 0) {
181
+ (0, helper_1.showRawFlagHint)(res.results.length, res.results[0]);
182
+ }
183
+ process.exit(0);
184
+ return;
185
+ }
186
+ // Handle raw JSON output
187
+ if (flags.raw) {
188
+ (0, helper_1.outputRawJson)(res);
189
+ process.exit(0);
190
+ return;
191
+ }
192
+ // Handle table output (default)
193
+ const options = {
194
+ printLine: this.log.bind(this),
195
+ ...flags,
196
+ };
197
+ (0, table_formatter_1.formatTable)(res.results, columns, options);
198
+ // Show hint after table output to make -r flag discoverable
199
+ // Use first result as sample to count fields
200
+ if (res.results.length > 0) {
201
+ (0, helper_1.showRawFlagHint)(res.results.length, res.results[0]);
202
+ }
203
+ }
204
+ catch (error) {
205
+ const cliError = error instanceof errors_1.NotionCLIError
206
+ ? error
207
+ : (0, errors_1.wrapNotionError)(error, {
208
+ endpoint: 'search',
209
+ userInput: flags.query || flags.filter
210
+ });
211
+ if (flags.json) {
212
+ this.log(JSON.stringify(cliError.toJSON(), null, 2));
213
+ }
214
+ else {
215
+ this.error(cliError.toHumanString());
216
+ }
217
+ process.exit(1);
218
+ }
219
+ }
220
+ }
221
+ Search.description = 'Search by title';
222
+ Search.examples = [
223
+ {
224
+ description: 'Search with full data (recommended for AI assistants)',
225
+ command: `$ notion-cli search -q 'My Page' -r`,
226
+ },
227
+ {
228
+ description: 'Search by title',
229
+ command: `$ notion-cli search -q 'My Page'`,
230
+ },
231
+ {
232
+ description: 'Search only within a specific database',
233
+ command: `$ notion-cli search -q 'meeting' --database DB_ID`,
234
+ },
235
+ {
236
+ description: 'Search with created date filter',
237
+ command: `$ notion-cli search -q 'report' --created-after 2025-10-01`,
238
+ },
239
+ {
240
+ description: 'Search with edited date filter',
241
+ command: `$ notion-cli search -q 'project' --edited-after 2025-10-20`,
242
+ },
243
+ {
244
+ description: 'Limit number of results',
245
+ command: `$ notion-cli search -q 'task' --limit 20`,
246
+ },
247
+ {
248
+ description: 'Combined filters',
249
+ command: `$ notion-cli search -q 'project' -d DB_ID --edited-after 2025-10-20 --limit 10`,
250
+ },
251
+ {
252
+ description: 'Search by title and output csv',
253
+ command: `$ notion-cli search -q 'My Page' --csv`,
254
+ },
255
+ {
256
+ description: 'Search by title and output raw json',
257
+ command: `$ notion-cli search -q 'My Page' -r`,
258
+ },
259
+ {
260
+ description: 'Search by title and output markdown table',
261
+ command: `$ notion-cli search -q 'My Page' --markdown`,
262
+ },
263
+ {
264
+ description: 'Search by title and output compact JSON',
265
+ command: `$ notion-cli search -q 'My Page' --compact-json`,
266
+ },
267
+ {
268
+ description: 'Search by title and output pretty table',
269
+ command: `$ notion-cli search -q 'My Page' --pretty`,
270
+ },
271
+ {
272
+ description: 'Search by title and output table with specific columns',
273
+ command: `$ notion-cli search -q 'My Page' --columns=title,object`,
274
+ },
275
+ {
276
+ description: 'Search by title and output table with specific columns and sort direction',
277
+ command: `$ notion-cli search -q 'My Page' --columns=title,object -d asc`,
278
+ },
279
+ {
280
+ description: 'Search by title and output table with specific columns and sort direction and page size',
281
+ command: `$ notion-cli search -q 'My Page' -columns=title,object -d asc -s 10`,
282
+ },
283
+ {
284
+ description: 'Search by title and output table with specific columns and sort direction and page size and start cursor',
285
+ command: `$ notion-cli search -q 'My Page' --columns=title,object -d asc -s 10 -c START_CURSOR_ID`,
286
+ },
287
+ {
288
+ description: 'Search by title and output table with specific columns and sort direction and page size and start cursor and property',
289
+ command: `$ notion-cli search -q 'My Page' --columns=title,object -d asc -s 10 -c START_CURSOR_ID -p page`,
290
+ },
291
+ {
292
+ description: 'Search and output JSON for automation',
293
+ command: `$ notion-cli search -q 'My Page' --json`,
294
+ },
295
+ ];
296
+ Search.flags = {
297
+ query: core_1.Flags.string({
298
+ char: 'q',
299
+ description: 'The text that the API compares page and database titles against',
300
+ }),
301
+ sort_direction: core_1.Flags.string({
302
+ char: 'd',
303
+ options: ['asc', 'desc'],
304
+ description: 'The direction to sort results. The only supported timestamp value is "last_edited_time"',
305
+ default: 'desc',
306
+ }),
307
+ property: core_1.Flags.string({
308
+ char: 'p',
309
+ options: ['data_source', 'page'],
310
+ }),
311
+ start_cursor: core_1.Flags.string({
312
+ char: 'c',
313
+ }),
314
+ page_size: core_1.Flags.integer({
315
+ char: 's',
316
+ description: 'The number of results to return. The default is 5, with a minimum of 1 and a maximum of 100.',
317
+ min: 1,
318
+ max: 100,
319
+ default: 5,
320
+ }),
321
+ database: core_1.Flags.string({
322
+ description: 'Limit search to pages within a specific database (data source ID)',
323
+ }),
324
+ 'created-after': core_1.Flags.string({
325
+ description: 'Filter results created after this date (ISO 8601 format: YYYY-MM-DD)',
326
+ }),
327
+ 'created-before': core_1.Flags.string({
328
+ description: 'Filter results created before this date (ISO 8601 format: YYYY-MM-DD)',
329
+ }),
330
+ 'edited-after': core_1.Flags.string({
331
+ description: 'Filter results edited after this date (ISO 8601 format: YYYY-MM-DD)',
332
+ }),
333
+ 'edited-before': core_1.Flags.string({
334
+ description: 'Filter results edited before this date (ISO 8601 format: YYYY-MM-DD)',
335
+ }),
336
+ limit: core_1.Flags.integer({
337
+ description: 'Maximum number of results to return (applied after filters)',
338
+ min: 1,
339
+ }),
340
+ raw: core_1.Flags.boolean({
341
+ char: 'r',
342
+ description: 'output raw json (recommended for AI assistants - returns all search results)',
343
+ }),
344
+ ...table_formatter_1.tableFlags,
345
+ ...base_flags_1.OutputFormatFlags,
346
+ ...base_flags_1.AutomationFlags,
347
+ };
348
+ exports.default = Search;
@@ -0,0 +1,24 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class Sync extends Command {
3
+ static description: string;
4
+ static aliases: string[];
5
+ static examples: {
6
+ description: string;
7
+ command: string;
8
+ }[];
9
+ static flags: {
10
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
11
+ 'page-size': import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
12
+ retry: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
13
+ timeout: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
14
+ 'no-cache': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
15
+ verbose: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
16
+ minimal: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
17
+ force: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
18
+ };
19
+ run(): Promise<void>;
20
+ /**
21
+ * Fetch all databases from Notion API with pagination
22
+ */
23
+ private fetchAllDatabases;
24
+ }