@harperfast/template-vue-ts-studio 1.6.4 → 1.7.1

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.
@@ -40,70 +40,153 @@ type ExamplePerson @table @export {
40
40
  }
41
41
  ```
42
42
 
43
- ### 1.2 Schema Design & Tooling
43
+ ### 1.2 Schema Design and Tooling
44
44
 
45
- Harper uses GraphQL schemas to define database tables, relationships, and APIs. To ensure the best development experience for both humans and AI agents, it's important to understand the core directives and configure your project tooling correctly.
45
+ Instructions for the agent to follow when designing Harper schemas, applying core directives, and configuring GraphQL tooling.
46
46
 
47
- #### Core Harper Directives
47
+ #### When to Use
48
48
 
49
- Harper extends GraphQL with custom directives that define database behavior. These are typically defined in `node_modules/harper/schema.graphql`. If you don't have access to that file, here is a reference of the most important ones:
49
+ Apply this rule when creating or modifying Harper schema files, configuring `graphqlSchema` in `config.yaml`, or deciding which directives to apply to tables and fields. Use it any time a component needs tables, indexes, primary keys, or exported endpoints defined.
50
50
 
51
- ##### Table Definition
51
+ #### How It Works
52
52
 
53
- - `@table`: Marks a GraphQL type as a Harper database table.
54
- - `@export`: Automatically generates REST and WebSocket APIs for the table.
55
- - `@table(expiration: Int)`: Configures a time-to-expire for records in the table (useful for caching).
53
+ 1. **Create a GraphQL schema file** with Harper-specific directives. Name it (e.g., `schema.graphql`) and place it in your component directory.
56
54
 
57
- ##### Attribute Constraints & Indexing
55
+ ```graphql
56
+ type Dog @table {
57
+ id: Long @primaryKey
58
+ name: String
59
+ breed: String
60
+ age: Int
61
+ }
58
62
 
59
- - `@primaryKey`: Specifies the unique identifier for the table.
60
- - `@indexed`: Creates a standard index on the field for faster lookups.
61
- - `@indexed(type: "HNSW", distance: "cosine" | "euclidean" | "dot")`: Creates a vector index for similarity search.
63
+ type Breed @table {
64
+ id: Long @primaryKey
65
+ name: String @indexed
66
+ }
67
+ ```
62
68
 
63
- ##### Relationships
69
+ 2. **Register the schema in `config.yaml`** using the `graphqlSchema` plugin key:
64
70
 
65
- - `@relationship(from: String)`: Defines a relationship to another table. `from` specifies the local field holding the foreign key.
71
+ ```yaml
72
+ graphqlSchema:
73
+ files: 'schema.graphql'
74
+ ```
66
75
 
67
- ##### Authentication & Authorization
76
+ Both plugins and applications can specify schemas this way.
68
77
 
69
- - `@auth(role: String)`: Restricts access to a table or field based on user roles.
78
+ 3. **Mark every table type with `@table`**. The type name becomes the table name by default. Use optional arguments to override behavior:
70
79
 
71
- #### Configuring GraphQL Tooling
80
+ | Argument | Type | Default | Description |
81
+ | -------------- | --------- | ----------------------------- | ------------------------------------------------------------- |
82
+ | `table` | `String` | type name | Override the table name |
83
+ | `database` | `String` | `"data"` | Database to place the table in |
84
+ | `expiration` | `Int` | — | Seconds until a record goes stale |
85
+ | `eviction` | `Int` | `0` | Additional seconds after `expiration` before physical removal |
86
+ | `scanInterval` | `Int` | `(expiration + eviction) / 4` | Seconds between eviction scans |
87
+ | `replicate` | `Boolean` | `true` | Enable replication of this table |
72
88
 
73
- To get the best IDE support (autocompletion, validation) and to help AI agents understand your schema context, you should create a `graphql.config.yml` file in your project root.
89
+ 4. **Designate a primary key on every table** using `@primaryKey`. Primary keys must be unique; duplicate-key inserts are rejected. If no key is provided on insert, Harper auto-generates one:
90
+ - `String` or `ID` → UUID string
91
+ - `Int`, `Long`, or `Any` → auto-incrementing integer
74
92
 
75
- This file tells GraphQL tools where to find Harper's built-in types and directives alongside your own schema files.
93
+ Prefer `Long` or `Any` for auto-generated numeric keys; `Int` is 32-bit and may be insufficient for large tables.
76
94
 
77
- ##### Creating `graphql.config.yml`
95
+ 5. **Index fields that need fast querying** with `@indexed`. This is required for filtering by that attribute in REST queries, SQL, or NoSQL operations. If the field value is an array, each element is individually indexed.
78
96
 
79
- Create a file named `graphql.config.yml` in your project root with the following content:
97
+ ```graphql
98
+ type Product @table {
99
+ id: Long @primaryKey
100
+ category: String @indexed
101
+ price: Float @indexed
102
+ }
103
+ ```
80
104
 
81
- ```yaml
82
- schema:
83
- - 'node_modules/harper/schema.graphql'
84
- - 'schema.graphql'
85
- - 'schemas/*.graphql'
105
+ 6. **Expose a table as an external resource endpoint** with `@export`. This makes the table accessible via REST, MQTT, and other interfaces. The optional `name` parameter sets the URL path segment; without it, the type name is used.
106
+
107
+ ```graphql
108
+ type MyTable @table @export(name: "my-table") {
109
+ id: Long @primaryKey
110
+ }
111
+ ```
112
+
113
+ 7. **Restrict extra properties** with `@sealed` when records must not include attributes beyond those declared. By default, Harper allows additional properties.
114
+
115
+ ```graphql
116
+ type StrictRecord @table @sealed {
117
+ id: Long @primaryKey
118
+ name: String
119
+ }
120
+ ```
121
+
122
+ 8. **Configure expiration, eviction, and scan behavior** together when building caching tables. These three arguments control the full record lifecycle:
123
+ - `expiration` — record becomes stale; next request triggers a source fetch
124
+ - `eviction` — additional time after `expiration` before physical removal
125
+ - `scanInterval` — how often Harper scans for records to evict; clock-aligned, not startup-aligned
126
+
127
+ #### Examples
128
+
129
+ **Caching table with tuned expiration:**
130
+
131
+ ```graphql
132
+ # Expire after 5 minutes, evict after 1 hour, scan every 10 minutes
133
+ type WeatherCache @table(expiration: 300, eviction: 3300, scanInterval: 600) {
134
+ id: ID @primaryKey
135
+ temperature: Float
136
+ }
86
137
  ```
87
138
 
88
- ##### Why this is important:
139
+ **Table in a named database with expiration and an indexed field:**
89
140
 
90
- 1. **Shared Directives**: It includes `@table`, `@primaryKey`, etc., so they aren't marked as "unknown directives".
91
- 2. **Context for Agents**: When an agent reads your project, seeing this config helps it locate the core Harper definitions, leading to more accurate code generation.
92
- 3. **Consistency**: The `npm create harper@latest` command includes this by default. Manually adding it to existing projects ensures they follow the same standards.
141
+ ```graphql
142
+ type Event @table(database: "analytics", expiration: 86400) {
143
+ id: Long @primaryKey
144
+ name: String @indexed
145
+ }
146
+ ```
93
147
 
94
- #### Example Project Structure
148
+ **Session cache with auto-expiry:**
149
+
150
+ ```graphql
151
+ type Session @table(expiration: 3600) {
152
+ id: Long @primaryKey
153
+ userId: String
154
+ }
155
+ ```
95
156
 
96
- A typical Harper project with proper schema tooling:
157
+ **Table with audit timestamps:**
97
158
 
98
- ```text
99
- my-harper-app/
100
- ├── config.yaml
101
- ├── graphql.config.yml
102
- ├── package.json
103
- ├── schema.graphql
104
- └── resources.js
159
+ ```graphql
160
+ type Order @table @export(name: "orders") {
161
+ id: Long @primaryKey
162
+ createdAt: Long @createdTime
163
+ updatedAt: Long @updatedTime
164
+ status: String @indexed
165
+ }
105
166
  ```
106
167
 
168
+ **Overriding the table name and disabling replication:**
169
+
170
+ ```graphql
171
+ type Product @table(table: "products") {
172
+ id: Long @primaryKey
173
+ name: String
174
+ }
175
+
176
+ type LocalRecord @table(replicate: false) {
177
+ id: Long @primaryKey
178
+ value: String
179
+ }
180
+ ```
181
+
182
+ #### Notes
183
+
184
+ - Use unique `database` names in plugins and applications to avoid table naming collisions, since all tables default to the `"data"` database.
185
+ - Eviction removes non-indexed record data but does **not** remove a record from its secondary indexes. Indexes remain functional for evicted records; Harper fetches the full record from the source on demand when a query matches an evicted record.
186
+ - `scanInterval` is clock-aligned to the server's local timezone. The server's startup time does not affect when eviction runs.
187
+ - If replication is disabled on a table and later re-enabled, it will not catch up on writes made while replication was disabled.
188
+ - Null values are indexed by `@indexed` fields, enabling queries such as `GET /Product/?category=null`.
189
+
107
190
  ### 1.3 Defining Relationships
108
191
 
109
192
  Instructions for the agent to follow when defining relationships between Harper tables.
@@ -1138,34 +1221,60 @@ for await (const record of tables.Product.search({
1138
1221
 
1139
1222
  Be very careful when performing updates and deletions! You may be dealing with live production data. The wrong request to delete, without approval from a human, could be devastating to a business. Always use the proper approval process.
1140
1223
 
1141
- ### 3.4 TypeScript Type Stripping
1224
+ ### 3.4 TypeScript Type Stripping in Harper
1142
1225
 
1143
- Instructions for the agent to follow when using TypeScript in Harper.
1226
+ Instructions for the agent to run `.ts` files directly in Harper without a build step using Node.js's built-in type stripping.
1144
1227
 
1145
1228
  #### When to Use
1146
1229
 
1147
- Use this skill when you want to write Harper Resources in TypeScript and have them execute directly in Node.js without an intermediate build or compilation step.
1230
+ Apply this rule when writing Harper resource files in TypeScript. Use it any time you need to reference `.ts` source files from `config.yaml` or import between local TypeScript modules in a Harper project.
1148
1231
 
1149
1232
  #### How It Works
1150
1233
 
1151
- 1. **Verify Node.js Version**: Ensure you are using Node.js v22.6.0 or higher.
1152
- 2. **Name Files with `.ts`**: Create your resource files in the `resources/` directory with a `.ts` extension.
1153
- 3. **Use TypeScript Syntax**: Write your resource classes using standard TypeScript (interfaces, types, etc.).
1154
- ```typescript
1155
- import { Resource } from 'harper';
1156
- export class MyResource extends Resource {
1157
- async get(): Promise<{ message: string }> {
1158
- return { message: 'Running TS directly!' };
1159
- }
1160
- }
1161
- ```
1162
- 4. **Use Explicit Extensions in Imports**: When importing other local modules, include the `.ts` extension: `import { helper } from './helper.ts'`.
1163
- 5. **Configure `config.yaml`**: Ensure `jsResource` points to your `.ts` files:
1234
+ 1. **Ensure Node.js version**: Require Node.js 22.6 or later. Type stripping is unavailable on earlier versions.
1235
+
1236
+ 2. **Point `jsResource` at `.ts` files**: The `jsResource` plugin loads both `.js` and `.ts` files. Set its `files` glob in `config.yaml` to target your `.ts` source files:
1237
+
1164
1238
  ```yaml
1165
1239
  jsResource:
1166
1240
  files: 'resources/*.ts'
1167
1241
  ```
1168
1242
 
1243
+ 3. **Use explicit `.ts` extensions in local imports**: Node's loader does not resolve `'./helper'` to `'./helper.ts'`, so always include the full extension:
1244
+
1245
+ ```typescript
1246
+ import { helper } from './helper.ts';
1247
+ ```
1248
+
1249
+ 4. **Stay within type-stripping limits**: Only type annotations and declarations are removed. Do not use enums with runtime values, namespaces with runtime semantics, or any other features that require code transformation beyond type stripping.
1250
+
1251
+ #### Examples
1252
+
1253
+ A complete Harper resource written in TypeScript, using imports from the `harper` package:
1254
+
1255
+ ```typescript
1256
+ import { type RequestTargetOrId, Resource, tables } from 'harper';
1257
+
1258
+ export class MyResource extends Resource {
1259
+ async get(target?: RequestTargetOrId): Promise<{ message: string }> {
1260
+ return { message: 'Hello from TS' };
1261
+ }
1262
+ }
1263
+ ```
1264
+
1265
+ Paired `config.yaml` entry loading the file via `jsResource`:
1266
+
1267
+ ```yaml
1268
+ jsResource:
1269
+ files: 'resources/*.ts'
1270
+ ```
1271
+
1272
+ #### Notes
1273
+
1274
+ - No build step or transpiler is required — Harper runs `.ts` files directly.
1275
+ - Type imports (e.g., `import { type RequestTargetOrId }`) from the `harper` package work as usual.
1276
+ - Unsupported TypeScript features include: enums with runtime values, namespaces with runtime semantics, and anything requiring code transformation beyond simple type stripping.
1277
+
1169
1278
  ### 3.5 Caching External Data Sources in Harper
1170
1279
 
1171
1280
  Instructions for the agent to implement integrated data caching in Harper by wrapping external sources with a cache table and `sourcedFrom`.
@@ -1456,11 +1565,14 @@ CLI_TARGET='YOUR_CLUSTER_URL'
1456
1565
 
1457
1566
  ### 4.3 Creating Harper Applications
1458
1567
 
1459
- The fastest way to start a new Harper project is using the `create-harper` CLI tool. This command initializes a project with a standard folder structure, essential configuration files, and basic schema definitions.
1568
+ The fastest way to start a new Harper project is using the `create-harper` CLI tool. This command
1569
+ initializes a project with a standard folder structure, essential configuration files, and basic
1570
+ schema definitions.
1460
1571
 
1461
1572
  #### When to Use
1462
1573
 
1463
- Use this command when starting a new Harper application or adding a new Harper microservice to an existing architecture.
1574
+ Use this command when starting a new Harper application or adding a new Harper microservice to an
1575
+ existing architecture.
1464
1576
 
1465
1577
  #### Commands
1466
1578
 
@@ -1714,3 +1826,102 @@ Tagged entries appear in `hdb.log` with the tag in the header:
1714
1826
  - `console.log` output is only forwarded to `hdb.log` when `logging.console: true` is explicitly set; it is not forwarded by default.
1715
1827
  - When logging to standard streams, run Harper in the foreground (`harper`, not `harper start`).
1716
1828
  - `TaggedLogger` is bound to the configured log level at creation time — always use `?.` on its methods.
1829
+
1830
+ ### 4.6 Load Environment Variables with loadEnv
1831
+
1832
+ Instructions for the agent to follow when loading environment variables from `.env` files into a Harper application using the `loadEnv` plugin.
1833
+
1834
+ #### When to Use
1835
+
1836
+ 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.
1837
+
1838
+ #### How It Works
1839
+
1840
+ 1. **Declare `loadEnv` in `config.yaml`**: Add `loadEnv` as a top-level key. It is built into Harper and requires no installation.
1841
+
1842
+ ```yaml
1843
+ loadEnv:
1844
+ files: '.env'
1845
+ ```
1846
+
1847
+ 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.
1848
+
1849
+ ```yaml
1850
+ # config.yaml — loadEnv must come first
1851
+ loadEnv:
1852
+ files: '.env'
1853
+
1854
+ rest: true
1855
+
1856
+ myApp:
1857
+ files: './src/*.js'
1858
+ ```
1859
+
1860
+ 3. **Configure the `files` option**: Provide one or more paths or glob patterns pointing to the env files to load. This option is required.
1861
+
1862
+ 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.
1863
+
1864
+ ```yaml
1865
+ loadEnv:
1866
+ files: '.env'
1867
+ override: true
1868
+ ```
1869
+
1870
+ 5. **Load multiple files when required**: Supply a list of files or a glob pattern. Files are loaded in the order specified.
1871
+ ```yaml
1872
+ loadEnv:
1873
+ files:
1874
+ - '.env'
1875
+ - '.env.local'
1876
+ ```
1877
+ or
1878
+ ```yaml
1879
+ loadEnv:
1880
+ files: 'env-vars/*'
1881
+ ```
1882
+
1883
+ ##### Configuration Options
1884
+
1885
+ | Option | Type | Required | Description |
1886
+ | ---------- | -------------------- | -------- | -------------------------------------------------------------------------------------- |
1887
+ | `files` | `string \| string[]` | **Yes** | Path(s) or glob pattern(s) to the env file(s) to load. |
1888
+ | `override` | `boolean` | No | If `true`, loaded values override existing environment variables. Defaults to `false`. |
1889
+
1890
+ #### Examples
1891
+
1892
+ **Minimal setup — single `.env` file:**
1893
+
1894
+ ```yaml
1895
+ loadEnv:
1896
+ files: '.env'
1897
+ ```
1898
+
1899
+ **Full `config.yaml` with load order, multiple files, and override:**
1900
+
1901
+ ```yaml
1902
+ # config.yaml — loadEnv must come first
1903
+ loadEnv:
1904
+ files:
1905
+ - '.env'
1906
+ - '.env.local'
1907
+ override: true
1908
+
1909
+ rest: true
1910
+
1911
+ myApp:
1912
+ files: './src/*.js'
1913
+ ```
1914
+
1915
+ **Glob pattern:**
1916
+
1917
+ ```yaml
1918
+ loadEnv:
1919
+ files: 'env-vars/*'
1920
+ ```
1921
+
1922
+ #### Notes
1923
+
1924
+ - `loadEnv` is built into Harper — do not install it separately; only declare it in `config.yaml`.
1925
+ - Because Harper is a single-process application, variables loaded onto `process.env` are shared across all components.
1926
+ - Without `override: true`, variables already set in the shell or container environment will not be overwritten by values in `.env` files.
1927
+ - `files` is the only required option; omitting it will produce an invalid configuration.
@@ -82,6 +82,7 @@ See the concrete examples embedded in each rule subsection below (GraphQL schema
82
82
  - `creating-harper-apps` — How to initialize a new Harper application using the CLI.
83
83
  - `serving-web-content` — How to serve static files and integrated Vite/React applications in Harper.
84
84
  - `logging` — Best practices for logging in Harper, including console capture, the granular logger interface, and programmatic log retrieval.
85
+ - `load-env` — How to load environment variables from .env files into a Harper application using the loadEnv plugin.
85
86
 
86
87
  <!-- END GENERATED INDEX -->
87
88
 
@@ -7,11 +7,14 @@ metadata:
7
7
 
8
8
  # Creating Harper Applications
9
9
 
10
- The fastest way to start a new Harper project is using the `create-harper` CLI tool. This command initializes a project with a standard folder structure, essential configuration files, and basic schema definitions.
10
+ The fastest way to start a new Harper project is using the `create-harper` CLI tool. This command
11
+ initializes a project with a standard folder structure, essential configuration files, and basic
12
+ schema definitions.
11
13
 
12
14
  ## When to Use
13
15
 
14
- Use this command when starting a new Harper application or adding a new Harper microservice to an existing architecture.
16
+ Use this command when starting a new Harper application or adding a new Harper microservice to an
17
+ existing architecture.
15
18
 
16
19
  ## Commands
17
20
 
@@ -0,0 +1,111 @@
1
+ ---
2
+ name: load-env
3
+ description: >-
4
+ How to load environment variables from .env files into a Harper application
5
+ using the loadEnv plugin.
6
+ metadata:
7
+ mode: generate
8
+ sources:
9
+ - reference/v5/environment-variables/overview.md
10
+ sourceCommit: 42231db17c025a4a455e3d91875fad4084a01cb5
11
+ inputHash: fe610fc245226357
12
+ ---
13
+
14
+ # Load Environment Variables with loadEnv
15
+
16
+ Instructions for the agent to follow when loading environment variables from `.env` files into a Harper application using the `loadEnv` plugin.
17
+
18
+ ## When to Use
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.
21
+
22
+ ## How It Works
23
+
24
+ 1. **Declare `loadEnv` in `config.yaml`**: Add `loadEnv` as a top-level key. It is built into Harper and requires no installation.
25
+
26
+ ```yaml
27
+ loadEnv:
28
+ files: '.env'
29
+ ```
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.
32
+
33
+ ```yaml
34
+ # config.yaml — loadEnv must come first
35
+ loadEnv:
36
+ files: '.env'
37
+
38
+ rest: true
39
+
40
+ myApp:
41
+ files: './src/*.js'
42
+ ```
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.
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.
47
+
48
+ ```yaml
49
+ loadEnv:
50
+ files: '.env'
51
+ override: true
52
+ ```
53
+
54
+ 5. **Load multiple files when required**: Supply a list of files or a glob pattern. Files are loaded in the order specified.
55
+ ```yaml
56
+ loadEnv:
57
+ files:
58
+ - '.env'
59
+ - '.env.local'
60
+ ```
61
+ or
62
+ ```yaml
63
+ loadEnv:
64
+ files: 'env-vars/*'
65
+ ```
66
+
67
+ ### Configuration Options
68
+
69
+ | Option | Type | Required | Description |
70
+ | ---------- | -------------------- | -------- | -------------------------------------------------------------------------------------- |
71
+ | `files` | `string \| string[]` | **Yes** | Path(s) or glob pattern(s) to the env file(s) to load. |
72
+ | `override` | `boolean` | No | If `true`, loaded values override existing environment variables. Defaults to `false`. |
73
+
74
+ ## Examples
75
+
76
+ **Minimal setup — single `.env` file:**
77
+
78
+ ```yaml
79
+ loadEnv:
80
+ files: '.env'
81
+ ```
82
+
83
+ **Full `config.yaml` with load order, multiple files, and override:**
84
+
85
+ ```yaml
86
+ # config.yaml — loadEnv must come first
87
+ loadEnv:
88
+ files:
89
+ - '.env'
90
+ - '.env.local'
91
+ override: true
92
+
93
+ rest: true
94
+
95
+ myApp:
96
+ files: './src/*.js'
97
+ ```
98
+
99
+ **Glob pattern:**
100
+
101
+ ```yaml
102
+ loadEnv:
103
+ files: 'env-vars/*'
104
+ ```
105
+
106
+ ## Notes
107
+
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.
@@ -1,70 +1,161 @@
1
1
  ---
2
2
  name: schema-design-tooling
3
- description: Best practices for Harper schema design, including core directives and GraphQL tooling configuration.
3
+ description: >-
4
+ Best practices for Harper schema design, including core directives and GraphQL
5
+ tooling configuration.
4
6
  metadata:
5
- mode: synthesized
7
+ mode: generate
8
+ sources:
9
+ - reference/v5/database/schema.md#Overview
10
+ - reference/v5/database/schema.md#Type Directives
11
+ - reference/v5/database/schema.md#Field Directives
12
+ sourceCommit: b7fbddadd42eb4487190b650a9abc4bcfeef5819
13
+ inputHash: 4faa3baed7cfa854
6
14
  ---
7
15
 
8
- # Schema Design & Tooling
16
+ # Schema Design and Tooling
9
17
 
10
- Harper uses GraphQL schemas to define database tables, relationships, and APIs. To ensure the best development experience for both humans and AI agents, it's important to understand the core directives and configure your project tooling correctly.
18
+ Instructions for the agent to follow when designing Harper schemas, applying core directives, and configuring GraphQL tooling.
11
19
 
12
- ## Core Harper Directives
20
+ ## When to Use
13
21
 
14
- Harper extends GraphQL with custom directives that define database behavior. These are typically defined in `node_modules/harper/schema.graphql`. If you don't have access to that file, here is a reference of the most important ones:
22
+ Apply this rule when creating or modifying Harper schema files, configuring `graphqlSchema` in `config.yaml`, or deciding which directives to apply to tables and fields. Use it any time a component needs tables, indexes, primary keys, or exported endpoints defined.
15
23
 
16
- ### Table Definition
24
+ ## How It Works
17
25
 
18
- - `@table`: Marks a GraphQL type as a Harper database table.
19
- - `@export`: Automatically generates REST and WebSocket APIs for the table.
20
- - `@table(expiration: Int)`: Configures a time-to-expire for records in the table (useful for caching).
26
+ 1. **Create a GraphQL schema file** with Harper-specific directives. Name it (e.g., `schema.graphql`) and place it in your component directory.
21
27
 
22
- ### Attribute Constraints & Indexing
28
+ ```graphql
29
+ type Dog @table {
30
+ id: Long @primaryKey
31
+ name: String
32
+ breed: String
33
+ age: Int
34
+ }
23
35
 
24
- - `@primaryKey`: Specifies the unique identifier for the table.
25
- - `@indexed`: Creates a standard index on the field for faster lookups.
26
- - `@indexed(type: "HNSW", distance: "cosine" | "euclidean" | "dot")`: Creates a vector index for similarity search.
36
+ type Breed @table {
37
+ id: Long @primaryKey
38
+ name: String @indexed
39
+ }
40
+ ```
27
41
 
28
- ### Relationships
42
+ 2. **Register the schema in `config.yaml`** using the `graphqlSchema` plugin key:
29
43
 
30
- - `@relationship(from: String)`: Defines a relationship to another table. `from` specifies the local field holding the foreign key.
44
+ ```yaml
45
+ graphqlSchema:
46
+ files: 'schema.graphql'
47
+ ```
31
48
 
32
- ### Authentication & Authorization
49
+ Both plugins and applications can specify schemas this way.
33
50
 
34
- - `@auth(role: String)`: Restricts access to a table or field based on user roles.
51
+ 3. **Mark every table type with `@table`**. The type name becomes the table name by default. Use optional arguments to override behavior:
35
52
 
36
- ## Configuring GraphQL Tooling
53
+ | Argument | Type | Default | Description |
54
+ | -------------- | --------- | ----------------------------- | ------------------------------------------------------------- |
55
+ | `table` | `String` | type name | Override the table name |
56
+ | `database` | `String` | `"data"` | Database to place the table in |
57
+ | `expiration` | `Int` | — | Seconds until a record goes stale |
58
+ | `eviction` | `Int` | `0` | Additional seconds after `expiration` before physical removal |
59
+ | `scanInterval` | `Int` | `(expiration + eviction) / 4` | Seconds between eviction scans |
60
+ | `replicate` | `Boolean` | `true` | Enable replication of this table |
37
61
 
38
- To get the best IDE support (autocompletion, validation) and to help AI agents understand your schema context, you should create a `graphql.config.yml` file in your project root.
62
+ 4. **Designate a primary key on every table** using `@primaryKey`. Primary keys must be unique; duplicate-key inserts are rejected. If no key is provided on insert, Harper auto-generates one:
63
+ - `String` or `ID` → UUID string
64
+ - `Int`, `Long`, or `Any` → auto-incrementing integer
39
65
 
40
- This file tells GraphQL tools where to find Harper's built-in types and directives alongside your own schema files.
66
+ Prefer `Long` or `Any` for auto-generated numeric keys; `Int` is 32-bit and may be insufficient for large tables.
41
67
 
42
- ### Creating `graphql.config.yml`
68
+ 5. **Index fields that need fast querying** with `@indexed`. This is required for filtering by that attribute in REST queries, SQL, or NoSQL operations. If the field value is an array, each element is individually indexed.
43
69
 
44
- Create a file named `graphql.config.yml` in your project root with the following content:
70
+ ```graphql
71
+ type Product @table {
72
+ id: Long @primaryKey
73
+ category: String @indexed
74
+ price: Float @indexed
75
+ }
76
+ ```
45
77
 
46
- ```yaml
47
- schema:
48
- - 'node_modules/harper/schema.graphql'
49
- - 'schema.graphql'
50
- - 'schemas/*.graphql'
78
+ 6. **Expose a table as an external resource endpoint** with `@export`. This makes the table accessible via REST, MQTT, and other interfaces. The optional `name` parameter sets the URL path segment; without it, the type name is used.
79
+
80
+ ```graphql
81
+ type MyTable @table @export(name: "my-table") {
82
+ id: Long @primaryKey
83
+ }
84
+ ```
85
+
86
+ 7. **Restrict extra properties** with `@sealed` when records must not include attributes beyond those declared. By default, Harper allows additional properties.
87
+
88
+ ```graphql
89
+ type StrictRecord @table @sealed {
90
+ id: Long @primaryKey
91
+ name: String
92
+ }
93
+ ```
94
+
95
+ 8. **Configure expiration, eviction, and scan behavior** together when building caching tables. These three arguments control the full record lifecycle:
96
+ - `expiration` — record becomes stale; next request triggers a source fetch
97
+ - `eviction` — additional time after `expiration` before physical removal
98
+ - `scanInterval` — how often Harper scans for records to evict; clock-aligned, not startup-aligned
99
+
100
+ ## Examples
101
+
102
+ **Caching table with tuned expiration:**
103
+
104
+ ```graphql
105
+ # Expire after 5 minutes, evict after 1 hour, scan every 10 minutes
106
+ type WeatherCache @table(expiration: 300, eviction: 3300, scanInterval: 600) {
107
+ id: ID @primaryKey
108
+ temperature: Float
109
+ }
110
+ ```
111
+
112
+ **Table in a named database with expiration and an indexed field:**
113
+
114
+ ```graphql
115
+ type Event @table(database: "analytics", expiration: 86400) {
116
+ id: Long @primaryKey
117
+ name: String @indexed
118
+ }
119
+ ```
120
+
121
+ **Session cache with auto-expiry:**
122
+
123
+ ```graphql
124
+ type Session @table(expiration: 3600) {
125
+ id: Long @primaryKey
126
+ userId: String
127
+ }
51
128
  ```
52
129
 
53
- ### Why this is important:
130
+ **Table with audit timestamps:**
54
131
 
55
- 1. **Shared Directives**: It includes `@table`, `@primaryKey`, etc., so they aren't marked as "unknown directives".
56
- 2. **Context for Agents**: When an agent reads your project, seeing this config helps it locate the core Harper definitions, leading to more accurate code generation.
57
- 3. **Consistency**: The `npm create harper@latest` command includes this by default. Manually adding it to existing projects ensures they follow the same standards.
132
+ ```graphql
133
+ type Order @table @export(name: "orders") {
134
+ id: Long @primaryKey
135
+ createdAt: Long @createdTime
136
+ updatedAt: Long @updatedTime
137
+ status: String @indexed
138
+ }
139
+ ```
58
140
 
59
- ## Example Project Structure
141
+ **Overriding the table name and disabling replication:**
60
142
 
61
- A typical Harper project with proper schema tooling:
143
+ ```graphql
144
+ type Product @table(table: "products") {
145
+ id: Long @primaryKey
146
+ name: String
147
+ }
62
148
 
63
- ```text
64
- my-harper-app/
65
- ├── config.yaml
66
- ├── graphql.config.yml
67
- ├── package.json
68
- ├── schema.graphql
69
- └── resources.js
149
+ type LocalRecord @table(replicate: false) {
150
+ id: Long @primaryKey
151
+ value: String
152
+ }
70
153
  ```
154
+
155
+ ## Notes
156
+
157
+ - Use unique `database` names in plugins and applications to avoid table naming collisions, since all tables default to the `"data"` database.
158
+ - Eviction removes non-indexed record data but does **not** remove a record from its secondary indexes. Indexes remain functional for evicted records; Harper fetches the full record from the source on demand when a query matches an evicted record.
159
+ - `scanInterval` is clock-aligned to the server's local timezone. The server's startup time does not affect when eviction runs.
160
+ - If replication is disabled on a table and later re-enabled, it will not catch up on writes made while replication was disabled.
161
+ - Null values are indexed by `@indexed` fields, enabling queries such as `GET /Product/?category=null`.
@@ -2,33 +2,63 @@
2
2
  name: typescript-type-stripping
3
3
  description: How to run TypeScript files directly in Harper without a build step.
4
4
  metadata:
5
- mode: synthesized
5
+ mode: generate
6
+ sources:
7
+ - reference/v5/components/javascript-environment.md#TypeScript Support
8
+ sourceCommit: b7fbddadd42eb4487190b650a9abc4bcfeef5819
9
+ inputHash: 4e6bd8b610edd595
6
10
  ---
7
11
 
8
- # TypeScript Type Stripping
12
+ # TypeScript Type Stripping in Harper
9
13
 
10
- Instructions for the agent to follow when using TypeScript in Harper.
14
+ Instructions for the agent to run `.ts` files directly in Harper without a build step using Node.js's built-in type stripping.
11
15
 
12
16
  ## When to Use
13
17
 
14
- Use this skill when you want to write Harper Resources in TypeScript and have them execute directly in Node.js without an intermediate build or compilation step.
18
+ Apply this rule when writing Harper resource files in TypeScript. Use it any time you need to reference `.ts` source files from `config.yaml` or import between local TypeScript modules in a Harper project.
15
19
 
16
20
  ## How It Works
17
21
 
18
- 1. **Verify Node.js Version**: Ensure you are using Node.js v22.6.0 or higher.
19
- 2. **Name Files with `.ts`**: Create your resource files in the `resources/` directory with a `.ts` extension.
20
- 3. **Use TypeScript Syntax**: Write your resource classes using standard TypeScript (interfaces, types, etc.).
21
- ```typescript
22
- import { Resource } from 'harper';
23
- export class MyResource extends Resource {
24
- async get(): Promise<{ message: string }> {
25
- return { message: 'Running TS directly!' };
26
- }
27
- }
28
- ```
29
- 4. **Use Explicit Extensions in Imports**: When importing other local modules, include the `.ts` extension: `import { helper } from './helper.ts'`.
30
- 5. **Configure `config.yaml`**: Ensure `jsResource` points to your `.ts` files:
22
+ 1. **Ensure Node.js version**: Require Node.js 22.6 or later. Type stripping is unavailable on earlier versions.
23
+
24
+ 2. **Point `jsResource` at `.ts` files**: The `jsResource` plugin loads both `.js` and `.ts` files. Set its `files` glob in `config.yaml` to target your `.ts` source files:
25
+
31
26
  ```yaml
32
27
  jsResource:
33
28
  files: 'resources/*.ts'
34
29
  ```
30
+
31
+ 3. **Use explicit `.ts` extensions in local imports**: Node's loader does not resolve `'./helper'` to `'./helper.ts'`, so always include the full extension:
32
+
33
+ ```typescript
34
+ import { helper } from './helper.ts';
35
+ ```
36
+
37
+ 4. **Stay within type-stripping limits**: Only type annotations and declarations are removed. Do not use enums with runtime values, namespaces with runtime semantics, or any other features that require code transformation beyond type stripping.
38
+
39
+ ## Examples
40
+
41
+ A complete Harper resource written in TypeScript, using imports from the `harper` package:
42
+
43
+ ```typescript
44
+ import { type RequestTargetOrId, Resource, tables } from 'harper';
45
+
46
+ export class MyResource extends Resource {
47
+ async get(target?: RequestTargetOrId): Promise<{ message: string }> {
48
+ return { message: 'Hello from TS' };
49
+ }
50
+ }
51
+ ```
52
+
53
+ Paired `config.yaml` entry loading the file via `jsResource`:
54
+
55
+ ```yaml
56
+ jsResource:
57
+ files: 'resources/*.ts'
58
+ ```
59
+
60
+ ## Notes
61
+
62
+ - No build step or transpiler is required — Harper runs `.ts` files directly.
63
+ - Type imports (e.g., `import { type RequestTargetOrId }`) from the `harper` package work as usual.
64
+ - Unsupported TypeScript features include: enums with runtime values, namespaces with runtime semantics, and anything requiring code transformation beyond simple type stripping.
@@ -9,6 +9,9 @@
9
9
  # Phase 3 flips 7 obvious 1:1 rules to mode: generate (automatic-apis,
10
10
  # querying-rest-apis, real-time-apps, checking-authentication, logging,
11
11
  # deploying-to-harper-fabric, caching). All others remain synthesized.
12
+ # Phase 4 migrates schema-design-tooling and typescript-type-stripping to
13
+ # mode: generate. creating-harper-apps stays synthesized pending dedicated
14
+ # create-harper CLI documentation.
12
15
 
13
16
  rules:
14
17
  # ===========================================================================
@@ -27,7 +30,23 @@ rules:
27
30
  category: schema
28
31
  priority: 1
29
32
  order: 2
30
- mode: synthesized
33
+ mode: generate
34
+ sources:
35
+ - path: reference/v5/database/schema.md
36
+ section: 'Overview'
37
+ role: primary
38
+ - path: reference/v5/database/schema.md
39
+ section: 'Type Directives'
40
+ role: primary
41
+ - path: reference/v5/database/schema.md
42
+ section: 'Field Directives'
43
+ role: primary
44
+ must_cover:
45
+ - '@table'
46
+ - '@export'
47
+ - '@primaryKey'
48
+ - '@indexed'
49
+ - 'graphqlSchema'
31
50
 
32
51
  - rule: defining-relationships
33
52
  description: How to define and use relationships between tables in Harper using GraphQL.
@@ -178,7 +197,16 @@ rules:
178
197
  category: logic
179
198
  priority: 3
180
199
  order: 4
181
- mode: synthesized
200
+ mode: generate
201
+ sources:
202
+ - path: reference/v5/components/javascript-environment.md
203
+ section: 'TypeScript Support'
204
+ role: primary
205
+ must_cover:
206
+ - '.ts'
207
+ - 'jsResource'
208
+ - 'Node.js 22.6'
209
+ - 'type stripping'
182
210
 
183
211
  - rule: caching
184
212
  description: How to implement integrated data caching in Harper from external sources.
@@ -256,3 +284,19 @@ rules:
256
284
  - 'console.log'
257
285
  - 'logger'
258
286
  - 'withTag('
287
+
288
+ - rule: load-env
289
+ description: How to load environment variables from .env files into a Harper application using the loadEnv plugin.
290
+ category: ops
291
+ priority: 4
292
+ order: 6
293
+ mode: generate
294
+ sources:
295
+ - path: reference/v5/environment-variables/overview.md
296
+ role: primary
297
+ must_cover:
298
+ - 'loadEnv'
299
+ - 'files'
300
+ - 'process.env'
301
+ - 'override'
302
+ - 'config.yaml'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@harperfast/template-vue-ts-studio",
3
- "version": "1.6.4",
3
+ "version": "1.7.1",
4
4
  "type": "module",
5
5
  "repository": "github:HarperFast/create-harper",
6
6
  "scripts": {},
package/skills-lock.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "source": "harperfast/skills",
6
6
  "sourceType": "github",
7
7
  "skillPath": "harper-best-practices/SKILL.md",
8
- "computedHash": "ec4a4a4e9f20599d3204e5d34cdebb0b1e6b78e89fdcb2542e9e15d6e0e3ae47"
8
+ "computedHash": "921b0848ec9f7ee375fec2d4191c99325e1d7160c0ab463832b3e0443e80576a"
9
9
  }
10
10
  }
11
11
  }