@drawcall/market 0.1.4 → 0.1.6
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/asset-implementation.d.ts +88 -0
- package/dist/asset-implementation.d.ts.map +1 -0
- package/dist/asset-implementation.js +2 -0
- package/dist/asset-implementation.js.map +1 -0
- package/dist/cli-client.d.ts +2 -2
- package/dist/cli-client.d.ts.map +1 -1
- package/dist/cli-client.js +4 -4
- package/dist/cli-client.js.map +1 -1
- package/dist/cli.js +104 -22
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +1 -3
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +4 -12
- package/dist/client.js.map +1 -1
- package/dist/commands/generate.d.ts.map +1 -1
- package/dist/commands/generate.js +9 -4
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/install.d.ts.map +1 -1
- package/dist/commands/install.js +33 -27
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/logout.js +3 -3
- package/dist/commands/logout.js.map +1 -1
- package/dist/commands/preview.d.ts +9 -0
- package/dist/commands/preview.d.ts.map +1 -0
- package/dist/commands/preview.js +50 -0
- package/dist/commands/preview.js.map +1 -0
- package/dist/commands/search.d.ts +4 -1
- package/dist/commands/search.d.ts.map +1 -1
- package/dist/commands/search.js +21 -11
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/upload.d.ts +9 -0
- package/dist/commands/upload.d.ts.map +1 -0
- package/dist/commands/upload.js +220 -0
- package/dist/commands/upload.js.map +1 -0
- package/dist/config.d.ts +4 -7
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +8 -4
- package/dist/config.js.map +1 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +2 -10
- package/dist/constants.js.map +1 -1
- package/dist/contract.d.ts +37 -134
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +10 -48
- package/dist/contract.js.map +1 -1
- package/dist/generate.d.ts +0 -2
- package/dist/generate.d.ts.map +1 -1
- package/dist/generate.js +5 -22
- package/dist/generate.js.map +1 -1
- package/dist/index.d.ts +5 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -3
- package/dist/index.js.map +1 -1
- package/dist/install.d.ts +1 -1
- package/dist/install.d.ts.map +1 -1
- package/dist/install.js +14 -11
- package/dist/install.js.map +1 -1
- package/dist/output.d.ts +26 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +52 -0
- package/dist/output.js.map +1 -0
- package/dist/resolve.d.ts.map +1 -1
- package/dist/resolve.js +15 -26
- package/dist/resolve.js.map +1 -1
- package/dist/schemas.d.ts +31 -39
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +23 -25
- package/dist/schemas.js.map +1 -1
- package/package.json +13 -4
- package/src/asset-implementation.ts +114 -0
- package/src/cli-client.ts +7 -6
- package/src/cli.ts +144 -29
- package/src/client.ts +5 -15
- package/src/commands/generate.ts +9 -6
- package/src/commands/install.ts +41 -30
- package/src/commands/logout.ts +3 -3
- package/src/commands/preview.ts +69 -0
- package/src/commands/search.ts +28 -12
- package/src/commands/upload.ts +262 -0
- package/src/config.ts +11 -5
- package/src/constants.ts +2 -10
- package/src/contract.ts +22 -120
- package/src/generate.ts +5 -29
- package/src/index.ts +23 -14
- package/src/install.ts +24 -14
- package/src/output.ts +76 -0
- package/src/resolve.ts +22 -38
- package/src/schemas.ts +26 -27
- package/tsconfig.json +2 -1
- package/dist/commands/login.d.ts +0 -10
- package/dist/commands/login.d.ts.map +0 -1
- package/dist/commands/login.js +0 -92
- package/dist/commands/login.js.map +0 -1
- package/dist/internal-contract.d.ts +0 -19
- package/dist/internal-contract.d.ts.map +0 -1
- package/dist/internal-contract.js +0 -19
- package/dist/internal-contract.js.map +0 -1
- package/src/commands/login.ts +0 -113
- package/src/internal-contract.ts +0 -26
package/src/install.ts
CHANGED
|
@@ -6,15 +6,23 @@
|
|
|
6
6
|
* 3. Runs the package manager to install npm deps.
|
|
7
7
|
*
|
|
8
8
|
* NOTE: This module uses Node.js APIs (fs, path, nypm) and is only
|
|
9
|
-
* used by the CLI binary
|
|
9
|
+
* used by the CLI binary; it is NOT exported from the package index.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import * as fs from 'fs/promises'
|
|
13
13
|
import * as path from 'path'
|
|
14
|
+
import { unzipSync } from 'fflate'
|
|
14
15
|
import { detectPackageManager, installDependencies } from 'nypm'
|
|
15
16
|
import type { MarketClient } from './client.js'
|
|
16
17
|
import type { ResolveResult } from './resolve.js'
|
|
17
18
|
|
|
19
|
+
interface PackageJson {
|
|
20
|
+
name?: string
|
|
21
|
+
private?: boolean
|
|
22
|
+
dependencies?: Record<string, string>
|
|
23
|
+
[key: string]: unknown
|
|
24
|
+
}
|
|
25
|
+
|
|
18
26
|
export interface InstallOptions {
|
|
19
27
|
/** Project root directory (default: cwd) */
|
|
20
28
|
cwd?: string
|
|
@@ -49,25 +57,27 @@ async function downloadAssets(
|
|
|
49
57
|
|
|
50
58
|
log(`Downloading ${asset.name}@${asset.version}...`)
|
|
51
59
|
|
|
52
|
-
const
|
|
60
|
+
const zip = await client.asset.downloadZip({ name: asset.name, version: asset.version })
|
|
61
|
+
const files = unzipSync(new Uint8Array(await zip.arrayBuffer()))
|
|
53
62
|
|
|
54
|
-
for (const
|
|
55
|
-
const filePath = path.join(destDir,
|
|
63
|
+
for (const [relativePath, content] of Object.entries(files) as [string, Uint8Array][]) {
|
|
64
|
+
const filePath = path.join(destDir, relativePath)
|
|
65
|
+
if (!isInside(destDir, filePath)) {
|
|
66
|
+
throw new Error(`Zip contains an unsafe path: ${relativePath}`)
|
|
67
|
+
}
|
|
56
68
|
await fs.mkdir(path.dirname(filePath), { recursive: true })
|
|
57
|
-
|
|
58
|
-
const blob = await client.asset.getRawFile({
|
|
59
|
-
name: asset.name,
|
|
60
|
-
version: asset.version,
|
|
61
|
-
path: file.path,
|
|
62
|
-
})
|
|
63
|
-
const content = Buffer.from(await blob.arrayBuffer())
|
|
64
69
|
await fs.writeFile(filePath, content)
|
|
65
70
|
}
|
|
66
71
|
|
|
67
|
-
log(`
|
|
72
|
+
log(`Downloaded ${Object.keys(files).length} files to src/${asset.name}/`)
|
|
68
73
|
}
|
|
69
74
|
}
|
|
70
75
|
|
|
76
|
+
function isInside(root: string, target: string): boolean {
|
|
77
|
+
const relative = path.relative(root, target)
|
|
78
|
+
return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative))
|
|
79
|
+
}
|
|
80
|
+
|
|
71
81
|
async function installNpmDeps(
|
|
72
82
|
resolution: ResolveResult,
|
|
73
83
|
cwd: string,
|
|
@@ -78,9 +88,9 @@ async function installNpmDeps(
|
|
|
78
88
|
|
|
79
89
|
// Read existing package.json
|
|
80
90
|
const pkgPath = path.join(cwd, 'package.json')
|
|
81
|
-
let pkg:
|
|
91
|
+
let pkg: PackageJson
|
|
82
92
|
try {
|
|
83
|
-
pkg = JSON.parse(await fs.readFile(pkgPath, 'utf-8'))
|
|
93
|
+
pkg = JSON.parse(await fs.readFile(pkgPath, 'utf-8')) as PackageJson
|
|
84
94
|
} catch {
|
|
85
95
|
pkg = { name: 'my-project', private: true, dependencies: {} }
|
|
86
96
|
}
|
package/src/output.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { AssetSearchResult } from './contract.js'
|
|
2
|
+
|
|
3
|
+
export function assetVersionRef(name: string, version?: string): string {
|
|
4
|
+
return version ? `${name}@${version}` : name
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function assetApproval(approved: boolean): 'approved' | 'unapproved' {
|
|
8
|
+
return approved ? 'approved' : 'unapproved'
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function searchSummary(input: {
|
|
12
|
+
query: string
|
|
13
|
+
type: string
|
|
14
|
+
includeUnapproved: boolean
|
|
15
|
+
count: number
|
|
16
|
+
total: number
|
|
17
|
+
}): string {
|
|
18
|
+
const approval = input.includeUnapproved ? 'approved+unapproved' : 'approved'
|
|
19
|
+
const scope = `query="${input.query}" type=${input.type} approval=${approval}`
|
|
20
|
+
if (input.count === 0) {
|
|
21
|
+
return `No results: ${scope}`
|
|
22
|
+
}
|
|
23
|
+
return `Results: ${input.count}/${input.total} ${scope}`
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function assetSearchResultLine(
|
|
27
|
+
item: AssetSearchResult,
|
|
28
|
+
opts: { verbose?: boolean } = {},
|
|
29
|
+
): string {
|
|
30
|
+
const description = item.description
|
|
31
|
+
? ` | ${compact(item.description, opts.verbose ? 160 : 80)}`
|
|
32
|
+
: ''
|
|
33
|
+
return `- ${assetVersionRef(item.name, item.latestVersion)} | ${item.type} | ${assetApproval(
|
|
34
|
+
item.approved,
|
|
35
|
+
)}${description}`
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function installResult(assetVersions: Array<{ name: string; version: string }>): string {
|
|
39
|
+
const label = assetVersions.length === 1 ? 'asset' : 'assets'
|
|
40
|
+
return `Installed ${assetVersions.length} ${label}: ${assetVersions
|
|
41
|
+
.map((asset) => assetVersionRef(asset.name, asset.version))
|
|
42
|
+
.join(', ')}`
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function generatedInstallResult(name: string, version: string): string {
|
|
46
|
+
return `Generated and installed ${assetVersionRef(name, version)}`
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function uploadResult(name: string, version: string): string {
|
|
50
|
+
return `Uploaded ${assetVersionRef(name, version)}`
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function unchangedUploadResult(name: string, version: string): string {
|
|
54
|
+
return `No upload needed: ${assetVersionRef(name, version)} is unchanged`
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function previewResult(name: string, version: string, out: string): string {
|
|
58
|
+
return `Saved preview for ${assetVersionRef(name, version)}: ${out}`
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function loginResult(email: string, configPath: string): string {
|
|
62
|
+
return `Logged in as ${email} (config: ${configPath})`
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function logoutResult(configPath?: string): string {
|
|
66
|
+
return configPath ? `Logged out (removed ${configPath})` : 'Already logged out'
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function errorResult(message: string): string {
|
|
70
|
+
return `Error: ${message}`
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function compact(value: string, max = 96): string {
|
|
74
|
+
const normalized = value.replace(/\s+/g, ' ').trim()
|
|
75
|
+
return normalized.length > max ? normalized.slice(0, max - 3) + '...' : normalized
|
|
76
|
+
}
|
package/src/resolve.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import * as semver from 'semver'
|
|
12
12
|
import type { MarketClient } from './client.js'
|
|
13
|
-
import type {
|
|
13
|
+
import type { AssetSearchResult } from './contract.js'
|
|
14
14
|
|
|
15
15
|
export interface ResolvedAsset {
|
|
16
16
|
name: string
|
|
@@ -41,71 +41,51 @@ export async function resolve(
|
|
|
41
41
|
requests: AssetRequest[],
|
|
42
42
|
opts: { includeUnapproved?: boolean } = {},
|
|
43
43
|
): Promise<ResolveResult> {
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
// Seed constraints from the requested assets
|
|
52
|
-
for (const req of requests) {
|
|
53
|
-
addConstraint(constraints, req.name, req.range, '<root>')
|
|
44
|
+
const constraints = new Map<string, { range: string; from: string }[]>()
|
|
45
|
+
const resolved = new Map<string, ResolvedAsset>()
|
|
46
|
+
const metaCache = new Map<string, AssetSearchResult>()
|
|
47
|
+
|
|
48
|
+
for (const request of requests) {
|
|
49
|
+
addConstraint(constraints, request.name, request.range, '<root>')
|
|
54
50
|
}
|
|
55
51
|
|
|
56
|
-
// Iteratively resolve until stable
|
|
57
52
|
let unresolved = getUnresolved(constraints, resolved)
|
|
58
53
|
while (unresolved.length > 0) {
|
|
59
54
|
for (const assetName of unresolved) {
|
|
60
|
-
const meta = await fetchMeta(client, metaCache, assetName)
|
|
55
|
+
const meta = await fetchMeta(client, metaCache, assetName, opts.includeUnapproved ?? false)
|
|
61
56
|
if (!meta) {
|
|
62
57
|
throw new ResolutionError(`Asset "${assetName}" not found.`)
|
|
63
58
|
}
|
|
64
59
|
|
|
65
|
-
|
|
66
|
-
const candidates = meta.versions.filter((v) => opts.includeUnapproved || v.approved)
|
|
67
|
-
|
|
68
|
-
if (candidates.length === 0) {
|
|
60
|
+
if (!opts.includeUnapproved && !meta.approved) {
|
|
69
61
|
throw new ResolutionError(
|
|
70
62
|
`Asset "${assetName}" has no ${opts.includeUnapproved ? '' : 'approved '}versions.`,
|
|
71
63
|
)
|
|
72
64
|
}
|
|
73
65
|
|
|
74
|
-
// Collect all constraints for this asset
|
|
75
66
|
const assetConstraints = constraints.get(assetName) ?? []
|
|
76
|
-
|
|
77
|
-
// Find the best (highest) version that satisfies ALL constraints
|
|
78
|
-
const candidateVersions = candidates.map((c) => c.version)
|
|
79
|
-
const satisfying = candidateVersions.filter((v) =>
|
|
80
|
-
assetConstraints.every((c) => semver.satisfies(v, c.range)),
|
|
81
|
-
)
|
|
82
|
-
|
|
83
|
-
if (satisfying.length === 0) {
|
|
67
|
+
if (!assetConstraints.every((c) => semver.satisfies(meta.latestVersion, c.range))) {
|
|
84
68
|
const constraintDesc = assetConstraints
|
|
85
69
|
.map((c) => ` ${c.range} (from ${c.from})`)
|
|
86
70
|
.join('\n')
|
|
87
71
|
throw new ResolutionError(
|
|
88
72
|
`No version of "${assetName}" satisfies all constraints:\n${constraintDesc}\n` +
|
|
89
|
-
`Available${opts.includeUnapproved ? '' : ' approved'}: ${
|
|
73
|
+
`Available${opts.includeUnapproved ? '' : ' approved'}: ${meta.latestVersion}`,
|
|
90
74
|
)
|
|
91
75
|
}
|
|
92
76
|
|
|
93
|
-
const
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
const npmDeps: Record<string, string> = JSON.parse(versionMeta.npmDependencies)
|
|
97
|
-
const assetDeps: Record<string, string> = JSON.parse(versionMeta.assetDependencies)
|
|
77
|
+
const npmDeps: Record<string, string> = JSON.parse(meta.npmDependencies)
|
|
78
|
+
const assetDeps: Record<string, string> = JSON.parse(meta.assetDependencies)
|
|
98
79
|
|
|
99
80
|
resolved.set(assetName, {
|
|
100
81
|
name: assetName,
|
|
101
|
-
version:
|
|
82
|
+
version: meta.latestVersion,
|
|
102
83
|
npmDependencies: npmDeps,
|
|
103
84
|
assetDependencies: assetDeps,
|
|
104
85
|
})
|
|
105
86
|
|
|
106
|
-
// Add transitive asset dependency constraints
|
|
107
87
|
for (const [depName, depRange] of Object.entries(assetDeps)) {
|
|
108
|
-
addConstraint(constraints, depName, depRange, `${assetName}@${
|
|
88
|
+
addConstraint(constraints, depName, depRange, `${assetName}@${meta.latestVersion}`)
|
|
109
89
|
}
|
|
110
90
|
}
|
|
111
91
|
|
|
@@ -155,11 +135,15 @@ function getUnresolved(
|
|
|
155
135
|
|
|
156
136
|
async function fetchMeta(
|
|
157
137
|
client: MarketClient['asset'],
|
|
158
|
-
cache: Map<string,
|
|
138
|
+
cache: Map<string, AssetSearchResult>,
|
|
159
139
|
name: string,
|
|
160
|
-
|
|
140
|
+
includeUnapproved: boolean,
|
|
141
|
+
): Promise<AssetSearchResult | null> {
|
|
161
142
|
if (cache.has(name)) return cache.get(name)!
|
|
162
|
-
const meta = await client.
|
|
143
|
+
const meta = await client.exact({
|
|
144
|
+
name,
|
|
145
|
+
includeUnapproved,
|
|
146
|
+
})
|
|
163
147
|
if (meta) cache.set(name, meta)
|
|
164
148
|
return meta
|
|
165
149
|
}
|
package/src/schemas.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
2
|
|
|
3
|
-
export const ASSET_TYPES = ['
|
|
3
|
+
export const ASSET_TYPES = ['model'] as const
|
|
4
4
|
export type AssetType = (typeof ASSET_TYPES)[number]
|
|
5
5
|
|
|
6
6
|
export const assetTypeSchema = z.enum(ASSET_TYPES)
|
|
@@ -28,8 +28,29 @@ export const npmDependenciesSchema = z.record(z.string(), z.string()).default({}
|
|
|
28
28
|
|
|
29
29
|
export const assetDependenciesSchema = z.record(z.string(), z.string()).default({})
|
|
30
30
|
|
|
31
|
-
export const
|
|
31
|
+
export const updateProfileSchema = z.object({
|
|
32
|
+
name: z.string().min(1).max(100).optional(),
|
|
33
|
+
image: z.string().url().optional(),
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
export const listAssetsSchema = z.object({
|
|
37
|
+
page: z.number().int().min(1).default(1),
|
|
38
|
+
limit: z.number().int().min(1).max(100).default(20),
|
|
39
|
+
type: assetTypeSchema.optional(),
|
|
40
|
+
query: z.string().max(200).optional(),
|
|
41
|
+
includeUnapproved: z.boolean().default(false),
|
|
42
|
+
sort: z.enum(['newest', 'alphabetical', 'relevance']).default('newest'),
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
export const exactAssetSchema = z.object({
|
|
32
46
|
name: assetNameSchema,
|
|
47
|
+
type: assetTypeSchema.optional(),
|
|
48
|
+
includeUnapproved: z.boolean().default(false),
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
export const uploadZipSchema = z.object({
|
|
52
|
+
name: assetNameSchema,
|
|
53
|
+
type: assetTypeSchema,
|
|
33
54
|
version: semverSchema,
|
|
34
55
|
description: z.string().max(1000).optional(),
|
|
35
56
|
npmDependencies: npmDependenciesSchema,
|
|
@@ -37,34 +58,12 @@ export const uploadGenericSchema = z.object({
|
|
|
37
58
|
tags: z.array(z.string()).default([]),
|
|
38
59
|
})
|
|
39
60
|
|
|
40
|
-
export const
|
|
61
|
+
export const downloadZipSchema = z.object({
|
|
41
62
|
name: assetNameSchema,
|
|
42
63
|
version: semverSchema,
|
|
43
|
-
description: z.string().max(1000).optional(),
|
|
44
|
-
tags: z.array(z.string()).default([]),
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
export const uploadMaterialSchema = uploadTypedSchema.extend({
|
|
48
|
-
properties: z.object({
|
|
49
|
-
color: z.string().default('#ffffff'),
|
|
50
|
-
roughness: z.number().min(0).max(1).default(0.5),
|
|
51
|
-
metalness: z.number().min(0).max(1).default(0),
|
|
52
|
-
normalScale: z.number().min(0).max(2).default(1),
|
|
53
|
-
emissive: z.string().default('#000000'),
|
|
54
|
-
emissiveIntensity: z.number().min(0).max(10).default(0),
|
|
55
|
-
}),
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
export const updateProfileSchema = z.object({
|
|
59
|
-
name: z.string().min(1).max(100).optional(),
|
|
60
|
-
image: z.string().url().optional(),
|
|
61
64
|
})
|
|
62
65
|
|
|
63
|
-
export const
|
|
64
|
-
|
|
65
|
-
limit: z.number().int().min(1).max(100).default(20),
|
|
66
|
+
export const generateAssetSchema = z.object({
|
|
67
|
+
description: z.string().min(3).max(1000),
|
|
66
68
|
type: assetTypeSchema.optional(),
|
|
67
|
-
tag: z.string().optional(),
|
|
68
|
-
search: z.string().max(200).optional(),
|
|
69
|
-
sort: z.enum(['newest', 'alphabetical', 'relevance']).default('newest'),
|
|
70
69
|
})
|
package/tsconfig.json
CHANGED
package/dist/commands/login.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export interface LoginOptions {
|
|
2
|
-
baseUrl: string;
|
|
3
|
-
timeoutMs?: number;
|
|
4
|
-
}
|
|
5
|
-
/**
|
|
6
|
-
* Spins up a localhost HTTP server, opens the browser to {baseUrl}/cli-auth,
|
|
7
|
-
* waits for the web app to redirect back with the key, saves it to config.
|
|
8
|
-
*/
|
|
9
|
-
export declare function login(opts: LoginOptions): Promise<void>;
|
|
10
|
-
//# sourceMappingURL=login.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;GAGG;AACH,wBAAsB,KAAK,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAiC7D"}
|
package/dist/commands/login.js
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import * as http from 'http';
|
|
2
|
-
import chalk from 'chalk';
|
|
3
|
-
import open from 'open';
|
|
4
|
-
import ora from 'ora';
|
|
5
|
-
import { createMarketClient } from '../client.js';
|
|
6
|
-
import { saveConfig, getConfigPath } from '../config.js';
|
|
7
|
-
/**
|
|
8
|
-
* Spins up a localhost HTTP server, opens the browser to {baseUrl}/cli-auth,
|
|
9
|
-
* waits for the web app to redirect back with the key, saves it to config.
|
|
10
|
-
*/
|
|
11
|
-
export async function login(opts) {
|
|
12
|
-
const timeoutMs = opts.timeoutMs ?? 120_000;
|
|
13
|
-
const state = crypto.randomUUID();
|
|
14
|
-
const { port, waitForKey, close } = await startCallbackServer(state, timeoutMs);
|
|
15
|
-
const authUrl = new URL('/cli-auth', opts.baseUrl);
|
|
16
|
-
authUrl.searchParams.set('state', state);
|
|
17
|
-
authUrl.searchParams.set('callback', `http://127.0.0.1:${port}/callback`);
|
|
18
|
-
console.log(chalk.dim(`If your browser doesn't open, visit:\n ${authUrl.toString()}`));
|
|
19
|
-
await open(authUrl.toString()).catch(() => { });
|
|
20
|
-
const spinner = ora('Waiting for browser approval…').start();
|
|
21
|
-
try {
|
|
22
|
-
const key = await waitForKey;
|
|
23
|
-
spinner.text = 'Verifying key…';
|
|
24
|
-
const verifyClient = createMarketClient({ baseUrl: opts.baseUrl, apiKey: key });
|
|
25
|
-
const profile = await verifyClient.user.getProfile();
|
|
26
|
-
if (!profile) {
|
|
27
|
-
throw new Error('Key was not accepted by the server.');
|
|
28
|
-
}
|
|
29
|
-
await saveConfig({ apiKey: key, baseUrl: opts.baseUrl });
|
|
30
|
-
spinner.succeed(`Logged in as ${chalk.cyan(profile.email)}`);
|
|
31
|
-
console.log(chalk.dim(` Key saved to ${getConfigPath()}`));
|
|
32
|
-
}
|
|
33
|
-
catch (err) {
|
|
34
|
-
spinner.fail(err instanceof Error ? err.message : String(err));
|
|
35
|
-
throw err;
|
|
36
|
-
}
|
|
37
|
-
finally {
|
|
38
|
-
close();
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
async function startCallbackServer(expectedState, timeoutMs) {
|
|
42
|
-
let resolveKey;
|
|
43
|
-
let rejectKey;
|
|
44
|
-
const waitForKey = new Promise((resolve, reject) => {
|
|
45
|
-
resolveKey = resolve;
|
|
46
|
-
rejectKey = reject;
|
|
47
|
-
});
|
|
48
|
-
const server = http.createServer((req, res) => {
|
|
49
|
-
if (!req.url) {
|
|
50
|
-
res.writeHead(400).end();
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
const url = new URL(req.url, 'http://localhost');
|
|
54
|
-
if (url.pathname !== '/callback') {
|
|
55
|
-
res.writeHead(404).end();
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
const receivedState = url.searchParams.get('state');
|
|
59
|
-
const receivedKey = url.searchParams.get('key');
|
|
60
|
-
if (receivedState !== expectedState) {
|
|
61
|
-
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
62
|
-
res.end('<h1>Invalid state</h1><p>You can close this window.</p>');
|
|
63
|
-
rejectKey(new Error('Invalid state parameter from callback.'));
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
if (!receivedKey) {
|
|
67
|
-
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
68
|
-
res.end('<h1>Missing key</h1><p>You can close this window.</p>');
|
|
69
|
-
rejectKey(new Error('Callback did not include a key.'));
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
73
|
-
res.end('<h1>Logged in!</h1><p>You can close this window.</p>');
|
|
74
|
-
resolveKey(receivedKey);
|
|
75
|
-
});
|
|
76
|
-
await new Promise((resolve, reject) => {
|
|
77
|
-
server.once('error', reject);
|
|
78
|
-
server.listen(0, '127.0.0.1', () => resolve());
|
|
79
|
-
});
|
|
80
|
-
const address = server.address();
|
|
81
|
-
if (!address)
|
|
82
|
-
throw new Error('Failed to bind local callback server.');
|
|
83
|
-
const timer = setTimeout(() => {
|
|
84
|
-
rejectKey(new Error(`Timed out after ${timeoutMs / 1000}s waiting for browser approval.`));
|
|
85
|
-
}, timeoutMs);
|
|
86
|
-
const close = () => {
|
|
87
|
-
clearTimeout(timer);
|
|
88
|
-
server.close();
|
|
89
|
-
};
|
|
90
|
-
return { port: address.port, waitForKey, close };
|
|
91
|
-
}
|
|
92
|
-
//# sourceMappingURL=login.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
export declare const internalContract: {
|
|
3
|
-
buildUpload: import("@orpc/contract").ContractProcedureBuilderWithInputOutput<z.ZodObject<{
|
|
4
|
-
key: z.ZodString;
|
|
5
|
-
content: z.ZodString;
|
|
6
|
-
contentType: z.ZodString;
|
|
7
|
-
}, z.core.$strip>, z.ZodObject<{
|
|
8
|
-
ok: z.ZodBoolean;
|
|
9
|
-
}, z.core.$strip>, Record<never, never>, Record<never, never>>;
|
|
10
|
-
buildComplete: import("@orpc/contract").ContractProcedureBuilderWithInputOutput<z.ZodObject<{
|
|
11
|
-
assetName: z.ZodString;
|
|
12
|
-
version: z.ZodString;
|
|
13
|
-
buildOutputKey: z.ZodString;
|
|
14
|
-
}, z.core.$strip>, z.ZodObject<{
|
|
15
|
-
ok: z.ZodBoolean;
|
|
16
|
-
}, z.core.$strip>, Record<never, never>, Record<never, never>>;
|
|
17
|
-
};
|
|
18
|
-
export type InternalContract = typeof internalContract;
|
|
19
|
-
//# sourceMappingURL=internal-contract.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"internal-contract.d.ts","sourceRoot":"","sources":["../src/internal-contract.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;CAoB5B,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG,OAAO,gBAAgB,CAAA"}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { oc } from '@orpc/contract';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
export const internalContract = {
|
|
4
|
-
buildUpload: oc
|
|
5
|
-
.input(z.object({
|
|
6
|
-
key: z.string(),
|
|
7
|
-
content: z.string(), // base64-encoded
|
|
8
|
-
contentType: z.string(),
|
|
9
|
-
}))
|
|
10
|
-
.output(z.object({ ok: z.boolean() })),
|
|
11
|
-
buildComplete: oc
|
|
12
|
-
.input(z.object({
|
|
13
|
-
assetName: z.string(),
|
|
14
|
-
version: z.string(),
|
|
15
|
-
buildOutputKey: z.string(),
|
|
16
|
-
}))
|
|
17
|
-
.output(z.object({ ok: z.boolean() })),
|
|
18
|
-
};
|
|
19
|
-
//# sourceMappingURL=internal-contract.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"internal-contract.js","sourceRoot":"","sources":["../src/internal-contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAA;AACnC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,WAAW,EAAE,EAAE;SACZ,KAAK,CACJ,CAAC,CAAC,MAAM,CAAC;QACP,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE;QACf,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,iBAAiB;QACtC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;KACxB,CAAC,CACH;SACA,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAExC,aAAa,EAAE,EAAE;SACd,KAAK,CACJ,CAAC,CAAC,MAAM,CAAC;QACP,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;QACrB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;QACnB,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE;KAC3B,CAAC,CACH;SACA,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;CACzC,CAAA"}
|
package/src/commands/login.ts
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import * as http from 'http'
|
|
2
|
-
import type { AddressInfo } from 'net'
|
|
3
|
-
import chalk from 'chalk'
|
|
4
|
-
import open from 'open'
|
|
5
|
-
import ora from 'ora'
|
|
6
|
-
import { createMarketClient } from '../client.js'
|
|
7
|
-
import { saveConfig, getConfigPath } from '../config.js'
|
|
8
|
-
|
|
9
|
-
export interface LoginOptions {
|
|
10
|
-
baseUrl: string
|
|
11
|
-
timeoutMs?: number
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Spins up a localhost HTTP server, opens the browser to {baseUrl}/cli-auth,
|
|
16
|
-
* waits for the web app to redirect back with the key, saves it to config.
|
|
17
|
-
*/
|
|
18
|
-
export async function login(opts: LoginOptions): Promise<void> {
|
|
19
|
-
const timeoutMs = opts.timeoutMs ?? 120_000
|
|
20
|
-
const state = crypto.randomUUID()
|
|
21
|
-
|
|
22
|
-
const { port, waitForKey, close } = await startCallbackServer(state, timeoutMs)
|
|
23
|
-
|
|
24
|
-
const authUrl = new URL('/cli-auth', opts.baseUrl)
|
|
25
|
-
authUrl.searchParams.set('state', state)
|
|
26
|
-
authUrl.searchParams.set('callback', `http://127.0.0.1:${port}/callback`)
|
|
27
|
-
|
|
28
|
-
console.log(chalk.dim(`If your browser doesn't open, visit:\n ${authUrl.toString()}`))
|
|
29
|
-
await open(authUrl.toString()).catch(() => {})
|
|
30
|
-
|
|
31
|
-
const spinner = ora('Waiting for browser approval…').start()
|
|
32
|
-
try {
|
|
33
|
-
const key = await waitForKey
|
|
34
|
-
|
|
35
|
-
spinner.text = 'Verifying key…'
|
|
36
|
-
const verifyClient = createMarketClient({ baseUrl: opts.baseUrl, apiKey: key })
|
|
37
|
-
const profile = await verifyClient.user.getProfile()
|
|
38
|
-
if (!profile) {
|
|
39
|
-
throw new Error('Key was not accepted by the server.')
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
await saveConfig({ apiKey: key, baseUrl: opts.baseUrl })
|
|
43
|
-
spinner.succeed(`Logged in as ${chalk.cyan(profile.email)}`)
|
|
44
|
-
console.log(chalk.dim(` Key saved to ${getConfigPath()}`))
|
|
45
|
-
} catch (err) {
|
|
46
|
-
spinner.fail(err instanceof Error ? err.message : String(err))
|
|
47
|
-
throw err
|
|
48
|
-
} finally {
|
|
49
|
-
close()
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async function startCallbackServer(
|
|
54
|
-
expectedState: string,
|
|
55
|
-
timeoutMs: number,
|
|
56
|
-
): Promise<{ port: number; waitForKey: Promise<string>; close: () => void }> {
|
|
57
|
-
let resolveKey!: (k: string) => void
|
|
58
|
-
let rejectKey!: (e: Error) => void
|
|
59
|
-
const waitForKey = new Promise<string>((resolve, reject) => {
|
|
60
|
-
resolveKey = resolve
|
|
61
|
-
rejectKey = reject
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
const server = http.createServer((req, res) => {
|
|
65
|
-
if (!req.url) {
|
|
66
|
-
res.writeHead(400).end()
|
|
67
|
-
return
|
|
68
|
-
}
|
|
69
|
-
const url = new URL(req.url, 'http://localhost')
|
|
70
|
-
if (url.pathname !== '/callback') {
|
|
71
|
-
res.writeHead(404).end()
|
|
72
|
-
return
|
|
73
|
-
}
|
|
74
|
-
const receivedState = url.searchParams.get('state')
|
|
75
|
-
const receivedKey = url.searchParams.get('key')
|
|
76
|
-
|
|
77
|
-
if (receivedState !== expectedState) {
|
|
78
|
-
res.writeHead(400, { 'Content-Type': 'text/html' })
|
|
79
|
-
res.end('<h1>Invalid state</h1><p>You can close this window.</p>')
|
|
80
|
-
rejectKey(new Error('Invalid state parameter from callback.'))
|
|
81
|
-
return
|
|
82
|
-
}
|
|
83
|
-
if (!receivedKey) {
|
|
84
|
-
res.writeHead(400, { 'Content-Type': 'text/html' })
|
|
85
|
-
res.end('<h1>Missing key</h1><p>You can close this window.</p>')
|
|
86
|
-
rejectKey(new Error('Callback did not include a key.'))
|
|
87
|
-
return
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
res.writeHead(200, { 'Content-Type': 'text/html' })
|
|
91
|
-
res.end('<h1>Logged in!</h1><p>You can close this window.</p>')
|
|
92
|
-
resolveKey(receivedKey)
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
await new Promise<void>((resolve, reject) => {
|
|
96
|
-
server.once('error', reject)
|
|
97
|
-
server.listen(0, '127.0.0.1', () => resolve())
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
const address = server.address() as AddressInfo | null
|
|
101
|
-
if (!address) throw new Error('Failed to bind local callback server.')
|
|
102
|
-
|
|
103
|
-
const timer = setTimeout(() => {
|
|
104
|
-
rejectKey(new Error(`Timed out after ${timeoutMs / 1000}s waiting for browser approval.`))
|
|
105
|
-
}, timeoutMs)
|
|
106
|
-
|
|
107
|
-
const close = () => {
|
|
108
|
-
clearTimeout(timer)
|
|
109
|
-
server.close()
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return { port: address.port, waitForKey, close }
|
|
113
|
-
}
|
package/src/internal-contract.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { oc } from '@orpc/contract'
|
|
2
|
-
import { z } from 'zod'
|
|
3
|
-
|
|
4
|
-
export const internalContract = {
|
|
5
|
-
buildUpload: oc
|
|
6
|
-
.input(
|
|
7
|
-
z.object({
|
|
8
|
-
key: z.string(),
|
|
9
|
-
content: z.string(), // base64-encoded
|
|
10
|
-
contentType: z.string(),
|
|
11
|
-
}),
|
|
12
|
-
)
|
|
13
|
-
.output(z.object({ ok: z.boolean() })),
|
|
14
|
-
|
|
15
|
-
buildComplete: oc
|
|
16
|
-
.input(
|
|
17
|
-
z.object({
|
|
18
|
-
assetName: z.string(),
|
|
19
|
-
version: z.string(),
|
|
20
|
-
buildOutputKey: z.string(),
|
|
21
|
-
}),
|
|
22
|
-
)
|
|
23
|
-
.output(z.object({ ok: z.boolean() })),
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export type InternalContract = typeof internalContract
|