@verbatims/cli 0.1.18 → 1.0.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/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  CLI for the [Verbatims](https://verbatims.cc) quotes API.
4
4
 
5
+ Version 1 uses normalized provenance options for quote creation and updates.
6
+
5
7
  ## Install
6
8
 
7
9
  ```bash
@@ -27,12 +29,12 @@ verbatims quotes get 123 --format json
27
29
  verbatims quotes attributions list 123
28
30
  verbatims quotes attributions create 123 --author-id 1 --reference-id 2 --status manually_verified --primary
29
31
  verbatims quotes sources list 123
30
- verbatims quotes sources create 123 --source-type book --source-url https://example.com/edition --status externally_verified
32
+ verbatims quotes sources create 123 --attribution-id 7 --source-type book --source-url https://example.com/edition --status externally_verified
31
33
 
32
34
  # Create a quote with a source
33
- verbatims quotes create --source-type book --source-url https://example.com/edition
35
+ verbatims quotes create --name "Alea jacta est" --author-id 1 --source-type book --source-url https://example.com/edition
34
36
 
35
- The quote-level `--author-id`, `--reference-id`, `--source-type`, and `--source-url` options are deprecated compatibility options. New integrations should use the SDK `provenance` payload; the dedicated `quotes attributions` and `quotes sources` commands manage secondary provenance.
37
+ Use `--author-id` or `--reference-id` to create the required primary attribution. Sources always require `--attribution-id`; use the dedicated `quotes attributions` and `quotes sources` commands for additional or edited provenance.
36
38
 
37
39
  # Browse interactively
38
40
  verbatims quotes browse
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verbatims/cli",
3
- "version": "0.1.18",
3
+ "version": "1.0.1",
4
4
  "description": "CLI for the Verbatims quotes API",
5
5
  "type": "module",
6
6
  "bin": {
@@ -16,7 +16,7 @@
16
16
  "typecheck": "tsc --noEmit"
17
17
  },
18
18
  "dependencies": {
19
- "@verbatims/sdk": "^1.0.0",
19
+ "@verbatims/sdk": "^2.0.1",
20
20
  "@clack/prompts": "^0.10.1",
21
21
  "chalk": "^5.4.1",
22
22
  "commander": "^13.1.0",
@@ -10,13 +10,6 @@ function getFormat(program: Command): Format {
10
10
  return (program.opts().format ?? 'table') as Format
11
11
  }
12
12
 
13
- function warnLegacyQuoteOptions(options: Record<string, unknown>): void {
14
- const fields = ['authorId', 'referenceId', 'sourceType', 'sourceUrl']
15
- if (fields.some(field => options[field] !== undefined)) {
16
- console.error(chalk.yellow('Warning: quote provenance options are deprecated; use the provenance API fields instead.'))
17
- }
18
- }
19
-
20
13
  export function registerQuotesCommand(program: Command) {
21
14
  const quotes = program.command('quotes').description('Manage quotes')
22
15
 
@@ -73,14 +66,13 @@ export function registerQuotesCommand(program: Command) {
73
66
  .description('Create a quote')
74
67
  .option('--name <text>', 'Quote text')
75
68
  .option('--language <lang>', 'Language')
76
- .option('--author-id <id>', 'Author ID (deprecated)')
77
- .option('--reference-id <id>', 'Reference ID (deprecated)')
78
- .option('--source-type <type>', 'Source type (deprecated)')
79
- .option('--source-url <url>', 'Source URL (deprecated)')
69
+ .option('--author-id <id>', 'Primary attribution author ID')
70
+ .option('--reference-id <id>', 'Primary attribution reference ID')
71
+ .option('--source-type <type>', 'Source type for the primary attribution')
72
+ .option('--source-url <url>', 'Source URL for the primary attribution')
80
73
  .action(async (options: Record<string, string>) => {
81
74
  const client = await getClient()
82
75
  const format = getFormat(program)
83
- warnLegacyQuoteOptions(options)
84
76
 
85
77
  const name = options.name ?? await text({ message: 'Quote text', validate: (v) => !v ? 'Required' : undefined })
86
78
  if (isCancel(name)) cancel('Cancelled')
@@ -90,20 +82,29 @@ export function registerQuotesCommand(program: Command) {
90
82
 
91
83
  const authorId = options.authorId ? Number(options.authorId) : undefined
92
84
  const referenceId = options.referenceId ? Number(options.referenceId) : undefined
85
+ if (authorId === undefined && referenceId === undefined) {
86
+ throw new Error('A quote requires --author-id or --reference-id')
87
+ }
93
88
 
94
89
  const { data } = await withSpinner('Creating quote', () =>
95
90
  client.quotes.create({
96
91
  content: name as string,
97
92
  name: name as string,
98
93
  language: language as string,
99
- provenance: {
100
- author_id: authorId,
101
- reference_id: referenceId,
102
- source: options.sourceType ? { source_type: options.sourceType, source_url: options.sourceUrl } : undefined,
103
- },
94
+ attributions: [{ author_id: authorId, reference_id: referenceId, is_primary: true }],
104
95
  }),
105
96
  format,
106
97
  )
98
+ if (options.sourceType && data) {
99
+ const primary = data.attributions?.find(attribution => attribution.is_primary)
100
+ if (!primary) throw new Error('The created quote has no primary attribution')
101
+ await withSpinner('Creating source', () => client.quotes.createSource(data.id, {
102
+ attribution_id: primary.id,
103
+ source_type: options.sourceType,
104
+ source_url: options.sourceUrl,
105
+ is_primary: true,
106
+ }), format)
107
+ }
107
108
  console.log(chalk.green(' Quote created'))
108
109
  output(data, format)
109
110
  })
@@ -113,28 +114,28 @@ export function registerQuotesCommand(program: Command) {
113
114
  .description('Update a quote')
114
115
  .option('--name <text>', 'Quote text')
115
116
  .option('--language <lang>', 'Language')
116
- .option('--author-id <id>', 'Author ID (deprecated)')
117
- .option('--reference-id <id>', 'Reference ID (deprecated)')
118
- .option('--source-type <type>', 'Source type (deprecated)')
119
- .option('--source-url <url>', 'Source URL (deprecated)')
117
+ .option('--author-id <id>', 'Primary attribution author ID')
118
+ .option('--reference-id <id>', 'Primary attribution reference ID')
120
119
  .action(async (id: string, options: Record<string, string>) => {
121
120
  const client = await getClient()
122
121
  const format = getFormat(program)
123
- warnLegacyQuoteOptions(options)
124
122
 
125
123
  const data_: Record<string, unknown> = {}
126
124
  if (options.name) { data_.name = options.name; data_.content = options.name }
127
125
  if (options.language) data_.language = options.language
128
- if (options.authorId !== undefined) data_.provenance = { ...(data_.provenance as object), author_id: options.authorId === 'null' ? null : Number(options.authorId) }
129
- if (options.referenceId !== undefined) data_.provenance = { ...(data_.provenance as object), reference_id: options.referenceId === 'null' ? null : Number(options.referenceId) }
130
- if (options.sourceType !== undefined || options.sourceUrl !== undefined) {
131
- data_.provenance = {
132
- ...(data_.provenance as object),
133
- source: { source_type: options.sourceType ?? 'manual', source_url: options.sourceUrl },
134
- }
135
- }
126
+ const authorId = options.authorId === undefined ? undefined : options.authorId === 'null' ? null : Number(options.authorId)
127
+ const referenceId = options.referenceId === undefined ? undefined : options.referenceId === 'null' ? null : Number(options.referenceId)
136
128
 
137
129
  const { data } = await withSpinner('Updating quote', () => client.quotes.update(Number(id), data_ as any), format)
130
+ if (authorId !== undefined || referenceId !== undefined) {
131
+ const attributions = await client.quotes.listAttributions(Number(id))
132
+ const primary = attributions.data?.find(attribution => attribution.is_primary)
133
+ if (!primary) throw new Error('The quote has no primary attribution')
134
+ await withSpinner('Updating primary attribution', () => client.quotes.updateAttribution(Number(id), primary.id, {
135
+ author_id: authorId === undefined ? primary.author_id : authorId,
136
+ reference_id: referenceId === undefined ? primary.reference_id : referenceId,
137
+ }), format)
138
+ }
138
139
  console.log(chalk.green(' Quote updated'))
139
140
  output(data, format)
140
141
  })
@@ -306,8 +307,9 @@ export function registerQuotesCommand(program: Command) {
306
307
  }
307
308
  if (action === 'create') {
308
309
  if (!options.sourceType) throw new Error('--source-type is required')
310
+ if (!options.attributionId) throw new Error('--attribution-id is required')
309
311
  const { data } = await withSpinner('Creating source', () => client.quotes.createSource(id, {
310
- attribution_id: options.attributionId ? Number(options.attributionId) : null,
312
+ attribution_id: Number(options.attributionId),
311
313
  source_type: options.sourceType,
312
314
  source_url: options.sourceUrl,
313
315
  label: options.label,