@harperfast/template-react-ts-studio 1.12.2 → 1.12.3

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 (20) hide show
  1. package/.agents/skills/harper-best-practices/AGENTS.md +632 -474
  2. package/.agents/skills/harper-best-practices/rules/automatic-apis.md +131 -55
  3. package/.agents/skills/harper-best-practices/rules/checking-authentication.md +155 -61
  4. package/.agents/skills/harper-best-practices/rules/deploying-to-harper-fabric.md +63 -85
  5. package/.agents/skills/harper-best-practices/rules/programmatic-table-requests.md +111 -52
  6. package/.agents/skills/harper-best-practices/rules/querying-rest-apis.md +38 -70
  7. package/.agents/skills/harper-best-practices/rules/schema-design-tooling.md +81 -69
  8. package/.agents/skills/harper-best-practices/rules/v5-upgrade.md +82 -96
  9. package/.agents/skills/harper-best-practices/rules.manifest.yaml +212 -0
  10. package/agent/skills/harper-best-practices/AGENTS.md +632 -474
  11. package/agent/skills/harper-best-practices/rules/automatic-apis.md +131 -55
  12. package/agent/skills/harper-best-practices/rules/checking-authentication.md +155 -61
  13. package/agent/skills/harper-best-practices/rules/deploying-to-harper-fabric.md +63 -85
  14. package/agent/skills/harper-best-practices/rules/programmatic-table-requests.md +111 -52
  15. package/agent/skills/harper-best-practices/rules/querying-rest-apis.md +38 -70
  16. package/agent/skills/harper-best-practices/rules/schema-design-tooling.md +81 -69
  17. package/agent/skills/harper-best-practices/rules/v5-upgrade.md +82 -96
  18. package/agent/skills/harper-best-practices/rules.manifest.yaml +212 -0
  19. package/package.json +1 -1
  20. package/skills-lock.json +1 -1
@@ -8,17 +8,17 @@ metadata:
8
8
  - >-
9
9
  fabric/cluster-creation-management.md#Connecting the Harper CLI to a
10
10
  Cluster
11
- sourceCommit: 6bf676d4bde158fcd08a81565556a0ee91768274
12
- inputHash: 8c8b2fabac08a561
11
+ sourceCommit: 677ad213d67822e109c83619e181ca23a59823db
12
+ inputHash: e5586ad2bcc7c12a
13
13
  ---
14
14
 
15
15
  # Deploying to Harper Fabric
16
16
 
17
- Instructions for the agent to follow when deploying a Harper application to a remote Harper Fabric cluster.
17
+ Instructions for the agent to follow when deploying a Harper application to a remote Harper Fabric cloud cluster.
18
18
 
19
19
  ## When to Use
20
20
 
21
- Apply this rule when deploying a Harper application to a remote Harper Fabric cluster or any remote Harper instance. This includes first-time deploys, redeployments, rollbacks, and CI/CD pipeline deployments. See [creating-a-fabric-account-and-cluster.md](creating-a-fabric-account-and-cluster.md) to set up a cluster before deploying.
21
+ Apply this rule when deploying a Harper application to a remote Harper Fabric cluster or any remote Harper instance. This includes first-time deploys, redeployments, rollbacks, CI/CD pipeline deploys, and provisioning credentials for private repositories. See [creating-a-fabric-account-and-cluster.md](creating-a-fabric-account-and-cluster.md) for setting up the cluster before deploying.
22
22
 
23
23
  ## How It Works
24
24
 
@@ -29,7 +29,7 @@ Apply this rule when deploying a Harper application to a remote Harper Fabric cl
29
29
  # Provide cluster username and password when prompted
30
30
  ```
31
31
 
32
- 2. **Deploy the application**: Run `harper deploy` with the required parameters. After logging in, no credentials need to be repeated.
32
+ 2. **Deploy the application**: After login, run `harper deploy` without repeating credentials. Set `restart=true` and `replicated=true` for a production deploy.
33
33
 
34
34
  ```bash
35
35
  harper deploy \
@@ -40,30 +40,42 @@ Apply this rule when deploying a Harper application to a remote Harper Fabric cl
40
40
  replicated=true
41
41
  ```
42
42
 
43
- 3. **Choose a package source**: Set the `package` parameter to any valid npm dependency value, or omit it to package and upload the current local directory.
43
+ 3. **Use environment variables for CI/CD**: Instead of `harper login`, export credentials as environment variables before calling `harper deploy`.
44
44
 
45
- | Value | Effect |
46
- | ---------------------------------------------------- | ------------------------------------------------ |
47
- | _(omitted)_ | Packages and deploys the current local directory |
48
- | `"@harperdb/status-check"` | npm package |
49
- | `"HarperDB/status-check"` | GitHub shorthand |
50
- | `"https://github.com/HarperDB/status-check"` | GitHub URL |
51
- | `"git+ssh://git@github.com:HarperDB/secret-app.git"` | Private repo via SSH |
52
- | `"https://example.com/application.tar.gz"` | Tarball URL |
45
+ ```bash
46
+ export HARPER_CLI_USERNAME=<username>
47
+ export HARPER_CLI_PASSWORD=<password>
48
+ harper deploy \
49
+ project=<name> \
50
+ package=<package> \
51
+ target=<remote> \
52
+ restart=true \
53
+ replicated=true
54
+ ```
55
+
56
+ 4. **Choose a package source**: The `package` field accepts any valid npm dependency value. Select the form that matches your source:
57
+
58
+ | Source | `package` value |
59
+ | ----------------------- | ---------------------------------------------------- |
60
+ | Current local directory | Omit `package` |
61
+ | npm package | `"@harperdb/status-check"` |
62
+ | GitHub (public) | `"HarperFast/status-check"` or full URL |
63
+ | Private repo (SSH) | `"git+ssh://git@github.com:HarperDB/secret-app.git"` |
64
+ | Tarball | `"https://example.com/application.tar.gz"` |
53
65
 
54
66
  For git tags, use the `semver` directive:
55
67
 
56
68
  ```
57
- HarperDB/application-template#semver:v1.0.0
69
+ HarperFast/application-template#semver:v1.0.0
58
70
  ```
59
71
 
60
- 4. **Deploy by reference (optional)**: Instead of uploading a snapshot, send a pinned git reference so the cluster fetches and builds that exact commit. Use `by_ref=true` to resolve the current commit from the local repository automatically.
72
+ 5. **Deploy by reference for reproducible deploys**: Pass `by_ref=true` to send a pinned git SHA instead of uploading a snapshot. The cluster fetches and builds from that exact commit.
61
73
 
62
74
  ```bash
63
75
  harper deploy by_ref=true restart=true replicated=true
64
76
  ```
65
77
 
66
- Use `ref` to deploy a specific commit, tag, or branch (resolved to a full SHA before sending):
78
+ Use `ref` to target a specific commit, tag, or branch (resolved to a full SHA before sending):
67
79
 
68
80
  ```bash
69
81
  # Deploy a specific tag
@@ -73,53 +85,32 @@ Apply this rule when deploying a Harper application to a remote Harper Fabric cl
73
85
  harper deploy ref=9f8c2a1 restart=true replicated=true
74
86
  ```
75
87
 
76
- **Key `by_ref` parameters:**
77
-
78
- | Parameter | Required | Description |
79
- | ------------ | -------- | --------------------------------------------------------------------------------------------------------------------------- |
80
- | `by_ref` | — | Build the package reference from the local repository |
81
- | `ref` | optional | Deploy a specific commit, tag, or branch instead of `HEAD`. Implies `by_ref`. |
82
- | `credential` | optional | Set to `true` to authenticate the clone with the stored credential for the repository's host. Omit for public repositories. |
83
-
84
- > Commit and push before deploying by reference. The cluster clones from the remote and only sees pushed commits. Run `git fetch` if the unpushed-commit check fires for a commit you know you pushed.
88
+ **Key constraints for `ref` values:**
89
+ - Must name something a clone can fetch: `refs/heads/*` and `refs/tags/*`, or a bare branch or tag name.
90
+ - Anything else (e.g., `refs/pull/123/head`) is rejected up front.
91
+ - If a ref can't be resolved, the deploy stops — run `git fetch` and retry, or pass a full commit SHA.
92
+ - Commit and push before deploying: the cluster clones from the remote and only sees pushed commits.
85
93
 
86
- 5. **Authenticate for CI/CD**: Use environment variables instead of `harper login` for automated pipelines.
94
+ 6. **Deploy private repositories by reference**: Pass `credential=true` alongside `by_ref=true`. The CLI attaches a credentials reference; the cluster resolves the secret in memory at clone time — no token travels in the operation body or lands on disk.
87
95
 
88
96
  ```bash
89
- export HARPER_CLI_USERNAME=<username>
90
- export HARPER_CLI_PASSWORD=<password>
91
- harper deploy \
92
- project=<name> \
93
- package=<package> \
94
- target=<remote> \
95
- restart=true \
96
- replicated=true
97
+ harper deploy by_ref=true credential=true restart=true replicated=true
97
98
  ```
98
99
 
99
- 6. **Provision credentials for private repositories**: Run `harper deploy setup=true` once per component and source to provision a deploy credential. Run this with an administrative credential, not the CI identity.
100
+ 7. **Provision a deploy credential for private sources**: Run `harper deploy setup=true` once per component and source. This is interactive and requires **super_user** — run it with an administrative credential, not the CI identity.
100
101
 
101
102
  ```bash
102
103
  harper deploy setup=true
103
104
  ```
104
105
 
105
- Then pass `credential=true` on subsequent deploys:
106
-
107
- ```bash
108
- harper deploy by_ref=true credential=true restart=true replicated=true
109
- ```
110
-
111
- 7. **Use inline auth for one-off commands (not recommended for production)**: Pass `auth_username` and `auth_password` directly. These take precedence over environment variables and saved login tokens.
106
+ This command:
107
+ 1. Fetches the cluster's public key with `get_secrets_public_key`.
108
+ 2. Encrypts the token locally into an `enc:v1:` envelope.
109
+ 3. Stores only the ciphertext with `set_secret`, in the component-scoped tier.
110
+ 4. Grants the component permission to resolve it with `grant_secret`.
111
+ 5. Prints the `credentials` reference for the deploy to use.
112
112
 
113
- ```bash
114
- harper deploy \
115
- project=<name> \
116
- package=<package> \
117
- auth_username=<username> \
118
- auth_password=<password> \
119
- target=<remote> \
120
- restart=true \
121
- replicated=true
122
- ```
113
+ Use a **fine-grained** personal access token (PAT) scoped to **Contents: Read-only** on the specific repository. Avoid session tokens from `gh` CLI — they typically carry `repo`, `read:org`, `gist`, and `workflow` scopes across your whole account.
123
114
 
124
115
  ## Examples
125
116
 
@@ -129,60 +120,47 @@ Apply this rule when deploying a Harper application to a remote Harper Fabric cl
129
120
  harper login https://my-cluster.harperdbcloud.com
130
121
  harper deploy \
131
122
  project=my-app \
132
- package="@myorg/my-app" \
123
+ package="HarperFast/my-app" \
133
124
  target=https://my-cluster.harperdbcloud.com \
134
125
  restart=true \
135
126
  replicated=true
136
127
  ```
137
128
 
138
- **Deploy current directory as a snapshot:**
129
+ **CI/CD deploy using environment variables:**
139
130
 
140
131
  ```bash
132
+ export HARPER_CLI_USERNAME=admin
133
+ export HARPER_CLI_PASSWORD=secret
141
134
  harper deploy \
142
135
  project=my-app \
136
+ package="HarperFast/my-app" \
143
137
  target=https://my-cluster.harperdbcloud.com \
144
138
  restart=true \
145
139
  replicated=true
146
140
  ```
147
141
 
148
- **Deploy a pinned tag by reference:**
149
-
150
- ```bash
151
- harper deploy ref=v1.2.0 restart=true replicated=true
152
- ```
153
-
154
- **Deploy a private repository by reference with a stored credential:**
155
-
156
- ```bash
157
- harper deploy by_ref=true credential=true restart=true replicated=true
158
- ```
159
-
160
- **GitHub Actions — deploy the pull request head commit explicitly:**
142
+ **Deploy by reference in GitHub Actions (pull request):**
161
143
 
162
144
  ```bash
163
145
  harper deploy ref=${{ github.event.pull_request.head.sha }} restart=true replicated=true
164
146
  ```
165
147
 
166
- **CI/CD deploy using environment variables:**
148
+ **Deploy a private repo by reference with a provisioned credential:**
167
149
 
168
150
  ```bash
169
- export HARPER_CLI_USERNAME=<username>
170
- export HARPER_CLI_PASSWORD=<password>
171
- harper deploy \
172
- project=my-app \
173
- package="HarperDB/my-app#semver:v1.0.0" \
174
- target=https://my-cluster.harperdbcloud.com \
175
- restart=true \
176
- replicated=true
151
+ # Provision once (run as super_user)
152
+ harper deploy setup=true
153
+
154
+ # Deploy subsequently
155
+ harper deploy by_ref=true credential=true restart=true replicated=true
177
156
  ```
178
157
 
179
158
  ## Notes
180
159
 
181
- - `harper login` stores an authentication token so subsequent `harper deploy` commands do not require credentials to be repeated.
182
- - Inline `auth_username`/`auth_password` parameters take precedence over environment variables, which take precedence over saved login tokens.
183
- - For SSH-based private repos, register keys with the `add_ssh_key` operation before deploying.
184
- - `by_ref` deploys build from source on each cluster node. If your application requires a build step that cannot run on the node, deploy a built payload (omit `by_ref`) instead.
185
- - `harper deploy setup=true` requires **super_user** privileges. Provision credentials with an administrative account, not the CI identity.
186
- - Tags and branches passed to `ref` are resolved to a full commit SHA locally before the deploy is sent. If resolution fails, run `git fetch` and retry, or pass a full commit SHA directly.
187
- - The `refs/pull/<n>/head` style refs are rejected; use `ref=${{ github.event.pull_request.head.sha }}` in GitHub Actions pull request workflows instead.
188
- - Deploy credentials provisioned via `harper deploy setup=true` are stored scoped to the component and reused on every subsequent deploy, including rollbacks.
160
+ - `auth_username` and `auth_password` can be passed directly as deploy parameters for one-off commands, but this is not recommended for production. Dedicated authentication parameters take precedence over environment variables and saved login tokens.
161
+ - The `enc:v1:` envelope means the plaintext token never leaves your machine — only ciphertext is stored and replicated.
162
+ - Deploy credentials are stored scoped to the component, never in the global `processEnv` tier. If a global secret exists at the derived name, it is converted to the component-scoped tier automatically.
163
+ - Because stored credentials are durable, later deploys and rollbacks reuse them without re-entering anything.
164
+ - The unpushed-commit check is skipped under GitHub Actions; the dirty-tree warning still applies.
165
+ - Deploying by reference means the cluster installs and builds from source. If your application requires a build step that cannot run on the node, deploy the built output as a payload deploy instead.
166
+ - For SSH-based private repos, use the `add_ssh_key` operation to register keys before deploying.
@@ -14,21 +14,21 @@ metadata:
14
14
  reference/v5/resources/resource-api.md#`addTo(property: string, value:
15
15
  number)`
16
16
  - reference/v5/components/javascript-environment.md#Module Loading
17
- sourceCommit: 3749d0c54be457a2a65d9a63c738a5dc88989ecd
18
- inputHash: ace5c3f4a0ad4519
17
+ sourceCommit: 677ad213d67822e109c83619e181ca23a59823db
18
+ inputHash: ce2181ecade6522f
19
19
  ---
20
20
 
21
21
  # Programmatic Table Requests
22
22
 
23
- Instructions for the agent to interact with Harper tables programmatically using the `tables` object and its query API.
23
+ Instructions for the agent to interact with Harper tables programmatically using the `tables` object, including querying, transactions, and module integration.
24
24
 
25
25
  ## When to Use
26
26
 
27
- Apply this rule when writing server-side code that reads from or writes to Harper tables directly — for example, in request handlers, background jobs, or SSR rendering — without going through the REST API. Use it whenever you need to construct queries with `conditions`, `select`, `sort`, or `search(`.
27
+ Apply this rule when writing server-side Harper component code that reads from or writes to tables directly — bypassing REST endpoints — such as in request handlers, background jobs, timers, or SSR rendering. Use it whenever you need to construct queries with `conditions`, manage transactions explicitly, or perform CRDT-safe mutations.
28
28
 
29
29
  ## How It Works
30
30
 
31
- 1. **Import `tables`**: Pull `tables` from the `harper` package. Each property on `tables` corresponds to a table defined in `schema.graphql`.
31
+ 1. **Import `tables` from `harper`**: Access all tables in the default `data` database via the `tables` object. Each table defined with `@table` in `schema.graphql` is a property.
32
32
 
33
33
  ```javascript
34
34
  import { tables } from 'harper';
@@ -36,7 +36,7 @@ Apply this rule when writing server-side code that reads from or writes to Harpe
36
36
  // same as: databases.data.Product
37
37
  ```
38
38
 
39
- 2. **Define your schema**: Declare tables with `@table` in `schema.graphql`. Each type becomes a property on `tables`.
39
+ 2. **Define your schema with `@table`**: Tables must be declared in `schema.graphql`. Use `@indexed` on attributes you intend to sort or filter efficiently.
40
40
 
41
41
  ```graphql
42
42
  type Product @table {
@@ -46,15 +46,7 @@ Apply this rule when writing server-side code that reads from or writes to Harpe
46
46
  }
47
47
  ```
48
48
 
49
- 3. **Create and modify records**: Use `create`, `patch`, and `get` for basic CRUD.
50
-
51
- ```javascript
52
- const created = await Product.create({ name: 'Shirt', price: 9.5 });
53
- await Product.patch(created.id, { price: Math.round(created.price * 0.8 * 100) / 100 });
54
- const record = await Product.get(created.id);
55
- ```
56
-
57
- 4. **Query with `search(`**: Pass a query object to `Product.search(query)`. It returns an async iterable.
49
+ 3. **Use `search(` to query records**: Pass a Query object to `search(`. Iterate results with `for await`.
58
50
 
59
51
  ```javascript
60
52
  const query = {
@@ -65,7 +57,7 @@ Apply this rule when writing server-side code that reads from or writes to Harpe
65
57
  }
66
58
  ```
67
59
 
68
- 5. **Build `conditions`**: Each condition object filters records. Nest conditions with `operator` for boolean logic.
60
+ 4. **Build `conditions` arrays to filter**: Each condition object supports these properties:
69
61
 
70
62
  | Property | Description |
71
63
  | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -75,46 +67,95 @@ Apply this rule when writing server-side code that reads from or writes to Harpe
75
67
  | `conditions` | Nested conditions array |
76
68
  | `operator` | `and` (default) or `or` for the nested `conditions` |
77
69
 
78
- 6. **Use `select`** to control which properties are returned. Accepts an array of property names, a string for a single property, or nested objects for relationships.
70
+ 5. **Apply `select` to shape results**: Return only the fields you need. Supports arrays, nested relationship selects, and special properties.
79
71
 
80
72
  ```javascript
81
- // Array of names
73
+ // Array of fields
82
74
  Product.search({ select: ['name', 'price'] });
83
75
 
84
76
  // Nested relationship select
85
77
  Book.get({ id: 42, select: ['id', 'title', { name: 'author', select: ['name'] }] });
86
78
  ```
87
79
 
88
- Special `select` values:
89
- - `$id` — returns the primary key regardless of its name
90
- - `$updatedtime` — returns the last-updated timestamp
91
- - `$distance` — returns the computed distance when querying a vector index
92
-
93
- 7. **Use `addTo`** for concurrent-safe numeric increments (CRDT incrementation, safe across threads and nodes).
80
+ Special `select` values: `$id`, `$updatedtime`, `$distance`.
94
81
 
95
- ```javascript
96
- const record = await Product.update(target.id);
97
- record.addTo('quantity', -1);
98
- ```
99
-
100
- 8. **Apply `sort`, `limit`, and `offset`** for ordering and pagination. A `sort` attribute must be `@indexed`, or at least one `conditions` entry must be present. Pass `allowFullScan: true` to permit an unconditional ordered scan.
82
+ 6. **Apply `sort` with an `@indexed` attribute**: Harper uses an index to provide sort order. Sort by an `@indexed` attribute without requiring a condition, or provide at least one condition when sorting by a non-indexed attribute.
101
83
 
102
84
  ```javascript
85
+ // Sort by primary key with an open-ended condition to avoid scan error
103
86
  Product.search({
104
87
  conditions: [{ attribute: 'id', comparator: 'greater_than', value: '' }],
105
88
  sort: { attribute: 'id' },
106
89
  });
107
90
  ```
108
91
 
109
- | Sort property | Description |
110
- | ------------- | ---------------------------------------------------------- |
111
- | `attribute` | Property name (or array for chained relationship property) |
112
- | `descending` | Sort descending if `true` (default: `false`) |
113
- | `next` | Secondary sort to resolve ties (same structure) |
92
+ Sort object properties:
93
+
94
+ | Property | Description |
95
+ | ------------ | -------------------------------------------------------- |
96
+ | `attribute` | Property name or array for chained relationship property |
97
+ | `descending` | Sort descending if `true` (default: `false`) |
98
+ | `next` | Secondary sort to resolve ties (same structure) |
99
+
100
+ 7. **Use `limit` and `offset` for pagination**:
101
+
102
+ ```javascript
103
+ Product.search({ conditions: [...], limit: 20, offset: 40 });
104
+ ```
105
+
106
+ 8. **Use `explain` and `enforceExecutionOrder` for debugging**:
107
+ - `explain: true` — returns conditions reordered as Harper will execute them.
108
+ - `enforceExecutionOrder: true` — forces conditions to execute in the order supplied, disabling automatic re-ordering.
109
+
110
+ 9. **Use `addTo` for concurrent-safe numeric updates**: `addTo` uses CRDT incrementation, safe across threads and nodes.
111
+
112
+ ```javascript
113
+ static async post(target, data) {
114
+ const record = await this.update(target.id);
115
+ record.addTo('quantity', -1); // decrement safely across nodes
116
+ }
117
+ ```
118
+
119
+ 10. **Wrap background work in `transaction()`**: HTTP handlers get a transaction automatically. Use `transaction()` explicitly for timers, background jobs, or any code outside a natural transaction context.
120
+
121
+ ```javascript
122
+ import { tables } from 'harper';
123
+ const { MyTable } = tables;
124
+
125
+ if (isMainThread) {
126
+ setInterval(async () => {
127
+ let data = await (await fetch('https://example.com/data')).json();
128
+ transaction(async (txn) => {
129
+ for (let item of data) {
130
+ await MyTable.put(item, txn);
131
+ }
132
+ });
133
+ }, 3600000); // every hour
134
+ }
135
+ ```
136
+
137
+ The `txn` object members:
138
+
139
+ | Member | Type | Description |
140
+ | --------------------- | --------------- | ------------------------------------------------------ |
141
+ | `commit()` | `() => Promise` | Commits the current transaction |
142
+ | `abort()` | `() => void` | Aborts the transaction and resets it |
143
+ | `resetReadSnapshot()` | `() => void` | Resets the read snapshot to the latest committed state |
144
+ | `timestamp` | `number` | Timestamp associated with the current transaction |
145
+
146
+ 11. **Understand atomicity boundaries**: All tables within the same database share one transactional context — writes across multiple tables commit atomically. Tables in different databases each get their own transaction with no cross-database atomicity guarantee.
147
+
148
+ 12. **Keep `harper` external in bundlers**: When using SSR bundlers, mark `harper` as external so it resolves to the live runtime. In `vite.config`:
149
+
150
+ ```javascript
151
+ ssr: {
152
+ external: ['harper'];
153
+ }
154
+ ```
114
155
 
115
156
  ## Examples
116
157
 
117
- **Nested conditions with `or`:**
158
+ ### Nested conditions query
118
159
 
119
160
  ```javascript
120
161
  Product.search({
@@ -131,25 +172,34 @@ Product.search({
131
172
  });
132
173
  ```
133
174
 
134
- **Chained attribute reference (relationship join):**
175
+ ### Chained attribute reference (join/relationship)
135
176
 
136
177
  ```javascript
137
178
  Product.search({ conditions: [{ attribute: ['brand', 'name'], value: 'Harper' }] });
138
179
  ```
139
180
 
140
- **Deep nested `select` across multiple relationships:**
181
+ ### Full CRUD sequence
141
182
 
142
183
  ```javascript
143
- Product.search({
144
- select: [
145
- 'id',
146
- 'name',
147
- { name: 'segments', select: ['id', 'name', { name: 'client', select: ['id', 'name'] }] },
148
- ],
149
- });
184
+ // Create a new record (id auto-generated)
185
+ const created = await Product.create({ name: 'Shirt', price: 9.5 });
186
+
187
+ // Modify the record
188
+ await Product.patch(created.id, { price: Math.round(created.price * 0.8 * 100) / 100 });
189
+
190
+ // Retrieve by primary key
191
+ const record = await Product.get(created.id);
192
+
193
+ // Query with conditions
194
+ const query = {
195
+ conditions: [{ attribute: 'price', comparator: 'less_than', value: 8.0 }],
196
+ };
197
+ for await (const record of Product.search(query)) {
198
+ // process record
199
+ }
150
200
  ```
151
201
 
152
- **SSR usage — read directly from `tables` in a render function:**
202
+ ### SSR rendering with `tables`
153
203
 
154
204
  ```typescript
155
205
  import { tables } from 'harper';
@@ -160,11 +210,20 @@ export async function render(url: string): Promise<string> {
160
210
  }
161
211
  ```
162
212
 
213
+ ### Mutable update with `addTo`
214
+
215
+ ```javascript
216
+ const product = await Product.update(32);
217
+ product.status = 'active';
218
+ product.subtractFrom('quantity', 1);
219
+ product.save();
220
+ ```
221
+
163
222
  ## Notes
164
223
 
165
- - Scope destructive operations (`update`, `patch`, `delete`) with specific `conditions` and validate the affected set before writing. These operate on live data and are not easily reversible.
166
- - Sorting by a bare `@primaryKey` with no conditions raises `HdbError: <attribute> is not indexed and not combined with any other conditions`. Add an open-ended condition or pass `allowFullScan: true`.
167
- - Selecting a relationship field without filtering on it behaves as a **LEFT JOIN**. Adding a condition on a related attribute (e.g. `attribute: ['author', 'name']`) behaves as an **INNER JOIN**.
168
- - A to-many relationship resolves to an array; `await` the property before iterating when needed.
169
- - `tables` and `databases.data` reference the same live objects — a record written through one component is immediately visible to all others.
170
- - Keep `harper` external when bundling for SSR (e.g. `ssr: { external: ['harper'] }` in `vite.config`) so it resolves to the runtime.
224
+ - `tables` calls run in a trusted server-side context and do **not** automatically apply the target table's role permissions. Enforce authorization in your own application logic.
225
+ - Destructive operations (`update`, `patch`, `delete`) act on live data and are not easily reversible. Always scope with specific `conditions`, validate the affected set before writing, and gate behind authorization controls.
226
+ - Sorting by the bare `@primaryKey` alone with no conditions triggers `HdbError: <attribute> is not indexed and not combined with any other conditions`. Add an open-ended range condition or pass `allowFullScan: true` to permit an unconditional scan.
227
+ - Selecting a relationship field without filtering on it behaves as a **LEFT JOIN**; adding a condition on a related attribute behaves as an **INNER JOIN**.
228
+ - `transaction()` is safe to call defensively — if a transaction is already active on the context, it reuses it and executes the callback immediately.
229
+ - Link the `harper` package for correct typings in standalone component directories: `npm link harper`.