@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.
- package/dist/document-models/account-transactions/gen/schema/zod.d.ts.map +1 -1
- package/dist/document-models/account-transactions/gen/schema/zod.js +3 -3
- package/dist/document-models/account-transactions/module.d.ts +1 -1
- package/dist/document-models/account-transactions/module.d.ts.map +1 -1
- package/dist/document-models/account-transactions/module.js +1 -1
- package/dist/document-models/accounts/gen/schema/zod.d.ts.map +1 -1
- package/dist/document-models/accounts/module.d.ts +1 -1
- package/dist/document-models/accounts/module.d.ts.map +1 -1
- package/dist/document-models/accounts/module.js +1 -1
- package/dist/document-models/billing-statement/gen/schema/zod.d.ts.map +1 -1
- package/dist/document-models/billing-statement/gen/schema/zod.js +4 -4
- package/dist/document-models/billing-statement/module.d.ts +1 -1
- package/dist/document-models/billing-statement/module.d.ts.map +1 -1
- package/dist/document-models/billing-statement/module.js +1 -1
- package/dist/document-models/expense-report/gen/schema/zod.d.ts.map +1 -1
- package/dist/document-models/expense-report/gen/schema/zod.js +38 -18
- package/dist/document-models/expense-report/module.d.ts +1 -1
- package/dist/document-models/expense-report/module.d.ts.map +1 -1
- package/dist/document-models/expense-report/module.js +1 -1
- package/dist/document-models/invoice/gen/document-model.d.ts.map +1 -1
- package/dist/document-models/invoice/gen/document-model.js +150 -150
- package/dist/document-models/invoice/gen/schema/types.d.ts +3 -6
- package/dist/document-models/invoice/gen/schema/types.d.ts.map +1 -1
- package/dist/document-models/invoice/gen/schema/zod.d.ts +2 -8
- package/dist/document-models/invoice/gen/schema/zod.d.ts.map +1 -1
- package/dist/document-models/invoice/gen/schema/zod.js +14 -25
- package/dist/document-models/invoice/module.d.ts +1 -1
- package/dist/document-models/invoice/module.d.ts.map +1 -1
- package/dist/document-models/invoice/module.js +1 -1
- package/dist/document-models/invoice/src/reducers/general.d.ts.map +1 -1
- package/dist/document-models/invoice/src/reducers/general.js +8 -0
- package/dist/document-models/invoice/src/reducers/items.d.ts.map +1 -1
- package/dist/document-models/invoice/src/reducers/items.js +2 -1
- package/dist/document-models/invoice/src/reducers/parties.d.ts.map +1 -1
- package/dist/document-models/invoice/src/reducers/parties.js +6 -2
- package/dist/document-models/invoice/src/reducers/transitions.d.ts +0 -5
- package/dist/document-models/invoice/src/reducers/transitions.d.ts.map +1 -1
- package/dist/document-models/invoice/src/reducers/transitions.js +19 -6
- package/dist/document-models/invoice/tests/general.test.js +11 -2
- package/dist/document-models/invoice/tests/items.test.js +1 -1
- package/dist/document-models/invoice/tests/parties.test.js +1 -1
- package/dist/document-models/invoice/tests/transitions.test.js +7 -2
- package/dist/document-models/operational-hub-profile/module.d.ts +1 -1
- package/dist/document-models/operational-hub-profile/module.d.ts.map +1 -1
- package/dist/document-models/operational-hub-profile/module.js +1 -1
- package/dist/document-models/snapshot-report/gen/schema/zod.d.ts.map +1 -1
- package/dist/document-models/snapshot-report/gen/schema/zod.js +12 -12
- package/dist/document-models/snapshot-report/module.d.ts +1 -1
- package/dist/document-models/snapshot-report/module.d.ts.map +1 -1
- package/dist/document-models/snapshot-report/module.js +1 -1
- package/dist/editors/accounts-editor/editor.d.ts.map +1 -1
- package/dist/editors/accounts-editor/editor.js +2 -2
- package/dist/editors/builder-team-admin/components/DriveExplorer.d.ts.map +1 -1
- package/dist/editors/builder-team-admin/components/DriveExplorer.js +64 -4
- package/dist/editors/builder-team-admin/module.js +1 -1
- package/dist/editors/contributor-billing/components/DashboardHome.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/DashboardHome.js +2 -8
- package/dist/editors/contributor-billing/components/DocumentDropZone.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/DocumentDropZone.js +37 -8
- package/dist/editors/contributor-billing/components/DriveContents.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/DriveContents.js +4 -1
- package/dist/editors/contributor-billing/components/DriveExplorer.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/DriveExplorer.js +54 -3
- package/dist/editors/contributor-billing/components/FolderTree.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/FolderTree.js +6 -15
- package/dist/editors/contributor-billing/components/InvoiceTable/HeaderControls.d.ts +2 -1
- package/dist/editors/contributor-billing/components/InvoiceTable/HeaderControls.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/InvoiceTable/HeaderControls.js +41 -6
- package/dist/editors/contributor-billing/components/InvoiceTable/InvoiceTable.d.ts +1 -1
- package/dist/editors/contributor-billing/components/InvoiceTable/InvoiceTable.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/InvoiceTable/InvoiceTable.js +16 -1
- package/dist/editors/contributor-billing/components/InvoiceTable/InvoiceTableContainer.d.ts +3 -1
- package/dist/editors/contributor-billing/components/InvoiceTable/InvoiceTableContainer.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/InvoiceTable/InvoiceTableContainer.js +13 -11
- package/dist/editors/contributor-billing/components/MonthReportCard.d.ts +11 -4
- package/dist/editors/contributor-billing/components/MonthReportCard.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/MonthReportCard.js +55 -6
- package/dist/editors/contributor-billing/components/MonthlyReportsOverview.d.ts +1 -1
- package/dist/editors/contributor-billing/components/MonthlyReportsOverview.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/MonthlyReportsOverview.js +104 -7
- package/dist/editors/contributor-billing/components/ReportingView.d.ts +0 -3
- package/dist/editors/contributor-billing/components/ReportingView.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/ReportingView.js +65 -8
- package/dist/editors/contributor-billing/components/ToastRenderer.d.ts +2 -0
- package/dist/editors/contributor-billing/components/ToastRenderer.d.ts.map +1 -0
- package/dist/editors/contributor-billing/components/ToastRenderer.js +14 -0
- package/dist/editors/contributor-billing/components/cbToast.d.ts +16 -0
- package/dist/editors/contributor-billing/components/cbToast.d.ts.map +1 -0
- package/dist/editors/contributor-billing/components/cbToast.js +29 -0
- package/dist/editors/contributor-billing/hooks/useDocumentAutoPlacement.d.ts.map +1 -1
- package/dist/editors/contributor-billing/hooks/useDocumentAutoPlacement.js +42 -2
- package/dist/editors/contributor-billing/hooks/useMonthlyReports.d.ts +4 -0
- package/dist/editors/contributor-billing/hooks/useMonthlyReports.d.ts.map +1 -1
- package/dist/editors/contributor-billing/hooks/useMonthlyReports.js +4 -0
- package/dist/editors/contributor-billing/module.js +1 -1
- package/dist/editors/invoice/InvoicePDF.d.ts.map +1 -1
- package/dist/editors/invoice/InvoicePDF.js +12 -9
- package/dist/editors/invoice/editor.d.ts.map +1 -1
- package/dist/editors/invoice/editor.js +6 -10
- package/dist/editors/invoice/exportUBL.d.ts.map +1 -1
- package/dist/editors/invoice/exportUBL.js +1 -2
- package/dist/editors/invoice/ingestPDF.js +1 -1
- package/dist/editors/invoice/invoiceToGnosis.d.ts.map +1 -1
- package/dist/editors/invoice/invoiceToGnosis.js +25 -22
- package/dist/editors/invoice/invoiceToast.d.ts +4 -0
- package/dist/editors/invoice/invoiceToast.d.ts.map +1 -0
- package/dist/editors/invoice/invoiceToast.js +6 -0
- package/dist/editors/invoice/legalEntity/legalEntity.d.ts +2 -1
- package/dist/editors/invoice/legalEntity/legalEntity.d.ts.map +1 -1
- package/dist/editors/invoice/legalEntity/legalEntity.js +3 -14
- package/dist/editors/invoice/legalEntity/walletSection.d.ts +1 -0
- package/dist/editors/invoice/legalEntity/walletSection.d.ts.map +1 -1
- package/dist/editors/invoice/legalEntity/walletSection.js +2 -2
- package/dist/editors/invoice/lineItems.js +1 -1
- package/dist/editors/invoice/requestFinance.d.ts +3 -2
- package/dist/editors/invoice/requestFinance.d.ts.map +1 -1
- package/dist/editors/invoice/requestFinance.js +38 -42
- package/dist/editors/invoice/validation/validationHandler.d.ts +1 -1
- package/dist/editors/invoice/validation/validationHandler.d.ts.map +1 -1
- package/dist/editors/invoice/validation/validationHandler.js +15 -2
- package/dist/editors/invoice/validation/validationManager.d.ts +1 -1
- package/dist/editors/invoice/validation/validationManager.d.ts.map +1 -1
- package/dist/editors/invoice/validation/validationManager.js +2 -1
- package/dist/editors/invoice/validation/validationRules.d.ts +1 -0
- package/dist/editors/invoice/validation/validationRules.d.ts.map +1 -1
- package/dist/editors/invoice/validation/validationRules.js +26 -1
- package/dist/editors/snapshot-report-editor/components/DateRangePicker.d.ts +19 -0
- package/dist/editors/snapshot-report-editor/components/DateRangePicker.d.ts.map +1 -0
- package/dist/editors/snapshot-report-editor/components/DateRangePicker.js +66 -0
- package/dist/editors/snapshot-report-editor/editor.d.ts.map +1 -1
- package/dist/editors/snapshot-report-editor/editor.js +72 -48
- package/dist/scripts/download-all-drive-documents/download-drive-documents.d.ts +33 -0
- package/dist/scripts/download-all-drive-documents/download-drive-documents.d.ts.map +1 -0
- package/dist/scripts/download-all-drive-documents/download-drive-documents.js +583 -0
- package/dist/scripts/invoice/requestFinance.d.ts +18 -1
- package/dist/scripts/invoice/requestFinance.d.ts.map +1 -1
- package/dist/scripts/invoice/requestFinance.js +17 -5
- package/dist/scripts/upload-phd-documents/upload-phd-documents.d.ts +20 -0
- package/dist/scripts/upload-phd-documents/upload-phd-documents.d.ts.map +1 -0
- package/dist/scripts/upload-phd-documents/upload-phd-documents.js +313 -0
- package/dist/style.css +201 -106
- package/dist/subgraphs/budget-statements/resolvers.d.ts +38 -0
- package/dist/subgraphs/budget-statements/resolvers.d.ts.map +1 -1
- package/dist/subgraphs/budget-statements/resolvers.js +192 -62
- package/dist/subgraphs/budget-statements/resolvers.test.d.ts +2 -0
- package/dist/subgraphs/budget-statements/resolvers.test.d.ts.map +1 -0
- package/dist/subgraphs/budget-statements/resolvers.test.js +339 -0
- package/dist/subgraphs/budget-statements/schema.d.ts.map +1 -1
- package/dist/subgraphs/budget-statements/schema.js +8 -0
- package/dist/subgraphs/index.d.ts +0 -1
- package/dist/subgraphs/index.d.ts.map +1 -1
- package/dist/subgraphs/index.js +0 -1
- package/dist/subgraphs/invoice-addon/customResolvers.d.ts +70 -11
- package/dist/subgraphs/invoice-addon/customResolvers.d.ts.map +1 -1
- package/dist/subgraphs/invoice-addon/customResolvers.js +12 -27
- package/package.json +35 -28
- package/dist/document-models/invoice/src/tests/document-model.test.d.ts +0 -10
- package/dist/document-models/invoice/src/tests/document-model.test.d.ts.map +0 -1
- package/dist/document-models/invoice/src/tests/document-model.test.js +0 -104
- package/dist/document-models/invoice/src/tests/general.test.d.ts +0 -6
- package/dist/document-models/invoice/src/tests/general.test.d.ts.map +0 -1
- package/dist/document-models/invoice/src/tests/general.test.js +0 -49
- package/dist/document-models/invoice/src/tests/items.test.d.ts +0 -6
- package/dist/document-models/invoice/src/tests/items.test.d.ts.map +0 -1
- package/dist/document-models/invoice/src/tests/items.test.js +0 -59
- package/dist/document-models/invoice/src/tests/parties.test.d.ts +0 -6
- package/dist/document-models/invoice/src/tests/parties.test.d.ts.map +0 -1
- package/dist/document-models/invoice/src/tests/parties.test.js +0 -69
- package/dist/document-models/invoice/src/tests/transitions.test.d.ts +0 -6
- package/dist/document-models/invoice/src/tests/transitions.test.d.ts.map +0 -1
- package/dist/document-models/invoice/src/tests/transitions.test.js +0 -59
- package/dist/document-models/invoice/utils/statusTransitions.d.ts +0 -13
- package/dist/document-models/invoice/utils/statusTransitions.d.ts.map +0 -1
- package/dist/document-models/invoice/utils/statusTransitions.js +0 -13
- package/dist/editors/builder-team-admin/components/overview/SubscriptionsStats.d.ts +0 -15
- package/dist/editors/builder-team-admin/components/overview/SubscriptionsStats.d.ts.map +0 -1
- package/dist/editors/builder-team-admin/components/overview/SubscriptionsStats.js +0 -61
- package/dist/editors/contributor-billing/components/CreateHubProfileModal.d.ts +0 -12
- package/dist/editors/contributor-billing/components/CreateHubProfileModal.d.ts.map +0 -1
- package/dist/editors/contributor-billing/components/CreateHubProfileModal.js +0 -74
- package/dist/subgraphs/resources-services/index.d.ts +0 -11
- package/dist/subgraphs/resources-services/index.d.ts.map +0 -1
- package/dist/subgraphs/resources-services/index.js +0 -11
- package/dist/subgraphs/resources-services/resolvers.d.ts +0 -3
- package/dist/subgraphs/resources-services/resolvers.d.ts.map +0 -1
- package/dist/subgraphs/resources-services/resolvers.js +0 -462
- package/dist/subgraphs/resources-services/schema.d.ts +0 -3
- package/dist/subgraphs/resources-services/schema.d.ts.map +0 -1
- package/dist/subgraphs/resources-services/schema.js +0 -284
|
@@ -0,0 +1,583 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Download all documents from a Powerhouse switchboard as .phd files.
|
|
4
|
+
*
|
|
5
|
+
* REQUIRES: Bun runtime (https://bun.sh) — Node.js is NOT supported.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* bun scripts/download-drive-documents.ts <switchboard-url> [drive-id]
|
|
9
|
+
*
|
|
10
|
+
* Examples:
|
|
11
|
+
* # Download all documents from all drives
|
|
12
|
+
* bun scripts/download-drive-documents.ts https://switchboard-dev.powerhouse.xyz
|
|
13
|
+
*
|
|
14
|
+
* # Download documents from a specific drive
|
|
15
|
+
* bun scripts/download-drive-documents.ts https://switchboard-dev.powerhouse.xyz layer-resources-drive
|
|
16
|
+
*
|
|
17
|
+
* Output structure:
|
|
18
|
+
* ./downloads/<drive-name>/
|
|
19
|
+
* ├── document-a.phd
|
|
20
|
+
* ├── FolderName/
|
|
21
|
+
* │ └── document-b.phd
|
|
22
|
+
* └── ...
|
|
23
|
+
*
|
|
24
|
+
* The .phd files are ZIP archives containing:
|
|
25
|
+
* - header.json — document metadata (id, type, timestamps)
|
|
26
|
+
* - state.json — initial empty state
|
|
27
|
+
* - current-state.json — current document state
|
|
28
|
+
* - operations.json — operation history (global scope)
|
|
29
|
+
*
|
|
30
|
+
* No external dependencies required — uses only Node.js built-in modules.
|
|
31
|
+
*/
|
|
32
|
+
import { deflateRawSync, inflateRawSync } from "node:zlib";
|
|
33
|
+
import fs from "node:fs";
|
|
34
|
+
import path from "node:path";
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// Minimal ZIP implementation (DEFLATE, no external deps)
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
function crc32(buf) {
|
|
39
|
+
// Standard CRC-32 lookup table
|
|
40
|
+
const table = new Uint32Array(256);
|
|
41
|
+
for (let i = 0; i < 256; i++) {
|
|
42
|
+
let c = i;
|
|
43
|
+
for (let j = 0; j < 8; j++) {
|
|
44
|
+
c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
|
|
45
|
+
}
|
|
46
|
+
table[i] = c;
|
|
47
|
+
}
|
|
48
|
+
let crc = 0xffffffff;
|
|
49
|
+
for (let i = 0; i < buf.length; i++) {
|
|
50
|
+
crc = table[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8);
|
|
51
|
+
}
|
|
52
|
+
return (crc ^ 0xffffffff) >>> 0;
|
|
53
|
+
}
|
|
54
|
+
function createZipBuffer(files) {
|
|
55
|
+
const entries = [];
|
|
56
|
+
let offset = 0;
|
|
57
|
+
const localHeaders = [];
|
|
58
|
+
for (const [name, content] of files) {
|
|
59
|
+
const nameBytes = Buffer.from(name, "utf-8");
|
|
60
|
+
const data = Buffer.from(content, "utf-8");
|
|
61
|
+
const compressed = deflateRawSync(data);
|
|
62
|
+
const crc = crc32(data);
|
|
63
|
+
// Local file header (30 bytes + name + compressed data)
|
|
64
|
+
const local = Buffer.alloc(30);
|
|
65
|
+
local.writeUInt32LE(0x04034b50, 0); // signature
|
|
66
|
+
local.writeUInt16LE(20, 4); // version needed
|
|
67
|
+
local.writeUInt16LE(0, 6); // flags
|
|
68
|
+
local.writeUInt16LE(8, 8); // compression: DEFLATE
|
|
69
|
+
local.writeUInt16LE(0, 10); // mod time
|
|
70
|
+
local.writeUInt16LE(0, 12); // mod date
|
|
71
|
+
local.writeUInt32LE(crc, 14); // crc-32
|
|
72
|
+
local.writeUInt32LE(compressed.length, 18); // compressed size
|
|
73
|
+
local.writeUInt32LE(data.length, 22); // uncompressed size
|
|
74
|
+
local.writeUInt16LE(nameBytes.length, 26); // filename length
|
|
75
|
+
local.writeUInt16LE(0, 28); // extra length
|
|
76
|
+
entries.push({ name: nameBytes, data, compressed, crc, offset });
|
|
77
|
+
localHeaders.push(local, nameBytes, compressed);
|
|
78
|
+
offset += 30 + nameBytes.length + compressed.length;
|
|
79
|
+
}
|
|
80
|
+
// Central directory
|
|
81
|
+
const centralDir = [];
|
|
82
|
+
let centralSize = 0;
|
|
83
|
+
const centralOffset = offset;
|
|
84
|
+
for (const entry of entries) {
|
|
85
|
+
const central = Buffer.alloc(46);
|
|
86
|
+
central.writeUInt32LE(0x02014b50, 0); // signature
|
|
87
|
+
central.writeUInt16LE(20, 4); // version made by
|
|
88
|
+
central.writeUInt16LE(20, 6); // version needed
|
|
89
|
+
central.writeUInt16LE(0, 8); // flags
|
|
90
|
+
central.writeUInt16LE(8, 10); // compression: DEFLATE
|
|
91
|
+
central.writeUInt16LE(0, 12); // mod time
|
|
92
|
+
central.writeUInt16LE(0, 14); // mod date
|
|
93
|
+
central.writeUInt32LE(entry.crc, 16); // crc-32
|
|
94
|
+
central.writeUInt32LE(entry.compressed.length, 20); // compressed size
|
|
95
|
+
central.writeUInt32LE(entry.data.length, 24); // uncompressed size
|
|
96
|
+
central.writeUInt16LE(entry.name.length, 28); // filename length
|
|
97
|
+
central.writeUInt16LE(0, 30); // extra length
|
|
98
|
+
central.writeUInt16LE(0, 32); // comment length
|
|
99
|
+
central.writeUInt16LE(0, 34); // disk start
|
|
100
|
+
central.writeUInt16LE(0, 36); // internal attrs
|
|
101
|
+
central.writeUInt32LE(0, 38); // external attrs
|
|
102
|
+
central.writeUInt32LE(entry.offset, 42); // local header offset
|
|
103
|
+
centralDir.push(central, entry.name);
|
|
104
|
+
centralSize += 46 + entry.name.length;
|
|
105
|
+
}
|
|
106
|
+
// End of central directory
|
|
107
|
+
const eocd = Buffer.alloc(22);
|
|
108
|
+
eocd.writeUInt32LE(0x06054b50, 0); // signature
|
|
109
|
+
eocd.writeUInt16LE(0, 4); // disk number
|
|
110
|
+
eocd.writeUInt16LE(0, 6); // start disk
|
|
111
|
+
eocd.writeUInt16LE(entries.length, 8); // entries on disk
|
|
112
|
+
eocd.writeUInt16LE(entries.length, 10); // total entries
|
|
113
|
+
eocd.writeUInt32LE(centralSize, 12); // central dir size
|
|
114
|
+
eocd.writeUInt32LE(centralOffset, 16); // central dir offset
|
|
115
|
+
eocd.writeUInt16LE(0, 20); // comment length
|
|
116
|
+
return Buffer.concat([...localHeaders, ...centralDir, eocd]);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Read a single file entry from a ZIP buffer by name.
|
|
120
|
+
* Returns the decompressed content as a Buffer, or null if not found.
|
|
121
|
+
*/
|
|
122
|
+
function readZipEntry(zipBuf, entryName) {
|
|
123
|
+
let offset = 0;
|
|
124
|
+
while (offset + 30 <= zipBuf.length) {
|
|
125
|
+
const sig = zipBuf.readUInt32LE(offset);
|
|
126
|
+
if (sig !== 0x04034b50)
|
|
127
|
+
break; // not a local file header
|
|
128
|
+
const compressionMethod = zipBuf.readUInt16LE(offset + 8);
|
|
129
|
+
const compressedSize = zipBuf.readUInt32LE(offset + 18);
|
|
130
|
+
const nameLen = zipBuf.readUInt16LE(offset + 26);
|
|
131
|
+
const extraLen = zipBuf.readUInt16LE(offset + 28);
|
|
132
|
+
const nameStart = offset + 30;
|
|
133
|
+
const name = zipBuf
|
|
134
|
+
.subarray(nameStart, nameStart + nameLen)
|
|
135
|
+
.toString("utf-8");
|
|
136
|
+
const dataStart = nameStart + nameLen + extraLen;
|
|
137
|
+
const dataEnd = dataStart + compressedSize;
|
|
138
|
+
if (name === entryName) {
|
|
139
|
+
const raw = zipBuf.subarray(dataStart, dataEnd);
|
|
140
|
+
if (compressionMethod === 8) {
|
|
141
|
+
// DEFLATE
|
|
142
|
+
return Buffer.from(inflateRawSync(raw));
|
|
143
|
+
}
|
|
144
|
+
// stored (method 0) — return as-is
|
|
145
|
+
return Buffer.from(raw);
|
|
146
|
+
}
|
|
147
|
+
offset = dataEnd;
|
|
148
|
+
}
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
function verifyPhdFile(filePath, expectedStateJSON) {
|
|
152
|
+
const zipBuf = fs.readFileSync(filePath);
|
|
153
|
+
const currentStateBuf = readZipEntry(zipBuf, "current-state.json");
|
|
154
|
+
if (!currentStateBuf) {
|
|
155
|
+
return { valid: false, reason: "current-state.json not found in .phd" };
|
|
156
|
+
}
|
|
157
|
+
let savedState;
|
|
158
|
+
try {
|
|
159
|
+
savedState = JSON.parse(currentStateBuf.toString("utf-8"));
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
return { valid: false, reason: "Failed to parse current-state.json" };
|
|
163
|
+
}
|
|
164
|
+
const savedGlobal = JSON.stringify(savedState.global ?? {});
|
|
165
|
+
const expectedGlobal = JSON.stringify(expectedStateJSON ?? {});
|
|
166
|
+
if (savedGlobal === expectedGlobal) {
|
|
167
|
+
return { valid: true };
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
valid: false,
|
|
171
|
+
reason: `State mismatch — saved global has ${savedGlobal.length} chars, API stateJSON has ${expectedGlobal.length} chars`,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
// ---------------------------------------------------------------------------
|
|
175
|
+
// Helpers
|
|
176
|
+
// ---------------------------------------------------------------------------
|
|
177
|
+
const REQUEST_DELAY_MS = 300;
|
|
178
|
+
function sleep(ms) {
|
|
179
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Normalize the base URL: strip trailing slashes and common suffixes like
|
|
183
|
+
* "/graphql" so that both "https://sb.xyz" and "https://sb.xyz/graphql" work.
|
|
184
|
+
*/
|
|
185
|
+
function normalizeBaseUrl(raw) {
|
|
186
|
+
return raw.replace(/\/+$/, "").replace(/\/graphql$/i, "");
|
|
187
|
+
}
|
|
188
|
+
async function gqlQuery(endpoint, query, variables) {
|
|
189
|
+
const res = await fetch(endpoint, {
|
|
190
|
+
method: "POST",
|
|
191
|
+
headers: { "Content-Type": "application/json" },
|
|
192
|
+
body: JSON.stringify({ query, variables }),
|
|
193
|
+
});
|
|
194
|
+
if (!res.ok) {
|
|
195
|
+
let body = "";
|
|
196
|
+
try {
|
|
197
|
+
body = await res.text();
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
/* ignore */
|
|
201
|
+
}
|
|
202
|
+
const detail = body ? `\n Response: ${body.slice(0, 500)}` : "";
|
|
203
|
+
throw new Error(`GraphQL request failed: ${res.status} ${res.statusText} (${endpoint})${detail}`);
|
|
204
|
+
}
|
|
205
|
+
const json = (await res.json());
|
|
206
|
+
if (json.errors?.length) {
|
|
207
|
+
throw new Error(`GraphQL errors:\n${json.errors.map((e) => ` - ${e.message}`).join("\n")}`);
|
|
208
|
+
}
|
|
209
|
+
if (!json.data) {
|
|
210
|
+
throw new Error("No data returned from GraphQL query");
|
|
211
|
+
}
|
|
212
|
+
return json.data;
|
|
213
|
+
}
|
|
214
|
+
// ---------------------------------------------------------------------------
|
|
215
|
+
// API calls
|
|
216
|
+
// ---------------------------------------------------------------------------
|
|
217
|
+
async function fetchDrives(baseUrl) {
|
|
218
|
+
const data = await gqlQuery(`${baseUrl}/graphql`, `{ drives }`);
|
|
219
|
+
return data.drives;
|
|
220
|
+
}
|
|
221
|
+
async function fetchDriveInfo(baseUrl, driveId) {
|
|
222
|
+
const data = await gqlQuery(`${baseUrl}/d/${driveId}`, `{
|
|
223
|
+
drive { id name slug icon }
|
|
224
|
+
driveDocument {
|
|
225
|
+
state {
|
|
226
|
+
name icon
|
|
227
|
+
nodes {
|
|
228
|
+
... on DocumentDrive_FileNode {
|
|
229
|
+
id name kind documentType parentFolder
|
|
230
|
+
}
|
|
231
|
+
... on DocumentDrive_FolderNode {
|
|
232
|
+
id name kind parentFolder
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}`);
|
|
238
|
+
return {
|
|
239
|
+
drive: data.drive,
|
|
240
|
+
nodes: data.driveDocument.state.nodes,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
async function fetchDocument(baseUrl, driveId, docId) {
|
|
244
|
+
// First fetch document metadata + stateJSON + first batch of operations
|
|
245
|
+
const BATCH_SIZE = 100;
|
|
246
|
+
const data = await gqlQuery(`${baseUrl}/d/${driveId}`, `query ($id: String!, $first: Int, $skip: Int) {
|
|
247
|
+
document(id: $id) {
|
|
248
|
+
id name documentType revision
|
|
249
|
+
createdAtUtcIso lastModifiedAtUtcIso
|
|
250
|
+
operations(first: $first, skip: $skip) {
|
|
251
|
+
id type index timestampUtcMs hash skip inputText error
|
|
252
|
+
}
|
|
253
|
+
stateJSON
|
|
254
|
+
}
|
|
255
|
+
}`, { id: docId, first: BATCH_SIZE, skip: 0 });
|
|
256
|
+
const doc = data.document;
|
|
257
|
+
const allOps = [...doc.operations];
|
|
258
|
+
// Paginate through remaining operations if first batch was full
|
|
259
|
+
while (allOps.length > 0 && allOps.length % BATCH_SIZE === 0) {
|
|
260
|
+
await sleep(REQUEST_DELAY_MS);
|
|
261
|
+
const moreData = await gqlQuery(`${baseUrl}/d/${driveId}`, `query ($id: String!, $first: Int, $skip: Int) {
|
|
262
|
+
document(id: $id) {
|
|
263
|
+
operations(first: $first, skip: $skip) {
|
|
264
|
+
id type index timestampUtcMs hash skip inputText error
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}`, { id: docId, first: BATCH_SIZE, skip: allOps.length });
|
|
268
|
+
const batch = moreData.document.operations;
|
|
269
|
+
if (batch.length === 0)
|
|
270
|
+
break;
|
|
271
|
+
allOps.push(...batch);
|
|
272
|
+
}
|
|
273
|
+
doc.operations = allOps;
|
|
274
|
+
return doc;
|
|
275
|
+
}
|
|
276
|
+
// ---------------------------------------------------------------------------
|
|
277
|
+
// Folder path resolution
|
|
278
|
+
// ---------------------------------------------------------------------------
|
|
279
|
+
function buildFolderPaths(nodes) {
|
|
280
|
+
const folders = nodes.filter((n) => n.kind === "folder");
|
|
281
|
+
const folderMap = new Map();
|
|
282
|
+
for (const f of folders) {
|
|
283
|
+
folderMap.set(f.id, f);
|
|
284
|
+
}
|
|
285
|
+
const pathCache = new Map();
|
|
286
|
+
function resolve(folderId) {
|
|
287
|
+
if (pathCache.has(folderId))
|
|
288
|
+
return pathCache.get(folderId);
|
|
289
|
+
const folder = folderMap.get(folderId);
|
|
290
|
+
if (!folder)
|
|
291
|
+
return "";
|
|
292
|
+
const parentPath = folder.parentFolder ? resolve(folder.parentFolder) : "";
|
|
293
|
+
const fullPath = parentPath
|
|
294
|
+
? path.join(parentPath, sanitize(folder.name))
|
|
295
|
+
: sanitize(folder.name);
|
|
296
|
+
pathCache.set(folderId, fullPath);
|
|
297
|
+
return fullPath;
|
|
298
|
+
}
|
|
299
|
+
for (const f of folders) {
|
|
300
|
+
resolve(f.id);
|
|
301
|
+
}
|
|
302
|
+
return pathCache;
|
|
303
|
+
}
|
|
304
|
+
function getNodePath(node, folderPaths) {
|
|
305
|
+
if (!node.parentFolder)
|
|
306
|
+
return "";
|
|
307
|
+
return folderPaths.get(node.parentFolder) ?? "";
|
|
308
|
+
}
|
|
309
|
+
function sanitize(name) {
|
|
310
|
+
return name.replace(/[<>:"/\\|?*\x00-\x1f]/g, "_").trim() || "unnamed";
|
|
311
|
+
}
|
|
312
|
+
// ---------------------------------------------------------------------------
|
|
313
|
+
// .phd file creation
|
|
314
|
+
// ---------------------------------------------------------------------------
|
|
315
|
+
function gqlOperationToInternal(op, scope) {
|
|
316
|
+
let input = {};
|
|
317
|
+
if (op.inputText) {
|
|
318
|
+
try {
|
|
319
|
+
input = JSON.parse(op.inputText);
|
|
320
|
+
}
|
|
321
|
+
catch {
|
|
322
|
+
input = op.inputText;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return {
|
|
326
|
+
id: op.id,
|
|
327
|
+
index: op.index,
|
|
328
|
+
skip: op.skip ?? 0,
|
|
329
|
+
hash: op.hash,
|
|
330
|
+
timestampUtcMs: op.timestampUtcMs,
|
|
331
|
+
error: op.error ?? undefined,
|
|
332
|
+
action: {
|
|
333
|
+
id: op.id,
|
|
334
|
+
type: op.type,
|
|
335
|
+
timestampUtcMs: op.timestampUtcMs,
|
|
336
|
+
input,
|
|
337
|
+
scope,
|
|
338
|
+
},
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
function createPhdFile(doc) {
|
|
342
|
+
const header = {
|
|
343
|
+
id: doc.id,
|
|
344
|
+
sig: { publicKey: {}, nonce: "" },
|
|
345
|
+
documentType: doc.documentType,
|
|
346
|
+
createdAtUtcIso: doc.createdAtUtcIso,
|
|
347
|
+
slug: doc.id,
|
|
348
|
+
name: doc.name,
|
|
349
|
+
branch: "main",
|
|
350
|
+
revision: { global: doc.revision },
|
|
351
|
+
lastModifiedAtUtcIso: doc.lastModifiedAtUtcIso,
|
|
352
|
+
meta: {},
|
|
353
|
+
};
|
|
354
|
+
const initialState = {
|
|
355
|
+
auth: {},
|
|
356
|
+
document: {
|
|
357
|
+
version: 0,
|
|
358
|
+
hash: { algorithm: "sha1", encoding: "base64" },
|
|
359
|
+
},
|
|
360
|
+
global: {},
|
|
361
|
+
local: {},
|
|
362
|
+
};
|
|
363
|
+
const currentState = {
|
|
364
|
+
auth: {},
|
|
365
|
+
document: {
|
|
366
|
+
version: 0,
|
|
367
|
+
hash: { algorithm: "sha1", encoding: "base64" },
|
|
368
|
+
},
|
|
369
|
+
global: doc.stateJSON ?? {},
|
|
370
|
+
local: {},
|
|
371
|
+
};
|
|
372
|
+
const operations = {
|
|
373
|
+
global: doc.operations.map((op) => gqlOperationToInternal(op, "global")),
|
|
374
|
+
};
|
|
375
|
+
const files = new Map();
|
|
376
|
+
files.set("header.json", JSON.stringify(header, null, 2));
|
|
377
|
+
files.set("state.json", JSON.stringify(initialState, null, 2));
|
|
378
|
+
files.set("current-state.json", JSON.stringify(currentState, null, 2));
|
|
379
|
+
files.set("operations.json", JSON.stringify(operations, null, 2));
|
|
380
|
+
return createZipBuffer(files);
|
|
381
|
+
}
|
|
382
|
+
// ---------------------------------------------------------------------------
|
|
383
|
+
// Main
|
|
384
|
+
// ---------------------------------------------------------------------------
|
|
385
|
+
async function downloadDrive(baseUrl, driveId, outputBase) {
|
|
386
|
+
console.log(`\n${"=".repeat(60)}`);
|
|
387
|
+
console.log(`DRIVE: ${driveId}`);
|
|
388
|
+
console.log(`${"=".repeat(60)}`);
|
|
389
|
+
console.log(` Endpoint: ${baseUrl}/d/${driveId}`);
|
|
390
|
+
console.log(` Fetching drive info...`);
|
|
391
|
+
const { drive, nodes } = await fetchDriveInfo(baseUrl, driveId);
|
|
392
|
+
const driveName = sanitize(drive.name || driveId);
|
|
393
|
+
const driveDir = path.join(outputBase, driveName);
|
|
394
|
+
console.log(` Name: ${drive.name}`);
|
|
395
|
+
console.log(` Slug: ${drive.slug}`);
|
|
396
|
+
console.log(` Icon: ${drive.icon ?? "(none)"}`);
|
|
397
|
+
const folders = nodes.filter((n) => n.kind === "folder");
|
|
398
|
+
const files = nodes.filter((n) => "documentType" in n && n.kind === "file");
|
|
399
|
+
console.log(` Nodes: ${nodes.length} total (${files.length} files, ${folders.length} folders)`);
|
|
400
|
+
if (folders.length > 0) {
|
|
401
|
+
console.log(` Folders:`);
|
|
402
|
+
const folderPaths = buildFolderPaths(nodes);
|
|
403
|
+
for (const folder of folders) {
|
|
404
|
+
const resolvedPath = folderPaths.get(folder.id) ?? folder.name;
|
|
405
|
+
const parent = folder.parentFolder
|
|
406
|
+
? ` (parent: ${folder.parentFolder})`
|
|
407
|
+
: " (root)";
|
|
408
|
+
console.log(` /${resolvedPath}${parent}`);
|
|
409
|
+
}
|
|
410
|
+
// Create folder structure
|
|
411
|
+
for (const folderPath of folderPaths.values()) {
|
|
412
|
+
fs.mkdirSync(path.join(driveDir, folderPath), { recursive: true });
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
// Build a map of document ID -> file node for name/path resolution
|
|
416
|
+
const fileNodes = new Map();
|
|
417
|
+
for (const node of nodes) {
|
|
418
|
+
if ("documentType" in node && node.kind === "file") {
|
|
419
|
+
fileNodes.set(node.id, node);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
if (files.length > 0) {
|
|
423
|
+
console.log(` Files:`);
|
|
424
|
+
for (const file of files) {
|
|
425
|
+
const folderPaths = buildFolderPaths(nodes);
|
|
426
|
+
const filePath = file.parentFolder
|
|
427
|
+
? `${folderPaths.get(file.parentFolder) ?? ""}/${file.name}`
|
|
428
|
+
: file.name;
|
|
429
|
+
console.log(` ${file.id} -> /${filePath} (${file.documentType})`);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
const docIds = [...fileNodes.keys()];
|
|
433
|
+
console.log(`\n Downloading ${docIds.length} documents...`);
|
|
434
|
+
let saved = 0;
|
|
435
|
+
let failed = 0;
|
|
436
|
+
let verified = 0;
|
|
437
|
+
let verifyFailed = 0;
|
|
438
|
+
let emptyState = 0;
|
|
439
|
+
const failures = [];
|
|
440
|
+
const verifyFailures = [];
|
|
441
|
+
const emptyStateIds = [];
|
|
442
|
+
for (const docId of docIds) {
|
|
443
|
+
const fileNode = fileNodes.get(docId);
|
|
444
|
+
const nodeName = fileNode?.name ?? docId;
|
|
445
|
+
try {
|
|
446
|
+
if (saved + failed > 0)
|
|
447
|
+
await sleep(REQUEST_DELAY_MS);
|
|
448
|
+
console.log(` [${saved + failed + 1}/${docIds.length}] Fetching "${nodeName}" (${docId})...`);
|
|
449
|
+
const doc = await fetchDocument(baseUrl, driveId, docId);
|
|
450
|
+
// Warn about empty stateJSON
|
|
451
|
+
const stateIsEmpty = doc.stateJSON == null ||
|
|
452
|
+
(typeof doc.stateJSON === "object" &&
|
|
453
|
+
Object.keys(doc.stateJSON).length === 0);
|
|
454
|
+
if (stateIsEmpty) {
|
|
455
|
+
emptyState++;
|
|
456
|
+
emptyStateIds.push({
|
|
457
|
+
id: docId,
|
|
458
|
+
name: nodeName,
|
|
459
|
+
documentType: doc.documentType,
|
|
460
|
+
});
|
|
461
|
+
console.warn(` WARNING: stateJSON is empty for "${nodeName}" (${doc.documentType})` +
|
|
462
|
+
` — the downloaded .phd will have an empty global state`);
|
|
463
|
+
}
|
|
464
|
+
const folderPaths = buildFolderPaths(nodes);
|
|
465
|
+
const subDir = fileNode ? getNodePath(fileNode, folderPaths) : "";
|
|
466
|
+
const docName = sanitize(doc.name || docId);
|
|
467
|
+
const fileName = `${docName}.phd`;
|
|
468
|
+
const fullDir = path.join(driveDir, subDir);
|
|
469
|
+
const filePath = path.join(fullDir, fileName);
|
|
470
|
+
fs.mkdirSync(fullDir, { recursive: true });
|
|
471
|
+
const data = createPhdFile(doc);
|
|
472
|
+
fs.writeFileSync(filePath, data);
|
|
473
|
+
const relativePath = path.relative(outputBase, filePath);
|
|
474
|
+
const sizeKb = (data.length / 1024).toFixed(1);
|
|
475
|
+
const opsCount = doc.operations.length;
|
|
476
|
+
console.log(` Saved ${relativePath} (${doc.documentType}, ${opsCount} ops, ${sizeKb} KB)`);
|
|
477
|
+
// Post-save verification: read back the .phd and compare state
|
|
478
|
+
const vResult = verifyPhdFile(filePath, doc.stateJSON);
|
|
479
|
+
if (vResult.valid) {
|
|
480
|
+
verified++;
|
|
481
|
+
console.log(` Verified OK`);
|
|
482
|
+
}
|
|
483
|
+
else {
|
|
484
|
+
verifyFailed++;
|
|
485
|
+
verifyFailures.push({
|
|
486
|
+
id: docId,
|
|
487
|
+
name: nodeName,
|
|
488
|
+
reason: vResult.reason,
|
|
489
|
+
});
|
|
490
|
+
console.warn(` VERIFY FAILED: ${vResult.reason}`);
|
|
491
|
+
}
|
|
492
|
+
saved++;
|
|
493
|
+
}
|
|
494
|
+
catch (err) {
|
|
495
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
496
|
+
console.error(` SKIP "${nodeName}": ${reason}`);
|
|
497
|
+
failures.push({ id: docId, name: nodeName, reason });
|
|
498
|
+
failed++;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
console.log(`\n Summary for "${drive.name}":`);
|
|
502
|
+
console.log(` Saved: ${saved}`);
|
|
503
|
+
console.log(` Skipped: ${failed}`);
|
|
504
|
+
console.log(` Verified OK: ${verified}`);
|
|
505
|
+
console.log(` Verify failed: ${verifyFailed}`);
|
|
506
|
+
console.log(` Empty stateJSON: ${emptyState}`);
|
|
507
|
+
if (failures.length > 0) {
|
|
508
|
+
console.log(` Reasons for skipped documents:`);
|
|
509
|
+
for (const f of failures) {
|
|
510
|
+
console.log(` - "${f.name}" (${f.id})`);
|
|
511
|
+
console.log(` ${f.reason}`);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
if (verifyFailures.length > 0) {
|
|
515
|
+
console.log(` Verification failures:`);
|
|
516
|
+
for (const f of verifyFailures) {
|
|
517
|
+
console.log(` - "${f.name}" (${f.id})`);
|
|
518
|
+
console.log(` ${f.reason}`);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
if (emptyStateIds.length > 0) {
|
|
522
|
+
console.log(` Documents with empty stateJSON:`);
|
|
523
|
+
for (const d of emptyStateIds) {
|
|
524
|
+
console.log(` - "${d.name}" (${d.id}) [${d.documentType}]`);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
async function main() {
|
|
529
|
+
const args = process.argv.slice(2);
|
|
530
|
+
if (args.length === 0) {
|
|
531
|
+
console.log("Usage: bun scripts/download-drive-documents.ts <switchboard-url> [drive-id]");
|
|
532
|
+
console.log("\nExamples:");
|
|
533
|
+
console.log(" bun scripts/download-drive-documents.ts https://switchboard-dev.powerhouse.xyz");
|
|
534
|
+
console.log(" bun scripts/download-drive-documents.ts https://switchboard-dev.powerhouse.xyz layer-resources-drive");
|
|
535
|
+
process.exit(1);
|
|
536
|
+
}
|
|
537
|
+
const baseUrl = normalizeBaseUrl(args[0]);
|
|
538
|
+
const driveIdArg = args[1];
|
|
539
|
+
const outputBase = path.resolve("./downloads");
|
|
540
|
+
console.log(`Switchboard: ${baseUrl}`);
|
|
541
|
+
console.log(`Output dir: ${outputBase}`);
|
|
542
|
+
console.log(`\nFetching drive list...`);
|
|
543
|
+
const driveIds = driveIdArg ? [driveIdArg] : await fetchDrives(baseUrl);
|
|
544
|
+
console.log(`Found ${driveIds.length} drive(s): ${driveIds.join(", ")}`);
|
|
545
|
+
let drivesProcessed = 0;
|
|
546
|
+
let drivesFailed = 0;
|
|
547
|
+
const driveFailures = [];
|
|
548
|
+
for (let i = 0; i < driveIds.length; i++) {
|
|
549
|
+
if (i > 0)
|
|
550
|
+
await sleep(REQUEST_DELAY_MS);
|
|
551
|
+
const driveId = driveIds[i];
|
|
552
|
+
try {
|
|
553
|
+
await downloadDrive(baseUrl, driveId, outputBase);
|
|
554
|
+
drivesProcessed++;
|
|
555
|
+
}
|
|
556
|
+
catch (err) {
|
|
557
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
558
|
+
console.error(`\n${"=".repeat(60)}`);
|
|
559
|
+
console.error(`DRIVE: ${driveId} — FAILED`);
|
|
560
|
+
console.error(`${"=".repeat(60)}`);
|
|
561
|
+
console.error(` Reason: ${reason}`);
|
|
562
|
+
driveFailures.push({ id: driveId, reason });
|
|
563
|
+
drivesFailed++;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
console.log(`\n${"=".repeat(60)}`);
|
|
567
|
+
console.log(`DONE`);
|
|
568
|
+
console.log(`${"=".repeat(60)}`);
|
|
569
|
+
console.log(` Output: ${outputBase}`);
|
|
570
|
+
console.log(` Drives processed: ${drivesProcessed}`);
|
|
571
|
+
console.log(` Drives skipped: ${drivesFailed}`);
|
|
572
|
+
if (driveFailures.length > 0) {
|
|
573
|
+
console.log(` Reasons for skipped drives:`);
|
|
574
|
+
for (const f of driveFailures) {
|
|
575
|
+
console.log(` - "${f.id}"`);
|
|
576
|
+
console.log(` ${f.reason}`);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
main().catch((err) => {
|
|
581
|
+
console.error(err);
|
|
582
|
+
process.exit(1);
|
|
583
|
+
});
|
|
@@ -1,2 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
interface InvoicePaymentData {
|
|
2
|
+
buyerInfo: {
|
|
3
|
+
email: string;
|
|
4
|
+
[key: string]: unknown;
|
|
5
|
+
};
|
|
6
|
+
invoiceNumber?: string;
|
|
7
|
+
[key: string]: unknown;
|
|
8
|
+
}
|
|
9
|
+
export interface RequestFinanceResponse {
|
|
10
|
+
errors?: string[];
|
|
11
|
+
invoiceLinks?: {
|
|
12
|
+
pay: string;
|
|
13
|
+
};
|
|
14
|
+
id?: string;
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
}
|
|
17
|
+
export declare const requestDirectPayment: (invoiceData: InvoicePaymentData | Record<string, unknown>) => Promise<RequestFinanceResponse>;
|
|
18
|
+
export {};
|
|
2
19
|
//# sourceMappingURL=requestFinance.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"requestFinance.d.ts","sourceRoot":"","sources":["../../../scripts/invoice/requestFinance.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,oBAAoB,
|
|
1
|
+
{"version":3,"file":"requestFinance.d.ts","sourceRoot":"","sources":["../../../scripts/invoice/requestFinance.ts"],"names":[],"mappings":"AAMA,UAAU,kBAAkB;IAC1B,SAAS,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IACrD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,YAAY,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,eAAO,MAAM,oBAAoB,GAC/B,aAAa,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KACxD,OAAO,CAAC,sBAAsB,CA0DhC,CAAC"}
|
|
@@ -3,8 +3,9 @@ const API_URL = "https://api.request.finance/invoices";
|
|
|
3
3
|
const API_KEY = process.env.REQUEST_FINANCE_API_KEY; // Store in .env file
|
|
4
4
|
const REQUEST_FINANCE_EMAIL = process.env.REQUEST_FINANCE_EMAIL;
|
|
5
5
|
export const requestDirectPayment = async (invoiceData) => {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
const data = invoiceData;
|
|
7
|
+
data.buyerInfo.email = REQUEST_FINANCE_EMAIL ?? "";
|
|
8
|
+
console.log("Getting a request to create an invoice", data.invoiceNumber);
|
|
8
9
|
try {
|
|
9
10
|
// First API call to create the invoice
|
|
10
11
|
const response = await axios.post(API_URL, invoiceData, {
|
|
@@ -30,11 +31,22 @@ export const requestDirectPayment = async (invoiceData) => {
|
|
|
30
31
|
}
|
|
31
32
|
catch (error) {
|
|
32
33
|
console.error("Server: Error making invoice on-chain:", error);
|
|
33
|
-
|
|
34
|
+
if (axios.isAxiosError(error) && error.response) {
|
|
35
|
+
return error.response.data;
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
errors: [error instanceof Error ? error.message : "Unknown error"],
|
|
39
|
+
};
|
|
34
40
|
}
|
|
35
41
|
}
|
|
36
42
|
catch (error) {
|
|
37
|
-
|
|
38
|
-
|
|
43
|
+
if (axios.isAxiosError(error) && error.response) {
|
|
44
|
+
console.error("Error creating invoice: error.response", error.response.data);
|
|
45
|
+
return error.response.data;
|
|
46
|
+
}
|
|
47
|
+
console.error("Error creating invoice:", error);
|
|
48
|
+
return {
|
|
49
|
+
errors: [error instanceof Error ? error.message : "Unknown error"],
|
|
50
|
+
};
|
|
39
51
|
}
|
|
40
52
|
};
|
|
@@ -0,0 +1,20 @@
|
|
|
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
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=upload-phd-documents.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload-phd-documents.d.ts","sourceRoot":"","sources":["../../../scripts/upload-phd-documents/upload-phd-documents.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;GAgBG"}
|