@harperfast/template-vue-ts-studio 1.12.12 → 1.13.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 +684 -239
- package/.agents/skills/harper-best-practices/SKILL.md +2 -1
- package/.agents/skills/harper-best-practices/rules/creating-a-fabric-account-and-cluster.md +7 -4
- package/.agents/skills/harper-best-practices/rules/creating-harper-apps.md +71 -4
- package/.agents/skills/harper-best-practices/rules/custom-resources.md +63 -29
- package/.agents/skills/harper-best-practices/rules/deploying-from-ci.md +358 -0
- package/.agents/skills/harper-best-practices/rules/deploying-to-harper-fabric.md +132 -103
- package/.agents/skills/harper-best-practices/rules/load-env.md +37 -49
- package/.agents/skills/harper-best-practices/rules/programmatic-table-requests.md +71 -57
- package/.agents/skills/harper-best-practices/rules.manifest.yaml +184 -8
- package/README.md +0 -48
- package/agent/skills/harper-best-practices/AGENTS.md +684 -239
- package/agent/skills/harper-best-practices/SKILL.md +2 -1
- package/agent/skills/harper-best-practices/rules/creating-a-fabric-account-and-cluster.md +7 -4
- package/agent/skills/harper-best-practices/rules/creating-harper-apps.md +71 -4
- package/agent/skills/harper-best-practices/rules/custom-resources.md +63 -29
- package/agent/skills/harper-best-practices/rules/deploying-from-ci.md +358 -0
- package/agent/skills/harper-best-practices/rules/deploying-to-harper-fabric.md +132 -103
- package/agent/skills/harper-best-practices/rules/load-env.md +37 -49
- package/agent/skills/harper-best-practices/rules/programmatic-table-requests.md +71 -57
- package/agent/skills/harper-best-practices/rules.manifest.yaml +184 -8
- package/package.json +1 -1
- package/skills-lock.json +1 -1
|
@@ -14,31 +14,37 @@ metadata:
|
|
|
14
14
|
reference/v5/resources/resource-api.md#`addTo(property: string, value:
|
|
15
15
|
number)`
|
|
16
16
|
- reference/v5/components/javascript-environment.md#Module Formats
|
|
17
|
-
sourceCommit:
|
|
18
|
-
inputHash:
|
|
17
|
+
sourceCommit: e73e5efb2823cc52caf7a6458d67fbcff3bbff2c
|
|
18
|
+
inputHash: bb360b0d6c0a7bd4
|
|
19
19
|
---
|
|
20
20
|
|
|
21
21
|
# Programmatic Table Requests
|
|
22
22
|
|
|
23
|
-
Instructions for the agent to
|
|
23
|
+
Instructions for the agent to follow when interacting with Harper tables programmatically using the `tables` object.
|
|
24
24
|
|
|
25
25
|
## When to Use
|
|
26
26
|
|
|
27
|
-
Apply this rule when writing server-side Harper component code that reads from or writes to tables
|
|
27
|
+
Apply this rule when writing server-side Harper component code that reads from or writes to tables using the programmatic API — for example, in HTTP handlers, background jobs, timers, or SSR entry points. Use it whenever you need to construct queries with `conditions`, `sort`, `select`, pagination, or transactions outside of the REST layer.
|
|
28
28
|
|
|
29
29
|
## How It Works
|
|
30
30
|
|
|
31
|
-
1. **Import `tables` (and other APIs) from `harper`**: Access every table defined in `schema.graphql` as a
|
|
31
|
+
1. **Import `tables` (and other APIs) from `harper`**: Access every table defined in `schema.graphql` as a property of `tables`. Each property is the table class implementing the Resource API.
|
|
32
32
|
|
|
33
33
|
```javascript
|
|
34
34
|
import { tables, transaction } from 'harper';
|
|
35
35
|
const { Product } = tables;
|
|
36
|
-
//
|
|
36
|
+
// same as: databases.data.Product
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
For
|
|
39
|
+
For components in their own directory, run:
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
```bash
|
|
42
|
+
npm link harper
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
All installed components have `harper` automatically linked.
|
|
46
|
+
|
|
47
|
+
2. **Define your schema with `@table`**: Every type you want to access via `tables` must carry the `@table` directive. Mark queryable fields with `@indexed`.
|
|
42
48
|
|
|
43
49
|
```graphql
|
|
44
50
|
type Product @table {
|
|
@@ -48,7 +54,7 @@ Apply this rule when writing server-side Harper component code that reads from o
|
|
|
48
54
|
}
|
|
49
55
|
```
|
|
50
56
|
|
|
51
|
-
3. **Query records
|
|
57
|
+
3. **Query records using `search(`**: Pass a Query object to `search()`. The query is an async iterable.
|
|
52
58
|
|
|
53
59
|
```javascript
|
|
54
60
|
const query = {
|
|
@@ -59,7 +65,7 @@ Apply this rule when writing server-side Harper component code that reads from o
|
|
|
59
65
|
}
|
|
60
66
|
```
|
|
61
67
|
|
|
62
|
-
4. **Build `conditions`**: Each condition object supports
|
|
68
|
+
4. **Build `conditions`**: Each condition object supports the following properties:
|
|
63
69
|
|
|
64
70
|
| Property | Description |
|
|
65
71
|
| ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -69,53 +75,60 @@ Apply this rule when writing server-side Harper component code that reads from o
|
|
|
69
75
|
| `conditions` | Nested conditions array |
|
|
70
76
|
| `operator` | `and` (default) or `or` for the nested `conditions` |
|
|
71
77
|
|
|
72
|
-
5. **
|
|
78
|
+
5. **Apply `select` to shape results**: Pass an array of property names, a string for a single property, or nested objects for relationships.
|
|
73
79
|
|
|
74
80
|
```javascript
|
|
75
|
-
//
|
|
81
|
+
// Flat select
|
|
76
82
|
Product.search({ select: ['name', 'price'] });
|
|
77
83
|
|
|
78
|
-
//
|
|
84
|
+
// Nested relationship select
|
|
79
85
|
Book.get({ id: 42, select: ['id', 'title', { name: 'author', select: ['name'] }] });
|
|
80
86
|
```
|
|
81
87
|
|
|
82
88
|
Special `select` values: `$id`, `$updatedtime`, `$distance`.
|
|
83
89
|
|
|
84
|
-
6. **
|
|
85
|
-
|
|
86
|
-
```javascript
|
|
87
|
-
Product.search({ conditions: [...], limit: 20, offset: 40 });
|
|
88
|
-
```
|
|
90
|
+
6. **Apply `sort`**: Harper uses an index to provide sort order.
|
|
89
91
|
|
|
90
|
-
|
|
92
|
+
| Property | Description |
|
|
93
|
+
| ------------ | ---------------------------------------------------------- |
|
|
94
|
+
| `attribute` | Property name (or array for chained relationship property) |
|
|
95
|
+
| `descending` | Sort descending if `true` (default: `false`) |
|
|
96
|
+
| `next` | Secondary sort to resolve ties (same structure) |
|
|
97
|
+
- If the sort `attribute` is `@indexed`, no condition is required.
|
|
98
|
+
- If the sort `attribute` is not indexed, at least one entry in `conditions` (on **any** attribute) is required.
|
|
99
|
+
- Sorting by a non-indexed attribute with zero conditions raises:
|
|
100
|
+
> `HdbError: <attribute> is not indexed and not combined with any other conditions`
|
|
101
|
+
- The bare `@primaryKey` is treated as not indexed for sort purposes. To iterate in primary-key order, add an open-ended condition:
|
|
91
102
|
|
|
92
|
-
|
|
103
|
+
```javascript
|
|
104
|
+
Product.search({
|
|
105
|
+
conditions: [{ attribute: 'id', comparator: 'greater_than', value: '' }],
|
|
106
|
+
sort: { attribute: 'id' },
|
|
107
|
+
});
|
|
108
|
+
```
|
|
93
109
|
|
|
94
|
-
|
|
110
|
+
- Pass `allowFullScan: true` to permit an unconditional ordered scan, or omit `sort` entirely to iterate without an index requirement.
|
|
95
111
|
|
|
96
|
-
|
|
112
|
+
7. **Paginate with `limit` and `offset`**:
|
|
97
113
|
|
|
98
114
|
```javascript
|
|
99
|
-
Product.search({
|
|
100
|
-
conditions: [{ attribute: 'id', comparator: 'greater_than', value: '' }],
|
|
101
|
-
sort: { attribute: 'id' },
|
|
102
|
-
});
|
|
115
|
+
Product.search({ conditions: [...], limit: 20, offset: 40 });
|
|
103
116
|
```
|
|
104
117
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
8. **Debug query planning with `explain` and `enforceExecutionOrder`**:
|
|
118
|
+
8. **Debug with `explain` and `enforceExecutionOrder`**:
|
|
108
119
|
- `explain: true` — returns conditions reordered as Harper will execute them.
|
|
109
|
-
- `enforceExecutionOrder: true` — forces conditions to execute in the order supplied, disabling automatic re-ordering.
|
|
120
|
+
- `enforceExecutionOrder: true` — forces conditions to execute in the order supplied, disabling Harper's automatic re-ordering.
|
|
110
121
|
|
|
111
|
-
9. **Use `addTo` for concurrent-safe
|
|
122
|
+
9. **Use `addTo` for concurrent-safe increments**: `addTo(property, value)` uses CRDT incrementation, safe across threads and nodes.
|
|
112
123
|
|
|
113
124
|
```javascript
|
|
114
|
-
|
|
115
|
-
|
|
125
|
+
static async post(target, data) {
|
|
126
|
+
const record = await this.update(target.id);
|
|
127
|
+
record.addTo('quantity', -1);
|
|
128
|
+
}
|
|
116
129
|
```
|
|
117
130
|
|
|
118
|
-
10. **Wrap background work in `transaction()`**:
|
|
131
|
+
10. **Wrap background work in `transaction()`**: Harper auto-starts transactions for HTTP handlers. Use `transaction()` explicitly for timers, background jobs, or any code outside a natural transaction context.
|
|
119
132
|
|
|
120
133
|
```javascript
|
|
121
134
|
await transaction(async (txn) => {
|
|
@@ -127,18 +140,18 @@ Apply this rule when writing server-side Harper component code that reads from o
|
|
|
127
140
|
|
|
128
141
|
The `txn` object exposes:
|
|
129
142
|
|
|
130
|
-
| Member | Description |
|
|
131
|
-
| --------------------- | ------------------------------------------------------ |
|
|
132
|
-
| `commit()` | Commits the current transaction |
|
|
133
|
-
| `abort()` | Aborts and resets
|
|
134
|
-
| `resetReadSnapshot()` | Resets the read snapshot to the latest committed state |
|
|
135
|
-
| `timestamp` | Timestamp associated with the current transaction |
|
|
143
|
+
| Member | Type | Description |
|
|
144
|
+
| --------------------- | --------------- | ------------------------------------------------------ |
|
|
145
|
+
| `commit()` | `() => Promise` | Commits the current transaction |
|
|
146
|
+
| `abort()` | `() => void` | Aborts the transaction and resets it |
|
|
147
|
+
| `resetReadSnapshot()` | `() => void` | Resets the read snapshot to the latest committed state |
|
|
148
|
+
| `timestamp` | `number` | Timestamp associated with the current transaction |
|
|
136
149
|
|
|
137
|
-
|
|
150
|
+
On normal callback completion the transaction commits automatically. If the callback throws, the transaction is aborted.
|
|
138
151
|
|
|
139
|
-
|
|
152
|
+
11. **Understand atomicity**: Transactions span a single database. All tables within the same database share one transactional context — reads return a consistent snapshot and writes across multiple tables commit atomically. Cross-database operations get separate transactions with no cross-database atomicity guarantee.
|
|
140
153
|
|
|
141
|
-
|
|
154
|
+
12. **Keep `harper` external when bundling for SSR**: In `vite.config`, mark `harper` as external so it resolves to the runtime rather than being bundled.
|
|
142
155
|
|
|
143
156
|
```javascript
|
|
144
157
|
// vite.config
|
|
@@ -149,7 +162,7 @@ Apply this rule when writing server-side Harper component code that reads from o
|
|
|
149
162
|
|
|
150
163
|
## Examples
|
|
151
164
|
|
|
152
|
-
|
|
165
|
+
**Full CRUD flow:**
|
|
153
166
|
|
|
154
167
|
```javascript
|
|
155
168
|
import { tables } from 'harper';
|
|
@@ -161,19 +174,18 @@ const created = await Product.create({ name: 'Shirt', price: 9.5 });
|
|
|
161
174
|
// Patch
|
|
162
175
|
await Product.patch(created.id, { price: Math.round(created.price * 0.8 * 100) / 100 });
|
|
163
176
|
|
|
164
|
-
//
|
|
177
|
+
// Get by primary key
|
|
165
178
|
const record = await Product.get(created.id);
|
|
166
179
|
|
|
167
|
-
//
|
|
168
|
-
const
|
|
180
|
+
// Search with conditions
|
|
181
|
+
for await (const record of Product.search({
|
|
169
182
|
conditions: [{ attribute: 'price', comparator: 'less_than', value: 8.0 }],
|
|
170
|
-
}
|
|
171
|
-
for await (const record of Product.search(query)) {
|
|
183
|
+
})) {
|
|
172
184
|
// process record
|
|
173
185
|
}
|
|
174
186
|
```
|
|
175
187
|
|
|
176
|
-
|
|
188
|
+
**Nested conditions with `or`:**
|
|
177
189
|
|
|
178
190
|
```javascript
|
|
179
191
|
Product.search({
|
|
@@ -190,13 +202,13 @@ Product.search({
|
|
|
190
202
|
});
|
|
191
203
|
```
|
|
192
204
|
|
|
193
|
-
|
|
205
|
+
**Chained attribute reference (join):**
|
|
194
206
|
|
|
195
207
|
```javascript
|
|
196
208
|
Product.search({ conditions: [{ attribute: ['brand', 'name'], value: 'Harper' }] });
|
|
197
209
|
```
|
|
198
210
|
|
|
199
|
-
|
|
211
|
+
**Background job with `transaction()`:**
|
|
200
212
|
|
|
201
213
|
```javascript
|
|
202
214
|
import { isMainThread } from 'node:worker_threads';
|
|
@@ -224,7 +236,7 @@ if (isMainThread) {
|
|
|
224
236
|
}
|
|
225
237
|
```
|
|
226
238
|
|
|
227
|
-
|
|
239
|
+
**SSR with Harper data:**
|
|
228
240
|
|
|
229
241
|
```typescript
|
|
230
242
|
import { tables } from 'harper';
|
|
@@ -237,7 +249,9 @@ export async function render(url: string): Promise<string> {
|
|
|
237
249
|
|
|
238
250
|
## Notes
|
|
239
251
|
|
|
240
|
-
- `tables` and `databases`
|
|
241
|
-
-
|
|
242
|
-
- `
|
|
243
|
-
-
|
|
252
|
+
- `tables` and `databases` calls run in a trusted server-side context and do **not** automatically apply the target table's role permissions.
|
|
253
|
+
- Programmatic `update`, `patch`, and `delete` calls operate directly on stored data. Scope destructive operations with specific `conditions`, validate the affected set before writing, and gate them behind authorization controls.
|
|
254
|
+
- If `transaction()` is called with a context that already has an active transaction, it reuses that transaction — making it safe to call defensively.
|
|
255
|
+
- Always `await` the `transaction()` call and `catch` errors when outside a request context; an unawaited call means a failed write is never observed.
|
|
256
|
+
- Guard against timer overlap: if a job can outlast its interval, use a `running` flag to skip a tick rather than opening two transactions over the same rows.
|
|
257
|
+
- CommonJS is also supported: `const { tables, Resource } = require('harper');`
|
|
@@ -595,8 +595,12 @@ rules:
|
|
|
595
595
|
# Infrastructure & Ops (priority 4 — MEDIUM)
|
|
596
596
|
# ===========================================================================
|
|
597
597
|
|
|
598
|
+
# Deploying is split across two rules: as one, its sources would come to
|
|
599
|
+
# ~57KB, well over any other rule's input, and the larger the input, the more
|
|
600
|
+
# facts regeneration compresses away. This rule covers a CLI deploy and what
|
|
601
|
+
# happens to a release afterwards; deploying-from-ci covers OIDC in CI.
|
|
598
602
|
- rule: deploying-to-harper-fabric
|
|
599
|
-
description: How to deploy a Harper application to
|
|
603
|
+
description: How to deploy a Harper application to Harper Fabric with the CLI, check that the release was certified, and roll back by activating a previous release's `deployment_id`.
|
|
600
604
|
category: ops
|
|
601
605
|
priority: 4
|
|
602
606
|
order: 1
|
|
@@ -608,6 +612,41 @@ rules:
|
|
|
608
612
|
- path: fabric/cluster-creation-management.md
|
|
609
613
|
section: 'Connecting the Harper CLI to a Cluster'
|
|
610
614
|
role: supplemental
|
|
615
|
+
# The CLI forms of `restart=rolling`, `replicated=false`, `activate=false`
|
|
616
|
+
# and `deployment_id=`. Matched by heading text, so the
|
|
617
|
+
# `restart=rolling` anchor also fails if commands.md ever gains an
|
|
618
|
+
# earlier `Parameters` heading.
|
|
619
|
+
- path: reference/v5/cli/commands.md
|
|
620
|
+
section: 'Parameters'
|
|
621
|
+
role: supplemental
|
|
622
|
+
# How `list_deployments` and `get_job` are run from the CLI.
|
|
623
|
+
- path: reference/v5/cli/operations-api-commands.md
|
|
624
|
+
section: 'General Syntax'
|
|
625
|
+
role: supplemental
|
|
626
|
+
# `deploy_component` is sourced by subsection: the whole section is
|
|
627
|
+
# ~30KB, mostly detail that does not change what an agent does.
|
|
628
|
+
# `Restarting` is left out: Parameters and the canary section carry
|
|
629
|
+
# what an agent needs from it.
|
|
630
|
+
- path: reference/v5/operations-api/operations.md
|
|
631
|
+
section: 'Certifying a release in a canary worker'
|
|
632
|
+
role: primary
|
|
633
|
+
- path: reference/v5/operations-api/operations.md
|
|
634
|
+
section: 'Staging a build and activating it later'
|
|
635
|
+
role: primary
|
|
636
|
+
- path: reference/v5/operations-api/operations.md
|
|
637
|
+
section: 'Going back to a previous release'
|
|
638
|
+
role: primary
|
|
639
|
+
# What a retried activation does on each node, and that a retry with
|
|
640
|
+
# `restart` restarts every worker even where the release is live.
|
|
641
|
+
- path: reference/v5/operations-api/operations.md
|
|
642
|
+
section: 'Retrying an activation'
|
|
643
|
+
role: supplemental
|
|
644
|
+
- path: reference/v5/operations-api/operations.md
|
|
645
|
+
section: '`list_deployments`'
|
|
646
|
+
role: supplemental
|
|
647
|
+
- path: reference/v5/operations-api/operations.md
|
|
648
|
+
section: '`get_job`'
|
|
649
|
+
role: supplemental
|
|
611
650
|
must_cover:
|
|
612
651
|
- 'harper deploy'
|
|
613
652
|
- 'harper login'
|
|
@@ -619,6 +658,10 @@ rules:
|
|
|
619
658
|
# enc:v1: (1×) → the client-side-encryption envelope
|
|
620
659
|
# They double as the rename detector for that subheading: if it is
|
|
621
660
|
# retitled or removed, the content goes and these anchors fail.
|
|
661
|
+
#
|
|
662
|
+
# Deploying by reference is no longer the CI default, but a private
|
|
663
|
+
# repository is still deployed that way. If the docs move this guidance
|
|
664
|
+
# out of `## Remote Management`, re-point the source; don't drop these.
|
|
622
665
|
- 'fine-grained'
|
|
623
666
|
- 'Contents: Read-only'
|
|
624
667
|
- 'read:org'
|
|
@@ -633,35 +676,168 @@ rules:
|
|
|
633
676
|
# provisions for. The source escapes it as `super\_user`; every generated
|
|
634
677
|
# body so far unescapes, so the anchor is the unescaped form.
|
|
635
678
|
- 'super_user'
|
|
679
|
+
# Going back: activating a kept release rebuilds nothing, where
|
|
680
|
+
# redeploying an older commit installs it again from source.
|
|
681
|
+
# `stagingRetention` holds how many releases a node keeps.
|
|
682
|
+
- 'deployment_id'
|
|
683
|
+
- 'list_deployments'
|
|
684
|
+
- 'stagingRetention'
|
|
685
|
+
- 'activate: false'
|
|
686
|
+
# On Pro and Fabric a deploy replicates unless `replicated=false`.
|
|
687
|
+
- 'replicated=false'
|
|
688
|
+
# `not-requested` occurs only in the `certification` table, so it holds
|
|
689
|
+
# the table, not a passing mention of the field. `restartJobId`, `get_job`
|
|
690
|
+
# and `COMPLETE` hold the wait: a rolling deploy responds once its job
|
|
691
|
+
# starts, and its record says `success` even if the job then fails.
|
|
692
|
+
- 'restart=rolling'
|
|
693
|
+
- 'certification'
|
|
694
|
+
- 'not-requested'
|
|
695
|
+
- 'fails closed'
|
|
696
|
+
- 'restartJobId'
|
|
697
|
+
- 'get_job'
|
|
698
|
+
- 'COMPLETE'
|
|
636
699
|
cross_links:
|
|
637
700
|
- creating-a-fabric-account-and-cluster
|
|
701
|
+
- deploying-from-ci
|
|
702
|
+
|
|
703
|
+
- rule: deploying-from-ci
|
|
704
|
+
description: How to deploy a Harper application from GitHub Actions with OIDC trusted publishing, so CI stores no Harper credential, including the one-command setup with `harper deploy setup=true provider=github-actions`.
|
|
705
|
+
category: ops
|
|
706
|
+
priority: 4
|
|
707
|
+
order: 2
|
|
708
|
+
mode: generate
|
|
709
|
+
# The guide's isolated-worker and per-PR preview sections are left out:
|
|
710
|
+
# ~18KB on their own, and a different task from deploying a release.
|
|
711
|
+
sources:
|
|
712
|
+
# The one-command setup (v5.4.0) for a workflow that deploys when changes
|
|
713
|
+
# merge to a branch, which create-harper projects scaffold. The guide's
|
|
714
|
+
# hand-written policy is still what a tag-triggered release needs.
|
|
715
|
+
- path: reference/v5/cli/commands.md
|
|
716
|
+
section: 'GitHub Actions deploys (OIDC)'
|
|
717
|
+
role: primary
|
|
718
|
+
- path: learn/developers/deploying-from-ci.md
|
|
719
|
+
section: 'Let the workflow authenticate with OIDC'
|
|
720
|
+
role: primary
|
|
721
|
+
- path: learn/developers/deploying-from-ci.md
|
|
722
|
+
section: 'Path A: deploy a tagged release from your repository'
|
|
723
|
+
role: primary
|
|
724
|
+
- path: learn/developers/deploying-from-ci.md
|
|
725
|
+
section: 'Give Harper a durable credential for a private source'
|
|
726
|
+
role: supplemental
|
|
727
|
+
- path: learn/developers/deploying-from-ci.md
|
|
728
|
+
section: 'Path B: build in CI, publish to GitHub Packages, deploy the artifact'
|
|
729
|
+
role: supplemental
|
|
730
|
+
- path: learn/developers/deploying-from-ci.md
|
|
731
|
+
section: 'Check the deployment record'
|
|
732
|
+
role: supplemental
|
|
733
|
+
- path: learn/developers/deploying-from-ci.md
|
|
734
|
+
section: 'Operational notes'
|
|
735
|
+
role: supplemental
|
|
736
|
+
# Where the exchange sits in credential precedence, and how to diagnose
|
|
737
|
+
# a refused one.
|
|
738
|
+
- path: reference/v5/cli/authentication.md
|
|
739
|
+
section: 'Workload identity (OIDC)'
|
|
740
|
+
role: supplemental
|
|
741
|
+
- path: reference/v5/operations-api/operations.md
|
|
742
|
+
section: 'Policy specificity for GitHub Actions'
|
|
743
|
+
role: supplemental
|
|
744
|
+
- path: reference/v5/operations-api/operations.md
|
|
745
|
+
section: '`list_oidc_trust`'
|
|
746
|
+
role: supplemental
|
|
747
|
+
- path: reference/v5/operations-api/operations.md
|
|
748
|
+
section: '`drop_oidc_trust`'
|
|
749
|
+
role: supplemental
|
|
750
|
+
must_cover:
|
|
751
|
+
# The one-command setup: `workflow=` holds the default-file rule (a
|
|
752
|
+
# `deploy.yml` workflow can't match a policy pinned to `deploy.yaml`),
|
|
753
|
+
# and `github-actions-<project>` the policy name a revocation drops.
|
|
754
|
+
- 'provider=github-actions'
|
|
755
|
+
- 'workflow='
|
|
756
|
+
- 'github-actions-<project>'
|
|
757
|
+
# The version check `harper deploy` makes before it uploads; a role
|
|
758
|
+
# without it logs a refused operation on every run.
|
|
759
|
+
- 'registration_info'
|
|
760
|
+
- 'id-token: write'
|
|
761
|
+
- 'vars.HARPER_CLI_TARGET'
|
|
762
|
+
# A configured credential outranks the exchange, so a pipeline that
|
|
763
|
+
# keeps its refresh token never uses OIDC.
|
|
764
|
+
- 'HARPER_CLI_REFRESH_TOKEN'
|
|
765
|
+
# The workflow as written: without a checkout and the CLI, a clean
|
|
766
|
+
# runner has nothing to deploy and nothing to deploy it with. Fact
|
|
767
|
+
# retention can't see inside a fence, and step 2's single job also has
|
|
768
|
+
# `runs-on: ubuntu-latest` and `actions/checkout`, so Path A's complete
|
|
769
|
+
# workflow is held by what only it has: its trigger (`push:` and
|
|
770
|
+
# `tags: ['v*']`), its `jobs:` wrapper, and the wait loop's
|
|
771
|
+
# `.[0].status`. The CLI install is held with its pin: an unpinned one
|
|
772
|
+
# would change under a rerun of an old tag after a new major release.
|
|
773
|
+
- 'actions/checkout'
|
|
774
|
+
- 'npm install --global harper@^5.3'
|
|
775
|
+
- 'runs-on: ubuntu-latest'
|
|
776
|
+
- 'push:'
|
|
777
|
+
- "tags: ['v*']"
|
|
778
|
+
- 'jobs:'
|
|
779
|
+
- '.[0].status'
|
|
780
|
+
# `workflow_path` is what a tag-triggered release pins instead of
|
|
781
|
+
# `workflow_ref`. `trailing slash` holds the audience rule, without which
|
|
782
|
+
# a policy never matches. The environment is the ref gate, and only as
|
|
783
|
+
# strong as its deployment branch and tag rules.
|
|
784
|
+
- 'add_oidc_trust'
|
|
785
|
+
- 'super_user'
|
|
786
|
+
- 'token.actions.githubusercontent.com'
|
|
787
|
+
- 'repository_id'
|
|
788
|
+
- 'workflow_ref'
|
|
789
|
+
- 'workflow_path'
|
|
790
|
+
- 'environment: production'
|
|
791
|
+
- 'Deployment branches and tags'
|
|
792
|
+
- 'trailing slash'
|
|
793
|
+
# An `operations` allowlist refuses what it doesn't list, so the wait
|
|
794
|
+
# step needs `get_job`. A job lives only on the node that received the
|
|
795
|
+
# deploy, so polls through a load-balanced URL have to reach it.
|
|
796
|
+
- 'deploy_component'
|
|
797
|
+
- 'get_job'
|
|
798
|
+
- 'get_deployment'
|
|
799
|
+
- 'restartJobId'
|
|
800
|
+
- 'load-balanced'
|
|
801
|
+
- 'credential=true'
|
|
802
|
+
# A rejected exchange never says which check failed; `invalid_reason`
|
|
803
|
+
# and the `oidc-trust` log do. Dropping a policy leaves an issued token
|
|
804
|
+
# valid for its hour; `alter_user` stops it.
|
|
805
|
+
- 'list_oidc_trust'
|
|
806
|
+
- 'invalid_reason'
|
|
807
|
+
- 'oidc-trust'
|
|
808
|
+
- 'drop_oidc_trust'
|
|
809
|
+
- 'alter_user'
|
|
810
|
+
# The user setup creates, which an incident revocation deactivates.
|
|
811
|
+
- '<project>-ci-deploy'
|
|
812
|
+
cross_links:
|
|
813
|
+
- deploying-to-harper-fabric
|
|
638
814
|
|
|
639
815
|
- rule: creating-a-fabric-account-and-cluster
|
|
640
816
|
description: How to create a Harper Fabric account, organization, and cluster.
|
|
641
817
|
category: ops
|
|
642
818
|
priority: 4
|
|
643
|
-
order:
|
|
819
|
+
order: 3
|
|
644
820
|
mode: synthesized
|
|
645
821
|
|
|
646
822
|
- rule: creating-harper-apps
|
|
647
823
|
description: How to initialize a new Harper application using the CLI.
|
|
648
824
|
category: ops
|
|
649
825
|
priority: 4
|
|
650
|
-
order:
|
|
826
|
+
order: 4
|
|
651
827
|
mode: synthesized
|
|
652
828
|
|
|
653
829
|
- rule: serving-web-content
|
|
654
830
|
description: How to serve static files and integrated Vite/React applications in Harper.
|
|
655
831
|
category: ops
|
|
656
832
|
priority: 4
|
|
657
|
-
order:
|
|
833
|
+
order: 5
|
|
658
834
|
mode: synthesized
|
|
659
835
|
|
|
660
836
|
- rule: logging
|
|
661
837
|
description: Best practices for logging in Harper, including console capture, the granular logger interface, and programmatic log retrieval.
|
|
662
838
|
category: ops
|
|
663
839
|
priority: 4
|
|
664
|
-
order:
|
|
840
|
+
order: 6
|
|
665
841
|
mode: generate
|
|
666
842
|
sources:
|
|
667
843
|
- path: reference/v5/logging/overview.md
|
|
@@ -677,7 +853,7 @@ rules:
|
|
|
677
853
|
description: How to load environment variables from .env files into a Harper application using the loadEnv plugin.
|
|
678
854
|
category: ops
|
|
679
855
|
priority: 4
|
|
680
|
-
order:
|
|
856
|
+
order: 7
|
|
681
857
|
mode: generate
|
|
682
858
|
sources:
|
|
683
859
|
- path: reference/v5/environment-variables/overview.md
|
|
@@ -693,7 +869,7 @@ rules:
|
|
|
693
869
|
description: Breaking changes and recommended updates when migrating a Harper application to v5.
|
|
694
870
|
category: ops
|
|
695
871
|
priority: 4
|
|
696
|
-
order:
|
|
872
|
+
order: 8
|
|
697
873
|
mode: generate
|
|
698
874
|
sources:
|
|
699
875
|
- path: release-notes/v5-lincoln/v5-migration.md
|
|
@@ -723,7 +899,7 @@ rules:
|
|
|
723
899
|
description: How to delegate tasks to Harper's built-in agent via the CLI and the agent operations API.
|
|
724
900
|
category: ops
|
|
725
901
|
priority: 4
|
|
726
|
-
order:
|
|
902
|
+
order: 9
|
|
727
903
|
mode: synthesized
|
|
728
904
|
cross_links:
|
|
729
905
|
- deploying-to-harper-fabric
|
package/README.md
CHANGED
|
@@ -96,54 +96,6 @@ You should see the following:
|
|
|
96
96
|
|
|
97
97
|
Take a look at the [default configuration](./config.yaml), which specifies how files are handled in your application.
|
|
98
98
|
|
|
99
|
-
### One-time setup (private repos)
|
|
100
|
-
|
|
101
|
-
So the cluster can clone your private repository, give it a read-only token — sealed on your machine, stored encrypted:
|
|
102
|
-
|
|
103
|
-
```sh
|
|
104
|
-
npm run deploy:setup
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
This fetches your cluster's public key, has you provide a GitHub token (a fine-grained PAT with **Contents: Read-only**, or your `gh` CLI session), **encrypts it locally**, and stores only the ciphertext in the cluster's secret store. The plaintext never leaves your machine; the cluster decrypts it in memory only while cloning. Because the token is durable, rollbacks keep working for as long as it's valid.
|
|
108
|
-
|
|
109
|
-
> Public repo? Skip this step and drop `credential=true` from the `deploy` script — no credential is needed.
|
|
110
|
-
|
|
111
|
-
### Deploy
|
|
112
|
-
|
|
113
|
-
```sh
|
|
114
|
-
npm run deploy
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
This deploys the current commit over `git+https` — commit and push first, since the cluster clones from GitHub and only sees pushed commits. To roll back, check out an older commit and run it again.
|
|
118
|
-
|
|
119
|
-
### Deploy automatically from CI
|
|
120
|
-
|
|
121
|
-
The included [GitHub Actions workflow](./.github/workflows/deploy.yaml) deploys whenever you push a version tag:
|
|
122
|
-
|
|
123
|
-
```sh
|
|
124
|
-
git tag v1.0.0
|
|
125
|
-
git push --tags
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
Add these repository secrets first, under **Settings → Secrets and variables → Actions**:
|
|
129
|
-
|
|
130
|
-
- `HARPER_CLI_TARGET` — your cluster's operations URL (e.g. `https://your-cluster.harperdb.io:9925`)
|
|
131
|
-
- `HARPER_CLI_REFRESH_TOKEN` — a long-lived token CI authenticates with, so no password is stored
|
|
132
|
-
|
|
133
|
-
Set both in one command — this pipes the credentials straight from your cluster into GitHub, so the token never appears on screen or in your shell history:
|
|
134
|
-
|
|
135
|
-
```sh
|
|
136
|
-
harper login --for-ci | gh secret set --env-file -
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
(No [`gh` CLI](https://cli.github.com)? `harper login --for-ci | pbcopy` copies the two lines for you to paste in by hand.)
|
|
140
|
-
|
|
141
|
-
The clone credential already lives in the cluster from `npm run deploy:setup`, so CI never handles a token itself.
|
|
142
|
-
|
|
143
|
-
### Private npm dependencies
|
|
144
|
-
|
|
145
|
-
If your app depends on private npm packages, run `npm run deploy:setup` again and choose the npm registry — the same sealed-token flow, stored as a separate credential.
|
|
146
|
-
|
|
147
99
|
## Keep Going!
|
|
148
100
|
|
|
149
101
|
For more information about getting started with Harper and building applications, see our [getting started guide](https://docs.harperdb.io/docs).
|