@harperfast/template-vue-ts-studio 1.9.1 → 1.10.0

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 (24) hide show
  1. package/.agents/skills/harper-best-practices/AGENTS.md +770 -254
  2. package/.agents/skills/harper-best-practices/rules/caching.md +68 -62
  3. package/.agents/skills/harper-best-practices/rules/custom-resources.md +106 -23
  4. package/.agents/skills/harper-best-practices/rules/defining-relationships.md +152 -22
  5. package/.agents/skills/harper-best-practices/rules/extending-tables.md +90 -21
  6. package/.agents/skills/harper-best-practices/rules/handling-binary-data.md +103 -23
  7. package/.agents/skills/harper-best-practices/rules/programmatic-table-requests.md +51 -7
  8. package/.agents/skills/harper-best-practices/rules/schema-design-tooling.md +87 -64
  9. package/.agents/skills/harper-best-practices/rules/using-blob-datatype.md +96 -16
  10. package/.agents/skills/harper-best-practices/rules/vector-indexing.md +59 -29
  11. package/.agents/skills/harper-best-practices/rules.manifest.yaml +83 -6
  12. package/agent/skills/harper-best-practices/AGENTS.md +770 -254
  13. package/agent/skills/harper-best-practices/rules/caching.md +68 -62
  14. package/agent/skills/harper-best-practices/rules/custom-resources.md +106 -23
  15. package/agent/skills/harper-best-practices/rules/defining-relationships.md +152 -22
  16. package/agent/skills/harper-best-practices/rules/extending-tables.md +90 -21
  17. package/agent/skills/harper-best-practices/rules/handling-binary-data.md +103 -23
  18. package/agent/skills/harper-best-practices/rules/programmatic-table-requests.md +51 -7
  19. package/agent/skills/harper-best-practices/rules/schema-design-tooling.md +87 -64
  20. package/agent/skills/harper-best-practices/rules/using-blob-datatype.md +96 -16
  21. package/agent/skills/harper-best-practices/rules/vector-indexing.md +59 -29
  22. package/agent/skills/harper-best-practices/rules.manifest.yaml +83 -6
  23. package/package.json +1 -1
  24. package/skills-lock.json +1 -1
@@ -2,37 +2,117 @@
2
2
  name: using-blob-datatype
3
3
  description: How to use the Blob data type for efficient binary storage in Harper.
4
4
  metadata:
5
- mode: synthesized
5
+ mode: generate
6
+ sources:
7
+ - reference/v5/database/schema.md#Blob Type
8
+ - reference/v5/database/api.md#Streaming
9
+ - reference/v5/database/api.md#`BlobOptions`
10
+ - reference/v5/database/api.md#Blob Coercion
11
+ sourceCommit: 4fe4c9c95e0974eaa77032f6f10e36fbd8ec64ac
12
+ inputHash: 71a3e738ebf87fa4
6
13
  ---
7
14
 
8
- # Using Blob Datatype
15
+ # Using the Blob Data Type
9
16
 
10
- Instructions for the agent to follow when working with the Blob data type in Harper.
17
+ Instructions for the agent to follow when storing and retrieving large binary content using Harper's `Blob` data type.
11
18
 
12
19
  ## When to Use
13
20
 
14
- Use this skill when you need to store unstructured or large binary data (media, documents) that is too large for standard JSON fields. Blobs provide efficient storage and integrated streaming support.
21
+ Apply this rule when a schema field needs to store large binary content such as images, video, audio, or large HTML typically content larger than 20KB. Use `Blob` instead of `Bytes` when you need streaming support or want to avoid loading the entire value into memory. See [handling-binary-data.md](handling-binary-data.md) for broader binary data guidance.
15
22
 
16
23
  ## How It Works
17
24
 
18
- 1. **Define Blob Fields**: In your GraphQL schema, use the `Blob` type:
25
+ 1. **Declare a `Blob` field in your schema**: Add a field typed as `Blob` to a `@table` type.
26
+
19
27
  ```graphql
20
28
  type MyTable @table {
21
- id: ID @primaryKey
29
+ id: Any! @primaryKey
22
30
  data: Blob
23
31
  }
24
32
  ```
25
- 2. **Create and Store Blobs**: Use `createBlob()` from Harper's globals to wrap Buffers or Streams:
33
+
34
+ 2. **Create a blob with `createBlob()`**: Pass a buffer, string, or stream as the first argument. Pass a `BlobOptions` object as the second argument to configure behavior.
35
+
36
+ ```javascript
37
+ let blob = createBlob(largeBuffer);
38
+ await MyTable.put({ id: 'my-record', data: blob });
39
+ ```
40
+
41
+ 3. **Read blob data using standard Web API methods**: The `Blob` type implements the Web API `Blob` interface. Use `.bytes()`, `.text()`, `.arrayBuffer()`, `.stream()`, or `.slice()` to access content.
42
+
43
+ ```javascript
44
+ let record = await MyTable.get('my-record');
45
+ let buffer = await record.data.bytes(); // ArrayBuffer
46
+ let text = await record.data.text(); // string
47
+ let stream = record.data.stream(); // ReadableStream
48
+ ```
49
+
50
+ 4. **Use `saveBeforeCommit` for ACID-compliant writes**: By default, blobs are not ACID-compliant — a record can reference a blob before it is fully written. Set `saveBeforeCommit: true` to wait for the full write before the transaction commits.
51
+
26
52
  ```javascript
27
- import { tables } from 'harper';
28
- const blob = createBlob(largeBuffer);
29
- await tables.MyTable.put('my-id', { data: blob });
53
+ let blob = createBlob(stream, { saveBeforeCommit: true });
54
+ await MyTable.put({ id: 'my-record', data: blob });
55
+ // put() resolves only after blob is fully written and record is committed
30
56
  ```
31
- 3. **Use Streaming (Optional)**: For very large files, pass a stream to `createBlob()` to avoid loading the entire file into memory.
32
- 4. **Read Blob Data**: Retrieve the record and use `.bytes()` or streaming interfaces on the blob field:
57
+
58
+ 5. **Register an error handler when returning a blob via REST**: Interrupted streams must be handled explicitly to avoid stale records.
59
+
33
60
  ```javascript
34
- const record = await tables.MyTable.get('my-id');
35
- const buffer = await record.data.bytes();
61
+ export class MyEndpoint extends MyTable {
62
+ static async get(target) {
63
+ const record = super.get(target);
64
+ let blob = record.data;
65
+ blob.on('error', () => {
66
+ MyTable.invalidate(target);
67
+ });
68
+ return { status: 200, headers: {}, body: blob };
69
+ }
70
+ }
36
71
  ```
37
- 5. **Ensure Write Completion**: Use `saveBeforeCommit: true` in `createBlob` options if you need the blob fully written before the record is committed.
38
- 6. **Handle Errors**: Attach error listeners to the blob object to handle streaming failures.
72
+
73
+ 6. **Rely on automatic coercion where applicable**: When a field is typed as `Blob` in the schema, any string or buffer assigned via `put`, `patch`, or `publish` is automatically coerced to a `Blob`. Manual `createBlob()` calls are not required for plain JSON HTTP bodies or MQTT messages in most cases.
74
+
75
+ ### `BlobOptions` Reference
76
+
77
+ | Option | Type | Default | Description |
78
+ | ------------------ | --------- | ----------- | ------------------------------------------------------------------------------------------------------------------------ |
79
+ | `type` | `string` | `undefined` | MIME type to associate with the blob (e.g., `image/jpeg`). Readable via `blob.type` and used when serving HTTP. |
80
+ | `size` | `number` | `undefined` | Size of the data in bytes, if known ahead of time. Otherwise inferred from a buffer or determined as a stream completes. |
81
+ | `saveBeforeCommit` | `boolean` | `false` | Wait for the blob to be fully written before committing the transaction. |
82
+ | `compress` | `boolean` | `false` | Compress the stored data with deflate. |
83
+ | `flush` | `boolean` | `false` | Flush the file to disk after writing, before the `createBlob` promise chain resolves. |
84
+
85
+ ## Examples
86
+
87
+ **Store an image with a MIME type:**
88
+
89
+ ```javascript
90
+ let blob = createBlob(imageBuffer, { type: 'image/jpeg' });
91
+ await Photo.put({ id, data: blob });
92
+ ```
93
+
94
+ **Stream large media with low latency:**
95
+
96
+ ```javascript
97
+ let blob = createBlob(incomingStream);
98
+ // blob exists, but data is still streaming to storage
99
+ await MyTable.put({ id: 'my-record', data: blob });
100
+
101
+ let record = await MyTable.get('my-record');
102
+ // blob data is accessible as it arrives
103
+ let outgoingStream = record.data.stream();
104
+ ```
105
+
106
+ **Guaranteed write before commit:**
107
+
108
+ ```javascript
109
+ let blob = createBlob(stream, { saveBeforeCommit: true });
110
+ await MyTable.put({ id: 'my-record', data: blob });
111
+ ```
112
+
113
+ ## Notes
114
+
115
+ - `Blob` stores data separately from the record; `Bytes` does not. Prefer `Blob` for content larger than 20KB.
116
+ - All standard Web API `Blob` methods are available: `.bytes()`, `.text()`, `.arrayBuffer()`, `.stream()`, `.slice()`.
117
+ - Blobs are **not** ACID-compliant by default when created from a stream. Use `saveBeforeCommit: true` to enforce transactional consistency.
118
+ - Always attach an `error` handler on blobs returned as HTTP response bodies to handle interrupted streams.
@@ -5,21 +5,21 @@ metadata:
5
5
  mode: generate
6
6
  sources:
7
7
  - reference/v5/database/schema.md#Vector Indexing
8
- sourceCommit: b7fbddadd42eb4487190b650a9abc4bcfeef5819
9
- inputHash: 3732961c671aac00
8
+ sourceCommit: 4fe4c9c95e0974eaa77032f6f10e36fbd8ec64ac
9
+ inputHash: d90b1b74597d08a6
10
10
  ---
11
11
 
12
12
  # Vector Indexing
13
13
 
14
- Instructions for the agent to follow when enabling and querying vector indexes for similarity search in Harper using the HNSW algorithm.
14
+ Instructions for the agent to enable HNSW vector indexes on table fields and query them for similarity search in Harper.
15
15
 
16
16
  ## When to Use
17
17
 
18
- Apply this rule when adding a vector index to a Harper table schema or writing similarity search queries against high-dimensional vector fields. Use it whenever you need approximate nearest-neighbor search, distance-threshold filtering, or distance-scored results.
18
+ Apply this rule when adding a vector similarity search capability to a Harper table for example, storing text embeddings and querying for nearest neighbors, filtering by distance threshold, or tuning index construction and search parameters. Use it alongside [adding-tables-with-schemas.md](adding-tables-with-schemas.md) when defining the schema that hosts the vector field.
19
19
 
20
20
  ## How It Works
21
21
 
22
- 1. **Declare the vector index on a `[Float]` field**: Add `@indexed(type: "HNSW")` to any `[Float]` attribute in a `@table` type. See [adding-tables-with-schemas.md](adding-tables-with-schemas.md) for general schema setup.
22
+ 1. **Declare the vector index on a field**: Add `@indexed(type: "HNSW")` to a `[Float]` field inside a `@table` type. This creates an HNSW (Hierarchical Navigable Small World) index for approximate nearest-neighbor search.
23
23
 
24
24
  ```graphql
25
25
  type Document @table {
@@ -28,7 +28,7 @@ Apply this rule when adding a vector index to a Harper table schema or writing s
28
28
  }
29
29
  ```
30
30
 
31
- 2. **Query by nearest neighbors using `sort`**: Call `Document.search()` with a `sort` object containing `attribute` (the indexed field name) and `target` (the query vector). Include `limit` to cap results.
31
+ 2. **Query by nearest neighbors using `sort`**: Call `.search()` with a `sort` descriptor that specifies the indexed `attribute` and a `target` vector. Use `limit` to cap results.
32
32
 
33
33
  ```javascript
34
34
  let results = Document.search({
@@ -47,7 +47,7 @@ Apply this rule when adding a vector index to a Harper table schema or writing s
47
47
  });
48
48
  ```
49
49
 
50
- 4. **Filter by distance threshold**: To return only records within a similarity cutoff (without ranking), place `target` directly on the condition alongside `comparator` and `value`. Omit `sort`.
50
+ 4. **Filter by distance threshold**: To return only records within a similarity cutoff (without ranking), place `target` directly on the condition alongside `comparator` and `value`. This bounds result quality rather than ranking by similarity.
51
51
 
52
52
  ```javascript
53
53
  let results = Document.search({
@@ -60,7 +60,7 @@ Apply this rule when adding a vector index to a Harper table schema or writing s
60
60
  });
61
61
  ```
62
62
 
63
- 5. **Include computed distance in results**: Use the special `$distance` field in `select` to return the distance from the target vector. Works with both `sort`-based and `conditions`-based queries.
63
+ 5. **Include computed distance in results**: Use the special `$distance` field in `select` to return the distance from the target vector. Available in both `sort`-based and threshold-based queries.
64
64
 
65
65
  ```javascript
66
66
  let results = Document.search({
@@ -70,43 +70,59 @@ Apply this rule when adding a vector index to a Harper table schema or writing s
70
70
  });
71
71
  ```
72
72
 
73
- 6. **Tune HNSW parameters**: Pass additional parameters to `@indexed(type: "HNSW", ...)` to control index quality and performance.
73
+ 6. **Tune per-query search options**: Pass `distance` and `ef` directly on the `sort` descriptor to override index defaults for a single query.
74
74
 
75
- | Parameter | Default | Description |
76
- | ---------------------- | ----------------- | --------------------------------------------------------------------------------------------------- |
77
- | `distance` | `"cosine"` | Distance function: `"euclidean"` or `"cosine"` (negative cosine similarity) |
78
- | `efConstruction` | `100` | Max nodes explored during index construction. Higher = better recall, lower = better performance |
79
- | `M` | `16` | Preferred connections per graph layer. Higher = more space, better recall for high-dimensional data |
80
- | `optimizeRouting` | `0.5` | Heuristic aggressiveness for omitting redundant connections (0 = off, 1 = most aggressive) |
81
- | `mL` | computed from `M` | Normalization factor for level generation |
82
- | `efSearchConstruction` | `50` | Max nodes explored during search |
75
+ ```javascript
76
+ let results = Document.search({
77
+ sort: { attribute: 'textEmbeddings', target: searchVector, distance: 'dotProduct', ef: 200 },
78
+ limit: 5,
79
+ });
80
+ ```
81
+
82
+ - `distance` overrides the distance function for this query: `"cosine"`, `"euclidean"`, or `"dotProduct"`.
83
+ - `ef` — overrides the search exploration budget. Higher values improve recall at the cost of latency.
84
+
85
+ 7. **Configure HNSW index parameters**: Pass parameters directly in the `@indexed` directive. Structural parameters (`distance`, `M`, `efConstruction`, `quantization`) trigger an index rebuild when changed; `efConstructionSearch` does not.
86
+
87
+ ```graphql
88
+ type Document @table {
89
+ id: Long @primaryKey
90
+ textEmbeddings: [Float]
91
+ @indexed(type: "HNSW", distance: "euclidean", optimizeRouting: 0, efConstructionSearch: 100)
92
+ }
93
+ ```
94
+
95
+ 8. **Enable vector quantization**: Use `quantization: "int8"` to store vectors as 8-bit integers, reducing index size and memory usage. Harper re-ranks nearest-neighbor `sort` results against full-precision vectors automatically.
96
+
97
+ ```graphql
98
+ type Document @table {
99
+ id: Long @primaryKey
100
+ textEmbeddings: [Float] @indexed(type: "HNSW", quantization: "int8")
101
+ }
102
+ ```
83
103
 
84
104
  ## Examples
85
105
 
86
- **Schema with custom HNSW parameters:**
106
+ Full schema with custom HNSW parameters and a nearest-neighbor query with distance output:
87
107
 
88
108
  ```graphql
89
109
  type Document @table {
90
110
  id: Long @primaryKey
91
111
  textEmbeddings: [Float]
92
- @indexed(type: "HNSW", distance: "euclidean", optimizeRouting: 0, efSearchConstruction: 100)
112
+ @indexed(type: "HNSW", distance: "euclidean", optimizeRouting: 0, efConstructionSearch: 100)
93
113
  }
94
114
  ```
95
115
 
96
- **Nearest-neighbor search with distance score:**
97
-
98
116
  ```javascript
117
+ // Nearest-neighbor search with distance scores
99
118
  let results = Document.search({
100
119
  select: ['name', '$distance'],
101
120
  sort: { attribute: 'textEmbeddings', target: searchVector },
102
121
  limit: 5,
103
122
  });
104
- ```
105
123
 
106
- **Distance-threshold filter (no ranking):**
107
-
108
- ```javascript
109
- let results = Document.search({
124
+ // Distance-threshold query (no ranking)
125
+ let closeMatches = Document.search({
110
126
  conditions: {
111
127
  attribute: 'textEmbeddings',
112
128
  comparator: 'lt',
@@ -118,7 +134,21 @@ let results = Document.search({
118
134
 
119
135
  ## Notes
120
136
 
121
- - The default `distance` function is `cosine`. Pass `distance: "euclidean"` to switch.
122
- - `efConstruction` controls index build quality; raising it improves recall at the cost of build time.
137
+ ### HNSW Parameters
138
+
139
+ | Parameter | Default | Description |
140
+ | ---------------------- | ----------------- | ------------------------------------------------------------------------------------------------------ |
141
+ | `distance` | `"cosine"` | Distance function: `"cosine"`, `"euclidean"`, or `"dotProduct"` |
142
+ | `efConstruction` | `100` | Max nodes explored during index construction. Higher = better recall, lower = better performance |
143
+ | `M` | `16` | Preferred connections per graph layer. Higher = more space, better recall for high-dimensional data |
144
+ | `optimizeRouting` | `0.5` | Heuristic aggressiveness for omitting redundant connections (0 = off, 1 = most aggressive) |
145
+ | `mL` | computed from `M` | Normalization factor for level generation |
146
+ | `efConstructionSearch` | auto-scaled | Max nodes explored during search. When unset, auto-scales with index size; setting it fixes the budget |
147
+ | `quantization` | — | `"int8"` stores vectors quantized to int8 |
148
+
149
+ - The `distance` option on a per-query `sort` descriptor accepts `"cosine"`, `"euclidean"`, or `"dotProduct"`.
150
+ - When no `ef` is passed and `efConstructionSearch` (or `efConstruction`) is not explicitly set on the index, the search budget auto-scales with index size.
151
+ - `efConstruction` seeds the initial value of `efConstructionSearch`; setting either one fixes the search budget.
152
+ - The correct parameter name is `efConstructionSearch` (not `efSearchConstruction`).
123
153
  - `$distance` is available in both `sort`-based ranking and `conditions`-based threshold queries.
124
- - Use the threshold (`conditions` + `target`) form when you want to bound result quality by a similarity cutoff rather than ranking by similarity.
154
+ - For `quantization: "int8"`, distance-threshold (`lt`/`le`) queries filter on approximate distance; `sort` queries re-rank against full-precision vectors.
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # Declarative source of truth for rule taxonomy, sources, and generation mode.
4
4
  # Owned by humans; the generator reads this file and writes derived artifacts
5
- # (rule bodies, AGENTS.md). See docs/plans/docs-driven-skills.md for the
5
+ # (rule bodies, AGENTS.md). See docs/plans-archive/docs-driven-skills.md for the
6
6
  # full schema definition and Manifest ↔ frontmatter reconciliation semantics.
7
7
  #
8
8
  # Phase 2 flipped vector-indexing to mode: generate.
@@ -53,7 +53,20 @@ rules:
53
53
  category: schema
54
54
  priority: 1
55
55
  order: 3
56
- mode: synthesized
56
+ mode: generate
57
+ sources:
58
+ - path: reference/v5/database/schema.md
59
+ section: 'Relationships'
60
+ role: primary
61
+ - path: reference/v5/rest/querying.md
62
+ section: 'Relationships and Joins'
63
+ role: supplemental
64
+ must_cover:
65
+ - '@relationship'
66
+ - 'from'
67
+ - 'to'
68
+ - 'one-to-many'
69
+ - 'many-to-one'
57
70
 
58
71
  - rule: vector-indexing
59
72
  description: How to enable and query vector indexes for similarity search in Harper.
@@ -79,14 +92,51 @@ rules:
79
92
  category: schema
80
93
  priority: 1
81
94
  order: 5
82
- mode: synthesized
95
+ mode: generate
96
+ sources:
97
+ - path: reference/v5/database/schema.md
98
+ section: 'Blob Type'
99
+ role: primary
100
+ - path: reference/v5/database/api.md
101
+ section: 'Streaming'
102
+ role: supplemental
103
+ - path: reference/v5/database/api.md
104
+ section: '`BlobOptions`'
105
+ role: supplemental
106
+ - path: reference/v5/database/api.md
107
+ section: 'Blob Coercion'
108
+ role: supplemental
109
+ must_cover:
110
+ - 'Blob'
111
+ - 'createBlob'
112
+ - 'saveBeforeCommit'
113
+ - '.bytes()'
114
+ cross_links:
115
+ - handling-binary-data
83
116
 
84
117
  - rule: handling-binary-data
85
118
  description: How to store and serve binary data like images or audio in Harper.
86
119
  category: schema
87
120
  priority: 1
88
121
  order: 6
89
- mode: synthesized
122
+ mode: generate
123
+ sources:
124
+ - path: reference/v5/database/api.md
125
+ section: 'Accepting Binary in JSON Requests'
126
+ role: primary
127
+ - path: reference/v5/database/api.md
128
+ section: 'Serving Binary from a Resource'
129
+ role: primary
130
+ - path: reference/v5/rest/content-types.md
131
+ section: 'Storing Arbitrary Content Types'
132
+ role: supplemental
133
+ must_cover:
134
+ - 'createBlob'
135
+ - 'Content-Type'
136
+ - 'application/octet-stream'
137
+ - 'base64'
138
+ cross_links:
139
+ - using-blob-datatype
90
140
 
91
141
  # ===========================================================================
92
142
  # API & Communication (priority 2 — HIGH)
@@ -176,14 +226,41 @@ rules:
176
226
  category: logic
177
227
  priority: 3
178
228
  order: 1
179
- mode: synthesized
229
+ mode: generate
230
+ sources:
231
+ - path: reference/v5/resources/overview.md
232
+ section: 'Custom External Data Source'
233
+ role: primary
234
+ - path: reference/v5/resources/overview.md
235
+ section: 'Exporting Resources as Endpoints'
236
+ role: primary
237
+ - path: reference/v5/components/javascript-environment.md
238
+ section: 'Module Loading'
239
+ role: supplemental
240
+ must_cover:
241
+ - 'extends Resource'
242
+ - 'export class'
243
+ - 'server.resources.set('
244
+ - 'static'
180
245
 
181
246
  - rule: extending-tables
182
247
  description: How to add custom logic to automatically generated table resources in Harper.
183
248
  category: logic
184
249
  priority: 3
185
250
  order: 2
186
- mode: synthesized
251
+ mode: generate
252
+ sources:
253
+ - path: reference/v5/resources/overview.md
254
+ section: 'Extending a Table'
255
+ role: primary
256
+ - path: reference/v5/resources/resource-api.md
257
+ section: 'Throwing Errors'
258
+ role: supplemental
259
+ must_cover:
260
+ - 'extends tables.'
261
+ - 'super.'
262
+ - '@export'
263
+ - 'statusCode'
187
264
 
188
265
  - rule: programmatic-table-requests
189
266
  description: How to interact with Harper tables programmatically using the `tables` object.