@machinemetrics/mm-erp-sdk 0.9.6-beta.0 → 0.9.6-beta.1

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.
@@ -23,17 +23,25 @@ function getDb() {
23
23
  if (!db) {
24
24
  const filename = dbPath();
25
25
  ensureDbDirectory(filename);
26
- db = new Database(filename);
27
- db.pragma("journal_mode = WAL");
28
- db.pragma("busy_timeout = 5000");
29
- db.exec(`
26
+ const instance = new Database(filename);
27
+ instance.pragma("journal_mode = WAL");
28
+ instance.pragma("busy_timeout = 5000");
29
+ instance.exec(`
30
30
  CREATE TABLE IF NOT EXISTS ${TABLE} (
31
31
  key TEXT PRIMARY KEY,
32
32
  value TEXT NOT NULL,
33
33
  updated_at TEXT NOT NULL
34
34
  );
35
35
  `);
36
- importLegacyJobStateFileOnce();
36
+ db = instance;
37
+ try {
38
+ importLegacyJobStateFileOnce();
39
+ }
40
+ catch (error) {
41
+ instance.close();
42
+ db = null;
43
+ throw error;
44
+ }
37
45
  }
38
46
  return db;
39
47
  }
@@ -54,27 +62,22 @@ function importLegacyJobStateFileOnce() {
54
62
  if (readRaw(LEGACY_IMPORT_FLAG_KEY)) {
55
63
  return;
56
64
  }
57
- try {
58
- if (fs.existsSync(LEGACY_JOB_STATE_FILE)) {
59
- const raw = fs.readFileSync(LEGACY_JOB_STATE_FILE, "utf-8");
60
- const data = JSON.parse(raw);
61
- if (data.companyInfo && !readRaw("companyInfo")) {
62
- writeRaw("companyInfo", JSON.stringify(data.companyInfo));
63
- }
64
- if (data.mmApiToken && !readRaw("mmApiToken")) {
65
- writeRaw("mmApiToken", JSON.stringify(data.mmApiToken));
66
- }
67
- if (data.initialLoadComplete !== undefined &&
68
- !readRaw("initialLoadComplete")) {
69
- writeRaw("initialLoadComplete", JSON.stringify(data.initialLoadComplete));
70
- }
71
- if (data.databaseLock && !readRaw("databaseLock")) {
72
- writeRaw("databaseLock", JSON.stringify(data.databaseLock));
73
- }
65
+ if (fs.existsSync(LEGACY_JOB_STATE_FILE)) {
66
+ const raw = fs.readFileSync(LEGACY_JOB_STATE_FILE, "utf-8");
67
+ const data = JSON.parse(raw);
68
+ if (data.companyInfo && !readRaw("companyInfo")) {
69
+ writeRaw("companyInfo", JSON.stringify(data.companyInfo));
70
+ }
71
+ if (data.mmApiToken && !readRaw("mmApiToken")) {
72
+ writeRaw("mmApiToken", JSON.stringify(data.mmApiToken));
73
+ }
74
+ if (data.initialLoadComplete !== undefined &&
75
+ !readRaw("initialLoadComplete")) {
76
+ writeRaw("initialLoadComplete", JSON.stringify(data.initialLoadComplete));
77
+ }
78
+ if (data.databaseLock && !readRaw("databaseLock")) {
79
+ writeRaw("databaseLock", JSON.stringify(data.databaseLock));
74
80
  }
75
- }
76
- catch (error) {
77
- console.error(`Failed to import legacy job state from ${LEGACY_JOB_STATE_FILE}:`, error);
78
81
  }
79
82
  writeRaw(LEGACY_IMPORT_FLAG_KEY, JSON.stringify(true));
80
83
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sdk-runtime-state-db.js","sourceRoot":"","sources":["../../../src/utils/local-data-store/sdk-runtime-state-db.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sdk-runtime-state-db.js","sourceRoot":"","sources":["../../../src/utils/local-data-store/sdk-runtime-state-db.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@machinemetrics/mm-erp-sdk",
3
3
  "description": "A library for syncing data between MachineMetrics and ERP systems",
4
- "version": "0.9.6-beta.0",
4
+ "version": "0.9.6-beta.1",
5
5
  "license": "MIT",
6
6
  "author": "machinemetrics",
7
7
  "main": "dist/index.js",
@@ -0,0 +1,106 @@
1
+ import fs from "fs";
2
+ import os from "os";
3
+ import path from "path";
4
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
5
+ import {
6
+ getRuntimeStateJson,
7
+ resetRuntimeStateDbForTests,
8
+ } from "./sdk-runtime-state-db.js";
9
+
10
+ const LEGACY_JOB_STATE_FILE = path.join("/tmp", "job-state.json");
11
+
12
+ function mockLegacyFileExists(exists: boolean): void {
13
+ const realExistsSync = fs.existsSync.bind(fs);
14
+ vi.spyOn(fs, "existsSync").mockImplementation((filePath) => {
15
+ if (path.resolve(String(filePath)) === LEGACY_JOB_STATE_FILE) {
16
+ return exists;
17
+ }
18
+ return realExistsSync(filePath);
19
+ });
20
+ }
21
+
22
+ function mockLegacyFileContents(contents: string): void {
23
+ mockLegacyFileExists(true);
24
+ const realReadFileSync = fs.readFileSync.bind(fs);
25
+ vi.spyOn(fs, "readFileSync").mockImplementation((filePath, encoding) => {
26
+ if (path.resolve(String(filePath)) === LEGACY_JOB_STATE_FILE) {
27
+ return contents;
28
+ }
29
+ return realReadFileSync(filePath, encoding);
30
+ });
31
+ }
32
+
33
+ describe("sdk-runtime-state-db legacy import", () => {
34
+ let sqlitePath: string;
35
+
36
+ beforeEach(() => {
37
+ sqlitePath = path.join(
38
+ os.tmpdir(),
39
+ `sdk-runtime-state-${process.pid}-${Date.now()}.sqlite3`
40
+ );
41
+ process.env.SQLITE_DB_PATH = sqlitePath;
42
+ resetRuntimeStateDbForTests();
43
+ });
44
+
45
+ afterEach(() => {
46
+ resetRuntimeStateDbForTests();
47
+ delete process.env.SQLITE_DB_PATH;
48
+ for (const suffix of ["", "-wal", "-shm"]) {
49
+ try {
50
+ fs.rmSync(`${sqlitePath}${suffix}`);
51
+ } catch {
52
+ // ignore
53
+ }
54
+ }
55
+ vi.restoreAllMocks();
56
+ });
57
+
58
+ it("marks import complete when the legacy file is absent", () => {
59
+ mockLegacyFileExists(false);
60
+
61
+ getRuntimeStateJson("companyInfo");
62
+
63
+ expect(getRuntimeStateJson<boolean>("_legacyJobStateImported")).toBe(true);
64
+ expect(getRuntimeStateJson("companyInfo")).toBeNull();
65
+ });
66
+
67
+ it("imports legacy keys when the legacy file is valid", () => {
68
+ mockLegacyFileContents(
69
+ JSON.stringify({
70
+ companyInfo: { timezone: "US/Central" },
71
+ mmApiToken: { token: "abc", expiresAt: "2099-01-01T00:00:00.000Z" },
72
+ initialLoadComplete: true,
73
+ databaseLock: { holder: "worker-1" },
74
+ })
75
+ );
76
+
77
+ expect(getRuntimeStateJson<{ timezone: string }>("companyInfo")).toEqual({
78
+ timezone: "US/Central",
79
+ });
80
+ expect(getRuntimeStateJson<{ token: string }>("mmApiToken")).toEqual({
81
+ token: "abc",
82
+ expiresAt: "2099-01-01T00:00:00.000Z",
83
+ });
84
+ expect(getRuntimeStateJson<boolean>("initialLoadComplete")).toBe(true);
85
+ expect(getRuntimeStateJson<{ holder: string }>("databaseLock")).toEqual({
86
+ holder: "worker-1",
87
+ });
88
+ expect(getRuntimeStateJson<boolean>("_legacyJobStateImported")).toBe(true);
89
+ });
90
+
91
+ it("fails fast on corrupt legacy JSON and retries import on next access", () => {
92
+ mockLegacyFileContents("{ invalid json");
93
+
94
+ expect(() => getRuntimeStateJson("companyInfo")).toThrow(SyntaxError);
95
+
96
+ vi.restoreAllMocks();
97
+ mockLegacyFileContents(
98
+ JSON.stringify({ companyInfo: { timezone: "US/Eastern" } })
99
+ );
100
+
101
+ expect(getRuntimeStateJson<{ timezone: string }>("companyInfo")).toEqual({
102
+ timezone: "US/Eastern",
103
+ });
104
+ expect(getRuntimeStateJson<boolean>("_legacyJobStateImported")).toBe(true);
105
+ });
106
+ });
@@ -27,17 +27,24 @@ function getDb(): Database.Database {
27
27
  if (!db) {
28
28
  const filename = dbPath();
29
29
  ensureDbDirectory(filename);
30
- db = new Database(filename);
31
- db.pragma("journal_mode = WAL");
32
- db.pragma("busy_timeout = 5000");
33
- db.exec(`
30
+ const instance = new Database(filename);
31
+ instance.pragma("journal_mode = WAL");
32
+ instance.pragma("busy_timeout = 5000");
33
+ instance.exec(`
34
34
  CREATE TABLE IF NOT EXISTS ${TABLE} (
35
35
  key TEXT PRIMARY KEY,
36
36
  value TEXT NOT NULL,
37
37
  updated_at TEXT NOT NULL
38
38
  );
39
39
  `);
40
- importLegacyJobStateFileOnce();
40
+ db = instance;
41
+ try {
42
+ importLegacyJobStateFileOnce();
43
+ } catch (error) {
44
+ instance.close();
45
+ db = null;
46
+ throw error;
47
+ }
41
48
  }
42
49
  return db;
43
50
  }
@@ -64,35 +71,28 @@ function importLegacyJobStateFileOnce(): void {
64
71
  return;
65
72
  }
66
73
 
67
- try {
68
- if (fs.existsSync(LEGACY_JOB_STATE_FILE)) {
69
- const raw = fs.readFileSync(LEGACY_JOB_STATE_FILE, "utf-8");
70
- const data = JSON.parse(raw) as Record<string, unknown>;
74
+ if (fs.existsSync(LEGACY_JOB_STATE_FILE)) {
75
+ const raw = fs.readFileSync(LEGACY_JOB_STATE_FILE, "utf-8");
76
+ const data = JSON.parse(raw) as Record<string, unknown>;
71
77
 
72
- if (data.companyInfo && !readRaw("companyInfo")) {
73
- writeRaw("companyInfo", JSON.stringify(data.companyInfo));
74
- }
75
- if (data.mmApiToken && !readRaw("mmApiToken")) {
76
- writeRaw("mmApiToken", JSON.stringify(data.mmApiToken));
77
- }
78
- if (
79
- data.initialLoadComplete !== undefined &&
80
- !readRaw("initialLoadComplete")
81
- ) {
82
- writeRaw(
83
- "initialLoadComplete",
84
- JSON.stringify(data.initialLoadComplete)
85
- );
86
- }
87
- if (data.databaseLock && !readRaw("databaseLock")) {
88
- writeRaw("databaseLock", JSON.stringify(data.databaseLock));
89
- }
78
+ if (data.companyInfo && !readRaw("companyInfo")) {
79
+ writeRaw("companyInfo", JSON.stringify(data.companyInfo));
80
+ }
81
+ if (data.mmApiToken && !readRaw("mmApiToken")) {
82
+ writeRaw("mmApiToken", JSON.stringify(data.mmApiToken));
83
+ }
84
+ if (
85
+ data.initialLoadComplete !== undefined &&
86
+ !readRaw("initialLoadComplete")
87
+ ) {
88
+ writeRaw(
89
+ "initialLoadComplete",
90
+ JSON.stringify(data.initialLoadComplete)
91
+ );
92
+ }
93
+ if (data.databaseLock && !readRaw("databaseLock")) {
94
+ writeRaw("databaseLock", JSON.stringify(data.databaseLock));
90
95
  }
91
- } catch (error) {
92
- console.error(
93
- `Failed to import legacy job state from ${LEGACY_JOB_STATE_FILE}:`,
94
- error
95
- );
96
96
  }
97
97
 
98
98
  writeRaw(LEGACY_IMPORT_FLAG_KEY, JSON.stringify(true));