@jskit-ai/agent-docs 0.1.283 → 0.1.284

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 (151) hide show
  1. package/guide/agent/app-extras/assistant.md +14 -2
  2. package/guide/agent/app-extras/realtime.md +38 -1
  3. package/guide/agent/app-setup/authentication.md +64 -14
  4. package/guide/agent/app-setup/console.md +8 -0
  5. package/guide/agent/app-setup/database-layer.md +23 -103
  6. package/guide/agent/app-setup/existing-application-migration.md +105 -72
  7. package/guide/agent/app-setup/multi-homing.md +94 -32
  8. package/guide/agent/app-setup/quickstart.md +1 -1
  9. package/guide/agent/app-setup/run-an-accounts-hub.md +1 -1
  10. package/guide/agent/app-setup/upgrading-jskit.md +8 -3
  11. package/guide/agent/app-setup/users.md +8 -5
  12. package/guide/agent/framework/application-operations.md +1 -1
  13. package/guide/agent/framework/crud-operations.md +63 -45
  14. package/guide/agent/framework/data-access.md +1031 -0
  15. package/guide/agent/framework/sanity-checks.md +26 -27
  16. package/guide/agent/framework/typed-features.md +114 -247
  17. package/guide/agent/index.md +2 -0
  18. package/package.json +6 -3
  19. package/patterns/feature-package/PATTERN.md +25 -17
  20. package/patterns/feature-package/example/booking-engine/package.json +1 -1
  21. package/patterns/feature-package/example/variations/InvoiceRollupFeature.js +6 -7
  22. package/patterns/feature-package/example/variations/invoiceResource.js +15 -0
  23. package/patterns/feature-package/example/variations/invoiceRollupActions.js +4 -4
  24. package/patterns/feature-package/example/variations/ownedTableRepository.js +27 -0
  25. package/patterns/feature-package/example/variations/types.js +1 -1
  26. package/patterns/minimal-foundation/example/AGENTS.md +4 -0
  27. package/patterns/minimal-foundation/example/package.json +4 -4
  28. package/patterns/minimal-foundation/example/server.js +4 -1
  29. package/patterns/shell-foundation/example/AGENTS.md +4 -0
  30. package/patterns/shell-foundation/example/package.json +5 -5
  31. package/patterns/shell-foundation/example/packages/main/package.json +1 -1
  32. package/patterns/shell-foundation/example/server.js +4 -1
  33. package/reference/autogen/KERNEL_MAP.md +2 -1
  34. package/reference/autogen/PATTERN_INDEX.md +70 -59
  35. package/reference/autogen/README.md +1 -1
  36. package/reference/autogen/packages/agent-docs.md +7 -3
  37. package/reference/autogen/packages/agent-runtime.md +48 -11
  38. package/reference/autogen/packages/architecture-inspector.md +6 -2
  39. package/reference/autogen/packages/assistant-core.md +4 -4
  40. package/reference/autogen/packages/assistant-runtime.md +33 -13
  41. package/reference/autogen/packages/auth-provider-local-core.md +3 -1
  42. package/reference/autogen/packages/auth-provider-local-db-core.md +65 -14
  43. package/reference/autogen/packages/auth-provider-oidc-core.md +5 -1
  44. package/reference/autogen/packages/auth-provider-supabase-core.md +1 -1
  45. package/reference/autogen/packages/connectors-core.md +22 -2
  46. package/reference/autogen/packages/console-core.md +9 -5
  47. package/reference/autogen/packages/crud-core.md +38 -173
  48. package/reference/autogen/packages/database-runtime.md +8 -32
  49. package/reference/autogen/packages/http-runtime.md +3 -3
  50. package/reference/autogen/packages/http-web.md +12 -0
  51. package/reference/autogen/packages/kernel.md +25 -2
  52. package/reference/autogen/packages/oidc-issuer-core.md +4 -0
  53. package/reference/autogen/packages/payments-core.md +29 -6
  54. package/reference/autogen/packages/realtime.md +15 -6
  55. package/reference/autogen/packages/resource-core.md +30 -5
  56. package/reference/autogen/packages/resource-crud-core.md +30 -34
  57. package/reference/autogen/packages/resource-runtime.md +198 -0
  58. package/reference/autogen/packages/rewarded-core.md +16 -10
  59. package/reference/autogen/packages/shell-web.md +1 -0
  60. package/reference/autogen/packages/users-core.md +26 -14
  61. package/reference/autogen/packages/workspaces-core.md +17 -10
  62. package/reference/autogen/tooling/config-eslint.md +69 -0
  63. package/reference/autogen/tooling/jskit-catalog.md +36 -1
  64. package/reference/autogen/tooling/jskit-release.md +3 -0
  65. package/skills/jskit/SKILL.md +4 -1
  66. package/skills/jskit/references/app-operations.md +1 -1
  67. package/skills/jskit/references/crud-operations.md +62 -44
  68. package/skills/jskit/references/data-access.md +1026 -0
  69. package/skills/jskit/references/database-layer.md +411 -0
  70. package/skills/jskit/references/existing-application-migration.md +105 -72
  71. package/skills/jskit/references/heuristics/INDEX.md +6 -4
  72. package/skills/jskit/references/heuristics/crud-authoring.md +22 -14
  73. package/skills/jskit/references/heuristics/data-access.md +19 -0
  74. package/skills/jskit/references/heuristics/filters.md +6 -6
  75. package/skills/jskit/references/heuristics/row-policies.md +40 -16
  76. package/skills/jskit/references/heuristics/server-search.md +30 -42
  77. package/skills/jskit/references/heuristics/table-resource-fields.md +78 -0
  78. package/skills/jskit/references/heuristics/typed-features.md +3 -3
  79. package/skills/jskit/references/multi-homing.md +94 -32
  80. package/skills/jskit/references/pattern-index.md +70 -59
  81. package/skills/jskit/references/patterns/app/minimal-foundation/example/AGENTS.md +4 -0
  82. package/skills/jskit/references/patterns/app/minimal-foundation/example/package.json +4 -4
  83. package/skills/jskit/references/patterns/app/minimal-foundation/example/server.js +4 -1
  84. package/skills/jskit/references/patterns/app/shell-foundation/example/AGENTS.md +4 -0
  85. package/skills/jskit/references/patterns/app/shell-foundation/example/package.json +5 -5
  86. package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/package.json +1 -1
  87. package/skills/jskit/references/patterns/app/shell-foundation/example/server.js +4 -1
  88. package/skills/jskit/references/patterns/assistant/assistant-surface/PATTERN.md +5 -2
  89. package/skills/jskit/references/patterns/auth/accounts-hub/example/package.json +3 -2
  90. package/skills/jskit/references/patterns/auth/auth-surface/PATTERN.md +15 -0
  91. package/skills/jskit/references/patterns/auth/oidc-sign-in/example/package.json +2 -2
  92. package/skills/jskit/references/patterns/auth/supabase-auth/example/package.json +1 -1
  93. package/skills/jskit/references/patterns/connectors/calendar-cli/example/package.json +4 -4
  94. package/skills/jskit/references/patterns/crud/crud-contract/PATTERN.md +133 -0
  95. package/skills/jskit/references/patterns/crud/crud-contract/example/bookResource.js +74 -0
  96. package/skills/jskit/references/patterns/crud/{json-api-resource-package → crud-feature-package}/PATTERN.md +69 -37
  97. package/skills/jskit/references/patterns/crud/{json-api-resource-package → crud-feature-package}/example/packages/books/package.json +5 -4
  98. package/skills/jskit/references/patterns/crud/crud-feature-package/example/packages/books/src/server/BooksFeature.js +13 -0
  99. package/skills/jskit/references/patterns/crud/crud-feature-package/example/packages/books/src/shared/bookResource.js +74 -0
  100. package/skills/jskit/references/patterns/crud/crud-feature-package/example/packages/books/src/shared/index.js +1 -0
  101. package/skills/jskit/references/patterns/crud/crud-screen-set/PATTERN.md +26 -8
  102. package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/BookEditPage.vue +2 -2
  103. package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/BookListPage.vue +2 -2
  104. package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/BookNewPage.vue +2 -2
  105. package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/BookViewPage.vue +3 -3
  106. package/skills/jskit/references/patterns/database/mysql-application/PATTERN.md +9 -4
  107. package/skills/jskit/references/patterns/database/mysql-application/example/package.json +2 -1
  108. package/skills/jskit/references/patterns/database/mysql-application/example/scripts/prepare-database.js +8 -0
  109. package/skills/jskit/references/patterns/database/postgres-application/PATTERN.md +8 -4
  110. package/skills/jskit/references/patterns/database/postgres-application/example/package.json +2 -1
  111. package/skills/jskit/references/patterns/database/postgres-application/example/scripts/prepare-database.js +8 -0
  112. package/skills/jskit/references/patterns/database/table-resource/PATTERN.md +117 -0
  113. package/skills/jskit/references/patterns/database/table-resource/example/orderResource.js +25 -0
  114. package/skills/jskit/references/patterns/realtime/realtime-application/PATTERN.md +7 -0
  115. package/skills/jskit/references/patterns/realtime/realtime-application/example/package.json +2 -2
  116. package/skills/jskit/references/patterns/rewards/google-rewarded/PATTERN.md +1 -1
  117. package/skills/jskit/references/patterns/server/feature-package/PATTERN.md +25 -17
  118. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/package.json +1 -1
  119. package/skills/jskit/references/patterns/server/feature-package/example/variations/InvoiceRollupFeature.js +6 -7
  120. package/skills/jskit/references/patterns/server/feature-package/example/variations/invoiceResource.js +15 -0
  121. package/skills/jskit/references/patterns/server/feature-package/example/variations/invoiceRollupActions.js +4 -4
  122. package/skills/jskit/references/patterns/server/feature-package/example/variations/ownedTableRepository.js +27 -0
  123. package/skills/jskit/references/patterns/server/feature-package/example/variations/types.js +1 -1
  124. package/skills/jskit/references/patterns/users/user-administration-server/PATTERN.md +59 -10
  125. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/package.json +5 -4
  126. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/src/server/UsersFeature.js +7 -5
  127. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/src/shared/index.js +1 -1
  128. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/src/shared/userCrud.js +21 -0
  129. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/package.json +11 -5
  130. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/server/UsersWorkspaceFeature.js +14 -5
  131. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/server/workspaceMembersOnly.js +52 -0
  132. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/shared/index.js +1 -1
  133. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/shared/userCrud.js +21 -0
  134. package/skills/jskit/references/patterns/workspaces/workspace-server/PATTERN.md +9 -9
  135. package/skills/jskit/references/patterns/workspaces/workspace-surfaces/PATTERN.md +16 -0
  136. package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/pages/home/workspaces/index.vue +2 -0
  137. package/skills/jskit/references/sanity-checks.md +27 -28
  138. package/skills/jskit/references/typed-features.md +114 -247
  139. package/patterns/feature-package/example/variations/customKnexRepository.js +0 -40
  140. package/reference/autogen/packages/json-rest-api-core.md +0 -66
  141. package/skills/jskit/references/heuristics/crud-repository-mapping.md +0 -140
  142. package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/src/server/BooksFeature.js +0 -13
  143. package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/src/shared/bookResource.js +0 -83
  144. package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/src/shared/index.js +0 -1
  145. package/skills/jskit/references/patterns/crud/resource-contract/PATTERN.md +0 -155
  146. package/skills/jskit/references/patterns/crud/resource-contract/example/bookResource.js +0 -87
  147. package/skills/jskit/references/patterns/server/feature-package/example/variations/customKnexRepository.js +0 -40
  148. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/src/shared/userResource.js +0 -69
  149. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/shared/userResource.js +0 -56
  150. /package/skills/jskit/references/patterns/crud/{json-api-resource-package → crud-feature-package}/example/migrations/20260815000000_books.cjs +0 -0
  151. /package/skills/jskit/references/patterns/crud/{json-api-resource-package → crud-feature-package}/example/packages/books/src/server/types.js +0 -0
@@ -1,140 +0,0 @@
1
- <!-- Generated from `packages/agent-docs/heuristics/crud-repository-mapping.md`. -->
2
-
3
- # CRUD Repository Mapping
4
-
5
- Use when:
6
- - a CRUD resource needs explicit DB column mapping
7
- - a field should exist in API output but is not a real DB column
8
- - the user mentions computed fields or projections
9
-
10
- Default JSKIT pattern:
11
- 1. Treat the schema as the API contract only.
12
- 2. Put persistence mapping on the field definitions themselves.
13
- 3. Use `actualField` for explicit DB column overrides.
14
- 4. Let generic CRUD runtime handle standard writable `date-time` fields automatically at the DB write seam.
15
- 5. Use `storage.writeSerializer` only for non-default write serialization.
16
- 6. Use `storage: { virtual: true }` for computed output fields.
17
- 7. For `createCrudResourceRuntime(...)` repositories, register computed SQL projections once with `virtualFields`.
18
- 8. For internal JSON REST repositories, register SQL-selected output fields with `createJsonRestResourceScopeOptions(resource, { queryFields })`.
19
- 9. Let generic read paths apply those projections automatically.
20
-
21
- Field metadata rules:
22
- - for a normal override, write:
23
-
24
- ```js
25
- createdAt: {
26
- type: "dateTime",
27
- required: true,
28
- actualField: "created_at"
29
- }
30
- ```
31
-
32
- - for a non-default write serializer override, write:
33
-
34
- ```js
35
- arrivalDatetime: {
36
- type: "dateTime",
37
- required: true,
38
- storage: {
39
- writeSerializer: "datetime-utc"
40
- }
41
- }
42
- ```
43
-
44
- - for a computed output field, write:
45
-
46
- ```js
47
- remainingBatchWeight: {
48
- type: "number",
49
- required: true,
50
- storage: {
51
- virtual: true
52
- }
53
- }
54
- ```
55
-
56
- - omit `actualField`/`storage` when the field is column-backed and the default snake_case mapping is correct
57
- - standard writable `format: "date-time"` fields do not need explicit `storage.writeSerializer`
58
- - use `storage.writeSerializer` only for non-default DB write behavior
59
- - `storage: { virtual: true }` cannot also define `actualField` or `storage.column`
60
- - `storage: { virtual: true }` cannot also define `storage.writeSerializer`
61
- - `storage: { virtual: true }` fields must not appear in create/patch write schemas
62
-
63
- Repository pattern:
64
- - build the runtime with `createCrudResourceRuntime(resource, knex, { ... })`, passing the application's Knex instance
65
- - register computed projections in `virtualFields`
66
- - keep SQL in the repository, not in shared metadata
67
- - let generic CRUD runtime apply `storage.writeSerializer` during create/update writes
68
-
69
- Example:
70
-
71
- ```js
72
- const repositoryRuntime = createCrudResourceRuntime(resource, knex, {
73
- context: "receivals repository",
74
- list: LIST_CONFIG,
75
- virtualFields: {
76
- remainingBatchWeight: {
77
- applyProjection(dbQuery, { knex, tableName, alias }) {
78
- const { sql, bindings } = getRemainingBatchWeightSqlParts({ tableName });
79
- dbQuery.select(knex.raw(`${sql} as ??`, [...bindings, alias]));
80
- }
81
- }
82
- }
83
- });
84
- ```
85
-
86
- Internal JSON REST pattern:
87
- - keep the API field in the resource schema as `storage: { virtual: true }`
88
- - pass server-only SQL projection callbacks through `createJsonRestResourceScopeOptions(...)`
89
- - keep query projection SQL in the provider/server registration file, not in browser-imported page code
90
-
91
- Example:
92
-
93
- ```js
94
- await addResourceIfMissing(
95
- api,
96
- "receivals",
97
- createJsonRestResourceScopeOptions(resource, {
98
- queryFields: {
99
- remainingProcessableWeight: {
100
- type: "number",
101
- select({ knex, column }) {
102
- return knex.raw("?? - coalesce(??, 0)", [
103
- column("received_weight"),
104
- column("processed_weight")
105
- ]);
106
- }
107
- }
108
- }
109
- })
110
- );
111
- ```
112
-
113
- If the resource module is server-only, a field may also declare `storage.queryProjection`; `createJsonRestResourceScopeOptions(...)` moves it into JSON REST `queryFields` and removes the virtual field from the storage schema. Prefer the `queryFields` option when the resource module is shared with client code.
114
-
115
- What CRUD core does for you:
116
- - default select columns include only column-backed output fields
117
- - create/update write payloads serialize standard writable `date-time` fields centrally
118
- - database reads serialize `date`, `time`, and `dateTime` values to their
119
- strict `json-rest-schema` string contracts before resource validation,
120
- respecting `temporalPrecision`
121
- - create/update write payloads also apply any explicit field write serializers centrally
122
- - `list`, `findById`, `listByIds`, and `listByForeignIds` apply registered virtual projections automatically
123
- - search and parent-filter fallback derivation only use column-backed fields
124
- - `listByIds(..., { valueKey })` requires that `valueKey` be column-backed
125
-
126
- Avoid:
127
- - manual `clearSelect()` / re-select hacks in individual repository methods just to add computed fields
128
- - putting SQL fragments or joins into shared field metadata
129
- - inventing `storage` modes beyond the documented `virtual` contract
130
-
131
- Review checks:
132
- - schema defines contract, not storage
133
- - field definitions own mapping
134
- - standard datetime DB write serialization stays automatic and runtime-owned
135
- - any non-default DB write serialization lives in `storage.writeSerializer`, not in per-repository hooks
136
- - computed fields use `storage: { virtual: true }`
137
- - repository runtime registers matching `virtualFields`, or the JSON REST provider registers matching `queryFields`
138
- - no per-method projection duplication when generic CRUD reads already cover the field
139
- - no JavaScript `Date` object crosses a strict resource validation boundary;
140
- custom repositories return ISO/RFC 3339 strings explicitly
@@ -1,13 +0,0 @@
1
- import { defineCrudJsonApiFeature } from "@jskit-ai/crud-core/server/defineCrudJsonApiFeature";
2
- import { bookResource } from "../shared/bookResource.js";
3
-
4
- const BooksFeature = defineCrudJsonApiFeature({
5
- resource: bookResource,
6
- id: "app.books",
7
- capability: "app.books",
8
- surface: "app",
9
- ownershipFilter: "user",
10
- relativePath: "/books"
11
- });
12
-
13
- export { BooksFeature };
@@ -1,83 +0,0 @@
1
- import { defineCrudResource } from "@jskit-ai/resource-crud-core/shared/crudResource";
2
-
3
- const bookResource = defineCrudResource({
4
- namespace: "books",
5
- tableName: "books",
6
- apiAccess: "authenticated",
7
- autofilter: "user",
8
- schema: {
9
- userId: {
10
- type: "id",
11
- required: true,
12
- hidden: true,
13
- operations: {}
14
- },
15
- title: {
16
- type: "string",
17
- maxLength: 255,
18
- required: true,
19
- search: true,
20
- operations: {
21
- output: { required: true },
22
- create: { required: true },
23
- patch: { required: false }
24
- }
25
- },
26
- author: {
27
- type: "string",
28
- maxLength: 255,
29
- required: true,
30
- search: true,
31
- operations: {
32
- output: { required: true },
33
- create: { required: true },
34
- patch: { required: false }
35
- }
36
- },
37
- notes: {
38
- type: "string",
39
- maxLength: 65535,
40
- nullable: true,
41
- search: true,
42
- operations: {
43
- output: { required: true },
44
- create: { required: false },
45
- patch: { required: false }
46
- }
47
- },
48
- createdAt: {
49
- type: "dateTime",
50
- temporalPrecision: 0,
51
- default: "now()",
52
- storage: { writeSerializer: "datetime-utc" },
53
- operations: { output: { required: true } }
54
- },
55
- updatedAt: {
56
- type: "dateTime",
57
- temporalPrecision: 0,
58
- default: "now()",
59
- storage: { writeSerializer: "datetime-utc" },
60
- operations: { output: { required: true } }
61
- }
62
- },
63
- searchSchema: {
64
- id: { type: "id", actualField: "id" },
65
- q: {
66
- type: "string",
67
- oneOf: ["title", "author", "notes"],
68
- filterOperator: "like",
69
- splitBy: " ",
70
- matchAll: true
71
- }
72
- },
73
- defaultSort: ["-createdAt"],
74
- messages: {
75
- validation: "Fix invalid values and try again.",
76
- saveSuccess: "Book saved.",
77
- saveError: "Unable to save this book.",
78
- deleteSuccess: "Book deleted.",
79
- deleteError: "Unable to delete this book."
80
- }
81
- });
82
-
83
- export { bookResource };
@@ -1 +0,0 @@
1
- export { bookResource } from "./bookResource.js";
@@ -1,155 +0,0 @@
1
- ---
2
- id: crud/resource-contract
3
- title: Owner-scoped CRUD resource contract
4
- summary: Define an authenticated application resource whose records belong to the current user.
5
- keywords: authenticated, crud, database, owner-scoped, resource, user
6
- requires: @jskit-ai/resource-crud-core
7
- ---
8
-
9
- # Owner-scoped CRUD resource 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 `defineCrudResource()`.
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 `autofilter` 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
- - `autofilter: "user"` is used only for genuine current-user ownership.
47
- - Each product field's output, create, and patch participation is its
48
- `operations` block, or the default `defineCrudResource()` gives a field
49
- without one (see Field operations and lookups below).
50
- - Temporal database values use the declared storage serializer.
51
- - The source-controlled migration and resource contract agree.
52
- - Server policy tests prove that one user cannot read or mutate another user's
53
- records.
54
-
55
- ## Framework APIs
56
-
57
- The example uses `defineCrudResource()` from
58
- `@jskit-ai/resource-crud-core/shared/crudResource`. That API derives the normal
59
- CRUD operation validators from one readable field contract.
60
-
61
- Higher layers should consume this resource through JSKIT's CRUD service,
62
- repository, route, and UI APIs. They should not rebuild field validators or
63
- serialize requests independently.
64
-
65
- ## Field operations and lookups
66
-
67
- A field's `operations` name the operations it takes part in: `output` (the
68
- record in every response), and `create` and `patch` (the request bodies; an
69
- enabled `replace` uses the `create` fields unless a field names `replace`). A
70
- field that leaves `operations` out takes the default:
71
-
72
- | Field | Default `operations` |
73
- | --- | --- |
74
- | `primary: true` | `{}`: no operation; every record output already carries its `id` |
75
- | `hidden: true` | `{}`: no operation |
76
- | `readOnly: true` | `{ output: { required: true } }` |
77
- | any other field | `{ output: { required: true }, create: { required: <the field's required> }, patch: { required: false } }` |
78
-
79
- So a `required: true` field is required on create, and any other field is
80
- optional there. An `operations` block you write always wins, for example
81
- `operations: { output: {}, create: {}, patch: {} }` for a field that is
82
- optional everywhere. Write the block only where it differs from the default:
83
-
84
- ```js
85
- schema: {
86
- userId: { type: "id", required: true, hidden: true },
87
- title: { type: "string", maxLength: 255, required: true, search: true },
88
- notes: { type: "string", maxLength: 65535, nullable: true, search: true },
89
- createdAt: { type: "dateTime", default: "now()", readOnly: true, storage: { writeSerializer: "datetime-utc" } }
90
- }
91
- ```
92
-
93
- A field that looks up a record of another resource can name that resource's
94
- namespace with `lookup`:
95
-
96
- ```js
97
- shelfId: { type: "id", nullable: true, search: true, lookup: "shelves" }
98
- ```
99
-
100
- `defineCrudResource()` expands it, where `lookup` stood, to:
101
-
102
- ```js
103
- relation: { kind: "lookup", namespace: "shelves", valueKey: "id" },
104
- belongsTo: "shelves", // the namespace's JSON REST resource, camel-cased
105
- as: "shelf", // the field key without its Id suffix
106
- ui: { formControl: "autocomplete" }
107
- ```
108
-
109
- Keys you write beside `lookup` win: `belongsTo` and `as` replace the
110
- filled-in values, and `relation` and `ui` are merged over them, so
111
- `relation: { labelKey: "name" }` adds a label key and
112
- `ui: { formControl: "select" }` picks a select. A field whose key has no `Id`
113
- suffix must write `as`. The built resource equals one that writes the expanded
114
- keys out.
115
-
116
- ## Example files
117
-
118
- - `example/bookResource.js` is a complete resource contract for personal book
119
- records.
120
-
121
- The example deliberately uses a concrete domain. Rename and edit normal source
122
- rather than feeding it through placeholder interpolation.
123
-
124
- ## Variation points
125
-
126
- Safe adaptations include:
127
-
128
- - namespace and table name
129
- - product fields and validation
130
- - searchable fields and default sort
131
- - enabled CRUD operations
132
- - user-facing messages
133
- - lookup relationships supported by the resource APIs
134
-
135
- Changing ownership, access, identity, or persistence architecture selects a
136
- different pattern and requires corresponding policy and migration evidence.
137
-
138
- ## Verification
139
-
140
- - Import the resource and prove all intended operations exist.
141
- - Validate representative accepted and rejected field values.
142
- - Rebuild the table from source-controlled migrations in a disposable database.
143
- - Run positive current-user CRUD tests.
144
- - Run negative cross-user read and mutation tests.
145
- - Run the application's focused tests and broad verifier at sign-off.
146
-
147
- ## Avoid
148
-
149
- - generator provenance or scaffold-shape metadata
150
- - a field-by-field questionnaire
151
- - a live table as the only source of schema truth
152
- - app-specific request serializers that duplicate the resource contract
153
- - hidden ownership aliases other than the framework's explicit ownership field
154
- - durable receipts recording that this pattern was copied
155
- - changing an installed baseline migration instead of adding a new migration
@@ -1,87 +0,0 @@
1
- import { defineCrudResource } from "@jskit-ai/resource-crud-core/shared/crudResource";
2
-
3
- const bookResource = defineCrudResource({
4
- namespace: "books",
5
- tableName: "books",
6
- apiAccess: "authenticated",
7
- schema: {
8
- userId: {
9
- type: "id",
10
- required: true,
11
- hidden: true,
12
- operations: {}
13
- },
14
- title: {
15
- type: "string",
16
- maxLength: 255,
17
- required: true,
18
- search: true,
19
- operations: {
20
- output: { required: true },
21
- create: { required: true },
22
- patch: { required: false }
23
- }
24
- },
25
- author: {
26
- type: "string",
27
- maxLength: 255,
28
- required: true,
29
- search: true,
30
- operations: {
31
- output: { required: true },
32
- create: { required: true },
33
- patch: { required: false }
34
- }
35
- },
36
- notes: {
37
- type: "string",
38
- maxLength: 65535,
39
- nullable: true,
40
- search: true,
41
- operations: {
42
- output: { required: true },
43
- create: { required: false },
44
- patch: { required: false }
45
- }
46
- },
47
- createdAt: {
48
- type: "dateTime",
49
- temporalPrecision: 0,
50
- default: "now()",
51
- storage: { writeSerializer: "datetime-utc" },
52
- operations: {
53
- output: { required: true }
54
- }
55
- },
56
- updatedAt: {
57
- type: "dateTime",
58
- temporalPrecision: 0,
59
- default: "now()",
60
- storage: { writeSerializer: "datetime-utc" },
61
- operations: {
62
- output: { required: true }
63
- }
64
- }
65
- },
66
- searchSchema: {
67
- id: { type: "id", actualField: "id" },
68
- q: {
69
- type: "string",
70
- oneOf: ["title", "author", "notes"],
71
- filterOperator: "like",
72
- splitBy: " ",
73
- matchAll: true
74
- }
75
- },
76
- defaultSort: ["-createdAt"],
77
- autofilter: "user",
78
- messages: {
79
- validation: "Fix invalid values and try again.",
80
- saveSuccess: "Book saved.",
81
- saveError: "Unable to save this book.",
82
- deleteSuccess: "Book deleted.",
83
- deleteError: "Unable to delete this book."
84
- }
85
- });
86
-
87
- export { bookResource };
@@ -1,40 +0,0 @@
1
- import { createWithTransaction } from "@jskit-ai/database-runtime/shared";
2
-
3
- /**
4
- * The invoice rollup's persistence: a reviewed custom Knex repository.
5
- * @param {{ knex: import("@jskit-ai/database-runtime/server/types").RuntimeKnex }} dependencies
6
- */
7
- function createInvoiceRollup({ knex }) {
8
- const withTransaction = createWithTransaction(knex);
9
-
10
- async function getStatus(input, options = {}) {
11
- return {
12
- ok: true,
13
- feature: "invoice-rollup",
14
- persistence: "custom-knex",
15
- tableName: "invoice_rollups",
16
- hasTransaction: Boolean(options.trx),
17
- input
18
- };
19
- }
20
-
21
- async function execute(input, options = {}) {
22
- return {
23
- accepted: false,
24
- feature: "invoice-rollup",
25
- persistence: "custom-knex",
26
- tableName: "invoice_rollups",
27
- hasTransaction: Boolean(options.trx),
28
- input,
29
- message: "Replace this example with the reviewed domain-specific query."
30
- };
31
- }
32
-
33
- return Object.freeze({
34
- withTransaction,
35
- getStatus,
36
- execute
37
- });
38
- }
39
-
40
- export { createInvoiceRollup };
@@ -1,69 +0,0 @@
1
- import { defineCrudResource } from "@jskit-ai/resource-crud-core/shared/crudResource";
2
-
3
- const resource = defineCrudResource({
4
- namespace: "users",
5
- tableName: "users",
6
- crudOperations: ["list", "view"],
7
- schema: {
8
- name: {
9
- type: "string",
10
- required: true,
11
- minLength: 1,
12
- maxLength: 160,
13
- actualField: "display_name",
14
- search: true,
15
- operations: {
16
- output: { required: false }
17
- }
18
- },
19
- email: {
20
- type: "string",
21
- required: true,
22
- search: true,
23
- operations: {
24
- output: { required: false }
25
- }
26
- },
27
- username: {
28
- type: "string",
29
- required: true,
30
- search: true,
31
- operations: {
32
- output: { required: false }
33
- }
34
- },
35
- createdAt: {
36
- type: "dateTime",
37
- required: true,
38
- storage: { writeSerializer: "datetime-utc" },
39
- operations: {
40
- output: { required: true }
41
- }
42
- },
43
- updatedAt: {
44
- type: "dateTime",
45
- required: true,
46
- storage: { writeSerializer: "datetime-utc" },
47
- operations: {
48
- output: { required: true }
49
- }
50
- }
51
- },
52
- searchSchema: {
53
- id: {
54
- type: "id",
55
- actualField: "id"
56
- },
57
- q: {
58
- type: "string",
59
- oneOf: ["name", "email", "username"],
60
- filterOperator: "like",
61
- splitBy: " ",
62
- matchAll: true
63
- }
64
- },
65
- defaultSort: ["name", "email"],
66
- autofilter: "public"
67
- });
68
-
69
- export { resource };
@@ -1,56 +0,0 @@
1
- import { defineCrudResource } from "@jskit-ai/resource-crud-core/shared/crudResource";
2
-
3
- const resource = defineCrudResource({
4
- namespace: "users",
5
- tableName: "users",
6
- crudOperations: ["list", "view"],
7
- schema: {
8
- name: {
9
- type: "string",
10
- required: true,
11
- minLength: 1,
12
- maxLength: 160,
13
- actualField: "display_name",
14
- search: true,
15
- operations: { output: { required: false } }
16
- },
17
- email: {
18
- type: "string",
19
- required: true,
20
- search: true,
21
- operations: { output: { required: false } }
22
- },
23
- username: {
24
- type: "string",
25
- required: true,
26
- search: true,
27
- operations: { output: { required: false } }
28
- },
29
- createdAt: {
30
- type: "dateTime",
31
- required: true,
32
- storage: { writeSerializer: "datetime-utc" },
33
- operations: { output: { required: true } }
34
- },
35
- updatedAt: {
36
- type: "dateTime",
37
- required: true,
38
- storage: { writeSerializer: "datetime-utc" },
39
- operations: { output: { required: true } }
40
- }
41
- },
42
- searchSchema: {
43
- id: { type: "id", actualField: "id" },
44
- q: {
45
- type: "string",
46
- oneOf: ["name", "email", "username"],
47
- filterOperator: "like",
48
- splitBy: " ",
49
- matchAll: true
50
- }
51
- },
52
- defaultSort: ["name", "email"],
53
- autofilter: "public"
54
- });
55
-
56
- export { resource };