@markwharton/liquidplanner 2.0.0 → 2.0.1

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/README.md +68 -33
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -16,29 +16,36 @@ import { LPClient, resolveTaskToAssignment } from '@markwharton/liquidplanner';
16
16
  const client = new LPClient({ apiToken: 'xxx', workspaceId: 123 });
17
17
 
18
18
  // Validate credentials
19
- await client.validateToken();
19
+ const validation = await client.validateToken();
20
+ if (!validation.ok) throw new Error(validation.error);
20
21
 
21
22
  // Get workspaces
22
- const { workspaces } = await client.getWorkspaces();
23
+ const wsResult = await client.getWorkspaces();
24
+ if (wsResult.ok) console.log(wsResult.data); // LPWorkspace[]
23
25
 
24
26
  // Get workspace members
25
- const { members } = await client.getWorkspaceMembers();
27
+ const membersResult = await client.getWorkspaceMembers();
28
+ if (membersResult.ok) console.log(membersResult.data); // LPMember[]
26
29
 
27
30
  // Get user's assignments (for task picker)
28
- const { assignments } = await client.getMyAssignments(memberId);
31
+ const assignResult = await client.getMyAssignments(memberId);
32
+ if (assignResult.ok) console.log(assignResult.data); // LPItem[]
29
33
 
30
34
  // Get assignments with parent task/project names resolved
31
- const { assignments: enriched } = await client.getMyAssignmentsWithContext(memberId, {
35
+ const ctxResult = await client.getMyAssignmentsWithContext(memberId, {
32
36
  includeProject: true // optional: also fetch project names
33
37
  });
38
+ if (ctxResult.ok) console.log(ctxResult.data); // LPAssignmentWithContext[]
34
39
 
35
40
  // Get assignments with full hierarchy path
36
- const { assignments: withHierarchy } = await client.getMyAssignmentsWithContext(memberId, {
41
+ const hierResult = await client.getMyAssignmentsWithContext(memberId, {
37
42
  includeHierarchy: true // includes ancestors and hierarchyPath
38
43
  });
44
+ if (hierResult.ok) console.log(hierResult.data); // LPAssignmentWithContext[]
39
45
 
40
46
  // Get item ancestors (hierarchy chain)
41
- const { ancestors } = await client.getItemAncestors(itemId);
47
+ const ancResult = await client.getItemAncestors(itemId);
48
+ if (ancResult.ok) console.log(ancResult.data); // LPAncestor[]
42
49
 
43
50
  // Resolve task to assignment
44
51
  const resolution = await resolveTaskToAssignment(client, taskId, memberId);
@@ -52,31 +59,39 @@ await client.createTimesheetEntry({
52
59
  });
53
60
 
54
61
  // Query existing entries for a date
55
- const { entries } = await client.getTimesheetEntries('2026-01-29', assignmentId);
62
+ const tsResult = await client.getTimesheetEntries('2026-01-29', assignmentId);
63
+ if (tsResult.ok) console.log(tsResult.data); // LPTimesheetEntryWithId[]
56
64
 
57
65
  // Update an existing entry (accumulate hours)
58
- await client.updateTimesheetEntry(entryId, existingEntry, {
59
- hours: existingEntry.hours + 1.5,
66
+ const existing = tsResult.data![0];
67
+ await client.updateTimesheetEntry(existing.id, existing, {
68
+ hours: existing.hours + 1.5,
60
69
  note: 'Additional work'
61
70
  });
62
71
 
63
72
  // Find items with filters
64
- const { items } = await client.findItems({
73
+ const lateResult = await client.findItems({
65
74
  itemType: 'tasks',
66
75
  taskStatusGroupNot: 'done',
67
76
  late: true,
68
77
  });
78
+ if (lateResult.ok) console.log(lateResult.data); // LPItem[]
69
79
 
70
80
  // Get children of an item
71
- const { items: children } = await client.getChildren(parentId);
81
+ const childResult = await client.getChildren(parentId);
82
+ if (childResult.ok) console.log(childResult.data); // LPItem[]
72
83
 
73
84
  // Get workspace tree snapshot (cached, all hierarchy lookups resolved in memory)
74
- const { tree } = await client.getWorkspaceTree();
85
+ const treeResult = await client.getWorkspaceTree();
86
+ if (treeResult.ok) console.log(treeResult.data); // LPWorkspaceTree
75
87
 
76
88
  // Get a member's work with full context from the tree
77
- const { assignments: myWork, treeItemCount } = await client.getMyWork(memberId);
78
- // Each assignment includes taskName, projectId, projectName, hierarchyPath, ancestors
79
- // treeItemCount shows total items loaded (only member's assignments returned downstream)
89
+ const workResult = await client.getMyWork(memberId);
90
+ if (workResult.ok) {
91
+ const { assignments, treeItemCount } = workResult.data;
92
+ // Each assignment includes taskName, projectId, projectName, hierarchyPath, ancestors
93
+ // treeItemCount shows total items loaded (only member's assignments returned downstream)
94
+ }
80
95
  ```
81
96
 
82
97
  ### Tree Utilities
@@ -97,29 +112,49 @@ const path = getTreeHierarchyPath(tree, itemId);
97
112
  const lateTasks = findInTree(tree, item => item.late === true);
98
113
  ```
99
114
 
100
- ## API Reference
115
+ ## Result Pattern
116
+
117
+ All methods return `Result<T>` objects rather than throwing exceptions. Always check `ok` before accessing `data`:
118
+
119
+ ```typescript
120
+ interface Result<T> {
121
+ ok: boolean;
122
+ data?: T; // present when ok is true
123
+ error?: string; // present when ok is false
124
+ status?: number; // HTTP status code on error
125
+ }
126
+ ```
101
127
 
102
- All methods return `{ data?, error? }` result objects rather than throwing exceptions.
128
+ ```typescript
129
+ const result = await client.getMyWork(memberId);
130
+ if (!result.ok) {
131
+ console.error(result.error, result.status);
132
+ return;
133
+ }
134
+ const { assignments, treeItemCount } = result.data;
135
+ ```
136
+
137
+ ## API Reference
103
138
 
104
139
  | Method | Parameters | Returns |
105
140
  |--------|-----------|---------|
106
- | `validateToken()` | — | `{ valid, error? }` |
107
- | `getWorkspaces()` | — | `{ workspaces?, error? }` |
108
- | `getWorkspaceMembers()` | — | `{ members?, error? }` |
109
- | `getItem(itemId)` | `number` | `{ item?, error? }` |
110
- | `getItems(itemIds)` | `number[]` | `{ items?, error? }` |
111
- | `getItemAncestors(itemId)` | `number` | `{ ancestors?, error? }` |
112
- | `findAssignments(taskId)` | `number` | `{ assignments?, error? }` |
113
- | `getMyAssignments(memberId)` | `number` | `{ assignments?, error? }` |
114
- | `getMyAssignmentsWithContext(memberId, options?)` | `number, { includeProject?, includeHierarchy? }` | `{ assignments?, error? }` |
115
- | `findItems(options)` | `LPFindItemsOptions` | `{ items?, error? }` |
116
- | `getChildren(parentId, options?)` | `number, { itemType? }?` | `{ items?, error? }` |
117
- | `getWorkspaceTree()` | — | `{ tree?, error? }` |
118
- | `getMyWork(memberId)` | `number` | `{ assignments?, treeItemCount?, error? }` |
141
+ | `validateToken()` | — | `Result<void>` |
142
+ | `getWorkspaces()` | — | `Result<LPWorkspace[]>` |
143
+ | `getWorkspaceMembers()` | — | `Result<LPMember[]>` |
144
+ | `getItem(itemId)` | `number` | `Result<LPItem>` |
145
+ | `getItems(itemIds)` | `number[]` | `Result<LPItem[]>` |
146
+ | `getItemAncestors(itemId)` | `number` | `Result<LPAncestor[]>` |
147
+ | `findAssignments(taskId)` | `number` | `Result<LPItem[]>` |
148
+ | `getMyAssignments(memberId)` | `number` | `Result<LPItem[]>` |
149
+ | `getMyAssignmentsWithContext(memberId, options?)` | `number, { includeProject?, includeHierarchy? }` | `Result<LPAssignmentWithContext[]>` |
150
+ | `findItems(options)` | `LPFindItemsOptions` | `Result<LPItem[]>` |
151
+ | `getChildren(parentId, options?)` | `number, { itemType? }?` | `Result<LPItem[]>` |
152
+ | `getWorkspaceTree()` | — | `Result<LPWorkspaceTree>` |
153
+ | `getMyWork(memberId)` | `number` | `Result<{ assignments: LPAssignmentWithContext[], treeItemCount: number }>` |
119
154
  | `invalidateTreeCache()` | — | `void` |
120
- | `getCostCodes()` | — | `{ costCodes?, error? }` |
155
+ | `getCostCodes()` | — | `Result<LPCostCode[]>` |
121
156
  | `createTimesheetEntry(entry)` | `LPTimesheetEntry` | `LPSyncResult` |
122
- | `getTimesheetEntries(date, itemId?)` | `string \| string[], number?` | `{ entries?, error? }` |
157
+ | `getTimesheetEntries(date, itemId?)` | `string \| string[], number?` | `Result<LPTimesheetEntryWithId[]>` |
123
158
  | `updateTimesheetEntry(entryId, existing, updates)` | `number, LPTimesheetEntryWithId, Partial<LPTimesheetEntry>` | `LPSyncResult` |
124
159
  | `upsertTimesheetEntry(entry, options?)` | `LPTimesheetEntry, LPUpsertOptions?` | `LPSyncResult` |
125
160
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markwharton/liquidplanner",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "LiquidPlanner API client for timesheet integration",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",