@curviate/cli 0.1.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.
- package/CHANGELOG.md +22 -0
- package/LICENSE +21 -0
- package/README.md +174 -0
- package/dist/account-YOW2MCZS.js +639 -0
- package/dist/chunk-2NCPJJPC.js +140 -0
- package/dist/chunk-6JNCLLNY.js +195 -0
- package/dist/chunk-BNUTM6KD.js +33 -0
- package/dist/chunk-Q43HZUN3.js +29 -0
- package/dist/chunk-R3VLWLVV.js +23 -0
- package/dist/chunk-SND3NHCT.js +46 -0
- package/dist/chunk-UWO2D4HW.js +34 -0
- package/dist/cli.js +159 -0
- package/dist/company-IKVDW7MX.js +82 -0
- package/dist/config-4JOXBFYX.js +262 -0
- package/dist/connect-HLDHFBGX.js +348 -0
- package/dist/exit-codes-NFIR57ZA.js +57 -0
- package/dist/inbox-JBLYJMV2.js +294 -0
- package/dist/login-VWJEBBFU.js +122 -0
- package/dist/message-IK7VGB63.js +566 -0
- package/dist/post-EAAGVR5D.js +496 -0
- package/dist/profile-WXA3NC7D.js +352 -0
- package/dist/recruiter-TGCV36EH.js +984 -0
- package/dist/sales-nav-XGFO5I6F.js +488 -0
- package/dist/search-LHPTHPWH.js +354 -0
- package/dist/webhook-QM5LGAUF.js +445 -0
- package/package.json +54 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
readConfig
|
|
4
|
+
} from "./chunk-6JNCLLNY.js";
|
|
5
|
+
|
|
6
|
+
// src/lib/resolve.ts
|
|
7
|
+
var DEFAULT_BASE_URL = "https://api.curviate.com";
|
|
8
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
9
|
+
async function resolveEffectiveConfig(flags) {
|
|
10
|
+
const cfg = await readConfig();
|
|
11
|
+
const profileName = flags.profile ?? (cfg?.active ?? "default");
|
|
12
|
+
const profile = cfg?.profiles[profileName];
|
|
13
|
+
const apiKey = flags.apiKey ?? process.env["CURVIATE_API_KEY"] ?? profile?.apiKey ?? void 0;
|
|
14
|
+
const baseUrl = flags.baseUrl ?? process.env["CURVIATE_BASE_URL"] ?? profile?.baseUrl ?? DEFAULT_BASE_URL;
|
|
15
|
+
const timeoutFlag = flags.timeout !== void 0 ? parseInt(flags.timeout, 10) : void 0;
|
|
16
|
+
const timeout = timeoutFlag ?? profile?.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
17
|
+
const account = flags.account ?? process.env["CURVIATE_ACCOUNT"] ?? profile?.account ?? void 0;
|
|
18
|
+
return { apiKey, baseUrl, timeout, account };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// src/lib/client.ts
|
|
22
|
+
import { Curviate } from "@curviate/sdk";
|
|
23
|
+
function createClient(config) {
|
|
24
|
+
return new Curviate({
|
|
25
|
+
apiKey: config.apiKey.trim(),
|
|
26
|
+
...config.baseUrl !== void 0 ? { baseUrl: config.baseUrl } : {},
|
|
27
|
+
...config.timeout !== void 0 ? { timeout: config.timeout } : {}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// src/lib/output.ts
|
|
32
|
+
function isJsonMode(opts) {
|
|
33
|
+
return opts.json || !opts.isTTY;
|
|
34
|
+
}
|
|
35
|
+
function projectFields(obj, fields) {
|
|
36
|
+
if (fields.length === 0) return obj;
|
|
37
|
+
const result = {};
|
|
38
|
+
for (const field of fields) {
|
|
39
|
+
const parts = field.split(".");
|
|
40
|
+
let value = obj;
|
|
41
|
+
for (const part of parts) {
|
|
42
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
43
|
+
value = value[part];
|
|
44
|
+
} else {
|
|
45
|
+
value = void 0;
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (value !== void 0) {
|
|
50
|
+
result[field] = value;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
function applyProjection(data, fields) {
|
|
56
|
+
if (fields.length === 0) return data;
|
|
57
|
+
if (Array.isArray(data)) {
|
|
58
|
+
return data.map(
|
|
59
|
+
(item) => typeof item === "object" && item !== null ? projectFields(item, fields) : item
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
if (typeof data === "object" && data !== null) {
|
|
63
|
+
const obj = data;
|
|
64
|
+
if (Array.isArray(obj["items"])) {
|
|
65
|
+
return {
|
|
66
|
+
...obj,
|
|
67
|
+
items: obj["items"].map(
|
|
68
|
+
(item) => typeof item === "object" && item !== null ? projectFields(item, fields) : item
|
|
69
|
+
)
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
return projectFields(obj, fields);
|
|
73
|
+
}
|
|
74
|
+
return data;
|
|
75
|
+
}
|
|
76
|
+
function renderSuccess(data, opts, out) {
|
|
77
|
+
const json = isJsonMode(opts);
|
|
78
|
+
const fields = opts.fields ? opts.fields.split(",").map((f) => f.trim()).filter(Boolean) : [];
|
|
79
|
+
const projected = applyProjection(data, fields);
|
|
80
|
+
if (json) {
|
|
81
|
+
out.stdout.write(JSON.stringify(projected) + "\n");
|
|
82
|
+
} else {
|
|
83
|
+
out.stdout.write(renderHuman(projected) + "\n");
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function renderHuman(data) {
|
|
87
|
+
if (data === null || data === void 0) return "(empty)";
|
|
88
|
+
if (typeof data === "object" && !Array.isArray(data)) {
|
|
89
|
+
const obj = data;
|
|
90
|
+
if (Array.isArray(obj["items"])) {
|
|
91
|
+
const items = obj["items"];
|
|
92
|
+
if (items.length === 0) return "(no items)";
|
|
93
|
+
return items.map(renderHuman).join("\n");
|
|
94
|
+
}
|
|
95
|
+
return Object.entries(obj).map(([k, v]) => `${k}: ${typeof v === "object" ? JSON.stringify(v) : String(v)}`).join("\n");
|
|
96
|
+
}
|
|
97
|
+
if (Array.isArray(data)) {
|
|
98
|
+
return data.map(renderHuman).join("\n");
|
|
99
|
+
}
|
|
100
|
+
return String(data);
|
|
101
|
+
}
|
|
102
|
+
function renderError(err, opts, out) {
|
|
103
|
+
const json = isJsonMode(opts);
|
|
104
|
+
const errJson = err.toJSON();
|
|
105
|
+
if (json) {
|
|
106
|
+
out.stdout.write(JSON.stringify({ error: errJson }) + "\n");
|
|
107
|
+
out.stderr.write(
|
|
108
|
+
`error [${errJson.code}] ${errJson.message}
|
|
109
|
+
`
|
|
110
|
+
);
|
|
111
|
+
} else {
|
|
112
|
+
let msg = `Error: [${errJson.code}] ${errJson.message}`;
|
|
113
|
+
if (errJson.requiredTier) {
|
|
114
|
+
msg += `
|
|
115
|
+
Required tier: ${errJson.requiredTier}`;
|
|
116
|
+
}
|
|
117
|
+
if (errJson.retryAfterMs) {
|
|
118
|
+
msg += `
|
|
119
|
+
Retry after: ${errJson.retryAfterMs}ms`;
|
|
120
|
+
}
|
|
121
|
+
if (errJson.retryHint && errJson.retryHint.kind !== "never") {
|
|
122
|
+
msg += `
|
|
123
|
+
Hint: ${errJson.retryHint.kind}`;
|
|
124
|
+
}
|
|
125
|
+
out.stderr.write(msg + "\n");
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function renderUnexpectedError(err, out) {
|
|
129
|
+
const message = err instanceof Error ? err.message : "An unexpected error occurred.";
|
|
130
|
+
out.stderr.write(`Internal error: ${message}
|
|
131
|
+
`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export {
|
|
135
|
+
resolveEffectiveConfig,
|
|
136
|
+
createClient,
|
|
137
|
+
renderSuccess,
|
|
138
|
+
renderError,
|
|
139
|
+
renderUnexpectedError
|
|
140
|
+
};
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/lib/config.ts
|
|
4
|
+
import {
|
|
5
|
+
readFile,
|
|
6
|
+
writeFile,
|
|
7
|
+
mkdir,
|
|
8
|
+
rename,
|
|
9
|
+
chmod,
|
|
10
|
+
unlink
|
|
11
|
+
} from "fs/promises";
|
|
12
|
+
import { join, dirname } from "path";
|
|
13
|
+
import { homedir, tmpdir } from "os";
|
|
14
|
+
import { randomBytes } from "crypto";
|
|
15
|
+
function getConfigPath() {
|
|
16
|
+
const xdg = process.env["XDG_CONFIG_HOME"] ?? (process.env["APPDATA"] ?? join(homedir(), ".config"));
|
|
17
|
+
return join(xdg, "curviate", "config.json");
|
|
18
|
+
}
|
|
19
|
+
async function readConfig() {
|
|
20
|
+
const cfgPath = getConfigPath();
|
|
21
|
+
let raw;
|
|
22
|
+
try {
|
|
23
|
+
raw = await readFile(cfgPath, "utf8");
|
|
24
|
+
} catch (err) {
|
|
25
|
+
const e = err;
|
|
26
|
+
if (e.code === "ENOENT") return null;
|
|
27
|
+
throw err;
|
|
28
|
+
}
|
|
29
|
+
return JSON.parse(raw);
|
|
30
|
+
}
|
|
31
|
+
async function writeConfig(cfg) {
|
|
32
|
+
const cfgPath = getConfigPath();
|
|
33
|
+
const cfgDir = dirname(cfgPath);
|
|
34
|
+
await mkdir(cfgDir, { recursive: true, mode: 448 });
|
|
35
|
+
try {
|
|
36
|
+
await chmod(cfgDir, 448);
|
|
37
|
+
} catch {
|
|
38
|
+
}
|
|
39
|
+
const content = JSON.stringify(cfg, null, 2) + "\n";
|
|
40
|
+
const tmpPath = join(
|
|
41
|
+
tmpdir(),
|
|
42
|
+
`curviate-cfg-${randomBytes(6).toString("hex")}.tmp`
|
|
43
|
+
);
|
|
44
|
+
try {
|
|
45
|
+
await writeFile(tmpPath, content, { encoding: "utf8", mode: 384 });
|
|
46
|
+
try {
|
|
47
|
+
await chmod(tmpPath, 384);
|
|
48
|
+
} catch {
|
|
49
|
+
}
|
|
50
|
+
await rename(tmpPath, cfgPath);
|
|
51
|
+
try {
|
|
52
|
+
await chmod(cfgPath, 384);
|
|
53
|
+
} catch {
|
|
54
|
+
}
|
|
55
|
+
} catch (err) {
|
|
56
|
+
try {
|
|
57
|
+
await unlink(tmpPath);
|
|
58
|
+
} catch {
|
|
59
|
+
}
|
|
60
|
+
throw err;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async function writeProfile(profileName, entry) {
|
|
64
|
+
const existing = await readConfig() ?? {
|
|
65
|
+
active: profileName,
|
|
66
|
+
profiles: {}
|
|
67
|
+
};
|
|
68
|
+
const current = existing.profiles[profileName] ?? {};
|
|
69
|
+
existing.profiles[profileName] = { ...current, ...entry };
|
|
70
|
+
if (!existing.active) {
|
|
71
|
+
existing.active = profileName;
|
|
72
|
+
}
|
|
73
|
+
await writeConfig(existing);
|
|
74
|
+
}
|
|
75
|
+
async function setActiveProfile(profileName) {
|
|
76
|
+
const cfg = await readConfig();
|
|
77
|
+
if (!cfg || !cfg.profiles[profileName]) {
|
|
78
|
+
throw new Error(`Profile "${profileName}" not found.`);
|
|
79
|
+
}
|
|
80
|
+
cfg.active = profileName;
|
|
81
|
+
await writeConfig(cfg);
|
|
82
|
+
}
|
|
83
|
+
async function renameProfile(oldName, newName) {
|
|
84
|
+
const cfg = await readConfig();
|
|
85
|
+
if (!cfg || !cfg.profiles[oldName]) {
|
|
86
|
+
throw new Error(`Profile "${oldName}" not found.`);
|
|
87
|
+
}
|
|
88
|
+
if (cfg.profiles[newName]) {
|
|
89
|
+
throw new Error(
|
|
90
|
+
`Profile "${newName}" already exists \u2014 remove it first or choose another name.`
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
cfg.profiles[newName] = cfg.profiles[oldName];
|
|
94
|
+
delete cfg.profiles[oldName];
|
|
95
|
+
if (cfg.active === oldName) {
|
|
96
|
+
cfg.active = newName;
|
|
97
|
+
}
|
|
98
|
+
await writeConfig(cfg);
|
|
99
|
+
}
|
|
100
|
+
async function removeProfile(profileName) {
|
|
101
|
+
const cfg = await readConfig();
|
|
102
|
+
if (!cfg) return;
|
|
103
|
+
delete cfg.profiles[profileName];
|
|
104
|
+
if (cfg.active === profileName) {
|
|
105
|
+
cfg.active = "default";
|
|
106
|
+
}
|
|
107
|
+
await writeConfig(cfg);
|
|
108
|
+
}
|
|
109
|
+
async function updateProfileField(profileName, field, value) {
|
|
110
|
+
const cfg = await readConfig();
|
|
111
|
+
if (!cfg || !cfg.profiles[profileName]) {
|
|
112
|
+
throw new Error(`Profile "${profileName}" not found.`);
|
|
113
|
+
}
|
|
114
|
+
const profile = cfg.profiles[profileName];
|
|
115
|
+
if (profile) {
|
|
116
|
+
if (field === "timeout") {
|
|
117
|
+
profile.timeout = typeof value === "number" ? value : value !== void 0 ? Number(value) : void 0;
|
|
118
|
+
} else if (field === "apiKey") {
|
|
119
|
+
profile.apiKey = value !== void 0 ? String(value) : void 0;
|
|
120
|
+
} else if (field === "account") {
|
|
121
|
+
profile.account = value !== void 0 ? String(value) : void 0;
|
|
122
|
+
} else if (field === "baseUrl") {
|
|
123
|
+
profile.baseUrl = value !== void 0 ? String(value) : void 0;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
await writeConfig(cfg);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// src/lib/global-flags.ts
|
|
130
|
+
var GLOBAL_FLAGS = {
|
|
131
|
+
// Auth / config
|
|
132
|
+
"api-key": {
|
|
133
|
+
type: "string",
|
|
134
|
+
description: "API key (overrides env and profile). Note: a key passed on the command line is visible to other processes via `ps` and is saved in shell history; prefer the CURVIATE_API_KEY env var or `curviate login`."
|
|
135
|
+
},
|
|
136
|
+
profile: {
|
|
137
|
+
type: "string",
|
|
138
|
+
description: "Named profile to use from the config file."
|
|
139
|
+
},
|
|
140
|
+
account: {
|
|
141
|
+
type: "string",
|
|
142
|
+
description: "Account id for account-scoped commands."
|
|
143
|
+
},
|
|
144
|
+
"base-url": {
|
|
145
|
+
type: "string",
|
|
146
|
+
description: "Override the API base URL."
|
|
147
|
+
},
|
|
148
|
+
timeout: {
|
|
149
|
+
type: "string",
|
|
150
|
+
description: "Request timeout in milliseconds."
|
|
151
|
+
},
|
|
152
|
+
// Output
|
|
153
|
+
json: {
|
|
154
|
+
type: "boolean",
|
|
155
|
+
description: "Emit JSON output (default when stdout is not a TTY).",
|
|
156
|
+
default: false
|
|
157
|
+
},
|
|
158
|
+
fields: {
|
|
159
|
+
type: "string",
|
|
160
|
+
description: "Comma-separated dot-path field projection (e.g. id,name)."
|
|
161
|
+
},
|
|
162
|
+
limit: {
|
|
163
|
+
type: "string",
|
|
164
|
+
description: "Maximum items per page."
|
|
165
|
+
},
|
|
166
|
+
cursor: {
|
|
167
|
+
type: "string",
|
|
168
|
+
description: "Pagination cursor (opaque token from a previous response)."
|
|
169
|
+
},
|
|
170
|
+
all: {
|
|
171
|
+
type: "boolean",
|
|
172
|
+
description: "Stream all pages as NDJSON.",
|
|
173
|
+
default: false
|
|
174
|
+
},
|
|
175
|
+
"max-pages": {
|
|
176
|
+
type: "string",
|
|
177
|
+
description: "Maximum number of pages to fetch when --all is used."
|
|
178
|
+
},
|
|
179
|
+
preview: {
|
|
180
|
+
type: "boolean",
|
|
181
|
+
description: "Render the request that would be sent without calling the API.",
|
|
182
|
+
default: false
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
export {
|
|
187
|
+
getConfigPath,
|
|
188
|
+
readConfig,
|
|
189
|
+
writeProfile,
|
|
190
|
+
setActiveProfile,
|
|
191
|
+
renameProfile,
|
|
192
|
+
removeProfile,
|
|
193
|
+
updateProfileField,
|
|
194
|
+
GLOBAL_FLAGS
|
|
195
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/lib/identifier.ts
|
|
4
|
+
var MEMBER_URL_RE = /^https?:\/\/(?:[a-z0-9-]+\.)?linkedin\.com\/in\/([^/?#]+)/i;
|
|
5
|
+
var COMPANY_URL_RE = /^https?:\/\/(?:[a-z0-9-]+\.)?linkedin\.com\/company\/([^/?#]+)/i;
|
|
6
|
+
var MEMBER_PATH_RE = /^\/in\/([^/?#/]+)\/?$/;
|
|
7
|
+
var COMPANY_PATH_RE = /^\/company\/([^/?#/]+)\/?$/;
|
|
8
|
+
function resolveIdentifier(raw) {
|
|
9
|
+
const memberUrlMatch = MEMBER_URL_RE.exec(raw);
|
|
10
|
+
if (memberUrlMatch?.[1]) {
|
|
11
|
+
return stripTrailingSlash(memberUrlMatch[1]);
|
|
12
|
+
}
|
|
13
|
+
const companyUrlMatch = COMPANY_URL_RE.exec(raw);
|
|
14
|
+
if (companyUrlMatch?.[1]) {
|
|
15
|
+
return stripTrailingSlash(companyUrlMatch[1]);
|
|
16
|
+
}
|
|
17
|
+
const memberPathMatch = MEMBER_PATH_RE.exec(raw);
|
|
18
|
+
if (memberPathMatch?.[1]) {
|
|
19
|
+
return memberPathMatch[1];
|
|
20
|
+
}
|
|
21
|
+
const companyPathMatch = COMPANY_PATH_RE.exec(raw);
|
|
22
|
+
if (companyPathMatch?.[1]) {
|
|
23
|
+
return companyPathMatch[1];
|
|
24
|
+
}
|
|
25
|
+
return raw;
|
|
26
|
+
}
|
|
27
|
+
function stripTrailingSlash(s) {
|
|
28
|
+
return s.endsWith("/") ? s.slice(0, -1) : s;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export {
|
|
32
|
+
resolveIdentifier
|
|
33
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/lib/attach.ts
|
|
4
|
+
import { readFile } from "fs/promises";
|
|
5
|
+
import { basename } from "path";
|
|
6
|
+
var AttachError = class extends Error {
|
|
7
|
+
constructor(message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.exitCode = 2;
|
|
10
|
+
this.name = "AttachError";
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
async function readAttachment(filePath) {
|
|
14
|
+
try {
|
|
15
|
+
const buf = await readFile(filePath);
|
|
16
|
+
return buf;
|
|
17
|
+
} catch (err) {
|
|
18
|
+
const filename = basename(filePath);
|
|
19
|
+
const reason = err instanceof Error ? err.message : "unknown error";
|
|
20
|
+
throw new AttachError(
|
|
21
|
+
`Cannot read attachment "${filename}": ${reason}. Pass a valid file path.`
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export {
|
|
27
|
+
AttachError,
|
|
28
|
+
readAttachment
|
|
29
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/lib/preview.ts
|
|
4
|
+
function buildPreviewOutput(req) {
|
|
5
|
+
const result = {
|
|
6
|
+
method: req.method,
|
|
7
|
+
args: req.args,
|
|
8
|
+
body: req.body
|
|
9
|
+
};
|
|
10
|
+
if (req.account !== void 0) {
|
|
11
|
+
result.account = req.account;
|
|
12
|
+
}
|
|
13
|
+
if (req.attachments && req.attachments.length > 0) {
|
|
14
|
+
result.attachments = req.attachments.map(
|
|
15
|
+
(a) => `${a.name} (${a.buffer.byteLength} bytes)`
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export {
|
|
22
|
+
buildPreviewOutput
|
|
23
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/lib/paginate.ts
|
|
4
|
+
var PaginateError = class extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.exitCode = 2;
|
|
8
|
+
this.name = "PaginateError";
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
async function* streamAll(fn, params, opts = {}) {
|
|
12
|
+
const maxPages = opts.maxPages ?? 100;
|
|
13
|
+
let cursor = void 0;
|
|
14
|
+
let pageCount = 0;
|
|
15
|
+
let firstPage = true;
|
|
16
|
+
while (true) {
|
|
17
|
+
const pageParams = cursor !== void 0 && cursor !== null ? { ...params, cursor } : params;
|
|
18
|
+
const page = await fn(pageParams);
|
|
19
|
+
pageCount++;
|
|
20
|
+
const items = page.items ?? page.data;
|
|
21
|
+
if (firstPage && !Array.isArray(items)) {
|
|
22
|
+
throw new PaginateError(
|
|
23
|
+
"--all requires a paginated method (response must have `items` or `data` array). Remove --all for non-list commands."
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
firstPage = false;
|
|
27
|
+
if (Array.isArray(items)) {
|
|
28
|
+
for (const item of items) {
|
|
29
|
+
yield item;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
cursor = page.cursor;
|
|
33
|
+
if (!cursor) break;
|
|
34
|
+
if (pageCount >= maxPages) {
|
|
35
|
+
const msg = `Streaming truncated at ${maxPages} page(s) \u2014 more results may exist. Increase --max-pages or use --cursor / --limit for manual paging.`;
|
|
36
|
+
if (opts.onTruncated) {
|
|
37
|
+
opts.onTruncated(msg);
|
|
38
|
+
}
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export {
|
|
45
|
+
streamAll
|
|
46
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/lib/binary.ts
|
|
4
|
+
import { writeFile } from "fs/promises";
|
|
5
|
+
var BinaryOutputError = class extends Error {
|
|
6
|
+
constructor(message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.exitCode = 2;
|
|
9
|
+
this.name = "BinaryOutputError";
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
async function writeBinaryOutput(data, opts) {
|
|
13
|
+
const buf = data instanceof Buffer ? data : Buffer.from(new Uint8Array(data));
|
|
14
|
+
if (opts.outputPath) {
|
|
15
|
+
await writeFile(opts.outputPath, buf);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (opts.isTTY) {
|
|
19
|
+
throw new BinaryOutputError(
|
|
20
|
+
"Binary output: pass -o <file> to save it, or redirect stdout to a file/pipe."
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
await new Promise((resolve, reject) => {
|
|
24
|
+
opts.stdout.write(buf, (err) => {
|
|
25
|
+
if (err) reject(err);
|
|
26
|
+
else resolve();
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export {
|
|
32
|
+
BinaryOutputError,
|
|
33
|
+
writeBinaryOutput
|
|
34
|
+
};
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/cli.ts
|
|
4
|
+
import { defineCommand } from "citty";
|
|
5
|
+
import { createRequire } from "module";
|
|
6
|
+
|
|
7
|
+
// src/dispatch.ts
|
|
8
|
+
import { runCommand } from "citty";
|
|
9
|
+
async function resolveValue(input) {
|
|
10
|
+
return typeof input === "function" ? input() : input;
|
|
11
|
+
}
|
|
12
|
+
function firstPositionalIndex(rawArgs) {
|
|
13
|
+
return rawArgs.findIndex((a) => !a.startsWith("-"));
|
|
14
|
+
}
|
|
15
|
+
async function nodeHasPositional(cmd) {
|
|
16
|
+
const argsDef = await resolveValue(cmd.args ?? {});
|
|
17
|
+
return Object.values(argsDef).some((def) => def?.type === "positional");
|
|
18
|
+
}
|
|
19
|
+
async function declaredArgNames(cmd) {
|
|
20
|
+
const names = /* @__PURE__ */ new Set();
|
|
21
|
+
const argsDef = await resolveValue(cmd.args ?? {});
|
|
22
|
+
for (const [name, def] of Object.entries(argsDef)) {
|
|
23
|
+
names.add(name);
|
|
24
|
+
const alias = def?.alias;
|
|
25
|
+
if (typeof alias === "string") names.add(alias);
|
|
26
|
+
else if (Array.isArray(alias)) for (const a of alias) names.add(a);
|
|
27
|
+
}
|
|
28
|
+
return names;
|
|
29
|
+
}
|
|
30
|
+
function findUnknownFlag(rawArgs, declared) {
|
|
31
|
+
let afterDoubleDash = false;
|
|
32
|
+
for (const arg of rawArgs) {
|
|
33
|
+
if (afterDoubleDash) continue;
|
|
34
|
+
if (arg === "--") {
|
|
35
|
+
afterDoubleDash = true;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (!arg.startsWith("-")) continue;
|
|
39
|
+
let name = arg.replace(/^-+/, "");
|
|
40
|
+
const eq = name.indexOf("=");
|
|
41
|
+
if (eq !== -1) name = name.slice(0, eq);
|
|
42
|
+
if (name.startsWith("no-")) name = name.slice(3);
|
|
43
|
+
if (name === "") continue;
|
|
44
|
+
if (!declared.has(name)) return arg;
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
function hasEmptyFields(rawArgs) {
|
|
49
|
+
for (let i = 0; i < rawArgs.length; i++) {
|
|
50
|
+
const arg = rawArgs[i];
|
|
51
|
+
if (arg === "--fields") {
|
|
52
|
+
const next = rawArgs[i + 1];
|
|
53
|
+
if (next === void 0 || next.startsWith("-")) return true;
|
|
54
|
+
if (next.trim() === "") return true;
|
|
55
|
+
} else if (arg?.startsWith("--fields=")) {
|
|
56
|
+
if (arg.slice("--fields=".length).trim() === "") return true;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
function usageError(message) {
|
|
62
|
+
process.stderr.write(`error: ${message}
|
|
63
|
+
`);
|
|
64
|
+
process.stderr.write("Run `curviate --help` for usage.\n");
|
|
65
|
+
process.exit(2);
|
|
66
|
+
}
|
|
67
|
+
async function resolveLeaf(cmd, rawArgs) {
|
|
68
|
+
const subCommands = await resolveValue(cmd.subCommands);
|
|
69
|
+
if (subCommands && Object.keys(subCommands).length > 0) {
|
|
70
|
+
const idx = firstPositionalIndex(rawArgs);
|
|
71
|
+
const token = idx === -1 ? void 0 : rawArgs[idx];
|
|
72
|
+
const hasBarePositional = await nodeHasPositional(cmd);
|
|
73
|
+
if (token !== void 0 && subCommands[token]) {
|
|
74
|
+
const sub = await resolveValue(subCommands[token]);
|
|
75
|
+
return resolveLeaf(sub, rawArgs.slice(idx + 1));
|
|
76
|
+
}
|
|
77
|
+
if (token !== void 0 && hasBarePositional) {
|
|
78
|
+
return { leaf: cmd, leafArgs: rawArgs };
|
|
79
|
+
}
|
|
80
|
+
if (token !== void 0) {
|
|
81
|
+
usageError(`unknown command \`${token}\``);
|
|
82
|
+
}
|
|
83
|
+
return { leaf: cmd, leafArgs: rawArgs };
|
|
84
|
+
}
|
|
85
|
+
return { leaf: cmd, leafArgs: rawArgs };
|
|
86
|
+
}
|
|
87
|
+
async function dispatch(root, rawArgs) {
|
|
88
|
+
if (rawArgs.includes("--help") || rawArgs.includes("-h")) {
|
|
89
|
+
const { showUsage, runMain } = await import("citty");
|
|
90
|
+
void showUsage;
|
|
91
|
+
await runMain(root, { rawArgs });
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (rawArgs.length === 1 && rawArgs[0] === "--version") {
|
|
95
|
+
const meta = await resolveValue(root.meta ?? {});
|
|
96
|
+
if (meta.version) {
|
|
97
|
+
process.stdout.write(meta.version + "\n");
|
|
98
|
+
}
|
|
99
|
+
process.exit(0);
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
const { leaf, leafArgs } = await resolveLeaf(root, rawArgs);
|
|
103
|
+
if (hasEmptyFields(leafArgs)) {
|
|
104
|
+
usageError("--fields must not be empty.");
|
|
105
|
+
}
|
|
106
|
+
const declared = await declaredArgNames(leaf);
|
|
107
|
+
const unknown = findUnknownFlag(leafArgs, declared);
|
|
108
|
+
if (unknown !== null) {
|
|
109
|
+
usageError(`unknown flag \`${unknown}\`.`);
|
|
110
|
+
}
|
|
111
|
+
const leafToRun = { ...leaf, subCommands: void 0 };
|
|
112
|
+
await runCommand(leafToRun, { rawArgs: leafArgs });
|
|
113
|
+
} catch (err) {
|
|
114
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
115
|
+
const code = err?.code;
|
|
116
|
+
process.stderr.write(`error: ${message}
|
|
117
|
+
`);
|
|
118
|
+
process.exit(code === "EARG" ? 2 : 1);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// src/cli.ts
|
|
123
|
+
import { fileURLToPath } from "url";
|
|
124
|
+
import { dirname, resolve } from "path";
|
|
125
|
+
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
126
|
+
var require2 = createRequire(import.meta.url);
|
|
127
|
+
var pkg = require2(resolve(__dirname, "../package.json"));
|
|
128
|
+
var main = defineCommand({
|
|
129
|
+
meta: {
|
|
130
|
+
name: "curviate",
|
|
131
|
+
version: pkg.version,
|
|
132
|
+
description: "Official command-line interface for the Curviate API."
|
|
133
|
+
},
|
|
134
|
+
// Subcommand registry — names and descriptions are static for help rendering;
|
|
135
|
+
// the handler implementation is loaded lazily on first invocation.
|
|
136
|
+
subCommands: {
|
|
137
|
+
login: () => import("./login-VWJEBBFU.js").then((m) => m.loginCommand),
|
|
138
|
+
config: () => import("./config-4JOXBFYX.js").then((m) => m.configCommand),
|
|
139
|
+
// ---------------------------------------------------------------------------
|
|
140
|
+
// Noun groups — lazy-loaded on first invocation.
|
|
141
|
+
// ---------------------------------------------------------------------------
|
|
142
|
+
profile: () => import("./profile-WXA3NC7D.js").then((m) => m.profileCommand),
|
|
143
|
+
company: () => import("./company-IKVDW7MX.js").then((m) => m.companyCommand),
|
|
144
|
+
connect: () => import("./connect-HLDHFBGX.js").then((m) => m.connectCommand),
|
|
145
|
+
search: () => import("./search-LHPTHPWH.js").then((m) => m.searchCommand),
|
|
146
|
+
inbox: () => import("./inbox-JBLYJMV2.js").then((m) => m.inboxCommand),
|
|
147
|
+
message: () => import("./message-IK7VGB63.js").then((m) => m.messageCommand),
|
|
148
|
+
post: () => import("./post-EAAGVR5D.js").then((m) => m.postCommand),
|
|
149
|
+
account: () => import("./account-YOW2MCZS.js").then((m) => m.accountCommand),
|
|
150
|
+
webhook: () => import("./webhook-QM5LGAUF.js").then((m) => m.webhookCommand),
|
|
151
|
+
"sales-nav": () => import("./sales-nav-XGFO5I6F.js").then((m) => m.salesNavCommand),
|
|
152
|
+
recruiter: () => import("./recruiter-TGCV36EH.js").then((m) => m.recruiterCommand)
|
|
153
|
+
},
|
|
154
|
+
async run() {
|
|
155
|
+
const { runMain } = await import("citty");
|
|
156
|
+
await runMain(main, { rawArgs: ["--help"] });
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
void dispatch(main, process.argv.slice(2));
|