@jskit-ai/agent-docs 0.1.131 → 0.1.133
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/guide/agent/app-extras/assistant.md +29 -605
- package/guide/agent/app-extras/mobile-capacitor.md +29 -362
- package/guide/agent/app-extras/realtime.md +29 -277
- package/guide/agent/app-setup/a-more-interesting-shell.md +44 -815
- package/guide/agent/app-setup/authentication.md +43 -1073
- package/guide/agent/app-setup/console.md +26 -298
- package/guide/agent/app-setup/database-layer.md +110 -790
- package/guide/agent/app-setup/existing-application-migration.md +273 -0
- package/guide/agent/app-setup/initial-scaffolding.md +50 -784
- package/guide/agent/app-setup/multi-homing.md +39 -712
- package/guide/agent/app-setup/quickstart.md +43 -179
- package/guide/agent/app-setup/users.md +34 -353
- package/guide/agent/index.md +17 -23
- package/package.json +2 -2
- package/patterns/INDEX.md +7 -7
- package/patterns/child-cruds.md +3 -3
- package/patterns/client-requests.md +6 -6
- package/patterns/crud-authoring.md +94 -0
- package/patterns/crud-links.md +1 -1
- package/patterns/feature-package/PATTERN.md +108 -0
- package/patterns/feature-package/example/booking-engine/package.json +48 -0
- package/patterns/feature-package/example/booking-engine/src/server/BookingEngineProvider.js +33 -0
- package/patterns/feature-package/example/booking-engine/src/server/actions.js +26 -0
- package/patterns/feature-package/example/booking-engine/src/server/inputSchemas.js +19 -0
- package/patterns/feature-package/example/variations/AvailabilityEngineProvider.js +31 -0
- package/patterns/feature-package/example/variations/InvoiceRollupProvider.js +36 -0
- package/patterns/feature-package/example/variations/customKnexRepository.js +34 -0
- package/patterns/feature-package/example/variations/orchestratorService.js +23 -0
- package/patterns/filters.md +8 -8
- package/patterns/live-actions.md +5 -18
- package/patterns/minimal-foundation/PATTERN.md +98 -0
- package/patterns/minimal-foundation/example/.nvmrc +1 -0
- package/patterns/minimal-foundation/example/AGENTS.md +17 -0
- package/patterns/minimal-foundation/example/Procfile +2 -0
- package/patterns/minimal-foundation/example/app.json +14 -0
- package/patterns/minimal-foundation/example/bin/develop.js +71 -0
- package/patterns/minimal-foundation/example/bin/server.js +8 -0
- package/patterns/minimal-foundation/example/config/public.js +40 -0
- package/patterns/minimal-foundation/example/config/server.js +1 -0
- package/patterns/minimal-foundation/example/config/surfaceAccessPolicies.js +3 -0
- package/patterns/minimal-foundation/example/eslint.config.mjs +19 -0
- package/patterns/minimal-foundation/example/favicon.svg +7 -0
- package/patterns/minimal-foundation/example/gitignore +9 -0
- package/patterns/minimal-foundation/example/index.html +13 -0
- package/patterns/minimal-foundation/example/jsconfig.json +8 -0
- package/patterns/minimal-foundation/example/package.json +57 -0
- package/patterns/minimal-foundation/example/packages/main/package.json +42 -0
- package/patterns/minimal-foundation/example/packages/main/src/shared/index.js +10 -0
- package/patterns/minimal-foundation/example/packages/main/src/shared/schemas/index.js +22 -0
- package/patterns/minimal-foundation/example/playwright.config.mjs +31 -0
- package/patterns/minimal-foundation/example/server/lib/runtimeEnv.js +45 -0
- package/patterns/minimal-foundation/example/server/lib/surfaceRuntime.js +10 -0
- package/patterns/minimal-foundation/example/server.js +195 -0
- package/patterns/minimal-foundation/example/src/App.vue +13 -0
- package/patterns/minimal-foundation/example/src/main.js +85 -0
- package/patterns/minimal-foundation/example/src/pages/home/index.vue +48 -0
- package/patterns/minimal-foundation/example/src/pages/home.vue +13 -0
- package/patterns/minimal-foundation/example/src/views/NotFound.vue +13 -0
- package/patterns/minimal-foundation/example/tests/client/smoke.vitest.js +7 -0
- package/patterns/minimal-foundation/example/tests/e2e/base-shell.spec.ts +23 -0
- package/patterns/minimal-foundation/example/tests/server/smoke.test.js +16 -0
- package/patterns/minimal-foundation/example/vite.config.mjs +81 -0
- package/patterns/page-scaffolding.md +20 -17
- package/patterns/placements.md +17 -15
- package/patterns/row-policies.md +4 -5
- package/patterns/server-search.md +3 -3
- package/patterns/shell-foundation/PATTERN.md +104 -0
- package/patterns/shell-foundation/example/.nvmrc +1 -0
- package/patterns/shell-foundation/example/AGENTS.md +17 -0
- package/patterns/shell-foundation/example/Procfile +2 -0
- package/patterns/shell-foundation/example/app.json +14 -0
- package/patterns/shell-foundation/example/bin/develop.js +71 -0
- package/patterns/shell-foundation/example/bin/server.js +8 -0
- package/patterns/shell-foundation/example/config/public.js +40 -0
- package/patterns/shell-foundation/example/config/server.js +1 -0
- package/patterns/shell-foundation/example/config/surfaceAccessPolicies.js +3 -0
- package/patterns/shell-foundation/example/eslint.config.mjs +19 -0
- package/patterns/shell-foundation/example/favicon.svg +7 -0
- package/patterns/shell-foundation/example/gitignore +9 -0
- package/patterns/shell-foundation/example/index.html +13 -0
- package/patterns/shell-foundation/example/jsconfig.json +8 -0
- package/patterns/shell-foundation/example/package.json +59 -0
- package/patterns/shell-foundation/example/packages/main/package.json +56 -0
- package/patterns/shell-foundation/example/packages/main/src/client/index.js +9 -0
- package/patterns/shell-foundation/example/packages/main/src/client/providers/MainClientProvider.js +18 -0
- package/patterns/shell-foundation/example/packages/main/src/shared/index.js +10 -0
- package/patterns/shell-foundation/example/packages/main/src/shared/schemas/index.js +22 -0
- package/patterns/shell-foundation/example/playwright.config.mjs +31 -0
- package/patterns/shell-foundation/example/server/lib/runtimeEnv.js +45 -0
- package/patterns/shell-foundation/example/server/lib/surfaceRuntime.js +10 -0
- package/patterns/shell-foundation/example/server.js +195 -0
- package/patterns/shell-foundation/example/src/App.vue +11 -0
- package/patterns/shell-foundation/example/src/components/ShellLayout.vue +12 -0
- package/patterns/shell-foundation/example/src/components/menus/MenuLinkItem.vue +30 -0
- package/patterns/shell-foundation/example/src/components/menus/SurfaceAwareMenuLinkItem.vue +42 -0
- package/patterns/shell-foundation/example/src/components/menus/TabLinkItem.vue +42 -0
- package/patterns/shell-foundation/example/src/error.js +19 -0
- package/patterns/shell-foundation/example/src/main.js +85 -0
- package/patterns/shell-foundation/example/src/pages/home/index.vue +116 -0
- package/patterns/shell-foundation/example/src/pages/home/settings/general/index.vue +40 -0
- package/patterns/shell-foundation/example/src/pages/home/settings/index.vue +7 -0
- package/patterns/shell-foundation/example/src/pages/home/settings.vue +109 -0
- package/patterns/shell-foundation/example/src/pages/home.vue +20 -0
- package/patterns/shell-foundation/example/src/placement.js +56 -0
- package/patterns/shell-foundation/example/src/placementTopology.js +149 -0
- package/patterns/shell-foundation/example/src/views/NotFound.vue +13 -0
- package/patterns/shell-foundation/example/tests/client/smoke.vitest.js +7 -0
- package/patterns/shell-foundation/example/tests/e2e/adaptive-shell.spec.ts +10 -0
- package/patterns/shell-foundation/example/tests/e2e/base-shell.spec.ts +23 -0
- package/patterns/shell-foundation/example/tests/server/smoke.test.js +16 -0
- package/patterns/shell-foundation/example/vite.config.mjs +81 -0
- package/patterns/ui-contract.md +56 -0
- package/patterns/ui-testing.md +10 -12
- package/reference/autogen/KERNEL_MAP.md +29 -107
- package/reference/autogen/PATTERN_INDEX.md +230 -0
- package/reference/autogen/README.md +4 -8
- package/reference/autogen/packages/agent-docs.md +259 -0
- package/reference/autogen/packages/assistant-core.md +3 -3
- package/reference/autogen/packages/assistant-runtime.md +32 -17
- package/reference/autogen/packages/auth-core.md +31 -33
- package/reference/autogen/packages/auth-provider-local-core.md +4 -12
- package/reference/autogen/packages/auth-provider-local-db-core.md +4 -4
- package/reference/autogen/packages/auth-provider-supabase-core.md +14 -18
- package/reference/autogen/packages/auth-web.md +42 -22
- package/reference/autogen/packages/console-core.md +8 -25
- package/reference/autogen/packages/console-web.md +5 -5
- package/reference/autogen/packages/crud-core.md +61 -17
- package/reference/autogen/packages/database-runtime-mysql.md +12 -2
- package/reference/autogen/packages/database-runtime-postgres.md +12 -2
- package/reference/autogen/packages/database-runtime.md +26 -25
- package/reference/autogen/packages/google-rewarded-core.md +19 -104
- package/reference/autogen/packages/http-runtime.md +4 -8
- package/reference/autogen/packages/http-web.md +32 -0
- package/reference/autogen/packages/json-rest-api-core.md +4 -6
- package/reference/autogen/packages/kernel.md +109 -390
- package/reference/autogen/packages/mobile-capacitor.md +2 -13
- package/reference/autogen/packages/realtime.md +29 -26
- package/reference/autogen/packages/resource-crud-core.md +6 -0
- package/reference/autogen/packages/shell-web.md +69 -54
- package/reference/autogen/packages/storage-runtime.md +3 -3
- package/reference/autogen/packages/uploads-image-web.md +0 -1
- package/reference/autogen/packages/uploads-runtime.md +3 -3
- package/reference/autogen/packages/users-core.md +45 -90
- package/reference/autogen/packages/users-web.md +5 -7
- package/reference/autogen/packages/workspaces-core.md +53 -74
- package/reference/autogen/packages/workspaces-web.md +15 -16
- package/reference/autogen/tooling/jskit-catalog.md +34 -0
- package/reference/autogen/tooling/testUtils.md +4 -4
- package/skills/jskit/SKILL.md +38 -31
- package/skills/jskit/references/app-operations.md +68 -53
- package/skills/jskit/references/crud-operations.md +58 -106
- package/skills/jskit/references/material-3.md +1 -1
- package/skills/jskit/references/ui-operations.md +41 -44
- package/templates/app/AGENTS.md +7 -3
- package/guide/agent/app-setup/upgrade-beta-1-to-final.md +0 -252
- package/guide/agent/app-setup/working-with-the-jskit-cli.md +0 -325
- package/guide/agent/generators/advanced-cruds.md +0 -1935
- package/guide/agent/generators/crud-generators.md +0 -948
- package/guide/agent/generators/intro.md +0 -65
- package/guide/agent/generators/row-policies.md +0 -537
- package/guide/agent/generators/ui-generators.md +0 -690
- package/patterns/crud-scaffolding.md +0 -198
- package/patterns/generated-ui-contract-tracking.md +0 -66
- package/reference/autogen/packages/assistant.md +0 -68
- package/reference/autogen/packages/crud-server-generator.md +0 -215
- package/reference/autogen/packages/crud-ui-generator.md +0 -192
- package/reference/autogen/packages/feature-server-generator.md +0 -65
- package/reference/autogen/packages/ui-generator.md +0 -127
- package/reference/autogen/tooling/create-app.md +0 -317
- package/reference/autogen/tooling/jskit-cli.md +0 -933
- package/reference/autogen/tooling/test-support.md +0 -27
package/patterns/filters.md
CHANGED
|
@@ -19,9 +19,9 @@ Ask first:
|
|
|
19
19
|
- whether there are presets such as "Today", "Last 7 Days", or "Only Archived"
|
|
20
20
|
|
|
21
21
|
Default JSKIT client pattern:
|
|
22
|
-
1.
|
|
22
|
+
1. CRUD list pages use a page-local `listFilters.js` file next to `index.vue`.
|
|
23
23
|
2. Put client filter definitions in that file with `defineCrudListFilters(...)`.
|
|
24
|
-
3. The
|
|
24
|
+
3. The app-owned `index.vue` passes `listFilters` into `useCrudListScreen(...)`; the shared list screen builds `useCrudListFilters(listFilters)`, passes `filterRuntime.queryParams` into the list request, and renders `CrudListFilterSurface`.
|
|
25
25
|
4. If `listFilters` is empty, the filter surface renders nothing and the page behaves like a normal searchable list.
|
|
26
26
|
5. The AI/app author is responsible for ensuring the server accepts and applies the query params declared in `listFilters.js`.
|
|
27
27
|
6. For lookup-backed filters, use `useCrudListFilterLookups(...)` when the page needs remote options or readable chip labels.
|
|
@@ -47,7 +47,7 @@ const listFilters = defineCrudListFilters({
|
|
|
47
47
|
});
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
Client shape:
|
|
51
51
|
- `src/pages/<surface>/<resource>/listFilters.js`
|
|
52
52
|
- `const listFilters = defineCrudListFilters({ ... })`
|
|
53
53
|
- `useCrudListScreen({ ..., listFilters })`
|
|
@@ -77,8 +77,8 @@ Exact file checklist:
|
|
|
77
77
|
`listFilterQueryValidator`
|
|
78
78
|
- update the provider's `createJsonRestResourceScopeOptions(...)` call so `searchSchema: listFilterContract.jsonRestSearchSchema` is merged into the internal JSON REST resource
|
|
79
79
|
- update `packages/<crud>/src/server/repository.js` so list queries pass `listFilterContract.toJsonRestQuery(query)` into `buildJsonRestQueryParams(...)`
|
|
80
|
-
- update the
|
|
81
|
-
- for lookup-backed filters, wire `useCrudListFilterLookups(...)` beside the existing
|
|
80
|
+
- update the page-local `listFilters.js` first; only edit `index.vue` if a specialist lookup label/runtime integration is needed
|
|
81
|
+
- for lookup-backed filters, wire `useCrudListFilterLookups(...)` beside the existing filter runtime instead of replacing `CrudListFilterSurface`
|
|
82
82
|
|
|
83
83
|
Standard route and action query composition:
|
|
84
84
|
|
|
@@ -154,7 +154,7 @@ Avoid:
|
|
|
154
154
|
- appending a list-filter validator after `createStandardCrudListQueryValidators(...)` when it belongs in the dedicated `listFilterQueryValidator` option
|
|
155
155
|
- hand-rolled preset apply/reset/active-state helpers when `useCrudListFilters(..., { presets })`, `applyPreset(...)`, and `matchesPreset(...)` fit
|
|
156
156
|
- per-screen `useList()` wrappers for lookup-backed filters when `useCrudListFilterLookups(...)` fits
|
|
157
|
-
- editing
|
|
157
|
+
- editing `.vue` files just to add basic filter controls; use the page-local `listFilters.js` seam first
|
|
158
158
|
- overloading `q` with structured filter meaning
|
|
159
159
|
- inline filter-definition objects passed into `useCrudListFilters(...)`, `createCrudListFilters(...)`, or `createCrudListFilterContract(...)`; keep definitions in a named module
|
|
160
160
|
- assigning a default to `filterRuntime.values` after `useCrudListScreen(...)` has started; that changes the query after construction and can issue a second initial request
|
|
@@ -162,7 +162,7 @@ Avoid:
|
|
|
162
162
|
Good shape:
|
|
163
163
|
- `src/pages/home/customers/listFilters.js`
|
|
164
164
|
- `const listFilters = defineCrudListFilters({ status: { type: "enum", ... } })`
|
|
165
|
-
-
|
|
165
|
+
- page passes `listFilters` into `useCrudListScreen(...)`
|
|
166
166
|
- shared screen runtime passes `filterRuntime.queryParams` into the list request
|
|
167
167
|
- `packages/receivals/src/shared/receivalListFilters.js`
|
|
168
168
|
- `createCrudListFilterContract(RECEIVAL_LIST_FILTER_DEFINITIONS, { columns, invalidValues: "reject" })`
|
|
@@ -178,7 +178,7 @@ Preset contract notes:
|
|
|
178
178
|
- if the URL contains `status=archived&status=bogus`, a preset for only `archived` should not render as active while the `bogus` chip is still visible
|
|
179
179
|
|
|
180
180
|
Review checks:
|
|
181
|
-
- one filter definition source of truth:
|
|
181
|
+
- one filter definition source of truth: page-local `listFilters.js` for client-only filters, or a shared CRUD-package module when server code imports the same definitions
|
|
182
182
|
- server validator, JSON REST search schema, and repository query projection derived from that source through `createCrudListFilterContract(...)`
|
|
183
183
|
- route and action boundaries independently compose
|
|
184
184
|
`createStandardCrudListQueryValidators(...)`, using the dedicated
|
package/patterns/live-actions.md
CHANGED
|
@@ -12,26 +12,13 @@ Rules:
|
|
|
12
12
|
- Prefer `useCommand()` for live actions.
|
|
13
13
|
- Prefer form runtimes such as `useCrudAddEdit()` or `useAddEdit()` for real forms.
|
|
14
14
|
- Prefer `useCrudList()` and `useCrudView()` for routed CRUD loading and URL resolution.
|
|
15
|
-
- For ordinary routed CRUD record deletion,
|
|
16
|
-
of rebuilding it page by page
|
|
17
|
-
|
|
18
|
-
```bash
|
|
19
|
-
npx --no-install jskit generate crud-ui-generator crud notes \
|
|
20
|
-
--resource-file packages/notes/src/shared/noteResource.js \
|
|
21
|
-
--id-param noteId \
|
|
22
|
-
--display-fields title,body \
|
|
23
|
-
--parent-title contextual \
|
|
24
|
-
--navigation-role primary \
|
|
25
|
-
--delete-confirmation
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
`--delete-confirmation` requires generated list and view pages plus a shared
|
|
29
|
-
resource with a `DELETE` operation. It extends the view through the public
|
|
30
|
-
`CrudViewScreen` `actions` slot with `CrudDeleteAction` and wires it to
|
|
15
|
+
- For ordinary routed CRUD record deletion, start from the package-owned CRUD
|
|
16
|
+
UI pattern instead of rebuilding it page by page. Its view screen uses the
|
|
17
|
+
public `CrudViewScreen` `actions` slot with `CrudDeleteAction` and wires it to
|
|
31
18
|
`useCrudDeleteAction()`: the shared component owns the alert dialog,
|
|
32
19
|
`useCommand()` owns the request state, the shared resource owns the DELETE
|
|
33
20
|
contract, and successful deletion invalidates the list query and navigates
|
|
34
|
-
to the
|
|
21
|
+
to the list route.
|
|
35
22
|
|
|
36
23
|
Good live-action pattern:
|
|
37
24
|
|
|
@@ -51,5 +38,5 @@ Avoid:
|
|
|
51
38
|
|
|
52
39
|
- manually hand-rolling fetch logic for a standard live action when `useCommand()` fits
|
|
53
40
|
- inspecting private `http-web` internals or creating a page-local transport
|
|
54
|
-
for
|
|
41
|
+
for standard record deletion
|
|
55
42
|
- pushing derived write rules into the client just because the action is small
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: app/minimal-foundation
|
|
3
|
+
title: Minimal JSKIT application foundation
|
|
4
|
+
summary: A concrete Fastify, Vue, and JSKIT application foundation for products that do not yet need the full adaptive shell.
|
|
5
|
+
keywords: app, fastify, foundation, minimal, server, vite, vue
|
|
6
|
+
requires: @jskit-ai/http-runtime, @jskit-ai/kernel
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Minimal JSKIT application foundation
|
|
10
|
+
|
|
11
|
+
## Use when
|
|
12
|
+
|
|
13
|
+
Use this pattern when establishing a new JSKIT web application in an existing
|
|
14
|
+
project repository and the product does not yet need the full adaptive shell,
|
|
15
|
+
settings navigation, or placement topology. It provides a working server,
|
|
16
|
+
client bootstrap, app-local provider package, one public surface, linting, unit
|
|
17
|
+
tests, browser tests, and the normal build entrypoints.
|
|
18
|
+
|
|
19
|
+
The example is a concrete application named `reading-room`. Copy the useful
|
|
20
|
+
files into the project root, rename the application in normal source and
|
|
21
|
+
package metadata, and then edit the product-facing page. The files become
|
|
22
|
+
ordinary application source immediately.
|
|
23
|
+
|
|
24
|
+
## Do not use when
|
|
25
|
+
|
|
26
|
+
Do not use this pattern when the application already has an established
|
|
27
|
+
server/client foundation. Do not replace a working app merely to make it
|
|
28
|
+
resemble the example. Prefer the shell foundation when responsive navigation,
|
|
29
|
+
settings, or placement contributions are already clear requirements.
|
|
30
|
+
|
|
31
|
+
## Product decisions
|
|
32
|
+
|
|
33
|
+
Decide the application name, first useful route, public versus authenticated
|
|
34
|
+
surface access, and whether the product needs the adaptive shell. These are
|
|
35
|
+
product decisions for the user and agent; this pattern does not ask a
|
|
36
|
+
questionnaire or infer tenancy, authentication, or database requirements.
|
|
37
|
+
|
|
38
|
+
## Invariants
|
|
39
|
+
|
|
40
|
+
- Preserve `.git` and all unrelated project and agent context.
|
|
41
|
+
- Refuse or resolve real destination-file collisions before copying.
|
|
42
|
+
- Keep `packages/main` limited to app composition and lightweight glue.
|
|
43
|
+
- Use package public APIs; do not deep-import package internals.
|
|
44
|
+
- Keep one server entry, one client bootstrap, and explicit surface access.
|
|
45
|
+
- Keep one app-owned `npm run develop` entry that runs the API on loopback and
|
|
46
|
+
Vite on the host-supplied preview port; do not require a host to infer or
|
|
47
|
+
supervise framework-specific processes.
|
|
48
|
+
- Treat copied files as app-owned source. Do not add provenance, ownership
|
|
49
|
+
markers, receipts, ledgers, or operation-history state.
|
|
50
|
+
- Keep browser dependencies aligned with the execution environment that will
|
|
51
|
+
run the tests. Vibe64 supplies its exact managed Playwright version.
|
|
52
|
+
|
|
53
|
+
## Framework APIs
|
|
54
|
+
|
|
55
|
+
The example composes `@jskit-ai/kernel` for provider/runtime composition and
|
|
56
|
+
`@jskit-ai/http-runtime` for the web runtime. `packages/main` demonstrates the
|
|
57
|
+
app-local provider boundary. Vite, Vue Router, Pinia, Vuetify, Fastify, and Vue
|
|
58
|
+
Query remain normal application dependencies.
|
|
59
|
+
|
|
60
|
+
## Example files
|
|
61
|
+
|
|
62
|
+
`example/` is a complete concrete application tree. Copy only after inspecting
|
|
63
|
+
collisions. Rename `example/gitignore` to `.gitignore` in the application;
|
|
64
|
+
the neutral filename ensures npm publishes the reference asset. Managed preview
|
|
65
|
+
identity belongs to the authentication surface pattern, not the neutral
|
|
66
|
+
foundation.
|
|
67
|
+
|
|
68
|
+
Important starting points are:
|
|
69
|
+
|
|
70
|
+
- `example/package.json`
|
|
71
|
+
- `example/server.js`, `example/bin/server.js`, and `example/bin/develop.js`
|
|
72
|
+
- `example/src/main.js` and `example/src/App.vue`
|
|
73
|
+
- `example/config/public.js`
|
|
74
|
+
- `example/packages/main/`
|
|
75
|
+
- `example/tests/`
|
|
76
|
+
|
|
77
|
+
## Variation points
|
|
78
|
+
|
|
79
|
+
Rename the package and title, replace the home page with the first real
|
|
80
|
+
product surface, add capabilities through their owning packages, and change
|
|
81
|
+
surface access deliberately. Add authentication, database, CRUD, shell, or
|
|
82
|
+
mobile patterns only when chosen. Do not pre-emptively include them.
|
|
83
|
+
|
|
84
|
+
## Verification
|
|
85
|
+
|
|
86
|
+
After adapting the example, install the declared packages once and run
|
|
87
|
+
`npm run develop` for the live application. Then run the application's lint,
|
|
88
|
+
server tests, client tests, production build, and focused browser smoke.
|
|
89
|
+
Confirm `/api/health` and the first product route.
|
|
90
|
+
|
|
91
|
+
## Avoid
|
|
92
|
+
|
|
93
|
+
- Do not run a scaffold questionnaire.
|
|
94
|
+
- Do not create a temporary app and copy its result over the project.
|
|
95
|
+
- Do not force-overwrite an existing repository.
|
|
96
|
+
- Do not keep `reading-room` names that no longer describe the product.
|
|
97
|
+
- Do not add a hidden file recording that this pattern was copied.
|
|
98
|
+
- Do not turn the example into a field interpolation language.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
26
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# App Agent Instructions
|
|
2
|
+
|
|
3
|
+
Use current project context, JSKIT public APIs, and the installed JSKIT pattern
|
|
4
|
+
index as the source of truth for application work.
|
|
5
|
+
|
|
6
|
+
Recommended references:
|
|
7
|
+
|
|
8
|
+
- `node_modules/@jskit-ai/agent-docs/guide/agent/index.md`
|
|
9
|
+
- `node_modules/@jskit-ai/agent-docs/patterns/INDEX.md`
|
|
10
|
+
|
|
11
|
+
Before database, schema, CRUD, repository, or persistence work, inspect the
|
|
12
|
+
relevant package-owned pattern from
|
|
13
|
+
`node_modules/@jskit-ai/agent-docs/reference/autogen/PATTERN_INDEX.md`.
|
|
14
|
+
|
|
15
|
+
Copied pattern source is ordinary application source. Do not add generator
|
|
16
|
+
provenance, receipts, completion ledgers, or tooling-operation history. Keep
|
|
17
|
+
changes scoped to the user request and verify runtime behavior directly.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { startServer } from "../server.js";
|
|
3
|
+
|
|
4
|
+
const LOOPBACK_HOST = "127.0.0.1";
|
|
5
|
+
|
|
6
|
+
function requiredPort(value, fallback = 3000) {
|
|
7
|
+
const normalized = String(value || "").trim();
|
|
8
|
+
const parsed = Number.parseInt(normalized || String(fallback), 10);
|
|
9
|
+
if (!Number.isInteger(parsed) || parsed < 1 || parsed > 65_535) {
|
|
10
|
+
throw new Error(`Invalid development port: ${normalized || "(empty)"}.`);
|
|
11
|
+
}
|
|
12
|
+
return parsed;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function waitForChild(child) {
|
|
16
|
+
return new Promise((resolve, reject) => {
|
|
17
|
+
child.once("error", reject);
|
|
18
|
+
child.once("exit", (code, signal) => resolve({ code, signal }));
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const previewHost = String(process.env.HOST || "").trim() || "0.0.0.0";
|
|
23
|
+
const previewPort = requiredPort(process.env.PORT);
|
|
24
|
+
let apiServer = null;
|
|
25
|
+
let viteProcess = null;
|
|
26
|
+
let requestedSignal = "";
|
|
27
|
+
|
|
28
|
+
function requestShutdown(signal) {
|
|
29
|
+
requestedSignal = signal;
|
|
30
|
+
if (viteProcess && !viteProcess.killed) {
|
|
31
|
+
viteProcess.kill(signal);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
process.once("SIGINT", () => requestShutdown("SIGINT"));
|
|
36
|
+
process.once("SIGTERM", () => requestShutdown("SIGTERM"));
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
apiServer = await startServer({ host: LOOPBACK_HOST, port: 0 });
|
|
40
|
+
const apiPort = requiredPort(apiServer.server.address()?.port);
|
|
41
|
+
const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
42
|
+
viteProcess = spawn(
|
|
43
|
+
npmCommand,
|
|
44
|
+
["run", "dev", "--", "--host", previewHost, "--port", String(previewPort), "--strictPort"],
|
|
45
|
+
{
|
|
46
|
+
cwd: process.cwd(),
|
|
47
|
+
env: {
|
|
48
|
+
...process.env,
|
|
49
|
+
HOST: previewHost,
|
|
50
|
+
PORT: String(previewPort),
|
|
51
|
+
VITE_API_PROXY_TARGET: `http://${LOOPBACK_HOST}:${apiPort}`,
|
|
52
|
+
VITE_DEV_PORT: String(previewPort)
|
|
53
|
+
},
|
|
54
|
+
stdio: "inherit"
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
const result = await waitForChild(viteProcess);
|
|
59
|
+
if (!requestedSignal && result.code !== 0) {
|
|
60
|
+
throw new Error(
|
|
61
|
+
`Vite development server stopped unexpectedly (${result.signal || `exit ${result.code ?? "unknown"}`}).`
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error("Failed to start the development application:", error);
|
|
66
|
+
process.exitCode = 1;
|
|
67
|
+
} finally {
|
|
68
|
+
if (apiServer) {
|
|
69
|
+
await apiServer.close().catch(() => {});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { surfaceAccessPolicies } from "./surfaceAccessPolicies.js";
|
|
2
|
+
|
|
3
|
+
export const config = {};
|
|
4
|
+
|
|
5
|
+
config.surfaceModeAll = "all";
|
|
6
|
+
config.surfaceDefaultId = "home";
|
|
7
|
+
config.webRootAllowed = "no";
|
|
8
|
+
config.surfaceAccessPolicies = surfaceAccessPolicies;
|
|
9
|
+
config.mobile = {
|
|
10
|
+
enabled: false,
|
|
11
|
+
strategy: "",
|
|
12
|
+
appId: "",
|
|
13
|
+
appName: "",
|
|
14
|
+
assetMode: "bundled",
|
|
15
|
+
devServerUrl: "",
|
|
16
|
+
apiBaseUrl: "",
|
|
17
|
+
auth: {
|
|
18
|
+
callbackPath: "/auth/login",
|
|
19
|
+
customScheme: "",
|
|
20
|
+
appLinkDomains: []
|
|
21
|
+
},
|
|
22
|
+
android: {
|
|
23
|
+
packageName: "",
|
|
24
|
+
minSdk: 26,
|
|
25
|
+
targetSdk: 35,
|
|
26
|
+
versionCode: 1,
|
|
27
|
+
versionName: "1.0.0"
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
config.surfaceDefinitions = {};
|
|
31
|
+
config.surfaceDefinitions.home = {
|
|
32
|
+
id: "home",
|
|
33
|
+
label: "Home",
|
|
34
|
+
pagesRoot: "home",
|
|
35
|
+
enabled: true,
|
|
36
|
+
requiresAuth: false,
|
|
37
|
+
requiresWorkspace: false,
|
|
38
|
+
accessPolicyId: "public",
|
|
39
|
+
origin: ""
|
|
40
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const config = {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { baseConfig, nodeConfig, vueConfig, webConfig } from "@jskit-ai/config-eslint/server";
|
|
2
|
+
|
|
3
|
+
export default [
|
|
4
|
+
{
|
|
5
|
+
ignores: ["dist/**", "node_modules/**", "coverage/**", "test-results/**", ".jskit/**"]
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
files: ["src/pages/**/*.vue"],
|
|
9
|
+
languageOptions: {
|
|
10
|
+
globals: {
|
|
11
|
+
definePage: "readonly"
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
...baseConfig,
|
|
16
|
+
...vueConfig,
|
|
17
|
+
...webConfig,
|
|
18
|
+
...nodeConfig
|
|
19
|
+
];
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
7
|
+
<title>Reading Room</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="app"></div>
|
|
11
|
+
<script type="module" src="/src/main.js"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "reading-room",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "Minimal JSKIT base app (Fastify + Vue)",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": "26.x"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"server": "node ./bin/server.js",
|
|
12
|
+
"server:all": "node ./bin/server.js",
|
|
13
|
+
"server:home": "SERVER_SURFACE=home node ./bin/server.js",
|
|
14
|
+
"start": "node ./bin/server.js",
|
|
15
|
+
"develop": "node ./bin/develop.js",
|
|
16
|
+
"dev": "vite",
|
|
17
|
+
"dev:all": "vite",
|
|
18
|
+
"dev:home": "VITE_SURFACE=home vite",
|
|
19
|
+
"build": "vite build",
|
|
20
|
+
"build:all": "vite build",
|
|
21
|
+
"build:home": "VITE_SURFACE=home vite build",
|
|
22
|
+
"preview": "vite preview",
|
|
23
|
+
"lint": "eslint .",
|
|
24
|
+
"test": "node --test",
|
|
25
|
+
"test:client": "vitest run tests/client",
|
|
26
|
+
"test:e2e": "playwright test tests/e2e",
|
|
27
|
+
"verify": "npm run lint && npm run test && npm run test:client && npm run build"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@local/main": "file:packages/main",
|
|
31
|
+
"@fastify/static": "^10.1.3",
|
|
32
|
+
"@jskit-ai/kernel": "0.1.161",
|
|
33
|
+
"@tanstack/vue-query": "^5.101.0",
|
|
34
|
+
"fastify": "^5.8.5",
|
|
35
|
+
"json-rest-schema": "^1.0.17",
|
|
36
|
+
"pinia": "^3.0.4",
|
|
37
|
+
"vue": "^3.5.38",
|
|
38
|
+
"vue-router": "^5.1.0",
|
|
39
|
+
"vuetify": "^4.1.2",
|
|
40
|
+
"@jskit-ai/http-runtime": "0.1.159"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@jskit-ai/agent-docs": "0.1.133",
|
|
44
|
+
"@jskit-ai/config-eslint": "0.1.158",
|
|
45
|
+
"@playwright/test": "1.61.1",
|
|
46
|
+
"@vitejs/plugin-vue": "^6.0.7",
|
|
47
|
+
"eslint": "^10.8.0",
|
|
48
|
+
"vite": "^8.2.1",
|
|
49
|
+
"vite-plugin-vuetify": "^2.1.3",
|
|
50
|
+
"vitest": "^4.1.9"
|
|
51
|
+
},
|
|
52
|
+
"allowScripts": {
|
|
53
|
+
"fsevents@2.3.2": true,
|
|
54
|
+
"fsevents@2.3.3": true,
|
|
55
|
+
"vue-demi@0.14.10": true
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@local/main",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
"./shared": "./src/shared/index.js"
|
|
8
|
+
},
|
|
9
|
+
"description": "App-local runtime composition and lightweight glue.",
|
|
10
|
+
"jskit": {
|
|
11
|
+
"kind": "runtime",
|
|
12
|
+
"capabilities": {
|
|
13
|
+
"provides": [],
|
|
14
|
+
"requires": []
|
|
15
|
+
},
|
|
16
|
+
"metadata": {
|
|
17
|
+
"jskit": {
|
|
18
|
+
"ownershipGuidance": {
|
|
19
|
+
"title": "App-local main lane",
|
|
20
|
+
"summary": "Keep @local/main focused on app composition and lightweight glue. Substantial server features should become dedicated packages instead of growing inside packages/main.",
|
|
21
|
+
"responsibilities": [
|
|
22
|
+
"packages/main server code: bootstraps app-local configuration and lightweight wiring only",
|
|
23
|
+
"substantial server features: author a dedicated app-local package from the relevant framework pattern",
|
|
24
|
+
"packages/main: do not add service/controller/route/repository feature trees here"
|
|
25
|
+
],
|
|
26
|
+
"examples": [
|
|
27
|
+
"packages/booking-engine owns booking operations",
|
|
28
|
+
"packages/availability-engine owns availability orchestration"
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"server": {
|
|
33
|
+
"routes": []
|
|
34
|
+
},
|
|
35
|
+
"ui": {
|
|
36
|
+
"routes": [],
|
|
37
|
+
"elements": [],
|
|
38
|
+
"overrides": []
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* App-local shared transport validators/resources live here.
|
|
3
|
+
* Dedicated feature packages should keep their own schemas with the feature.
|
|
4
|
+
*
|
|
5
|
+
* Example:
|
|
6
|
+
* import { createSchema } from "json-rest-schema";
|
|
7
|
+
*
|
|
8
|
+
* export const helloQuerySchema = createSchema({
|
|
9
|
+
* name: { type: "string", minLength: 1, maxLength: 80 }
|
|
10
|
+
* });
|
|
11
|
+
*
|
|
12
|
+
* export const helloResponseSchema = {
|
|
13
|
+
* type: "object",
|
|
14
|
+
* additionalProperties: false,
|
|
15
|
+
* required: ["ok", "message"],
|
|
16
|
+
* properties: {
|
|
17
|
+
* ok: { type: "boolean" },
|
|
18
|
+
* message: { type: "string", minLength: 1 }
|
|
19
|
+
* }
|
|
20
|
+
* };
|
|
21
|
+
*/
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { defineConfig } from "@playwright/test";
|
|
2
|
+
|
|
3
|
+
const managedBaseUrl = String(process.env.PLAYWRIGHT_BASE_URL || "")
|
|
4
|
+
.trim()
|
|
5
|
+
.replace(/\/+$/u, "");
|
|
6
|
+
const baseURL = managedBaseUrl || "http://127.0.0.1:4173";
|
|
7
|
+
const storageState = String(process.env.VIBE64_PLAYWRIGHT_STORAGE_STATE || "").trim();
|
|
8
|
+
|
|
9
|
+
export default defineConfig({
|
|
10
|
+
testDir: "./tests/e2e",
|
|
11
|
+
timeout: 60_000,
|
|
12
|
+
expect: {
|
|
13
|
+
timeout: 10_000
|
|
14
|
+
},
|
|
15
|
+
use: {
|
|
16
|
+
baseURL,
|
|
17
|
+
headless: true,
|
|
18
|
+
...(storageState ? { storageState } : {})
|
|
19
|
+
},
|
|
20
|
+
...(managedBaseUrl ? {} : {
|
|
21
|
+
webServer: {
|
|
22
|
+
command: "npm run build && node ./bin/server.js",
|
|
23
|
+
env: {
|
|
24
|
+
PORT: "4173"
|
|
25
|
+
},
|
|
26
|
+
url: `${baseURL}/api/health`,
|
|
27
|
+
reuseExistingServer: true,
|
|
28
|
+
timeout: 180_000
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { surfaceRuntime } from "./surfaceRuntime.js";
|
|
3
|
+
|
|
4
|
+
const require = createRequire(import.meta.url);
|
|
5
|
+
|
|
6
|
+
function toPort(value, fallback = 3000) {
|
|
7
|
+
const parsed = Number.parseInt(String(value || "").trim(), 10);
|
|
8
|
+
if (Number.isInteger(parsed) && parsed > 0) {
|
|
9
|
+
return parsed;
|
|
10
|
+
}
|
|
11
|
+
return fallback;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let envLoaded = false;
|
|
15
|
+
|
|
16
|
+
function ensureRuntimeEnvLoaded() {
|
|
17
|
+
if (envLoaded) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
const dotenvModule = require("dotenv");
|
|
22
|
+
const loadDotEnv = dotenvModule?.config;
|
|
23
|
+
if (typeof loadDotEnv === "function") {
|
|
24
|
+
loadDotEnv();
|
|
25
|
+
}
|
|
26
|
+
} catch {
|
|
27
|
+
// dotenv is optional in base-shell; bundles can add it when needed.
|
|
28
|
+
}
|
|
29
|
+
envLoaded = true;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function resolveRuntimeEnv() {
|
|
33
|
+
ensureRuntimeEnvLoaded();
|
|
34
|
+
const serverSurface = surfaceRuntime.normalizeSurfaceMode(
|
|
35
|
+
process.env.JSKIT_SERVER_SURFACE || process.env.SERVER_SURFACE
|
|
36
|
+
);
|
|
37
|
+
return {
|
|
38
|
+
...process.env,
|
|
39
|
+
SERVER_SURFACE: serverSurface,
|
|
40
|
+
PORT: toPort(process.env.PORT, 3000),
|
|
41
|
+
HOST: String(process.env.HOST || "").trim() || "0.0.0.0"
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export { resolveRuntimeEnv };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { createSurfaceRuntime } from "@jskit-ai/kernel/shared/surface/runtime";
|
|
2
|
+
import { config } from "../../config/public.js";
|
|
3
|
+
|
|
4
|
+
const surfaceRuntime = createSurfaceRuntime({
|
|
5
|
+
allMode: config.surfaceModeAll,
|
|
6
|
+
surfaces: config.surfaceDefinitions,
|
|
7
|
+
defaultSurfaceId: config.surfaceDefaultId
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export { surfaceRuntime };
|