@harperfast/template-vue-ts-studio 1.6.4 → 1.7.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.
@@ -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
+
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
+
51
+ #### How It Works
52
+
53
+ 1. **Create a GraphQL schema file** with Harper-specific directives. Name it (e.g., `schema.graphql`) and place it in your component directory.
48
54
 
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:
55
+ ```graphql
56
+ type Dog @table {
57
+ id: Long @primaryKey
58
+ name: String
59
+ breed: String
60
+ age: Int
61
+ }
62
+
63
+ type Breed @table {
64
+ id: Long @primaryKey
65
+ name: String @indexed
66
+ }
67
+ ```
68
+
69
+ 2. **Register the schema in `config.yaml`** using the `graphqlSchema` plugin key:
70
+
71
+ ```yaml
72
+ graphqlSchema:
73
+ files: 'schema.graphql'
74
+ ```
50
75
 
51
- ##### Table Definition
76
+ Both plugins and applications can specify schemas this way.
52
77
 
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).
78
+ 3. **Mark every table type with `@table`**. The type name becomes the table name by default. Use optional arguments to override behavior:
56
79
 
57
- ##### Attribute Constraints & Indexing
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 |
58
88
 
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.
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
62
92
 
63
- ##### Relationships
93
+ Prefer `Long` or `Any` for auto-generated numeric keys; `Int` is 32-bit and may be insufficient for large tables.
64
94
 
65
- - `@relationship(from: String)`: Defines a relationship to another table. `from` specifies the local field holding the foreign key.
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.
66
96
 
67
- ##### Authentication & Authorization
97
+ ```graphql
98
+ type Product @table {
99
+ id: Long @primaryKey
100
+ category: String @indexed
101
+ price: Float @indexed
102
+ }
103
+ ```
68
104
 
69
- - `@auth(role: String)`: Restricts access to a table or field based on user roles.
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.
70
106
 
71
- #### Configuring GraphQL Tooling
107
+ ```graphql
108
+ type MyTable @table @export(name: "my-table") {
109
+ id: Long @primaryKey
110
+ }
111
+ ```
72
112
 
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.
113
+ 7. **Restrict extra properties** with `@sealed` when records must not include attributes beyond those declared. By default, Harper allows additional properties.
74
114
 
75
- This file tells GraphQL tools where to find Harper's built-in types and directives alongside your own schema files.
115
+ ```graphql
116
+ type StrictRecord @table @sealed {
117
+ id: Long @primaryKey
118
+ name: String
119
+ }
120
+ ```
76
121
 
77
- ##### Creating `graphql.config.yml`
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
78
126
 
79
- Create a file named `graphql.config.yml` in your project root with the following content:
127
+ #### Examples
80
128
 
81
- ```yaml
82
- schema:
83
- - 'node_modules/harper/schema.graphql'
84
- - 'schema.graphql'
85
- - 'schemas/*.graphql'
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:**
140
+
141
+ ```graphql
142
+ type Event @table(database: "analytics", expiration: 86400) {
143
+ id: Long @primaryKey
144
+ name: String @indexed
145
+ }
146
+ ```
89
147
 
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.
148
+ **Session cache with auto-expiry:**
149
+
150
+ ```graphql
151
+ type Session @table(expiration: 3600) {
152
+ id: Long @primaryKey
153
+ userId: String
154
+ }
155
+ ```
156
+
157
+ **Table with audit timestamps:**
158
+
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
+ }
166
+ ```
93
167
 
94
- #### Example Project Structure
168
+ **Overriding the table name and disabling replication:**
95
169
 
96
- A typical Harper project with proper schema tooling:
170
+ ```graphql
171
+ type Product @table(table: "products") {
172
+ id: Long @primaryKey
173
+ name: String
174
+ }
97
175
 
98
- ```text
99
- my-harper-app/
100
- ├── config.yaml
101
- ├── graphql.config.yml
102
- ├── package.json
103
- ├── schema.graphql
104
- └── resources.js
176
+ type LocalRecord @table(replicate: false) {
177
+ id: Long @primaryKey
178
+ value: String
179
+ }
105
180
  ```
106
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,91 @@ 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 you need to configure `loadEnv` in `config.yaml`, control load order, handle multiple files, or manage override behavior.
1837
+
1838
+ #### How It Works
1839
+
1840
+ 1. **Declare `loadEnv` in `config.yaml`**: Add `loadEnv` to your `config.yaml` with a `files` key pointing to the `.env` file. `loadEnv` is built into Harper and does not need to be installed separately.
1841
+
1842
+ ```yaml
1843
+ loadEnv:
1844
+ files: '.env'
1845
+ ```
1846
+
1847
+ This loads the specified file from the root of your component directory into `process.env`.
1848
+
1849
+ 2. **Place `loadEnv` first**: Always declare `loadEnv` before any other components in `config.yaml` so environment variables are available before dependent components start. Because Harper is single-process, variables loaded onto `process.env` are shared across all components.
1850
+
1851
+ ```yaml
1852
+ # config.yaml — loadEnv must come first
1853
+ loadEnv:
1854
+ files: '.env'
1855
+
1856
+ rest: true
1857
+
1858
+ myApp:
1859
+ files: './src/*.js'
1860
+ ```
1861
+
1862
+ 3. **Control override behavior**: By default, existing shell or container environment variables take precedence over values in `.env` files. To force `.env` values to overwrite existing variables, set `override: true`.
1863
+
1864
+ ```yaml
1865
+ loadEnv:
1866
+ files: '.env'
1867
+ override: true
1868
+ ```
1869
+
1870
+ 4. **Load multiple files**: Provide a list of files or a glob pattern under `files`. Files are loaded in the order specified.
1871
+ ```yaml
1872
+ loadEnv:
1873
+ files:
1874
+ - '.env'
1875
+ - '.env.local'
1876
+ ```
1877
+ Or using a glob pattern:
1878
+ ```yaml
1879
+ loadEnv:
1880
+ files: 'env-vars/*'
1881
+ ```
1882
+
1883
+ #### Examples
1884
+
1885
+ A complete `config.yaml` using `loadEnv` with multiple files and override enabled:
1886
+
1887
+ ```yaml
1888
+ # config.yaml — loadEnv must come first
1889
+ loadEnv:
1890
+ files:
1891
+ - '.env'
1892
+ - '.env.local'
1893
+ override: true
1894
+
1895
+ rest: true
1896
+
1897
+ myApp:
1898
+ files: './src/*.js'
1899
+ ```
1900
+
1901
+ A minimal setup loading a single `.env` file:
1902
+
1903
+ ```yaml
1904
+ loadEnv:
1905
+ files: '.env'
1906
+
1907
+ myApp:
1908
+ files: './src/*.js'
1909
+ ```
1910
+
1911
+ #### Notes
1912
+
1913
+ - `loadEnv` is built into Harper — declare it in `config.yaml` only; do not install it as a separate package.
1914
+ - The `files` value accepts either a single string, a list of strings, or a glob pattern.
1915
+ - Without `override: true`, variables already present in the environment are never overwritten by values in `.env` files.
1916
+ - `process.env` is shared across all Harper components in the same process, so load order in `config.yaml` determines availability.
@@ -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,100 @@
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: b7fbddadd42eb4487190b650a9abc4bcfeef5819
11
+ inputHash: c73a0caf28a2b833
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 you need to configure `loadEnv` in `config.yaml`, control load order, handle multiple files, or manage override behavior.
21
+
22
+ ## How It Works
23
+
24
+ 1. **Declare `loadEnv` in `config.yaml`**: Add `loadEnv` to your `config.yaml` with a `files` key pointing to the `.env` file. `loadEnv` is built into Harper and does not need to be installed separately.
25
+
26
+ ```yaml
27
+ loadEnv:
28
+ files: '.env'
29
+ ```
30
+
31
+ This loads the specified file from the root of your component directory into `process.env`.
32
+
33
+ 2. **Place `loadEnv` first**: Always declare `loadEnv` before any other components in `config.yaml` so environment variables are available before dependent components start. Because Harper is single-process, variables loaded onto `process.env` are shared across all components.
34
+
35
+ ```yaml
36
+ # config.yaml — loadEnv must come first
37
+ loadEnv:
38
+ files: '.env'
39
+
40
+ rest: true
41
+
42
+ myApp:
43
+ files: './src/*.js'
44
+ ```
45
+
46
+ 3. **Control override behavior**: By default, existing shell or container environment variables take precedence over values in `.env` files. To force `.env` values to overwrite existing variables, set `override: true`.
47
+
48
+ ```yaml
49
+ loadEnv:
50
+ files: '.env'
51
+ override: true
52
+ ```
53
+
54
+ 4. **Load multiple files**: Provide a list of files or a glob pattern under `files`. Files are loaded in the order specified.
55
+ ```yaml
56
+ loadEnv:
57
+ files:
58
+ - '.env'
59
+ - '.env.local'
60
+ ```
61
+ Or using a glob pattern:
62
+ ```yaml
63
+ loadEnv:
64
+ files: 'env-vars/*'
65
+ ```
66
+
67
+ ## Examples
68
+
69
+ A complete `config.yaml` using `loadEnv` with multiple files and override enabled:
70
+
71
+ ```yaml
72
+ # config.yaml — loadEnv must come first
73
+ loadEnv:
74
+ files:
75
+ - '.env'
76
+ - '.env.local'
77
+ override: true
78
+
79
+ rest: true
80
+
81
+ myApp:
82
+ files: './src/*.js'
83
+ ```
84
+
85
+ A minimal setup loading a single `.env` file:
86
+
87
+ ```yaml
88
+ loadEnv:
89
+ files: '.env'
90
+
91
+ myApp:
92
+ files: './src/*.js'
93
+ ```
94
+
95
+ ## Notes
96
+
97
+ - `loadEnv` is built into Harper — declare it in `config.yaml` only; do not install it as a separate package.
98
+ - The `files` value accepts either a single string, a list of strings, or a glob pattern.
99
+ - Without `override: true`, variables already present in the environment are never overwritten by values in `.env` files.
100
+ - `process.env` is shared across all Harper components in the same process, so load order in `config.yaml` determines availability.
@@ -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.0",
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": "95a41a7ba907538a69fc52b31399db843b403b617cc6705d9e54ee2c0b7af502"
9
9
  }
10
10
  }
11
11
  }