@harperfast/template-react-ts-studio 1.11.2 → 1.11.4

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 (54) hide show
  1. package/.agents/skills/harper-best-practices/AGENTS.md +702 -490
  2. package/.agents/skills/harper-best-practices/SKILL.md +1 -0
  3. package/.agents/skills/harper-best-practices/rules/automatic-apis.md +46 -78
  4. package/.agents/skills/harper-best-practices/rules/defining-relationships.md +41 -63
  5. package/.agents/skills/harper-best-practices/rules/delegating-to-the-built-in-agent.md +141 -0
  6. package/.agents/skills/harper-best-practices/rules/deploying-to-harper-fabric.md +59 -45
  7. package/.agents/skills/harper-best-practices/rules/load-env.md +24 -23
  8. package/.agents/skills/harper-best-practices/rules/programmatic-table-requests.md +62 -78
  9. package/.agents/skills/harper-best-practices/rules/querying-rest-apis.md +92 -65
  10. package/.agents/skills/harper-best-practices/rules/schema-design-tooling.md +53 -55
  11. package/.agents/skills/harper-best-practices/rules/v5-upgrade.md +98 -62
  12. package/.agents/skills/harper-best-practices/rules/vector-indexing.md +113 -42
  13. package/.agents/skills/harper-best-practices/rules.manifest.yaml +9 -0
  14. package/.agents/skills/harper-mcp/AGENTS.md +501 -0
  15. package/.agents/skills/harper-mcp/SKILL.md +91 -0
  16. package/.agents/skills/harper-mcp/rules/automatic-verb-tools.md +50 -0
  17. package/.agents/skills/harper-mcp/rules/connecting-clients.md +59 -0
  18. package/.agents/skills/harper-mcp/rules/custom-mcp-prompts.md +52 -0
  19. package/.agents/skills/harper-mcp/rules/custom-mcp-resources.md +64 -0
  20. package/.agents/skills/harper-mcp/rules/custom-mcp-tools.md +72 -0
  21. package/.agents/skills/harper-mcp/rules/durable-quotas.md +73 -0
  22. package/.agents/skills/harper-mcp/rules/enabling-mcp.md +63 -0
  23. package/.agents/skills/harper-mcp/rules/rate-limiting.md +62 -0
  24. package/.agents/skills/harper-mcp/rules/resources-surface.md +44 -0
  25. package/.agents/skills/harper-mcp/rules/security-posture.md +36 -0
  26. package/.agents/skills/harper-mcp/rules.manifest.yaml +203 -0
  27. package/agent/skills/harper-best-practices/AGENTS.md +702 -490
  28. package/agent/skills/harper-best-practices/SKILL.md +1 -0
  29. package/agent/skills/harper-best-practices/rules/automatic-apis.md +46 -78
  30. package/agent/skills/harper-best-practices/rules/defining-relationships.md +41 -63
  31. package/agent/skills/harper-best-practices/rules/delegating-to-the-built-in-agent.md +141 -0
  32. package/agent/skills/harper-best-practices/rules/deploying-to-harper-fabric.md +59 -45
  33. package/agent/skills/harper-best-practices/rules/load-env.md +24 -23
  34. package/agent/skills/harper-best-practices/rules/programmatic-table-requests.md +62 -78
  35. package/agent/skills/harper-best-practices/rules/querying-rest-apis.md +92 -65
  36. package/agent/skills/harper-best-practices/rules/schema-design-tooling.md +53 -55
  37. package/agent/skills/harper-best-practices/rules/v5-upgrade.md +98 -62
  38. package/agent/skills/harper-best-practices/rules/vector-indexing.md +113 -42
  39. package/agent/skills/harper-best-practices/rules.manifest.yaml +9 -0
  40. package/agent/skills/harper-mcp/AGENTS.md +501 -0
  41. package/agent/skills/harper-mcp/SKILL.md +83 -0
  42. package/agent/skills/harper-mcp/rules/automatic-verb-tools.md +50 -0
  43. package/agent/skills/harper-mcp/rules/connecting-clients.md +59 -0
  44. package/agent/skills/harper-mcp/rules/custom-mcp-prompts.md +52 -0
  45. package/agent/skills/harper-mcp/rules/custom-mcp-resources.md +64 -0
  46. package/agent/skills/harper-mcp/rules/custom-mcp-tools.md +72 -0
  47. package/agent/skills/harper-mcp/rules/durable-quotas.md +73 -0
  48. package/agent/skills/harper-mcp/rules/enabling-mcp.md +63 -0
  49. package/agent/skills/harper-mcp/rules/rate-limiting.md +62 -0
  50. package/agent/skills/harper-mcp/rules/resources-surface.md +44 -0
  51. package/agent/skills/harper-mcp/rules/security-posture.md +36 -0
  52. package/agent/skills/harper-mcp/rules.manifest.yaml +203 -0
  53. package/package.json +1 -1
  54. package/skills-lock.json +7 -1
@@ -8,28 +8,32 @@ metadata:
8
8
  - >-
9
9
  fabric/cluster-creation-management.md#Connecting the Harper CLI to a
10
10
  Cluster
11
- sourceCommit: b7fbddadd42eb4487190b650a9abc4bcfeef5819
12
- inputHash: ccdefbbf8f3b8657
11
+ sourceCommit: 3749d0c54be457a2a65d9a63c738a5dc88989ecd
12
+ inputHash: 39faf283b6964e93
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 the Harper Fabric cloud using the Harper CLI.
17
+ Instructions for the agent to follow when deploying a Harper application to a remote Harper Fabric cloud instance.
18
18
 
19
19
  ## When to Use
20
20
 
21
- Apply this rule when deploying a Harper application to a remote Harper instance or Harper Fabric cluster. This covers interactive deployments, CI/CD pipelines, and any scenario where the agent must push a local or remote package to a target environment.
21
+ Apply this rule when deploying a Harper application to a remote Harper Fabric cluster or any remote Harper instance. Use it when setting up CI/CD pipelines that push application packages to a target environment, or when deploying from a local directory or external package source to a remote cluster.
22
22
 
23
23
  ## How It Works
24
24
 
25
- 1. **Authenticate with the remote target**: Run `harper login` once to store an authentication token. The CLI writes `HARPER_CLI_TARGET` to a local `.env` so subsequent commands do not need credentials repeated. Find the **Application URL** on the cluster's **Config → Overview** page (see [creating-a-fabric-account-and-cluster.md](creating-a-fabric-account-and-cluster.md)).
25
+ 1. **Obtain the target URL**: Get the cluster's **Application URL** from the cluster's **Config → Overview** page. This is the hostname passed to all CLI commands as `target`.
26
+
27
+ 2. **Authenticate with `harper login`**: Run `harper login` once to store an authentication token locally. The CLI also writes `HARPER_CLI_TARGET` to a local `.env` for subsequent commands.
26
28
 
27
29
  ```bash
28
30
  harper login <Application URL>
29
31
  # Provide cluster username and password when prompted
30
32
  ```
31
33
 
32
- 2. **Deploy the application**: Run `harper deploy` with the required parameters. After logging in, no credentials are needed inline.
34
+ See [creating-a-fabric-account-and-cluster.md](creating-a-fabric-account-and-cluster.md) for setting up a cluster before this step.
35
+
36
+ 3. **Deploy with `harper deploy`**: After logging in, deploy without repeating credentials.
33
37
 
34
38
  ```bash
35
39
  harper deploy \
@@ -40,83 +44,93 @@ Apply this rule when deploying a Harper application to a remote Harper instance
40
44
  replicated=true
41
45
  ```
42
46
 
43
- 3. **Choose a package source**: Set the `package` parameter to any valid npm dependency value, or omit it to package and deploy the current local directory.
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 repo (short form) |
50
- | `"https://github.com/HarperDB/status-check"` | GitHub repo (full URL) |
51
- | `"git+ssh://git@github.com:HarperDB/secret-app.git"` | Private repo via SSH |
52
- | `"https://example.com/application.tar.gz"` | Remote tarball |
53
-
54
- For git tags, use the `semver` directive for reliable versioning:
47
+ 4. **Use environment variables for CI/CD**: Instead of `harper login`, export credentials as environment variables before running `harper deploy`.
55
48
 
56
- ```
57
- HarperDB/application-template#semver:v1.0.0
49
+ ```bash
50
+ export HARPER_CLI_USERNAME=<username>
51
+ export HARPER_CLI_PASSWORD=<password>
52
+ harper deploy \
53
+ project=<name> \
54
+ package=<package> \
55
+ target=<remote> \
56
+ restart=true \
57
+ replicated=true
58
58
  ```
59
59
 
60
- 4. **Authenticate for CI/CD pipelines**: Use environment variables instead of interactive login. Set credentials before running `harper deploy`.
60
+ 5. **Use inline auth parameters for one-off commands**: Pass `auth_username` and `auth_password` directly. These take precedence over environment variables and saved login tokens. Not recommended for production.
61
61
 
62
62
  ```bash
63
- export HARPER_CLI_USERNAME=<username>
64
- export HARPER_CLI_PASSWORD=<password>
65
63
  harper deploy \
66
64
  project=<name> \
67
65
  package=<package> \
66
+ auth_username=<username> \
67
+ auth_password=<password> \
68
68
  target=<remote> \
69
69
  restart=true \
70
70
  replicated=true
71
71
  ```
72
72
 
73
- 5. **Register SSH keys for private repos**: Before deploying from an SSH-based private repository, use the Add SSH Key operation to register the key with the remote instance.
73
+ 6. **Choose a package source**: Set the `package` parameter to any valid npm dependency value, or omit it to package and deploy the current local directory.
74
+
75
+ | Value | Meaning |
76
+ | ---------------------------------------------------- | ---------------------------------------------- |
77
+ | _(omitted)_ | Package and deploy the current local directory |
78
+ | `"@harperdb/status-check"` | npm package |
79
+ | `"HarperDB/status-check"` | GitHub shorthand |
80
+ | `"https://github.com/HarperDB/status-check"` | GitHub full URL |
81
+ | `"git+ssh://git@github.com:HarperDB/secret-app.git"` | Private repo via SSH |
82
+ | `"https://example.com/application.tar.gz"` | Remote tarball |
83
+
84
+ For pinned git tags, use the `semver` directive:
85
+
86
+ ```
87
+ HarperDB/application-template#semver:v1.0.0
88
+ ```
89
+
90
+ For SSH-based private repos, register keys with the `Add SSH Key` operation before deploying.
74
91
 
75
92
  ## Examples
76
93
 
77
- **Interactive login then deploy (recommended):**
94
+ **Interactive login then deploy:**
78
95
 
79
96
  ```bash
80
- # Log in once
81
- harper login <remote>
82
- # Provide your username and password when prompted
97
+ harper login https://my-cluster.harperdbcloud.com
98
+ # Enter username and password when prompted
83
99
 
84
- # Subsequently deploy without credentials
85
100
  harper deploy \
86
- project=<name> \
87
- package=<package> \
88
- target=<remote> \
101
+ project=my-app \
102
+ package="HarperDB/application-template#semver:v1.0.0" \
103
+ target=https://my-cluster.harperdbcloud.com \
89
104
  restart=true \
90
105
  replicated=true
91
106
  ```
92
107
 
93
- **Deploy with inline credentials (not recommended for production):**
108
+ **CI/CD pipeline deploy using environment variables:**
94
109
 
95
110
  ```bash
111
+ export HARPER_CLI_USERNAME=admin
112
+ export HARPER_CLI_PASSWORD=secret
96
113
  harper deploy \
97
- project=<name> \
98
- package=<package> \
99
- username=<username> \
100
- password=<password> \
101
- target=<remote> \
114
+ project=my-app \
115
+ package="@harperdb/status-check" \
116
+ target=https://my-cluster.harperdbcloud.com \
102
117
  restart=true \
103
118
  replicated=true
104
119
  ```
105
120
 
106
- **Deploy a specific GitHub release by semver tag:**
121
+ **Deploy current local directory:**
107
122
 
108
123
  ```bash
109
124
  harper deploy \
110
125
  project=my-app \
111
- package="HarperDB/application-template#semver:v1.0.0" \
112
- target=<remote> \
126
+ target=https://my-cluster.harperdbcloud.com \
113
127
  restart=true \
114
128
  replicated=true
115
129
  ```
116
130
 
117
131
  ## Notes
118
132
 
119
- - Always prefer `harper login` for interactive use and environment variables (`HARPER_CLI_USERNAME`, `HARPER_CLI_PASSWORD`) for CI/CD. Avoid inline `username`/`password` parameters in production.
120
- - Omitting `package` causes the CLI to package the current local directory. Specifying a local file path creates a symlink, so changes are picked up between restarts without redeploying.
121
- - Harper generates a `package.json` from component configurations and resolves dependencies using a form of `npm install`.
122
- - For SSH-based private repos, register keys with the Add SSH Key operation before deploying.
133
+ - Authentication precedence (highest to lowest): inline `auth_username`/`auth_password` parameters → environment variables (`HARPER_CLI_USERNAME`/`HARPER_CLI_PASSWORD`) → saved login token from `harper login`.
134
+ - `harper login` writes `HARPER_CLI_TARGET` to a local `.env`, so subsequent commands do not need `target` repeated if that file is present.
135
+ - Harper generates a `package.json` from component configurations and resolves packages via `npm install`. A local file path creates a symlink, so changes are picked up between restarts without redeploying.
136
+ - For SSH-based private repos, register the SSH key with the `Add SSH Key` operation before running `harper deploy`.
@@ -7,8 +7,8 @@ metadata:
7
7
  mode: generate
8
8
  sources:
9
9
  - reference/v5/environment-variables/overview.md
10
- sourceCommit: 42231db17c025a4a455e3d91875fad4084a01cb5
11
- inputHash: fe610fc245226357
10
+ sourceCommit: 3749d0c54be457a2a65d9a63c738a5dc88989ecd
11
+ inputHash: b4db5ede6b93d426
12
12
  ---
13
13
 
14
14
  # Load Environment Variables with loadEnv
@@ -17,18 +17,18 @@ Instructions for the agent to follow when loading environment variables from `.e
17
17
 
18
18
  ## When to Use
19
19
 
20
- Apply this rule when a Harper application needs to load secrets or configuration values from `.env` files into `process.env` at startup. Use it whenever hardcoding values must be avoided and environment-specific configuration must be supplied to Harper components.
20
+ Apply this rule when a Harper application needs to supply secrets, API endpoints, or other configuration values to component code via `process.env` without hardcoding them. Use `loadEnv` any time you need to load one or more `.env` files at application startup.
21
21
 
22
22
  ## How It Works
23
23
 
24
- 1. **Declare `loadEnv` in `config.yaml`**: Add `loadEnv` as a top-level key. It is built into Harper and requires no installation.
24
+ 1. **Declare `loadEnv` in `config.yaml`**: Add `loadEnv` as the first entry in `config.yaml`. It is built into Harper and requires no installation.
25
25
 
26
26
  ```yaml
27
27
  loadEnv:
28
28
  files: '.env'
29
29
  ```
30
30
 
31
- 2. **Place `loadEnv` first**: Always list `loadEnv` before any other components in `config.yaml` so that environment variables are available on `process.env` before dependent components start.
31
+ 2. **Place `loadEnv` first**: Harper is a single-process application. List `loadEnv` before all other components so that environment variables are available on `process.env` before dependent components start.
32
32
 
33
33
  ```yaml
34
34
  # config.yaml — loadEnv must come first
@@ -41,9 +41,9 @@ Apply this rule when a Harper application needs to load secrets or configuration
41
41
  files: './src/*.js'
42
42
  ```
43
43
 
44
- 3. **Configure the `files` option**: Provide one or more paths or glob patterns pointing to the env files to load. This option is required.
44
+ 3. **Access loaded values in component code**: After `loadEnv` runs, all loaded values are available on `process.env` and shared across all components.
45
45
 
46
- 4. **Set `override` if needed**: By default, existing environment variables take precedence over values in `.env` files. Set `override: true` to reverse this and have loaded values win.
46
+ 4. **Control override behavior**: By default, existing environment variables take precedence over values in `.env` files. Set `override: true` to make loaded values win instead.
47
47
 
48
48
  ```yaml
49
49
  loadEnv:
@@ -51,14 +51,17 @@ Apply this rule when a Harper application needs to load secrets or configuration
51
51
  override: true
52
52
  ```
53
53
 
54
- 5. **Load multiple files when required**: Supply a list of files or a glob pattern. Files are loaded in the order specified.
54
+ 5. **Load multiple files**: Pass an array of paths or a glob pattern to `files`. Files are loaded in the order specified.
55
+
55
56
  ```yaml
56
57
  loadEnv:
57
58
  files:
58
59
  - '.env'
59
60
  - '.env.local'
60
61
  ```
61
- or
62
+
63
+ or with a glob:
64
+
62
65
  ```yaml
63
66
  loadEnv:
64
67
  files: 'env-vars/*'
@@ -73,17 +76,23 @@ Apply this rule when a Harper application needs to load secrets or configuration
73
76
 
74
77
  ## Examples
75
78
 
76
- **Minimal setup — single `.env` file:**
79
+ **Single file, default behavior:**
77
80
 
78
81
  ```yaml
82
+ # config.yaml
79
83
  loadEnv:
80
84
  files: '.env'
85
+
86
+ rest: true
87
+
88
+ myApp:
89
+ files: './src/*.js'
81
90
  ```
82
91
 
83
- **Full `config.yaml` with load order, multiple files, and override:**
92
+ **Multiple files with override:**
84
93
 
85
94
  ```yaml
86
- # config.yaml — loadEnv must come first
95
+ # config.yaml
87
96
  loadEnv:
88
97
  files:
89
98
  - '.env'
@@ -96,16 +105,8 @@ myApp:
96
105
  files: './src/*.js'
97
106
  ```
98
107
 
99
- **Glob pattern:**
100
-
101
- ```yaml
102
- loadEnv:
103
- files: 'env-vars/*'
104
- ```
105
-
106
108
  ## Notes
107
109
 
108
- - `loadEnv` is built into Harper — do not install it separately; only declare it in `config.yaml`.
109
- - Because Harper is a single-process application, variables loaded onto `process.env` are shared across all components.
110
- - Without `override: true`, variables already set in the shell or container environment will not be overwritten by values in `.env` files.
111
- - `files` is the only required option; omitting it will produce an invalid configuration.
110
+ - `loadEnv` loads values into `process.env` for **application** code only — it does not configure Harper itself.
111
+ - Harper's own instance-wide configuration is composed at startup **before** any component's `loadEnv` runs. Variables such as `HARPER_CONFIG`, `HARPER_SET_CONFIG`, and `HARPER_DEFAULT_CONFIG` delivered through a `.env` file are read too late and are ignored. Set Harper configuration directly in the configuration file or export variables in the real process/container environment before Harper starts.
112
+ - For production credentials, prefer the encrypted secrets store over a committed `.env` file. Secrets are also delivered to components via `process.env`.
@@ -14,8 +14,8 @@ 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: be709f9978319dcdb669c05d794effc82bcda8b7
18
- inputHash: 3d2417fbff687c42
17
+ sourceCommit: 3749d0c54be457a2a65d9a63c738a5dc88989ecd
18
+ inputHash: ace5c3f4a0ad4519
19
19
  ---
20
20
 
21
21
  # Programmatic Table Requests
@@ -24,11 +24,11 @@ Instructions for the agent to interact with Harper tables programmatically using
24
24
 
25
25
  ## When to Use
26
26
 
27
- Apply this rule when writing server-side Harper code that reads from or writes to tables directly — for example, in request handlers, background jobs, or SSR entry points — instead of going through the REST API. Use it whenever you need to construct queries with `conditions`, paginate results, select specific fields, or perform CRDT-safe mutations with `addTo`.
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(`.
28
28
 
29
29
  ## How It Works
30
30
 
31
- 1. **Import `tables`**: Import from the `harper` package. Each table defined in `schema.graphql` with `@table` is available as a named property.
31
+ 1. **Import `tables`**: Pull `tables` from the `harper` package. Each property on `tables` corresponds to a table defined in `schema.graphql`.
32
32
 
33
33
  ```javascript
34
34
  import { tables } from 'harper';
@@ -36,10 +36,9 @@ Apply this rule when writing server-side Harper code that reads from or writes t
36
36
  // same as: databases.data.Product
37
37
  ```
38
38
 
39
- 2. **Define your schema**: Declare tables in `schema.graphql` using `@table` and `@primaryKey`.
39
+ 2. **Define your schema**: Declare tables with `@table` in `schema.graphql`. Each type becomes a property on `tables`.
40
40
 
41
41
  ```graphql
42
- # schema.graphql
43
42
  type Product @table {
44
43
  id: Long @primaryKey
45
44
  name: String
@@ -47,57 +46,75 @@ Apply this rule when writing server-side Harper code that reads from or writes t
47
46
  }
48
47
  ```
49
48
 
50
- 3. **Create and mutate records**: Use `create`, `patch`, `get`, and `update` on the table class.
49
+ 3. **Create and modify records**: Use `create`, `patch`, and `get` for basic CRUD.
51
50
 
52
51
  ```javascript
53
- // Create a new record (id auto-generated)
54
52
  const created = await Product.create({ name: 'Shirt', price: 9.5 });
55
-
56
- // Modify the record
57
53
  await Product.patch(created.id, { price: Math.round(created.price * 0.8 * 100) / 100 });
58
-
59
- // Retrieve by primary key
60
54
  const record = await Product.get(created.id);
61
55
  ```
62
56
 
63
- 4. **Query with `search(` and `conditions`**: Pass a query object to `search()` to filter records. Iterate the async result.
57
+ 4. **Query with `search(`**: Pass a query object to `Product.search(query)`. It returns an async iterable.
64
58
 
65
59
  ```javascript
66
60
  const query = {
67
61
  conditions: [{ attribute: 'price', comparator: 'less_than', value: 8.0 }],
68
62
  };
69
63
  for await (const record of Product.search(query)) {
70
- // ...
64
+ // process record
71
65
  }
72
66
  ```
73
67
 
74
- 5. **Use `select` to shape results**: Pass a `select` array to return only specific properties, including nested relationship fields.
68
+ 5. **Build `conditions`**: Each condition object filters records. Nest conditions with `operator` for boolean logic.
69
+
70
+ | Property | Description |
71
+ | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
72
+ | `attribute` | Property name, or array for chained/joined properties (e.g. `['brand', 'name']`) |
73
+ | `value` | The value to match |
74
+ | `comparator` | `equals` (default), `greater_than`, `greater_than_equal`, `less_than`, `less_than_equal`, `starts_with`, `contains`, `ends_with`, `between`, `not_equal` |
75
+ | `conditions` | Nested conditions array |
76
+ | `operator` | `and` (default) or `or` for the nested `conditions` |
77
+
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.
75
79
 
76
80
  ```javascript
77
- const book = await Book.get({ id: 42, select: ['id', 'title', 'author'] });
78
- book.author.name; // full related Author record
81
+ // Array of names
82
+ Product.search({ select: ['name', 'price'] });
79
83
 
80
- // Partial related record
81
- const book = await Book.get({
82
- id: 42,
83
- select: ['id', 'title', { name: 'author', select: ['name'] }],
84
- });
84
+ // Nested relationship select
85
+ Book.get({ id: 42, select: ['id', 'title', { name: 'author', select: ['name'] }] });
85
86
  ```
86
87
 
87
- 6. **Use `addTo` for concurrent-safe increments**: Call `addTo` on a mutable resource instance obtained via `update()`. This uses CRDT incrementation, safe across threads and nodes.
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).
88
94
 
89
95
  ```javascript
90
- static async post(target, data) {
91
- const record = await this.update(target.id);
92
- record.addTo('quantity', -1); // decrement safely across nodes
93
- }
96
+ const record = await Product.update(target.id);
97
+ record.addTo('quantity', -1);
94
98
  ```
95
99
 
96
- 7. **Scope destructive operations carefully**: `update`, `patch`, and `delete` operate directly on stored data. Always use specific `conditions`, validate the affected set before writing, and gate behind authorization controls.
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.
101
+
102
+ ```javascript
103
+ Product.search({
104
+ conditions: [{ attribute: 'id', comparator: 'greater_than', value: '' }],
105
+ sort: { attribute: 'id' },
106
+ });
107
+ ```
108
+
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) |
97
114
 
98
115
  ## Examples
99
116
 
100
- ### Nested conditions query
117
+ **Nested conditions with `or`:**
101
118
 
102
119
  ```javascript
103
120
  Product.search({
@@ -114,23 +131,25 @@ Product.search({
114
131
  });
115
132
  ```
116
133
 
117
- ### Chained attribute reference (relationship join)
134
+ **Chained attribute reference (relationship join):**
118
135
 
119
136
  ```javascript
120
137
  Product.search({ conditions: [{ attribute: ['brand', 'name'], value: 'Harper' }] });
121
138
  ```
122
139
 
123
- ### Deep nested `select`
140
+ **Deep nested `select` across multiple relationships:**
124
141
 
125
142
  ```javascript
126
- select: [
127
- 'id',
128
- 'name',
129
- { name: 'segments', select: ['id', 'name', { name: 'client', select: ['id', 'name'] }] },
130
- ];
143
+ Product.search({
144
+ select: [
145
+ 'id',
146
+ 'name',
147
+ { name: 'segments', select: ['id', 'name', { name: 'client', select: ['id', 'name'] }] },
148
+ ],
149
+ });
131
150
  ```
132
151
 
133
- ### SSR usage
152
+ **SSR usage — read directly from `tables` in a render function:**
134
153
 
135
154
  ```typescript
136
155
  import { tables } from 'harper';
@@ -143,44 +162,9 @@ export async function render(url: string): Promise<string> {
143
162
 
144
163
  ## Notes
145
164
 
146
- ### `conditions` comparator values
147
-
148
- | Comparator | Description |
149
- | -------------------- | ---------------------- |
150
- | `equals` | Default equality match |
151
- | `greater_than` | Strictly greater |
152
- | `greater_than_equal` | Greater than or equal |
153
- | `less_than` | Strictly less |
154
- | `less_than_equal` | Less than or equal |
155
- | `starts_with` | String prefix match |
156
- | `contains` | String contains |
157
- | `ends_with` | String suffix match |
158
- | `between` | Range match |
159
- | `not_equal` | Inequality match |
160
-
161
- ### Query object options
162
-
163
- | Property | Description |
164
- | ----------------------- | ----------------------------------------------------------------------- |
165
- | `conditions` | Array of condition objects to filter records |
166
- | `operator` | Top-level `and` (default) or `or` for the `conditions` array |
167
- | `limit` | Maximum number of records to return |
168
- | `offset` | Number of records to skip (for pagination) |
169
- | `select` | Properties to include in each returned record |
170
- | `sort` | Sort order object with `attribute`, `descending`, and `next` properties |
171
- | `explain` | If `true`, returns conditions reordered as Harper will execute them |
172
- | `enforceExecutionOrder` | If `true`, forces conditions to execute in the order supplied |
173
-
174
- ### `select` special properties
175
-
176
- - `$id` — Returns the primary key regardless of its name
177
- - `$updatedtime` — Returns the last-updated timestamp
178
- - `$distance` — Returns the computed distance from the target vector when the query uses a vector index
179
-
180
- ### Relationship join behavior
181
-
182
- - Selecting a relationship **without** filtering on it behaves as a **LEFT JOIN** — records with no related row are still returned.
183
- - Adding a `conditions` entry on a related attribute (e.g. `attribute: ['author', 'name']`) behaves as an **INNER JOIN** — only records with a matching related row are returned.
184
-
185
- - Keep `harper` external when bundling for SSR (e.g. `ssr: { external: ['harper'] }` in `vite.config`) so it resolves to the runtime instead of being bundled.
186
- - `tables`, `databases`, and other Harper APIs are the same live, process-wide objects regardless of whether accessed as globals or via `import { tables } from 'harper'`.
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.