@powerhousedao/contributor-billing 0.1.53 → 1.0.0-dev.10

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 (189) hide show
  1. package/dist/document-models/account-transactions/gen/schema/zod.d.ts.map +1 -1
  2. package/dist/document-models/account-transactions/gen/schema/zod.js +3 -3
  3. package/dist/document-models/account-transactions/module.d.ts +1 -1
  4. package/dist/document-models/account-transactions/module.d.ts.map +1 -1
  5. package/dist/document-models/account-transactions/module.js +1 -1
  6. package/dist/document-models/accounts/gen/schema/zod.d.ts.map +1 -1
  7. package/dist/document-models/accounts/module.d.ts +1 -1
  8. package/dist/document-models/accounts/module.d.ts.map +1 -1
  9. package/dist/document-models/accounts/module.js +1 -1
  10. package/dist/document-models/billing-statement/gen/schema/zod.d.ts.map +1 -1
  11. package/dist/document-models/billing-statement/gen/schema/zod.js +4 -4
  12. package/dist/document-models/billing-statement/module.d.ts +1 -1
  13. package/dist/document-models/billing-statement/module.d.ts.map +1 -1
  14. package/dist/document-models/billing-statement/module.js +1 -1
  15. package/dist/document-models/expense-report/gen/schema/zod.d.ts.map +1 -1
  16. package/dist/document-models/expense-report/gen/schema/zod.js +38 -18
  17. package/dist/document-models/expense-report/module.d.ts +1 -1
  18. package/dist/document-models/expense-report/module.d.ts.map +1 -1
  19. package/dist/document-models/expense-report/module.js +1 -1
  20. package/dist/document-models/invoice/gen/document-model.d.ts.map +1 -1
  21. package/dist/document-models/invoice/gen/document-model.js +150 -150
  22. package/dist/document-models/invoice/gen/schema/types.d.ts +3 -6
  23. package/dist/document-models/invoice/gen/schema/types.d.ts.map +1 -1
  24. package/dist/document-models/invoice/gen/schema/zod.d.ts +2 -8
  25. package/dist/document-models/invoice/gen/schema/zod.d.ts.map +1 -1
  26. package/dist/document-models/invoice/gen/schema/zod.js +14 -25
  27. package/dist/document-models/invoice/module.d.ts +1 -1
  28. package/dist/document-models/invoice/module.d.ts.map +1 -1
  29. package/dist/document-models/invoice/module.js +1 -1
  30. package/dist/document-models/invoice/src/reducers/general.d.ts.map +1 -1
  31. package/dist/document-models/invoice/src/reducers/general.js +8 -0
  32. package/dist/document-models/invoice/src/reducers/items.d.ts.map +1 -1
  33. package/dist/document-models/invoice/src/reducers/items.js +2 -1
  34. package/dist/document-models/invoice/src/reducers/parties.d.ts.map +1 -1
  35. package/dist/document-models/invoice/src/reducers/parties.js +6 -2
  36. package/dist/document-models/invoice/src/reducers/transitions.d.ts +0 -5
  37. package/dist/document-models/invoice/src/reducers/transitions.d.ts.map +1 -1
  38. package/dist/document-models/invoice/src/reducers/transitions.js +19 -6
  39. package/dist/document-models/invoice/tests/general.test.js +11 -2
  40. package/dist/document-models/invoice/tests/items.test.js +1 -1
  41. package/dist/document-models/invoice/tests/parties.test.js +1 -1
  42. package/dist/document-models/invoice/tests/transitions.test.js +7 -2
  43. package/dist/document-models/operational-hub-profile/module.d.ts +1 -1
  44. package/dist/document-models/operational-hub-profile/module.d.ts.map +1 -1
  45. package/dist/document-models/operational-hub-profile/module.js +1 -1
  46. package/dist/document-models/snapshot-report/gen/schema/zod.d.ts.map +1 -1
  47. package/dist/document-models/snapshot-report/gen/schema/zod.js +12 -12
  48. package/dist/document-models/snapshot-report/module.d.ts +1 -1
  49. package/dist/document-models/snapshot-report/module.d.ts.map +1 -1
  50. package/dist/document-models/snapshot-report/module.js +1 -1
  51. package/dist/editors/accounts-editor/editor.d.ts.map +1 -1
  52. package/dist/editors/accounts-editor/editor.js +2 -2
  53. package/dist/editors/builder-team-admin/components/DriveExplorer.d.ts.map +1 -1
  54. package/dist/editors/builder-team-admin/components/DriveExplorer.js +64 -4
  55. package/dist/editors/builder-team-admin/module.js +1 -1
  56. package/dist/editors/contributor-billing/components/DashboardHome.d.ts.map +1 -1
  57. package/dist/editors/contributor-billing/components/DashboardHome.js +2 -8
  58. package/dist/editors/contributor-billing/components/DocumentDropZone.d.ts.map +1 -1
  59. package/dist/editors/contributor-billing/components/DocumentDropZone.js +37 -8
  60. package/dist/editors/contributor-billing/components/DriveContents.d.ts.map +1 -1
  61. package/dist/editors/contributor-billing/components/DriveContents.js +4 -1
  62. package/dist/editors/contributor-billing/components/DriveExplorer.d.ts.map +1 -1
  63. package/dist/editors/contributor-billing/components/DriveExplorer.js +54 -3
  64. package/dist/editors/contributor-billing/components/FolderTree.d.ts.map +1 -1
  65. package/dist/editors/contributor-billing/components/FolderTree.js +6 -15
  66. package/dist/editors/contributor-billing/components/InvoiceTable/HeaderControls.d.ts +2 -1
  67. package/dist/editors/contributor-billing/components/InvoiceTable/HeaderControls.d.ts.map +1 -1
  68. package/dist/editors/contributor-billing/components/InvoiceTable/HeaderControls.js +41 -6
  69. package/dist/editors/contributor-billing/components/InvoiceTable/InvoiceTable.d.ts +1 -1
  70. package/dist/editors/contributor-billing/components/InvoiceTable/InvoiceTable.d.ts.map +1 -1
  71. package/dist/editors/contributor-billing/components/InvoiceTable/InvoiceTable.js +16 -1
  72. package/dist/editors/contributor-billing/components/InvoiceTable/InvoiceTableContainer.d.ts +3 -1
  73. package/dist/editors/contributor-billing/components/InvoiceTable/InvoiceTableContainer.d.ts.map +1 -1
  74. package/dist/editors/contributor-billing/components/InvoiceTable/InvoiceTableContainer.js +13 -11
  75. package/dist/editors/contributor-billing/components/MonthReportCard.d.ts +11 -4
  76. package/dist/editors/contributor-billing/components/MonthReportCard.d.ts.map +1 -1
  77. package/dist/editors/contributor-billing/components/MonthReportCard.js +55 -6
  78. package/dist/editors/contributor-billing/components/MonthlyReportsOverview.d.ts +1 -1
  79. package/dist/editors/contributor-billing/components/MonthlyReportsOverview.d.ts.map +1 -1
  80. package/dist/editors/contributor-billing/components/MonthlyReportsOverview.js +104 -7
  81. package/dist/editors/contributor-billing/components/ReportingView.d.ts +0 -3
  82. package/dist/editors/contributor-billing/components/ReportingView.d.ts.map +1 -1
  83. package/dist/editors/contributor-billing/components/ReportingView.js +65 -8
  84. package/dist/editors/contributor-billing/components/ToastRenderer.d.ts +2 -0
  85. package/dist/editors/contributor-billing/components/ToastRenderer.d.ts.map +1 -0
  86. package/dist/editors/contributor-billing/components/ToastRenderer.js +14 -0
  87. package/dist/editors/contributor-billing/components/cbToast.d.ts +16 -0
  88. package/dist/editors/contributor-billing/components/cbToast.d.ts.map +1 -0
  89. package/dist/editors/contributor-billing/components/cbToast.js +29 -0
  90. package/dist/editors/contributor-billing/hooks/useDocumentAutoPlacement.d.ts.map +1 -1
  91. package/dist/editors/contributor-billing/hooks/useDocumentAutoPlacement.js +42 -2
  92. package/dist/editors/contributor-billing/hooks/useMonthlyReports.d.ts +4 -0
  93. package/dist/editors/contributor-billing/hooks/useMonthlyReports.d.ts.map +1 -1
  94. package/dist/editors/contributor-billing/hooks/useMonthlyReports.js +4 -0
  95. package/dist/editors/contributor-billing/module.js +1 -1
  96. package/dist/editors/invoice/InvoicePDF.d.ts.map +1 -1
  97. package/dist/editors/invoice/InvoicePDF.js +12 -9
  98. package/dist/editors/invoice/editor.d.ts.map +1 -1
  99. package/dist/editors/invoice/editor.js +6 -10
  100. package/dist/editors/invoice/exportUBL.d.ts.map +1 -1
  101. package/dist/editors/invoice/exportUBL.js +1 -2
  102. package/dist/editors/invoice/ingestPDF.js +1 -1
  103. package/dist/editors/invoice/invoiceToGnosis.d.ts.map +1 -1
  104. package/dist/editors/invoice/invoiceToGnosis.js +25 -22
  105. package/dist/editors/invoice/invoiceToast.d.ts +4 -0
  106. package/dist/editors/invoice/invoiceToast.d.ts.map +1 -0
  107. package/dist/editors/invoice/invoiceToast.js +6 -0
  108. package/dist/editors/invoice/legalEntity/legalEntity.d.ts +2 -1
  109. package/dist/editors/invoice/legalEntity/legalEntity.d.ts.map +1 -1
  110. package/dist/editors/invoice/legalEntity/legalEntity.js +3 -14
  111. package/dist/editors/invoice/legalEntity/walletSection.d.ts +1 -0
  112. package/dist/editors/invoice/legalEntity/walletSection.d.ts.map +1 -1
  113. package/dist/editors/invoice/legalEntity/walletSection.js +2 -2
  114. package/dist/editors/invoice/lineItems.js +1 -1
  115. package/dist/editors/invoice/requestFinance.d.ts +3 -2
  116. package/dist/editors/invoice/requestFinance.d.ts.map +1 -1
  117. package/dist/editors/invoice/requestFinance.js +38 -42
  118. package/dist/editors/invoice/validation/validationHandler.d.ts +1 -1
  119. package/dist/editors/invoice/validation/validationHandler.d.ts.map +1 -1
  120. package/dist/editors/invoice/validation/validationHandler.js +15 -2
  121. package/dist/editors/invoice/validation/validationManager.d.ts +1 -1
  122. package/dist/editors/invoice/validation/validationManager.d.ts.map +1 -1
  123. package/dist/editors/invoice/validation/validationManager.js +2 -1
  124. package/dist/editors/invoice/validation/validationRules.d.ts +1 -0
  125. package/dist/editors/invoice/validation/validationRules.d.ts.map +1 -1
  126. package/dist/editors/invoice/validation/validationRules.js +26 -1
  127. package/dist/editors/snapshot-report-editor/components/DateRangePicker.d.ts +19 -0
  128. package/dist/editors/snapshot-report-editor/components/DateRangePicker.d.ts.map +1 -0
  129. package/dist/editors/snapshot-report-editor/components/DateRangePicker.js +66 -0
  130. package/dist/editors/snapshot-report-editor/editor.d.ts.map +1 -1
  131. package/dist/editors/snapshot-report-editor/editor.js +72 -48
  132. package/dist/scripts/download-all-drive-documents/download-drive-documents.d.ts +33 -0
  133. package/dist/scripts/download-all-drive-documents/download-drive-documents.d.ts.map +1 -0
  134. package/dist/scripts/download-all-drive-documents/download-drive-documents.js +583 -0
  135. package/dist/scripts/invoice/requestFinance.d.ts +18 -1
  136. package/dist/scripts/invoice/requestFinance.d.ts.map +1 -1
  137. package/dist/scripts/invoice/requestFinance.js +17 -5
  138. package/dist/scripts/upload-phd-documents/upload-phd-documents.d.ts +20 -0
  139. package/dist/scripts/upload-phd-documents/upload-phd-documents.d.ts.map +1 -0
  140. package/dist/scripts/upload-phd-documents/upload-phd-documents.js +313 -0
  141. package/dist/style.css +201 -106
  142. package/dist/subgraphs/budget-statements/resolvers.d.ts +38 -0
  143. package/dist/subgraphs/budget-statements/resolvers.d.ts.map +1 -1
  144. package/dist/subgraphs/budget-statements/resolvers.js +192 -62
  145. package/dist/subgraphs/budget-statements/resolvers.test.d.ts +2 -0
  146. package/dist/subgraphs/budget-statements/resolvers.test.d.ts.map +1 -0
  147. package/dist/subgraphs/budget-statements/resolvers.test.js +339 -0
  148. package/dist/subgraphs/budget-statements/schema.d.ts.map +1 -1
  149. package/dist/subgraphs/budget-statements/schema.js +8 -0
  150. package/dist/subgraphs/index.d.ts +0 -1
  151. package/dist/subgraphs/index.d.ts.map +1 -1
  152. package/dist/subgraphs/index.js +0 -1
  153. package/dist/subgraphs/invoice-addon/customResolvers.d.ts +70 -11
  154. package/dist/subgraphs/invoice-addon/customResolvers.d.ts.map +1 -1
  155. package/dist/subgraphs/invoice-addon/customResolvers.js +12 -27
  156. package/package.json +35 -28
  157. package/dist/document-models/invoice/src/tests/document-model.test.d.ts +0 -10
  158. package/dist/document-models/invoice/src/tests/document-model.test.d.ts.map +0 -1
  159. package/dist/document-models/invoice/src/tests/document-model.test.js +0 -104
  160. package/dist/document-models/invoice/src/tests/general.test.d.ts +0 -6
  161. package/dist/document-models/invoice/src/tests/general.test.d.ts.map +0 -1
  162. package/dist/document-models/invoice/src/tests/general.test.js +0 -49
  163. package/dist/document-models/invoice/src/tests/items.test.d.ts +0 -6
  164. package/dist/document-models/invoice/src/tests/items.test.d.ts.map +0 -1
  165. package/dist/document-models/invoice/src/tests/items.test.js +0 -59
  166. package/dist/document-models/invoice/src/tests/parties.test.d.ts +0 -6
  167. package/dist/document-models/invoice/src/tests/parties.test.d.ts.map +0 -1
  168. package/dist/document-models/invoice/src/tests/parties.test.js +0 -69
  169. package/dist/document-models/invoice/src/tests/transitions.test.d.ts +0 -6
  170. package/dist/document-models/invoice/src/tests/transitions.test.d.ts.map +0 -1
  171. package/dist/document-models/invoice/src/tests/transitions.test.js +0 -59
  172. package/dist/document-models/invoice/utils/statusTransitions.d.ts +0 -13
  173. package/dist/document-models/invoice/utils/statusTransitions.d.ts.map +0 -1
  174. package/dist/document-models/invoice/utils/statusTransitions.js +0 -13
  175. package/dist/editors/builder-team-admin/components/overview/SubscriptionsStats.d.ts +0 -15
  176. package/dist/editors/builder-team-admin/components/overview/SubscriptionsStats.d.ts.map +0 -1
  177. package/dist/editors/builder-team-admin/components/overview/SubscriptionsStats.js +0 -61
  178. package/dist/editors/contributor-billing/components/CreateHubProfileModal.d.ts +0 -12
  179. package/dist/editors/contributor-billing/components/CreateHubProfileModal.d.ts.map +0 -1
  180. package/dist/editors/contributor-billing/components/CreateHubProfileModal.js +0 -74
  181. package/dist/subgraphs/resources-services/index.d.ts +0 -11
  182. package/dist/subgraphs/resources-services/index.d.ts.map +0 -1
  183. package/dist/subgraphs/resources-services/index.js +0 -11
  184. package/dist/subgraphs/resources-services/resolvers.d.ts +0 -3
  185. package/dist/subgraphs/resources-services/resolvers.d.ts.map +0 -1
  186. package/dist/subgraphs/resources-services/resolvers.js +0 -462
  187. package/dist/subgraphs/resources-services/schema.d.ts +0 -3
  188. package/dist/subgraphs/resources-services/schema.d.ts.map +0 -1
  189. package/dist/subgraphs/resources-services/schema.js +0 -284
@@ -0,0 +1,313 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Upload local .phd documents to a Powerhouse switchboard.
4
+ *
5
+ * Works with ANY document type — reads header.json and operations.json from
6
+ * the .phd file, auto-detects the document type, creates a new document via
7
+ * the matching _createDocument mutation, then replays all operations via
8
+ * pushUpdates on the drive endpoint.
9
+ *
10
+ * REQUIRES: Bun runtime (https://bun.sh)
11
+ *
12
+ * Usage:
13
+ * bun scripts/upload-phd-documents/upload-phd-documents.ts <switchboard-url> <drive-id> <file.phd> [file2.phd ...]
14
+ *
15
+ * Examples:
16
+ * bun scripts/upload-phd-documents/upload-phd-documents.ts http://localhost:4001 preview-f80015b9 "op hub.phd" "oh service.phd"
17
+ * bun scripts/upload-phd-documents/upload-phd-documents.ts http://localhost:4001 preview-f80015b9 invoice.phd
18
+ */
19
+ import { inflateRawSync } from "node:zlib";
20
+ import fs from "node:fs";
21
+ // ---------------------------------------------------------------------------
22
+ // ZIP reader (from download script)
23
+ // ---------------------------------------------------------------------------
24
+ function readZipEntry(zipBuf, entryName) {
25
+ let offset = 0;
26
+ while (offset + 30 <= zipBuf.length) {
27
+ const sig = zipBuf.readUInt32LE(offset);
28
+ if (sig !== 0x04034b50)
29
+ break;
30
+ const compressionMethod = zipBuf.readUInt16LE(offset + 8);
31
+ const compressedSize = zipBuf.readUInt32LE(offset + 18);
32
+ const nameLen = zipBuf.readUInt16LE(offset + 26);
33
+ const extraLen = zipBuf.readUInt16LE(offset + 28);
34
+ const nameStart = offset + 30;
35
+ const name = zipBuf
36
+ .subarray(nameStart, nameStart + nameLen)
37
+ .toString("utf-8");
38
+ const dataStart = nameStart + nameLen + extraLen;
39
+ const dataEnd = dataStart + compressedSize;
40
+ if (name === entryName) {
41
+ const raw = zipBuf.subarray(dataStart, dataEnd);
42
+ if (compressionMethod === 8) {
43
+ return Buffer.from(inflateRawSync(raw));
44
+ }
45
+ return Buffer.from(raw);
46
+ }
47
+ offset = dataEnd;
48
+ }
49
+ return null;
50
+ }
51
+ function readPhdJson(filePath, entryName) {
52
+ const zipBuf = fs.readFileSync(filePath);
53
+ const buf = readZipEntry(zipBuf, entryName);
54
+ if (!buf)
55
+ throw new Error(`${entryName} not found in ${filePath}`);
56
+ return JSON.parse(buf.toString("utf-8"));
57
+ }
58
+ // ---------------------------------------------------------------------------
59
+ // GraphQL helper
60
+ // ---------------------------------------------------------------------------
61
+ const REQUEST_DELAY_MS = 200;
62
+ const PUSH_BATCH_SIZE = 50;
63
+ function sleep(ms) {
64
+ return new Promise((resolve) => setTimeout(resolve, ms));
65
+ }
66
+ async function gql(endpoint, query, variables) {
67
+ const res = await fetch(endpoint, {
68
+ method: "POST",
69
+ headers: { "Content-Type": "application/json" },
70
+ body: JSON.stringify({ query, variables }),
71
+ });
72
+ if (!res.ok) {
73
+ const body = await res.text().catch(() => "");
74
+ throw new Error(`GraphQL ${res.status}: ${body.slice(0, 500)}`);
75
+ }
76
+ const json = (await res.json());
77
+ if (json.errors?.length) {
78
+ throw new Error(`GraphQL errors:\n${json.errors.map((e) => ` - ${e.message}`).join("\n")}`);
79
+ }
80
+ if (!json.data)
81
+ throw new Error("No data returned from GraphQL");
82
+ return json.data;
83
+ }
84
+ // ---------------------------------------------------------------------------
85
+ // Document type -> mutation prefix mapping
86
+ // ---------------------------------------------------------------------------
87
+ /**
88
+ * Discover available _createDocument mutations by introspecting the API.
89
+ * Returns a map of documentType -> mutation prefix.
90
+ * e.g. "powerhouse/resource-template" -> "ResourceTemplate"
91
+ */
92
+ async function discoverDocumentTypes(endpoint) {
93
+ const data = await gql(endpoint, `{ __schema { mutationType { fields { name } } } }`);
94
+ const map = new Map();
95
+ for (const field of data.__schema.mutationType.fields) {
96
+ if (!field.name.endsWith("_createDocument"))
97
+ continue;
98
+ const prefix = field.name.replace("_createDocument", "");
99
+ // Convert PascalCase prefix to kebab-case document type
100
+ const kebab = prefix.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
101
+ const docType = `powerhouse/${kebab}`;
102
+ map.set(docType, prefix);
103
+ }
104
+ return map;
105
+ }
106
+ // ---------------------------------------------------------------------------
107
+ // Create document via type-specific _createDocument mutation
108
+ // ---------------------------------------------------------------------------
109
+ async function createDocument(endpoint, driveId, mutationPrefix, name) {
110
+ const mutationName = `${mutationPrefix}_createDocument`;
111
+ const data = await gql(endpoint, `mutation ($name: String!, $driveId: String) {
112
+ ${mutationName}(name: $name, driveId: $driveId)
113
+ }`, { name, driveId });
114
+ return data[mutationName];
115
+ }
116
+ // ---------------------------------------------------------------------------
117
+ // Push operations via pushUpdates on the drive endpoint
118
+ // ---------------------------------------------------------------------------
119
+ async function pushOperations(driveEndpoint, driveId, docId, documentType, operations) {
120
+ let totalPushed = 0;
121
+ for (const scope of ["global", "local"]) {
122
+ const scopeOps = operations[scope];
123
+ if (!scopeOps?.length)
124
+ continue;
125
+ console.log(` Pushing ${scopeOps.length} ${scope} operations...`);
126
+ for (let i = 0; i < scopeOps.length; i += PUSH_BATCH_SIZE) {
127
+ const batch = scopeOps.slice(i, i + PUSH_BATCH_SIZE);
128
+ const inputOps = batch.map((op) => ({
129
+ index: op.index,
130
+ skip: op.skip,
131
+ type: op.action.type,
132
+ id: op.id,
133
+ actionId: op.action.id || op.id,
134
+ input: JSON.stringify(op.action.input),
135
+ hash: op.hash,
136
+ timestampUtcMs: op.timestampUtcMs,
137
+ error: op.error ?? null,
138
+ }));
139
+ const strand = {
140
+ driveId,
141
+ documentId: docId,
142
+ documentType,
143
+ scope,
144
+ branch: "main",
145
+ operations: inputOps,
146
+ };
147
+ if (i > 0)
148
+ await sleep(REQUEST_DELAY_MS);
149
+ const result = await gql(driveEndpoint, `mutation ($strands: [InputStrandUpdate!]) {
150
+ pushUpdates(strands: $strands) { revision status error }
151
+ }`, { strands: [strand] });
152
+ const update = result.pushUpdates[0];
153
+ if (update.status !== "SUCCESS") {
154
+ throw new Error(`pushUpdates failed at batch ${Math.floor(i / PUSH_BATCH_SIZE) + 1}: ` +
155
+ `status=${update.status}, error=${update.error}`);
156
+ }
157
+ totalPushed += batch.length;
158
+ const batchNum = Math.floor(i / PUSH_BATCH_SIZE) + 1;
159
+ const totalBatches = Math.ceil(scopeOps.length / PUSH_BATCH_SIZE);
160
+ console.log(` [${batchNum}/${totalBatches}] ${batch.length} ops -> revision ${update.revision}`);
161
+ }
162
+ }
163
+ return totalPushed;
164
+ }
165
+ // ---------------------------------------------------------------------------
166
+ // State verification
167
+ // ---------------------------------------------------------------------------
168
+ async function verifyState(driveEndpoint, docId, expectedGlobal) {
169
+ const data = await gql(driveEndpoint, `query ($id: String!) { document(id: $id) { stateJSON } }`, { id: docId });
170
+ const actual = data.document.stateJSON;
171
+ const expectedStr = JSON.stringify(expectedGlobal, Object.keys(expectedGlobal).sort());
172
+ const actualStr = JSON.stringify(actual, Object.keys(actual).sort());
173
+ if (expectedStr === actualStr)
174
+ return true;
175
+ // Count differences for reporting
176
+ const allKeys = new Set([
177
+ ...Object.keys(expectedGlobal),
178
+ ...Object.keys(actual),
179
+ ]);
180
+ let diffs = 0;
181
+ for (const key of allKeys) {
182
+ const ev = JSON.stringify(expectedGlobal[key], null, 0);
183
+ const av = JSON.stringify(actual[key], null, 0);
184
+ if (ev !== av) {
185
+ diffs++;
186
+ if (diffs <= 5) {
187
+ const evShort = (ev || "undefined").slice(0, 60);
188
+ const avShort = (av || "undefined").slice(0, 60);
189
+ console.log(` DIFF: ${key}: expected=${evShort} actual=${avShort}`);
190
+ }
191
+ }
192
+ }
193
+ if (diffs > 5) {
194
+ console.log(` ... and ${diffs - 5} more differences`);
195
+ }
196
+ return false;
197
+ }
198
+ // ---------------------------------------------------------------------------
199
+ // Upload a single .phd file
200
+ // ---------------------------------------------------------------------------
201
+ async function uploadPhdFile(baseUrl, driveId, filePath, typeMap) {
202
+ const endpoint = `${baseUrl}/graphql`;
203
+ const driveEndpoint = `${baseUrl}/d/${driveId}`;
204
+ // 1. Read .phd contents
205
+ const header = readPhdJson(filePath, "header.json");
206
+ const operations = readPhdJson(filePath, "operations.json");
207
+ const currentState = readPhdJson(filePath, "current-state.json");
208
+ const docType = header.documentType;
209
+ const docName = header.name || filePath.replace(/^.*\//, "").replace(/\.phd$/, "");
210
+ const globalOpsCount = operations.global?.length ?? 0;
211
+ const localOpsCount = operations.local?.length ?? 0;
212
+ console.log(`\n${"─".repeat(60)}`);
213
+ console.log(` File: ${filePath}`);
214
+ console.log(` Type: ${docType}`);
215
+ console.log(` Name: ${docName || "(unnamed)"}`);
216
+ console.log(` Ops: ${globalOpsCount} global, ${localOpsCount} local`);
217
+ // 2. Find the matching _createDocument mutation
218
+ const mutationPrefix = typeMap.get(docType);
219
+ if (!mutationPrefix) {
220
+ throw new Error(`No _createDocument mutation found for type "${docType}". ` +
221
+ `Available types: ${[...typeMap.keys()].join(", ")}`);
222
+ }
223
+ // 3. Create the document
224
+ console.log(` Creating ${mutationPrefix} document...`);
225
+ const docId = await createDocument(endpoint, driveId, mutationPrefix, docName || "Untitled");
226
+ console.log(` Created: ${docId}`);
227
+ // 4. Push operations
228
+ let totalPushed = 0;
229
+ if (globalOpsCount + localOpsCount > 0) {
230
+ await sleep(REQUEST_DELAY_MS);
231
+ totalPushed = await pushOperations(driveEndpoint, driveId, docId, docType, operations);
232
+ console.log(` Pushed: ${totalPushed} operations`);
233
+ }
234
+ else {
235
+ console.log(` No operations to push`);
236
+ }
237
+ // 5. Verify state
238
+ await sleep(REQUEST_DELAY_MS);
239
+ console.log(` Verifying state...`);
240
+ const stateMatch = await verifyState(driveEndpoint, docId, currentState.global);
241
+ if (stateMatch) {
242
+ console.log(` State: EXACT MATCH`);
243
+ }
244
+ else {
245
+ console.log(` State: MISMATCH (see diffs above — may be expected with schema changes)`);
246
+ }
247
+ return {
248
+ file: filePath,
249
+ documentType: docType,
250
+ docId,
251
+ name: docName,
252
+ operationsPushed: totalPushed,
253
+ stateMatch,
254
+ };
255
+ }
256
+ // ---------------------------------------------------------------------------
257
+ // Main
258
+ // ---------------------------------------------------------------------------
259
+ async function main() {
260
+ const args = process.argv.slice(2);
261
+ if (args.length < 3) {
262
+ console.log("Usage: bun scripts/upload-phd-documents/upload-phd-documents.ts <switchboard-url> <drive-id> <file.phd> [file2.phd ...]");
263
+ console.log("\nExamples:" +
264
+ '\n bun scripts/upload-phd-documents/upload-phd-documents.ts http://localhost:4001 preview-f80015b9 "op hub.phd" "oh service.phd"' +
265
+ "\n bun scripts/upload-phd-documents/upload-phd-documents.ts http://localhost:4001 preview-f80015b9 invoice.phd");
266
+ process.exit(1);
267
+ }
268
+ const [rawBaseUrl, driveId, ...phdFiles] = args;
269
+ const baseUrl = rawBaseUrl.replace(/\/+$/, "").replace(/\/graphql$/i, "");
270
+ console.log(`Switchboard: ${baseUrl}`);
271
+ console.log(`Drive: ${driveId}`);
272
+ console.log(`Files: ${phdFiles.length}`);
273
+ // Discover available document types from the API
274
+ console.log(`\nDiscovering document types...`);
275
+ const typeMap = await discoverDocumentTypes(`${baseUrl}/graphql`);
276
+ console.log(` Found ${typeMap.size} types: ${[...typeMap.keys()].join(", ")}`);
277
+ // Upload each .phd file
278
+ const results = [];
279
+ const failures = [];
280
+ for (const file of phdFiles) {
281
+ try {
282
+ const result = await uploadPhdFile(baseUrl, driveId, file, typeMap);
283
+ results.push(result);
284
+ }
285
+ catch (err) {
286
+ const reason = err instanceof Error ? err.message : String(err);
287
+ console.error(`\n FAILED: ${file}`);
288
+ console.error(` Reason: ${reason}`);
289
+ failures.push({ file, reason });
290
+ }
291
+ }
292
+ // Summary
293
+ console.log(`\n${"=".repeat(60)}`);
294
+ console.log(`DONE`);
295
+ console.log(`${"=".repeat(60)}`);
296
+ console.log(` Drive: ${driveId}`);
297
+ console.log(` Uploaded: ${results.length}`);
298
+ console.log(` Failed: ${failures.length}`);
299
+ for (const r of results) {
300
+ const stateIcon = r.stateMatch ? "OK" : "~";
301
+ console.log(` [${stateIcon}] ${r.name || r.file} (${r.documentType}) -> ${r.docId} (${r.operationsPushed} ops)`);
302
+ }
303
+ for (const f of failures) {
304
+ console.log(` [X] ${f.file}: ${f.reason}`);
305
+ }
306
+ if (failures.length > 0) {
307
+ process.exit(1);
308
+ }
309
+ }
310
+ main().catch((err) => {
311
+ console.error(err);
312
+ process.exit(1);
313
+ });