@jskit-ai/agent-docs 0.1.283 → 0.1.285
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 +14 -2
- package/guide/agent/app-extras/realtime.md +38 -1
- package/guide/agent/app-setup/authentication.md +76 -14
- package/guide/agent/app-setup/console.md +8 -0
- package/guide/agent/app-setup/database-layer.md +23 -103
- package/guide/agent/app-setup/existing-application-migration.md +134 -72
- package/guide/agent/app-setup/multi-homing.md +94 -32
- package/guide/agent/app-setup/quickstart.md +1 -1
- package/guide/agent/app-setup/run-an-accounts-hub.md +1 -1
- package/guide/agent/app-setup/upgrading-jskit.md +17 -3
- package/guide/agent/app-setup/users.md +8 -5
- package/guide/agent/framework/application-operations.md +1 -1
- package/guide/agent/framework/crud-operations.md +63 -45
- package/guide/agent/framework/data-access.md +1207 -0
- package/guide/agent/framework/sanity-checks.md +26 -27
- package/guide/agent/framework/typed-features.md +117 -248
- package/guide/agent/index.md +2 -0
- package/package.json +6 -3
- package/patterns/feature-package/PATTERN.md +25 -17
- package/patterns/feature-package/example/booking-engine/package.json +1 -1
- package/patterns/feature-package/example/variations/InvoiceRollupFeature.js +6 -7
- package/patterns/feature-package/example/variations/invoiceResource.js +15 -0
- package/patterns/feature-package/example/variations/invoiceRollupActions.js +4 -4
- package/patterns/feature-package/example/variations/ownedTableRepository.js +27 -0
- package/patterns/feature-package/example/variations/types.js +1 -1
- package/patterns/minimal-foundation/example/AGENTS.md +4 -0
- package/patterns/minimal-foundation/example/package.json +4 -4
- package/patterns/minimal-foundation/example/server.js +4 -1
- package/patterns/shell-foundation/example/AGENTS.md +4 -0
- package/patterns/shell-foundation/example/package.json +5 -5
- package/patterns/shell-foundation/example/packages/main/package.json +1 -1
- package/patterns/shell-foundation/example/server.js +4 -1
- package/reference/autogen/KERNEL_MAP.md +3 -1
- package/reference/autogen/PATTERN_INDEX.md +70 -59
- package/reference/autogen/README.md +1 -1
- package/reference/autogen/packages/agent-docs.md +7 -3
- package/reference/autogen/packages/agent-runtime.md +48 -11
- package/reference/autogen/packages/architecture-inspector.md +6 -2
- package/reference/autogen/packages/assistant-core.md +4 -4
- package/reference/autogen/packages/assistant-runtime.md +33 -13
- package/reference/autogen/packages/auth-provider-local-core.md +3 -1
- package/reference/autogen/packages/auth-provider-local-db-core.md +69 -14
- package/reference/autogen/packages/auth-provider-oidc-core.md +5 -1
- package/reference/autogen/packages/auth-provider-supabase-core.md +1 -1
- package/reference/autogen/packages/connectors-core.md +22 -2
- package/reference/autogen/packages/console-core.md +9 -5
- package/reference/autogen/packages/crud-core.md +45 -175
- package/reference/autogen/packages/database-runtime-mysql.md +0 -26
- package/reference/autogen/packages/database-runtime.md +11 -33
- package/reference/autogen/packages/http-runtime.md +3 -3
- package/reference/autogen/packages/http-web.md +12 -0
- package/reference/autogen/packages/kernel.md +27 -2
- package/reference/autogen/packages/oidc-issuer-core.md +4 -0
- package/reference/autogen/packages/payments-core.md +28 -6
- package/reference/autogen/packages/realtime.md +15 -6
- package/reference/autogen/packages/resource-core.md +32 -5
- package/reference/autogen/packages/resource-crud-core.md +30 -34
- package/reference/autogen/packages/resource-runtime.md +220 -0
- package/reference/autogen/packages/rewarded-core.md +16 -10
- package/reference/autogen/packages/shell-web.md +1 -0
- package/reference/autogen/packages/users-core.md +33 -14
- package/reference/autogen/packages/workspaces-core.md +17 -10
- package/reference/autogen/tooling/config-eslint.md +74 -0
- package/reference/autogen/tooling/jskit-catalog.md +50 -1
- package/reference/autogen/tooling/jskit-release.md +5 -0
- package/skills/jskit/SKILL.md +4 -1
- package/skills/jskit/references/app-operations.md +1 -1
- package/skills/jskit/references/crud-operations.md +62 -44
- package/skills/jskit/references/data-access.md +1202 -0
- package/skills/jskit/references/database-layer.md +411 -0
- package/skills/jskit/references/existing-application-migration.md +134 -72
- package/skills/jskit/references/heuristics/INDEX.md +6 -4
- package/skills/jskit/references/heuristics/crud-authoring.md +26 -15
- package/skills/jskit/references/heuristics/data-access.md +19 -0
- package/skills/jskit/references/heuristics/filters.md +6 -6
- package/skills/jskit/references/heuristics/row-policies.md +40 -16
- package/skills/jskit/references/heuristics/server-search.md +30 -42
- package/skills/jskit/references/heuristics/table-resource-fields.md +78 -0
- package/skills/jskit/references/heuristics/typed-features.md +3 -3
- package/skills/jskit/references/multi-homing.md +94 -32
- package/skills/jskit/references/pattern-index.md +70 -59
- package/skills/jskit/references/patterns/app/minimal-foundation/example/AGENTS.md +4 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/package.json +4 -4
- package/skills/jskit/references/patterns/app/minimal-foundation/example/server.js +4 -1
- package/skills/jskit/references/patterns/app/shell-foundation/example/AGENTS.md +4 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/package.json +5 -5
- package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/package.json +1 -1
- package/skills/jskit/references/patterns/app/shell-foundation/example/server.js +4 -1
- package/skills/jskit/references/patterns/assistant/assistant-surface/PATTERN.md +5 -2
- package/skills/jskit/references/patterns/auth/accounts-hub/example/package.json +3 -2
- package/skills/jskit/references/patterns/auth/auth-surface/PATTERN.md +15 -0
- package/skills/jskit/references/patterns/auth/oidc-sign-in/example/package.json +2 -2
- package/skills/jskit/references/patterns/auth/supabase-auth/example/package.json +1 -1
- package/skills/jskit/references/patterns/connectors/calendar-cli/example/package.json +4 -4
- package/skills/jskit/references/patterns/crud/crud-contract/PATTERN.md +133 -0
- package/skills/jskit/references/patterns/crud/crud-contract/example/bookResource.js +74 -0
- package/skills/jskit/references/patterns/crud/{json-api-resource-package → crud-feature-package}/PATTERN.md +69 -37
- package/skills/jskit/references/patterns/crud/{json-api-resource-package → crud-feature-package}/example/packages/books/package.json +5 -4
- package/skills/jskit/references/patterns/crud/crud-feature-package/example/packages/books/src/server/BooksFeature.js +13 -0
- package/skills/jskit/references/patterns/crud/crud-feature-package/example/packages/books/src/shared/bookResource.js +74 -0
- package/skills/jskit/references/patterns/crud/crud-feature-package/example/packages/books/src/shared/index.js +1 -0
- package/skills/jskit/references/patterns/crud/crud-screen-set/PATTERN.md +26 -8
- package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/BookEditPage.vue +2 -2
- package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/BookListPage.vue +2 -2
- package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/BookNewPage.vue +2 -2
- package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/BookViewPage.vue +3 -3
- package/skills/jskit/references/patterns/database/mysql-application/PATTERN.md +9 -4
- package/skills/jskit/references/patterns/database/mysql-application/example/package.json +2 -1
- package/skills/jskit/references/patterns/database/mysql-application/example/scripts/prepare-database.js +8 -0
- package/skills/jskit/references/patterns/database/postgres-application/PATTERN.md +8 -4
- package/skills/jskit/references/patterns/database/postgres-application/example/package.json +2 -1
- package/skills/jskit/references/patterns/database/postgres-application/example/scripts/prepare-database.js +8 -0
- package/skills/jskit/references/patterns/database/table-resource/PATTERN.md +120 -0
- package/skills/jskit/references/patterns/database/table-resource/example/orderResource.js +25 -0
- package/skills/jskit/references/patterns/realtime/realtime-application/PATTERN.md +7 -0
- package/skills/jskit/references/patterns/realtime/realtime-application/example/package.json +2 -2
- package/skills/jskit/references/patterns/rewards/google-rewarded/PATTERN.md +1 -1
- package/skills/jskit/references/patterns/server/feature-package/PATTERN.md +25 -17
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/package.json +1 -1
- package/skills/jskit/references/patterns/server/feature-package/example/variations/InvoiceRollupFeature.js +6 -7
- package/skills/jskit/references/patterns/server/feature-package/example/variations/invoiceResource.js +15 -0
- package/skills/jskit/references/patterns/server/feature-package/example/variations/invoiceRollupActions.js +4 -4
- package/skills/jskit/references/patterns/server/feature-package/example/variations/ownedTableRepository.js +27 -0
- package/skills/jskit/references/patterns/server/feature-package/example/variations/types.js +1 -1
- package/skills/jskit/references/patterns/users/user-administration-server/PATTERN.md +63 -10
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/package.json +5 -4
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/src/server/UsersFeature.js +7 -5
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/src/shared/index.js +1 -1
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/src/shared/userCrud.js +21 -0
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/package.json +11 -5
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/server/UsersWorkspaceFeature.js +14 -5
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/server/workspaceMembersOnly.js +52 -0
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/shared/index.js +1 -1
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/shared/userCrud.js +21 -0
- package/skills/jskit/references/patterns/workspaces/workspace-server/PATTERN.md +9 -9
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/PATTERN.md +16 -0
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/pages/home/workspaces/index.vue +2 -0
- package/skills/jskit/references/sanity-checks.md +27 -28
- package/skills/jskit/references/typed-features.md +117 -248
- package/patterns/feature-package/example/variations/customKnexRepository.js +0 -40
- package/reference/autogen/packages/json-rest-api-core.md +0 -66
- package/skills/jskit/references/heuristics/crud-repository-mapping.md +0 -140
- package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/src/server/BooksFeature.js +0 -13
- package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/src/shared/bookResource.js +0 -83
- package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/src/shared/index.js +0 -1
- package/skills/jskit/references/patterns/crud/resource-contract/PATTERN.md +0 -155
- package/skills/jskit/references/patterns/crud/resource-contract/example/bookResource.js +0 -87
- package/skills/jskit/references/patterns/server/feature-package/example/variations/customKnexRepository.js +0 -40
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/src/shared/userResource.js +0 -69
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/shared/userResource.js +0 -56
- /package/skills/jskit/references/patterns/crud/{json-api-resource-package → crud-feature-package}/example/migrations/20260815000000_books.cjs +0 -0
- /package/skills/jskit/references/patterns/crud/{json-api-resource-package → crud-feature-package}/example/packages/books/src/server/types.js +0 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: crud/crud-contract
|
|
3
|
+
title: Owner-scoped CRUD contract
|
|
4
|
+
summary: Define an application table resource whose records belong to the current user, and the authenticated CRUD contract that serves it.
|
|
5
|
+
keywords: authenticated, crud, database, owner-scoped, resource, table, user
|
|
6
|
+
requires: @jskit-ai/resource-core, @jskit-ai/resource-crud-core
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Owner-scoped CRUD contract
|
|
10
|
+
|
|
11
|
+
## Use when
|
|
12
|
+
|
|
13
|
+
Use this pattern when an authenticated application stores records that belong
|
|
14
|
+
to one user and standard list, view, create, patch, and delete behaviour fits
|
|
15
|
+
the product.
|
|
16
|
+
|
|
17
|
+
The example is intentionally a normal source file. Copy it directly when the
|
|
18
|
+
shape fits, adapt its fields and language for another entity, or read it as a
|
|
19
|
+
reference for `defineTableResource()` and `defineCrudContract()`.
|
|
20
|
+
|
|
21
|
+
## Do not use when
|
|
22
|
+
|
|
23
|
+
Do not use this pattern for public records, workspace-owned records, inherited
|
|
24
|
+
ownership, composite identities, or a domain whose operations do not match
|
|
25
|
+
normal CRUD behaviour. Select a pattern matching the real ownership and
|
|
26
|
+
operation model instead of changing `ownership` merely to make a test pass.
|
|
27
|
+
|
|
28
|
+
## Product decisions
|
|
29
|
+
|
|
30
|
+
Know these decisions before adapting the example:
|
|
31
|
+
|
|
32
|
+
- whether records truly belong to the current user
|
|
33
|
+
- which fields are required, optional, nullable, searchable, or hidden
|
|
34
|
+
- whether a value is free text or a constrained vocabulary
|
|
35
|
+
- which operations the product actually exposes
|
|
36
|
+
- the user-facing success and failure language
|
|
37
|
+
|
|
38
|
+
Those decisions come from the product conversation or existing application,
|
|
39
|
+
not from a JSKIT questionnaire.
|
|
40
|
+
|
|
41
|
+
## Invariants
|
|
42
|
+
|
|
43
|
+
- The persisted table has a normal single-column primary key.
|
|
44
|
+
- User ownership is represented by a non-null `user_id` column.
|
|
45
|
+
- The resource's hidden `userId` field maps to that ownership column.
|
|
46
|
+
- `ownership: "user"` is used only for genuine current-user ownership.
|
|
47
|
+
- The table has exactly one table resource; the CRUD contract is built on it.
|
|
48
|
+
- Each field the API shows or accepts has an entry in the CRUD contract's
|
|
49
|
+
`fields` stating its output, create and patch participation; a field without
|
|
50
|
+
one is neither shown nor accepted (see Field operations and lookups below).
|
|
51
|
+
- Temporal database values use the declared storage serializer.
|
|
52
|
+
- The source-controlled migration and the table resource agree.
|
|
53
|
+
- Server policy tests prove that one user cannot read or mutate another user's
|
|
54
|
+
records.
|
|
55
|
+
|
|
56
|
+
## Framework APIs
|
|
57
|
+
|
|
58
|
+
The example uses `defineTableResource()` from
|
|
59
|
+
`@jskit-ai/resource-core/shared/tableResource` for the table's facts (name,
|
|
60
|
+
table, ownership, fields, search and sort) and `defineCrudContract()` from
|
|
61
|
+
`@jskit-ai/resource-crud-core/shared/crudContract` for its HTTP surface
|
|
62
|
+
(its required `namespace`, operations, access, field operations and messages). The CRUD contract derives
|
|
63
|
+
the normal CRUD operation validators from the table resource's fields.
|
|
64
|
+
|
|
65
|
+
Higher layers should consume this resource through JSKIT's CRUD service,
|
|
66
|
+
repository, route, and UI APIs. They should not rebuild field validators or
|
|
67
|
+
serialize requests independently.
|
|
68
|
+
|
|
69
|
+
## Field operations and lookups
|
|
70
|
+
|
|
71
|
+
The CRUD contract's `fields` name, for each field, the operations it takes part
|
|
72
|
+
in: `output` (the record in every response), and `create` and `patch` (the
|
|
73
|
+
request bodies; an enabled `replace` uses the `create` fields unless a field
|
|
74
|
+
names `replace`). Each takes `"required"`, `"optional"` or an object, for
|
|
75
|
+
example `title: { output: "required", create: "required", patch: "optional" }`.
|
|
76
|
+
|
|
77
|
+
A contract shows and accepts only the fields it names: a field without an entry
|
|
78
|
+
is not in any output, a body that sends it is refused, and the CRUD service
|
|
79
|
+
leaves it out of the records it answers. So a column added to the table later
|
|
80
|
+
stays out of every API until a contract names it. Every record output carries
|
|
81
|
+
its `id` without an entry, and a stored `createdAt` or `updatedAt` is output
|
|
82
|
+
without one.
|
|
83
|
+
|
|
84
|
+
A stored `createdAt` or `updatedAt` is output only, and a contract that lets a
|
|
85
|
+
request write one (a `create`, `patch` or `replace` entry, or an explicit body
|
|
86
|
+
that takes it) is refused: the handle stamps `createdAt` on a create and
|
|
87
|
+
`updatedAt` on every write, replacing what a request sends. Only a system
|
|
88
|
+
context, as an import uses, sets its own.
|
|
89
|
+
|
|
90
|
+
A lookup field (`lookup: "<namespace>"`) is the table resource's: the
|
|
91
|
+
`database/table-resource` pattern lists what it expands to.
|
|
92
|
+
|
|
93
|
+
## Example files
|
|
94
|
+
|
|
95
|
+
- `example/bookResource.js` is a complete table resource (`bookResource`) and
|
|
96
|
+
CRUD contract (`bookCrud`) for personal book records.
|
|
97
|
+
|
|
98
|
+
The example deliberately uses a concrete domain. Rename and edit normal source
|
|
99
|
+
rather than feeding it through placeholder interpolation.
|
|
100
|
+
|
|
101
|
+
## Variation points
|
|
102
|
+
|
|
103
|
+
Safe adaptations include:
|
|
104
|
+
|
|
105
|
+
- resource name, table name and CRUD namespace
|
|
106
|
+
- product fields and validation
|
|
107
|
+
- searchable fields and default sort
|
|
108
|
+
- enabled CRUD operations
|
|
109
|
+
- user-facing messages
|
|
110
|
+
- lookup relationships supported by the resource APIs
|
|
111
|
+
|
|
112
|
+
Changing ownership, access, identity, or persistence architecture selects a
|
|
113
|
+
different pattern and requires corresponding policy and migration evidence.
|
|
114
|
+
|
|
115
|
+
## Verification
|
|
116
|
+
|
|
117
|
+
- Import the CRUD contract and prove all intended operations exist.
|
|
118
|
+
- Validate representative accepted and rejected field values.
|
|
119
|
+
- Rebuild the table from source-controlled migrations in a disposable database.
|
|
120
|
+
- Run positive current-user CRUD tests.
|
|
121
|
+
- Run negative cross-user read and mutation tests.
|
|
122
|
+
- Run the application's focused tests and broad verifier at sign-off.
|
|
123
|
+
|
|
124
|
+
## Avoid
|
|
125
|
+
|
|
126
|
+
- generator provenance or scaffold-shape metadata
|
|
127
|
+
- a field-by-field questionnaire
|
|
128
|
+
- a live table as the only source of schema truth
|
|
129
|
+
- app-specific request serializers that duplicate the CRUD contract
|
|
130
|
+
- a second table resource for the same table
|
|
131
|
+
- hidden ownership aliases other than the framework's explicit ownership field
|
|
132
|
+
- durable receipts recording that this pattern was copied
|
|
133
|
+
- changing an installed baseline migration instead of adding a new migration
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { defineTableResource } from "@jskit-ai/resource-core/shared/tableResource";
|
|
2
|
+
import { defineCrudContract } from "@jskit-ai/resource-crud-core/shared/crudContract";
|
|
3
|
+
|
|
4
|
+
const bookResource = defineTableResource({
|
|
5
|
+
name: "books",
|
|
6
|
+
tableName: "books",
|
|
7
|
+
ownership: "user",
|
|
8
|
+
schema: {
|
|
9
|
+
userId: {
|
|
10
|
+
type: "id",
|
|
11
|
+
required: true,
|
|
12
|
+
hidden: true
|
|
13
|
+
},
|
|
14
|
+
title: {
|
|
15
|
+
type: "string",
|
|
16
|
+
maxLength: 255,
|
|
17
|
+
required: true,
|
|
18
|
+
search: true
|
|
19
|
+
},
|
|
20
|
+
author: {
|
|
21
|
+
type: "string",
|
|
22
|
+
maxLength: 255,
|
|
23
|
+
required: true,
|
|
24
|
+
search: true
|
|
25
|
+
},
|
|
26
|
+
notes: {
|
|
27
|
+
type: "string",
|
|
28
|
+
maxLength: 65535,
|
|
29
|
+
nullable: true,
|
|
30
|
+
search: true
|
|
31
|
+
},
|
|
32
|
+
createdAt: {
|
|
33
|
+
type: "dateTime",
|
|
34
|
+
temporalPrecision: 0,
|
|
35
|
+
storage: { writeSerializer: "datetime-utc" }
|
|
36
|
+
},
|
|
37
|
+
updatedAt: {
|
|
38
|
+
type: "dateTime",
|
|
39
|
+
temporalPrecision: 0,
|
|
40
|
+
storage: { writeSerializer: "datetime-utc" }
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
searchSchema: {
|
|
44
|
+
q: {
|
|
45
|
+
type: "string",
|
|
46
|
+
oneOf: ["title", "author", "notes"],
|
|
47
|
+
filterOperator: "like",
|
|
48
|
+
splitBy: " ",
|
|
49
|
+
matchAll: true
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
defaultSort: ["-createdAt"]
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const bookCrud = defineCrudContract(bookResource, {
|
|
56
|
+
namespace: "books",
|
|
57
|
+
apiAccess: "authenticated",
|
|
58
|
+
fields: {
|
|
59
|
+
title: { output: "required", create: "required", patch: "optional" },
|
|
60
|
+
author: { output: "required", create: "required", patch: "optional" },
|
|
61
|
+
notes: { output: "required", create: "optional", patch: "optional" },
|
|
62
|
+
createdAt: { output: "required" },
|
|
63
|
+
updatedAt: { output: "required" }
|
|
64
|
+
},
|
|
65
|
+
messages: {
|
|
66
|
+
validation: "Fix invalid values and try again.",
|
|
67
|
+
saveSuccess: "Book saved.",
|
|
68
|
+
saveError: "Unable to save this book.",
|
|
69
|
+
deleteSuccess: "Book deleted.",
|
|
70
|
+
deleteError: "Unable to delete this book."
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
export { bookCrud, bookResource };
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
---
|
|
2
|
-
id: crud/
|
|
3
|
-
title:
|
|
4
|
-
summary: Build a complete application-owned CRUD server package from a migration, resource contract, and one framework module declaration.
|
|
5
|
-
keywords: actions, crud, database, json-api, migration,
|
|
6
|
-
requires: @jskit-ai/crud-core, @jskit-ai/resource-crud-core
|
|
2
|
+
id: crud/crud-feature-package
|
|
3
|
+
title: CRUD feature package
|
|
4
|
+
summary: Build a complete application-owned CRUD server package from a migration, a table resource with its CRUD contract, and one framework module declaration.
|
|
5
|
+
keywords: actions, crud, database, defineCrudFeature, json-api, migration, owns, permissions, repository, routes, service, table resource
|
|
6
|
+
requires: @jskit-ai/crud-core, @jskit-ai/resource-core, @jskit-ai/resource-crud-core
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
#
|
|
9
|
+
# CRUD feature package
|
|
10
10
|
|
|
11
11
|
## Use when
|
|
12
12
|
|
|
13
13
|
Use this pattern when a product entity needs conventional JSON API list, view,
|
|
14
14
|
create, patch, and delete behavior. JSKIT owns the repeated repository, service,
|
|
15
15
|
action, route, and provider mechanics. The application owns the migration,
|
|
16
|
-
resource contract, access surface, ownership policy, and package
|
|
16
|
+
table resource, CRUD contract, access surface, ownership policy, and package
|
|
17
|
+
composition.
|
|
17
18
|
|
|
18
19
|
## Do not use when
|
|
19
20
|
|
|
@@ -30,8 +31,10 @@ from a generator questionnaire or treat a live table as the sole contract.
|
|
|
30
31
|
|
|
31
32
|
## Invariants
|
|
32
33
|
|
|
33
|
-
-
|
|
34
|
-
|
|
34
|
+
- The migration and the table resource's storage metadata describe the same
|
|
35
|
+
table, and that table has no other table resource.
|
|
36
|
+
- The CRUD contract's `apiAccess`, surface access, and the table resource's
|
|
37
|
+
`ownership` agree.
|
|
35
38
|
- Public routes use public ownership only.
|
|
36
39
|
- Workspace routes receive explicit scope validators and route-to-action input:
|
|
37
40
|
workspaces-core's `WORKSPACE_CRUD_SCOPE`, never a copied scope literal.
|
|
@@ -55,10 +58,15 @@ from a generator questionnaire or treat a live table as the sole contract.
|
|
|
55
58
|
|
|
56
59
|
## Framework APIs
|
|
57
60
|
|
|
58
|
-
Use `
|
|
59
|
-
`
|
|
60
|
-
|
|
61
|
-
|
|
61
|
+
Use `defineTableResource()` from `@jskit-ai/resource-core`,
|
|
62
|
+
`defineCrudContract()` from `@jskit-ai/resource-crud-core` and
|
|
63
|
+
`defineCrudFeature()` from `@jskit-ai/crud-core`. The feature takes the CRUD
|
|
64
|
+
contract as `crud` and owns its table resource: its repository is the table's
|
|
65
|
+
handle, and it composes the CRUD service, standard CRUD actions with their
|
|
66
|
+
record-changed events, route contracts, access policy, and HTTP routes. The
|
|
67
|
+
routes' visibility and the rows each call reaches follow the table resource's
|
|
68
|
+
`ownership`. More tables the feature owns go in `owns`, and so do the CRUD
|
|
69
|
+
table's server-only extras (`{ resource: bookResource, rowPolicy, hooks }`).
|
|
62
70
|
|
|
63
71
|
## Example files
|
|
64
72
|
|
|
@@ -80,8 +88,8 @@ For a package-owned migration instead, declare its actual directory in
|
|
|
80
88
|
`package.json#jskit.migrations.directories`, as described in the database-layer
|
|
81
89
|
guide.
|
|
82
90
|
|
|
83
|
-
`BooksFeature.js` is deliberately tiny: it binds the
|
|
84
|
-
|
|
91
|
+
`BooksFeature.js` is deliberately tiny: it binds the `bookCrud` contract to the
|
|
92
|
+
framework module and exports the resulting provider.
|
|
85
93
|
`types.js` declares the type of the `app.books` capability, for features that
|
|
86
94
|
require it.
|
|
87
95
|
|
|
@@ -104,18 +112,17 @@ an unfiltered collection can satisfy a matching-row-only assertion.
|
|
|
104
112
|
|
|
105
113
|
## Variation points
|
|
106
114
|
|
|
107
|
-
Change the package name, resource fields, table,
|
|
115
|
+
Change the package name, resource fields, table, ownership, surface,
|
|
108
116
|
relative route, messages, and migration. Supply explicit permissions when the
|
|
109
117
|
surface uses named policy. For workspace ownership, pass `scope:
|
|
110
118
|
WORKSPACE_CRUD_SCOPE` (`@jskit-ai/workspaces-core/server/support/workspaceCrud`):
|
|
111
119
|
the `/w/:workspaceSlug` route base, the workspace route and action validators
|
|
112
|
-
and the slug input. A repository method of such a feature
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
hand-written workspace route's path is
|
|
120
|
+
and the slug input. A repository method of such a feature passes the call's
|
|
121
|
+
`options` on to its handle, which scopes every read and write to the caller's
|
|
122
|
+
workspace, and a hand-written workspace route's path is
|
|
116
123
|
`resolveWorkspaceRoutePath("relative-path")`
|
|
117
124
|
(`@jskit-ai/workspaces-core/server/support/workspaceRoutePaths`). The feature exposes the
|
|
118
|
-
operations declared by the
|
|
125
|
+
operations declared by the CRUD contract. Use `operations` only to narrow that
|
|
119
126
|
surface further; do not register unused mutation actions and routes. Use
|
|
120
127
|
`routes: false` only for an internal
|
|
121
128
|
capability/action surface that deliberately has no HTTP API.
|
|
@@ -140,24 +147,29 @@ function of the action execution.
|
|
|
140
147
|
|
|
141
148
|
When otherwise-standard CRUD earns product behavior, name the exact
|
|
142
149
|
capabilities in `requires` and provide `decorateService({ service, repository,
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
such as `confirmBooking()` or
|
|
146
|
-
|
|
147
|
-
|
|
150
|
+
crud, ...dependencies })`. Retain the standard methods (`list`, `view`,
|
|
151
|
+
`create`, `patch`, `delete`), override only the methods whose CRUD behavior
|
|
152
|
+
changes, and add resource-related domain methods such as `confirmBooking()` or
|
|
153
|
+
`sendReminder()` directly to that service. Those additional methods remain
|
|
154
|
+
available through the resource capability. An overridden `create()` returns
|
|
155
|
+
the created record, with its id, as a
|
|
148
156
|
tagged JSON:API result: a document result (`returnJsonApiDocument`), as the
|
|
149
157
|
standard one does, or a data result (`returnJsonApiData(record)`). The create
|
|
150
158
|
action's created and `record.changed` events read the record's id from it, and
|
|
151
159
|
a create whose service returns an untagged document or record, or a result
|
|
152
160
|
without the record's id, fails in every channel. When the
|
|
153
161
|
product needs only a few additional queries or locking operations, provide
|
|
154
|
-
`decorateRepository({ repository,
|
|
155
|
-
|
|
156
|
-
|
|
162
|
+
`decorateRepository({ repository, resources, crud, ...dependencies })`, where
|
|
163
|
+
`repository` is the CRUD table's handle and `resources` holds the handle of
|
|
164
|
+
every table the feature owns; return the handle's methods plus only those
|
|
165
|
+
unique persistence operations, each taking the call's `options` last and
|
|
166
|
+
passing them on untouched.
|
|
157
167
|
|
|
158
168
|
Use `operationLifecycle` for behavior surrounding a standard operation. Its
|
|
159
169
|
per-operation `before`, `execute`, and `after` phases share one repository
|
|
160
|
-
transaction for create, update, and delete
|
|
170
|
+
transaction for create, update, and delete: each receives `options`, the call
|
|
171
|
+
options carrying the action context and that transaction, to pass on to every
|
|
172
|
+
repository or service call it makes. An `execute` hook receives
|
|
161
173
|
`standard(nextInput)` so it can retain the framework write while adjusting its
|
|
162
174
|
input or coordinating other repository work, and returns what `standard()`
|
|
163
175
|
returns: the operation's tagged JSON:API result (null for delete). A create's
|
|
@@ -173,7 +185,10 @@ service and repository its hooks call. Put durable external delivery behind an
|
|
|
173
185
|
outbox written inside the transaction; do not make an email or webhook the
|
|
174
186
|
arbiter of whether an already-committed request appears successful.
|
|
175
187
|
|
|
176
|
-
Declare resource-related non-CRUD commands in `actions`. Each
|
|
188
|
+
Declare resource-related non-CRUD commands in `actions`. Each key is the
|
|
189
|
+
action's name: lower case, starting with a letter, with only letters, digits,
|
|
190
|
+
`_`, `.` and `-` (`cancel-day`, never `cancelDay`); its id is
|
|
191
|
+
`crud.<namespace>.<name>`. Each named action has
|
|
177
192
|
a normal JSKIT input, permission, audit, events, and `execute({ input, context,
|
|
178
193
|
service, repository, ...dependencies })` contract. Type that argument with
|
|
179
194
|
`CrudCustomActionInvocation` from `@jskit-ai/crud-core/server/types`. Its first
|
|
@@ -183,13 +198,15 @@ by local name; its third is the repository the action calls, when
|
|
|
183
198
|
`decorateRepository` adds the method. Its optional `route`
|
|
184
199
|
declares an HTTP method, path below the resource base, explicit route contract,
|
|
185
200
|
status code, and optional request-to-action input mapper. This is the normal
|
|
186
|
-
home for `confirm`, `publish`, `cancel`, `reorder`, or `
|
|
201
|
+
home for `confirm`, `publish`, `cancel`, `reorder`, or `send-reminder`. Move to a
|
|
187
202
|
separate explicit feature only when the operation belongs to another domain or
|
|
188
203
|
the resource is no longer principally CRUD.
|
|
189
204
|
|
|
190
205
|
If a product-specific list filter needs additional transport validation and
|
|
191
206
|
JSON API search mapping, pass its validator as `listFilterQueryValidator` and
|
|
192
|
-
its storage mapping
|
|
207
|
+
put its storage mapping in the table resource's `searchSchema` (or, when it is
|
|
208
|
+
server-only, in the CRUD table's `owns` entry); keep that contract next to the
|
|
209
|
+
feature.
|
|
193
210
|
Use `operationInputs.create` or `operationInputs.update` when a standard CRUD
|
|
194
211
|
operation intentionally accepts a small virtual product field that is handled
|
|
195
212
|
by the service decorator rather than stored on the resource row.
|
|
@@ -234,15 +251,15 @@ function decorateBookingsService({ service, repository }) {
|
|
|
234
251
|
```
|
|
235
252
|
|
|
236
253
|
```js
|
|
237
|
-
const BookingsFeature =
|
|
238
|
-
|
|
254
|
+
const BookingsFeature = defineCrudFeature({
|
|
255
|
+
crud: bookingCrud,
|
|
239
256
|
surface: "app",
|
|
240
257
|
decorateRepository: decorateBookingsRepository,
|
|
241
258
|
decorateService: decorateBookingsService,
|
|
242
259
|
operationLifecycle: {
|
|
243
260
|
update: {
|
|
244
|
-
async before({ input, service,
|
|
245
|
-
await service.assertUpdateAllowed(input.recordId,
|
|
261
|
+
async before({ input, service, options }) {
|
|
262
|
+
await service.assertUpdateAllowed(input.recordId, options);
|
|
246
263
|
},
|
|
247
264
|
async afterCommit({ result, service, context }) {
|
|
248
265
|
await service.recordUpdateCompleted(result.value.data.id, { context });
|
|
@@ -266,6 +283,21 @@ const BookingsFeature = defineCrudJsonApiFeature({
|
|
|
266
283
|
});
|
|
267
284
|
```
|
|
268
285
|
|
|
286
|
+
An action's `input` is one schema definition, `{ schema, mode }`, for
|
|
287
|
+
everything it validates; its route contract names each part of the request it
|
|
288
|
+
reads, `params`, `query` or `body`, each a schema definition, and the route
|
|
289
|
+
hands the action their fields merged. A workspace scope adds `workspaceSlug` to
|
|
290
|
+
both itself.
|
|
291
|
+
|
|
292
|
+
```js
|
|
293
|
+
import { createSchema } from "json-rest-schema";
|
|
294
|
+
import { composeSchemaDefinitions, recordIdParamsValidator } from "@jskit-ai/kernel/shared/validators";
|
|
295
|
+
|
|
296
|
+
const confirmBookingBody = { schema: createSchema({ note: { type: "string", maxLength: 500 } }), mode: "patch" };
|
|
297
|
+
const confirmBookingInput = composeSchemaDefinitions([recordIdParamsValidator, confirmBookingBody], { mode: "patch" });
|
|
298
|
+
const confirmBookingRouteContract = { params: recordIdParamsValidator, body: confirmBookingBody };
|
|
299
|
+
```
|
|
300
|
+
|
|
269
301
|
## Verification
|
|
270
302
|
|
|
271
303
|
- Rebuild the table from migrations in disposable MySQL and PostgreSQL databases
|
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
"./shared": "./src/shared/index.js"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@jskit-ai/crud-core": "0.2.
|
|
13
|
-
"@jskit-ai/resource-
|
|
12
|
+
"@jskit-ai/crud-core": "0.2.16",
|
|
13
|
+
"@jskit-ai/resource-core": "0.1.206",
|
|
14
|
+
"@jskit-ai/resource-crud-core": "0.1.206"
|
|
14
15
|
},
|
|
15
16
|
"jskit": {
|
|
16
17
|
"kind": "runtime",
|
|
@@ -19,10 +20,10 @@
|
|
|
19
20
|
"app.books"
|
|
20
21
|
],
|
|
21
22
|
"requires": [
|
|
23
|
+
"crud.contracts",
|
|
22
24
|
"runtime.http",
|
|
23
|
-
"runtime.json-rest-api",
|
|
24
25
|
"runtime.actions",
|
|
25
|
-
"runtime.
|
|
26
|
+
"runtime.resources"
|
|
26
27
|
]
|
|
27
28
|
},
|
|
28
29
|
"runtime": {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { defineCrudFeature } from "@jskit-ai/crud-core/server/defineCrudFeature";
|
|
2
|
+
import { bookCrud } from "../shared/bookResource.js";
|
|
3
|
+
|
|
4
|
+
// Owns the books table and serves its CRUD contract.
|
|
5
|
+
const BooksFeature = defineCrudFeature({
|
|
6
|
+
crud: bookCrud,
|
|
7
|
+
id: "app.books",
|
|
8
|
+
capability: "app.books",
|
|
9
|
+
surface: "app",
|
|
10
|
+
relativePath: "/books"
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export { BooksFeature };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { defineTableResource } from "@jskit-ai/resource-core/shared/tableResource";
|
|
2
|
+
import { defineCrudContract } from "@jskit-ai/resource-crud-core/shared/crudContract";
|
|
3
|
+
|
|
4
|
+
const bookResource = defineTableResource({
|
|
5
|
+
name: "books",
|
|
6
|
+
tableName: "books",
|
|
7
|
+
ownership: "user",
|
|
8
|
+
schema: {
|
|
9
|
+
userId: {
|
|
10
|
+
type: "id",
|
|
11
|
+
required: true,
|
|
12
|
+
hidden: true
|
|
13
|
+
},
|
|
14
|
+
title: {
|
|
15
|
+
type: "string",
|
|
16
|
+
maxLength: 255,
|
|
17
|
+
required: true,
|
|
18
|
+
search: true
|
|
19
|
+
},
|
|
20
|
+
author: {
|
|
21
|
+
type: "string",
|
|
22
|
+
maxLength: 255,
|
|
23
|
+
required: true,
|
|
24
|
+
search: true
|
|
25
|
+
},
|
|
26
|
+
notes: {
|
|
27
|
+
type: "string",
|
|
28
|
+
maxLength: 65535,
|
|
29
|
+
nullable: true,
|
|
30
|
+
search: true
|
|
31
|
+
},
|
|
32
|
+
createdAt: {
|
|
33
|
+
type: "dateTime",
|
|
34
|
+
temporalPrecision: 0,
|
|
35
|
+
storage: { writeSerializer: "datetime-utc" }
|
|
36
|
+
},
|
|
37
|
+
updatedAt: {
|
|
38
|
+
type: "dateTime",
|
|
39
|
+
temporalPrecision: 0,
|
|
40
|
+
storage: { writeSerializer: "datetime-utc" }
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
searchSchema: {
|
|
44
|
+
q: {
|
|
45
|
+
type: "string",
|
|
46
|
+
oneOf: ["title", "author", "notes"],
|
|
47
|
+
filterOperator: "like",
|
|
48
|
+
splitBy: " ",
|
|
49
|
+
matchAll: true
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
defaultSort: ["-createdAt"]
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const bookCrud = defineCrudContract(bookResource, {
|
|
56
|
+
namespace: "books",
|
|
57
|
+
apiAccess: "authenticated",
|
|
58
|
+
fields: {
|
|
59
|
+
title: { output: "required", create: "required", patch: "optional" },
|
|
60
|
+
author: { output: "required", create: "required", patch: "optional" },
|
|
61
|
+
notes: { output: "required", create: "optional", patch: "optional" },
|
|
62
|
+
createdAt: { output: "required" },
|
|
63
|
+
updatedAt: { output: "required" }
|
|
64
|
+
},
|
|
65
|
+
messages: {
|
|
66
|
+
validation: "Fix invalid values and try again.",
|
|
67
|
+
saveSuccess: "Book saved.",
|
|
68
|
+
saveError: "Unable to save this book.",
|
|
69
|
+
deleteSuccess: "Book deleted.",
|
|
70
|
+
deleteError: "Unable to delete this book."
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
export { bookCrud, bookResource };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { bookCrud, bookResource } from "./bookResource.js";
|
|
@@ -3,7 +3,7 @@ id: crud/crud-screen-set
|
|
|
3
3
|
title: CRUD list, view, create, and edit screens
|
|
4
4
|
summary: Build a routed CRUD user interface as thin application pages over JSKIT's shared screen components and composables.
|
|
5
5
|
keywords: actions, add, crud, delete, edit, filters, list, material, routes, view, vue
|
|
6
|
-
requires: @jskit-ai/http-web, @jskit-ai/resource-crud-core
|
|
6
|
+
requires: @jskit-ai/http-web, @jskit-ai/resource-crud-core, @jskit-ai/resource-core
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# CRUD list, view, create, and edit screens
|
|
@@ -27,7 +27,7 @@ supporting detail content; those are public extension seams.
|
|
|
27
27
|
|
|
28
28
|
Decide which operations exist, the route hierarchy, record title, visible
|
|
29
29
|
fields, create/edit participation, destructive confirmation language, access
|
|
30
|
-
surface, filters, and domain actions. The
|
|
30
|
+
surface, filters, and domain actions. The CRUD contract and product intent
|
|
31
31
|
are authoritative. Do not derive these decisions from a live table or a field
|
|
32
32
|
questionnaire.
|
|
33
33
|
|
|
@@ -49,7 +49,7 @@ questionnaire.
|
|
|
49
49
|
history entry, so neither Up nor Back reopens it.
|
|
50
50
|
- View fields are two-line list items with the value first:
|
|
51
51
|
`<v-list-item :title="record.author" subtitle="Author" />`.
|
|
52
|
-
- Transport and validators come from the shared
|
|
52
|
+
- Transport and validators come from the shared CRUD contract.
|
|
53
53
|
- Initial visible loading uses structure-matching skeletons; pending buttons use
|
|
54
54
|
stable disabled labels, never spinners.
|
|
55
55
|
- Resource-load errors stay inside the screen with retry. Command success and
|
|
@@ -71,15 +71,18 @@ questionnaire.
|
|
|
71
71
|
Use `CrudListScreen`, `CrudViewScreen`, `CrudAddEditScreen`, and
|
|
72
72
|
`CrudDeleteAction` with their matching composables from `@jskit-ai/http-web`.
|
|
73
73
|
Use `defineCrudListFilters()`, `defineCrudListRowActions()`, and
|
|
74
|
-
`defineCrudListBulkActions()` for optional list extensions.
|
|
75
|
-
from `
|
|
74
|
+
`defineCrudListBulkActions()` for optional list extensions. Screens take the
|
|
75
|
+
CRUD contract from `defineCrudContract()` in `@jskit-ai/resource-crud-core`,
|
|
76
|
+
built on the table resource from `defineTableResource()` in
|
|
77
|
+
`@jskit-ai/resource-core`.
|
|
76
78
|
|
|
77
79
|
## Example files
|
|
78
80
|
|
|
79
81
|
`example/books/` contains concrete list, view, new, and edit pages for the
|
|
80
|
-
owner-scoped `bookResource`
|
|
81
|
-
show the small product-owned form
|
|
82
|
-
filters and actions explicit without
|
|
82
|
+
owner-scoped `bookResource` table resource and its `bookCrud` contract.
|
|
83
|
+
`BookFormFields.vue` and `formFields.js` show the small product-owned form
|
|
84
|
+
seam. `listExtensions.js` makes optional filters and actions explicit without
|
|
85
|
+
adding empty screen machinery elsewhere.
|
|
83
86
|
|
|
84
87
|
## Variation points
|
|
85
88
|
|
|
@@ -166,6 +169,21 @@ through to Vuetify.
|
|
|
166
169
|
Here `lookups` is the page's `createCrudLookupFieldRuntime()` result for the
|
|
167
170
|
same form fields.
|
|
168
171
|
|
|
172
|
+
### Linked records in a list
|
|
173
|
+
|
|
174
|
+
A list that shows a field of a linked record asks for it by relationship name
|
|
175
|
+
in `useCrudListScreen({ ..., requestQueryParams: { include: "service" } })`,
|
|
176
|
+
and each row reads it from its `lookups`: `record.lookups.service.name`. The
|
|
177
|
+
contract decides which of the linked record's fields arrive: its id, its
|
|
178
|
+
relation's `labelKey`, and what `fields.serviceId.output.includeFields` names.
|
|
179
|
+
|
|
180
|
+
```vue
|
|
181
|
+
<template #table-row="{ record }">
|
|
182
|
+
<td>{{ record.title }}</td>
|
|
183
|
+
<td>{{ record.lookups?.service?.name }}</td>
|
|
184
|
+
</template>
|
|
185
|
+
```
|
|
186
|
+
|
|
169
187
|
## Verification
|
|
170
188
|
|
|
171
189
|
- Mount each route with a representative resource response.
|
package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/BookEditPage.vue
CHANGED
|
@@ -3,7 +3,7 @@ import { computed } from "vue";
|
|
|
3
3
|
import { useRoute } from "vue-router";
|
|
4
4
|
import CrudAddEditScreen from "@jskit-ai/http-web/client/components/CrudAddEditScreen";
|
|
5
5
|
import { useCrudAddEditScreen } from "@jskit-ai/http-web/client/composables/useCrudAddEditScreen";
|
|
6
|
-
import {
|
|
6
|
+
import { bookCrud } from "@local/books/shared";
|
|
7
7
|
import BookFormFields from "./BookFormFields.vue";
|
|
8
8
|
import { bookFormFields } from "./formFields.js";
|
|
9
9
|
|
|
@@ -17,7 +17,7 @@ const screen = useCrudAddEditScreen({
|
|
|
17
17
|
saveLabel: "Save changes",
|
|
18
18
|
cancelTo: "/books/:bookId",
|
|
19
19
|
preserveCancelQuery: true,
|
|
20
|
-
resource:
|
|
20
|
+
resource: bookCrud,
|
|
21
21
|
operationName: "patch",
|
|
22
22
|
formFields: bookFormFields,
|
|
23
23
|
addEditOptions: {
|
package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/BookListPage.vue
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import CrudListScreen from "@jskit-ai/http-web/client/components/CrudListScreen";
|
|
3
3
|
import { useCrudListScreen } from "@jskit-ai/http-web/client/composables/useCrudListScreen";
|
|
4
|
-
import {
|
|
4
|
+
import { bookCrud } from "@local/books/shared";
|
|
5
5
|
import { listBulkActions, listFilters, listRowActions } from "./listExtensions.js";
|
|
6
6
|
|
|
7
7
|
// A main menu destination: the app bar shows its title and no Up arrow.
|
|
8
8
|
definePage({ meta: { jskit: { title: "Books" } } });
|
|
9
9
|
|
|
10
10
|
const screen = useCrudListScreen({
|
|
11
|
-
resource:
|
|
11
|
+
resource: bookCrud,
|
|
12
12
|
resourceNamespace: "books",
|
|
13
13
|
apiSuffix: "/books",
|
|
14
14
|
recordIdParam: "bookId",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import CrudAddEditScreen from "@jskit-ai/http-web/client/components/CrudAddEditScreen";
|
|
3
3
|
import { useCrudAddEditScreen } from "@jskit-ai/http-web/client/composables/useCrudAddEditScreen";
|
|
4
|
-
import {
|
|
4
|
+
import { bookCrud } from "@local/books/shared";
|
|
5
5
|
import BookFormFields from "./BookFormFields.vue";
|
|
6
6
|
import { bookFormFields } from "./formFields.js";
|
|
7
7
|
|
|
@@ -11,7 +11,7 @@ const screen = useCrudAddEditScreen({
|
|
|
11
11
|
mode: "new",
|
|
12
12
|
saveLabel: "Save book",
|
|
13
13
|
cancelTo: "/books",
|
|
14
|
-
resource:
|
|
14
|
+
resource: bookCrud,
|
|
15
15
|
operationName: "create",
|
|
16
16
|
formFields: bookFormFields,
|
|
17
17
|
addEditOptions: {
|