@velaro/cli 1.4.101 → 1.4.103

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 (47) hide show
  1. package/README.md +19 -0
  2. package/bin/velaro.js +12 -0
  3. package/lib/api.js +2 -1
  4. package/lib/apple-pay.js +32 -0
  5. package/lib/apple-pay.test.js +32 -0
  6. package/lib/avatar-switch.js +42 -0
  7. package/lib/avatar-switch.test.js +49 -0
  8. package/lib/build-info.js +28 -0
  9. package/lib/build-info.test.js +24 -0
  10. package/lib/commands/apple-pay.js +73 -0
  11. package/lib/commands/avatar.js +60 -2
  12. package/lib/commands/billing-automation.js +172 -0
  13. package/lib/commands/copilotstudio.js +14 -1
  14. package/lib/commands/enterprise-reports.js +13 -1
  15. package/lib/commands/entitlement.js +29 -1
  16. package/lib/commands/focus.js +1 -1
  17. package/lib/commands/index.js +38 -2
  18. package/lib/commands/logs-insights.js +342 -0
  19. package/lib/commands/logs.js +313 -3
  20. package/lib/commands/magento.js +16 -0
  21. package/lib/commands/mcp-key.js +23 -1
  22. package/lib/commands/netsuite.js +67 -2
  23. package/lib/commands/notifications.js +34 -1
  24. package/lib/commands/ops.js +23 -54
  25. package/lib/commands/report-backfill.js +23 -5
  26. package/lib/commands/report.js +77 -14
  27. package/lib/commands/salesforce.js +101 -0
  28. package/lib/commands/shopify.js +84 -0
  29. package/lib/commands/signature.js +79 -0
  30. package/lib/commands/site-builder.js +30 -0
  31. package/lib/commands/support.js +22 -0
  32. package/lib/commands/teams.js +11 -1
  33. package/lib/commands/workflow.js +33 -0
  34. package/lib/commands/zoom-phone.js +15 -0
  35. package/lib/enterprise-reports.test.js +20 -1
  36. package/lib/entitlement-report-packages.test.js +47 -0
  37. package/lib/logs-insights.test.js +146 -0
  38. package/lib/mcp-key.test.js +11 -0
  39. package/lib/messaging-routes.test.js +10 -1
  40. package/lib/oauth.js +14 -2
  41. package/lib/report-range.js +21 -0
  42. package/lib/report-range.test.js +38 -0
  43. package/lib/shopify-write-policy.test.js +34 -0
  44. package/lib/signature-policy.js +70 -0
  45. package/lib/signature-policy.test.js +48 -0
  46. package/lib/year-in-review-range.js +44 -0
  47. package/package.json +1 -1
@@ -0,0 +1,48 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { parseMode, parseTeamId, buildPolicyBody, findPolicy, describeMode } from './signature-policy.js';
4
+
5
+ test('parseMode maps friendly names to API values and rejects unknown ones', () => {
6
+ assert.equal(parseMode('locked'), 'admin_locked');
7
+ assert.equal(parseMode('Company-Default'), 'company_default');
8
+ assert.equal(parseMode('personal_only'), 'personal_only');
9
+ assert.equal(parseMode('default'), null);
10
+ assert.equal(parseMode(undefined), undefined);
11
+ assert.throws(() => parseMode('strict'), /mode must be/);
12
+ });
13
+
14
+ test('parseTeamId defaults to company-wide and rejects junk', () => {
15
+ assert.equal(parseTeamId(undefined), 0);
16
+ assert.equal(parseTeamId('7'), 7);
17
+ assert.throws(() => parseTeamId('abc'), /teamId/);
18
+ assert.throws(() => parseTeamId(-1), /teamId/);
19
+ });
20
+
21
+ test('buildPolicyBody keeps current values for fields that are not passed', () => {
22
+ const cur = { teamId: 0, mode: 'company_default', corporateSignature: '<b>Acme</b>', disclaimerEnabled: true, disclaimerText: 'Confidential' };
23
+ const body = buildPolicyBody(cur, { mode: 'locked' });
24
+ assert.deepEqual(body, { teamId: 0, mode: 'admin_locked', corporateSignature: '<b>Acme</b>', disclaimerEnabled: true, disclaimerText: 'Confidential' });
25
+ });
26
+
27
+ test('buildPolicyBody with no existing row starts from all-null (follow company-wide)', () => {
28
+ const body = buildPolicyBody(undefined, { teamId: 5, disclaimerEnabled: true });
29
+ assert.deepEqual(body, { teamId: 5, mode: null, corporateSignature: null, disclaimerEnabled: true, disclaimerText: null });
30
+ });
31
+
32
+ test('null clears a field and over-long text is rejected before sending', () => {
33
+ const cur = { teamId: 0, mode: 'admin_locked', disclaimerEnabled: true, disclaimerText: 'x' };
34
+ assert.equal(buildPolicyBody(cur, { disclaimerEnabled: null }).disclaimerEnabled, null);
35
+ assert.equal(buildPolicyBody(cur, { mode: 'default' }).mode, null);
36
+ assert.throws(() => buildPolicyBody(cur, { disclaimerText: 'a'.repeat(2001) }), /2000/);
37
+ assert.throws(() => buildPolicyBody(cur, { corporateSignature: 'a'.repeat(4001) }), /4000/);
38
+ assert.throws(() => buildPolicyBody(cur, { disclaimerEnabled: 'yes' }), /true, false or null/);
39
+ });
40
+
41
+ test('findPolicy picks the row for a team and describeMode is readable', () => {
42
+ const rows = [{ teamId: 0, mode: 'personal_only' }, { teamId: 3, mode: 'admin_locked' }];
43
+ assert.equal(findPolicy(rows, 3).mode, 'admin_locked');
44
+ assert.equal(findPolicy(rows, undefined).teamId, 0);
45
+ assert.equal(findPolicy(null, 1), undefined);
46
+ assert.match(describeMode('admin_locked'), /locked/);
47
+ assert.match(describeMode(null), /follows/);
48
+ });
@@ -0,0 +1,44 @@
1
+ // Year in review (Enterprise Reports item 16) range helpers. The default is the last 12 whole calendar months in Pacific time,
2
+ // sent to the server as a half-open [from, to) pair of ISO instants (Pacific midnight), same rule as the Enterprise Reports tab.
3
+ // mcp/server.js carries the same logic inline (it is a separate package); enterprise-reports.test.js pins this one.
4
+
5
+ const ZONE = 'America/Los_Angeles';
6
+
7
+ function offsetMs(instantMs) {
8
+ const parts = new Intl.DateTimeFormat('en-US', { timeZone: ZONE, hourCycle: 'h23', year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' }).formatToParts(new Date(instantMs));
9
+ const g = (t) => Number(parts.find((p) => p.type === t).value);
10
+ return Date.UTC(g('year'), g('month') - 1, g('day'), g('hour'), g('minute'), g('second')) - Math.floor(instantMs / 1000) * 1000;
11
+ }
12
+
13
+ /** ISO instant of Pacific midnight at the start of the yyyy-MM-dd calendar day. */
14
+ export function pacificMidnightIso(key) {
15
+ const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(key || '');
16
+ if (!m) throw new Error(`Invalid date "${key}", expected yyyy-MM-dd`);
17
+ const wall = Date.UTC(Number(m[1]), Number(m[2]) - 1, Number(m[3]));
18
+ let t = wall - offsetMs(wall);
19
+ t = wall - offsetMs(t);
20
+ return new Date(t).toISOString();
21
+ }
22
+
23
+ export function addDays(key, n) {
24
+ const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(key);
25
+ return new Date(Date.UTC(Number(m[1]), Number(m[2]) - 1, Number(m[3]) + n)).toISOString().slice(0, 10);
26
+ }
27
+
28
+ /** Last 12 whole Pacific calendar months as inclusive day keys: { from: first day, to: last day }. */
29
+ export function lastTwelveWholeMonthsKeys(now = new Date()) {
30
+ const today = new Intl.DateTimeFormat('en-CA', { timeZone: ZONE, year: 'numeric', month: '2-digit', day: '2-digit' }).format(now); // yyyy-MM-dd
31
+ const y = Number(today.slice(0, 4));
32
+ const mo = today.slice(5, 7);
33
+ const firstOfThisMonth = `${today.slice(0, 4)}-${mo}-01`;
34
+ return { from: `${String(y - 1).padStart(4, '0')}-${mo}-01`, to: addDays(firstOfThisMonth, -1) };
35
+ }
36
+
37
+ /** The request body: { from, to } instants. `from`/`to` are inclusive yyyy-MM-dd day keys; both default to the last 12 whole months. */
38
+ export function yearInReviewBody(from, to, now = new Date()) {
39
+ const def = lastTwelveWholeMonthsKeys(now);
40
+ const f = from || def.from;
41
+ const t = to || def.to;
42
+ if (f > t) throw new Error('--from must be on or before --to');
43
+ return { from: pacificMidnightIso(f), to: pacificMidnightIso(addDays(t, 1)) };
44
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@velaro/cli",
3
- "version": "1.4.101",
3
+ "version": "1.4.103",
4
4
  "description": "Velaro Workspace v20 — command-line interface for managing bots, knowledge base ingestion, MCP API keys, search indexes, and ops health.",
5
5
  "type": "module",
6
6
  "bin": {