@_linked/cli 1.45.6 → 1.46.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
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.46.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#250](https://github.com/linked-fw/cli/pull/250) [`293c265`](https://github.com/linked-fw/cli/commit/293c265b166a99ca5ebf3ed6d5cc966cd35ca4e0) Thanks [@flyon](https://github.com/flyon)! - `linked create-app --template react-native` now scaffolds an app on `@_linked/react` 2 and the framework releases built on it: `@_linked/react` 2.0.1 (was 1.6.4), `@_linked/schema` 1.5.0 (was 1.4.0), `@_linked/core` 2.28.1 (was 2.26.0; React 2 needs `^2.27.0`), `@_linked/server` 2.24.8, `@_linked/server-utils` 1.12.3, `@_linked/fuseki` 3.4.2, `@_linked/s3` 1.6.2 and `@_linked/cli` 1.45.6. The pins stay exact. `npm ls @_linked/react --all` in a new app shows only 2.0.1; before, `@_linked/primitives` 1.8.0 (through `@_linked/schema`) installed a second copy, 2.0.1, next to the app's 1.6.4.
8
+
9
+ A new app also has one React again. `@_linked/server` 2.24.5 and later take `react` and `react-dom` as peers, and npm resolved the peers of hoisted packages to the newest React (19.3.0) at the root, nesting the app's 19.2.3 under `apps/mobile`, so `npm run check:react` failed and `@_linked/react` loaded a different React from the app. The root `package.json` now pins `react` 19.2.3, `services/api` pins `react` next to its `react-dom`, and `apps/mobile` pins `react-dom` 19.2.3 (without it, `npm install` failed with `ERESOLVE`: `react-dom@19.3.0` wants `react@^19.3.0`).
10
+
11
+ With React 2, mounted components refetch after a mutation and identical queries share one request. The template's `nativeDefaults` test gives its loading and error cases a subject each, because the error case otherwise joined the loading case's request, which never settles. Existing apps are not changed.
12
+
13
+ Minor rather than patch: the CLI's commands do not change, but a newly generated app runs on a new major of `@_linked/react`, with its reactive refetching.
14
+
3
15
  ## 1.45.6
4
16
 
5
17
  ### Patch Changes
@@ -60,9 +60,12 @@ cd apps/mobile && npx expo export --platform ios --output-dir /tmp/export
60
60
 
61
61
  ## React Native specifics
62
62
 
63
- - **One React.** `npm ls react` lists extra React copies nested under `@_linked/server` and
64
- `@_linked/server-utils`; the app never loads them, which `npm run check:react` verifies. Do not use
65
- `--legacy-peer-deps`: it would hide a duplicate React.
63
+ - **One React.** React is a peer of the `@_linked/*` packages, and npm resolves the peers of hoisted packages
64
+ at the repo root. Without a pin there, npm puts the newest React at the root and nests the app's 19.2.3
65
+ under `apps/mobile`, so `@_linked/react` and `react-native` would load a different React from the app.
66
+ The root `package.json` therefore pins `react` to the same version as `apps/mobile`, and every workspace
67
+ that depends on `@_linked/server` pins `react-dom` with it. `npm run check:react` verifies the result. Do
68
+ not use `--legacy-peer-deps`: it would hide a duplicate React.
66
69
  - **Workspaces are enumerated**, never globbed, so foreign repositories checked out under `packages/` are not
67
70
  adopted. `.gitignore` uses `packages/*` plus a negation per workspace package (`packages/` cannot be negated).
68
71
  - **Metro** (`apps/mobile/metro.config.js`) watches the workspace root and searches both `node_modules`
@@ -45,7 +45,7 @@ const flush = () => new Promise((resolve) => setTimeout(resolve, 0));
45
45
  describe('@_linked/react/native render defaults', () => {
46
46
  test('a loading component renders only React Native elements', async () => {
47
47
  mode = 'loading';
48
- await render(<ExampleLabel of={{ id: 'urn:example:1' }} />);
48
+ await render(<ExampleLabel of={{ id: 'urn:example:loading' }} />);
49
49
 
50
50
  expect(lowercaseHostTypes(screen.toJSON() as any)).toEqual([]);
51
51
  expect(screen.getByTestId('linked-loader')).toBeTruthy();
@@ -53,7 +53,9 @@ describe('@_linked/react/native render defaults', () => {
53
53
 
54
54
  test('a failed component renders only React Native elements', async () => {
55
55
  mode = 'error';
56
- await render(<ExampleLabel of={{ id: 'urn:example:1' }} />);
56
+ // A subject of its own: @_linked/react shares one request per query and subject, so reusing the loading
57
+ // test's subject would join its request, which never settles, and never reach the error state.
58
+ await render(<ExampleLabel of={{ id: 'urn:example:error' }} />);
57
59
  // Let the rejected query settle and the component re-render into its error state.
58
60
  await act(flush);
59
61
 
@@ -11,15 +11,16 @@
11
11
  "test:integration": "jest -c jest.integration.config.js --runInBand"
12
12
  },
13
13
  "dependencies": {
14
- "@_linked/core": "2.26.0",
15
- "@_linked/react": "1.6.4",
16
- "@_linked/schema": "1.4.0",
17
- "@_linked/server": "2.24.0",
14
+ "@_linked/core": "2.28.1",
15
+ "@_linked/react": "2.0.1",
16
+ "@_linked/schema": "1.5.0",
17
+ "@_linked/server": "2.24.8",
18
18
  "app-shapes": "*",
19
19
  "expo": "57.0.25",
20
20
  "expo-constants": "57.0.19",
21
21
  "expo-dev-client": "57.0.19",
22
22
  "react": "19.2.3",
23
+ "react-dom": "19.2.3",
23
24
  "react-native": "0.86.3"
24
25
  },
25
26
  "devDependencies": {
@@ -1,7 +1,8 @@
1
1
  // Example PersonOverview — demonstrates @_linked/react's data binding:
2
2
  // linkedSetComponent for the list (auto-runs the query, injects results and
3
3
  // an injected _refresh); linkedComponent for each row (see PersonPreview).
4
- // After Person.create the form calls _refresh() to re-run the list query.
4
+ // The list refetches by itself after Person.create; the form also calls the
5
+ // list's _refresh() through context, to show how to re-run a query by hand.
5
6
  // A React Native port of the web app-template's example (linked-fw/app-template).
6
7
  //
7
8
  // `linkedSetComponent` checks LinkedStorage when this module loads, so storage is imported first.
@@ -1,8 +1,10 @@
1
1
  // Example PersonPreview — single-Person row. Demonstrates @_linked/react's
2
2
  // linkedComponent: the wrapper runs the per-row query and injects query
3
- // result keys + `source` + `_refresh` into the render function. _refresh
4
- // patches local query state for optimistic UI; on delete, the parent
5
- // list re-runs via the PersonListRefresh context.
3
+ // result keys + `source` + `_refresh` into the render function. After a
4
+ // mutation, every mounted component whose query can read the changed data
5
+ // refetches by itself; _refresh patches the shared cached result first, for
6
+ // optimistic UI, and on delete the PersonListRefresh context re-runs the list
7
+ // explicitly.
6
8
  // A React Native port of the web app-template's example (linked-fw/app-template).
7
9
  // Storage is imported first, so the row's queries go to the API store however this module is reached.
8
10
  import '../shell/storage';
@@ -16,9 +16,12 @@
16
16
  "test": "npm test -w apps/mobile && npm test -w services/api",
17
17
  "test:integration": "npm run test:integration -w apps/mobile"
18
18
  },
19
+ "dependencies": {
20
+ "react": "19.2.3"
21
+ },
19
22
  "devDependencies": {
20
23
  "eslint": "9.39.5",
21
24
  "eslint-config-expo": "57.0.2",
22
- "typescript-eslint": "8.70.1"
25
+ "typescript-eslint": "8.71.0"
23
26
  }
24
27
  }
@@ -16,9 +16,9 @@
16
16
  "build": "linked build"
17
17
  },
18
18
  "dependencies": {
19
- "@_linked/core": "2.26.0"
19
+ "@_linked/core": "2.28.1"
20
20
  },
21
21
  "devDependencies": {
22
- "@_linked/cli": "1.40.0"
22
+ "@_linked/cli": "1.45.6"
23
23
  }
24
24
  }
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  // One React for the app: `react` resolved from apps/mobile, from the installed @_linked/react and from react-native
3
- // must be the same file. `npm ls react` is not used because @_linked/server and @_linked/server-utils nest their
4
- // own copies, which the app never loads.
3
+ // must be the same file. It checks resolution rather than `npm ls react`, because what matters is the file each
4
+ // of them loads: a second copy nested under apps/mobile (see the README) passes `npm ls` and still splits React.
5
5
  import { existsSync, readFileSync, realpathSync } from 'node:fs';
6
6
  import { createRequire } from 'node:module';
7
7
  import { dirname, join, resolve } from 'node:path';
@@ -39,9 +39,9 @@ that port is the one Docker Compose publishes for this repo's `fuseki` service.
39
39
 
40
40
  ## Dependencies
41
41
 
42
- `react-dom` is a direct dependency although the API renders no pages: `LinkedServer` imports `react-dom/server`
43
- at load time, and the root React is 19.2.3 (for `apps/mobile`), so `@_linked/server`'s own `react-dom` 18 is
44
- nested where Vite SSR cannot resolve it. Pinning `react-dom` 19.2.3 here hoists it next to the root React.
42
+ `react` and `react-dom` are direct dependencies although the API renders no pages: `LinkedServer` imports
43
+ `react-dom/server` at load time, and `@_linked/server` takes both as peers. They are pinned to the React that
44
+ `apps/mobile` uses (19.2.3), so npm installs one copy of each at the root instead of the newest release.
45
45
 
46
46
  `linked start` finds the hoisted `app-shapes` workspace and runs in workspace mode: Vite loads `app-shapes` from
47
47
  `src` through its `development` export condition, while published packages such as `@_linked/core` and
@@ -14,18 +14,19 @@
14
14
  "test": "node --experimental-strip-types --no-warnings=ExperimentalWarning --test test/*.test.mjs"
15
15
  },
16
16
  "dependencies": {
17
- "@_linked/core": "2.26.0",
18
- "@_linked/fuseki": "3.4.0",
19
- "@_linked/s3": "1.6.0",
20
- "@_linked/schema": "1.4.0",
21
- "@_linked/server": "2.24.0",
22
- "@_linked/server-utils": "1.12.0",
17
+ "@_linked/core": "2.28.1",
18
+ "@_linked/fuseki": "3.4.2",
19
+ "@_linked/s3": "1.6.2",
20
+ "@_linked/schema": "1.5.0",
21
+ "@_linked/server": "2.24.8",
22
+ "@_linked/server-utils": "1.12.3",
23
23
  "app-shapes": "*",
24
+ "react": "19.2.3",
24
25
  "react-dom": "19.2.3"
25
26
  },
26
27
  "devDependencies": {
27
- "@_linked/cli": "1.40.0",
28
- "@types/node": "22.20.4",
28
+ "@_linked/cli": "1.45.6",
29
+ "@types/node": "22.20.5",
29
30
  "typescript": "6.0.3"
30
31
  }
31
32
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@_linked/cli",
3
- "version": "1.45.6",
3
+ "version": "1.46.0",
4
4
  "packageManager": "npm@12.2.0",
5
5
  "description": "Command line tools for the @_linked/* packages and apps",
6
6
  "main": "lib/esm/index.js",
@@ -90,7 +90,7 @@
90
90
  "minimatch": "^9.0.4",
91
91
  "ora": "^8.0.1",
92
92
  "require-extensions": "^0.0.4",
93
- "rimraf": "^5.0.7",
93
+ "rimraf": "^6.0.0",
94
94
  "semver": "^7.8.5",
95
95
  "staged-git-files": "^1.3.0",
96
96
  "tailwindcss": "^4.1.4",