@hardfin/cli 0.0.2-dev.12 → 0.0.2-dev.14

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 (3) hide show
  1. package/README.md +16 -5
  2. package/dist/cli.js +168 -10
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -67,8 +67,19 @@ hardfin asset move execute create \
67
67
  --move assetId=ast_b2,locationId=loc_y
68
68
  ```
69
69
 
70
- An enum carries its values, so a wrong one fails locally with exit code 2 rather than at the
71
- API. A required field missing is caught the same way, before any request is made.
70
+ A value is sent as the type the document names. `--useful-life 36` sends the number 36. A
71
+ decimal such as `--salvage-value 1500.00` stays a string, which is how the API takes money
72
+ without losing precision.
73
+
74
+ Clear a field with `--unset`, naming the flag:
75
+
76
+ ```sh
77
+ hardfin asset accounting update ast_4f9xk2mq7plr8stz --unset useful-life
78
+ ```
79
+
80
+ Three things fail locally with exit code 2, before any request is made: a value outside an
81
+ enum, a required field that is missing, and `--unset` on a field the API will not take null
82
+ for.
72
83
 
73
84
  ### Overrides
74
85
 
@@ -274,9 +285,9 @@ Nothing secret is printed. An API key and a refresh token are each reported as a
274
285
  `sha256:` fingerprint, which identifies a credential across two machines without disclosing
275
286
  it.
276
287
 
277
- `refreshExpiresAt` is an estimate. Hardfin expires an unused refresh token after 90 days,
278
- but the token endpoint reports no expiry, so the CLI applies that rule to the date it last
279
- renewed. The flag `refreshExpiryIsEstimated` says so in the output.
288
+ `refreshExpiresAt` is what the server said when it issued the token. A sign in stored before
289
+ the server reported one falls back to Hardfin's 90-day rule, and `refreshExpiryIsEstimated`
290
+ says which of the two you are looking at.
280
291
 
281
292
  ## Local configuration
282
293
 
package/dist/cli.js CHANGED
@@ -293,6 +293,7 @@ const TokenResponse = z.looseObject({
293
293
  token_type: z.string(),
294
294
  expires_in: z.number().optional(),
295
295
  refresh_token: z.string().optional(),
296
+ refresh_token_expires_in: z.number().optional(),
296
297
  scope: z.string().optional()
297
298
  });
298
299
  /** GrantFailure is a token request the authorization server refused. */
@@ -351,6 +352,7 @@ async function toTokens(url, form) {
351
352
  return {
352
353
  accessToken: parsed.data.access_token,
353
354
  refreshToken: parsed.data.refresh_token,
355
+ refreshExpiresAt: parsed.data.refresh_token_expires_in === void 0 ? void 0 : Date.now() + parsed.data.refresh_token_expires_in * 1e3,
354
356
  scope: parsed.data.scope,
355
357
  expiresAt: parsed.data.expires_in === void 0 ? void 0 : Date.now() + parsed.data.expires_in * 1e3
356
358
  };
@@ -375,12 +377,13 @@ function toCredentialPath() {
375
377
  * family lifetime runs from. Callers hold the credential lock, which is what makes a write
376
378
  * from another process merge rather than disappear.
377
379
  */
378
- function keep(issuer, refreshToken) {
380
+ function keep(issuer, refreshToken, expiresAt) {
379
381
  const now = (/* @__PURE__ */ new Date()).toISOString();
380
382
  const record = {
381
383
  refreshToken,
382
384
  signedInAt: toCredential(issuer)?.signedInAt ?? now,
383
- renewedAt: now
385
+ renewedAt: now,
386
+ expiresAt: expiresAt === void 0 ? void 0 : new Date(expiresAt).toISOString()
384
387
  };
385
388
  const keyring = toKeyring(issuer);
386
389
  if (keyring) try {
@@ -566,7 +569,7 @@ async function toAccessToken(settings, refreshToken) {
566
569
  try {
567
570
  const tokens = await toTokensFromRefresh(metadata.token_endpoint, settings.clientId, latest);
568
571
  held.set(settings.issuerUrl, tokens);
569
- if (tokens.refreshToken && tokens.refreshToken !== latest) keep(settings.issuerUrl, tokens.refreshToken);
572
+ if (tokens.refreshToken && tokens.refreshToken !== latest) keep(settings.issuerUrl, tokens.refreshToken, tokens.refreshExpiresAt);
570
573
  return tokens;
571
574
  } catch (error) {
572
575
  if (error instanceof GrantFailure && isDead(error.code)) {
@@ -1366,7 +1369,7 @@ async function toSignedIn(input, metadata, tokens) {
1366
1369
  writeFailure("the authorization server issued no refresh token, so this sign in cannot be kept", input.isJSON);
1367
1370
  return ExitCode.ERROR;
1368
1371
  }
1369
- const backend = await withLock(() => keep(input.resolved.settings.issuerUrl, refreshToken));
1372
+ const backend = await withLock(() => keep(input.resolved.settings.issuerUrl, refreshToken, tokens.refreshExpiresAt));
1370
1373
  if (input.isJSON) {
1371
1374
  writeData({
1372
1375
  signedIn: true,
@@ -1632,6 +1635,13 @@ async function runMcp(input) {
1632
1635
  }
1633
1636
  //#endregion
1634
1637
  //#region src/command/operation.ts
1638
+ const UNSET_FLAG = {
1639
+ name: "unset",
1640
+ description: "A field to clear, named as its flag is, repeatable",
1641
+ valueName: "field",
1642
+ repeatable: true,
1643
+ schema: z.array(z.string())
1644
+ };
1635
1645
  const FILE_FLAG = {
1636
1646
  name: "file",
1637
1647
  description: "The file to upload",
@@ -1648,6 +1658,7 @@ function defineOperation(operation) {
1648
1658
  const flags = [
1649
1659
  ...operation.queryFlags,
1650
1660
  ...operation.bodyFlags,
1661
+ ...operation.bodyFlags.some((flag) => flag.nullable) ? [UNSET_FLAG] : [],
1651
1662
  ...operation.upload ? [...operation.upload.fields, FILE_FLAG] : [],
1652
1663
  JSON_FLAG
1653
1664
  ];
@@ -1661,6 +1672,10 @@ function defineOperation(operation) {
1661
1672
  description: operation.summary,
1662
1673
  command: operation.example
1663
1674
  }] : [],
1675
+ endpoint: {
1676
+ method: operation.method,
1677
+ path: operation.path
1678
+ },
1664
1679
  run: (input) => runOperation(operation, input)
1665
1680
  };
1666
1681
  }
@@ -1764,10 +1779,25 @@ function toBody(operation, flags) {
1764
1779
  hasField = true;
1765
1780
  continue;
1766
1781
  }
1767
- set(body, flag.jsonPath, value);
1782
+ const parsed = flag.schema.safeParse(value);
1783
+ set(body, flag.jsonPath, parsed.success ? parsed.data : value);
1768
1784
  hasField = true;
1769
1785
  }
1770
- return hasField ? body : void 0;
1786
+ const cleared = toCleared(operation, flags, body);
1787
+ if (cleared instanceof Error) return cleared;
1788
+ return hasField || cleared ? body : void 0;
1789
+ }
1790
+ /** toCleared sends null for each field named by --unset, which is how a field is cleared. */
1791
+ function toCleared(operation, flags, body) {
1792
+ const named = flags["unset"];
1793
+ const names = Array.isArray(named) ? named.map(String) : named === void 0 ? [] : [String(named)];
1794
+ for (const name of names) {
1795
+ const flag = operation.bodyFlags.find((entry) => entry.name === name.replace(/^--/, ""));
1796
+ if (!flag) return /* @__PURE__ */ new Error(`--unset names no field called ${name}`);
1797
+ if (!flag.nullable) return /* @__PURE__ */ new Error(`--${flag.name} cannot be cleared, because the API does not accept null for it`);
1798
+ set(body, flag.jsonPath, null);
1799
+ }
1800
+ return names.length > 0;
1771
1801
  }
1772
1802
  /** toElements reads the key=value pairs a repeated flag carries for one array element. */
1773
1803
  function toElements(flag, values) {
@@ -2007,6 +2037,7 @@ const surfaceCommands = [
2007
2037
  jsonPath: ["allocatedIndirect"],
2008
2038
  description: "One unit's share of overhead, a cost component",
2009
2039
  valueName: "value",
2040
+ nullable: true,
2010
2041
  schema: z.string()
2011
2042
  },
2012
2043
  {
@@ -2014,6 +2045,7 @@ const surfaceCommands = [
2014
2045
  jsonPath: ["billOfMaterials"],
2015
2046
  description: "The parts cost of one unit, a cost component",
2016
2047
  valueName: "value",
2048
+ nullable: true,
2017
2049
  schema: z.string()
2018
2050
  },
2019
2051
  {
@@ -2033,6 +2065,7 @@ const surfaceCommands = [
2033
2065
  jsonPath: ["description"],
2034
2066
  description: "A free-form description of the asset",
2035
2067
  valueName: "value",
2068
+ nullable: true,
2036
2069
  schema: z.string()
2037
2070
  },
2038
2071
  {
@@ -2040,6 +2073,7 @@ const surfaceCommands = [
2040
2073
  jsonPath: ["directLabor"],
2041
2074
  description: "The labor cost to build one unit, a cost component",
2042
2075
  valueName: "value",
2076
+ nullable: true,
2043
2077
  schema: z.string()
2044
2078
  },
2045
2079
  {
@@ -2047,6 +2081,7 @@ const surfaceCommands = [
2047
2081
  jsonPath: ["freightInbound"],
2048
2082
  description: "The shipping cost to receive one unit, a cost component",
2049
2083
  valueName: "value",
2084
+ nullable: true,
2050
2085
  schema: z.string()
2051
2086
  },
2052
2087
  {
@@ -2054,6 +2089,7 @@ const surfaceCommands = [
2054
2089
  jsonPath: ["freightOutbound"],
2055
2090
  description: "The shipping cost to deploy one unit, a deployment cost component",
2056
2091
  valueName: "value",
2092
+ nullable: true,
2057
2093
  schema: z.string()
2058
2094
  },
2059
2095
  {
@@ -2061,6 +2097,7 @@ const surfaceCommands = [
2061
2097
  jsonPath: ["functionalStatus"],
2062
2098
  description: "The asset's starting functional status, FUNCTIONAL when absent, which cannot be SCRAPPED",
2063
2099
  valueName: "value",
2100
+ nullable: true,
2064
2101
  schema: z.enum([
2065
2102
  "FUNCTIONAL",
2066
2103
  "NEEDS_REVIEW",
@@ -2080,6 +2117,7 @@ const surfaceCommands = [
2080
2117
  jsonPath: ["inServiceDate"],
2081
2118
  description: "The day the asset was put into service, which Hardfin sets itself when absent",
2082
2119
  valueName: "value",
2120
+ nullable: true,
2083
2121
  schema: z.string()
2084
2122
  },
2085
2123
  {
@@ -2087,6 +2125,7 @@ const surfaceCommands = [
2087
2125
  jsonPath: ["installation"],
2088
2126
  description: "The cost to install one unit, a deployment cost component",
2089
2127
  valueName: "value",
2128
+ nullable: true,
2090
2129
  schema: z.string()
2091
2130
  },
2092
2131
  {
@@ -2094,6 +2133,7 @@ const surfaceCommands = [
2094
2133
  jsonPath: ["interest"],
2095
2134
  description: "The financing cost of one unit, a cost component",
2096
2135
  valueName: "value",
2136
+ nullable: true,
2097
2137
  schema: z.string()
2098
2138
  },
2099
2139
  {
@@ -2116,6 +2156,7 @@ const surfaceCommands = [
2116
2156
  jsonPath: ["salvageValue"],
2117
2157
  description: "The value one unit keeps at the end of its useful life, or null to clear it",
2118
2158
  valueName: "value",
2159
+ nullable: true,
2119
2160
  schema: z.string()
2120
2161
  },
2121
2162
  {
@@ -2131,6 +2172,7 @@ const surfaceCommands = [
2131
2172
  jsonPath: ["simpleCostBasis"],
2132
2173
  description: "A single cost for one unit, which cannot be sent together with the cost components",
2133
2174
  valueName: "value",
2175
+ nullable: true,
2134
2176
  schema: z.string()
2135
2177
  },
2136
2178
  {
@@ -2138,6 +2180,7 @@ const surfaceCommands = [
2138
2180
  jsonPath: ["tariffs"],
2139
2181
  description: "The import duty paid on one unit, a cost component",
2140
2182
  valueName: "value",
2183
+ nullable: true,
2141
2184
  schema: z.string()
2142
2185
  },
2143
2186
  {
@@ -2145,6 +2188,7 @@ const surfaceCommands = [
2145
2188
  jsonPath: ["tax"],
2146
2189
  description: "The tax paid on one unit, a cost component",
2147
2190
  valueName: "value",
2191
+ nullable: true,
2148
2192
  schema: z.string()
2149
2193
  },
2150
2194
  {
@@ -2152,6 +2196,7 @@ const surfaceCommands = [
2152
2196
  jsonPath: ["usefulLife"],
2153
2197
  description: "The number of months one unit is depreciated over, or null to clear it",
2154
2198
  valueName: "number",
2199
+ nullable: true,
2155
2200
  schema: z.coerce.number()
2156
2201
  }
2157
2202
  ]
@@ -2257,6 +2302,7 @@ const surfaceCommands = [
2257
2302
  jsonPath: ["description"],
2258
2303
  description: "The asset's new description, or null to clear it",
2259
2304
  valueName: "value",
2305
+ nullable: true,
2260
2306
  schema: z.string()
2261
2307
  },
2262
2308
  {
@@ -2264,6 +2310,7 @@ const surfaceCommands = [
2264
2310
  jsonPath: ["functionalStatus"],
2265
2311
  description: "The asset's new functional status, which cannot be SCRAPPED because scrapping has its own endpoint",
2266
2312
  valueName: "value",
2313
+ nullable: true,
2267
2314
  schema: z.enum([
2268
2315
  "FUNCTIONAL",
2269
2316
  "NEEDS_REVIEW",
@@ -2276,6 +2323,7 @@ const surfaceCommands = [
2276
2323
  jsonPath: ["inInventoryDate"],
2277
2324
  description: "The day the asset entered inventory, which cannot be in the future",
2278
2325
  valueName: "value",
2326
+ nullable: true,
2279
2327
  schema: z.string()
2280
2328
  },
2281
2329
  {
@@ -2283,6 +2331,7 @@ const surfaceCommands = [
2283
2331
  jsonPath: ["initialLocationId"],
2284
2332
  description: "The ID of the location the asset entered inventory at",
2285
2333
  valueName: "value",
2334
+ nullable: true,
2286
2335
  schema: z.string()
2287
2336
  },
2288
2337
  {
@@ -2299,6 +2348,7 @@ const surfaceCommands = [
2299
2348
  jsonPath: ["serial"],
2300
2349
  description: "The asset's new serial number, which cannot be empty",
2301
2350
  valueName: "value",
2351
+ nullable: true,
2302
2352
  schema: z.string()
2303
2353
  }
2304
2354
  ]
@@ -2327,6 +2377,7 @@ const surfaceCommands = [
2327
2377
  jsonPath: ["allocatedIndirect"],
2328
2378
  description: "One unit's share of overhead, a cost component",
2329
2379
  valueName: "value",
2380
+ nullable: true,
2330
2381
  schema: z.string()
2331
2382
  },
2332
2383
  {
@@ -2334,6 +2385,7 @@ const surfaceCommands = [
2334
2385
  jsonPath: ["billOfMaterials"],
2335
2386
  description: "The parts cost of one unit, a cost component",
2336
2387
  valueName: "value",
2388
+ nullable: true,
2337
2389
  schema: z.string()
2338
2390
  },
2339
2391
  {
@@ -2353,6 +2405,7 @@ const surfaceCommands = [
2353
2405
  jsonPath: ["directLabor"],
2354
2406
  description: "The labor cost to build one unit, a cost component",
2355
2407
  valueName: "value",
2408
+ nullable: true,
2356
2409
  schema: z.string()
2357
2410
  },
2358
2411
  {
@@ -2360,6 +2413,7 @@ const surfaceCommands = [
2360
2413
  jsonPath: ["freightInbound"],
2361
2414
  description: "The shipping cost to receive one unit, a cost component",
2362
2415
  valueName: "value",
2416
+ nullable: true,
2363
2417
  schema: z.string()
2364
2418
  },
2365
2419
  {
@@ -2367,6 +2421,7 @@ const surfaceCommands = [
2367
2421
  jsonPath: ["freightOutbound"],
2368
2422
  description: "The shipping cost to deploy one unit, a deployment cost component",
2369
2423
  valueName: "value",
2424
+ nullable: true,
2370
2425
  schema: z.string()
2371
2426
  },
2372
2427
  {
@@ -2374,6 +2429,7 @@ const surfaceCommands = [
2374
2429
  jsonPath: ["inServiceDate"],
2375
2430
  description: "The day the asset was put into service and began depreciating, or null to clear it",
2376
2431
  valueName: "value",
2432
+ nullable: true,
2377
2433
  schema: z.string()
2378
2434
  },
2379
2435
  {
@@ -2381,6 +2437,7 @@ const surfaceCommands = [
2381
2437
  jsonPath: ["installation"],
2382
2438
  description: "The cost to install one unit, a deployment cost component",
2383
2439
  valueName: "value",
2440
+ nullable: true,
2384
2441
  schema: z.string()
2385
2442
  },
2386
2443
  {
@@ -2388,12 +2445,14 @@ const surfaceCommands = [
2388
2445
  jsonPath: ["interest"],
2389
2446
  description: "The financing cost of one unit, a cost component",
2390
2447
  valueName: "value",
2448
+ nullable: true,
2391
2449
  schema: z.string()
2392
2450
  },
2393
2451
  {
2394
2452
  name: "is-in-service-date-managed-automatically",
2395
2453
  jsonPath: ["isInServiceDateManagedAutomatically"],
2396
2454
  description: "Whether Hardfin sets the in-service date itself, which sending an in-service date turns off",
2455
+ nullable: true,
2397
2456
  schema: z.boolean()
2398
2457
  },
2399
2458
  {
@@ -2401,6 +2460,7 @@ const surfaceCommands = [
2401
2460
  jsonPath: ["salvageValue"],
2402
2461
  description: "The value one unit keeps at the end of its useful life, or null to clear it",
2403
2462
  valueName: "value",
2463
+ nullable: true,
2404
2464
  schema: z.string()
2405
2465
  },
2406
2466
  {
@@ -2408,6 +2468,7 @@ const surfaceCommands = [
2408
2468
  jsonPath: ["simpleCostBasis"],
2409
2469
  description: "A single cost for one unit, which cannot be sent together with the cost components",
2410
2470
  valueName: "value",
2471
+ nullable: true,
2411
2472
  schema: z.string()
2412
2473
  },
2413
2474
  {
@@ -2415,6 +2476,7 @@ const surfaceCommands = [
2415
2476
  jsonPath: ["tariffs"],
2416
2477
  description: "The import duty paid on one unit, a cost component",
2417
2478
  valueName: "value",
2479
+ nullable: true,
2418
2480
  schema: z.string()
2419
2481
  },
2420
2482
  {
@@ -2422,6 +2484,7 @@ const surfaceCommands = [
2422
2484
  jsonPath: ["tax"],
2423
2485
  description: "The tax paid on one unit, a cost component",
2424
2486
  valueName: "value",
2487
+ nullable: true,
2425
2488
  schema: z.string()
2426
2489
  },
2427
2490
  {
@@ -2429,6 +2492,7 @@ const surfaceCommands = [
2429
2492
  jsonPath: ["usefulLife"],
2430
2493
  description: "The number of months one unit is depreciated over, or null to clear it",
2431
2494
  valueName: "number",
2495
+ nullable: true,
2432
2496
  schema: z.coerce.number()
2433
2497
  }
2434
2498
  ]
@@ -2508,6 +2572,7 @@ const surfaceCommands = [
2508
2572
  jsonPath: ["notes"],
2509
2573
  description: "Free-form detail about the adjustment, which a reason of OTHER requires",
2510
2574
  valueName: "value",
2575
+ nullable: true,
2511
2576
  schema: z.string()
2512
2577
  },
2513
2578
  {
@@ -2716,6 +2781,7 @@ const surfaceCommands = [
2716
2781
  jsonPath: ["salePrice"],
2717
2782
  description: "What the customer paid for the asset, which cannot be negative",
2718
2783
  valueName: "value",
2784
+ nullable: true,
2719
2785
  schema: z.string()
2720
2786
  }
2721
2787
  ]
@@ -2781,6 +2847,7 @@ const surfaceCommands = [
2781
2847
  jsonPath: ["customerId"],
2782
2848
  description: "The ID of the customer that owned the asset during the segment",
2783
2849
  valueName: "value",
2850
+ nullable: true,
2784
2851
  schema: z.string()
2785
2852
  },
2786
2853
  {
@@ -2788,6 +2855,7 @@ const surfaceCommands = [
2788
2855
  jsonPath: ["date"],
2789
2856
  description: "The day the segment's owner took ownership, which cannot be in the future",
2790
2857
  valueName: "value",
2858
+ nullable: true,
2791
2859
  schema: z.string()
2792
2860
  },
2793
2861
  {
@@ -2795,6 +2863,7 @@ const surfaceCommands = [
2795
2863
  jsonPath: ["salePrice"],
2796
2864
  description: "What the owner paid for the asset, which cannot be negative",
2797
2865
  valueName: "value",
2866
+ nullable: true,
2798
2867
  schema: z.string()
2799
2868
  }
2800
2869
  ]
@@ -2851,6 +2920,7 @@ const surfaceCommands = [
2851
2920
  jsonPath: ["disposalPrice"],
2852
2921
  description: "What the scrapped asset was sold for, or null when it was not sold",
2853
2922
  valueName: "value",
2923
+ nullable: true,
2854
2924
  schema: z.string()
2855
2925
  },
2856
2926
  {
@@ -2858,6 +2928,7 @@ const surfaceCommands = [
2858
2928
  jsonPath: ["disposalReason"],
2859
2929
  description: "Why the asset was scrapped",
2860
2930
  valueName: "value",
2931
+ nullable: true,
2861
2932
  schema: z.string()
2862
2933
  }
2863
2934
  ]
@@ -2920,6 +2991,7 @@ const surfaceCommands = [
2920
2991
  jsonPath: ["name"],
2921
2992
  description: "The link's display name, or null to show the address instead",
2922
2993
  valueName: "value",
2994
+ nullable: true,
2923
2995
  schema: z.string()
2924
2996
  }, {
2925
2997
  name: "url",
@@ -2963,6 +3035,7 @@ const surfaceCommands = [
2963
3035
  jsonPath: ["notes"],
2964
3036
  description: "Free-form detail about the revision, which a reason of OTHER requires",
2965
3037
  valueName: "value",
3038
+ nullable: true,
2966
3039
  schema: z.string()
2967
3040
  },
2968
3041
  {
@@ -3092,6 +3165,7 @@ const surfaceCommands = [
3092
3165
  jsonPath: ["billingAddress"],
3093
3166
  description: "The address invoices are sent to",
3094
3167
  valueName: "value",
3168
+ nullable: true,
3095
3169
  schema: z.string()
3096
3170
  },
3097
3171
  {
@@ -3099,6 +3173,7 @@ const surfaceCommands = [
3099
3173
  jsonPath: ["billingContact", "email"],
3100
3174
  description: "The billing contact's email address",
3101
3175
  valueName: "value",
3176
+ nullable: true,
3102
3177
  schema: z.string()
3103
3178
  },
3104
3179
  {
@@ -3106,6 +3181,7 @@ const surfaceCommands = [
3106
3181
  jsonPath: ["billingContact", "name"],
3107
3182
  description: "The billing contact's name",
3108
3183
  valueName: "value",
3184
+ nullable: true,
3109
3185
  schema: z.string()
3110
3186
  },
3111
3187
  {
@@ -3113,6 +3189,7 @@ const surfaceCommands = [
3113
3189
  jsonPath: ["billingContact", "phone"],
3114
3190
  description: "The billing contact's phone number",
3115
3191
  valueName: "value",
3192
+ nullable: true,
3116
3193
  schema: z.string()
3117
3194
  },
3118
3195
  {
@@ -3120,6 +3197,7 @@ const surfaceCommands = [
3120
3197
  jsonPath: ["comment"],
3121
3198
  description: "A free-form note about the customer",
3122
3199
  valueName: "value",
3200
+ nullable: true,
3123
3201
  schema: z.string()
3124
3202
  },
3125
3203
  {
@@ -3127,6 +3205,7 @@ const surfaceCommands = [
3127
3205
  jsonPath: ["domain"],
3128
3206
  description: "The customer's web domain, used to look up its logo",
3129
3207
  valueName: "value",
3208
+ nullable: true,
3130
3209
  schema: z.string()
3131
3210
  },
3132
3211
  {
@@ -3134,6 +3213,7 @@ const surfaceCommands = [
3134
3213
  jsonPath: ["externalId"],
3135
3214
  description: "The customer's identifier in another system",
3136
3215
  valueName: "value",
3216
+ nullable: true,
3137
3217
  schema: z.string()
3138
3218
  },
3139
3219
  {
@@ -3190,6 +3270,7 @@ const surfaceCommands = [
3190
3270
  jsonPath: ["billingAddress"],
3191
3271
  description: "The address invoices are sent to",
3192
3272
  valueName: "value",
3273
+ nullable: true,
3193
3274
  schema: z.string()
3194
3275
  },
3195
3276
  {
@@ -3197,6 +3278,7 @@ const surfaceCommands = [
3197
3278
  jsonPath: ["billingContact", "email"],
3198
3279
  description: "The billing contact's email address",
3199
3280
  valueName: "value",
3281
+ nullable: true,
3200
3282
  schema: z.string()
3201
3283
  },
3202
3284
  {
@@ -3204,6 +3286,7 @@ const surfaceCommands = [
3204
3286
  jsonPath: ["billingContact", "name"],
3205
3287
  description: "The billing contact's name",
3206
3288
  valueName: "value",
3289
+ nullable: true,
3207
3290
  schema: z.string()
3208
3291
  },
3209
3292
  {
@@ -3211,6 +3294,7 @@ const surfaceCommands = [
3211
3294
  jsonPath: ["billingContact", "phone"],
3212
3295
  description: "The billing contact's phone number",
3213
3296
  valueName: "value",
3297
+ nullable: true,
3214
3298
  schema: z.string()
3215
3299
  },
3216
3300
  {
@@ -3218,6 +3302,7 @@ const surfaceCommands = [
3218
3302
  jsonPath: ["comment"],
3219
3303
  description: "A free-form note about the customer",
3220
3304
  valueName: "value",
3305
+ nullable: true,
3221
3306
  schema: z.string()
3222
3307
  },
3223
3308
  {
@@ -3225,6 +3310,7 @@ const surfaceCommands = [
3225
3310
  jsonPath: ["domain"],
3226
3311
  description: "The customer's web domain, used to look up its logo",
3227
3312
  valueName: "value",
3313
+ nullable: true,
3228
3314
  schema: z.string()
3229
3315
  },
3230
3316
  {
@@ -3232,24 +3318,28 @@ const surfaceCommands = [
3232
3318
  jsonPath: ["externalId"],
3233
3319
  description: "The customer's identifier in another system",
3234
3320
  valueName: "value",
3321
+ nullable: true,
3235
3322
  schema: z.string()
3236
3323
  },
3237
3324
  {
3238
3325
  name: "is-archived",
3239
3326
  jsonPath: ["isArchived"],
3240
3327
  description: "Whether the customer is archived",
3328
+ nullable: true,
3241
3329
  schema: z.boolean()
3242
3330
  },
3243
3331
  {
3244
3332
  name: "is-customer",
3245
3333
  jsonPath: ["isCustomer"],
3246
3334
  description: "Whether the company is a customer",
3335
+ nullable: true,
3247
3336
  schema: z.boolean()
3248
3337
  },
3249
3338
  {
3250
3339
  name: "is-supplier",
3251
3340
  jsonPath: ["isSupplier"],
3252
3341
  description: "Whether the company is a supplier",
3342
+ nullable: true,
3253
3343
  schema: z.boolean()
3254
3344
  },
3255
3345
  {
@@ -3257,6 +3347,7 @@ const surfaceCommands = [
3257
3347
  jsonPath: ["name"],
3258
3348
  description: "The customer's display name",
3259
3349
  valueName: "value",
3350
+ nullable: true,
3260
3351
  schema: z.string()
3261
3352
  }
3262
3353
  ]
@@ -3433,6 +3524,7 @@ const surfaceCommands = [
3433
3524
  jsonPath: ["description"],
3434
3525
  description: "A free-form description of the item",
3435
3526
  valueName: "value",
3527
+ nullable: true,
3436
3528
  schema: z.string()
3437
3529
  },
3438
3530
  {
@@ -3561,6 +3653,7 @@ const surfaceCommands = [
3561
3653
  name: "accepts-bulk-serials",
3562
3654
  jsonPath: ["acceptsBulkSerials"],
3563
3655
  description: "Whether a BULK item records serial numbers on its units, read only beside type",
3656
+ nullable: true,
3564
3657
  schema: z.boolean()
3565
3658
  },
3566
3659
  {
@@ -3568,6 +3661,7 @@ const surfaceCommands = [
3568
3661
  jsonPath: ["description"],
3569
3662
  description: "The item's new description, or null to clear it",
3570
3663
  valueName: "value",
3664
+ nullable: true,
3571
3665
  schema: z.string()
3572
3666
  },
3573
3667
  {
@@ -3587,6 +3681,7 @@ const surfaceCommands = [
3587
3681
  name: "is-archived",
3588
3682
  jsonPath: ["isArchived"],
3589
3683
  description: "Whether the item is archived, which cannot be null",
3684
+ nullable: true,
3590
3685
  schema: z.boolean()
3591
3686
  },
3592
3687
  {
@@ -3594,6 +3689,7 @@ const surfaceCommands = [
3594
3689
  jsonPath: ["name"],
3595
3690
  description: "The item's new display name, which cannot be empty",
3596
3691
  valueName: "value",
3692
+ nullable: true,
3597
3693
  schema: z.string()
3598
3694
  },
3599
3695
  {
@@ -3601,6 +3697,7 @@ const surfaceCommands = [
3601
3697
  jsonPath: ["sku"],
3602
3698
  description: "The item's new stock keeping unit, which cannot be empty and must be unique within your organization",
3603
3699
  valueName: "value",
3700
+ nullable: true,
3604
3701
  schema: z.string()
3605
3702
  },
3606
3703
  {
@@ -3608,6 +3705,7 @@ const surfaceCommands = [
3608
3705
  jsonPath: ["type"],
3609
3706
  description: "The type to convert the item to, when the item's assets and inventory history allow the conversion",
3610
3707
  valueName: "value",
3708
+ nullable: true,
3611
3709
  schema: z.enum([
3612
3710
  "BULK",
3613
3711
  "DEVICE",
@@ -3640,6 +3738,7 @@ const surfaceCommands = [
3640
3738
  jsonPath: ["allocatedIndirect"],
3641
3739
  description: "One unit's share of overhead, a cost component",
3642
3740
  valueName: "value",
3741
+ nullable: true,
3643
3742
  schema: z.string()
3644
3743
  },
3645
3744
  {
@@ -3647,6 +3746,7 @@ const surfaceCommands = [
3647
3746
  jsonPath: ["billOfMaterials"],
3648
3747
  description: "The parts cost of one unit, a cost component",
3649
3748
  valueName: "value",
3749
+ nullable: true,
3650
3750
  schema: z.string()
3651
3751
  },
3652
3752
  {
@@ -3666,6 +3766,7 @@ const surfaceCommands = [
3666
3766
  jsonPath: ["directLabor"],
3667
3767
  description: "The labor cost to build one unit, a cost component",
3668
3768
  valueName: "value",
3769
+ nullable: true,
3669
3770
  schema: z.string()
3670
3771
  },
3671
3772
  {
@@ -3673,6 +3774,7 @@ const surfaceCommands = [
3673
3774
  jsonPath: ["freightInbound"],
3674
3775
  description: "The shipping cost to receive one unit, a cost component",
3675
3776
  valueName: "value",
3777
+ nullable: true,
3676
3778
  schema: z.string()
3677
3779
  },
3678
3780
  {
@@ -3680,6 +3782,7 @@ const surfaceCommands = [
3680
3782
  jsonPath: ["freightOutbound"],
3681
3783
  description: "The shipping cost to deploy one unit, a deployment cost component",
3682
3784
  valueName: "value",
3785
+ nullable: true,
3683
3786
  schema: z.string()
3684
3787
  },
3685
3788
  {
@@ -3687,6 +3790,7 @@ const surfaceCommands = [
3687
3790
  jsonPath: ["installation"],
3688
3791
  description: "The cost to install one unit, a deployment cost component",
3689
3792
  valueName: "value",
3793
+ nullable: true,
3690
3794
  schema: z.string()
3691
3795
  },
3692
3796
  {
@@ -3694,6 +3798,7 @@ const surfaceCommands = [
3694
3798
  jsonPath: ["interest"],
3695
3799
  description: "The financing cost of one unit, a cost component",
3696
3800
  valueName: "value",
3801
+ nullable: true,
3697
3802
  schema: z.string()
3698
3803
  },
3699
3804
  {
@@ -3701,6 +3806,7 @@ const surfaceCommands = [
3701
3806
  jsonPath: ["salvageValue"],
3702
3807
  description: "The value one unit keeps at the end of its useful life, or null to clear it",
3703
3808
  valueName: "value",
3809
+ nullable: true,
3704
3810
  schema: z.string()
3705
3811
  },
3706
3812
  {
@@ -3708,6 +3814,7 @@ const surfaceCommands = [
3708
3814
  jsonPath: ["simpleCostBasis"],
3709
3815
  description: "A single cost for one unit, which cannot be sent together with the cost components",
3710
3816
  valueName: "value",
3817
+ nullable: true,
3711
3818
  schema: z.string()
3712
3819
  },
3713
3820
  {
@@ -3715,6 +3822,7 @@ const surfaceCommands = [
3715
3822
  jsonPath: ["tariffs"],
3716
3823
  description: "The import duty paid on one unit, a cost component",
3717
3824
  valueName: "value",
3825
+ nullable: true,
3718
3826
  schema: z.string()
3719
3827
  },
3720
3828
  {
@@ -3722,6 +3830,7 @@ const surfaceCommands = [
3722
3830
  jsonPath: ["tax"],
3723
3831
  description: "The tax paid on one unit, a cost component",
3724
3832
  valueName: "value",
3833
+ nullable: true,
3725
3834
  schema: z.string()
3726
3835
  },
3727
3836
  {
@@ -3729,6 +3838,7 @@ const surfaceCommands = [
3729
3838
  jsonPath: ["usefulLife"],
3730
3839
  description: "The number of months one unit is depreciated over, or null to clear it",
3731
3840
  valueName: "number",
3841
+ nullable: true,
3732
3842
  schema: z.coerce.number()
3733
3843
  }
3734
3844
  ]
@@ -3785,6 +3895,7 @@ const surfaceCommands = [
3785
3895
  description: "The field's position within its section, starting at 0",
3786
3896
  valueName: "number",
3787
3897
  required: true,
3898
+ nullable: true,
3788
3899
  schema: z.coerce.number()
3789
3900
  },
3790
3901
  {
@@ -3793,6 +3904,7 @@ const surfaceCommands = [
3793
3904
  description: "The group the field is shown in, starting at 0",
3794
3905
  valueName: "number",
3795
3906
  required: true,
3907
+ nullable: true,
3796
3908
  schema: z.coerce.number()
3797
3909
  }
3798
3910
  ]
@@ -3818,6 +3930,7 @@ const surfaceCommands = [
3818
3930
  jsonPath: ["label"],
3819
3931
  description: "The field's new display name, which cannot be empty",
3820
3932
  valueName: "value",
3933
+ nullable: true,
3821
3934
  schema: z.string()
3822
3935
  }]
3823
3936
  }),
@@ -3958,6 +4071,7 @@ const surfaceCommands = [
3958
4071
  jsonPath: ["address", "addressLine1"],
3959
4072
  description: "The first line of the street address",
3960
4073
  valueName: "value",
4074
+ nullable: true,
3961
4075
  schema: z.string()
3962
4076
  },
3963
4077
  {
@@ -3965,6 +4079,7 @@ const surfaceCommands = [
3965
4079
  jsonPath: ["address", "addressLine2"],
3966
4080
  description: "The second line of the street address, such as a suite",
3967
4081
  valueName: "value",
4082
+ nullable: true,
3968
4083
  schema: z.string()
3969
4084
  },
3970
4085
  {
@@ -3972,6 +4087,7 @@ const surfaceCommands = [
3972
4087
  jsonPath: ["address", "city"],
3973
4088
  description: "The city",
3974
4089
  valueName: "value",
4090
+ nullable: true,
3975
4091
  schema: z.string()
3976
4092
  },
3977
4093
  {
@@ -3979,6 +4095,7 @@ const surfaceCommands = [
3979
4095
  jsonPath: ["address", "country"],
3980
4096
  description: "The country",
3981
4097
  valueName: "value",
4098
+ nullable: true,
3982
4099
  schema: z.string()
3983
4100
  },
3984
4101
  {
@@ -3986,6 +4103,7 @@ const surfaceCommands = [
3986
4103
  jsonPath: ["address", "formattedAddress"],
3987
4104
  description: "The whole address on one line",
3988
4105
  valueName: "value",
4106
+ nullable: true,
3989
4107
  schema: z.string()
3990
4108
  },
3991
4109
  {
@@ -3993,6 +4111,7 @@ const surfaceCommands = [
3993
4111
  jsonPath: ["address", "postalCode"],
3994
4112
  description: "The postal or ZIP code",
3995
4113
  valueName: "value",
4114
+ nullable: true,
3996
4115
  schema: z.string()
3997
4116
  },
3998
4117
  {
@@ -4000,6 +4119,7 @@ const surfaceCommands = [
4000
4119
  jsonPath: ["address", "state"],
4001
4120
  description: "The state or region",
4002
4121
  valueName: "value",
4122
+ nullable: true,
4003
4123
  schema: z.string()
4004
4124
  },
4005
4125
  {
@@ -4007,6 +4127,7 @@ const surfaceCommands = [
4007
4127
  jsonPath: ["consignee"],
4008
4128
  description: "The ID of the customer a zone is designated for, such as for reservations, provisioning or a 3PL",
4009
4129
  valueName: "value",
4130
+ nullable: true,
4010
4131
  schema: z.string()
4011
4132
  },
4012
4133
  {
@@ -4014,6 +4135,7 @@ const surfaceCommands = [
4014
4135
  jsonPath: ["customerId"],
4015
4136
  description: "The ID of the customer to assign a site to, or null for your organization's own site",
4016
4137
  valueName: "value",
4138
+ nullable: true,
4017
4139
  schema: z.string()
4018
4140
  },
4019
4141
  {
@@ -4021,6 +4143,7 @@ const surfaceCommands = [
4021
4143
  jsonPath: ["description"],
4022
4144
  description: "A free-form description of a zone",
4023
4145
  valueName: "value",
4146
+ nullable: true,
4024
4147
  schema: z.string()
4025
4148
  },
4026
4149
  {
@@ -4053,6 +4176,7 @@ const surfaceCommands = [
4053
4176
  jsonPath: ["parentLocationId"],
4054
4177
  description: "The ID of the site a zone belongs to, required for a zone and refused for a site",
4055
4178
  valueName: "value",
4179
+ nullable: true,
4056
4180
  schema: z.string()
4057
4181
  },
4058
4182
  {
@@ -4100,6 +4224,7 @@ const surfaceCommands = [
4100
4224
  jsonPath: ["address", "addressLine1"],
4101
4225
  description: "The first line of the street address",
4102
4226
  valueName: "value",
4227
+ nullable: true,
4103
4228
  schema: z.string()
4104
4229
  },
4105
4230
  {
@@ -4107,6 +4232,7 @@ const surfaceCommands = [
4107
4232
  jsonPath: ["address", "addressLine2"],
4108
4233
  description: "The second line of the street address, such as a suite",
4109
4234
  valueName: "value",
4235
+ nullable: true,
4110
4236
  schema: z.string()
4111
4237
  },
4112
4238
  {
@@ -4114,6 +4240,7 @@ const surfaceCommands = [
4114
4240
  jsonPath: ["address", "city"],
4115
4241
  description: "The city",
4116
4242
  valueName: "value",
4243
+ nullable: true,
4117
4244
  schema: z.string()
4118
4245
  },
4119
4246
  {
@@ -4121,6 +4248,7 @@ const surfaceCommands = [
4121
4248
  jsonPath: ["address", "country"],
4122
4249
  description: "The country",
4123
4250
  valueName: "value",
4251
+ nullable: true,
4124
4252
  schema: z.string()
4125
4253
  },
4126
4254
  {
@@ -4128,6 +4256,7 @@ const surfaceCommands = [
4128
4256
  jsonPath: ["address", "formattedAddress"],
4129
4257
  description: "The whole address on one line",
4130
4258
  valueName: "value",
4259
+ nullable: true,
4131
4260
  schema: z.string()
4132
4261
  },
4133
4262
  {
@@ -4135,6 +4264,7 @@ const surfaceCommands = [
4135
4264
  jsonPath: ["address", "postalCode"],
4136
4265
  description: "The postal or ZIP code",
4137
4266
  valueName: "value",
4267
+ nullable: true,
4138
4268
  schema: z.string()
4139
4269
  },
4140
4270
  {
@@ -4142,6 +4272,7 @@ const surfaceCommands = [
4142
4272
  jsonPath: ["address", "state"],
4143
4273
  description: "The state or region",
4144
4274
  valueName: "value",
4275
+ nullable: true,
4145
4276
  schema: z.string()
4146
4277
  },
4147
4278
  {
@@ -4149,6 +4280,7 @@ const surfaceCommands = [
4149
4280
  jsonPath: ["consignee"],
4150
4281
  description: "The ID of the customer a zone is designated for, such as for reservations, provisioning or a 3PL",
4151
4282
  valueName: "value",
4283
+ nullable: true,
4152
4284
  schema: z.string()
4153
4285
  },
4154
4286
  {
@@ -4156,6 +4288,7 @@ const surfaceCommands = [
4156
4288
  jsonPath: ["customerId"],
4157
4289
  description: "The ID of the customer to assign a site to, or null for your organization's own site",
4158
4290
  valueName: "value",
4291
+ nullable: true,
4159
4292
  schema: z.string()
4160
4293
  },
4161
4294
  {
@@ -4163,30 +4296,35 @@ const surfaceCommands = [
4163
4296
  jsonPath: ["description"],
4164
4297
  description: "A free-form description of a zone",
4165
4298
  valueName: "value",
4299
+ nullable: true,
4166
4300
  schema: z.string()
4167
4301
  },
4168
4302
  {
4169
4303
  name: "is-archived",
4170
4304
  jsonPath: ["isArchived"],
4171
4305
  description: "Whether the location is archived, and archiving a site archives its zones",
4306
+ nullable: true,
4172
4307
  schema: z.boolean()
4173
4308
  },
4174
4309
  {
4175
4310
  name: "is-inventory",
4176
4311
  jsonPath: ["isInventory"],
4177
4312
  description: "Whether assets at the location count as inventory for reporting",
4313
+ nullable: true,
4178
4314
  schema: z.boolean()
4179
4315
  },
4180
4316
  {
4181
4317
  name: "is-inventory-override",
4182
4318
  jsonPath: ["isInventoryOverride"],
4183
4319
  description: "Whether a zone sets its own isInventory rather than inheriting its parent site's, which a site refuses",
4320
+ nullable: true,
4184
4321
  schema: z.boolean()
4185
4322
  },
4186
4323
  {
4187
4324
  name: "is-transient",
4188
4325
  jsonPath: ["isTransient"],
4189
4326
  description: "Whether assets make only occasional or temporary stops at the location, which hides it from location lists by default",
4327
+ nullable: true,
4190
4328
  schema: z.boolean()
4191
4329
  },
4192
4330
  {
@@ -4194,6 +4332,7 @@ const surfaceCommands = [
4194
4332
  jsonPath: ["name"],
4195
4333
  description: "The location's display name",
4196
4334
  valueName: "value",
4335
+ nullable: true,
4197
4336
  schema: z.string()
4198
4337
  },
4199
4338
  {
@@ -4242,6 +4381,23 @@ const surfaceCommands = [
4242
4381
  }
4243
4382
  ]
4244
4383
  },
4384
+ {
4385
+ name: "token",
4386
+ summary: "Token commands",
4387
+ arguments: [],
4388
+ flags: [],
4389
+ examples: [],
4390
+ subcommands: [defineOperation({
4391
+ name: "get",
4392
+ summary: "Report the credential this CLI is calling with",
4393
+ example: "hardfin token get",
4394
+ method: "GET",
4395
+ path: "/token",
4396
+ pathParameters: [],
4397
+ queryFlags: [],
4398
+ bodyFlags: []
4399
+ })]
4400
+ },
4245
4401
  {
4246
4402
  name: "url-link",
4247
4403
  summary: "URL link commands",
@@ -4280,12 +4436,14 @@ const surfaceCommands = [
4280
4436
  jsonPath: ["name"],
4281
4437
  description: "The link's display name, or null to show the address instead",
4282
4438
  valueName: "value",
4439
+ nullable: true,
4283
4440
  schema: z.string()
4284
4441
  }, {
4285
4442
  name: "url",
4286
4443
  jsonPath: ["url"],
4287
4444
  description: "The address the link points to, which cannot be empty or null",
4288
4445
  valueName: "value",
4446
+ nullable: true,
4289
4447
  schema: z.string()
4290
4448
  }]
4291
4449
  }),
@@ -4376,8 +4534,8 @@ function toFile(path) {
4376
4534
  //#endregion
4377
4535
  //#region src/command/status.ts
4378
4536
  /**
4379
- * Hardfin expires an unused refresh token after this long. It is the server's rule, not the
4380
- * CLI's, and the token endpoint reports no expiry, so what this produces is an estimate.
4537
+ * What the CLI falls back to for an older sign in, stored before the server began reporting
4538
+ * when a refresh token expires. Hardfin's own rule, and an estimate rather than a fact.
4381
4539
  */
4382
4540
  const REFRESH_SLIDING_DAYS = 90;
4383
4541
  const statusCommand = defineCommand({
@@ -4481,8 +4639,8 @@ function toCredentialReport(apiKey, stored) {
4481
4639
  fingerprint: toFingerprint(stored.refreshToken),
4482
4640
  signedInAt: stored.signedInAt ?? null,
4483
4641
  renewedAt: stored.renewedAt ?? null,
4484
- refreshExpiresAt: toRefreshExpiry(stored.renewedAt),
4485
- refreshExpiryIsEstimated: true
4642
+ refreshExpiresAt: stored.expiresAt ?? toRefreshExpiry(stored.renewedAt),
4643
+ refreshExpiryIsEstimated: stored.expiresAt === void 0
4486
4644
  };
4487
4645
  }
4488
4646
  function toServerReport(metadata) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hardfin/cli",
3
- "version": "0.0.2-dev.12",
3
+ "version": "0.0.2-dev.14",
4
4
  "description": "Command line interface for the Hardfin API",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Hardfin, Inc.",