@harperfast/template-react-ts-studio 1.12.2 → 1.12.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.
- package/.agents/skills/harper-best-practices/AGENTS.md +778 -580
- package/.agents/skills/harper-best-practices/rules/adding-tables-with-schemas.md +7 -7
- package/.agents/skills/harper-best-practices/rules/automatic-apis.md +131 -55
- package/.agents/skills/harper-best-practices/rules/checking-authentication.md +265 -127
- package/.agents/skills/harper-best-practices/rules/custom-resources.md +28 -45
- package/.agents/skills/harper-best-practices/rules/deploying-to-harper-fabric.md +63 -85
- package/.agents/skills/harper-best-practices/rules/programmatic-table-requests.md +125 -52
- package/.agents/skills/harper-best-practices/rules/querying-rest-apis.md +38 -70
- package/.agents/skills/harper-best-practices/rules/schema-design-tooling.md +81 -69
- package/.agents/skills/harper-best-practices/rules/v5-upgrade.md +82 -96
- package/.agents/skills/harper-best-practices/rules.manifest.yaml +273 -2
- package/.agents/skills/harper-mcp/AGENTS.md +77 -31
- package/.agents/skills/harper-mcp/rules/custom-mcp-tools.md +79 -33
- package/.agents/skills/harper-mcp/rules.manifest.yaml +1 -1
- package/agent/skills/harper-best-practices/AGENTS.md +778 -580
- package/agent/skills/harper-best-practices/rules/adding-tables-with-schemas.md +7 -7
- package/agent/skills/harper-best-practices/rules/automatic-apis.md +131 -55
- package/agent/skills/harper-best-practices/rules/checking-authentication.md +265 -127
- package/agent/skills/harper-best-practices/rules/custom-resources.md +28 -45
- package/agent/skills/harper-best-practices/rules/deploying-to-harper-fabric.md +63 -85
- package/agent/skills/harper-best-practices/rules/programmatic-table-requests.md +125 -52
- package/agent/skills/harper-best-practices/rules/querying-rest-apis.md +38 -70
- package/agent/skills/harper-best-practices/rules/schema-design-tooling.md +81 -69
- package/agent/skills/harper-best-practices/rules/v5-upgrade.md +82 -96
- package/agent/skills/harper-best-practices/rules.manifest.yaml +273 -2
- package/agent/skills/harper-mcp/AGENTS.md +77 -31
- package/agent/skills/harper-mcp/rules/custom-mcp-tools.md +79 -33
- package/agent/skills/harper-mcp/rules.manifest.yaml +1 -1
- package/package.json +1 -1
- package/skills-lock.json +2 -2
|
@@ -19,14 +19,14 @@ Use this skill when you need to define new data structures or modify existing on
|
|
|
19
19
|
2. **Use Directives**: All available directives for defining your schema are defined in `node_modules/harper/schema.graphql`. Common directives include `@table`, `@export`, `@primaryKey`, `@indexed`, and `@relationship`.
|
|
20
20
|
3. **Define Relationships**: Link tables together using the `@relationship` directive. For more details, see the [Defining Relationships](defining-relationships.md) skill.
|
|
21
21
|
4. **Enable Automatic APIs**: If you add `@table @export` to a schema type, Harper automatically sets up REST and WebSocket APIs for basic CRUD operations against that table. **Important**: REST endpoints also require `rest: true` in `config.yaml` — without it, `@export`ed tables will not respond to HTTP requests. For a detailed list of available endpoints and how to use them, see the [Automatic REST APIs](automatic-apis.md) skill.
|
|
22
|
-
- `GET /{TableName}`: Describes the
|
|
22
|
+
- `GET /{TableName}`: Describes the resource itself — table, database, and declared attributes. No trailing slash.
|
|
23
23
|
- `GET /{TableName}/`: Lists all records (supports filtering, sorting, and pagination via query parameters). See the [Querying REST APIs](querying-rest-apis.md) skill for details.
|
|
24
|
-
- `GET /{TableName}/{id}`: Retrieves a single record by its
|
|
25
|
-
- `POST /{TableName}/`: Creates a
|
|
26
|
-
- `PUT /{TableName}/{id}`:
|
|
27
|
-
- `PATCH /{TableName}/{id}`:
|
|
28
|
-
- `DELETE /{TableName}
|
|
29
|
-
- `DELETE /{TableName}
|
|
24
|
+
- `GET /{TableName}/{id}`: Retrieves a single record by its primary key.
|
|
25
|
+
- `POST /{TableName}/`: Creates a record and returns `201` with the Harper-assigned primary key in the `Location` response header (the bare key, not a URL). **The trailing slash is required** — `POST /{TableName}` returns `404`, and `POST /{TableName}/{id}` returns `405`.
|
|
26
|
+
- `PUT /{TableName}/{id}`: Creates **or replaces** the record at `{id}` (upsert). **Properties omitted from the body are removed** — send the complete record, or use `PATCH` to change a subset. Three exceptions survive the replacement: an `@updatedTime` attribute is re-stamped with the time of the write, a `@createdTime` attribute keeps its original value, and the primary key is forced to match the `{id}` in the URL, so a mismatched key in the body cannot create a second record.
|
|
27
|
+
- `PATCH /{TableName}/{id}`: Merges the request body into the existing record, preserving unspecified properties. The merge is **shallow** — a nested object in the body replaces the stored one wholesale rather than being deep-merged.
|
|
28
|
+
- `DELETE /{TableName}/{id}`: Deletes a single record by its primary key.
|
|
29
|
+
- `DELETE /{TableName}/`: Deletes every record matching the query parameters. **With no query parameters it matches — and deletes — every record in the table.** Always pass a filter unless emptying the table is the intent.
|
|
30
30
|
5. **Consider Table Extensions**: If you are going to [extend the table](./extending-tables.md) in your resources, then do not `@export` the table from the schema.
|
|
31
31
|
|
|
32
32
|
## Examples
|
|
@@ -4,23 +4,29 @@ description: How to use Harper's automatically generated REST and WebSocket APIs
|
|
|
4
4
|
metadata:
|
|
5
5
|
mode: generate
|
|
6
6
|
sources:
|
|
7
|
-
- reference/v5/rest/overview.md
|
|
7
|
+
- reference/v5/rest/overview.md#How the REST Interface Works
|
|
8
|
+
- reference/v5/rest/overview.md#Configuration
|
|
9
|
+
- reference/v5/rest/overview.md#Tables and Their Automatic Endpoints
|
|
10
|
+
- reference/v5/rest/overview.md#URL Structure
|
|
11
|
+
- reference/v5/rest/overview.md#HTTP Methods
|
|
12
|
+
- reference/v5/rest/overview.md#Content Types
|
|
13
|
+
- reference/v5/rest/overview.md#OpenAPI
|
|
8
14
|
- reference/v5/rest/websockets.md
|
|
9
|
-
sourceCommit:
|
|
10
|
-
inputHash:
|
|
15
|
+
sourceCommit: 677ad213d67822e109c83619e181ca23a59823db
|
|
16
|
+
inputHash: a9356e92dd3dc106
|
|
11
17
|
---
|
|
12
18
|
|
|
13
19
|
# Automatic APIs
|
|
14
20
|
|
|
15
|
-
Instructions for the agent to follow when
|
|
21
|
+
Instructions for the agent to follow when using Harper's automatically generated REST and WebSocket APIs for exported tables and resources.
|
|
16
22
|
|
|
17
23
|
## When to Use
|
|
18
24
|
|
|
19
|
-
Apply this rule when
|
|
25
|
+
Apply this rule when enabling HTTP REST endpoints or WebSocket subscriptions for Harper tables without writing custom handler code. Use it whenever a schema type needs to be served over HTTP, when configuring real-time subscriptions, or when setting up conditional caching behavior for REST responses.
|
|
20
26
|
|
|
21
27
|
## How It Works
|
|
22
28
|
|
|
23
|
-
1. **Enable
|
|
29
|
+
1. **Enable REST in `config.yaml`**: Add `rest: true` to the application configuration file. This registers REST endpoints and, by default, WebSocket subscriptions for all exported resources.
|
|
24
30
|
|
|
25
31
|
```yaml
|
|
26
32
|
rest: true
|
|
@@ -34,26 +40,47 @@ Apply this rule when adding REST or WebSocket API access to Harper tables or cus
|
|
|
34
40
|
webSocket: false # disables automatic WebSocket support (enabled by default)
|
|
35
41
|
```
|
|
36
42
|
|
|
37
|
-
2. **Export
|
|
43
|
+
2. **Export the table in the schema**: Add `@export` to the type definition. Without `@export`, Harper registers no REST route and callers receive `404`. Without `rest: true`, even an exported table does not respond to HTTP requests. Both are required.
|
|
38
44
|
|
|
39
|
-
|
|
45
|
+
```graphql
|
|
46
|
+
type Product @table @export {
|
|
47
|
+
id: Long @primaryKey
|
|
48
|
+
name: String
|
|
49
|
+
price: Float
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Reference the schema file in `config.yaml`:
|
|
54
|
+
|
|
55
|
+
```yaml
|
|
56
|
+
graphqlSchema:
|
|
57
|
+
files: schema.graphql
|
|
58
|
+
rest: true
|
|
59
|
+
```
|
|
40
60
|
|
|
41
|
-
|
|
42
|
-
| -------------------------------------------- | ----------------------------------------------------------- |
|
|
43
|
-
| `/my-resource` | Returns resource metadata |
|
|
44
|
-
| `/my-resource/` | Collection — all records; append query parameters to search |
|
|
45
|
-
| `/my-resource/record-id` | Specific record by primary key |
|
|
46
|
-
| `/my-resource/record-id/` | Collection of records with the given id prefix |
|
|
47
|
-
| `/my-resource/record-id/with/multiple/parts` | Record id with multiple path segments |
|
|
61
|
+
3. **Use the automatically registered endpoints**: Harper serves the following endpoints on the application HTTP server port (default `9926`) with no route definitions or handler code required.
|
|
48
62
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
63
|
+
| Endpoint | Description |
|
|
64
|
+
| ---------------------------- | --------------------------------------------------------------------------- |
|
|
65
|
+
| `GET /Product` | Returns resource description (table name, database, attributes) |
|
|
66
|
+
| `GET /Product/` | Returns the record collection; append query parameters to filter |
|
|
67
|
+
| `GET /Product/{id}` | Returns a single record by primary key; `404` if not found |
|
|
68
|
+
| `GET /Product/{id}.property` | Returns a single declared property of one record |
|
|
69
|
+
| `POST /Product/` | Creates a record; responds `201`; primary key returned in `Location` header |
|
|
70
|
+
| `PUT /Product/{id}` | Creates or replaces the record at `{id}` (upsert) |
|
|
71
|
+
| `PATCH /Product/{id}` | Merges body into existing record (shallow, top-level only) |
|
|
72
|
+
| `DELETE /Product/{id}` | Deletes the record at `{id}` |
|
|
73
|
+
| `DELETE /Product/?query` | Deletes every record matching the query |
|
|
55
74
|
|
|
56
|
-
|
|
75
|
+
4. **Handle `POST` primary key and `Location`**: On a successful `POST`, the new record's primary key is returned in the `Location` response header — the value the body supplied if it carried the primary-key property, otherwise a Harper-assigned key. The header carries the bare key value, not a URL.
|
|
76
|
+
|
|
77
|
+
5. **Understand `PUT` write behavior**: `PUT` replaces the stored record exactly. Three exceptions always apply: a `@createdTime` attribute keeps the original value, an `@updatedTime` attribute is re-stamped with the time of the write, and the primary key is forced to match the `{id}` in the URL.
|
|
78
|
+
|
|
79
|
+
6. **Use conditional requests for caching**: GET responses include an `ETag` header encoding the record's version/last-modification time. Send `If-None-Match` on subsequent requests with the cached `ETag` value. If the record has not changed, Harper returns `304 Not Modified` with no body.
|
|
80
|
+
|
|
81
|
+
7. **Select content type with `Accept`**: Use the `Accept` header to request a specific response format. The suffixes `.json`, `.cbor`, `.msgpack`, and `.csv` are reserved as content-type selectors on property paths and take precedence over property names. See [querying-rest-apis.md](querying-rest-apis.md) for query syntax details.
|
|
82
|
+
|
|
83
|
+
8. **Connect via WebSocket**: WebSocket support is enabled automatically when `rest` is enabled. Connecting to a resource URL subscribes to changes for that resource. See [real-time-apps.md](real-time-apps.md) for real-time patterns.
|
|
57
84
|
|
|
58
85
|
```javascript
|
|
59
86
|
let ws = new WebSocket('wss://server/my-resource/341');
|
|
@@ -62,29 +89,84 @@ Apply this rule when adding REST or WebSocket API access to Harper tables or cus
|
|
|
62
89
|
};
|
|
63
90
|
```
|
|
64
91
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
7. **Retrieve the OpenAPI spec**: Harper auto-generates an OpenAPI specification for all exported resources, available at:
|
|
92
|
+
9. **Implement a custom `connect()` handler** when default subscription behavior is insufficient. The method must return an async iterable that produces messages to send to the client.
|
|
68
93
|
|
|
69
|
-
```
|
|
70
|
-
|
|
94
|
+
```javascript
|
|
95
|
+
export class Echo extends Resource {
|
|
96
|
+
async *connect(incomingMessages) {
|
|
97
|
+
for await (let message of incomingMessages) {
|
|
98
|
+
yield message; // echo each message back
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
71
102
|
```
|
|
72
103
|
|
|
73
104
|
## Examples
|
|
74
105
|
|
|
75
|
-
|
|
106
|
+
### Full schema and config setup
|
|
76
107
|
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
108
|
+
```graphql
|
|
109
|
+
# schema.graphql
|
|
110
|
+
type Product @table @export {
|
|
111
|
+
id: Long @primaryKey
|
|
112
|
+
name: String
|
|
113
|
+
price: Float
|
|
84
114
|
}
|
|
85
115
|
```
|
|
86
116
|
|
|
87
|
-
|
|
117
|
+
```yaml
|
|
118
|
+
# config.yaml
|
|
119
|
+
graphqlSchema:
|
|
120
|
+
files: schema.graphql
|
|
121
|
+
rest: true
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Conditional GET with ETag caching
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
GET /Product/123
|
|
128
|
+
# Response includes:
|
|
129
|
+
# ETag: "abc123"
|
|
130
|
+
|
|
131
|
+
GET /Product/123
|
|
132
|
+
If-None-Match: "abc123"
|
|
133
|
+
# Response: 304 Not Modified (no body transferred)
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### POST and read the Location header
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
POST /Product/
|
|
140
|
+
Content-Type: application/json
|
|
141
|
+
|
|
142
|
+
{ "name": "Widget", "price": 9.99 }
|
|
143
|
+
|
|
144
|
+
# Response:
|
|
145
|
+
# 201 Created
|
|
146
|
+
# Location: 7f3a9c
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### PATCH (shallow merge only)
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
PATCH /Product/123
|
|
153
|
+
Content-Type: application/json
|
|
154
|
+
|
|
155
|
+
{ "price": 12.99 }
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Only `price` is updated; other top-level properties are preserved. Nested objects in the body replace the stored sub-object wholesale — deep merge does not occur.
|
|
159
|
+
|
|
160
|
+
### Request MessagePack response
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
GET /Product/123
|
|
164
|
+
Accept: application/msgpack
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Alternatively, use the `.msgpack` suffix on the URL path where supported.
|
|
168
|
+
|
|
169
|
+
### WebSocket with custom outgoing messages
|
|
88
170
|
|
|
89
171
|
```javascript
|
|
90
172
|
export class Example extends Resource {
|
|
@@ -96,7 +178,7 @@ export class Example extends Resource {
|
|
|
96
178
|
}, 1000);
|
|
97
179
|
|
|
98
180
|
incomingMessages.on('data', (message) => {
|
|
99
|
-
outgoingMessages.send(message);
|
|
181
|
+
outgoingMessages.send(message);
|
|
100
182
|
});
|
|
101
183
|
|
|
102
184
|
outgoingMessages.on('close', () => {
|
|
@@ -108,26 +190,20 @@ export class Example extends Resource {
|
|
|
108
190
|
}
|
|
109
191
|
```
|
|
110
192
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
```
|
|
114
|
-
GET /MyTable/123
|
|
115
|
-
GET /MyTable/?name=Harper
|
|
116
|
-
PUT /MyTable/123
|
|
117
|
-
PATCH /MyTable/123
|
|
118
|
-
DELETE /MyTable/?status=archived
|
|
119
|
-
```
|
|
193
|
+
### Disable WebSocket while keeping REST
|
|
120
194
|
|
|
121
|
-
```
|
|
122
|
-
|
|
195
|
+
```yaml
|
|
196
|
+
rest:
|
|
197
|
+
webSocket: false
|
|
123
198
|
```
|
|
124
199
|
|
|
125
200
|
## Notes
|
|
126
201
|
|
|
127
|
-
-
|
|
128
|
-
-
|
|
129
|
-
-
|
|
130
|
-
-
|
|
131
|
-
-
|
|
132
|
-
-
|
|
133
|
-
-
|
|
202
|
+
- The trailing slash is significant: `/Product` addresses the resource itself; `/Product/` addresses its record collection. `POST /Product` (no trailing slash) returns `404`.
|
|
203
|
+
- `HEAD` is served as `GET` with the body omitted. `QUERY` is accepted on the collection path and reads its search from the request body.
|
|
204
|
+
- A `POST` to an existing primary key fails with `409` — it does not overwrite.
|
|
205
|
+
- A component directory with **no configuration file** gets REST enabled by Harper's built-in default. As soon as a `config.yaml` exists it is used verbatim — add `rest: true` explicitly or REST is off.
|
|
206
|
+
- Do not apply `@export` to a schema type and also export a same-named JavaScript subclass of that table — this produces conflicting endpoints.
|
|
207
|
+
- Server-Sent Events subscriptions are served on the same paths, negotiated via `Accept: text/event-stream`. They are not affected by the `webSocket` option.
|
|
208
|
+
- Every non-hidden exported resource is included in the generated OpenAPI document at `GET /openapi`. Mark a type `@hidden` or set `static hidden = true` on a programmatic Resource to omit it.
|
|
209
|
+
- MQTT over WebSockets requires the sub-protocol header `Sec-WebSocket-Protocol: mqtt`.
|