@harperfast/template-vue-ts-studio 1.12.11 → 1.13.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.
@@ -7,8 +7,8 @@ metadata:
7
7
  - reference/v5/resources/overview.md#Custom External Data Source
8
8
  - reference/v5/resources/overview.md#Exporting Resources as Endpoints
9
9
  - reference/v5/components/javascript-environment.md#Module Formats
10
- sourceCommit: 9e6ecf87dd25bb488ad44dc2876ca6439ccd682e
11
- inputHash: 86858206e33925f0
10
+ sourceCommit: e73e5efb2823cc52caf7a6458d67fbcff3bbff2c
11
+ inputHash: b2f8749a92d64168
12
12
  ---
13
13
 
14
14
  # Custom Resources
@@ -17,7 +17,7 @@ Instructions for the agent to follow when defining custom REST endpoints with Ja
17
17
 
18
18
  ## When to Use
19
19
 
20
- Apply this rule when creating custom HTTP endpoints, wrapping external APIs, or registering routes programmatically in a Harper application. Use it any time business logic must live outside a table-backed resource or when a specific URL shape is required.
20
+ Apply this rule when you need to create custom HTTP endpoints, wrap external APIs, or register routes programmatically in a Harper application. Use it any time business logic must live outside a table-backed schema, or when you need fine-grained control over URL shape and path parameters.
21
21
 
22
22
  ## How It Works
23
23
 
@@ -27,7 +27,13 @@ Apply this rule when creating custom HTTP endpoints, wrapping external APIs, or
27
27
  import { tables, Resource } from 'harper';
28
28
  ```
29
29
 
30
- 2. **Define a class that `extends Resource`**: Implement HTTP methods as `static` methods. Each method receives a `target` object.
30
+ CommonJS alternative:
31
+
32
+ ```javascript
33
+ const { tables, Resource } = require('harper');
34
+ ```
35
+
36
+ 2. **Define a class that `extends Resource`**: Use `export class` so Harper exposes it as an endpoint. Implement HTTP methods as `static` methods on the class.
31
37
 
32
38
  ```javascript
33
39
  export class CustomEndpoint extends Resource {
@@ -39,7 +45,7 @@ Apply this rule when creating custom HTTP endpoints, wrapping external APIs, or
39
45
  }
40
46
  ```
41
47
 
42
- 3. **Use `async` static methods to call external services**: Return or forward the response directly.
48
+ 3. **Use `static` async methods to call external services**: Each HTTP verb maps to a `static` method of the same lowercase name.
43
49
 
44
50
  ```javascript
45
51
  export class MyExternalData extends Resource {
@@ -57,24 +63,20 @@ Apply this rule when creating custom HTTP endpoints, wrapping external APIs, or
57
63
  }
58
64
  ```
59
65
 
60
- 4. **Export the class to expose it as an endpoint**: The export form controls the resulting URL. Choose the form that matches the URL shape you need.
66
+ 4. **Control the URL by choosing the export form**: The shape of the export determines the resulting URL path.
61
67
 
62
68
  | Export form | URL | Notes |
63
69
  | ------------------------------------------- | --------------- | --------------------------------------------------------------- |
64
- | `export class Foo extends Resource {}` | `/Foo/` | Class name becomes the path segment. Case-sensitive. |
70
+ | `export class Foo extends Resource {}` | `/Foo/` | Class name becomes the path segment; case-sensitive. |
65
71
  | `export const Bar = { Foo };` | `/Bar/Foo/` | Nest under an object to add a path prefix. |
66
72
  | `export const bar = { 'foo-baz': Foo };` | `/bar/foo-baz/` | Use object keys for lowercase, hyphens, or non-identifier URLs. |
67
73
  | `export { Foo as '/widget/:id' }` | `/widget/:id` | Rename the export to set the path directly. |
68
74
  | `static path = '/widget/:id'` (class field) | `/widget/:id` | Declare path on the class; overrides the export name. |
69
- | `server.resources.set('my-path', Foo);` | `/my-path/` | Programmatic registration for dynamic paths. |
75
+ | `server.resources.set('my-path', Foo);` | `/my-path/` | Programmatic registration; useful when the path is dynamic. |
70
76
 
71
- 5. **Register programmatically when the path is dynamic**: Use `server.resources.set(` with a path string and the resource class.
72
-
73
- ```javascript
74
- server.resources.set('my-path', Foo);
75
- ```
77
+ URL path matching is case-sensitive — `/Foo/` and `/foo/` are different endpoints.
76
78
 
77
- 6. **Declare dynamic path segments with `static path`**: Use `:name` for a single segment and `*name` as a catch-all. Matched values are bound onto `target.<name>`.
79
+ 5. **Declare dynamic path segments with `static path`**: Use `:name` for a single segment and `*name` as a catch-all. Matched values are bound onto `target.<name>`.
78
80
 
79
81
  ```javascript
80
82
  export class Widget extends Resource {
@@ -84,13 +86,36 @@ Apply this rule when creating custom HTTP endpoints, wrapping external APIs, or
84
86
  return { id: target.id, action: target.action };
85
87
  }
86
88
  }
89
+
90
+ export class Files extends Resource {
91
+ // GET /files/a/b/c.txt -> target.rest === 'a/b/c.txt'
92
+ static path = '/files/*rest';
93
+ static get(target) {
94
+ return { path: target.rest };
95
+ }
96
+ }
87
97
  ```
88
98
 
89
- 7. **Resolve path precedence correctly**: Exact and static paths always win over parameterized ones. Among parameterized routes, more specific paths win: a literal segment beats a `:param`, which beats a `*` wildcard, compared left to right.
99
+ - A leading `/` in `static path` makes the path root-relative (top-level), independent of the file's location.
100
+ - A leading `./` or bare name resolves relative to the component directory.
101
+ - A bare `*` (no name) binds under `target.wildcard`. A wildcard must be the final segment.
102
+ - `static path` takes precedence over the export name.
103
+ - Exact and static paths always win over parameterized ones. Among parameterized routes, more specific paths win: a literal segment beats `:param`, which beats `*`, compared left to right.
104
+
105
+ 6. **Register programmatically when the path is dynamic**: Use `server.resources.set(` with a path string and the resource class.
106
+
107
+ ```javascript
108
+ server.resources.set('my-path', Foo);
109
+ ```
110
+
111
+ 7. **Optionally use a resource as a cache source for a local table**: Call `sourcedFrom` on the target table.
112
+ ```javascript
113
+ tables.MyCache.sourcedFrom(MyExternalData);
114
+ ```
90
115
 
91
116
  ## Examples
92
117
 
93
- **Wrapping an external API and using it as a cache source:**
118
+ **Custom endpoint with external API wrapping:**
94
119
 
95
120
  ```javascript
96
121
  import { tables, Resource } from 'harper';
@@ -113,9 +138,19 @@ export class MyExternalData extends Resource {
113
138
  tables.MyCache.sourcedFrom(MyExternalData);
114
139
  ```
115
140
 
116
- **Catch-all wildcard path:**
141
+ **Path parameters with `static path`:**
117
142
 
118
143
  ```javascript
144
+ import { Resource } from 'harper';
145
+
146
+ export class Widget extends Resource {
147
+ // GET /widget/10/action/jump -> target.id === '10', target.action === 'jump'
148
+ static path = '/widget/:id/action/:action';
149
+ static get(target) {
150
+ return { id: target.id, action: target.action };
151
+ }
152
+ }
153
+
119
154
  export class Files extends Resource {
120
155
  // GET /files/a/b/c.txt -> target.rest === 'a/b/c.txt'
121
156
  static path = '/files/*rest';
@@ -125,24 +160,23 @@ export class Files extends Resource {
125
160
  }
126
161
  ```
127
162
 
128
- **Root-relative fixed route:**
163
+ **Programmatic registration:**
129
164
 
130
165
  ```javascript
131
- export class AcmeChallenge extends Resource {
132
- static path = '/.well-known/acme-challenge/:token';
166
+ import { Resource } from 'harper';
167
+
168
+ export class Foo extends Resource {
133
169
  static get(target) {
134
- return { token: target.token };
170
+ return { ok: true };
135
171
  }
136
172
  }
173
+
174
+ server.resources.set('my-path', Foo);
137
175
  ```
138
176
 
139
177
  ## Notes
140
178
 
141
- - URL path matching is case-sensitive — `/Foo/` and `/foo/` are different endpoints.
142
- - A leading `/` in `static path` makes the path root-relative (top-level), independent of the file's location.
143
- - A leading `./` or a bare name in `static path` resolves relative to the component directory.
144
- - A bare `*` (no name) binds under `target.wildcard`. A wildcard must be the final segment of the path.
145
- - `static path` takes precedence over the export name when both are present.
146
- - Parameterized routes appear in the generated OpenAPI document as templated paths (e.g. `/widget/{id}/action/{action}`) and in MCP `resources/templates/list` as URI templates.
147
- - When a resource `extends` an existing table, avoid conflicting exports between the schema and the JavaScript implementation.
148
- - Link the `harper` package in your component directory to ensure correct typings: `npm link harper`. All installed components have `harper` automatically linked.
179
+ - Avoid conflicting exports between the schema and the JavaScript implementation when a resource `extends` an existing table.
180
+ - Parameterized routes appear in the generated OpenAPI document as templated paths (e.g. `/widget/{id}/action/{action}`) and in MCP `resources/templates/list` as `{param}` URI templates.
181
+ - When bundling for SSR with a tool like Vite, keep `harper` external so it resolves to the runtime: `ssr: { external: ['harper'] }`.
182
+ - For components in their own directory, run `npm link harper` to ensure typings match the running installation.
@@ -8,8 +8,8 @@ metadata:
8
8
  - >-
9
9
  fabric/cluster-creation-management.md#Connecting the Harper CLI to a
10
10
  Cluster
11
- sourceCommit: 2cfb81318f17e0aca2d600109e6ad813d2d0443e
12
- inputHash: c821d15a19e2370f
11
+ sourceCommit: e73e5efb2823cc52caf7a6458d67fbcff3bbff2c
12
+ inputHash: dc9d96d6393de8f7
13
13
  ---
14
14
 
15
15
  # Deploying to Harper Fabric
@@ -18,18 +18,20 @@ Instructions for the agent to follow when deploying a Harper application to a re
18
18
 
19
19
  ## When to Use
20
20
 
21
- Apply this rule when deploying a Harper application to a remote Harper instance or Fabric cluster, including first-time deploys, redeployments, rollbacks, and CI/CD pipeline deployments. Also apply it when provisioning credentials for private repository deploys. See [creating-a-fabric-account-and-cluster.md](creating-a-fabric-account-and-cluster.md) for setting up the cluster before deploying.
21
+ Apply this rule when deploying a Harper application to a remote Harper Fabric cluster, whether from a local machine or a CI/CD pipeline. Use it to configure authentication, select a package source, and run `harper deploy` with the correct parameters.
22
+
23
+ See [creating-a-fabric-account-and-cluster.md](creating-a-fabric-account-and-cluster.md) to set up a cluster before deploying.
22
24
 
23
25
  ## How It Works
24
26
 
25
- 1. **Authenticate against the remote cluster**: Run `harper login` once, pointing at the cluster's Application URL (found on the cluster's **Config → Overview** page). The CLI stores the token and writes `HARPER_CLI_TARGET` to a local `.env`.
27
+ 1. **Authenticate against the cluster**: Run `harper login` once, pointing at the cluster's Application URL (found on the cluster's **Config → Overview** page). The CLI stores the token so subsequent commands need no credentials. If the current directory already has a `.env` file that sets no target, it also appends `HARPER_CLI_TARGET` to it.
26
28
 
27
29
  ```bash
28
30
  harper login <Application URL>
29
31
  # Provide cluster username and password when prompted
30
32
  ```
31
33
 
32
- 2. **Deploy the application**: After login, run `harper deploy` without repeating credentials. Use `restart=true` and `replicated=true` for production deploys.
34
+ 2. **Deploy the application**: After logging in, run `harper deploy` without repeating credentials. Omit `package` to package and deploy the current local directory.
33
35
 
34
36
  ```bash
35
37
  harper deploy \
@@ -40,16 +42,16 @@ Apply this rule when deploying a Harper application to a remote Harper instance
40
42
  replicated=true
41
43
  ```
42
44
 
43
- 3. **Choose a package source**: Set the `package` parameter to any valid npm dependency value. Options:
45
+ 3. **Choose a package source**: Set `package` to any valid npm dependency value.
44
46
 
45
- | Source | Example value |
46
- | ----------------------- | ------------------------------------------------------------ |
47
- | Current local directory | Omit `package` |
48
- | npm package | `package="@harperdb/status-check"` |
49
- | GitHub (shorthand) | `package="HarperFast/status-check"` |
50
- | GitHub (URL) | `package="https://github.com/HarperFast/status-check"` |
51
- | Private repo (SSH) | `package="git+ssh://git@github.com:HarperDB/secret-app.git"` |
52
- | Tarball | `package="https://example.com/application.tar.gz"` |
47
+ | Value | Meaning |
48
+ | ------------------------------------------------------------ | ---------------------------------------------- |
49
+ | _(omit)_ | Package and deploy the current local directory |
50
+ | `package="@harperdb/status-check"` | npm package |
51
+ | `package="HarperFast/status-check"` | GitHub shorthand |
52
+ | `package="https://github.com/HarperFast/status-check"` | GitHub URL |
53
+ | `package="git+ssh://git@github.com:HarperDB/secret-app.git"` | Private repo (SSH) |
54
+ | `package="https://example.com/application.tar.gz"` | Tarball |
53
55
 
54
56
  When using git tags, use the `semver` directive:
55
57
 
@@ -57,68 +59,55 @@ Apply this rule when deploying a Harper application to a remote Harper instance
57
59
  HarperFast/application-template#semver:v1.0.0
58
60
  ```
59
61
 
60
- 4. **Deploy by reference (pinned commit)**: Use `by_ref=true` to send a pinned git reference instead of uploading a snapshot. The cluster fetches and builds from that exact commit SHA.
62
+ 4. **Deploy by reference** (pinned commit): Use `by_ref=true` to send a pinned git reference instead of uploading a snapshot. The cluster fetches and builds that exact commit.
61
63
 
62
64
  ```bash
63
65
  harper deploy by_ref=true restart=true replicated=true
64
66
  ```
65
67
 
66
68
  - `by_ref` — Build the package reference from the local repository.
67
- - `ref` _(optional)_ — Deploy a specific commit, tag, or branch instead of `HEAD`. Implies `by_ref`. Tags and branches in `refs/tags` and `refs/heads` namespaces are resolved to a full commit SHA before the deploy is sent.
69
+ - `ref` _(optional)_ — Deploy a specific commit, tag, or branch instead of `HEAD`. Implies `by_ref`. Resolved to a full commit SHA before being sent.
68
70
  - `credential` _(optional)_ — Set to `true` to authenticate the clone with the stored credential for the repository's host. Omit for public repositories.
69
71
 
72
+ Deploy a specific tag or commit:
73
+
70
74
  ```bash
71
- # Deploy a specific tag
72
75
  harper deploy ref=v1.2.0 restart=true replicated=true
73
-
74
- # Roll back by deploying an older commit
75
76
  harper deploy ref=9f8c2a1 restart=true replicated=true
76
77
  ```
77
78
 
78
- **Important constraints on refs:**
79
- - A full commit SHA is accepted directly with no resolution.
80
- - Every other `ref` must resolve to something a clone can fetch: `refs/tags/*` or `refs/heads/*`, or a bare branch or tag name.
81
- - Qualified refs outside those two namespaces (e.g., `refs/pull/123/head`) are rejected.
82
- - Commit and push before deploying — the cluster clones from the remote and only sees pushed commits.
83
- - Run `git fetch` if a ref can't be resolved, or pass a full commit SHA.
79
+ Valid `ref` values must resolve to `refs/heads/*` or `refs/tags/*`, or a bare branch or tag name. Qualified refs outside those two namespaces (e.g. `refs/pull/123/head`) are rejected. A full commit SHA is always accepted directly with no resolution attempted. Run `git fetch` if a ref can't be resolved, or pass a full commit SHA.
80
+
81
+ **Commit and push before deploying by reference.** The cluster clones from the remote and only sees pushed commits.
84
82
 
85
- 5. **Handle private repositories**: Pass `credential=true` so the CLI attaches a credentials reference that the cluster resolves in memory at clone time. No token travels in the operation body or lands on disk.
83
+ 5. **Roll back to a previous release**: Activate a kept release by its `deployment_id` to restore the exact installed release without a fetch, rebuild, or reinstall.
86
84
 
87
85
  ```bash
88
- harper deploy by_ref=true credential=true restart=true replicated=true
86
+ harper deploy project=<name> deployment_id=<id> restart=true
89
87
  ```
90
88
 
91
- Provision the credential once with `setup=true` before using `credential=true`.
92
-
93
- 6. **Provision a deploy credential**: Run `harper deploy setup=true` once per component and source to provision credentials for private deploys. This operation requires **super_user** — run it with an administrative credential, not the CI identity.
89
+ 6. **Provision a deploy credential for private repositories**: Run `harper deploy setup=true` once per component and source. This requires **super_user** privileges — run it with an administrative credential.
94
90
 
95
91
  ```bash
96
92
  harper deploy setup=true
97
93
  ```
98
94
 
99
- This interactive command:
95
+ The setup flow:
100
96
  1. Fetches the cluster's public key with `get_secrets_public_key`.
101
97
  2. Encrypts the token locally into an `enc:v1:` envelope.
102
- 3. Stores only the ciphertext with `set_secret`, in the component-scoped tier.
98
+ 3. Stores only the ciphertext with `set_secret`, scoped to the component.
103
99
  4. Grants the component permission to resolve it with `grant_secret`.
104
100
  5. Prints the `credentials` reference for the deploy to use.
105
101
 
106
- **Use a fine-grained PAT** for GitHub repositories. The prompt defaults to a fine-grained personal access token with **Contents: Read-only** on that one repository. If you use the `gh` CLI session token instead, it typically carries `read:org`, `repo`, `gist`, and `workflow` scopes across your whole account — the CLI prints a warning if you choose it. Use the narrowest credential that does the job, because the stored token is replayed on every cold deploy and rollback.
102
+ The plaintext never leaves your machine. Prefer a **fine-grained** personal access token with **Contents: Read-only** on the target repository. Avoid broad session tokens — they typically carry `read:org`, `gist`, and `workflow` scopes across your whole account.
107
103
 
108
- 7. **Use environment variables for CI/CD**: Instead of `harper login`, export credentials as environment variables.
104
+ 7. **Deploy from a private repository**: Pass `credential=true` after provisioning the deploy credential.
109
105
 
110
106
  ```bash
111
- export HARPER_CLI_USERNAME=<username>
112
- export HARPER_CLI_PASSWORD=<password>
113
- harper deploy \
114
- project=<name> \
115
- package=<package> \
116
- target=<remote> \
117
- restart=true \
118
- replicated=true
107
+ harper deploy by_ref=true credential=true restart=true replicated=true
119
108
  ```
120
109
 
121
- 8. **Use dedicated auth parameters for one-off commands** (not recommended for production): Pass `auth_username` and `auth_password` directly. These take precedence over environment variables and saved login tokens.
110
+ 8. **Use one-off authentication parameters** (not recommended for production): Pass `auth_username` and `auth_password` directly. These take precedence over environment variables and saved login tokens.
122
111
 
123
112
  ```bash
124
113
  harper deploy \
@@ -131,62 +120,58 @@ Apply this rule when deploying a Harper application to a remote Harper instance
131
120
  replicated=true
132
121
  ```
133
122
 
123
+ 9. **Use CI/CD pipelines**: For GitHub Actions, use workload identity (OIDC) so no Harper credential is stored in the pipeline. Alternatively, supply a refresh token from `harper login --for-ci`. On a `pull_request` run, pass the head SHA explicitly:
124
+
125
+ ```bash
126
+ harper deploy ref=${{ github.event.pull_request.head.sha }} restart=true replicated=true
127
+ ```
128
+
134
129
  ## Examples
135
130
 
136
- **Standard deploy after login:**
131
+ **Login and deploy the current directory to a remote cluster:**
137
132
 
138
133
  ```bash
139
134
  harper login https://my-cluster.harperdbcloud.com
140
135
  harper deploy \
141
136
  project=my-app \
142
- package="HarperFast/my-app" \
143
137
  target=https://my-cluster.harperdbcloud.com \
144
138
  restart=true \
145
139
  replicated=true
146
140
  ```
147
141
 
148
- **Deploy by reference with a tag:**
142
+ **Deploy a specific GitHub repository by tag:**
149
143
 
150
144
  ```bash
151
- harper deploy ref=v1.2.0 restart=true replicated=true
145
+ harper deploy \
146
+ project=my-app \
147
+ package="HarperFast/application-template#semver:v1.0.0" \
148
+ target=https://my-cluster.harperdbcloud.com \
149
+ restart=true \
150
+ replicated=true
152
151
  ```
153
152
 
154
- **Deploy a private GitHub repo by reference:**
153
+ **Deploy by reference from a private repository after provisioning credentials:**
155
154
 
156
155
  ```bash
157
- # Provision credential once (requires super_user)
156
+ # Provision once (requires super_user)
158
157
  harper deploy setup=true
159
158
 
160
- # Deploy using stored credential
159
+ # Deploy by reference with credential
161
160
  harper deploy by_ref=true credential=true restart=true replicated=true
162
161
  ```
163
162
 
164
- **GitHub Actions — pull request deploy:**
163
+ **Roll back to a previous deployment:**
165
164
 
166
165
  ```bash
167
- harper deploy ref=${{ github.event.pull_request.head.sha }} restart=true replicated=true
168
- ```
169
-
170
- **CI/CD deploy using environment variables:**
171
-
172
- ```bash
173
- export HARPER_CLI_USERNAME=<username>
174
- export HARPER_CLI_PASSWORD=<password>
175
- harper deploy \
176
- project=my-app \
177
- package="@myorg/my-app" \
178
- target=https://my-cluster.harperdbcloud.com \
179
- restart=true \
180
- replicated=true
166
+ harper deploy project=my-app deployment_id=<id> restart=true
181
167
  ```
182
168
 
183
169
  ## Notes
184
170
 
185
- - The cluster's Application URL is found on the **Config → Overview** page of the Fabric dashboard.
186
- - `harper deploy setup=true` calls `get_secrets_public_key`, `set_secret`, and `grant_secret`, all of which require **super_user**. Do not run it with the CI identity.
187
- - The `enc:v1:` envelope means the plaintext token never leaves your machine — only ciphertext is stored and replicated.
188
- - Secrets are stored scoped to the component, not in the global `processEnv` tier. If a global secret already exists at the derived name, it is converted to the scoped tier.
171
+ - The cluster's Application URL is found on the **Config → Overview** page.
172
+ - `harper deploy setup=true` requires **super_user** — run it with an administrative credential, not the CI identity it provisions for.
173
+ - Secrets are stored scoped to the component, never in the global `processEnv` tier. The `enc:v1:` envelope is the only form of the token that ever leaves your machine or travels over the operations API.
189
174
  - For SSH-based private repos, use the `add_ssh_key` operation to register keys before deploying.
190
- - If your application requires a build step that cannot run on the cluster node, deploy a built payload (omit `by_ref`) instead of deploying by reference.
175
+ - A `ref` pointing to `refs/tags` is resolved to a full commit SHA before the deploy is sent. Tags that move mid-deploy could otherwise leave cluster nodes running different code.
191
176
  - The unpushed-commit check is skipped under GitHub Actions; the dirty-tree warning still applies.
192
- - Annotated tags in `refs/tags` resolve to the commit they point at, not the tag object.
177
+ - Deploying by reference means the cluster installs and builds from source. If your application requires a build step that cannot run on the node, deploy a built payload instead.