ksef-client-ts 0.9.0 → 0.10.0
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/README.md +13 -72
- package/dist/cli.js +90 -85
- package/dist/cli.js.map +1 -1
- package/dist/hwm-storage-DQ4PCfBN.d.cts +316 -0
- package/dist/hwm-storage-DQ4PCfBN.d.ts +316 -0
- package/dist/index.cjs +190 -416
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +56 -353
- package/dist/index.d.ts +56 -353
- package/dist/index.js +185 -405
- package/dist/index.js.map +1 -1
- package/dist/node.cjs +308 -0
- package/dist/node.cjs.map +1 -0
- package/dist/node.d.cts +41 -0
- package/dist/node.d.ts +41 -0
- package/dist/node.js +260 -0
- package/dist/node.js.map +1 -0
- package/package.json +13 -1
package/dist/node.js
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
// src/offline/file-storage.ts
|
|
2
|
+
import * as fs from "node:fs/promises";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import * as os from "node:os";
|
|
5
|
+
|
|
6
|
+
// src/offline/storage.ts
|
|
7
|
+
function matchesFilter(invoice, filter) {
|
|
8
|
+
if (filter.status !== void 0) {
|
|
9
|
+
const statuses = Array.isArray(filter.status) ? filter.status : [filter.status];
|
|
10
|
+
if (!statuses.includes(invoice.status)) return false;
|
|
11
|
+
}
|
|
12
|
+
if (filter.mode !== void 0 && invoice.mode !== filter.mode) return false;
|
|
13
|
+
if (filter.sellerNip !== void 0 && invoice.sellerNip !== filter.sellerNip) return false;
|
|
14
|
+
if (filter.expiringBefore !== void 0) {
|
|
15
|
+
const cutoff = typeof filter.expiringBefore === "string" ? new Date(filter.expiringBefore).getTime() : filter.expiringBefore.getTime();
|
|
16
|
+
if (new Date(invoice.submitBy).getTime() >= cutoff) return false;
|
|
17
|
+
}
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// src/offline/file-storage.ts
|
|
22
|
+
function resolveDir(dir) {
|
|
23
|
+
if (dir === "~" || dir.startsWith("~/")) {
|
|
24
|
+
return path.join(os.homedir(), dir.slice(1));
|
|
25
|
+
}
|
|
26
|
+
return dir;
|
|
27
|
+
}
|
|
28
|
+
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
29
|
+
function validateId(id) {
|
|
30
|
+
if (!UUID_RE.test(id)) {
|
|
31
|
+
throw new Error(`Invalid invoice ID: ${id}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
var FileOfflineInvoiceStorage = class {
|
|
35
|
+
dir;
|
|
36
|
+
constructor(directory) {
|
|
37
|
+
this.dir = resolveDir(directory ?? "~/.ksef/offline");
|
|
38
|
+
}
|
|
39
|
+
async ensureDir() {
|
|
40
|
+
await fs.mkdir(this.dir, { recursive: true });
|
|
41
|
+
}
|
|
42
|
+
filePath(id) {
|
|
43
|
+
validateId(id);
|
|
44
|
+
return path.join(this.dir, `${id}.json`);
|
|
45
|
+
}
|
|
46
|
+
async save(invoice) {
|
|
47
|
+
await this.ensureDir();
|
|
48
|
+
const file = this.filePath(invoice.id);
|
|
49
|
+
const tmp = `${file}.tmp`;
|
|
50
|
+
await fs.writeFile(tmp, JSON.stringify(invoice, null, 2));
|
|
51
|
+
await fs.rename(tmp, file);
|
|
52
|
+
}
|
|
53
|
+
async get(id) {
|
|
54
|
+
const file = this.filePath(id);
|
|
55
|
+
try {
|
|
56
|
+
return JSON.parse(await fs.readFile(file, "utf-8"));
|
|
57
|
+
} catch (err) {
|
|
58
|
+
if (err instanceof Error && "code" in err && err.code === "ENOENT") {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
console.warn(`Warning: Failed to read offline invoice ${id}: ${err instanceof Error ? err.message : String(err)}`);
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async list(filter) {
|
|
66
|
+
let files;
|
|
67
|
+
try {
|
|
68
|
+
files = (await fs.readdir(this.dir)).filter((f) => f.endsWith(".json"));
|
|
69
|
+
} catch {
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
const results = [];
|
|
73
|
+
for (const file of files) {
|
|
74
|
+
try {
|
|
75
|
+
const data = JSON.parse(
|
|
76
|
+
await fs.readFile(path.join(this.dir, file), "utf-8")
|
|
77
|
+
);
|
|
78
|
+
if (!filter || matchesFilter(data, filter)) {
|
|
79
|
+
results.push(data);
|
|
80
|
+
}
|
|
81
|
+
} catch (err) {
|
|
82
|
+
console.warn(`Warning: Skipping corrupt offline invoice file ${file}: ${err instanceof Error ? err.message : String(err)}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return results;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Update invoice metadata (read-modify-write).
|
|
89
|
+
*
|
|
90
|
+
* Note: No file locking — concurrent updates to the same ID may cause
|
|
91
|
+
* lost writes. Acceptable for CLI (single process). Library consumers
|
|
92
|
+
* running parallel operations should use external locking.
|
|
93
|
+
*/
|
|
94
|
+
async update(id, updates) {
|
|
95
|
+
const existing = await this.get(id);
|
|
96
|
+
if (!existing) throw new Error(`Offline invoice not found: ${id}`);
|
|
97
|
+
await this.save({ ...existing, ...updates });
|
|
98
|
+
}
|
|
99
|
+
async delete(id) {
|
|
100
|
+
const file = this.filePath(id);
|
|
101
|
+
try {
|
|
102
|
+
await fs.unlink(file);
|
|
103
|
+
} catch (e) {
|
|
104
|
+
if (e instanceof Error && "code" in e && e.code !== "ENOENT") throw e;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// src/validation/xsd-validator.ts
|
|
110
|
+
import { createRequire } from "node:module";
|
|
111
|
+
import * as fs2 from "node:fs";
|
|
112
|
+
import * as path2 from "node:path";
|
|
113
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
114
|
+
var cachedPkgRoot = null;
|
|
115
|
+
function locatePackageRoot() {
|
|
116
|
+
if (cachedPkgRoot !== null) return cachedPkgRoot;
|
|
117
|
+
let dir = path2.dirname(fileURLToPath(import.meta.url));
|
|
118
|
+
const root = path2.parse(dir).root;
|
|
119
|
+
while (dir !== root) {
|
|
120
|
+
const candidate = path2.join(dir, "docs", "schemas");
|
|
121
|
+
if (fs2.existsSync(candidate)) {
|
|
122
|
+
cachedPkgRoot = dir;
|
|
123
|
+
return dir;
|
|
124
|
+
}
|
|
125
|
+
dir = path2.dirname(dir);
|
|
126
|
+
}
|
|
127
|
+
throw new Error("Could not locate ksef-client-ts package root (docs/schemas not found).");
|
|
128
|
+
}
|
|
129
|
+
var XSD_RELATIVE = {
|
|
130
|
+
FA2: ["FA", "schemat_FA(2)_v1-0E.xsd"],
|
|
131
|
+
FA3: ["FA", "schemat_FA(3)_v1-0E.xsd"],
|
|
132
|
+
PEF: ["PEF", "Schemat_PEF(3)_v2-1.xsd"],
|
|
133
|
+
PEF_KOR: ["PEF", "Schemat_PEF_KOR(3)_v2-1.xsd"]
|
|
134
|
+
};
|
|
135
|
+
var FA_XSD_PATHS = {
|
|
136
|
+
get FA2() {
|
|
137
|
+
return resolveXsdFor("FA2");
|
|
138
|
+
},
|
|
139
|
+
get FA3() {
|
|
140
|
+
return resolveXsdFor("FA3");
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
var PEF_XSD_PATHS = {
|
|
144
|
+
get PEF() {
|
|
145
|
+
return resolveXsdFor("PEF");
|
|
146
|
+
},
|
|
147
|
+
get PEF_KOR() {
|
|
148
|
+
return resolveXsdFor("PEF_KOR");
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
function resolveXsdFor(schema) {
|
|
152
|
+
const rel = XSD_RELATIVE[schema];
|
|
153
|
+
if (!rel) throw new Error(`Unknown invoice schema: ${String(schema)}`);
|
|
154
|
+
return path2.join(locatePackageRoot(), "docs", "schemas", ...rel);
|
|
155
|
+
}
|
|
156
|
+
var requireModule = createRequire(import.meta.url);
|
|
157
|
+
var libxmljs = null;
|
|
158
|
+
var libxmljsLoadError = null;
|
|
159
|
+
try {
|
|
160
|
+
libxmljs = requireModule("libxmljs2");
|
|
161
|
+
} catch (err) {
|
|
162
|
+
const code = err?.code;
|
|
163
|
+
if (code === "MODULE_NOT_FOUND" || code === "ERR_MODULE_NOT_FOUND") {
|
|
164
|
+
libxmljs = null;
|
|
165
|
+
} else {
|
|
166
|
+
libxmljs = null;
|
|
167
|
+
libxmljsLoadError = err instanceof Error ? err : new Error(String(err));
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
var libxmljsAvailable = libxmljs !== null;
|
|
171
|
+
var MISSING_LIBXMLJS_MESSAGE_PREFIX = "libxmljs2 is not installed";
|
|
172
|
+
function isMissingLibxmljsError(err) {
|
|
173
|
+
return err instanceof Error && err.message.startsWith(MISSING_LIBXMLJS_MESSAGE_PREFIX);
|
|
174
|
+
}
|
|
175
|
+
var EXTERNAL_STRUKTURY_DANYCH_URL = /schemaLocation="http:\/\/crd\.gov\.pl\/xml\/schematy\/dziedzinowe\/mf\/2022\/01\/05\/eD\/DefinicjeTypy\/StrukturyDanych_v10-0E\.xsd"/;
|
|
176
|
+
function rewriteSchemaLocations(xsdContent) {
|
|
177
|
+
if (!EXTERNAL_STRUKTURY_DANYCH_URL.test(xsdContent)) {
|
|
178
|
+
return xsdContent;
|
|
179
|
+
}
|
|
180
|
+
const bazoweStrukturyPath = path2.join(
|
|
181
|
+
locatePackageRoot(),
|
|
182
|
+
"docs",
|
|
183
|
+
"schemas",
|
|
184
|
+
"FA",
|
|
185
|
+
"bazowe",
|
|
186
|
+
"StrukturyDanych_v10-0E.xsd"
|
|
187
|
+
);
|
|
188
|
+
const bazoweStrukturyUrl = pathToFileURL(bazoweStrukturyPath).href;
|
|
189
|
+
const rewritten = xsdContent.replace(
|
|
190
|
+
EXTERNAL_STRUKTURY_DANYCH_URL,
|
|
191
|
+
`schemaLocation="${bazoweStrukturyUrl}"`
|
|
192
|
+
);
|
|
193
|
+
if (rewritten === xsdContent) {
|
|
194
|
+
throw new Error(
|
|
195
|
+
"FA XSD schemaLocation rewrite produced no replacement despite URL being present; regex likely out of sync with docs/schemas/FA/. Re-check after `yarn sync-schemas`."
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
return rewritten;
|
|
199
|
+
}
|
|
200
|
+
function validateAgainstXsd(xml, xsdPath) {
|
|
201
|
+
if (!libxmljs) {
|
|
202
|
+
const loadSuffix = libxmljsLoadError ? ` (load failed: ${libxmljsLoadError.message})` : "";
|
|
203
|
+
throw new Error(
|
|
204
|
+
`${MISSING_LIBXMLJS_MESSAGE_PREFIX}${loadSuffix}; cannot run XSD validation. Install it as an optional peer dependency (e.g. \`yarn add -O libxmljs2\` or \`npm i -O libxmljs2\`).`
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
const xsdDir = path2.dirname(xsdPath);
|
|
208
|
+
const rawXsd = fs2.readFileSync(xsdPath, "utf8");
|
|
209
|
+
const rewrittenXsd = rewriteSchemaLocations(rawXsd);
|
|
210
|
+
const baseUrl = pathToFileURL(xsdDir + path2.sep).href;
|
|
211
|
+
let schemaDoc;
|
|
212
|
+
try {
|
|
213
|
+
schemaDoc = libxmljs.parseXml(rewrittenXsd, { baseUrl });
|
|
214
|
+
} catch (err) {
|
|
215
|
+
return { valid: false, errors: [`XSD parse failed: ${err.message}`] };
|
|
216
|
+
}
|
|
217
|
+
let xmlDoc;
|
|
218
|
+
try {
|
|
219
|
+
xmlDoc = libxmljs.parseXml(xml);
|
|
220
|
+
} catch (err) {
|
|
221
|
+
return { valid: false, errors: [`XML parse failed: ${err.message}`] };
|
|
222
|
+
}
|
|
223
|
+
const valid = xmlDoc.validate(schemaDoc);
|
|
224
|
+
const errors = valid ? [] : xmlDoc.validationErrors.map((err) => err.message.trim());
|
|
225
|
+
return { valid, errors };
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// src/workflows/hwm-storage.ts
|
|
229
|
+
import * as fs3 from "node:fs/promises";
|
|
230
|
+
var FileHwmStore = class {
|
|
231
|
+
constructor(filePath) {
|
|
232
|
+
this.filePath = filePath;
|
|
233
|
+
}
|
|
234
|
+
filePath;
|
|
235
|
+
async load() {
|
|
236
|
+
try {
|
|
237
|
+
const data = await fs3.readFile(this.filePath, "utf-8");
|
|
238
|
+
return JSON.parse(data);
|
|
239
|
+
} catch (err) {
|
|
240
|
+
if (err.code === "ENOENT") {
|
|
241
|
+
return {};
|
|
242
|
+
}
|
|
243
|
+
throw err;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
async save(points) {
|
|
247
|
+
await fs3.writeFile(this.filePath, JSON.stringify(points, null, 2), "utf-8");
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
export {
|
|
251
|
+
FA_XSD_PATHS,
|
|
252
|
+
FileHwmStore,
|
|
253
|
+
FileOfflineInvoiceStorage,
|
|
254
|
+
PEF_XSD_PATHS,
|
|
255
|
+
isMissingLibxmljsError,
|
|
256
|
+
libxmljsAvailable,
|
|
257
|
+
resolveXsdFor,
|
|
258
|
+
validateAgainstXsd
|
|
259
|
+
};
|
|
260
|
+
//# sourceMappingURL=node.js.map
|
package/dist/node.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/offline/file-storage.ts","../src/offline/storage.ts","../src/validation/xsd-validator.ts","../src/workflows/hwm-storage.ts"],"sourcesContent":["import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport * as os from 'node:os';\nimport type { OfflineInvoiceMetadata } from './types.js';\nimport { matchesFilter } from './storage.js';\nimport type { OfflineInvoiceFilter, OfflineInvoiceStorage, OfflineInvoiceUpdates } from './storage.js';\n\nfunction resolveDir(dir: string): string {\n if (dir === '~' || dir.startsWith('~/')) {\n return path.join(os.homedir(), dir.slice(1));\n }\n return dir;\n}\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\nfunction validateId(id: string): void {\n if (!UUID_RE.test(id)) {\n throw new Error(`Invalid invoice ID: ${id}`);\n }\n}\n\nexport class FileOfflineInvoiceStorage implements OfflineInvoiceStorage {\n private readonly dir: string;\n\n constructor(directory?: string) {\n this.dir = resolveDir(directory ?? '~/.ksef/offline');\n }\n\n private async ensureDir(): Promise<void> {\n await fs.mkdir(this.dir, { recursive: true });\n }\n\n private filePath(id: string): string {\n validateId(id);\n return path.join(this.dir, `${id}.json`);\n }\n\n async save(invoice: OfflineInvoiceMetadata): Promise<void> {\n await this.ensureDir();\n const file = this.filePath(invoice.id);\n const tmp = `${file}.tmp`;\n await fs.writeFile(tmp, JSON.stringify(invoice, null, 2));\n await fs.rename(tmp, file);\n }\n\n async get(id: string): Promise<OfflineInvoiceMetadata | null> {\n const file = this.filePath(id);\n try {\n return JSON.parse(await fs.readFile(file, 'utf-8'));\n } catch (err: unknown) {\n if (err instanceof Error && 'code' in err && (err as NodeJS.ErrnoException).code === 'ENOENT') {\n return null;\n }\n console.warn(`Warning: Failed to read offline invoice ${id}: ${err instanceof Error ? err.message : String(err)}`);\n return null;\n }\n }\n\n async list(filter?: OfflineInvoiceFilter): Promise<OfflineInvoiceMetadata[]> {\n let files: string[];\n try {\n files = (await fs.readdir(this.dir)).filter(f => f.endsWith('.json'));\n } catch {\n return [];\n }\n const results: OfflineInvoiceMetadata[] = [];\n for (const file of files) {\n try {\n const data: OfflineInvoiceMetadata = JSON.parse(\n await fs.readFile(path.join(this.dir, file), 'utf-8'),\n );\n if (!filter || matchesFilter(data, filter)) {\n results.push(data);\n }\n } catch (err: unknown) {\n console.warn(`Warning: Skipping corrupt offline invoice file ${file}: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n return results;\n }\n\n /**\n * Update invoice metadata (read-modify-write).\n *\n * Note: No file locking — concurrent updates to the same ID may cause\n * lost writes. Acceptable for CLI (single process). Library consumers\n * running parallel operations should use external locking.\n */\n async update(id: string, updates: OfflineInvoiceUpdates): Promise<void> {\n const existing = await this.get(id);\n if (!existing) throw new Error(`Offline invoice not found: ${id}`);\n await this.save({ ...existing, ...updates });\n }\n\n async delete(id: string): Promise<void> {\n const file = this.filePath(id);\n try {\n await fs.unlink(file);\n } catch (e: unknown) {\n if (e instanceof Error && 'code' in e && e.code !== 'ENOENT') throw e;\n }\n }\n}\n","import type { OfflineInvoiceMetadata, OfflineInvoiceStatus, OfflineMode } from './types.js';\n\nexport interface OfflineInvoiceFilter {\n status?: OfflineInvoiceStatus | OfflineInvoiceStatus[];\n mode?: OfflineMode;\n expiringBefore?: Date | string;\n sellerNip?: string;\n}\n\nexport type OfflineInvoiceUpdates = Omit<Partial<OfflineInvoiceMetadata>, 'id'>;\n\nexport interface OfflineInvoiceStorage {\n save(invoice: OfflineInvoiceMetadata): Promise<void>;\n get(id: string): Promise<OfflineInvoiceMetadata | null>;\n list(filter?: OfflineInvoiceFilter): Promise<OfflineInvoiceMetadata[]>;\n update(id: string, updates: OfflineInvoiceUpdates): Promise<void>;\n delete(id: string): Promise<void>;\n}\n\nexport function matchesFilter(invoice: OfflineInvoiceMetadata, filter: OfflineInvoiceFilter): boolean {\n if (filter.status !== undefined) {\n const statuses = Array.isArray(filter.status) ? filter.status : [filter.status];\n if (!statuses.includes(invoice.status)) return false;\n }\n if (filter.mode !== undefined && invoice.mode !== filter.mode) return false;\n if (filter.sellerNip !== undefined && invoice.sellerNip !== filter.sellerNip) return false;\n if (filter.expiringBefore !== undefined) {\n const cutoff = typeof filter.expiringBefore === 'string'\n ? new Date(filter.expiringBefore).getTime()\n : filter.expiringBefore.getTime();\n if (new Date(invoice.submitBy).getTime() >= cutoff) return false;\n }\n return true;\n}\n\nexport class InMemoryOfflineInvoiceStorage implements OfflineInvoiceStorage {\n private readonly store = new Map<string, OfflineInvoiceMetadata>();\n\n async save(invoice: OfflineInvoiceMetadata): Promise<void> {\n this.store.set(invoice.id, JSON.parse(JSON.stringify(invoice)));\n }\n\n async get(id: string): Promise<OfflineInvoiceMetadata | null> {\n const entry = this.store.get(id);\n return entry ? JSON.parse(JSON.stringify(entry)) : null;\n }\n\n async list(filter?: OfflineInvoiceFilter): Promise<OfflineInvoiceMetadata[]> {\n const all = [...this.store.values()];\n if (!filter) return all.map(i => JSON.parse(JSON.stringify(i)));\n return all.filter(i => matchesFilter(i, filter)).map(i => JSON.parse(JSON.stringify(i)));\n }\n\n async update(id: string, updates: OfflineInvoiceUpdates): Promise<void> {\n const existing = this.store.get(id);\n if (!existing) throw new Error(`Offline invoice not found: ${id}`);\n this.store.set(id, JSON.parse(JSON.stringify({ ...existing, ...updates })));\n }\n\n async delete(id: string): Promise<void> {\n this.store.delete(id);\n }\n}\n","import { createRequire } from 'node:module';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\n\nlet cachedPkgRoot: string | null = null;\n\nfunction locatePackageRoot(): string {\n if (cachedPkgRoot !== null) return cachedPkgRoot;\n let dir = path.dirname(fileURLToPath(import.meta.url));\n const root = path.parse(dir).root;\n while (dir !== root) {\n const candidate = path.join(dir, 'docs', 'schemas');\n if (fs.existsSync(candidate)) {\n cachedPkgRoot = dir;\n return dir;\n }\n dir = path.dirname(dir);\n }\n throw new Error('Could not locate ksef-client-ts package root (docs/schemas not found).');\n}\n\nexport type InvoiceSchemaId = 'FA2' | 'FA3' | 'PEF' | 'PEF_KOR';\n\nconst XSD_RELATIVE: Record<InvoiceSchemaId, readonly string[]> = {\n FA2: ['FA', 'schemat_FA(2)_v1-0E.xsd'],\n FA3: ['FA', 'schemat_FA(3)_v1-0E.xsd'],\n PEF: ['PEF', 'Schemat_PEF(3)_v2-1.xsd'],\n PEF_KOR: ['PEF', 'Schemat_PEF_KOR(3)_v2-1.xsd'],\n};\n\nexport const FA_XSD_PATHS = {\n get FA2(): string { return resolveXsdFor('FA2'); },\n get FA3(): string { return resolveXsdFor('FA3'); },\n} as const;\n\nexport const PEF_XSD_PATHS = {\n get PEF(): string { return resolveXsdFor('PEF'); },\n get PEF_KOR(): string { return resolveXsdFor('PEF_KOR'); },\n} as const;\n\nexport function resolveXsdFor(schema: InvoiceSchemaId): string {\n const rel = XSD_RELATIVE[schema];\n if (!rel) throw new Error(`Unknown invoice schema: ${String(schema)}`);\n return path.join(locatePackageRoot(), 'docs', 'schemas', ...rel);\n}\n\nexport interface ValidateAgainstXsdResult {\n valid: boolean;\n errors: string[];\n}\n\nconst requireModule = createRequire(import.meta.url);\n\ntype LibxmljsModule = {\n parseXml: (\n xml: string,\n options?: { baseUrl?: string },\n ) => {\n validate: (schema: unknown) => boolean;\n validationErrors: Array<{ message: string }>;\n };\n};\n\nlet libxmljs: LibxmljsModule | null = null;\n// Non-MODULE_NOT_FOUND failures (e.g. ERR_DLOPEN_FAILED from a native\n// binding ABI mismatch after a Node upgrade) are retained so we can\n// surface them at call time instead of masking them as \"not installed\"\n// and sending users to reinstall a module that is already on disk.\nlet libxmljsLoadError: Error | null = null;\ntry {\n libxmljs = requireModule('libxmljs2') as LibxmljsModule;\n} catch (err) {\n const code = (err as NodeJS.ErrnoException | undefined)?.code;\n if (code === 'MODULE_NOT_FOUND' || code === 'ERR_MODULE_NOT_FOUND') {\n libxmljs = null;\n } else {\n libxmljs = null;\n libxmljsLoadError = err instanceof Error ? err : new Error(String(err));\n }\n}\n\nexport const libxmljsAvailable: boolean = libxmljs !== null;\n\nconst MISSING_LIBXMLJS_MESSAGE_PREFIX = 'libxmljs2 is not installed';\n\nexport function isMissingLibxmljsError(err: unknown): boolean {\n return err instanceof Error && err.message.startsWith(MISSING_LIBXMLJS_MESSAGE_PREFIX);\n}\n\n// Only FA XSDs reference the external crd.gov.pl schemaLocation that needs\n// rewriting to a local file://-URL. PEF XSDs have no such import, so this\n// regex legitimately produces no replacement on a PEF path — callers must\n// not treat a zero-replacement PEF rewrite as drift.\n//\n// Kept non-global: FA XSDs carry the import exactly once, and a non-global\n// regex avoids the stateful `lastIndex` footgun that `.test()` would\n// otherwise leave behind on repeat calls.\nconst EXTERNAL_STRUKTURY_DANYCH_URL =\n /schemaLocation=\"http:\\/\\/crd\\.gov\\.pl\\/xml\\/schematy\\/dziedzinowe\\/mf\\/2022\\/01\\/05\\/eD\\/DefinicjeTypy\\/StrukturyDanych_v10-0E\\.xsd\"/;\n\nfunction rewriteSchemaLocations(xsdContent: string): string {\n // No upstream URL present → nothing to rewrite (PEF XSDs reach this path\n // unchanged). Returning early makes the drift-guard below unambiguous.\n if (!EXTERNAL_STRUKTURY_DANYCH_URL.test(xsdContent)) {\n return xsdContent;\n }\n\n const bazoweStrukturyPath = path.join(\n locatePackageRoot(),\n 'docs',\n 'schemas',\n 'FA',\n 'bazowe',\n 'StrukturyDanych_v10-0E.xsd',\n );\n const bazoweStrukturyUrl = pathToFileURL(bazoweStrukturyPath).href;\n const rewritten = xsdContent.replace(\n EXTERNAL_STRUKTURY_DANYCH_URL,\n `schemaLocation=\"${bazoweStrukturyUrl}\"`,\n );\n\n // Drift-guard: the URL was present but `.replace()` produced no change.\n // Should be unreachable unless the regex and the URL diverge — fail loud\n // rather than pass through an unresolved `<xsd:import>` to libxmljs.\n if (rewritten === xsdContent) {\n throw new Error(\n 'FA XSD schemaLocation rewrite produced no replacement despite URL being present; ' +\n 'regex likely out of sync with docs/schemas/FA/. Re-check after `yarn sync-schemas`.',\n );\n }\n return rewritten;\n}\n\nexport function validateAgainstXsd(xml: string, xsdPath: string): ValidateAgainstXsdResult {\n if (!libxmljs) {\n const loadSuffix = libxmljsLoadError\n ? ` (load failed: ${libxmljsLoadError.message})`\n : '';\n throw new Error(\n `${MISSING_LIBXMLJS_MESSAGE_PREFIX}${loadSuffix}; cannot run XSD validation. ` +\n 'Install it as an optional peer dependency (e.g. `yarn add -O libxmljs2` or `npm i -O libxmljs2`).',\n );\n }\n\n const xsdDir = path.dirname(xsdPath);\n const rawXsd = fs.readFileSync(xsdPath, 'utf8');\n const rewrittenXsd = rewriteSchemaLocations(rawXsd);\n const baseUrl = pathToFileURL(xsdDir + path.sep).href;\n\n let schemaDoc;\n try {\n schemaDoc = libxmljs.parseXml(rewrittenXsd, { baseUrl });\n } catch (err) {\n return { valid: false, errors: [`XSD parse failed: ${(err as Error).message}`] };\n }\n let xmlDoc;\n try {\n xmlDoc = libxmljs.parseXml(xml);\n } catch (err) {\n return { valid: false, errors: [`XML parse failed: ${(err as Error).message}`] };\n }\n\n const valid = xmlDoc.validate(schemaDoc);\n const errors = valid\n ? []\n : xmlDoc.validationErrors.map((err) => err.message.trim());\n\n return { valid, errors };\n}\n","import * as fs from 'node:fs/promises';\nimport type { ContinuationPoints } from './hwm-coordinator.js';\n\nexport interface HwmStore {\n load(): Promise<ContinuationPoints>;\n save(points: ContinuationPoints): Promise<void>;\n}\n\nexport class InMemoryHwmStore implements HwmStore {\n private points: ContinuationPoints = {};\n\n async load(): Promise<ContinuationPoints> {\n return { ...this.points };\n }\n\n async save(points: ContinuationPoints): Promise<void> {\n this.points = { ...points };\n }\n}\n\nexport class FileHwmStore implements HwmStore {\n constructor(private readonly filePath: string) {}\n\n async load(): Promise<ContinuationPoints> {\n try {\n const data = await fs.readFile(this.filePath, 'utf-8');\n return JSON.parse(data) as ContinuationPoints;\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n return {};\n }\n throw err;\n }\n }\n\n async save(points: ContinuationPoints): Promise<void> {\n await fs.writeFile(this.filePath, JSON.stringify(points, null, 2), 'utf-8');\n }\n}\n"],"mappings":"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","names":["fs","path","fs"]}
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ksef-client-ts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "TypeScript client for the Polish National e-Invoice System (KSeF) API",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
6
7
|
"main": "./dist/index.cjs",
|
|
7
8
|
"module": "./dist/index.js",
|
|
8
9
|
"types": "./dist/index.d.ts",
|
|
@@ -16,6 +17,16 @@
|
|
|
16
17
|
"types": "./dist/index.d.cts",
|
|
17
18
|
"default": "./dist/index.cjs"
|
|
18
19
|
}
|
|
20
|
+
},
|
|
21
|
+
"./node": {
|
|
22
|
+
"import": {
|
|
23
|
+
"types": "./dist/node.d.ts",
|
|
24
|
+
"default": "./dist/node.js"
|
|
25
|
+
},
|
|
26
|
+
"require": {
|
|
27
|
+
"types": "./dist/node.d.cts",
|
|
28
|
+
"default": "./dist/node.cjs"
|
|
29
|
+
}
|
|
19
30
|
}
|
|
20
31
|
},
|
|
21
32
|
"bin": {
|
|
@@ -33,6 +44,7 @@
|
|
|
33
44
|
"test:e2e:watch": "vitest tests/e2e --reporter=verbose",
|
|
34
45
|
"test:watch": "vitest",
|
|
35
46
|
"lint": "tsc --noEmit",
|
|
47
|
+
"check:node-types": "tsc --project tsconfig.node-check.json",
|
|
36
48
|
"lint:md": "markdownlint-cli2",
|
|
37
49
|
"lint:md:fix": "markdownlint-cli2 --fix",
|
|
38
50
|
"link": "npm link",
|