@_linked/cli 1.8.2 → 1.9.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.
Files changed (182) hide show
  1. package/.github/workflows/publish.yml +23 -0
  2. package/CHANGELOG.md +18 -0
  3. package/defaults/setup-publish/dual-branch/github/workflows/publish.yml +26 -0
  4. package/defaults/setup-publish/github/workflows/publish.yml +27 -0
  5. package/jest.config.cjs +8 -4
  6. package/lib/esm/cli-methods.d.ts.map +1 -1
  7. package/lib/esm/cli-methods.js +15 -3
  8. package/lib/esm/cli-methods.js.map +1 -1
  9. package/lib/esm/vite-config.d.ts.map +1 -1
  10. package/lib/esm/vite-config.js +51 -16
  11. package/lib/esm/vite-config.js.map +1 -1
  12. package/package.json +8 -14
  13. package/tests/unit/safeYarn.test.ts +1 -1
  14. package/defaults/app-with-backend/.env-cmdrc.json +0 -19
  15. package/defaults/app-with-backend/.env.example +0 -20
  16. package/defaults/app-with-backend/.eslintignore +0 -5
  17. package/defaults/app-with-backend/.eslintrc.json +0 -40
  18. package/defaults/app-with-backend/.prettierignore +0 -4
  19. package/defaults/app-with-backend/.prettierrc.json +0 -27
  20. package/defaults/app-with-backend/.vscode/launch.json +0 -12
  21. package/defaults/app-with-backend/.yarn/plugins/@yarnpkg/plugin-version.cjs +0 -550
  22. package/defaults/app-with-backend/.yarn/releases/yarn-3.6.1.cjs +0 -874
  23. package/defaults/app-with-backend/gitignore.template +0 -27
  24. package/defaults/app-with-backend/linked.backend.datasets.example.json +0 -17
  25. package/defaults/app-with-backend/linked.backend.storage.ts +0 -35
  26. package/defaults/app-with-backend/linked.config.js +0 -7
  27. package/defaults/app-with-backend/package.json +0 -75
  28. package/defaults/app-with-backend/pm2-staging.config.js +0 -12
  29. package/defaults/app-with-backend/pm2.config.js +0 -12
  30. package/defaults/app-with-backend/public/favicon-144x144.png +0 -0
  31. package/defaults/app-with-backend/public/favicon-57x57.png +0 -0
  32. package/defaults/app-with-backend/public/favicon-72x72.png +0 -0
  33. package/defaults/app-with-backend/public/favicon.ico +0 -0
  34. package/defaults/app-with-backend/readme.md +0 -93
  35. package/defaults/app-with-backend/src/App.module.css +0 -83
  36. package/defaults/app-with-backend/src/App.tsx +0 -30
  37. package/defaults/app-with-backend/src/backend.ts +0 -9
  38. package/defaults/app-with-backend/src/components/Error.module.css +0 -9
  39. package/defaults/app-with-backend/src/components/Error.tsx +0 -11
  40. package/defaults/app-with-backend/src/components/PersonOverview.module.css +0 -100
  41. package/defaults/app-with-backend/src/components/PersonOverview.tsx +0 -97
  42. package/defaults/app-with-backend/src/components/PersonOverviewContext.tsx +0 -12
  43. package/defaults/app-with-backend/src/components/PersonPreview.module.css +0 -97
  44. package/defaults/app-with-backend/src/components/PersonPreview.tsx +0 -109
  45. package/defaults/app-with-backend/src/components/Spinner.module.css +0 -17
  46. package/defaults/app-with-backend/src/components/Spinner.tsx +0 -12
  47. package/defaults/app-with-backend/src/index.tsx +0 -34
  48. package/defaults/app-with-backend/src/layout/DefaultLayout.module.css +0 -15
  49. package/defaults/app-with-backend/src/layout/DefaultLayout.tsx +0 -12
  50. package/defaults/app-with-backend/src/layout/Header.module.css +0 -46
  51. package/defaults/app-with-backend/src/layout/Header.tsx +0 -27
  52. package/defaults/app-with-backend/src/linked.frontend.datasets.json +0 -12
  53. package/defaults/app-with-backend/src/linked.frontend.storage.ts +0 -36
  54. package/defaults/app-with-backend/src/package.ts +0 -16
  55. package/defaults/app-with-backend/src/pages/Home.module.css +0 -23
  56. package/defaults/app-with-backend/src/pages/Home.tsx +0 -14
  57. package/defaults/app-with-backend/src/pages/Page1.module.css +0 -111
  58. package/defaults/app-with-backend/src/pages/Page1.tsx +0 -196
  59. package/defaults/app-with-backend/src/pages/PageNotFound.module.css +0 -19
  60. package/defaults/app-with-backend/src/pages/PageNotFound.tsx +0 -14
  61. package/defaults/app-with-backend/src/pages/Signin.module.css +0 -20
  62. package/defaults/app-with-backend/src/pages/Signin.tsx +0 -16
  63. package/defaults/app-with-backend/src/routes.tsx +0 -78
  64. package/defaults/app-with-backend/src/theme.css +0 -91
  65. package/defaults/app-with-backend/src/types.ts +0 -14
  66. package/defaults/app-with-backend/src/utils/lazyWithPreload.tsx +0 -42
  67. package/defaults/app-with-backend/src/utils/preloadRoutes.ts +0 -38
  68. package/defaults/app-with-backend/tsconfig.json +0 -24
  69. package/defaults/app-with-backend/vite.config.ts +0 -13
  70. package/defaults/app-with-backend/yarnrc.yml.template +0 -8
  71. package/lib/cjs/cli-methods.d.ts +0 -75
  72. package/lib/cjs/cli-methods.d.ts.map +0 -1
  73. package/lib/cjs/cli-methods.js +0 -2655
  74. package/lib/cjs/cli-methods.js.map +0 -1
  75. package/lib/cjs/cli.d.ts +0 -3
  76. package/lib/cjs/cli.d.ts.map +0 -1
  77. package/lib/cjs/cli.js +0 -339
  78. package/lib/cjs/cli.js.map +0 -1
  79. package/lib/cjs/commands/build-package.d.ts +0 -9
  80. package/lib/cjs/commands/build-package.d.ts.map +0 -1
  81. package/lib/cjs/commands/build-package.js +0 -55
  82. package/lib/cjs/commands/build-package.js.map +0 -1
  83. package/lib/cjs/commands/safe-yarn.d.ts +0 -10
  84. package/lib/cjs/commands/safe-yarn.d.ts.map +0 -1
  85. package/lib/cjs/commands/safe-yarn.js +0 -66
  86. package/lib/cjs/commands/safe-yarn.js.map +0 -1
  87. package/lib/cjs/commands/setup-publish.d.ts +0 -23
  88. package/lib/cjs/commands/setup-publish.d.ts.map +0 -1
  89. package/lib/cjs/commands/setup-publish.js +0 -369
  90. package/lib/cjs/commands/setup-publish.js.map +0 -1
  91. package/lib/cjs/commands/start.d.ts +0 -6
  92. package/lib/cjs/commands/start.d.ts.map +0 -1
  93. package/lib/cjs/commands/start.js +0 -337
  94. package/lib/cjs/commands/start.js.map +0 -1
  95. package/lib/cjs/config-webpack-app.d.ts +0 -112
  96. package/lib/cjs/config-webpack-app.d.ts.map +0 -1
  97. package/lib/cjs/config-webpack-app.js +0 -427
  98. package/lib/cjs/config-webpack-app.js.map +0 -1
  99. package/lib/cjs/config-webpack.d.ts +0 -55
  100. package/lib/cjs/config-webpack.d.ts.map +0 -1
  101. package/lib/cjs/config-webpack.js +0 -417
  102. package/lib/cjs/config-webpack.js.map +0 -1
  103. package/lib/cjs/defineConfig.d.ts +0 -8
  104. package/lib/cjs/defineConfig.d.ts.map +0 -1
  105. package/lib/cjs/defineConfig.js +0 -12
  106. package/lib/cjs/defineConfig.js.map +0 -1
  107. package/lib/cjs/index.d.ts +0 -12
  108. package/lib/cjs/index.d.ts.map +0 -1
  109. package/lib/cjs/index.js +0 -43
  110. package/lib/cjs/index.js.map +0 -1
  111. package/lib/cjs/interfaces.d.ts +0 -140
  112. package/lib/cjs/interfaces.d.ts.map +0 -1
  113. package/lib/cjs/interfaces.js +0 -3
  114. package/lib/cjs/interfaces.js.map +0 -1
  115. package/lib/cjs/lifecycle.d.ts +0 -24
  116. package/lib/cjs/lifecycle.d.ts.map +0 -1
  117. package/lib/cjs/lifecycle.js +0 -187
  118. package/lib/cjs/lifecycle.js.map +0 -1
  119. package/lib/cjs/loaders/css-loader.d.mts +0 -2
  120. package/lib/cjs/loaders/css-loader.d.mts.map +0 -1
  121. package/lib/cjs/loaders/css-loader.mjs +0 -86
  122. package/lib/cjs/loaders/css-loader.mjs.map +0 -1
  123. package/lib/cjs/loaders/register-css-only.d.ts +0 -2
  124. package/lib/cjs/loaders/register-css-only.d.ts.map +0 -1
  125. package/lib/cjs/loaders/register-css-only.js +0 -11
  126. package/lib/cjs/loaders/register-css-only.js.map +0 -1
  127. package/lib/cjs/loaders/register.d.ts +0 -2
  128. package/lib/cjs/loaders/register.d.ts.map +0 -1
  129. package/lib/cjs/loaders/register.js +0 -11
  130. package/lib/cjs/loaders/register.js.map +0 -1
  131. package/lib/cjs/loaders/ts-loader.d.mts +0 -3
  132. package/lib/cjs/loaders/ts-loader.d.mts.map +0 -1
  133. package/lib/cjs/loaders/ts-loader.mjs +0 -125
  134. package/lib/cjs/loaders/ts-loader.mjs.map +0 -1
  135. package/lib/cjs/metadata.d.ts +0 -1
  136. package/lib/cjs/metadata.d.ts.map +0 -1
  137. package/lib/cjs/metadata.js +0 -155
  138. package/lib/cjs/metadata.js.map +0 -1
  139. package/lib/cjs/package.json +0 -144
  140. package/lib/cjs/plugins/check-imports.d.ts +0 -2
  141. package/lib/cjs/plugins/check-imports.d.ts.map +0 -1
  142. package/lib/cjs/plugins/check-imports.js +0 -68
  143. package/lib/cjs/plugins/check-imports.js.map +0 -1
  144. package/lib/cjs/plugins/declaration-plugin.d.ts +0 -15
  145. package/lib/cjs/plugins/declaration-plugin.d.ts.map +0 -1
  146. package/lib/cjs/plugins/declaration-plugin.js +0 -285
  147. package/lib/cjs/plugins/declaration-plugin.js.map +0 -1
  148. package/lib/cjs/plugins/externalise-modules.d.ts +0 -7
  149. package/lib/cjs/plugins/externalise-modules.d.ts.map +0 -1
  150. package/lib/cjs/plugins/externalise-modules.js +0 -190
  151. package/lib/cjs/plugins/externalise-modules.js.map +0 -1
  152. package/lib/cjs/plugins/lincd-tailwind-sources.d.ts +0 -3
  153. package/lib/cjs/plugins/lincd-tailwind-sources.d.ts.map +0 -1
  154. package/lib/cjs/plugins/lincd-tailwind-sources.js +0 -32
  155. package/lib/cjs/plugins/lincd-tailwind-sources.js.map +0 -1
  156. package/lib/cjs/plugins/watch-run.d.ts +0 -5
  157. package/lib/cjs/plugins/watch-run.d.ts.map +0 -1
  158. package/lib/cjs/plugins/watch-run.js +0 -45
  159. package/lib/cjs/plugins/watch-run.js.map +0 -1
  160. package/lib/cjs/preflight.css +0 -137
  161. package/lib/cjs/tailwind.config.d.ts +0 -8
  162. package/lib/cjs/tailwind.config.d.ts.map +0 -1
  163. package/lib/cjs/tailwind.config.js +0 -17
  164. package/lib/cjs/tailwind.config.js.map +0 -1
  165. package/lib/cjs/utils.d.ts +0 -77
  166. package/lib/cjs/utils.d.ts.map +0 -1
  167. package/lib/cjs/utils.js +0 -591
  168. package/lib/cjs/utils.js.map +0 -1
  169. package/lib/cjs/vite-config.d.ts +0 -20
  170. package/lib/cjs/vite-config.d.ts.map +0 -1
  171. package/lib/cjs/vite-config.js +0 -401
  172. package/lib/cjs/vite-config.js.map +0 -1
  173. package/lib/esm/loaders/register-css-only.d.ts +0 -2
  174. package/lib/esm/loaders/register-css-only.d.ts.map +0 -1
  175. package/lib/esm/loaders/register-css-only.js +0 -9
  176. package/lib/esm/loaders/register-css-only.js.map +0 -1
  177. package/lib/esm/loaders/register.d.ts +0 -2
  178. package/lib/esm/loaders/register.d.ts.map +0 -1
  179. package/lib/esm/loaders/register.js +0 -9
  180. package/lib/esm/loaders/register.js.map +0 -1
  181. package/lib/esm/package.json +0 -144
  182. /package/{babel.config.js → babel.config.cjs} +0 -0
@@ -1,27 +0,0 @@
1
- node_modules
2
- build
3
- mrgit.json
4
- public/bundles
5
- data/uploads
6
- data/metadata
7
- data/sessions
8
- linked.backend.datasets.json
9
- .yarn/*
10
- !.yarn/patches
11
- !.yarn/plugins
12
- !.yarn/releases
13
- !.yarn/sdks
14
- !.yarn/versions
15
- packages/**/dist
16
- packages/**/lib
17
- packages/**/.yarn/*
18
- !packages/**/.yarn/patches
19
- !packages/**/.yarn/plugins
20
- !packages/**/.yarn/releases
21
- !packages/**/.yarn/sdks
22
- !packages/**/.yarn/versions
23
- .idea
24
- android/app/build
25
- ios/App/App/public
26
- # Local env (copied from .env.example)
27
- .env
@@ -1,17 +0,0 @@
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
- }
@@ -1,35 +0,0 @@
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' with { 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);
@@ -1,7 +0,0 @@
1
- export default {
2
- cssMode: 'tailwind',
3
- // Materialize this app's registered shapes into its data store on boot (default).
4
- syncShapesOnBoot: true,
5
- cacheWebpack: true,
6
- analyse: false,
7
- };
@@ -1,75 +0,0 @@
1
- {
2
- "name": "${hyphen_name}",
3
- "displayName": "${name}",
4
- "description": "",
5
- "version": "0.1.0",
6
- "private": true,
7
- "type": "module",
8
- "linkedApp": true,
9
- "author": {
10
- "name": "",
11
- "url": "",
12
- "email": ""
13
- },
14
- "engines": {
15
- "node": ">=20.12.0"
16
- },
17
- "main": "scripts/start-server.js",
18
- "exports": {
19
- "./backend": {
20
- "development": "./src/backend.ts",
21
- "default": "./src/backend.ts"
22
- }
23
- },
24
- "license": "MIT",
25
- "scripts": {
26
- "start": "linked start",
27
- "build": "linked build-app --env production",
28
- "server:prod": "NODE_ENV=production linked start",
29
- "lint": "eslint \"src/**/*.{js,jsx,ts,tsx}\"",
30
- "lint:fix": "npm run lint -- --fix",
31
- "prettier": "prettier \"src/**/*.{js,jsx,ts,tsx,css,scss}\" --check",
32
- "prettier:fix": "npm run prettier -- --write",
33
- "format": "npm run prettier:fix && npm run lint:fix"
34
- },
35
- "keywords": [
36
- "linked",
37
- "linked code",
38
- "linked data",
39
- "structured data",
40
- "RDF",
41
- "semantic web",
42
- "web3"
43
- ],
44
- "dependencies": {
45
- "@_linked/core": "^2.10",
46
- "@_linked/server": "^2.0",
47
- "@_linked/server-utils": "^1.0.6",
48
- "@_linked/schema": "^1.0.6",
49
- "@_linked/fuseki": "^1.0",
50
- "@_linked/primitives": "^1.0.6",
51
- "@_linked/react": "^1.3",
52
- "react": "^18.2",
53
- "react-dom": "^18.2",
54
- "react-error-boundary": "^3.1.3",
55
- "react-router-dom": "^6.3.0"
56
- },
57
- "devDependencies": {
58
- "@_linked/cli": "^1.8",
59
- "@types/node": "^20.12.7",
60
- "@types/react": "^18.0.17",
61
- "@types/react-dom": "^18.0.6",
62
- "@typescript-eslint/eslint-plugin": "latest",
63
- "@typescript-eslint/parser": "latest",
64
- "eslint": "latest",
65
- "eslint-config-prettier": "^8.9.0",
66
- "eslint-import-resolver-typescript": "^3.5.5",
67
- "eslint-plugin-prettier": "^5.0.0",
68
- "eslint-plugin-react": "latest",
69
- "eslint-plugin-react-hooks": "latest",
70
- "nodemon": "^2.0.22",
71
- "pm2": "^5.3.0",
72
- "typescript-plugin-css-modules": "^5.1.0",
73
- "which": "^3.0.1"
74
- }
75
- }
@@ -1,12 +0,0 @@
1
- module.exports = {
2
- apps: [
3
- {
4
- name: '${hyphen_name}-staging',
5
- script: 'yarn run server:staging',
6
- time: true,
7
- log_date_format: 'DD-MM-YYYY HH:mm Z',
8
- out_file: './data/out.log',
9
- error_file: './data/error.log',
10
- },
11
- ],
12
- };
@@ -1,12 +0,0 @@
1
- module.exports = {
2
- apps: [
3
- {
4
- name: '${hyphen_name}',
5
- script: 'yarn run server:prod',
6
- time: true,
7
- log_date_format: 'DD-MM-YYYY HH:mm Z',
8
- out_file: "./data/out.log",
9
- error_file: "./data/error.log",
10
- }
11
- ],
12
- };
@@ -1,93 +0,0 @@
1
- # ${name}
2
-
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:
37
-
38
- ```bash
39
- npm install
40
- npm start
41
- ```
42
-
43
- Or with yarn:
44
-
45
- ```bash
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. `packages/` of another repo), 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
60
- ```
61
-
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
82
-
83
- ```bash
84
- npm run build
85
- npm run server:prod
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.
@@ -1,83 +0,0 @@
1
- @import '@_linked/css/package.css';
2
-
3
- :global(body) {
4
- font-family: var(--font-sans);
5
- background: var(--bg-page);
6
- color: var(--color-gray-900);
7
- margin: 0;
8
- overflow-x: hidden;
9
- }
10
-
11
- /* Animated background: soft radial-gradient "blobs" drifting and pulsing
12
- underneath the content. Brand-colored via @_linked/css tokens — recolors
13
- automatically when --color-primary-* / --color-secondary-* change in theme.css. */
14
- :global(body)::before {
15
- content: '';
16
- position: fixed;
17
- inset: 0;
18
- z-index: -1;
19
- pointer-events: none;
20
- background:
21
- radial-gradient(
22
- circle at 18% 22%,
23
- var(--color-primary-300) 0%,
24
- transparent 38%
25
- ),
26
- radial-gradient(
27
- circle at 82% 76%,
28
- var(--color-secondary-300) 0%,
29
- transparent 42%
30
- ),
31
- radial-gradient(
32
- circle at 55% 58%,
33
- var(--color-tertiary-200) 0%,
34
- transparent 50%
35
- );
36
- opacity: 0.35;
37
- filter: blur(40px);
38
- animation: drift 22s ease-in-out infinite;
39
- }
40
-
41
- @keyframes drift {
42
- 0%,
43
- 100% {
44
- transform: translate3d(0, 0, 0) scale(1);
45
- }
46
- 33% {
47
- transform: translate3d(-3%, 2%, 0) scale(1.05);
48
- }
49
- 66% {
50
- transform: translate3d(3%, -2%, 0) scale(0.97);
51
- }
52
- }
53
-
54
- @media (prefers-reduced-motion: reduce) {
55
- :global(body)::before {
56
- animation: none;
57
- }
58
- }
59
-
60
- .App {
61
- min-height: 100vh;
62
- position: relative;
63
- }
64
-
65
- :global(h1) {
66
- font-size: 1.75rem;
67
- font-weight: 600;
68
- margin: 0;
69
- }
70
-
71
- :global(h2) {
72
- font-size: 1.25rem;
73
- font-weight: 600;
74
- margin: 0 0 --spacing(3);
75
- }
76
-
77
- :global(a) {
78
- color: var(--color-primary-600);
79
- }
80
-
81
- :global(a:hover) {
82
- color: var(--color-primary-700);
83
- }
@@ -1,30 +0,0 @@
1
- import './theme.css'; //needs to be the first import before importing other components
2
- import React, { Suspense } from 'react';
3
- import { ErrorBoundary } from 'react-error-boundary';
4
- import { Spinner } from './components/Spinner';
5
- import { Error } from './components/Error';
6
- import { AppRoot } from '@_linked/server-utils/components/AppRoot';
7
- import { Head } from '@_linked/server-utils/components/Head';
8
- import { Body } from '@_linked/server-utils/components/Body';
9
- import AppRoutes, { ROUTES } from './routes';
10
- import style from './App.module.css'; //import any .module.css file like this and access the classnames from the style object
11
-
12
- // To add sign-in to this app, install `@_linked/auth`, wrap <AppRoutes/>
13
- // in <ProvideAuth>, and uncomment the `requireAuth` line in routes.tsx.
14
-
15
- export default function App() {
16
- return (
17
- <AppRoot>
18
- <Head>
19
- {/* Add tags to html <head> here, for example, a font <link href='https://fonts.someapi.com/...' />*/}
20
- </Head>
21
- <Body routes={ROUTES} pageStyles={style} className={style.App}>
22
- <Suspense fallback={<Spinner />}>
23
- <ErrorBoundary FallbackComponent={Error}>
24
- <AppRoutes />
25
- </ErrorBoundary>
26
- </Suspense>
27
- </Body>
28
- </AppRoot>
29
- );
30
- }
@@ -1,9 +0,0 @@
1
- //import all ShapeProviders here or define a generic BackendProvider, see https://linked.cm
2
-
3
- import { BackendProvider } from '@_linked/server-utils/utils/BackendProvider';
4
-
5
- export class Backend extends BackendProvider {
6
- constructor(server, linkedServer) {
7
- super(server, linkedServer);
8
- }
9
- }
@@ -1,9 +0,0 @@
1
- .error {
2
- color: white;
3
- margin: 2rem;
4
-
5
- pre {
6
- white-space: pre-wrap;
7
- padding: 1rem;
8
- }
9
- }
@@ -1,11 +0,0 @@
1
- import React from 'react';
2
- import style from './Error.module.css';
3
-
4
- export function Error({ error }) {
5
- return (
6
- <div className={style.error}>
7
- <h1>Application Error</h1>
8
- <pre>{error.stack}</pre>
9
- </div>
10
- );
11
- }
@@ -1,100 +0,0 @@
1
- @import '@_linked/css/package.css';
2
-
3
- .Root {
4
- background: var(--bg-card);
5
- border-radius: var(--radius-card);
6
- box-shadow: var(--shadow-card);
7
- padding: --spacing(6);
8
- }
9
-
10
- .Intro {
11
- color: var(--color-gray-600);
12
- font-size: 0.9rem;
13
- line-height: 1.5;
14
- margin: 0 0 --spacing(5);
15
- }
16
-
17
- .Intro code {
18
- background: var(--bg-section);
19
- padding: 0 --spacing(1);
20
- border-radius: var(--radius-element);
21
- font-family: var(--font-mono);
22
- font-size: 0.85em;
23
- }
24
-
25
- .Empty {
26
- color: var(--color-gray-500);
27
- font-style: italic;
28
- padding: --spacing(4) 0;
29
- margin: 0;
30
- }
31
-
32
- .Loading {
33
- color: var(--color-gray-500);
34
- padding: --spacing(4) 0;
35
- margin: 0;
36
- }
37
-
38
- .List {
39
- list-style: none;
40
- padding: 0;
41
- margin: 0 0 --spacing(5);
42
- }
43
-
44
- .List > li {
45
- padding: --spacing(3) 0;
46
- border-bottom: 1px solid var(--color-gray-200);
47
- }
48
-
49
- .List > li:first-child {
50
- padding-top: 0;
51
- }
52
-
53
- .List > li:last-child {
54
- border-bottom: none;
55
- }
56
-
57
- .Form {
58
- display: flex;
59
- gap: --spacing(2);
60
- flex-wrap: wrap;
61
- padding-top: --spacing(4);
62
- border-top: 1px solid var(--color-gray-200);
63
- }
64
-
65
- .Form input {
66
- flex: 1 1 140px;
67
- padding: --spacing(2) --spacing(3);
68
- border: 1px solid var(--color-gray-300);
69
- border-radius: var(--radius-element);
70
- background: var(--bg-card);
71
- color: var(--color-gray-900);
72
- font: inherit;
73
- }
74
-
75
- .Form input:focus {
76
- outline: none;
77
- border-color: var(--color-primary-500);
78
- box-shadow: 0 0 0 2px var(--color-primary-200);
79
- }
80
-
81
- .Form button {
82
- padding: --spacing(2) --spacing(5);
83
- background: var(--color-primary-500);
84
- color: var(--color-white);
85
- border: none;
86
- border-radius: var(--radius-element);
87
- font: inherit;
88
- font-weight: 500;
89
- cursor: pointer;
90
- transition: background 120ms ease;
91
- }
92
-
93
- .Form button:hover:not(:disabled) {
94
- background: var(--color-primary-600);
95
- }
96
-
97
- .Form button:disabled {
98
- opacity: 0.6;
99
- cursor: not-allowed;
100
- }
@@ -1,97 +0,0 @@
1
- // Example PersonOverview — demonstrates @_linked/react's data binding:
2
- // linkedSetComponent for the list (auto-runs the query, injects results and
3
- // an injected _refresh); linkedComponent for each row (see PersonPreview).
4
- // After Person.create the form calls _refresh() to re-run the list query.
5
- //
6
- // Replace or extend this with your own shapes (see https://linked.cm).
7
- import React, { useCallback, useRef, useState } from 'react';
8
- import { linkedSetComponent } from '@_linked/react';
9
- import { Person } from '@_linked/schema/shapes/Person';
10
- import { PersonPreview } from './PersonPreview';
11
- import { PersonListRefreshProvider } from './PersonOverviewContext';
12
- import style from './PersonOverview.module.css';
13
-
14
- const PersonList = linkedSetComponent(
15
- Person.select((p) => [p.givenName, p.familyName]),
16
- ({ linkedData = [], _refresh, refreshRef }: any) => {
17
- // Forward the list's _refresh up via a ref so the sibling form +
18
- // child rows can trigger a re-fetch through context.
19
- if (refreshRef) {
20
- refreshRef.current = _refresh;
21
- }
22
-
23
- if (linkedData.length === 0) {
24
- return (
25
- <p className={style.Empty}>No people yet. Add one below.</p>
26
- );
27
- }
28
-
29
- return (
30
- <ul className={style.List} data-testid="person-list">
31
- {linkedData.map((p: { id: string }) => (
32
- <li key={p.id}>
33
- <PersonPreview of={{ id: p.id }} />
34
- </li>
35
- ))}
36
- </ul>
37
- );
38
- },
39
- );
40
-
41
- function PersonAddForm({ onAdded }: { onAdded: () => void }) {
42
- const [given, setGiven] = useState('');
43
- const [family, setFamily] = useState('');
44
- const [busy, setBusy] = useState(false);
45
-
46
- async function submit(e: React.FormEvent) {
47
- e.preventDefault();
48
- if (!given && !family) return;
49
- setBusy(true);
50
- try {
51
- await Person.create({ givenName: given, familyName: family });
52
- setGiven('');
53
- setFamily('');
54
- onAdded();
55
- } finally {
56
- setBusy(false);
57
- }
58
- }
59
-
60
- return (
61
- <form className={style.Form} onSubmit={submit}>
62
- <input
63
- value={given}
64
- placeholder="First name"
65
- onChange={(e) => setGiven(e.target.value)}
66
- />
67
- <input
68
- value={family}
69
- placeholder="Last name"
70
- onChange={(e) => setFamily(e.target.value)}
71
- />
72
- <button type="submit" disabled={busy}>
73
- Add
74
- </button>
75
- </form>
76
- );
77
- }
78
-
79
- export function PersonOverview() {
80
- const refreshRef = useRef<() => void>(() => {});
81
- const refresh = useCallback(() => refreshRef.current(), []);
82
-
83
- return (
84
- <PersonListRefreshProvider value={refresh}>
85
- <div className={style.Root} data-testid="person-overview">
86
- <h2>People</h2>
87
- <p className={style.Intro}>
88
- Example code using the <code>@_linked</code> query DSL against
89
- your local Fuseki dataset. Edit{' '}
90
- <code>src/components/PersonOverview.tsx</code> to extend it.
91
- </p>
92
- <PersonList refreshRef={refreshRef} />
93
- <PersonAddForm onAdded={refresh} />
94
- </div>
95
- </PersonListRefreshProvider>
96
- );
97
- }
@@ -1,12 +0,0 @@
1
- // Small context that lets PersonPreview rows trigger a list refresh on
2
- // their parent PersonOverview without prop-drilling through the
3
- // linkedSetComponent's wrapped renderer.
4
- import React, { useContext } from 'react';
5
-
6
- const PersonListRefreshContext = React.createContext<() => void>(() => {});
7
-
8
- export const PersonListRefreshProvider = PersonListRefreshContext.Provider;
9
-
10
- export function usePersonListRefresh(): () => void {
11
- return useContext(PersonListRefreshContext);
12
- }