@laboverwire/stitch 0.6.5 → 0.7.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/CHANGELOG.md CHANGED
@@ -2,10 +2,15 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
- ### Added
6
-
7
5
  - _Nothing yet._
8
6
 
7
+ ## 0.7.0
8
+
9
+ ### Changed
10
+
11
+ - **Raised the minimum Node version to `>=22.22.1` (dropped Node 20).** `engines.node` moves from `>=20` to `>=22.22.1`; installing on Node 20 (EOL April 2026) or any Node below 22.22.1 now emits an `EBADENGINE` warning, a hard failure under `engine-strict` or pnpm. Two dev-toolchain upgrades drove the floor: vitest 5 (floor Node `^22.12.0 || ^24 || >=26`) and lint-staged 17 (floor Node `>=22.22.1`, the binding constraint); the pre-commit pipeline is unchanged (`prettier --write` then `oxlint --fix` on staged `src` files). CI now runs Node 22 and 24 instead of 20 and 22. No `@laboverwire/stitch` runtime or type surface changed.
12
+ - **Upgraded the build compiler to TypeScript 7 and replaced the ESLint toolchain with oxlint.** `typescript` moves from `^6.0.3` to `^7.0.2`, and `eslint`, `@eslint/js`, `typescript-eslint`, `eslint-plugin-react-hooks`, `eslint-config-prettier`, and `globals` are replaced by a single `oxlint` dev dependency (`eslint.config.js` → `.oxlintrc.json`). oxlint reproduces the prior lint coverage: its `correctness` rules plus the typescript-eslint `recommended` syntactic rules enforced as errors (`no-explicit-any`, `ban-ts-comment`, `no-namespace`, and the rest), and the `react-hooks` rules — `rules-of-hooks` (error) and `exhaustive-deps` (warn) — scoped to the React bindings under `src/react`. No type-aware rules were in use, so none are lost. The published `.d.ts` are unchanged from the previous TypeScript 6 build (verified by diffing both outputs), so there is no consumer-facing type or runtime change. Prettier remains the formatter. Trims 115 transitive dev dependencies.
13
+
9
14
  ## 0.6.5
10
15
 
11
16
  ### Added
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export { createStore } from "./store.js";
1
+ export { createStore } from './store.js';
2
2
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"internal-list-apply.js","sourceRoot":"","sources":["../src/internal-list-apply.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,UAAU,CACxB,IAAgB,EAChB,MAAe,EACf,EAAkC;IAElC,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,IAAI,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5E,MAAM,IAAI,GAAG,MAAkB,CAAC;IAChC,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC,CAAC;IACpD,QAAQ,EAAE,EAAE,CAAC;QACX,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,IAAI,GAAG,GAAG,CAAC;gBAAE,OAAO,CAAC,GAAG,IAAI,EAAE,IAAI,CAAC,CAAC;YACpC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YAC1B,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;YACjB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,IAAI,GAAG,GAAG,CAAC;gBAAE,OAAO,IAAI,CAAC;YACzB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YAC1B,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;YACjB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,IAAI,GAAG,GAAG,CAAC;gBAAE,OAAO,IAAI,CAAC;YACzB,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QACzD,CAAC;QACD;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC","sourcesContent":["export type ListItem = Record<string, unknown> & { id: string };\n\nexport function applyEvent(\n prev: ListItem[],\n entity: unknown,\n op: 'insert' | 'update' | 'delete'\n): ListItem[] {\n if (!entity || typeof entity !== 'object' || !('id' in entity)) return prev;\n const item = entity as ListItem;\n const idx = prev.findIndex((d) => d.id === item.id);\n switch (op) {\n case 'insert': {\n if (idx < 0) return [...prev, item];\n const next = prev.slice();\n next[idx] = item;\n return next;\n }\n case 'update': {\n if (idx < 0) return prev;\n const next = prev.slice();\n next[idx] = item;\n return next;\n }\n case 'delete': {\n if (idx < 0) return prev;\n return [...prev.slice(0, idx), ...prev.slice(idx + 1)];\n }\n default:\n return prev;\n }\n}\n"]}
1
+ {"version":3,"file":"internal-list-apply.js","sourceRoot":"","sources":["../src/internal-list-apply.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,UAAU,CACxB,IAAgB,EAChB,MAAe,EACf,EAAkC;IAElC,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,IAAI,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5E,MAAM,IAAI,GAAG,MAAkB,CAAC;IAChC,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC,CAAC;IACpD,QAAQ,EAAE,EAAE,CAAC;QACX,KAAK,QAAQ,EAAE,CAAC;YACd,IAAI,GAAG,GAAG,CAAC;gBAAE,OAAO,CAAC,GAAG,IAAI,EAAE,IAAI,CAAC,CAAC;YACpC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YAC1B,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;YACjB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,KAAK,QAAQ,EAAE,CAAC;YACd,IAAI,GAAG,GAAG,CAAC;gBAAE,OAAO,IAAI,CAAC;YACzB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YAC1B,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;YACjB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,KAAK,QAAQ,EAAE,CAAC;YACd,IAAI,GAAG,GAAG,CAAC;gBAAE,OAAO,IAAI,CAAC;YACzB,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QACzD,CAAC;QACD;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC","sourcesContent":["export type ListItem = Record<string, unknown> & { id: string };\n\nexport function applyEvent(\n prev: ListItem[],\n entity: unknown,\n op: 'insert' | 'update' | 'delete'\n): ListItem[] {\n if (!entity || typeof entity !== 'object' || !('id' in entity)) return prev;\n const item = entity as ListItem;\n const idx = prev.findIndex((d) => d.id === item.id);\n switch (op) {\n case 'insert': {\n if (idx < 0) return [...prev, item];\n const next = prev.slice();\n next[idx] = item;\n return next;\n }\n case 'update': {\n if (idx < 0) return prev;\n const next = prev.slice();\n next[idx] = item;\n return next;\n }\n case 'delete': {\n if (idx < 0) return prev;\n return [...prev.slice(0, idx), ...prev.slice(idx + 1)];\n }\n default:\n return prev;\n }\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { useEffect, useState, useCallback } from 'react';
2
- import { applyEvent } from "../../internal-list-apply.js";
2
+ import { applyEvent } from '../../internal-list-apply.js';
3
3
  export function useRootEntityList(store) {
4
4
  const rootEntity = store.config.scope.rootEntity;
5
5
  const [items, setItems] = useState([]);
@@ -1,5 +1,5 @@
1
1
  import { useEffect, useState, useCallback } from 'react';
2
- import { applyEvent } from "../../internal-list-apply.js";
2
+ import { applyEvent } from '../../internal-list-apply.js';
3
3
  export function useScopedEntities(store, scopeId, entity) {
4
4
  const effectiveScopeField = store.config.scope.scopeField;
5
5
  const [data, setData] = useState([]);
@@ -1,5 +1,5 @@
1
1
  import { useEffect, useState } from 'react';
2
- import { applyEvent } from "../../internal-list-apply.js";
2
+ import { applyEvent } from '../../internal-list-apply.js';
3
3
  export function useTopLevelEntities(store, entity) {
4
4
  const [items, setItems] = useState([]);
5
5
  const [loading, setLoading] = useState(true);
@@ -1,10 +1,10 @@
1
- export { StoreContext, useStore } from "./context.js";
2
- export { StoreProvider, AuthProvider } from "./provider.js";
3
- export { useEntitySnapshot, useEntitySnapshotAsMap } from "./hooks/useEntitySnapshot.js";
4
- export { useConnectionStatus } from "./hooks/useConnectionStatus.js";
5
- export { useScopedEntities } from "./hooks/useScopedEntities.js";
6
- export { useRootEntityList } from "./hooks/useRootEntityList.js";
7
- export { useTopLevelEntities } from "./hooks/useTopLevelEntities.js";
8
- export { useChildCounts } from "./hooks/useChildCounts.js";
9
- export { useSyncScope } from "./hooks/useSyncScope.js";
1
+ export { StoreContext, useStore } from './context.js';
2
+ export { StoreProvider, AuthProvider } from './provider.js';
3
+ export { useEntitySnapshot, useEntitySnapshotAsMap } from './hooks/useEntitySnapshot.js';
4
+ export { useConnectionStatus } from './hooks/useConnectionStatus.js';
5
+ export { useScopedEntities } from './hooks/useScopedEntities.js';
6
+ export { useRootEntityList } from './hooks/useRootEntityList.js';
7
+ export { useTopLevelEntities } from './hooks/useTopLevelEntities.js';
8
+ export { useChildCounts } from './hooks/useChildCounts.js';
9
+ export { useSyncScope } from './hooks/useSyncScope.js';
10
10
  //# sourceMappingURL=index.js.map
@@ -1,6 +1,6 @@
1
- import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useEffect, useState, useMemo } from 'react';
3
- import { StoreContext } from "./context.js";
3
+ import { StoreContext } from './context.js';
4
4
  /**
5
5
  * Store lifecycle only — initializes the store, tracks connection status, and
6
6
  * handles visibility-change reconnection. Authentication concerns (userId, session
@@ -1 +1 @@
1
- {"version":3,"file":"StitchAuth.d.ts","sourceRoot":"","sources":["../../src/vue/StitchAuth.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;GAIG;AACH,eAAO,MAAM,UAAU;;cAIM,QAAQ,CAAC,KAAK,CAAC;;;;;;;;;;;;cAGF,QAAQ,CAAC,MAAM,IAAI,CAAC;;;;cACjB,QAAQ,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;;;;;;;cAJ7C,QAAQ,CAAC,KAAK,CAAC;;;;;;;;;;;;cAGF,QAAQ,CAAC,MAAM,IAAI,CAAC;;;;cACjB,QAAQ,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;;;;;;4BADjB,IAAI;+BACD,OAAO,CAAC,IAAI,CAAC;4EA4BvE,CAAC"}
1
+ {"version":3,"file":"StitchAuth.d.ts","sourceRoot":"","sources":["../../src/vue/StitchAuth.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;GAIG;AACH,eAAO,MAAM,UAAU;;cAIM,QAAQ,CAAC,KAAK,CAAC;;;;QAC9B,IAAI;QAAU,OAAO;;;QACd,IAAI;QAAW,OAAO;;;QACnB,IAAI,EAAc,QAAQ,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO;;;QAC5C,IAAI,EAAc,QAAQ,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAD1B,IAAI;+BACD,OAAO,CAAC,IAAI,CAAC;4EA4BvE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"StoreRoot.d.ts","sourceRoot":"","sources":["../../src/vue/StoreRoot.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,KAAK,EAAoB,KAAK,EAAE,MAAM,aAAa,CAAC;AAG3D;;;;;GAKG;AACH,eAAO,MAAM,SAAS;;cAIO,QAAQ,CAAC,KAAK,CAAC;;;;;;;;cAET,QAAQ,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;;;;;;;cAFrC,QAAQ,CAAC,KAAK,CAAC;;;;;;;;cAET,QAAQ,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;;;;;qBAAhB,OAAO,CAAC,MAAM,CAAC;4EAkG/D,CAAC"}
1
+ {"version":3,"file":"StoreRoot.d.ts","sourceRoot":"","sources":["../../src/vue/StoreRoot.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,KAAK,EAAoB,KAAK,EAAE,MAAM,aAAa,CAAC;AAG3D;;;;;GAKG;AACH,eAAO,MAAM,SAAS;;cAIO,QAAQ,CAAC,KAAK,CAAC;;;;QAC3B,IAAI;QAAU,OAAO;;;QACrB,IAAI,EAAc,QAAQ,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;QAAE,OAAO;;;;;;;;;;;;;;;;;;;qBAAzB,OAAO,CAAC,MAAM,CAAC;4EAkG/D,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { defineComponent, provide, shallowRef, onMounted, onUnmounted, watch } from 'vue';
2
- import { STITCH_KEY } from "./injection-key.js";
2
+ import { STITCH_KEY } from './injection-key.js';
3
3
  /**
4
4
  * Store lifecycle component. Initializes the store, tracks connection status, and
5
5
  * handles visibility-change reconnection. Authentication concerns (userId, session
@@ -1,5 +1,5 @@
1
1
  import { shallowRef, watch, onBeforeUnmount } from 'vue';
2
- import { applyEvent } from "../../internal-list-apply.js";
2
+ import { applyEvent } from '../../internal-list-apply.js';
3
3
  export function useRootEntityList(store) {
4
4
  const rootEntity = store.config.scope.rootEntity;
5
5
  const items = shallowRef([]);
@@ -1,5 +1,5 @@
1
1
  import { shallowRef, watch, toValue, onBeforeUnmount } from 'vue';
2
- import { applyEvent } from "../../internal-list-apply.js";
2
+ import { applyEvent } from '../../internal-list-apply.js';
3
3
  export function useScopedEntities(store, scopeId, entity) {
4
4
  const effectiveScopeField = store.config.scope.scopeField;
5
5
  const data = shallowRef([]);
@@ -1,5 +1,5 @@
1
1
  import { inject } from 'vue';
2
- import { STITCH_KEY } from "../injection-key.js";
2
+ import { STITCH_KEY } from '../injection-key.js';
3
3
  export function useStore() {
4
4
  const ctx = inject(STITCH_KEY);
5
5
  if (!ctx)
@@ -1,5 +1,5 @@
1
1
  import { shallowRef, watch, onBeforeUnmount } from 'vue';
2
- import { applyEvent } from "../../internal-list-apply.js";
2
+ import { applyEvent } from '../../internal-list-apply.js';
3
3
  export function useTopLevelEntities(store, entity) {
4
4
  const items = shallowRef([]);
5
5
  const loading = shallowRef(true);
package/dist/vue/index.js CHANGED
@@ -1,12 +1,12 @@
1
- export { STITCH_KEY } from "./injection-key.js";
2
- export { StoreRoot } from "./StoreRoot.js";
3
- export { StitchAuth } from "./StitchAuth.js";
4
- export { useStore } from "./composables/useStore.js";
5
- export { useEntitySnapshot, useEntitySnapshotAsMap } from "./composables/useEntitySnapshot.js";
6
- export { useConnectionStatus } from "./composables/useConnectionStatus.js";
7
- export { useSyncScope } from "./composables/useSyncScope.js";
8
- export { useRootEntityList } from "./composables/useRootEntityList.js";
9
- export { useScopedEntities } from "./composables/useScopedEntities.js";
10
- export { useChildCounts } from "./composables/useChildCounts.js";
11
- export { useTopLevelEntities } from "./composables/useTopLevelEntities.js";
1
+ export { STITCH_KEY } from './injection-key.js';
2
+ export { StoreRoot } from './StoreRoot.js';
3
+ export { StitchAuth } from './StitchAuth.js';
4
+ export { useStore } from './composables/useStore.js';
5
+ export { useEntitySnapshot, useEntitySnapshotAsMap } from './composables/useEntitySnapshot.js';
6
+ export { useConnectionStatus } from './composables/useConnectionStatus.js';
7
+ export { useSyncScope } from './composables/useSyncScope.js';
8
+ export { useRootEntityList } from './composables/useRootEntityList.js';
9
+ export { useScopedEntities } from './composables/useScopedEntities.js';
10
+ export { useChildCounts } from './composables/useChildCounts.js';
11
+ export { useTopLevelEntities } from './composables/useTopLevelEntities.js';
12
12
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@laboverwire/stitch",
3
- "version": "0.6.5",
3
+ "version": "0.7.0",
4
4
  "description": "Reactive state synchronization library bridging an in-memory store, IndexedDB persistence, and MQTT-based remote sync.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "LabOverWire",
@@ -9,7 +9,7 @@
9
9
  "types": "./dist/index.d.ts",
10
10
  "sideEffects": false,
11
11
  "engines": {
12
- "node": ">=20"
12
+ "node": ">=22.22.1"
13
13
  },
14
14
  "repository": {
15
15
  "type": "git",
@@ -39,8 +39,8 @@
39
39
  ],
40
40
  "scripts": {
41
41
  "type-check": "tsc --noEmit",
42
- "lint": "eslint .",
43
- "lint:fix": "eslint --fix .",
42
+ "lint": "oxlint",
43
+ "lint:fix": "oxlint --fix",
44
44
  "format": "prettier --write 'src/**/*.{ts,tsx}'",
45
45
  "format:check": "prettier --check 'src/**/*.{ts,tsx}'",
46
46
  "test": "vitest run",
@@ -56,7 +56,7 @@
56
56
  "lint-staged": {
57
57
  "src/**/*.{ts,tsx}": [
58
58
  "prettier --write",
59
- "eslint --fix"
59
+ "oxlint --fix"
60
60
  ]
61
61
  },
62
62
  "exports": {
@@ -89,29 +89,25 @@
89
89
  }
90
90
  },
91
91
  "devDependencies": {
92
- "@eslint/js": "^10.0.1",
93
92
  "@testing-library/react": "^16.3.2",
94
93
  "@types/react": "^19.2.18",
95
- "@vitest/browser": "^4.1.11",
96
- "@vitest/browser-playwright": "^4.1.11",
97
- "@vitest/ui": "^4.1.11",
94
+ "@vitest/browser": "^5.0.5",
95
+ "@vitest/browser-playwright": "^5.0.5",
96
+ "@vitest/ui": "^5.0.5",
98
97
  "esbuild": "^0.28.1",
99
- "eslint": "^10.8.0",
100
- "eslint-config-prettier": "^10.1.8",
101
- "eslint-plugin-react-hooks": "^7.1.1",
102
- "globals": "^17.9.0",
103
98
  "husky": "^9.1.7",
104
- "lint-staged": "^16.4.0",
99
+ "lint-staged": "^17.6.0",
100
+ "oxlint": "^1.89.0",
105
101
  "playwright": "^1.62.1",
106
102
  "prettier": "^3.9.6",
107
103
  "react": "^19.2.8",
108
104
  "react-dom": "^19.2.8",
109
105
  "rollup": "^4.62.4",
110
- "typescript": "^6.0.3",
111
- "typescript-eslint": "^8.66.0",
106
+ "typescript": "^7.0.2",
107
+ "vite": "^8.3.5",
112
108
  "vite-plugin-top-level-await": "^1.6.0",
113
109
  "vite-plugin-wasm": "^3.6.0",
114
- "vitest": "^4.1.11",
110
+ "vitest": "^5.0.5",
115
111
  "vue": "^3.5.42"
116
112
  },
117
113
  "overrides": {