-
Notifications
You must be signed in to change notification settings - Fork 0
v0.10.0: fs-free environment-agnostic core + ksef-client-ts/node entry (GH#24) #31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
3572717
feat: fs-free root barrel + ksef-client-ts/node entry (FLO-244) (#27)
Fl0p 39dcfa1
test: /node subpath resolution tests — ESM, CJS, and types (FLO-246)
Fl0p 2b1d595
test: guard core bundles against fs leaks (FLO-245) (#28)
Fl0p c810cca
docs: v0.10.0 /node entry point — README, CHANGELOG & migration (FLO-…
Fl0p 8ea8a1f
ci: build before type check so /node subpath type fixture resolves (F…
762b7b8
docs(changelog): drop symbol names from /node entry point note
99dbcd1
docs(changelog): make async-crypto entry user-facing
c6c1cde
test(fs-guard): also assert the CJS node bundle carries fs markers
a5fd178
docs(core)+ci: describe core as fs-free; split node-type check out of…
be6fe9c
docs(migration): add troubleshooting for /node subpath resolution
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| # Migration Guide: v0.10.0 | ||
|
|
||
| Version `0.10.0` introduces a significant refactoring to improve portability and reduce the bundle size for web and edge environments. This guide outlines the breaking changes and how to update your code. | ||
|
|
||
| ## Node.js-specific Features Moved to a Separate Entry Point | ||
|
|
||
| To keep the core `ksef-client-ts` library free of filesystem dependencies (so it runs on Deno and edge functions without Node-specific filesystem access), filesystem-dependent and other Node-only features have been moved to a separate entry point: `ksef-client-ts/node`. | ||
|
|
||
| If your application runs on Node.js and uses any of the features listed below, you will need to update your import paths. | ||
|
|
||
| ### Affected Features | ||
|
|
||
| 1. **Offline Invoice Storage:** The `FileOfflineInvoiceStorage` class, which uses the filesystem to store offline invoices, is now exposed via the `ksef-client-ts/node` entry point. | ||
|
|
||
| **Before:** | ||
|
|
||
| ```typescript | ||
| import { FileOfflineInvoiceStorage } from 'ksef-client-ts'; | ||
| ``` | ||
|
|
||
| **After:** | ||
|
|
||
| ```typescript | ||
| import { FileOfflineInvoiceStorage } from 'ksef-client-ts/node'; | ||
| ``` | ||
|
|
||
| 2. **XSD Schema Validation:** The `validateAgainstXsd` function and its related helpers rely on `libxmljs2`, a native Node.js module. These are now available from the `ksef-client-ts/node` entry point. | ||
|
|
||
| **Before:** | ||
|
|
||
| ```typescript | ||
| import { validateAgainstXsd } from 'ksef-client-ts'; | ||
| ``` | ||
|
|
||
| **After:** | ||
|
|
||
| ```typescript | ||
| import { validateAgainstXsd } from 'ksef-client-ts/node'; | ||
| ``` | ||
|
|
||
| This also applies to `FA_XSD_PATHS`, `PEF_XSD_PATHS`, `libxmljsAvailable`, `resolveXsdFor`, and `isMissingLibxmljsError`. | ||
|
|
||
| 3. **High-Water-Mark Storage for Incremental Export:** The `FileHwmStore`, used for persisting the high-water-mark in incremental invoice exports, has been moved. | ||
|
|
||
| **Before:** | ||
|
|
||
| ```typescript | ||
| import { FileHwmStore } from 'ksef-client-ts'; | ||
| ``` | ||
|
|
||
| **After:** | ||
|
|
||
| ```typescript | ||
| import { FileHwmStore } from 'ksef-client-ts/node'; | ||
| ``` | ||
|
|
||
| ### Rationale | ||
|
|
||
| This change allows developers to use `ksef-client-ts` in a wider range of JavaScript environments without including unnecessary Node.js-specific code, leading to smaller bundles and better performance, especially in serverless and edge computing contexts. | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| The `ksef-client-ts/node` entry point is published as a [subpath export](https://nodejs.org/api/packages.html#subpath-exports). Two toolchain setups need attention after you update an import. | ||
|
|
||
| ### TypeScript: `Cannot find module 'ksef-client-ts/node'` (TS2307) | ||
|
|
||
| If TypeScript reports `TS2307` for the new import even though the code runs fine at runtime, your project is using the legacy module resolution that does not read the package `exports` map. Set `moduleResolution` to a value that supports subpath exports: | ||
|
|
||
| ```json | ||
| { | ||
| "compilerOptions": { | ||
| "module": "node16", | ||
| "moduleResolution": "node16" | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| `nodenext` or `bundler` work too. The legacy `node` (a.k.a. `node10`) resolution cannot resolve subpath exports and will keep failing. | ||
|
|
||
| ### CommonJS: the moved symbol is `undefined` | ||
|
|
||
| Under CommonJS, importing a moved symbol from the root entry point no longer throws at `require` time — it silently resolves to `undefined`, and you only see the failure later when you use it: | ||
|
|
||
| ```js | ||
| // ❌ FileHwmStore is undefined here — no error yet | ||
| const { FileHwmStore } = require('ksef-client-ts'); | ||
| new FileHwmStore(); // TypeError: FileHwmStore is not a constructor | ||
|
|
||
| // ✅ require from the /node entry point instead | ||
| const { FileHwmStore } = require('ksef-client-ts/node'); | ||
| ``` | ||
|
|
||
| If you hit a `TypeError: X is not a constructor` (or a call on `undefined`) for any of the moved symbols, update the `require` path to `ksef-client-ts/node`. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| import { readFile } from "node:fs/promises"; | ||
| import { fileURLToPath } from "node:url"; | ||
| import path from "node:path"; | ||
|
|
||
| const packageRoot = path.resolve( | ||
| path.dirname(fileURLToPath(import.meta.url)), | ||
| "..", | ||
| ); | ||
|
|
||
| export const coreBundlePaths = ["dist/index.js", "dist/index.cjs"]; | ||
| export const nodeBundlePaths = ["dist/node.js", "dist/node.cjs"]; | ||
|
|
||
| export const fsLeakPatterns = [ | ||
| { label: "node:fs/promises", pattern: /node:fs\/promises/ }, | ||
| { label: "node:fs", pattern: /node:fs/ }, | ||
| { label: "fs/promises", pattern: /(?<!node:)fs\/promises/ }, | ||
| { | ||
| label: "require(\"fs\")", | ||
| pattern: /require\s*\(\s*["'](?:node:)?fs["']\s*\)/, | ||
| }, | ||
| { | ||
| label: "require(\"fs/promises\")", | ||
| pattern: /require\s*\(\s*["'](?:node:)?fs\/promises["']\s*\)/, | ||
| }, | ||
| { | ||
| label: "from \"fs\"", | ||
| pattern: /from\s*["'](?:node:)?fs["']/, | ||
| }, | ||
| { | ||
| label: "from \"fs/promises\"", | ||
| pattern: /from\s*["'](?:node:)?fs\/promises["']/, | ||
| }, | ||
| { label: "readFileSync", pattern: /\breadFileSync\b/ }, | ||
| { label: "writeFileSync", pattern: /\bwriteFileSync\b/ }, | ||
| { label: "readFile", pattern: /\breadFile\b/ }, | ||
| { label: "writeFile", pattern: /\bwriteFile\b/ }, | ||
| { label: "homedir", pattern: /\bhomedir\b/ }, | ||
| ]; | ||
|
|
||
| export function findFsMarkers(source) { | ||
| return fsLeakPatterns | ||
| .filter(({ pattern }) => pattern.test(source)) | ||
| .map(({ label }) => label); | ||
| } | ||
|
|
||
| async function readBundle(relativePath) { | ||
| const absolutePath = path.join(packageRoot, relativePath); | ||
|
|
||
| try { | ||
| return await readFile(absolutePath, "utf8"); | ||
| } catch (error) { | ||
| if (error?.code === "ENOENT") { | ||
| throw new Error(`Missing built bundle: ${relativePath}. Run yarn build first.`); | ||
| } | ||
|
|
||
| throw error; | ||
| } | ||
| } | ||
|
|
||
| export async function checkFsFreeCore() { | ||
| const failures = []; | ||
|
|
||
| for (const relativePath of coreBundlePaths) { | ||
| const source = await readBundle(relativePath); | ||
| const markers = findFsMarkers(source); | ||
|
|
||
| if (markers.length > 0) { | ||
| failures.push(`${relativePath}: ${markers.join(", ")}`); | ||
| } | ||
| } | ||
|
|
||
| for (const relativePath of nodeBundlePaths) { | ||
| const nodeBundleMarkers = findFsMarkers(await readBundle(relativePath)); | ||
|
|
||
| if (nodeBundleMarkers.length === 0) { | ||
| failures.push(`${relativePath}: expected fs marker for node-only entry`); | ||
| } | ||
| } | ||
|
|
||
| if (failures.length > 0) { | ||
| throw new Error(`fs cleanliness guard failed:\n- ${failures.join("\n- ")}`); | ||
| } | ||
| } | ||
|
|
||
| if (process.argv[1] === fileURLToPath(import.meta.url)) { | ||
| checkFsFreeCore().catch((error) => { | ||
| console.error(error.message); | ||
| process.exitCode = 1; | ||
| }); | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.