@_linked/cli 1.3.3 → 1.4.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/.github/workflows/ci.yml +10 -2
- package/CHANGELOG.md +36 -0
- package/README.md +20 -1
- package/defaults/app-with-backend/.env-cmdrc.json +3 -1
- package/defaults/app-with-backend/gitignore.template +1 -0
- package/defaults/app-with-backend/linked.backend.datasets.example.json +17 -0
- package/defaults/app-with-backend/linked.backend.storage.ts +35 -0
- package/defaults/app-with-backend/package.json +13 -29
- package/defaults/app-with-backend/readme.md +80 -6
- package/jest.config.cjs +29 -0
- package/lib/cjs/cli-methods.d.ts.map +1 -1
- package/lib/cjs/cli-methods.js +65 -29
- package/lib/cjs/cli-methods.js.map +1 -1
- package/lib/cjs/cli.js +9 -9
- package/lib/cjs/cli.js.map +1 -1
- package/lib/cjs/config-webpack-app.d.ts.map +1 -1
- package/lib/cjs/config-webpack-app.js +40 -20
- package/lib/cjs/config-webpack-app.js.map +1 -1
- package/lib/cjs/defineConfig.d.ts.map +1 -1
- package/lib/cjs/defineConfig.js +1 -1
- package/lib/cjs/defineConfig.js.map +1 -1
- package/lib/cjs/index.d.ts.map +1 -1
- package/lib/cjs/interfaces.d.ts.map +1 -1
- package/lib/cjs/package.json +15 -7
- package/lib/cjs/utils.js +1 -1
- package/lib/cjs/utils.js.map +1 -1
- package/lib/esm/cli-methods.d.ts.map +1 -1
- package/lib/esm/cli-methods.js +67 -29
- package/lib/esm/cli-methods.js.map +1 -1
- package/lib/esm/cli.js +9 -9
- package/lib/esm/cli.js.map +1 -1
- package/lib/esm/config-webpack-app.d.ts.map +1 -1
- package/lib/esm/config-webpack-app.js +38 -18
- package/lib/esm/config-webpack-app.js.map +1 -1
- package/lib/esm/defineConfig.d.ts.map +1 -1
- package/lib/esm/defineConfig.js +1 -1
- package/lib/esm/defineConfig.js.map +1 -1
- package/lib/esm/index.d.ts.map +1 -1
- package/lib/esm/interfaces.d.ts.map +1 -1
- package/lib/esm/launch.d.ts.map +1 -0
- package/lib/esm/launch.js +17 -0
- package/lib/esm/launch.js.map +1 -0
- package/lib/esm/package.json +15 -7
- package/lib/esm/utils.js +1 -1
- package/lib/esm/utils.js.map +1 -1
- package/package.json +15 -8
- package/tsconfig-cjs.json +2 -1
- package/defaults/app-with-backend/.husky/post-merge +0 -4
- package/defaults/app-with-backend/.husky/pre-commit +0 -4
- package/defaults/app-with-backend/mrgit-template.json +0 -3
- package/defaults/app-with-backend/scripts/storage-config.js +0 -12
- package/preflight.css +0 -137
- /package/defaults/app-with-backend/{lincd.config.js → linked.config.js} +0 -0
package/.github/workflows/ci.yml
CHANGED
|
@@ -38,6 +38,14 @@ jobs:
|
|
|
38
38
|
if: steps.rpr.outputs.is_release_pr == 'false'
|
|
39
39
|
run: npm run build
|
|
40
40
|
|
|
41
|
-
- name: Test
|
|
41
|
+
- name: Test (unit)
|
|
42
42
|
if: steps.rpr.outputs.is_release_pr == 'false'
|
|
43
|
-
run: npm test --if-present
|
|
43
|
+
run: npm run test:unit --if-present
|
|
44
|
+
|
|
45
|
+
# e2e scaffolds a fresh app, installs deps from npm, starts a Fuseki
|
|
46
|
+
# testcontainer, and drives a browser flow. Requires Docker on the
|
|
47
|
+
# runner. Skipped until @_linked/* companion packages publish with
|
|
48
|
+
# matching versions; set RUN_E2E=1 to opt in once they do.
|
|
49
|
+
- name: Test (e2e)
|
|
50
|
+
if: steps.rpr.outputs.is_release_pr == 'false' && env.RUN_E2E == '1'
|
|
51
|
+
run: npm run test:e2e --if-present
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#23](https://github.com/linked-cm/cli/pull/23) [`a00168d`](https://github.com/linked-cm/cli/commit/a00168d0e55a3f7f8164df1ea90e8fe52aefd5d4) Thanks [@flyon](https://github.com/flyon)! - Rename `LincdConfig` / `LincdWebpackConfig` / `LincdServerConfig` → `LinkedConfig` / `LinkedWebpackConfig` / `LinkedServerConfig`. Function `getLincdConfig` → `getLinkedConfig`. Legacy package.json flags `lincd: true` and `lincdApp: true` are no longer read — migrate to `linkedPackage: true` / `linkedApp: true`. Built loader registration is unaffected.
|
|
8
|
+
|
|
9
|
+
Plus: CLI command help text refresh (`LINCD app` → `Linked app`, etc.). Config file name `lincd.config.{js,json}` → `linked.config.{js,json}` (hard cut, no fallback) — was previously rolled out separately.
|
|
10
|
+
|
|
11
|
+
- [#23](https://github.com/linked-cm/cli/pull/23) [`a00168d`](https://github.com/linked-cm/cli/commit/a00168d0e55a3f7f8164df1ea90e8fe52aefd5d4) Thanks [@flyon](https://github.com/flyon)! - Starter template: CN-branded CSS theme + `@_linked/react` integration in the example components.
|
|
12
|
+
|
|
13
|
+
**Brand defaults.** The `app-with-backend` template now ships with the CN palette (`--color-primary-*` mapped to a teal-blue ramp, `--color-secondary-*` to mint green) as a default-branded baseline. Apps override `@theme { --color-primary-500: ... }` to swap brand.
|
|
14
|
+
|
|
15
|
+
**Semantic-token shell.** `App.module.css`, `DefaultLayout.module.css`, `Header.module.css` rewritten using `@_linked/css` semantic tokens (`--bg-page`, `--bg-card`, `--color-primary-*`) instead of hardcoded hex. Module CSS files using `--spacing(N)` import `@_linked/css/package.css` per the documented pattern.
|
|
16
|
+
|
|
17
|
+
**Person CRUD demo uses `@_linked/react`.** `PersonOverview` is now built with `linkedSetComponent`, and `PersonPreview` with `linkedComponent` — replacing the previous `useEffect` + `useState` query patterns. The wrappers handle loading state via the framework's `.ld-loader` and inject `_refresh` so the form (sibling) and rows (children) can trigger re-fetch. Optimistic UI on inline edit via `_refresh({givenName, familyName})`.
|
|
18
|
+
|
|
19
|
+
**Pages polish.** `Home`, `Signin`, `Page1`, `PageNotFound` get card layouts using semantic tokens — consistent across routes.
|
|
20
|
+
|
|
21
|
+
**`@_linked/react` is now a direct dep** in the scaffolded app's `package.json` so the bindings can be imported. Companion changes ship in `@_linked/react` (loader / errorElement API, `_refresh` on set, factory overloads) and `@_linked/css` (`.ld-loader` / `.ld-error` defaults + `--color-error-*` ramp).
|
|
22
|
+
|
|
23
|
+
**Storage layout.** Template now ships `linked.backend.storage.ts` + `linked.backend.datasets.json` and a mirror `src/linked.frontend.storage.ts` + `src/linked.frontend.datasets.json`. Backend uses `loadStores` (async, dynamic-import). Frontend hardcodes the per-alias store mapping for webpack-friendly bundling.
|
|
24
|
+
|
|
25
|
+
**npm + yarn compatibility.** `create-app` works with either package manager. Lockfile-based detection determines which to invoke for install.
|
|
26
|
+
|
|
27
|
+
No breaking changes. Existing scaffolded apps that don't pull in the template updates keep working.
|
|
28
|
+
|
|
29
|
+
### Patch Changes
|
|
30
|
+
|
|
31
|
+
- [`67f01ab`](https://github.com/linked-cm/cli/commit/67f01abcbed04625175a5c82e584f09fee41cdea) - Remove `preflight.css` — moved to `@_linked/css`.
|
|
32
|
+
|
|
33
|
+
`preflight.css` is a CSS asset; it belongs in the CSS package alongside `theme-defaults.css` and `utilities.css`. Consumers should update imports from `@_linked/cli/preflight.css` to `@_linked/css/preflight.css`.
|
|
34
|
+
|
|
35
|
+
The exports entry `"./preflight.css": "./preflight.css"` is also removed from `package.json`.
|
|
36
|
+
|
|
37
|
+
- [`2b40588`](https://github.com/linked-cm/cli/commit/2b405880cbb21992c5005cb048f910df79c32145) - Relax `typescript` dep from `^5.7.3` to `^5.4.0` so consumers that pin a lower 5.x version (e.g. CN at 5.4.5) don't end up with a nested `typescript@5.9.x` install in `packages/cli/node_modules/`. The nested 5.9.x was incompatible with `react-refresh-typescript@2.0.12`'s AST walk — crashed frontend builds with `TypeError: Cannot read properties of undefined (reading 'declarations')` inside `VariableStatement.declarationList.declarations` traversal.
|
|
38
|
+
|
|
3
39
|
## 1.3.3
|
|
4
40
|
|
|
5
41
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -86,7 +86,7 @@ The CLI recognizes two flags in `package.json`:
|
|
|
86
86
|
}
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
-
The legacy `lincd: true`
|
|
89
|
+
The legacy `lincd: true` / `lincdApp: true` flags are no longer read. Migrate to `linkedPackage` / `linkedApp`.
|
|
90
90
|
|
|
91
91
|
## Development
|
|
92
92
|
|
|
@@ -106,6 +106,25 @@ Templates live in `defaults/`:
|
|
|
106
106
|
- `defaults/package/` — used by `linked create-package`
|
|
107
107
|
- `defaults/setup-publish/` — workflow + changeset files written by `linked setup-publish` (single-branch default; `dual-branch/` subdirectory for the `--dual-branch` variant)
|
|
108
108
|
|
|
109
|
+
### `linked create-app` template structure
|
|
110
|
+
|
|
111
|
+
`linked create-app <name>` copies `defaults/app-with-backend/` to the new app's folder, substitutes `${name}` / `${hyphen_name}` / `${app_prefix}` / `${app_domain}` placeholders in selected files, and copies `linked.backend.datasets.example.json` → `linked.backend.datasets.json` so first boot works zero-config.
|
|
112
|
+
|
|
113
|
+
Storage configuration follows the two-layer pattern from [backlog 016](https://github.com/create-now/docs/blob/main/docs/backlog/016-ejection-export-flow.md) (canonical spec) + the symmetric backend/frontend split:
|
|
114
|
+
|
|
115
|
+
| File | Side | Role | Git |
|
|
116
|
+
|---|---|---|---|
|
|
117
|
+
| `linked.backend.storage.ts` | backend | Shape→alias routing. Uses `parseDatasetsConfig` + `loadStores` from `@_linked/core`; calls `LinkedStorage.setDefaultDataset(...)` / `setDatasetForShapes(...)`. | committed |
|
|
118
|
+
| `linked.backend.datasets.json` | backend | Alias → `{ store, config }`. `store` is an npm import path; `config` is the store class's constructor arg. `${VAR:-default}` placeholders resolved at boot. | **gitignored** |
|
|
119
|
+
| `linked.backend.datasets.example.json` | backend | Template / seed for the gitignored file. Has placeholders matching env vars. | committed |
|
|
120
|
+
| `src/linked.frontend.storage.ts` | frontend | Same shape→alias model; imports store classes explicitly (webpack-bundle-safe), constructs per alias. | committed |
|
|
121
|
+
| `src/linked.frontend.datasets.json` | frontend | Frontend alias → `{ store, config }`. Public values only — never put secrets here, it ships in the browser bundle. | committed |
|
|
122
|
+
|
|
123
|
+
Conventions:
|
|
124
|
+
- Aliases on the two sides are **independent**. The framework re-routes by shape on each side; matching alias names between FE and BE is convention, not a framework requirement.
|
|
125
|
+
- The backend dispatcher is registry-free (dynamic `await import(entry.store)`). The frontend hardcodes each `new StoreClass(config)` because webpack can't bundle dynamic imports of arbitrary npm specifiers.
|
|
126
|
+
- Each store class accepts a single config-object constructor argument — `new FusekiStore({ endpoint, credentials? })`, `new BackendAPIStore({ name?, id? })`.
|
|
127
|
+
|
|
109
128
|
## Repository
|
|
110
129
|
|
|
111
130
|
`linked-cm/cli` on GitHub. License: MPL-2.0.
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
"DATA_ROOT": "https://${app_domain}/data",
|
|
4
4
|
"APP_PREFIX": "${app_prefix}",
|
|
5
5
|
"APP_NAME": "${app_name}",
|
|
6
|
-
"SOURCE_PATH": "./src"
|
|
6
|
+
"SOURCE_PATH": "./src",
|
|
7
|
+
"FUSEKI_USER": "admin",
|
|
8
|
+
"FUSEKI_PASSWORD": "admin"
|
|
7
9
|
},
|
|
8
10
|
"development": {
|
|
9
11
|
"NODE_ENV": "development",
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_note": "Backend datasets config. Copy this file to linked.backend.datasets.json (gitignored) and replace placeholders with literal values, OR set the env vars referenced via ${VAR}. The ${VAR:-default} form falls back to the literal after :- when the env var is unset. Each entry has two keys: `store` (an npm import path string identifying the IDataset class) and `config` (a single JSON object passed verbatim to `new StoreClass(config)` — its fields are whatever that class's constructor expects).",
|
|
3
|
+
|
|
4
|
+
"datasets": {
|
|
5
|
+
"appData": {
|
|
6
|
+
"store": "@_linked/fuseki/shapes/FusekiStore",
|
|
7
|
+
"config": {
|
|
8
|
+
"endpoint": "${FUSEKI_BASE_URL:-http://localhost:3030}/${FUSEKI_DATASET:-${hyphen_name}-main}",
|
|
9
|
+
"credentials": {
|
|
10
|
+
"type": "basic",
|
|
11
|
+
"username": "${FUSEKI_USER:-admin}",
|
|
12
|
+
"password": "${FUSEKI_PASSWORD:-admin}"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Backend storage for ${name}.
|
|
2
|
+
//
|
|
3
|
+
// Reads linked.backend.datasets.json, dynamically imports each alias's
|
|
4
|
+
// store class via its npm path, and instantiates with the entry's `config`
|
|
5
|
+
// verbatim. See the mirror at src/linked.frontend.storage.ts.
|
|
6
|
+
import datasetsConfig from './linked.backend.datasets.json' assert { type: 'json' };
|
|
7
|
+
import { parseDatasetsConfig } from '@_linked/core/utils/parseDatasetsConfig';
|
|
8
|
+
import { loadStores } from '@_linked/core/utils/loadStores';
|
|
9
|
+
import { LinkedStorage } from '@_linked/core/utils/LinkedStorage';
|
|
10
|
+
import { LinkedFileStorage } from '@_linked/core/utils/LinkedFileStorage';
|
|
11
|
+
import type { FusekiStore } from '@_linked/fuseki/shapes/FusekiStore';
|
|
12
|
+
import { LocalFileStore } from '@_linked/server/shapes/filestores/LocalFileStore';
|
|
13
|
+
|
|
14
|
+
// Resolve ${VAR} placeholders against the runtime environment, then
|
|
15
|
+
// instantiate each store class declared in the JSON.
|
|
16
|
+
const config = parseDatasetsConfig(datasetsConfig, process.env);
|
|
17
|
+
const stores = await loadStores(config);
|
|
18
|
+
|
|
19
|
+
// Auto-create the dataset on first boot.
|
|
20
|
+
const appData = stores.appData as FusekiStore;
|
|
21
|
+
appData.ensureDatasetExists().catch((err) =>
|
|
22
|
+
console.warn('dataset ensure failed:', err),
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
// Shape → alias. Single alias → default for every shape. For multi-alias
|
|
26
|
+
// add per-shape pins, e.g.:
|
|
27
|
+
// import { Person } from '@_linked/schema/shapes/Person';
|
|
28
|
+
// LinkedStorage.setDatasetForShapes(stores.appData, [Person]);
|
|
29
|
+
LinkedStorage.setDefaultDataset(appData);
|
|
30
|
+
|
|
31
|
+
// File storage (binary assets). Separate from RDF dataset routing.
|
|
32
|
+
const fileStore = new LocalFileStore(
|
|
33
|
+
(process.env.NODE_ENV || 'development') + '-files',
|
|
34
|
+
);
|
|
35
|
+
LinkedFileStorage.setDefaultDataset(fileStore);
|
|
@@ -12,35 +12,20 @@
|
|
|
12
12
|
"email": ""
|
|
13
13
|
},
|
|
14
14
|
"engines": {
|
|
15
|
-
"node": ">=
|
|
15
|
+
"node": ">=20.6.0"
|
|
16
16
|
},
|
|
17
17
|
"main": "scripts/start-server.js",
|
|
18
18
|
"license": "MIT",
|
|
19
19
|
"scripts": {
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"prepare": "husky",
|
|
24
|
-
"prepack": "pinst --disable",
|
|
25
|
-
"postpack": "pinst --enable",
|
|
26
|
-
"server:prod": "yarn linked start --env production",
|
|
20
|
+
"start": "linked start --env development",
|
|
21
|
+
"build": "linked build-app --env production",
|
|
22
|
+
"server:prod": "linked start --env production",
|
|
27
23
|
"lint": "eslint \"src/**/*.{js,jsx,ts,tsx}\"",
|
|
28
|
-
"lint:fix": "
|
|
24
|
+
"lint:fix": "npm run lint -- --fix",
|
|
29
25
|
"prettier": "prettier \"src/**/*.{js,jsx,ts,tsx,css,scss}\" --check",
|
|
30
|
-
"prettier:fix": "
|
|
31
|
-
"format": "
|
|
26
|
+
"prettier:fix": "npm run prettier -- --write",
|
|
27
|
+
"format": "npm run prettier:fix && npm run lint:fix"
|
|
32
28
|
},
|
|
33
|
-
"lint-staged": {
|
|
34
|
-
"*.{js,ts,tsx}": [
|
|
35
|
-
"prettier --write"
|
|
36
|
-
],
|
|
37
|
-
"*.{scss,css,json}": [
|
|
38
|
-
"prettier --write"
|
|
39
|
-
]
|
|
40
|
-
},
|
|
41
|
-
"workspaces": [
|
|
42
|
-
"packages/*"
|
|
43
|
-
],
|
|
44
29
|
"keywords": [
|
|
45
30
|
"linked",
|
|
46
31
|
"linked code",
|
|
@@ -51,16 +36,20 @@
|
|
|
51
36
|
"web3"
|
|
52
37
|
],
|
|
53
38
|
"dependencies": {
|
|
54
|
-
"@_linked/core": "^2.
|
|
39
|
+
"@_linked/core": "^2.2",
|
|
55
40
|
"@_linked/auth": "~1.0",
|
|
56
41
|
"@_linked/server": "~1.0",
|
|
57
42
|
"@_linked/server-utils": "~1.0",
|
|
43
|
+
"@_linked/schema": "^1.0",
|
|
44
|
+
"@_linked/fuseki": "^1.0",
|
|
45
|
+
"@_linked/react": "^1.2",
|
|
58
46
|
"react": "^18.2",
|
|
59
47
|
"react-dom": "^18.2",
|
|
60
48
|
"react-error-boundary": "^3.1.3",
|
|
61
49
|
"react-router-dom": "^6.3.0"
|
|
62
50
|
},
|
|
63
51
|
"devDependencies": {
|
|
52
|
+
"@_linked/cli": "^1.3",
|
|
64
53
|
"@types/node": "^20.12.7",
|
|
65
54
|
"@types/react": "^18.0.17",
|
|
66
55
|
"@types/react-dom": "^18.0.6",
|
|
@@ -73,14 +62,9 @@
|
|
|
73
62
|
"eslint-plugin-prettier": "^5.0.0",
|
|
74
63
|
"eslint-plugin-react": "latest",
|
|
75
64
|
"eslint-plugin-react-hooks": "^4.6.0",
|
|
76
|
-
"husky": "^8.0.0",
|
|
77
|
-
"@_linked/cli": "^1.2",
|
|
78
|
-
"mrgit": "latest",
|
|
79
65
|
"nodemon": "^2.0.22",
|
|
80
|
-
"pinst": "^3.0.0",
|
|
81
66
|
"pm2": "^5.3.0",
|
|
82
67
|
"typescript-plugin-css-modules": "^5.1.0",
|
|
83
68
|
"which": "^3.0.1"
|
|
84
|
-
}
|
|
85
|
-
"packageManager": "yarn@3.6.1"
|
|
69
|
+
}
|
|
86
70
|
}
|
|
@@ -1,19 +1,93 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ${name}
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A standalone [Linked](https://linked.cm) app generated with `@_linked/cli`. Requires **Node ≥ 20.6**.
|
|
4
|
+
|
|
5
|
+
## What is Linked
|
|
6
|
+
|
|
7
|
+
Linked is a TypeScript framework for building apps on top of a graph database (RDF / SPARQL). You write your domain as **shape classes**, query them with a **typed DSL**, and render with **linked React components** that subscribe to the query results.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
// 1. A shape — domain class + SHACL metadata, generated from TypeScript decorators
|
|
11
|
+
@linkedShape
|
|
12
|
+
export class Person extends Shape {
|
|
13
|
+
static targetClass = schema.Person;
|
|
14
|
+
|
|
15
|
+
@literalProperty({ path: schema.givenName }) givenName: string;
|
|
16
|
+
@literalProperty({ path: schema.familyName }) familyName: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// 2. A query — TypeScript-embedded, type-inferred, executed against any IDataset
|
|
20
|
+
const people = await Person.select((p) => [p.givenName, p.familyName]);
|
|
21
|
+
|
|
22
|
+
// 3. A linked component — re-renders when its query result changes
|
|
23
|
+
const PersonCard = linkedComponent(
|
|
24
|
+
Person.select((p) => [p.givenName, p.familyName]),
|
|
25
|
+
({ givenName, familyName }) => <span>{givenName} {familyName}</span>,
|
|
26
|
+
);
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The home page in this app demonstrates the full chain end-to-end with `@_linked/schema`'s shipped `Person` shape.
|
|
30
|
+
|
|
31
|
+
- **[@_linked/core](https://github.com/linked-cm/core)** — query DSL, Shape classes, storage routing.
|
|
32
|
+
- **[@_linked/react](https://github.com/Semantu/linked-react)** — `linkedComponent`, `linkedSetComponent`.
|
|
33
|
+
|
|
34
|
+
## Install + run
|
|
35
|
+
|
|
36
|
+
With npm:
|
|
4
37
|
|
|
5
38
|
```bash
|
|
6
|
-
|
|
39
|
+
npm install
|
|
40
|
+
npm start
|
|
7
41
|
```
|
|
8
42
|
|
|
9
|
-
|
|
43
|
+
Or with yarn:
|
|
10
44
|
|
|
11
45
|
```bash
|
|
12
46
|
yarn install
|
|
47
|
+
yarn start
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The home page demonstrates the `@_linked` query DSL with a small Person CRUD — see `src/components/PersonOverview.tsx` and `src/components/PersonPreview.tsx`.
|
|
51
|
+
|
|
52
|
+
> If you scaffolded this app **inside an existing Yarn-workspace monorepo** (e.g. `create_now/packages/`), use `yarn install` — `npm install` walks up to the workspace root and may hit peer-dep conflicts there. Outside a workspace, either tool works.
|
|
53
|
+
|
|
54
|
+
## Storage
|
|
55
|
+
|
|
56
|
+
This app talks to an Apache Jena Fuseki SPARQL endpoint. Start a local Fuseki container:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
docker run -d --rm -p 3030:3030 --name fuseki stain/jena-fuseki
|
|
13
60
|
```
|
|
14
61
|
|
|
15
|
-
|
|
62
|
+
The app auto-creates its dataset on first boot.
|
|
63
|
+
|
|
64
|
+
**Storage config lives in three files**, per the spec in [`@_linked/cli` docs](https://www.npmjs.com/package/@_linked/cli):
|
|
65
|
+
|
|
66
|
+
| File | Purpose |
|
|
67
|
+
|---|---|
|
|
68
|
+
| `linked.backend.datasets.json` | Backend Layer 2 — alias → store class + config. Gitignored. Copy of `linked.backend.datasets.example.json`. |
|
|
69
|
+
| `linked.backend.storage.ts` | Backend Layer 1 — shape → alias routing. Parses the JSON, instantiates stores via `loadStores`, calls `LinkedStorage.setDefaultDataset(...)` / `setDatasetForShapes(...)`. |
|
|
70
|
+
| `src/linked.frontend.{storage.ts,datasets.json}` | Frontend mirror — same JSON shape, public values only; storage TS imports store classes explicitly and constructs one per alias. |
|
|
71
|
+
|
|
72
|
+
Defaults shipped:
|
|
73
|
+
|
|
74
|
+
- `FUSEKI_BASE_URL` — `http://localhost:3030`
|
|
75
|
+
- `FUSEKI_DATASET` — `${hyphen_name}-main`
|
|
76
|
+
- `FUSEKI_USER` / `FUSEKI_PASSWORD` — `admin` / `admin` (matches the `stain/jena-fuseki` Docker image default)
|
|
77
|
+
- `FUSEKI_DB_TYPE` — `tdb2` (persistent). Set to `mem` for in-memory.
|
|
78
|
+
|
|
79
|
+
All of these are referenced as `${VAR:-default}` placeholders in `linked.backend.datasets.json`, so you can either edit the JSON directly or set env vars.
|
|
80
|
+
|
|
81
|
+
## Build for production
|
|
16
82
|
|
|
17
83
|
```bash
|
|
18
|
-
|
|
84
|
+
npm run build
|
|
85
|
+
npm run server:prod
|
|
19
86
|
```
|
|
87
|
+
|
|
88
|
+
## Learn more
|
|
89
|
+
|
|
90
|
+
- [@_linked/core](https://www.npmjs.com/package/@_linked/core) — query DSL, Shape classes, storage routing. See `parseDatasetsConfig` + `loadStores` for the dataset-config helpers.
|
|
91
|
+
- [@_linked/react](https://www.npmjs.com/package/@_linked/react) — `linkedComponent`, `linkedSetComponent`.
|
|
92
|
+
- [@_linked/schema](https://www.npmjs.com/package/@_linked/schema) — shipped Shape classes (Person, Place, Organization, …).
|
|
93
|
+
- [@_linked/css](https://www.npmjs.com/package/@_linked/css) — design tokens, Tailwind v4 theme primitives, `@utility` mixins. See `src/theme.css` for the wiring.
|
package/jest.config.cjs
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Jest config for @_linked/cli unit tests.
|
|
2
|
+
//
|
|
3
|
+
// Tests target the compiled CJS output in lib/cjs, not raw src/. This avoids
|
|
4
|
+
// configuring jest's ESM mode (notoriously fiddly with our mixed tsx/ESM
|
|
5
|
+
// runtime) and keeps the test runner identical to what npm consumers see.
|
|
6
|
+
// Run `yarn build` before `yarn test:unit` so lib/cjs exists.
|
|
7
|
+
//
|
|
8
|
+
// E2E specs live in tests/e2e/ and run under Playwright (see
|
|
9
|
+
// playwright.config.ts), not Jest.
|
|
10
|
+
module.exports = {
|
|
11
|
+
testEnvironment: 'node',
|
|
12
|
+
rootDir: '.',
|
|
13
|
+
roots: ['<rootDir>/tests/unit'],
|
|
14
|
+
testMatch: ['**/*.test.{ts,js}'],
|
|
15
|
+
transform: {
|
|
16
|
+
'^.+\\.tsx?$': [
|
|
17
|
+
'babel-jest',
|
|
18
|
+
{
|
|
19
|
+
configFile: false,
|
|
20
|
+
babelrc: false,
|
|
21
|
+
presets: [
|
|
22
|
+
['@babel/preset-env', { targets: { node: 'current' } }],
|
|
23
|
+
'@babel/preset-typescript',
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'],
|
|
29
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-methods.d.ts","sourceRoot":"","sources":["../../src/cli-methods.ts"],"names":[],"mappings":"AAyBA,OAAO,EAAC,cAAc,EAAC,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"cli-methods.d.ts","sourceRoot":"","sources":["../../src/cli-methods.ts"],"names":[],"mappings":"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"}
|
package/lib/cjs/cli-methods.js
CHANGED
|
@@ -66,6 +66,35 @@ let dirname__ = typeof __dirname !== 'undefined'
|
|
|
66
66
|
? __dirname
|
|
67
67
|
: //@ts-ignore
|
|
68
68
|
(0, path_1.dirname)(import.meta.url).replace('file:/', '');
|
|
69
|
+
/**
|
|
70
|
+
* Dynamically import the app's backend storage configuration. Tries the
|
|
71
|
+
* canonical `linked.backend.storage.{ts,js}` at app root first, then the
|
|
72
|
+
* earlier `backend-storage-config.{ts,js}` (Iter3), then the legacy
|
|
73
|
+
* `scripts/storage-config.js` (pre-rename). The fallback chain lets older
|
|
74
|
+
* app clones keep booting through the rename.
|
|
75
|
+
*/
|
|
76
|
+
async function loadBackendStorageConfig() {
|
|
77
|
+
const cwd = process.cwd();
|
|
78
|
+
const candidates = [
|
|
79
|
+
// Iter4 canonical:
|
|
80
|
+
path_1.default.join(cwd, 'linked.backend.storage.ts'),
|
|
81
|
+
path_1.default.join(cwd, 'linked.backend.storage.js'),
|
|
82
|
+
// Iter3:
|
|
83
|
+
path_1.default.join(cwd, 'backend-storage-config.ts'),
|
|
84
|
+
path_1.default.join(cwd, 'backend-storage-config.js'),
|
|
85
|
+
path_1.default.join(cwd, 'scripts', 'backend-storage-config.js'),
|
|
86
|
+
path_1.default.join(cwd, 'scripts', 'backend-storage-config.ts'),
|
|
87
|
+
// legacy pre-rename:
|
|
88
|
+
path_1.default.join(cwd, 'scripts', 'storage-config.js'),
|
|
89
|
+
];
|
|
90
|
+
for (const candidate of candidates) {
|
|
91
|
+
if (fs_extra_1.default.existsSync(candidate)) {
|
|
92
|
+
return Promise.resolve(`${candidate}`).then(s => __importStar(require(s)));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
console.warn(chalk_1.default.yellow('[linked.backend.storage] no linked.backend.storage.{ts,js} found at app root.'));
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
69
98
|
var variables = {};
|
|
70
99
|
/**
|
|
71
100
|
* Prompt user for input
|
|
@@ -136,8 +165,15 @@ const createApp = async (name, basePath = process.cwd(), options = {}) => {
|
|
|
136
165
|
});
|
|
137
166
|
fs_extra_1.default.renameSync(path_1.default.join(targetFolder, 'gitignore.template'), path_1.default.join(targetFolder, '.gitignore'));
|
|
138
167
|
fs_extra_1.default.renameSync(path_1.default.join(targetFolder, 'yarnrc.yml.template'), path_1.default.join(targetFolder, '.yarnrc.yml'));
|
|
168
|
+
// Seed the real (gitignored) Layer 2 config from the committed example so
|
|
169
|
+
// the scaffolded app boots first try. Users can edit either file later.
|
|
170
|
+
const datasetsExample = path_1.default.join(targetFolder, 'linked.backend.datasets.example.json');
|
|
171
|
+
const datasetsReal = path_1.default.join(targetFolder, 'linked.backend.datasets.json');
|
|
172
|
+
if (fs_extra_1.default.existsSync(datasetsExample) && !fs_extra_1.default.existsSync(datasetsReal)) {
|
|
173
|
+
fs_extra_1.default.copySync(datasetsExample, datasetsReal);
|
|
174
|
+
}
|
|
139
175
|
// fs.copySync(path.join(__dirname, '..', 'defaults', 'app'), targetFolder);
|
|
140
|
-
log("Creating new
|
|
176
|
+
log("Creating new Linked app '" + appName + "'");
|
|
141
177
|
//replace variables in some copied files
|
|
142
178
|
await replaceVariablesInFolder(targetFolder);
|
|
143
179
|
if (!options.skipInstall) {
|
|
@@ -149,7 +185,7 @@ const createApp = async (name, basePath = process.cwd(), options = {}) => {
|
|
|
149
185
|
console.warn('Could not install dependencies or start application');
|
|
150
186
|
});
|
|
151
187
|
}
|
|
152
|
-
log(`Your
|
|
188
|
+
log(`Your Linked app is ready at ${chalk_1.default.blueBright(targetFolder)}`, `\nStorage: linked.backend.storage.ts wires aliases to stores; linked.backend.datasets.json holds endpoints.`, `Defaults to Fuseki at ${chalk_1.default.cyan('http://localhost:3030')} (auto-creates the dataset on first boot).`, `Make sure Fuseki is running, e.g.:`, ` ${chalk_1.default.blueBright('docker run -d --rm -p 3030:3030 --name fuseki stain/jena-fuseki')}`, `Edit ${chalk_1.default.cyan('linked.backend.datasets.json')} to change endpoints or credentials.`, `Mirror file for the frontend: ${chalk_1.default.cyan('src/linked.frontend.storage.ts')} + ${chalk_1.default.cyan('src/linked.frontend.datasets.json')}.`, `\nTo start (with npm or yarn):`, ` ${chalk_1.default.blueBright(`cd ${hyphenName} && npm start`)}`, ` ${chalk_1.default.gray('# or: yarn start')}`);
|
|
153
189
|
};
|
|
154
190
|
exports.createApp = createApp;
|
|
155
191
|
function logHelp() {
|
|
@@ -232,7 +268,7 @@ function checkPackagePath(rootPath, packagePath, res) {
|
|
|
232
268
|
if (pack && pack.workspaces) {
|
|
233
269
|
checkWorkspaces(packagePath, pack.workspaces, res);
|
|
234
270
|
}
|
|
235
|
-
else if (pack &&
|
|
271
|
+
else if (pack && pack.linkedPackage === true) {
|
|
236
272
|
res.push({
|
|
237
273
|
path: packagePath,
|
|
238
274
|
packageName: pack.name,
|
|
@@ -443,7 +479,7 @@ function findAppRoot(startPath = process.cwd()) {
|
|
|
443
479
|
candidateRoots.push({
|
|
444
480
|
path: currentPath,
|
|
445
481
|
hasWorkspaces: !!packageJson.workspaces,
|
|
446
|
-
|
|
482
|
+
isLinked: packageJson.linkedPackage === true,
|
|
447
483
|
});
|
|
448
484
|
}
|
|
449
485
|
const parentPath = path_1.default.join(currentPath, '..');
|
|
@@ -454,16 +490,16 @@ function findAppRoot(startPath = process.cwd()) {
|
|
|
454
490
|
currentPath = parentPath;
|
|
455
491
|
}
|
|
456
492
|
// Find the topmost package.json that has workspaces
|
|
457
|
-
// Prefer non-
|
|
493
|
+
// Prefer non-linked packages (app roots) over linked packages
|
|
458
494
|
let appRoot = null;
|
|
459
495
|
for (let i = candidateRoots.length - 1; i >= 0; i--) {
|
|
460
496
|
const candidate = candidateRoots[i];
|
|
461
|
-
if (candidate.hasWorkspaces && !candidate.
|
|
497
|
+
if (candidate.hasWorkspaces && !candidate.isLinked) {
|
|
462
498
|
appRoot = candidate.path;
|
|
463
499
|
break;
|
|
464
500
|
}
|
|
465
501
|
}
|
|
466
|
-
// If no non-
|
|
502
|
+
// If no non-linked workspace found, use the topmost workspace
|
|
467
503
|
if (!appRoot) {
|
|
468
504
|
for (let i = candidateRoots.length - 1; i >= 0; i--) {
|
|
469
505
|
if (candidateRoots[i].hasWorkspaces) {
|
|
@@ -1307,23 +1343,23 @@ exports.runScript = runScript;
|
|
|
1307
1343
|
const runMethod = async (packageName, method, options) => {
|
|
1308
1344
|
await (0, exports.ensureEnvironmentLoaded)();
|
|
1309
1345
|
if (options.spawn) {
|
|
1310
|
-
let
|
|
1346
|
+
let linkedConfig = (await Promise.resolve(`${path_1.default.join(process.cwd(), 'linked.config.js')}`).then(s => __importStar(require(s)))).default;
|
|
1311
1347
|
// Set default loadAppComponent if not provided
|
|
1312
|
-
if (!
|
|
1313
|
-
|
|
1348
|
+
if (!linkedConfig.server) {
|
|
1349
|
+
linkedConfig.server = {};
|
|
1314
1350
|
}
|
|
1315
|
-
if (!
|
|
1316
|
-
|
|
1351
|
+
if (!linkedConfig.server.loadAppComponent) {
|
|
1352
|
+
linkedConfig.server.loadAppComponent = async () => (await Promise.resolve(`${path_1.default.join(process.cwd(), 'src', 'App')}`).then(s => __importStar(require(s)))).default;
|
|
1317
1353
|
}
|
|
1318
1354
|
// Set default loadRoutes if not provided
|
|
1319
|
-
if (!
|
|
1320
|
-
|
|
1355
|
+
if (!linkedConfig.server.loadRoutes) {
|
|
1356
|
+
linkedConfig.server.loadRoutes = async () => await Promise.resolve(`${path_1.default.join(process.cwd(), 'src', 'routes.tsx')}`).then(s => __importStar(require(s)));
|
|
1321
1357
|
}
|
|
1322
1358
|
//@ts-ignore
|
|
1323
1359
|
const ServerClass = (await Promise.resolve().then(() => __importStar(require('@_linked/server/shapes/LincdServer'))))
|
|
1324
1360
|
.LincdServer;
|
|
1325
|
-
await
|
|
1326
|
-
let server = new ServerClass(
|
|
1361
|
+
await loadBackendStorageConfig();
|
|
1362
|
+
let server = new ServerClass(linkedConfig);
|
|
1327
1363
|
//init the server
|
|
1328
1364
|
console.log('Initializing server...');
|
|
1329
1365
|
server.initOnly().then(() => {
|
|
@@ -1396,7 +1432,7 @@ const runMethod = async (packageName, method, options) => {
|
|
|
1396
1432
|
exports.runMethod = runMethod;
|
|
1397
1433
|
const startServer = async (initOnly = false, ServerClass = null) => {
|
|
1398
1434
|
await (0, exports.ensureEnvironmentLoaded)();
|
|
1399
|
-
let
|
|
1435
|
+
let linkedConfig = (await Promise.resolve(`${path_1.default.join(process.cwd(), 'linked.config.js')}`).then(s => __importStar(require(s))))
|
|
1400
1436
|
.default;
|
|
1401
1437
|
// function scssLoadcall(source, filename) {
|
|
1402
1438
|
// return 'console.log("SCSS CALL: ' + filename + '");\n' + source;
|
|
@@ -1412,12 +1448,12 @@ const startServer = async (initOnly = false, ServerClass = null) => {
|
|
|
1412
1448
|
//@ts-ignore
|
|
1413
1449
|
ServerClass = (await Promise.resolve().then(() => __importStar(require('@_linked/server/shapes/LincdServer')))).LincdServer;
|
|
1414
1450
|
}
|
|
1415
|
-
await
|
|
1451
|
+
await loadBackendStorageConfig();
|
|
1416
1452
|
// Set default loadAppComponent if not provided
|
|
1417
|
-
if (!
|
|
1418
|
-
|
|
1453
|
+
if (!linkedConfig.server) {
|
|
1454
|
+
linkedConfig.server = {};
|
|
1419
1455
|
}
|
|
1420
|
-
if (!
|
|
1456
|
+
if (!linkedConfig.server.loadAppComponent) {
|
|
1421
1457
|
let appPromise;
|
|
1422
1458
|
if (process.env.NODE_ENV !== 'development') {
|
|
1423
1459
|
appPromise = (await Promise.resolve(`${path_1.default.join(process.cwd(), 'lib', 'App.js')}`).then(s => __importStar(require(s))))
|
|
@@ -1427,13 +1463,13 @@ const startServer = async (initOnly = false, ServerClass = null) => {
|
|
|
1427
1463
|
appPromise = (await Promise.resolve(`${path_1.default.join(process.cwd(), 'src', 'App.tsx')}`).then(s => __importStar(require(s))))
|
|
1428
1464
|
.default;
|
|
1429
1465
|
}
|
|
1430
|
-
|
|
1466
|
+
linkedConfig.server.loadAppComponent = async () => {
|
|
1431
1467
|
return appPromise;
|
|
1432
1468
|
};
|
|
1433
1469
|
}
|
|
1434
1470
|
// Set default loadRoutes if not provided
|
|
1435
|
-
if (!
|
|
1436
|
-
|
|
1471
|
+
if (!linkedConfig.server.loadRoutes) {
|
|
1472
|
+
linkedConfig.server.loadRoutes = async () => {
|
|
1437
1473
|
if (process.env.NODE_ENV !== 'development') {
|
|
1438
1474
|
return await Promise.resolve(`${path_1.default.join(process.cwd(), 'lib', 'routes.js')}`).then(s => __importStar(require(s)));
|
|
1439
1475
|
}
|
|
@@ -1442,7 +1478,7 @@ const startServer = async (initOnly = false, ServerClass = null) => {
|
|
|
1442
1478
|
}
|
|
1443
1479
|
};
|
|
1444
1480
|
}
|
|
1445
|
-
let server = new ServerClass(
|
|
1481
|
+
let server = new ServerClass(linkedConfig);
|
|
1446
1482
|
//Important to use slice, because when using clusers, child processes need to be able to read the same arguments
|
|
1447
1483
|
let args = process.argv.slice(2);
|
|
1448
1484
|
//if --initOnly is passed, only initialize the server and don't start it
|
|
@@ -1513,10 +1549,10 @@ const buildFrontend = async () => {
|
|
|
1513
1549
|
// process.exit();
|
|
1514
1550
|
}
|
|
1515
1551
|
// load the storage config
|
|
1516
|
-
const storageConfig = await
|
|
1552
|
+
const storageConfig = await loadBackendStorageConfig();
|
|
1517
1553
|
// check if LincdFileStorage has a default FileStore
|
|
1518
1554
|
// if yes: copy all the files in the build folder over with LincdFileStorage
|
|
1519
|
-
if (LinkedFileStorage_1.LinkedFileStorage.
|
|
1555
|
+
if (LinkedFileStorage_1.LinkedFileStorage.getDefaultDataset()) {
|
|
1520
1556
|
// get public directory
|
|
1521
1557
|
const rootDirectory = 'public';
|
|
1522
1558
|
const pathDir = path_1.default.join(process.cwd(), rootDirectory);
|
|
@@ -1917,8 +1953,8 @@ const buildPackage = async (target, target2, packagePath = process.cwd(), logRes
|
|
|
1917
1953
|
// `linked build-app`. Plain packages (no linked flag) have no build pipeline
|
|
1918
1954
|
// defined here and should have their own build script.
|
|
1919
1955
|
const pkgJson = JSON.parse(fs_extra_1.default.readFileSync(path_1.default.join(packagePath, 'package.json'), 'utf8'));
|
|
1920
|
-
const isPackage = pkgJson.linkedPackage === true
|
|
1921
|
-
const isApp = pkgJson.linkedApp === true
|
|
1956
|
+
const isPackage = pkgJson.linkedPackage === true;
|
|
1957
|
+
const isApp = pkgJson.linkedApp === true;
|
|
1922
1958
|
if (!isPackage) {
|
|
1923
1959
|
if (isApp) {
|
|
1924
1960
|
console.error(chalk_1.default.red(`'${pkgJson.name || packagePath}' is a linkedApp, not a linkedPackage. Use 'linked build-app' instead of 'linked build'.`));
|