@andrzejchm/notion-cli 0.8.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -4,7 +4,7 @@
4
4
  import { readFileSync } from "fs";
5
5
  import { dirname, join as join3 } from "path";
6
6
  import { fileURLToPath } from "url";
7
- import { Command as Command23 } from "commander";
7
+ import { Command as Command24 } from "commander";
8
8
 
9
9
  // src/commands/append.ts
10
10
  import { Command } from "commander";
@@ -543,23 +543,25 @@ function reportTokenSource(source) {
543
543
  }
544
544
 
545
545
  // src/services/write.service.ts
546
- async function addComment(client, pageId, text, options = {}) {
547
- await client.comments.create({
548
- parent: { page_id: pageId },
549
- rich_text: [
550
- {
551
- type: "text",
552
- text: { content: text, link: null },
553
- annotations: {
554
- bold: false,
555
- italic: false,
556
- strikethrough: false,
557
- underline: false,
558
- code: false,
559
- color: "default"
560
- }
546
+ async function addComment(client, target, text, options = {}) {
547
+ const richText = [
548
+ {
549
+ type: "text",
550
+ text: { content: text, link: null },
551
+ annotations: {
552
+ bold: false,
553
+ italic: false,
554
+ strikethrough: false,
555
+ underline: false,
556
+ code: false,
557
+ color: "default"
561
558
  }
562
- ],
559
+ }
560
+ ];
561
+ const targetPayload = target.type === "reply" ? { discussion_id: target.discussionId } : target.type === "block" ? { parent: { block_id: target.blockId } } : { parent: { page_id: target.pageId } };
562
+ await client.comments.create({
563
+ ...targetPayload,
564
+ rich_text: richText,
563
565
  ...options.asUser && { display_name: { type: "user" } }
564
566
  });
565
567
  }
@@ -1316,20 +1318,50 @@ function statusCommand() {
1316
1318
 
1317
1319
  // src/commands/comment-add.ts
1318
1320
  import { Command as Command6 } from "commander";
1321
+ function resolveTarget(idOrUrl, opts) {
1322
+ const targetCount = [idOrUrl, opts.replyTo, opts.block].filter(
1323
+ Boolean
1324
+ ).length;
1325
+ if (targetCount > 1) {
1326
+ throw new CliError(
1327
+ ErrorCodes.INVALID_ARG,
1328
+ "Provide only one target: a page ID/URL, --reply-to, or --block.",
1329
+ "These options are mutually exclusive"
1330
+ );
1331
+ }
1332
+ if (opts.replyTo) {
1333
+ return { type: "reply", discussionId: opts.replyTo };
1334
+ }
1335
+ if (opts.block) {
1336
+ return { type: "block", blockId: opts.block };
1337
+ }
1338
+ if (idOrUrl) {
1339
+ const id = parseNotionId(idOrUrl);
1340
+ return { type: "page", pageId: toUuid(id) };
1341
+ }
1342
+ throw new CliError(
1343
+ ErrorCodes.INVALID_ARG,
1344
+ "Provide a page ID/URL, --reply-to <discussion-id>, or --block <block-id>."
1345
+ );
1346
+ }
1319
1347
  function commentAddCommand() {
1320
1348
  const cmd = new Command6("comment");
1321
- cmd.description("add a comment to a Notion page").argument("<id/url>", "Notion page ID or URL").requiredOption("-m, --message <text>", "comment text to post").action(
1322
- withErrorHandling(async (idOrUrl, opts) => {
1323
- const { token, source } = await resolveToken();
1324
- reportTokenSource(source);
1325
- const client = createNotionClient(token);
1326
- const id = parseNotionId(idOrUrl);
1327
- const uuid = toUuid(id);
1328
- await addComment(client, uuid, opts.message, {
1329
- asUser: source === "oauth"
1330
- });
1331
- process.stdout.write("Comment added.\n");
1332
- })
1349
+ cmd.description("add a comment to a Notion page, block, or discussion thread").argument("[id/url]", "Notion page ID or URL").requiredOption("-m, --message <text>", "comment text to post").option(
1350
+ "--reply-to <discussion-id>",
1351
+ "reply to an existing discussion thread"
1352
+ ).option("--block <block-id>", "comment on a specific block").action(
1353
+ withErrorHandling(
1354
+ async (idOrUrl, opts) => {
1355
+ const target = resolveTarget(idOrUrl, opts);
1356
+ const { token, source } = await resolveToken();
1357
+ reportTokenSource(source);
1358
+ const client = createNotionClient(token);
1359
+ await addComment(client, target, opts.message, {
1360
+ asUser: source === "oauth"
1361
+ });
1362
+ process.stdout.write("Comment added.\n");
1363
+ }
1364
+ )
1333
1365
  );
1334
1366
  return cmd;
1335
1367
  }
@@ -1352,6 +1384,14 @@ async function paginateResults(fetcher) {
1352
1384
  }
1353
1385
 
1354
1386
  // src/commands/comments.ts
1387
+ function formatParent(parent) {
1388
+ switch (parent.type) {
1389
+ case "page_id":
1390
+ return "page";
1391
+ case "block_id":
1392
+ return `block:${parent.block_id.slice(0, 8)}`;
1393
+ }
1394
+ }
1355
1395
  function commentsCommand() {
1356
1396
  const cmd = new Command7("comments");
1357
1397
  cmd.description("list comments on a Notion page").argument("<id/url>", "Notion page ID or URL").option("--json", "output as JSON").action(
@@ -1374,10 +1414,16 @@ function commentsCommand() {
1374
1414
  return [
1375
1415
  comment.created_time.split("T")[0],
1376
1416
  `${comment.created_by.id.slice(0, 8)}...`,
1417
+ comment.discussion_id.slice(0, 8),
1418
+ formatParent(comment.parent),
1377
1419
  text.slice(0, 80) + (text.length > 80 ? "\u2026" : "")
1378
1420
  ];
1379
1421
  });
1380
- printOutput(comments, ["DATE", "AUTHOR ID", "COMMENT"], rows);
1422
+ printOutput(
1423
+ comments,
1424
+ ["DATE", "AUTHOR ID", "DISCUSSION", "PARENT", "COMMENT"],
1425
+ rows
1426
+ );
1381
1427
  })
1382
1428
  );
1383
1429
  return cmd;
@@ -1638,6 +1684,126 @@ function displayDate(date) {
1638
1684
  if (!date) return "";
1639
1685
  return date.end ? `${date.start} \u2192 ${date.end}` : date.start;
1640
1686
  }
1687
+ var SIMPLE_PROPERTY_TYPES = /* @__PURE__ */ new Set([
1688
+ "title",
1689
+ "rich_text",
1690
+ "number",
1691
+ "date",
1692
+ "checkbox",
1693
+ "url",
1694
+ "email",
1695
+ "phone_number",
1696
+ "people",
1697
+ "files",
1698
+ "created_time",
1699
+ "last_edited_time"
1700
+ ]);
1701
+ var OPTIONS_PROPERTY_TYPES = /* @__PURE__ */ new Set(["select", "multi_select", "status"]);
1702
+ var UNSUPPORTED_PROPERTY_TYPES = {
1703
+ relation: "requires a data_source_id reference",
1704
+ rollup: "requires relation and property references",
1705
+ formula: "requires an expression string",
1706
+ unique_id: "auto-managed by Notion"
1707
+ };
1708
+ function parsePropertyDefinition(defString) {
1709
+ if (!defString) {
1710
+ throw new CliError(
1711
+ ErrorCodes.INVALID_ARG,
1712
+ "Property definition cannot be empty",
1713
+ 'Use format: --prop "Name:type" or --prop "Name:type:opt1,opt2"'
1714
+ );
1715
+ }
1716
+ const firstColon = defString.indexOf(":");
1717
+ if (firstColon === -1) {
1718
+ throw new CliError(
1719
+ ErrorCodes.INVALID_ARG,
1720
+ `Invalid property definition: "${defString}"`,
1721
+ 'Use format: --prop "Name:type" or --prop "Name:type:opt1,opt2"'
1722
+ );
1723
+ }
1724
+ const name = defString.slice(0, firstColon);
1725
+ const rest = defString.slice(firstColon + 1);
1726
+ const secondColon = rest.indexOf(":");
1727
+ const type = secondColon === -1 ? rest : rest.slice(0, secondColon);
1728
+ const optionsStr = secondColon === -1 ? "" : rest.slice(secondColon + 1);
1729
+ if (type in UNSUPPORTED_PROPERTY_TYPES) {
1730
+ throw new CliError(
1731
+ ErrorCodes.INVALID_ARG,
1732
+ `Property type "${type}" is not supported via CLI \u2014 ${UNSUPPORTED_PROPERTY_TYPES[type]}`,
1733
+ "Supported types: title, rich_text, number, select, multi_select, status, date, checkbox, url, email, phone_number, people, files, created_time, last_edited_time"
1734
+ );
1735
+ }
1736
+ if (SIMPLE_PROPERTY_TYPES.has(type)) {
1737
+ return { name, config: { [type]: {} } };
1738
+ }
1739
+ if (OPTIONS_PROPERTY_TYPES.has(type)) {
1740
+ const options = optionsStr ? optionsStr.split(",").map((opt) => ({ name: opt.trim() })) : [];
1741
+ return { name, config: { [type]: { options } } };
1742
+ }
1743
+ throw new CliError(
1744
+ ErrorCodes.INVALID_ARG,
1745
+ `Unknown property type: "${type}"`,
1746
+ "Supported types: title, rich_text, number, select, multi_select, status, date, checkbox, url, email, phone_number, people, files, created_time, last_edited_time"
1747
+ );
1748
+ }
1749
+ function parsePropertyDefinitions(defStrings) {
1750
+ const properties = {};
1751
+ let hasTitleProperty = false;
1752
+ for (const def of defStrings) {
1753
+ const { name, config } = parsePropertyDefinition(def);
1754
+ if (name in properties) {
1755
+ throw new CliError(
1756
+ ErrorCodes.INVALID_ARG,
1757
+ `Duplicate property name: "${name}"`,
1758
+ "Each property must have a unique name"
1759
+ );
1760
+ }
1761
+ const isTitle = "title" in config;
1762
+ if (isTitle && hasTitleProperty) {
1763
+ throw new CliError(
1764
+ ErrorCodes.INVALID_ARG,
1765
+ "Only one title property is allowed per database",
1766
+ "Remove one of the title property definitions"
1767
+ );
1768
+ }
1769
+ if (isTitle) hasTitleProperty = true;
1770
+ properties[name] = config;
1771
+ }
1772
+ if (!hasTitleProperty) {
1773
+ properties.Name = { title: {} };
1774
+ }
1775
+ return properties;
1776
+ }
1777
+ async function createDatabase(client, parentId, title, properties) {
1778
+ return client.databases.create({
1779
+ parent: { type: "page_id", page_id: parentId },
1780
+ title: [{ type: "text", text: { content: title } }],
1781
+ initial_data_source: {
1782
+ properties
1783
+ }
1784
+ });
1785
+ }
1786
+ async function resolveDataSourceId(client, idOrUrl) {
1787
+ const id = toUuid(parseNotionId(idOrUrl));
1788
+ try {
1789
+ await client.dataSources.retrieve({ data_source_id: id });
1790
+ return id;
1791
+ } catch {
1792
+ }
1793
+ try {
1794
+ const db = await client.databases.retrieve({
1795
+ database_id: id
1796
+ });
1797
+ if (db.data_sources && db.data_sources.length > 0) {
1798
+ return db.data_sources[0].id;
1799
+ }
1800
+ } catch {
1801
+ }
1802
+ throw new CliError(
1803
+ ErrorCodes.API_NOT_FOUND,
1804
+ `Could not find database or data source: ${id}`
1805
+ );
1806
+ }
1641
1807
  function displayPropertyValue(prop) {
1642
1808
  switch (prop.type) {
1643
1809
  case "title":
@@ -1873,8 +2039,46 @@ function createPageCommand() {
1873
2039
  return cmd;
1874
2040
  }
1875
2041
 
1876
- // src/commands/db/query.ts
2042
+ // src/commands/db/create.ts
1877
2043
  import { Command as Command10 } from "commander";
2044
+ function collectProps2(val, acc) {
2045
+ acc.push(val);
2046
+ return acc;
2047
+ }
2048
+ function dbCreateCommand() {
2049
+ return new Command10("create").description("Create a new database under a parent page").requiredOption("--parent <id/url>", "parent page ID or URL").requiredOption("--title <title>", "database title").option(
2050
+ "--prop <definition>",
2051
+ 'property definition (repeatable): --prop "Name:type:options"',
2052
+ collectProps2,
2053
+ []
2054
+ ).action(
2055
+ withErrorHandling(async (opts) => {
2056
+ const { token, source } = await resolveToken();
2057
+ reportTokenSource(source);
2058
+ const client = createNotionClient(token);
2059
+ const parentUuid = toUuid(parseNotionId(opts.parent));
2060
+ const properties = parsePropertyDefinitions(opts.prop);
2061
+ const response = await createDatabase(
2062
+ client,
2063
+ parentUuid,
2064
+ opts.title,
2065
+ properties
2066
+ );
2067
+ if (getOutputMode() === "json") {
2068
+ process.stdout.write(`${formatJSON(response)}
2069
+ `);
2070
+ return;
2071
+ }
2072
+ if ("url" in response) {
2073
+ process.stdout.write(`${response.url}
2074
+ `);
2075
+ }
2076
+ })
2077
+ );
2078
+ }
2079
+
2080
+ // src/commands/db/query.ts
2081
+ import { Command as Command11 } from "commander";
1878
2082
  var SKIP_TYPES_IN_AUTO = /* @__PURE__ */ new Set(["relation", "rich_text", "people"]);
1879
2083
  function autoSelectColumns(schema, entries) {
1880
2084
  const termWidth = process.stdout.columns || 120;
@@ -1902,7 +2106,7 @@ function autoSelectColumns(schema, entries) {
1902
2106
  return selected;
1903
2107
  }
1904
2108
  function dbQueryCommand() {
1905
- return new Command10("query").description("Query database entries with optional filtering and sorting").argument("<id>", "Notion database ID or URL").option(
2109
+ return new Command11("query").description("Query database entries with optional filtering and sorting").argument("<id>", "Notion database ID or URL").option(
1906
2110
  "--filter <filter>",
1907
2111
  'Filter entries (repeatable): --filter "Status=Done"',
1908
2112
  collect,
@@ -1915,22 +2119,22 @@ function dbQueryCommand() {
1915
2119
  ).option(
1916
2120
  "--columns <columns>",
1917
2121
  'Comma-separated list of columns to display: --columns "Title,Status"'
1918
- ).option("--json", "Output raw JSON").action(
2122
+ ).action(
1919
2123
  withErrorHandling(
1920
2124
  async (id, options) => {
1921
2125
  const { token } = await resolveToken();
1922
2126
  const client = createNotionClient(token);
1923
- const dbId = parseNotionId(id);
1924
- const schema = await fetchDatabaseSchema(client, dbId);
2127
+ const dsId = await resolveDataSourceId(client, id);
2128
+ const schema = await fetchDatabaseSchema(client, dsId);
1925
2129
  const columns = options.columns ? options.columns.split(",").map((c2) => c2.trim()) : void 0;
1926
2130
  const filter = options.filter.length ? buildFilter(options.filter, schema) : void 0;
1927
2131
  const sorts = options.sort.length ? buildSorts(options.sort) : void 0;
1928
- const entries = await queryDatabase(client, dbId, {
2132
+ const entries = await queryDatabase(client, dsId, {
1929
2133
  filter,
1930
2134
  sorts,
1931
2135
  columns
1932
2136
  });
1933
- if (options.json) {
2137
+ if (getOutputMode() === "json") {
1934
2138
  process.stdout.write(`${formatJSON(entries.map((e) => e.raw))}
1935
2139
  `);
1936
2140
  return;
@@ -1957,15 +2161,15 @@ function collect(value, previous) {
1957
2161
  }
1958
2162
 
1959
2163
  // src/commands/db/schema.ts
1960
- import { Command as Command11 } from "commander";
2164
+ import { Command as Command12 } from "commander";
1961
2165
  function dbSchemaCommand() {
1962
- return new Command11("schema").description("Show database schema (property names, types, and options)").argument("<id>", "Notion database ID or URL").option("--json", "Output raw JSON").action(
1963
- withErrorHandling(async (id, options) => {
2166
+ return new Command12("schema").description("Show database schema (property names, types, and options)").argument("<id>", "Notion database ID or URL").action(
2167
+ withErrorHandling(async (id) => {
1964
2168
  const { token } = await resolveToken();
1965
2169
  const client = createNotionClient(token);
1966
- const dbId = parseNotionId(id);
1967
- const schema = await fetchDatabaseSchema(client, dbId);
1968
- if (options.json) {
2170
+ const dsId = await resolveDataSourceId(client, id);
2171
+ const schema = await fetchDatabaseSchema(client, dsId);
2172
+ if (getOutputMode() === "json") {
1969
2173
  process.stdout.write(`${formatJSON(schema)}
1970
2174
  `);
1971
2175
  return;
@@ -1983,13 +2187,13 @@ function dbSchemaCommand() {
1983
2187
  }
1984
2188
 
1985
2189
  // src/commands/edit-page.ts
1986
- import { Command as Command12 } from "commander";
2190
+ import { Command as Command13 } from "commander";
1987
2191
  function collect2(val, acc) {
1988
2192
  acc.push(val);
1989
2193
  return acc;
1990
2194
  }
1991
2195
  function editPageCommand() {
1992
- const cmd = new Command12("edit-page");
2196
+ const cmd = new Command13("edit-page");
1993
2197
  cmd.description(
1994
2198
  "replace a Notion page's content \u2014 full page or a targeted section"
1995
2199
  ).argument("<id/url>", "Notion page ID or URL").option(
@@ -2087,7 +2291,7 @@ function editPageCommand() {
2087
2291
 
2088
2292
  // src/commands/init.ts
2089
2293
  import { confirm, input as input2, password } from "@inquirer/prompts";
2090
- import { Command as Command13 } from "commander";
2294
+ import { Command as Command14 } from "commander";
2091
2295
  async function runInitFlow() {
2092
2296
  const profileName = await input2({
2093
2297
  message: "Profile name:",
@@ -2167,7 +2371,7 @@ async function runInitFlow() {
2167
2371
  stderrWrite(dim(" notion auth login"));
2168
2372
  }
2169
2373
  function initCommand() {
2170
- const cmd = new Command13("init");
2374
+ const cmd = new Command14("init");
2171
2375
  cmd.description("authenticate with Notion and save a profile").action(
2172
2376
  withErrorHandling(async () => {
2173
2377
  if (!process.stdin.isTTY) {
@@ -2185,7 +2389,7 @@ function initCommand() {
2185
2389
 
2186
2390
  // src/commands/ls.ts
2187
2391
  import { isFullPageOrDataSource } from "@notionhq/client";
2188
- import { Command as Command14 } from "commander";
2392
+ import { Command as Command15 } from "commander";
2189
2393
  function getTitle(item) {
2190
2394
  if (item.object === "data_source") {
2191
2395
  return item.title.map((t) => t.plain_text).join("") || "(untitled)";
@@ -2202,7 +2406,7 @@ function displayType(item) {
2202
2406
  return item.object === "data_source" ? "database" : item.object;
2203
2407
  }
2204
2408
  function lsCommand() {
2205
- const cmd = new Command14("ls");
2409
+ const cmd = new Command15("ls");
2206
2410
  cmd.description("list accessible Notion pages and databases").option(
2207
2411
  "--type <type>",
2208
2412
  "filter by object type (page or database)",
@@ -2212,6 +2416,15 @@ function lsCommand() {
2212
2416
  }
2213
2417
  return val;
2214
2418
  }
2419
+ ).option(
2420
+ "--sort <direction>",
2421
+ "sort by last edited time (asc or desc)",
2422
+ (val) => {
2423
+ if (val !== "asc" && val !== "desc") {
2424
+ throw new Error('--sort must be "asc" or "desc"');
2425
+ }
2426
+ return val;
2427
+ }
2215
2428
  ).option(
2216
2429
  "--cursor <cursor>",
2217
2430
  "start from this pagination cursor (from a previous --next hint)"
@@ -2225,6 +2438,10 @@ function lsCommand() {
2225
2438
  reportTokenSource(source);
2226
2439
  const notion = createNotionClient(token);
2227
2440
  const response = await notion.search({
2441
+ sort: opts.sort ? {
2442
+ timestamp: "last_edited_time",
2443
+ direction: opts.sort === "asc" ? "ascending" : "descending"
2444
+ } : void 0,
2228
2445
  start_cursor: opts.cursor,
2229
2446
  page_size: 20
2230
2447
  });
@@ -2265,10 +2482,10 @@ function lsCommand() {
2265
2482
  // src/commands/open.ts
2266
2483
  import { exec } from "child_process";
2267
2484
  import { promisify } from "util";
2268
- import { Command as Command15 } from "commander";
2485
+ import { Command as Command16 } from "commander";
2269
2486
  var execAsync = promisify(exec);
2270
2487
  function openCommand() {
2271
- const cmd = new Command15("open");
2488
+ const cmd = new Command16("open");
2272
2489
  cmd.description("open a Notion page in the default browser").argument("<id/url>", "Notion page ID or URL").action(
2273
2490
  withErrorHandling(async (idOrUrl) => {
2274
2491
  const id = parseNotionId(idOrUrl);
@@ -2284,9 +2501,9 @@ function openCommand() {
2284
2501
  }
2285
2502
 
2286
2503
  // src/commands/profile/list.ts
2287
- import { Command as Command16 } from "commander";
2504
+ import { Command as Command17 } from "commander";
2288
2505
  function profileListCommand() {
2289
- const cmd = new Command16("list");
2506
+ const cmd = new Command17("list");
2290
2507
  cmd.description("list all authentication profiles").action(
2291
2508
  withErrorHandling(async () => {
2292
2509
  const config = await readGlobalConfig();
@@ -2315,9 +2532,9 @@ function profileListCommand() {
2315
2532
  }
2316
2533
 
2317
2534
  // src/commands/profile/remove.ts
2318
- import { Command as Command17 } from "commander";
2535
+ import { Command as Command18 } from "commander";
2319
2536
  function profileRemoveCommand() {
2320
- const cmd = new Command17("remove");
2537
+ const cmd = new Command18("remove");
2321
2538
  cmd.description("remove an authentication profile").argument("<name>", "profile name to remove").action(
2322
2539
  withErrorHandling(async (name) => {
2323
2540
  const config = await readGlobalConfig();
@@ -2343,9 +2560,9 @@ function profileRemoveCommand() {
2343
2560
  }
2344
2561
 
2345
2562
  // src/commands/profile/use.ts
2346
- import { Command as Command18 } from "commander";
2563
+ import { Command as Command19 } from "commander";
2347
2564
  function profileUseCommand() {
2348
- const cmd = new Command18("use");
2565
+ const cmd = new Command19("use");
2349
2566
  cmd.description("switch the active profile").argument("<name>", "profile name to activate").action(
2350
2567
  withErrorHandling(async (name) => {
2351
2568
  const config = await readGlobalConfig();
@@ -2368,7 +2585,7 @@ function profileUseCommand() {
2368
2585
  }
2369
2586
 
2370
2587
  // src/commands/read.ts
2371
- import { Command as Command19 } from "commander";
2588
+ import { Command as Command20 } from "commander";
2372
2589
 
2373
2590
  // src/output/markdown.ts
2374
2591
  import { Chalk as Chalk2 } from "chalk";
@@ -2508,7 +2725,7 @@ async function fetchPageMarkdown(client, pageId) {
2508
2725
 
2509
2726
  // src/commands/read.ts
2510
2727
  function readCommand() {
2511
- return new Command19("read").description("Read a Notion page as markdown").argument("<id>", "Notion page ID or URL").action(
2728
+ return new Command20("read").description("Read a Notion page as markdown").argument("<id>", "Notion page ID or URL").action(
2512
2729
  withErrorHandling(async (id) => {
2513
2730
  const { token } = await resolveToken();
2514
2731
  const client = createNotionClient(token);
@@ -2534,7 +2751,7 @@ function readCommand() {
2534
2751
 
2535
2752
  // src/commands/search.ts
2536
2753
  import { isFullPageOrDataSource as isFullPageOrDataSource2 } from "@notionhq/client";
2537
- import { Command as Command20 } from "commander";
2754
+ import { Command as Command21 } from "commander";
2538
2755
  function getTitle2(item) {
2539
2756
  if (item.object === "data_source") {
2540
2757
  return item.title.map((t) => t.plain_text).join("") || "(untitled)";
@@ -2554,7 +2771,7 @@ function displayType2(item) {
2554
2771
  return item.object === "data_source" ? "database" : item.object;
2555
2772
  }
2556
2773
  function searchCommand() {
2557
- const cmd = new Command20("search");
2774
+ const cmd = new Command21("search");
2558
2775
  cmd.description("search Notion workspace by keyword").argument("<query>", "search keyword").option(
2559
2776
  "--type <type>",
2560
2777
  "filter by object type (page or database)",
@@ -2564,6 +2781,15 @@ function searchCommand() {
2564
2781
  }
2565
2782
  return val;
2566
2783
  }
2784
+ ).option(
2785
+ "--sort <direction>",
2786
+ "sort by last edited time (asc or desc)",
2787
+ (val) => {
2788
+ if (val !== "asc" && val !== "desc") {
2789
+ throw new Error('--sort must be "asc" or "desc"');
2790
+ }
2791
+ return val;
2792
+ }
2567
2793
  ).option(
2568
2794
  "--cursor <cursor>",
2569
2795
  "start from this pagination cursor (from a previous --next hint)"
@@ -2579,6 +2805,10 @@ function searchCommand() {
2579
2805
  const response = await notion.search({
2580
2806
  query,
2581
2807
  filter: opts.type ? { property: "object", value: toSdkFilterValue(opts.type) } : void 0,
2808
+ sort: opts.sort ? {
2809
+ timestamp: "last_edited_time",
2810
+ direction: opts.sort === "asc" ? "ascending" : "descending"
2811
+ } : void 0,
2582
2812
  start_cursor: opts.cursor,
2583
2813
  page_size: 20
2584
2814
  });
@@ -2612,17 +2842,17 @@ function searchCommand() {
2612
2842
  }
2613
2843
 
2614
2844
  // src/commands/update.ts
2615
- import { Command as Command21 } from "commander";
2616
- function collectProps2(val, acc) {
2845
+ import { Command as Command22 } from "commander";
2846
+ function collectProps3(val, acc) {
2617
2847
  acc.push(val);
2618
2848
  return acc;
2619
2849
  }
2620
2850
  function updateCommand() {
2621
- const cmd = new Command21("update");
2851
+ const cmd = new Command22("update");
2622
2852
  cmd.description("update properties on a Notion page").argument("<id/url>", "Notion page ID or URL").option(
2623
2853
  "--prop <property=value>",
2624
2854
  "set a property value (repeatable)",
2625
- collectProps2,
2855
+ collectProps3,
2626
2856
  []
2627
2857
  ).option("--title <title>", "set the page title").action(
2628
2858
  withErrorHandling(async (idOrUrl, opts) => {
@@ -2676,7 +2906,7 @@ function updateCommand() {
2676
2906
  }
2677
2907
 
2678
2908
  // src/commands/users.ts
2679
- import { Command as Command22 } from "commander";
2909
+ import { Command as Command23 } from "commander";
2680
2910
  function getEmailOrWorkspace(user) {
2681
2911
  if (user.type === "person") {
2682
2912
  return user.person.email ?? "\u2014";
@@ -2688,7 +2918,7 @@ function getEmailOrWorkspace(user) {
2688
2918
  return "\u2014";
2689
2919
  }
2690
2920
  function usersCommand() {
2691
- const cmd = new Command22("users");
2921
+ const cmd = new Command23("users");
2692
2922
  cmd.description("list all users in the workspace").option("--json", "output as JSON").action(
2693
2923
  withErrorHandling(async (opts) => {
2694
2924
  if (opts.json) setOutputMode("json");
@@ -2719,7 +2949,7 @@ var __dirname = dirname(__filename);
2719
2949
  var pkg = JSON.parse(
2720
2950
  readFileSync(join3(__dirname, "../package.json"), "utf-8")
2721
2951
  );
2722
- var program = new Command23();
2952
+ var program = new Command24();
2723
2953
  program.name("notion").description("Notion CLI \u2014 read Notion pages and databases from the terminal").version(pkg.version);
2724
2954
  program.option("--verbose", "show API requests/responses").option("--color", "force color output").option("--json", "force JSON output (overrides TTY detection)").option("--md", "force markdown output for page content");
2725
2955
  program.configureOutput({
@@ -2740,7 +2970,7 @@ program.hook("preAction", (thisCommand) => {
2740
2970
  setOutputMode("md");
2741
2971
  }
2742
2972
  });
2743
- var authCmd = new Command23("auth").description("manage Notion authentication");
2973
+ var authCmd = new Command24("auth").description("manage Notion authentication");
2744
2974
  authCmd.action(authDefaultAction(authCmd));
2745
2975
  authCmd.addCommand(loginCommand());
2746
2976
  authCmd.addCommand(logoutCommand());
@@ -2750,7 +2980,7 @@ authCmd.addCommand(profileUseCommand());
2750
2980
  authCmd.addCommand(profileRemoveCommand());
2751
2981
  program.addCommand(authCmd);
2752
2982
  program.addCommand(initCommand(), { hidden: true });
2753
- var profileCmd = new Command23("profile").description(
2983
+ var profileCmd = new Command24("profile").description(
2754
2984
  "manage authentication profiles"
2755
2985
  );
2756
2986
  profileCmd.addCommand(profileListCommand());
@@ -2769,7 +2999,8 @@ program.addCommand(createPageCommand());
2769
2999
  program.addCommand(editPageCommand());
2770
3000
  program.addCommand(updateCommand());
2771
3001
  program.addCommand(archiveCommand());
2772
- var dbCmd = new Command23("db").description("Database operations");
3002
+ var dbCmd = new Command24("db").description("Database operations");
3003
+ dbCmd.addCommand(dbCreateCommand());
2773
3004
  dbCmd.addCommand(dbSchemaCommand());
2774
3005
  dbCmd.addCommand(dbQueryCommand());
2775
3006
  program.addCommand(dbCmd);