@harperfast/template-vue-ts-studio 1.8.2 → 1.9.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.
- package/.agents/skills/harper-best-practices/AGENTS.md +16 -12
- package/.agents/skills/harper-best-practices/rules/custom-resources.md +5 -4
- package/.agents/skills/harper-best-practices/rules/extending-tables.md +11 -8
- package/agent/skills/harper-best-practices/AGENTS.md +1950 -0
- package/agent/skills/harper-best-practices/SKILL.md +96 -0
- package/agent/skills/harper-best-practices/rules/adding-tables-with-schemas.md +42 -0
- package/agent/skills/harper-best-practices/rules/automatic-apis.md +165 -0
- package/agent/skills/harper-best-practices/rules/caching.md +163 -0
- package/agent/skills/harper-best-practices/rules/checking-authentication.md +190 -0
- package/agent/skills/harper-best-practices/rules/creating-a-fabric-account-and-cluster.md +30 -0
- package/agent/skills/harper-best-practices/rules/creating-harper-apps.md +54 -0
- package/agent/skills/harper-best-practices/rules/custom-resources.md +44 -0
- package/agent/skills/harper-best-practices/rules/defining-relationships.md +35 -0
- package/agent/skills/harper-best-practices/rules/deploying-to-harper-fabric.md +122 -0
- package/agent/skills/harper-best-practices/rules/extending-tables.md +46 -0
- package/agent/skills/harper-best-practices/rules/handling-binary-data.md +45 -0
- package/agent/skills/harper-best-practices/rules/load-env.md +111 -0
- package/agent/skills/harper-best-practices/rules/logging.md +169 -0
- package/agent/skills/harper-best-practices/rules/programmatic-table-requests.md +134 -0
- package/agent/skills/harper-best-practices/rules/querying-rest-apis.md +202 -0
- package/agent/skills/harper-best-practices/rules/real-time-apps.md +102 -0
- package/agent/skills/harper-best-practices/rules/schema-design-tooling.md +161 -0
- package/agent/skills/harper-best-practices/rules/serving-web-content.md +85 -0
- package/agent/skills/harper-best-practices/rules/typescript-type-stripping.md +64 -0
- package/agent/skills/harper-best-practices/rules/using-blob-datatype.md +38 -0
- package/agent/skills/harper-best-practices/rules/vector-indexing.md +124 -0
- package/agent/skills/harper-best-practices/rules.manifest.yaml +302 -0
- package/package.json +1 -1
- package/skills-lock.json +1 -1
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: creating-harper-apps
|
|
3
|
+
description: How to initialize a new Harper application using the CLI.
|
|
4
|
+
metadata:
|
|
5
|
+
mode: synthesized
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Creating Harper Applications
|
|
9
|
+
|
|
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.
|
|
13
|
+
|
|
14
|
+
## When to Use
|
|
15
|
+
|
|
16
|
+
Use this command when starting a new Harper application or adding a new Harper microservice to an
|
|
17
|
+
existing architecture.
|
|
18
|
+
|
|
19
|
+
## Commands
|
|
20
|
+
|
|
21
|
+
Initialize a project using your preferred package manager:
|
|
22
|
+
|
|
23
|
+
### NPM
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm create harper@latest
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### PNPM
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pnpm create harper@latest
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Bun
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
bun create harper@latest
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Options
|
|
42
|
+
|
|
43
|
+
You can specify the project name and template directly:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm create harper@latest my-app --template default
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Next Steps
|
|
50
|
+
|
|
51
|
+
1. **Configure Environment**: Set up your `.env` file with local or cloud credentials.
|
|
52
|
+
2. **Define Schema**: Modify `schema.graphql` to fit your application's data model.
|
|
53
|
+
3. **Start Development**: Run `npm run dev` to start the local Harper instance.
|
|
54
|
+
4. **Deploy**: Use `npm run deploy` to push your application to Harper Fabric.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: custom-resources
|
|
3
|
+
description: How to define custom REST endpoints with JavaScript or TypeScript in Harper.
|
|
4
|
+
metadata:
|
|
5
|
+
mode: synthesized
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Custom Resources
|
|
9
|
+
|
|
10
|
+
Instructions for the agent to follow when creating custom resources in Harper.
|
|
11
|
+
|
|
12
|
+
## When to Use
|
|
13
|
+
|
|
14
|
+
Use this skill when the automatic CRUD operations provided by `@table @export` are insufficient, and you need custom logic, third-party API integration, or specialized data handling for your REST endpoints.
|
|
15
|
+
|
|
16
|
+
## How It Works
|
|
17
|
+
|
|
18
|
+
1. **Check if a Custom Resource is Necessary**: Verify if [Automatic APIs](./automatic-apis.md) or [Extending Tables](./extending-tables.md) can satisfy the requirement first.
|
|
19
|
+
2. **Create the Resource File**: Create a `.ts` or `.js` file in the directory specified by `jsResource` in `config.yaml` (typically `resources/`).
|
|
20
|
+
3. **Define the Resource Class**: Export a class extending `Resource` from `harper` and define **static** methods for the HTTP verbs you handle. In Harper 5 the static methods are the HTTP handlers (mapped 1:1 to verbs); they receive a pre-parsed `RequestTarget`, and write handlers also receive the request body as an awaitable `data` argument:
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import { Resource } from 'harper';
|
|
24
|
+
|
|
25
|
+
export class MyResource extends Resource {
|
|
26
|
+
// v5 handlers are static and map 1:1 to HTTP verbs.
|
|
27
|
+
static async get(target: any) {
|
|
28
|
+
return { message: 'Hello from custom GET!' };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
4. **Implement HTTP Methods**: Add static methods (`get`, `post`, `put`, `patch`, or `delete`) to handle the corresponding requests. Read/delete handlers receive `(target)`; write handlers receive `(target, data)` where `data` is awaitable.
|
|
34
|
+
5. **Route Nesting and Naming**: You can control the URL structure by how you export your resources:
|
|
35
|
+
- **Direct Class Export**: `export class Foo extends Resource` creates endpoints at `/Foo/`. Class names are case-sensitive in the URL.
|
|
36
|
+
- **Nested Objects**: `export const Bar = { Foo };` creates endpoints at `/Bar/Foo/`.
|
|
37
|
+
- **Lowercase and Hyphens**: Use object keys to define custom paths: `export const bar = { 'foo-baz': Foo };` exposes endpoints at `/bar/foo-baz/`.
|
|
38
|
+
6. **Access Tables (Optional)**: Import and use the `tables` object to interact with your data:
|
|
39
|
+
```typescript
|
|
40
|
+
import { tables } from 'harper';
|
|
41
|
+
// ... inside a method
|
|
42
|
+
const results = await tables.MyTable.list();
|
|
43
|
+
```
|
|
44
|
+
7. **Configure Loading**: Ensure `config.yaml` points to your resource files (e.g., `jsResource: { files: 'resources/*.ts' }`).
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: defining-relationships
|
|
3
|
+
description: How to define and use relationships between tables in Harper using GraphQL.
|
|
4
|
+
metadata:
|
|
5
|
+
mode: synthesized
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Defining Relationships
|
|
9
|
+
|
|
10
|
+
Instructions for the agent to follow when defining relationships between Harper tables.
|
|
11
|
+
|
|
12
|
+
## When to Use
|
|
13
|
+
|
|
14
|
+
Use this skill when you need to link data across different tables, enabling automatic joins and efficient related-data fetching via REST APIs.
|
|
15
|
+
|
|
16
|
+
## How It Works
|
|
17
|
+
|
|
18
|
+
1. **Identify the Relationship Type**: Determine if it's one-to-one, many-to-one, or one-to-many.
|
|
19
|
+
2. **Use the `@relationship` Directive**: Apply it to a field in your GraphQL schema.
|
|
20
|
+
- **Many-to-One (Current table holds FK)**: Use `from`.
|
|
21
|
+
```graphql
|
|
22
|
+
type Book @table @export {
|
|
23
|
+
authorId: ID
|
|
24
|
+
author: Author @relationship(from: "authorId")
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
- **One-to-Many (Related table holds FK)**: Use `to` and an array type.
|
|
28
|
+
```graphql
|
|
29
|
+
type Author @table @export {
|
|
30
|
+
books: [Book] @relationship(to: "authorId")
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
3. **Query with Relationships**: Use dot syntax in REST API calls for filtering or the `select()` operator for including related data.
|
|
34
|
+
- Example Filter: `GET /Book/?author.name=Harper`
|
|
35
|
+
- Example Select: `GET /Author/?select(name,books(title))`
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: deploying-to-harper-fabric
|
|
3
|
+
description: How to deploy a Harper application to the Harper Fabric cloud.
|
|
4
|
+
metadata:
|
|
5
|
+
mode: generate
|
|
6
|
+
sources:
|
|
7
|
+
- reference/v5/components/applications.md#Remote Management
|
|
8
|
+
- >-
|
|
9
|
+
fabric/cluster-creation-management.md#Connecting the Harper CLI to a
|
|
10
|
+
Cluster
|
|
11
|
+
sourceCommit: b7fbddadd42eb4487190b650a9abc4bcfeef5819
|
|
12
|
+
inputHash: ccdefbbf8f3b8657
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Deploying to Harper Fabric
|
|
16
|
+
|
|
17
|
+
Instructions for the agent to follow when deploying a Harper application to the Harper Fabric cloud using the Harper CLI.
|
|
18
|
+
|
|
19
|
+
## When to Use
|
|
20
|
+
|
|
21
|
+
Apply this rule when deploying a Harper application to a remote Harper instance or Harper Fabric cluster. This covers interactive deployments, CI/CD pipelines, and any scenario where the agent must push a local or remote package to a target environment.
|
|
22
|
+
|
|
23
|
+
## How It Works
|
|
24
|
+
|
|
25
|
+
1. **Authenticate with the remote target**: Run `harper login` once to store an authentication token. The CLI writes `HARPER_CLI_TARGET` to a local `.env` so subsequent commands do not need credentials repeated. Find the **Application URL** on the cluster's **Config → Overview** page (see [creating-a-fabric-account-and-cluster.md](creating-a-fabric-account-and-cluster.md)).
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
harper login <Application URL>
|
|
29
|
+
# Provide cluster username and password when prompted
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
2. **Deploy the application**: Run `harper deploy` with the required parameters. After logging in, no credentials are needed inline.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
harper deploy \
|
|
36
|
+
project=<name> \
|
|
37
|
+
package=<package> \
|
|
38
|
+
target=<remote> \
|
|
39
|
+
restart=true \
|
|
40
|
+
replicated=true
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
3. **Choose a package source**: Set the `package` parameter to any valid npm dependency value, or omit it to package and deploy the current local directory.
|
|
44
|
+
|
|
45
|
+
| Value | Effect |
|
|
46
|
+
| ---------------------------------------------------- | ------------------------------------------------ |
|
|
47
|
+
| _(omitted)_ | Packages and deploys the current local directory |
|
|
48
|
+
| `"@harperdb/status-check"` | npm package |
|
|
49
|
+
| `"HarperDB/status-check"` | GitHub repo (short form) |
|
|
50
|
+
| `"https://github.com/HarperDB/status-check"` | GitHub repo (full URL) |
|
|
51
|
+
| `"git+ssh://git@github.com:HarperDB/secret-app.git"` | Private repo via SSH |
|
|
52
|
+
| `"https://example.com/application.tar.gz"` | Remote tarball |
|
|
53
|
+
|
|
54
|
+
For git tags, use the `semver` directive for reliable versioning:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
HarperDB/application-template#semver:v1.0.0
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
4. **Authenticate for CI/CD pipelines**: Use environment variables instead of interactive login. Set credentials before running `harper deploy`.
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
export HARPER_CLI_USERNAME=<username>
|
|
64
|
+
export HARPER_CLI_PASSWORD=<password>
|
|
65
|
+
harper deploy \
|
|
66
|
+
project=<name> \
|
|
67
|
+
package=<package> \
|
|
68
|
+
target=<remote> \
|
|
69
|
+
restart=true \
|
|
70
|
+
replicated=true
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
5. **Register SSH keys for private repos**: Before deploying from an SSH-based private repository, use the Add SSH Key operation to register the key with the remote instance.
|
|
74
|
+
|
|
75
|
+
## Examples
|
|
76
|
+
|
|
77
|
+
**Interactive login then deploy (recommended):**
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# Log in once
|
|
81
|
+
harper login <remote>
|
|
82
|
+
# Provide your username and password when prompted
|
|
83
|
+
|
|
84
|
+
# Subsequently deploy without credentials
|
|
85
|
+
harper deploy \
|
|
86
|
+
project=<name> \
|
|
87
|
+
package=<package> \
|
|
88
|
+
target=<remote> \
|
|
89
|
+
restart=true \
|
|
90
|
+
replicated=true
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Deploy with inline credentials (not recommended for production):**
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
harper deploy \
|
|
97
|
+
project=<name> \
|
|
98
|
+
package=<package> \
|
|
99
|
+
username=<username> \
|
|
100
|
+
password=<password> \
|
|
101
|
+
target=<remote> \
|
|
102
|
+
restart=true \
|
|
103
|
+
replicated=true
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Deploy a specific GitHub release by semver tag:**
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
harper deploy \
|
|
110
|
+
project=my-app \
|
|
111
|
+
package="HarperDB/application-template#semver:v1.0.0" \
|
|
112
|
+
target=<remote> \
|
|
113
|
+
restart=true \
|
|
114
|
+
replicated=true
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Notes
|
|
118
|
+
|
|
119
|
+
- Always prefer `harper login` for interactive use and environment variables (`HARPER_CLI_USERNAME`, `HARPER_CLI_PASSWORD`) for CI/CD. Avoid inline `username`/`password` parameters in production.
|
|
120
|
+
- Omitting `package` causes the CLI to package the current local directory. Specifying a local file path creates a symlink, so changes are picked up between restarts without redeploying.
|
|
121
|
+
- Harper generates a `package.json` from component configurations and resolves dependencies using a form of `npm install`.
|
|
122
|
+
- For SSH-based private repos, register keys with the Add SSH Key operation before deploying.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: extending-tables
|
|
3
|
+
description: How to add custom logic to automatically generated table resources in Harper.
|
|
4
|
+
metadata:
|
|
5
|
+
mode: synthesized
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Extending Tables
|
|
9
|
+
|
|
10
|
+
Instructions for the agent to follow when extending table resources in Harper.
|
|
11
|
+
|
|
12
|
+
## When to Use
|
|
13
|
+
|
|
14
|
+
Use this skill when you need to add custom validation, side effects (like webhooks), data transformation, or custom access control to the standard CRUD operations of a Harper table.
|
|
15
|
+
|
|
16
|
+
## How It Works
|
|
17
|
+
|
|
18
|
+
1. **Define the Table in GraphQL**: In your `.graphql` schema, define the table using the `@table` directive. **Do not** use `@export` if you plan to extend it.
|
|
19
|
+
```graphql
|
|
20
|
+
type MyTable @table {
|
|
21
|
+
id: ID @primaryKey
|
|
22
|
+
name: String
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
2. **Create the Extension File**: Create a `.ts` file in your `resources/` directory.
|
|
26
|
+
3. **Extend the Table Resource**: Export a class that extends `tables.YourTableName` and override the relevant **static** methods. In Harper 5 resource handlers are static and map 1:1 to HTTP verbs: `get(target)`, `post(target, data)`, `put(target, data)`, `patch(target, data)`, `delete(target)`. `target` is a pre-parsed `RequestTarget`; for writes, `data` is the request body and is **awaitable** (`await data`). Delegate to `super` to keep Harper's default behavior — a collection create passes just the record (`super.post(record)`), updates pass the target (`super.put(target, data)` / `super.patch(target, data)`), and reads/deletes pass the target (`super.get(target)`). To return a specific HTTP status from a thrown error, set **`.statusCode`** (e.g. `400`) on the error — a plain `.status` property is ignored.
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import { tables } from 'harper';
|
|
30
|
+
|
|
31
|
+
export class MyTable extends tables.MyTable {
|
|
32
|
+
// Static handler; receives (target, data) — data is awaitable.
|
|
33
|
+
static async post(target: any, data: any) {
|
|
34
|
+
const record = await data;
|
|
35
|
+
if (!record?.name) {
|
|
36
|
+
const error: any = new Error('Name is required');
|
|
37
|
+
error.statusCode = 400; // HTTP status (use statusCode, NOT status)
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
return super.post(record); // create delegates with the record (no id)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
4. **Override Methods**: Override the static `get`, `post`, `put`, `patch`, or `delete` as needed, delegating to `super.<method>` (see the argument forms above) to preserve Harper's default behavior unless you intend to replace it entirely.
|
|
46
|
+
5. **Implement Logic**: Use overrides for validation, side effects, or transforming data before/after database operations.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: handling-binary-data
|
|
3
|
+
description: How to store and serve binary data like images or audio in Harper.
|
|
4
|
+
metadata:
|
|
5
|
+
mode: synthesized
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Handling Binary Data
|
|
9
|
+
|
|
10
|
+
Instructions for the agent to follow when handling binary data in Harper.
|
|
11
|
+
|
|
12
|
+
## When to Use
|
|
13
|
+
|
|
14
|
+
Use this skill when you need to store binary files (images, audio, etc.) in the database or serve them back to clients via REST endpoints.
|
|
15
|
+
|
|
16
|
+
## How It Works
|
|
17
|
+
|
|
18
|
+
1. **Store Binary Data**: In your resource's `post` or `put` method, convert incoming data to Buffers and then to Blobs using `createBlob` from Harper's globals. Include the MIME type if available:
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
async post(target, record) {
|
|
22
|
+
if (record.data) {
|
|
23
|
+
record.data = createBlob(Buffer.from(record.data, record.encoding || 'base64'), {
|
|
24
|
+
type: record.contentType || 'application/octet-stream',
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
return super.post(target, record);
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
2. **Serve Binary Data**: In your resource's `get` method, return a response object with the appropriate `Content-Type` and the binary data in the `body`:
|
|
32
|
+
```typescript
|
|
33
|
+
async get(target) {
|
|
34
|
+
const record = await super.get(target);
|
|
35
|
+
if (record?.data) {
|
|
36
|
+
return {
|
|
37
|
+
status: 200,
|
|
38
|
+
headers: { 'Content-Type': record.data.type || 'application/octet-stream' },
|
|
39
|
+
body: record.data,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return record;
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
3. **Use the Blob Type**: Ensure your GraphQL schema uses the `Blob` scalar for binary fields.
|
|
@@ -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.
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: logging
|
|
3
|
+
description: >-
|
|
4
|
+
Best practices for logging in Harper, including console capture, the granular
|
|
5
|
+
logger interface, and programmatic log retrieval.
|
|
6
|
+
metadata:
|
|
7
|
+
mode: generate
|
|
8
|
+
sources:
|
|
9
|
+
- reference/v5/logging/overview.md
|
|
10
|
+
- reference/v5/logging/api.md
|
|
11
|
+
sourceCommit: b7fbddadd42eb4487190b650a9abc4bcfeef5819
|
|
12
|
+
inputHash: 46cd384598304e3b
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Harper Logging
|
|
16
|
+
|
|
17
|
+
Instructions for the agent to follow when implementing logging in Harper applications, including direct logger usage, tagged loggers, and console capture behavior.
|
|
18
|
+
|
|
19
|
+
## When to Use
|
|
20
|
+
|
|
21
|
+
Apply this rule when writing any JavaScript component, plugin, or resource that needs to emit structured log entries, filter logs by component, or capture existing `console.log` output into Harper's log system. Use it whenever you need to understand log levels, log entry format, or the `logger` global API.
|
|
22
|
+
|
|
23
|
+
## How It Works
|
|
24
|
+
|
|
25
|
+
1. **Use the `logger` global directly** — `logger` is available in all JavaScript components without any imports. Call the method matching the desired severity level:
|
|
26
|
+
|
|
27
|
+
```javascript
|
|
28
|
+
logger.trace('detailed trace message');
|
|
29
|
+
logger.debug('debug info', { someContext: 'value' });
|
|
30
|
+
logger.info('informational message');
|
|
31
|
+
logger.warn('potential issue');
|
|
32
|
+
logger.error('error occurred', error);
|
|
33
|
+
logger.fatal('fatal error');
|
|
34
|
+
logger.notify('server is ready');
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Only entries at or above the configured `logging.level` (or `logging.external.level`) are written to `hdb.log`.
|
|
38
|
+
|
|
39
|
+
2. **Create a tagged logger with `withTag(`** — Call `logger.withTag(tag)` once per module or class to get a `TaggedLogger` scoped to that tag. This prefixes every log entry with the tag, making log output filterable by component.
|
|
40
|
+
|
|
41
|
+
```javascript
|
|
42
|
+
const log = logger.withTag('my-resource');
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Because `TaggedLogger` methods for disabled levels are `null`, always use optional chaining (`?.`) when calling them:
|
|
46
|
+
|
|
47
|
+
```javascript
|
|
48
|
+
log.debug?.('Fetching record', { id });
|
|
49
|
+
log.warn?.('Record not found', { id });
|
|
50
|
+
log.error?.('Failed to update record', err);
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`TaggedLogger` does not have a `withTag()` method.
|
|
54
|
+
|
|
55
|
+
3. **Understand the interface contracts** — `MainLogger` always has all methods defined:
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
interface MainLogger {
|
|
59
|
+
trace(...messages: any[]): void;
|
|
60
|
+
debug(...messages: any[]): void;
|
|
61
|
+
info(...messages: any[]): void;
|
|
62
|
+
warn(...messages: any[]): void;
|
|
63
|
+
error(...messages: any[]): void;
|
|
64
|
+
fatal(...messages: any[]): void;
|
|
65
|
+
notify(...messages: any[]): void;
|
|
66
|
+
withTag(tag: string): TaggedLogger;
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`TaggedLogger` methods may be `null`:
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
interface TaggedLogger {
|
|
74
|
+
trace: ((...messages: any[]) => void) | null;
|
|
75
|
+
debug: ((...messages: any[]) => void) | null;
|
|
76
|
+
info: ((...messages: any[]) => void) | null;
|
|
77
|
+
warn: ((...messages: any[]) => void) | null;
|
|
78
|
+
error: ((...messages: any[]) => void) | null;
|
|
79
|
+
fatal: ((...messages: any[]) => void) | null;
|
|
80
|
+
notify: ((...messages: any[]) => void) | null;
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
4. **Know the log levels** — From least to most severe:
|
|
85
|
+
|
|
86
|
+
| Level | Description |
|
|
87
|
+
| -------- | -------------------------------------------------------------------- |
|
|
88
|
+
| `trace` | Highly detailed internal execution tracing. |
|
|
89
|
+
| `debug` | Diagnostic information useful during development. |
|
|
90
|
+
| `info` | General operational events. |
|
|
91
|
+
| `warn` | Potential issues that don't prevent normal operation. |
|
|
92
|
+
| `error` | Errors that affect specific operations. |
|
|
93
|
+
| `fatal` | Critical errors causing process termination. |
|
|
94
|
+
| `notify` | Important operational milestones. Always logged regardless of level. |
|
|
95
|
+
|
|
96
|
+
The default log level is `warn`. Setting a level includes that level and all more-severe levels.
|
|
97
|
+
|
|
98
|
+
5. **Enable console capture when porting existing code** — When `logging.console: true` is set, writes via `console.log`, `console.warn`, `console.error`, etc. are appended verbatim to `hdb.log`. Captured lines do **not** pass through `logger`'s level filter. Prefer `logger` directly in production code so that level filtering and tagging apply. Console capture is intended as a convenience for porting existing code and for debugging.
|
|
99
|
+
|
|
100
|
+
6. **Know where logs are written** — All standard log output goes to `<ROOTPATH>/log/hdb.log` (default: `~/hdb/log/hdb.log`). To also log to `stdout`/`stderr`, set `logging.stdStreams: true`.
|
|
101
|
+
|
|
102
|
+
## Examples
|
|
103
|
+
|
|
104
|
+
### Basic logging in a resource
|
|
105
|
+
|
|
106
|
+
```javascript
|
|
107
|
+
export class MyResource extends Resource {
|
|
108
|
+
async get(id) {
|
|
109
|
+
logger.debug('Fetching record', { id });
|
|
110
|
+
const record = await super.get(id);
|
|
111
|
+
if (!record) {
|
|
112
|
+
logger.warn('Record not found', { id });
|
|
113
|
+
}
|
|
114
|
+
return record;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async put(record) {
|
|
118
|
+
logger.info('Updating record', { id: record.id });
|
|
119
|
+
try {
|
|
120
|
+
return await super.put(record);
|
|
121
|
+
} catch (err) {
|
|
122
|
+
logger.error('Failed to update record', err);
|
|
123
|
+
throw err;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Tagged logging with `withTag()`
|
|
130
|
+
|
|
131
|
+
```javascript
|
|
132
|
+
const log = logger.withTag('my-resource');
|
|
133
|
+
|
|
134
|
+
export class MyResource extends Resource {
|
|
135
|
+
async get(id) {
|
|
136
|
+
log.debug?.('Fetching record', { id });
|
|
137
|
+
const record = await super.get(id);
|
|
138
|
+
if (!record) {
|
|
139
|
+
log.warn?.('Record not found', { id });
|
|
140
|
+
}
|
|
141
|
+
return record;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async put(record) {
|
|
145
|
+
log.info?.('Updating record', { id: record.id });
|
|
146
|
+
try {
|
|
147
|
+
return await super.put(record);
|
|
148
|
+
} catch (err) {
|
|
149
|
+
log.error?.('Failed to update record', err);
|
|
150
|
+
throw err;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Tagged entries appear in `hdb.log` with the tag in the header:
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
2023-03-09T14:25:05.269Z [info] [my-resource]: Updating record
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Notes
|
|
163
|
+
|
|
164
|
+
- All log output is written to `<ROOTPATH>/log/hdb.log`. The `logger` global writes to this file at the configured `logging.external` level.
|
|
165
|
+
- Log entry format for `logger`: `<timestamp> [<level>] [<thread>/<id>]: <message>`
|
|
166
|
+
- Log entry format for `TaggedLogger`: `<timestamp> [<level>] [<tag>]: <message>`
|
|
167
|
+
- `console.log` output is only forwarded to `hdb.log` when `logging.console: true` is explicitly set; it is not forwarded by default.
|
|
168
|
+
- When logging to standard streams, run Harper in the foreground (`harper`, not `harper start`).
|
|
169
|
+
- `TaggedLogger` is bound to the configured log level at creation time — always use `?.` on its methods.
|