@drawcall/market 0.8.25 → 0.8.27
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 +11 -0
- package/dist/cli-client.d.ts.map +1 -1
- package/dist/cli-client.js +2 -1
- package/dist/cli-client.js.map +1 -1
- package/dist/cli.js +5 -316
- package/dist/cli.js.map +1 -1
- package/dist/command-entry.d.ts +2 -0
- package/dist/command-entry.d.ts.map +1 -0
- package/dist/command-entry.js +2 -0
- package/dist/command-entry.js.map +1 -0
- package/dist/command.d.ts +9 -0
- package/dist/command.d.ts.map +1 -0
- package/dist/command.js +303 -0
- package/dist/command.js.map +1 -0
- package/dist/commands/logout.d.ts +1 -1
- package/dist/commands/logout.d.ts.map +1 -1
- package/dist/commands/logout.js +7 -7
- package/dist/commands/logout.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/package.json +7 -4
- package/src/cli-client.ts +2 -1
- package/src/cli.ts +5 -431
- package/src/command-entry.ts +1 -0
- package/src/command.ts +423 -0
- package/src/commands/logout.ts +7 -6
- package/src/config.ts +2 -2
package/src/command.ts
ADDED
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
import { createRequire } from 'node:module'
|
|
2
|
+
import {
|
|
3
|
+
getConfigPath as getAuthConfigPath,
|
|
4
|
+
runDeviceLogin,
|
|
5
|
+
saveAuthToken,
|
|
6
|
+
signOut,
|
|
7
|
+
} from '@drawcall/auth'
|
|
8
|
+
import { Command, Option } from 'commander'
|
|
9
|
+
import { ASSET_TYPES, type AssetAccess, type AssetType } from './schemas.js'
|
|
10
|
+
import { installCommand } from './commands/install.js'
|
|
11
|
+
import { searchCommand } from './commands/search.js'
|
|
12
|
+
import { agentCommand } from './commands/agent.js'
|
|
13
|
+
import { generateCommand } from './commands/generate.js'
|
|
14
|
+
import { generateInstallCommand } from './commands/generate-install.js'
|
|
15
|
+
import { listCommand } from './commands/list.js'
|
|
16
|
+
import { packCommand } from './commands/pack.js'
|
|
17
|
+
import { syncCommand } from './commands/sync.js'
|
|
18
|
+
import { previewCommand } from './commands/preview.js'
|
|
19
|
+
import { urlsCommand } from './commands/urls.js'
|
|
20
|
+
import { uploadCommand } from './commands/upload.js'
|
|
21
|
+
import { typesCommand } from './commands/types.js'
|
|
22
|
+
import { logout } from './commands/logout.js'
|
|
23
|
+
import { v1 } from './index.js'
|
|
24
|
+
import { clearConfig, saveConfig } from './config.js'
|
|
25
|
+
import { loginResult } from './output.js'
|
|
26
|
+
import { marketSkill } from './skill.js'
|
|
27
|
+
|
|
28
|
+
const DEFAULT_BASE_URL = 'https://market.drawcall.ai'
|
|
29
|
+
|
|
30
|
+
export interface MarketCommandOptions {
|
|
31
|
+
name?: string
|
|
32
|
+
invocation?: string
|
|
33
|
+
version?: string
|
|
34
|
+
includeAuthCommands?: boolean
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function createMarketCommand(options: MarketCommandOptions = {}): Command {
|
|
38
|
+
const program = new Command()
|
|
39
|
+
const invocation = options.invocation ?? options.name ?? 'market'
|
|
40
|
+
|
|
41
|
+
/** Accumulate a repeatable option into an array. */
|
|
42
|
+
const collect = (value: string, previous: string[]): string[] => previous.concat(value)
|
|
43
|
+
|
|
44
|
+
const typeOption = new Option('--type <type>', 'Asset type').choices([...ASSET_TYPES])
|
|
45
|
+
const referenceImageOption = new Option(
|
|
46
|
+
'--reference-image <file-or-url>',
|
|
47
|
+
'Reference image the result should match: file path or http(s) URL (repeatable)',
|
|
48
|
+
)
|
|
49
|
+
.argParser(collect)
|
|
50
|
+
.default([])
|
|
51
|
+
// Omitted → the server picks the default from your entitlement (private if you hold market:private,
|
|
52
|
+
// else public). `--access private` requires that entitlement.
|
|
53
|
+
const accessOption = new Option('--access <access>', 'Asset visibility').choices([
|
|
54
|
+
'public',
|
|
55
|
+
'private',
|
|
56
|
+
])
|
|
57
|
+
const apiOption = new Option('--api <url>', 'API URL').default(
|
|
58
|
+
process.env.MARKET_API_URL,
|
|
59
|
+
'from MARKET_API_URL / config / default',
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
program
|
|
63
|
+
.name(options.name ?? 'market')
|
|
64
|
+
.description('Find and use Drawcall Market assets')
|
|
65
|
+
.version(options.version ?? readPackageVersion())
|
|
66
|
+
.enablePositionalOptions()
|
|
67
|
+
.addHelpText(
|
|
68
|
+
'after',
|
|
69
|
+
`\nAI agents that have not already seen the Market skill should run \`${invocation} skill\` before using this CLI.`,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
program
|
|
73
|
+
.command('skill')
|
|
74
|
+
.description('Print the Market agent skill')
|
|
75
|
+
.action(() => {
|
|
76
|
+
process.stdout.write(marketSkill)
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
program
|
|
80
|
+
.command('types')
|
|
81
|
+
.description('List current asset types, generation support, and search guidance')
|
|
82
|
+
.addOption(apiOption)
|
|
83
|
+
.action(async (opts: { api?: string }) => {
|
|
84
|
+
await typesCommand(opts.api)
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
if (options.includeAuthCommands ?? true) addAuthCommands(program, apiOption)
|
|
88
|
+
|
|
89
|
+
program
|
|
90
|
+
.command('install')
|
|
91
|
+
.description(
|
|
92
|
+
'Install assets by name, or package.json assetDependencies when no names are given',
|
|
93
|
+
)
|
|
94
|
+
.argument('[assets...]', 'Asset names, optionally with @range')
|
|
95
|
+
.addOption(apiOption)
|
|
96
|
+
.option('--unapproved', 'Include unapproved versions', false)
|
|
97
|
+
.option('--force', 'Overwrite existing files', false)
|
|
98
|
+
.option('--key <key>', 'Access key of a shared private asset (no account needed)')
|
|
99
|
+
.option('--cwd <dir>', 'Project directory')
|
|
100
|
+
.option(
|
|
101
|
+
'--redirect <folder>',
|
|
102
|
+
'Do not download asset files destined for this static root (e.g. public); write <folder>/_redirects rules to their canonical URLs instead. Repeatable.',
|
|
103
|
+
collect,
|
|
104
|
+
[],
|
|
105
|
+
)
|
|
106
|
+
.action(
|
|
107
|
+
async (
|
|
108
|
+
args: string[],
|
|
109
|
+
opts: {
|
|
110
|
+
api?: string
|
|
111
|
+
unapproved: boolean
|
|
112
|
+
force: boolean
|
|
113
|
+
key?: string
|
|
114
|
+
cwd?: string
|
|
115
|
+
redirect: string[]
|
|
116
|
+
},
|
|
117
|
+
) => {
|
|
118
|
+
await installCommand(args, {
|
|
119
|
+
baseUrl: opts.api,
|
|
120
|
+
unapproved: opts.unapproved,
|
|
121
|
+
force: opts.force,
|
|
122
|
+
key: opts.key,
|
|
123
|
+
cwd: opts.cwd,
|
|
124
|
+
redirect: opts.redirect,
|
|
125
|
+
})
|
|
126
|
+
},
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
program
|
|
130
|
+
.command('list')
|
|
131
|
+
.description('List asset dependencies declared in package.json, including file aliases')
|
|
132
|
+
.option('--cwd <dir>', 'Project directory')
|
|
133
|
+
.action(async (opts: { cwd?: string }) => {
|
|
134
|
+
await listCommand({
|
|
135
|
+
cwd: opts.cwd,
|
|
136
|
+
})
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
program
|
|
140
|
+
.command('sync')
|
|
141
|
+
.description(
|
|
142
|
+
'Update package.json assetDependencies aliases to match where installed files live now',
|
|
143
|
+
)
|
|
144
|
+
.addOption(apiOption)
|
|
145
|
+
.option('--cwd <dir>', 'Project directory')
|
|
146
|
+
.action(async (opts: { api?: string; cwd?: string }) => {
|
|
147
|
+
await syncCommand({
|
|
148
|
+
baseUrl: opts.api,
|
|
149
|
+
cwd: opts.cwd,
|
|
150
|
+
})
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
program
|
|
154
|
+
.command('pack')
|
|
155
|
+
.description('Create a Market asset zip using the same packaging step as upload')
|
|
156
|
+
.argument('<source>', 'project directory, .zip path, or glob')
|
|
157
|
+
.addOption(typeOption)
|
|
158
|
+
.option('--out <file>', 'Output zip path')
|
|
159
|
+
.option('--cwd <dir>', 'Project directory')
|
|
160
|
+
.option('--npm <dep>', 'npm dependency name@range (repeatable)', collect, [])
|
|
161
|
+
.option('--asset <dep>', 'asset dependency name@range (repeatable)', collect, [])
|
|
162
|
+
.option('--skill <dep>', 'skill dependency label=source (repeatable)', collect, [])
|
|
163
|
+
.action(
|
|
164
|
+
async (
|
|
165
|
+
zipFilter: string,
|
|
166
|
+
opts: {
|
|
167
|
+
type?: AssetType
|
|
168
|
+
out?: string
|
|
169
|
+
cwd?: string
|
|
170
|
+
npm: string[]
|
|
171
|
+
asset: string[]
|
|
172
|
+
skill: string[]
|
|
173
|
+
},
|
|
174
|
+
) => {
|
|
175
|
+
await packCommand(zipFilter, {
|
|
176
|
+
type: opts.type,
|
|
177
|
+
out: opts.out,
|
|
178
|
+
cwd: opts.cwd,
|
|
179
|
+
npm: opts.npm,
|
|
180
|
+
asset: opts.asset,
|
|
181
|
+
skill: opts.skill,
|
|
182
|
+
})
|
|
183
|
+
},
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
program
|
|
187
|
+
.command('search')
|
|
188
|
+
.description('Find assets')
|
|
189
|
+
.argument('<query>', 'Search query')
|
|
190
|
+
.addOption(typeOption)
|
|
191
|
+
.addOption(apiOption)
|
|
192
|
+
.option('--unapproved', 'Include unapproved versions', false)
|
|
193
|
+
.option('--limit <n>', 'Max results, 1-5', parseSearchLimit, 5)
|
|
194
|
+
.option('--json', 'Emit a machine-readable JSON array instead of the summary lines', false)
|
|
195
|
+
.action(
|
|
196
|
+
async (
|
|
197
|
+
query: string,
|
|
198
|
+
opts: {
|
|
199
|
+
type?: AssetType
|
|
200
|
+
api?: string
|
|
201
|
+
unapproved: boolean
|
|
202
|
+
limit: number
|
|
203
|
+
json: boolean
|
|
204
|
+
},
|
|
205
|
+
) => {
|
|
206
|
+
requireType(opts.type, 'Search')
|
|
207
|
+
await searchCommand(query, {
|
|
208
|
+
type: opts.type,
|
|
209
|
+
baseUrl: opts.api,
|
|
210
|
+
unapproved: opts.unapproved,
|
|
211
|
+
limit: opts.limit,
|
|
212
|
+
json: opts.json,
|
|
213
|
+
})
|
|
214
|
+
},
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
const agent = program
|
|
218
|
+
.command('agent')
|
|
219
|
+
.description('Plan, find, judge and generate a set of assets from a goal')
|
|
220
|
+
.argument('[goal]', 'What you need, in plain language')
|
|
221
|
+
.addOption(apiOption)
|
|
222
|
+
.addOption(referenceImageOption)
|
|
223
|
+
.option('--json', 'Output JSON', false)
|
|
224
|
+
.action(
|
|
225
|
+
async (
|
|
226
|
+
goal: string | undefined,
|
|
227
|
+
opts: { api?: string; referenceImage: string[]; json: boolean },
|
|
228
|
+
) => {
|
|
229
|
+
if (!goal) {
|
|
230
|
+
agent.help({ error: true })
|
|
231
|
+
return
|
|
232
|
+
}
|
|
233
|
+
await agentCommand(goal, {
|
|
234
|
+
baseUrl: opts.api,
|
|
235
|
+
referenceImages: opts.referenceImage,
|
|
236
|
+
json: opts.json,
|
|
237
|
+
})
|
|
238
|
+
},
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
program
|
|
242
|
+
.command('upload')
|
|
243
|
+
.description('Publish one asset')
|
|
244
|
+
.argument('<name>', 'Asset name')
|
|
245
|
+
.argument('<zip-filter>', '.zip path or glob')
|
|
246
|
+
.argument('<description>', 'Short description')
|
|
247
|
+
.addOption(typeOption)
|
|
248
|
+
.addOption(apiOption)
|
|
249
|
+
.option('--version <version>', 'Explicit semver version')
|
|
250
|
+
.option('--cwd <dir>', 'Project directory')
|
|
251
|
+
.option('--npm <dep>', 'npm dependency name@range (repeatable)', collect, [])
|
|
252
|
+
.option('--asset <dep>', 'asset dependency name@range (repeatable)', collect, [])
|
|
253
|
+
.option('--skill <dep>', 'skill dependency label=source (repeatable)', collect, [])
|
|
254
|
+
.addOption(accessOption)
|
|
255
|
+
.action(
|
|
256
|
+
async (
|
|
257
|
+
name: string,
|
|
258
|
+
zipFilter: string,
|
|
259
|
+
description: string,
|
|
260
|
+
opts: {
|
|
261
|
+
type?: AssetType
|
|
262
|
+
api?: string
|
|
263
|
+
version?: string
|
|
264
|
+
cwd?: string
|
|
265
|
+
npm: string[]
|
|
266
|
+
asset: string[]
|
|
267
|
+
skill: string[]
|
|
268
|
+
access?: AssetAccess
|
|
269
|
+
},
|
|
270
|
+
) => {
|
|
271
|
+
requireType(opts.type, 'Upload')
|
|
272
|
+
await uploadCommand(name, zipFilter, description, {
|
|
273
|
+
type: opts.type,
|
|
274
|
+
version: opts.version,
|
|
275
|
+
baseUrl: opts.api,
|
|
276
|
+
cwd: opts.cwd,
|
|
277
|
+
npm: opts.npm,
|
|
278
|
+
asset: opts.asset,
|
|
279
|
+
skill: opts.skill,
|
|
280
|
+
access: opts.access,
|
|
281
|
+
})
|
|
282
|
+
},
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
program
|
|
286
|
+
.command('preview')
|
|
287
|
+
.description("Save an asset's preview image")
|
|
288
|
+
.argument('<asset>', 'Asset name, optionally with @version')
|
|
289
|
+
.addOption(apiOption)
|
|
290
|
+
.option('--unapproved', 'Include unapproved versions', false)
|
|
291
|
+
.option('--out <file>', 'Output image path')
|
|
292
|
+
.action(async (name: string, opts: { api?: string; unapproved: boolean; out?: string }) => {
|
|
293
|
+
await previewCommand(name, {
|
|
294
|
+
baseUrl: opts.api,
|
|
295
|
+
unapproved: opts.unapproved,
|
|
296
|
+
out: opts.out,
|
|
297
|
+
})
|
|
298
|
+
})
|
|
299
|
+
|
|
300
|
+
program
|
|
301
|
+
.command('urls')
|
|
302
|
+
.description("Print an asset's remote file base URL, subpaths, and preview URL")
|
|
303
|
+
.argument('<asset>', 'Asset name, optionally with @version')
|
|
304
|
+
.addOption(apiOption)
|
|
305
|
+
.option('--unapproved', 'Include unapproved versions', false)
|
|
306
|
+
.option('--key <key>', 'Access key of a shared private asset (no account needed)')
|
|
307
|
+
.action(async (ref: string, opts: { api?: string; unapproved: boolean; key?: string }) => {
|
|
308
|
+
await urlsCommand(ref, {
|
|
309
|
+
baseUrl: opts.api,
|
|
310
|
+
unapproved: opts.unapproved,
|
|
311
|
+
key: opts.key,
|
|
312
|
+
})
|
|
313
|
+
})
|
|
314
|
+
|
|
315
|
+
const generate = program
|
|
316
|
+
.command('generate')
|
|
317
|
+
.description('Generate and install an asset, or check a generation job')
|
|
318
|
+
.argument('[description]', 'Asset prompt (omit when using a subcommand)')
|
|
319
|
+
.addOption(typeOption)
|
|
320
|
+
.addOption(apiOption)
|
|
321
|
+
.addOption(referenceImageOption)
|
|
322
|
+
.option('--cwd <dir>', 'Project directory')
|
|
323
|
+
.addOption(accessOption)
|
|
324
|
+
.action(
|
|
325
|
+
async (
|
|
326
|
+
description: string | undefined,
|
|
327
|
+
opts: {
|
|
328
|
+
type?: AssetType
|
|
329
|
+
api?: string
|
|
330
|
+
referenceImage: string[]
|
|
331
|
+
cwd?: string
|
|
332
|
+
access?: AssetAccess
|
|
333
|
+
},
|
|
334
|
+
) => {
|
|
335
|
+
if (!description) {
|
|
336
|
+
generate.help({ error: true })
|
|
337
|
+
return
|
|
338
|
+
}
|
|
339
|
+
requireType(opts.type, 'Generate')
|
|
340
|
+
await generateCommand(description, {
|
|
341
|
+
type: opts.type,
|
|
342
|
+
baseUrl: opts.api,
|
|
343
|
+
referenceImages: opts.referenceImage,
|
|
344
|
+
cwd: opts.cwd,
|
|
345
|
+
access: opts.access,
|
|
346
|
+
})
|
|
347
|
+
},
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
// `generate install <jobId>` finishes a slow (job-based) generation: it checks the job once and, when
|
|
351
|
+
// it has completed, installs the produced asset into the project. Still running → prints a note and
|
|
352
|
+
// exits 0 (run again later); failed → exits 1. Fast asset types never need this — `generate` installs
|
|
353
|
+
// them inline. ("install" over "status": the command's job is to integrate the asset, not just report.)
|
|
354
|
+
generate
|
|
355
|
+
.command('install')
|
|
356
|
+
.description('Install the asset from a generation job once it has completed')
|
|
357
|
+
.argument('<jobId>', `Job id printed by \`${invocation} generate\``)
|
|
358
|
+
.addOption(apiOption)
|
|
359
|
+
.option('--cwd <dir>', 'Project directory')
|
|
360
|
+
// Read merged options: `--cwd`/`--api` after `generate install` are otherwise captured by the
|
|
361
|
+
// parent `generate` command (which declares the same options), leaving this subcommand's own opts
|
|
362
|
+
// undefined. `optsWithGlobals()` surfaces whichever level parsed them.
|
|
363
|
+
.action(async (jobId: string, _options, command: Command) => {
|
|
364
|
+
const { api, cwd } = command.optsWithGlobals()
|
|
365
|
+
await generateInstallCommand(jobId, { baseUrl: api, cwd })
|
|
366
|
+
})
|
|
367
|
+
|
|
368
|
+
return program
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
function addAuthCommands(program: Command, apiOption: Option): void {
|
|
372
|
+
program
|
|
373
|
+
.command('login')
|
|
374
|
+
.description('Sign in')
|
|
375
|
+
.addOption(apiOption)
|
|
376
|
+
.action(async (opts: { api?: string }) => {
|
|
377
|
+
const baseUrl = opts.api ?? DEFAULT_BASE_URL
|
|
378
|
+
const token = await runDeviceLogin()
|
|
379
|
+
const client = v1.createClient({ baseUrl, authToken: token })
|
|
380
|
+
const profile = await client.user.getProfile()
|
|
381
|
+
if (!profile) throw new Error('The Market API did not accept the auth token.')
|
|
382
|
+
|
|
383
|
+
if (opts.api) await saveConfig({ baseUrl: opts.api })
|
|
384
|
+
else await clearConfig()
|
|
385
|
+
await saveAuthToken(token)
|
|
386
|
+
console.log(loginResult(profile.email, getAuthConfigPath()))
|
|
387
|
+
})
|
|
388
|
+
|
|
389
|
+
program
|
|
390
|
+
.command('logout')
|
|
391
|
+
.description('Sign out')
|
|
392
|
+
.action(async () => {
|
|
393
|
+
await logout(await signOut())
|
|
394
|
+
})
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
function requireType(type: AssetType | undefined, command: string): asserts type is AssetType {
|
|
398
|
+
if (!type) {
|
|
399
|
+
throw new Error(`${command} requires --type. Available types: ${ASSET_TYPES.join(', ')}`)
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function parseSearchLimit(value: string): number {
|
|
404
|
+
const parsed = Number.parseInt(value, 10)
|
|
405
|
+
if (!Number.isInteger(parsed) || parsed < 1) {
|
|
406
|
+
throw new Error('--limit must be a positive integer')
|
|
407
|
+
}
|
|
408
|
+
return Math.min(parsed, 5)
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function readPackageVersion(): string {
|
|
412
|
+
const value: unknown = createRequire(import.meta.url)('../package.json')
|
|
413
|
+
if (
|
|
414
|
+
!value ||
|
|
415
|
+
typeof value !== 'object' ||
|
|
416
|
+
Array.isArray(value) ||
|
|
417
|
+
!('version' in value) ||
|
|
418
|
+
typeof value.version !== 'string'
|
|
419
|
+
) {
|
|
420
|
+
throw new Error('Market package.json is missing a valid version')
|
|
421
|
+
}
|
|
422
|
+
return value.version
|
|
423
|
+
}
|
package/src/commands/logout.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getConfigPath } from '@drawcall/auth'
|
|
2
|
+
import { clearConfig, getConfigPath as getMarketConfigPath } from '../config.js'
|
|
2
3
|
import { logoutResult } from '../output.js'
|
|
3
4
|
|
|
4
|
-
export async function logout(): Promise<void> {
|
|
5
|
-
const
|
|
6
|
-
if (
|
|
5
|
+
export async function logout(authExisted: boolean): Promise<void> {
|
|
6
|
+
const configExisted = await clearConfig()
|
|
7
|
+
if (authExisted) {
|
|
7
8
|
console.log(logoutResult(getConfigPath()))
|
|
8
|
-
|
|
9
|
-
console.log(logoutResult())
|
|
9
|
+
return
|
|
10
10
|
}
|
|
11
|
+
console.log(logoutResult(configExisted ? getMarketConfigPath() : undefined))
|
|
11
12
|
}
|
package/src/config.ts
CHANGED
|
@@ -4,12 +4,12 @@ import * as path from 'path'
|
|
|
4
4
|
import { z } from 'zod'
|
|
5
5
|
|
|
6
6
|
const rawConfigSchema = z.object({
|
|
7
|
-
authToken: z.string().min(1),
|
|
7
|
+
authToken: z.string().min(1).optional(),
|
|
8
8
|
baseUrl: z.string().url().optional(),
|
|
9
9
|
})
|
|
10
10
|
|
|
11
11
|
export interface Config {
|
|
12
|
-
authToken
|
|
12
|
+
authToken?: string
|
|
13
13
|
baseUrl?: string
|
|
14
14
|
}
|
|
15
15
|
|