mirror of
https://github.com/netajam/obsidian_note_uid_generator.git
synced 2026-07-22 12:30:29 +00:00
* feat: add Snowflake ID generator and multi-folder auto-generation scope - Add Snowflake ID generator (64-bit, time-sortable, distributed) - Uses Unix timestamp directly (no custom epoch) - 41-bit timestamp + 10-bit node ID + 12-bit sequence - Auto-detect node ID from MAC address via os.networkInterfaces() - Falls back to a random persistent value on mobile - Node ID manually overridable in settings - Support multiple target folders for auto-generation scope - Replace single autoGenerationFolder string with autoGenerationFolders array - Automatic migration of existing single-folder setting to array - New FolderSelectionModal with search and add/remove UI - Bump build target to ES2020 for BigInt support - Fix Automatic uid generation description rendering (use setDesc on heading) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Tighten Snowflake init and bound the per-ms spin-wait src/main.ts onload: - Drop the redundant outer `uidGenerator === 'snowflake' || ...` guard. The inner branch only ran when `snowflakeAutoDetectNodeId` was true, so the outer disjunction was dead. Restrict initialization to the case where the user has actually selected Snowflake. - Skip `saveSettings()` when `detectNodeId()` returns the value already stored. The previous code wrote settings to disk on every plugin load, even when nothing had changed. src/uidUtils.ts: - Drop the inferrable `: bigint` annotations on the module-level Snowflake state (lint). - Bound the sequence-overflow spin-wait to a few ms. The previous `while (timestamp <= snowflakeLastTimestamp)` had no exit if the system clock was stuck or jumped backwards (NTP, suspend/resume). - Treat a backwards clock jump explicitly: bump the stored timestamp forward by one ms instead of regressing or spinning. IDs stay monotonic across the jump; nodeID/sequence layout is unchanged. - Export a test-only `_resetSnowflakeState` so unit tests can reset module state between cases. * Update test fakes and cover Snowflake + multi-folder scope The previous test suite was authored against the single-folder `autoGenerationFolder` setting. The PR replaces that with the `autoGenerationFolders` array, which broke 11 existing tests (the array was undefined in the fake's default settings). tests/fakes/app.ts: - Initialize `autoGenerationFolders: []` and the new Snowflake fields in the fake's DEFAULT_SETTINGS so plugin code that reads them in tests doesn't crash on `undefined`. - `snowflakeAutoDetectNodeId` defaults to `false` in the fake to keep tests deterministic. src/commands.test.ts: - Rewrite every `autoGenerationFolder: 'X'` case to use `autoGenerationFolders: ['X']`. The legacy field is now only consulted by the one-shot migration in loadSettings. - Add a `multi-folder scope` block that verifies in/out-of-scope decisions across multiple configured folders, nested subfolders, whitespace handling, and blank entries. src/uidUtils.test.ts: - Add a `Snowflake ID generator` block: numeric-string output, node-ID encoding (including >1023 clamp), per-ms sequence increment, sequence reset on next ms, monotonic output across many calls in one ms, and recovery from a backwards clock jump. - Reset module state between cases via `_resetSnowflakeState`. * Document Snowflake generator and multi-folder auto-generation scope - Add Snowflake to the algorithm overview, noting the bit layout and the desktop-MAC / mobile-random node ID derivation. - Update the Auto-Generation section to reference Specific Folder(s), the new "Manage folders" modal, and the automatic migration of the legacy single-folder setting. - Add the new Snowflake settings (Auto-detect Node ID, Node ID) to the Settings reference. - Update the "Auto-Assign IDs to New Notes in Inbox" example for the new modal-based folder picker. - List src/ui/FolderSelectionModal.ts in the Code Structure section. * Show Machine and Custom Node IDs as separate fields Replace the single Node ID input + auto-detect toggle with two distinct fields, so users can see at a glance whether the value used for generated IDs is the machine default or an explicit override: - Machine Node ID (read-only): the MAC-derived value on desktop, or the random persistent fallback on mobile. Always visible and always current — re-resolved on plugin load and on every settings render via `resolveAutoDetectedNodeId`. - Custom Node ID (text input): optional override. When set, it takes precedence over the machine value at generation time. Clearing the field falls back to the machine value. Settings model: - Add `snowflakeNodeIdOverride: number | null`. - Remove the `snowflakeAutoDetectNodeId` toggle from the active model; it lives on as an optional legacy field for one-shot migration. - One-shot migration: a previous build's `snowflakeAutoDetectNodeId === false` with a non-zero `snowflakeNodeId` is preserved as a Custom Node ID, then the legacy field is deleted. Generator: `generateRawUID` now resolves `override ?? snowflakeNodeId` per call, so changes to either field take effect immediately. Tests: add coverage for both precedence directions (override wins; null override falls through to the machine value). Descriptions in the settings UI flip between "currently used" and "currently NOT used / overridden below" so the precedence is obvious without reading the README. * Cover the Snowflake auto-detect resolution paths `resolveAutoDetectedNodeId` is the entry point used by main.ts onload and the settings UI to keep the cached machine Node ID in sync with the hardware. It had zero unit coverage. To make the no-MAC (mobile) path testable without depending on the test machine, accept an optional `detect` parameter that defaults to `detectNodeId`. Production callers don't pass it. New tests cover: - Detected differs from stored → returns the detected value. - Detected matches stored → returns null (no churn). - Mobile + stored 0 → picks a random 10-bit value. - Mobile + stored already set → returns null (preserves the random pick). - Math.random() at extreme values stays in 0–1023 (Math.floor guard). Plus a smoke test for `detectNodeId`: never throws on the host running tests, returns either null or a number in 0–1023, and is deterministic across calls on the same machine. These exercise the cross-platform safety we rely on for Windows, Linux, macOS desktop and the iOS/Android Obsidian Mobile fallback. * Prevent the mobile random Node ID from colliding with the unset sentinel The previous code picked a random Node ID in 0..1023 when no MAC was available. `stored === 0` is also the sentinel for "not yet picked", so a 1-in-1024 unlucky roll landed on 0, made the saved settings look unset on next load, and triggered a re-roll. The user would silently get a new node ID on every restart, breaking ID stability across sessions and undermining the "random persistent" guarantee Snowflake relies on for mobile. Restrict the random fallback to 1..1023. The valid Snowflake node-ID range is unchanged (manual/MAC-derived values can still be 0); only the random pick is excluded from 0. Losing one out of 1024 possible values in the random pool is negligible. Add tests: - The mobile path never returns 0 (lock the sentinel-collision fix in). - A two-load simulation: first call picks a value, second call returns null — i.e. the saved value is genuinely persistent. --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Netajam <leonard.tavoli@gmail.com>
37 lines
733 B
JSON
37 lines
733 B
JSON
{
|
|
"compilerOptions": {
|
|
"baseUrl": ".",
|
|
"inlineSourceMap": true,
|
|
"inlineSources": true,
|
|
"module": "ESNext",
|
|
"target": "ES2020",
|
|
"allowJs": true,
|
|
"noImplicitAny": true,
|
|
"moduleResolution": "node",
|
|
"importHelpers": true,
|
|
"isolatedModules": true,
|
|
"strictNullChecks": true,
|
|
"lib": [
|
|
"DOM",
|
|
"ES5",
|
|
"ES6",
|
|
"ES7",
|
|
"ES2020"
|
|
]
|
|
},
|
|
"typeRoots": [
|
|
"./node_modules/@types", // Standard location for installed types
|
|
"./src/typings" // Your custom typings folder
|
|
],
|
|
"include": [
|
|
"**/*.ts","**/*.d.ts", "src/typings/obsidian.d.ts"
|
|
|
|
|
|
],
|
|
"exclude": [
|
|
"node_modules",
|
|
"tests",
|
|
"src/**/*.test.ts",
|
|
"vitest.config.ts"
|
|
]
|
|
}
|