@opsrev/acculynx-cli 1.3.0 → 1.5.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.
Files changed (2) hide show
  1. package/dist/index.js +72 -5
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -68,9 +68,26 @@ function createApiClient(config) {
68
68
  }
69
69
  return response.json();
70
70
  }
71
+ async function doPostForm(path, body) {
72
+ const url = `${config.baseUrl}${path}`;
73
+ const { "Content-Type": _, ...formHeaders } = headers;
74
+ const response = await fetchWithRetry(url, {
75
+ method: "POST",
76
+ headers: formHeaders,
77
+ body
78
+ });
79
+ if (!response.ok) {
80
+ const text = await response.text();
81
+ throw new Error(
82
+ `API error (${response.status} ${response.statusText}): ${text}`
83
+ );
84
+ }
85
+ return response.json();
86
+ }
71
87
  return {
72
88
  get: doGet,
73
- post: doPost
89
+ post: doPost,
90
+ postForm: doPostForm
74
91
  };
75
92
  }
76
93
 
@@ -82,6 +99,10 @@ function registerPingCommand(parentCmd, getClient2) {
82
99
  });
83
100
  }
84
101
 
102
+ // src/commands/jobs.ts
103
+ import { readFileSync } from "fs";
104
+ import { basename, extname } from "path";
105
+
85
106
  // src/api-helpers.ts
86
107
  var DEFAULT_PAGE_SIZE = 25;
87
108
  var DEFAULT_LIMIT = 25;
@@ -125,9 +146,22 @@ async function readStdin(stream = process.stdin) {
125
146
  }
126
147
 
127
148
  // src/commands/jobs.ts
149
+ var DISALLOWED_EXTENSIONS = /* @__PURE__ */ new Set([
150
+ ".exe",
151
+ ".com",
152
+ ".dll",
153
+ ".msi",
154
+ ".bat",
155
+ ".cmd",
156
+ ".sh",
157
+ ".pl",
158
+ ".vbs",
159
+ ".py",
160
+ ".php"
161
+ ]);
128
162
  function registerJobsCommands(parentCmd, getClient2) {
129
163
  const jobs = parentCmd.command("jobs").description("Job operations");
130
- jobs.command("list").description("List jobs (paginated)").option("--start-date <date>", "Start date (YYYY-MM-DD)").option("--end-date <date>", "End date (YYYY-MM-DD)").option("--date-filter-type <type>", "Date field to filter on").option("--milestones <milestones>", "Filter by milestones").option("--sort-by <field>", "Sort by: CreatedDate, MilestoneDate, ModifiedDate").option("--sort-order <order>", "Ascending or Descending").option("--includes <fields>", "Include: contact, initialAppointment").option("--limit <n>", "Max total results (default: 25)").option("--all", "Fetch all results (no limit)").action(async (opts) => {
164
+ jobs.command("list").description("List jobs (paginated)").option("--start-date <date>", "Start date (YYYY-MM-DD)").option("--end-date <date>", "End date (YYYY-MM-DD)").option("--date-filter-type <type>", "Date field to filter on").option("--milestones <milestones>", "Filter by milestones").option("--sort-by <field>", "Sort by: CreatedDate, MilestoneDate, ModifiedDate").option("--sort-order <order>", "Ascending or Descending").option("--includes <fields>", "Include: contact, initialAppointment").option("--assignment <type>", "Filter by assignment: assigned, unassigned").option("--limit <n>", "Max total results (default: 25)").option("--all", "Fetch all results (no limit)").action(async (opts) => {
131
165
  const params = {};
132
166
  if (opts.startDate) params.startDate = opts.startDate;
133
167
  if (opts.endDate) params.endDate = opts.endDate;
@@ -136,6 +170,7 @@ function registerJobsCommands(parentCmd, getClient2) {
136
170
  if (opts.sortBy) params.sortBy = opts.sortBy;
137
171
  if (opts.sortOrder) params.sortOrder = opts.sortOrder;
138
172
  if (opts.includes) params.includes = opts.includes;
173
+ if (opts.assignment) params.assignment = opts.assignment;
139
174
  const limit = opts.all ? Infinity : opts.limit ? parseInt(opts.limit, 10) : void 0;
140
175
  const result = await paginate(getClient2(), "/jobs", params, limit);
141
176
  console.log(JSON.stringify(result));
@@ -170,6 +205,38 @@ function registerJobsCommands(parentCmd, getClient2) {
170
205
  console.log(JSON.stringify(result));
171
206
  });
172
207
  }
208
+ jobs.command("document-folders").description("List document folders for the company").option("--page-size <n>", "Number of items per page").option("--record-start-index <n>", "Index of first element to return", "0").option("--sort-order <order>", "Ascending or Descending", "Ascending").action(async (opts) => {
209
+ const params = {
210
+ recordStartIndex: opts.recordStartIndex,
211
+ sortOrder: opts.sortOrder
212
+ };
213
+ if (opts.pageSize) params.pageSize = opts.pageSize;
214
+ const result = await getClient2().get(
215
+ "/company-settings/job-file-settings/document-folders",
216
+ params
217
+ );
218
+ console.log(JSON.stringify(result));
219
+ });
220
+ jobs.command("upload-document").argument("<jobId>", "Job ID").argument("<filePath>", "Path to the file to upload").requiredOption("--folder-id <id>", "Document folder ID (required)").option("--description <text>", "Brief description of the file").option("--external-id <id>", "External reference identifier").option("--external-source <source>", "External reference source").description("Upload a document to a job").action(async (jobId, filePath, opts) => {
221
+ const ext = extname(filePath).toLowerCase();
222
+ if (DISALLOWED_EXTENSIONS.has(ext)) {
223
+ throw new Error(`File type ${ext} is not allowed`);
224
+ }
225
+ const fileBuffer = readFileSync(filePath);
226
+ const fileName = basename(filePath);
227
+ const file = new File([fileBuffer], fileName);
228
+ const form = new FormData();
229
+ form.append("file", file);
230
+ form.append("documentFolderId", opts.folderId);
231
+ if (opts.description) form.append("description", opts.description);
232
+ if (opts.externalId) form.append("externalId", opts.externalId);
233
+ if (opts.externalSource) form.append("externalSource", opts.externalSource);
234
+ const result = await getClient2().postForm(
235
+ `/jobs/${jobId}/documents`,
236
+ form
237
+ );
238
+ console.log(JSON.stringify(result));
239
+ });
173
240
  }
174
241
 
175
242
  // src/commands/contacts.ts
@@ -236,7 +303,7 @@ function registerEstimatesCommands(parentCmd, getClient2) {
236
303
  // src/unofficial/session-store.ts
237
304
  import {
238
305
  existsSync,
239
- readFileSync,
306
+ readFileSync as readFileSync2,
240
307
  writeFileSync,
241
308
  mkdirSync,
242
309
  readdirSync,
@@ -314,7 +381,7 @@ function loadSession(email, companyId) {
314
381
  const file = join(SESSIONS_DIR, sessionKey(email, companyId));
315
382
  if (!existsSync(file)) return null;
316
383
  try {
317
- const data = JSON.parse(readFileSync(file, "utf-8"));
384
+ const data = JSON.parse(readFileSync2(file, "utf-8"));
318
385
  return {
319
386
  jar: CookieJar.fromJSON(data.cookies),
320
387
  companyId: data.companyId,
@@ -351,7 +418,7 @@ function listSessions() {
351
418
  return readdirSync(SESSIONS_DIR).filter((f) => f.endsWith(".json")).map((f) => {
352
419
  try {
353
420
  const data = JSON.parse(
354
- readFileSync(join(SESSIONS_DIR, f), "utf-8")
421
+ readFileSync2(join(SESSIONS_DIR, f), "utf-8")
355
422
  );
356
423
  return { email: data.email, companyId: data.companyId, file: f };
357
424
  } catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opsrev/acculynx-cli",
3
- "version": "1.3.0",
3
+ "version": "1.5.0",
4
4
  "description": "CLI for the AccuLynx roofing CRM API",
5
5
  "type": "module",
6
6
  "bin": {