@harperfast/template-vue-studio 1.10.8 → 1.10.9
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 +95 -0
- package/.agents/skills/harper-best-practices/SKILL.md +1 -0
- package/.agents/skills/harper-best-practices/rules/v5-upgrade.md +107 -0
- package/.agents/skills/harper-best-practices/rules.manifest.yaml +20 -0
- package/agent/skills/harper-best-practices/AGENTS.md +95 -0
- package/agent/skills/harper-best-practices/SKILL.md +1 -0
- package/agent/skills/harper-best-practices/rules/v5-upgrade.md +107 -0
- package/agent/skills/harper-best-practices/rules.manifest.yaml +20 -0
- package/package.json +1 -1
- package/skills-lock.json +1 -1
|
@@ -2526,3 +2526,98 @@ loadEnv:
|
|
|
2526
2526
|
- Because Harper is a single-process application, variables loaded onto `process.env` are shared across all components.
|
|
2527
2527
|
- Without `override: true`, variables already set in the shell or container environment will not be overwritten by values in `.env` files.
|
|
2528
2528
|
- `files` is the only required option; omitting it will produce an invalid configuration.
|
|
2529
|
+
|
|
2530
|
+
### 4.7 Upgrading a Harper Application to v5
|
|
2531
|
+
|
|
2532
|
+
Instructions for the agent to follow when migrating an existing Harper application to version 5, addressing the breaking changes and adopting the recommended patterns.
|
|
2533
|
+
|
|
2534
|
+
#### When to Use
|
|
2535
|
+
|
|
2536
|
+
Apply this rule when upgrading a Harper application from v4.x (or earlier) to v5, or when code written against older APIs behaves differently after a v5 upgrade — for example a record that can no longer be mutated, a query that returns stale data, or a `spawn` call that now throws. Harper v5 introduces breaking changes; applications built on documented APIs need the updates below, while code relying on undocumented behavior or timing may need broader review.
|
|
2537
|
+
|
|
2538
|
+
#### How It Works
|
|
2539
|
+
|
|
2540
|
+
1. **Adopt the `harper` package name**: HarperDB is now Harper, and the package was renamed. Install the open source edition with `npm i -g harper` and the pro edition with `npm i -g @harperfast/harper-pro`. Update application imports from `harperdb` to `harper`:
|
|
2541
|
+
|
|
2542
|
+
```javascript
|
|
2543
|
+
import { tables } from 'harper';
|
|
2544
|
+
```
|
|
2545
|
+
|
|
2546
|
+
2. **Opt in to install scripts when required**: Harper now installs packages with `--ignore-scripts` to guard against accidental script execution, a common security risk. If an application genuinely needs install scripts to run (for example to build native binaries), pass the `allowInstallScripts` option when deploying.
|
|
2547
|
+
|
|
2548
|
+
3. **Update `Table.get` return-value handling**: `Table.get` now returns a plain, frozen record object rather than an instance of the table class, so instance methods are no longer available on the result. The commonly used `wasLoadedFromSource()` method is gone; cache-vs-origin information now lives on the request `target` as `target.loadedFromSource`. Pass a `RequestTarget` to `Table.get` and read the flag from it. Because the record is frozen, create a copy instead of mutating it in place.
|
|
2549
|
+
|
|
2550
|
+
4. **Account for automatic transaction context**: With RocksDB, transactions are fully supported by the storage engine, and Harper v5 uses asynchronous context tracking to carry the current transaction across calls automatically. A nested `Table.get` now reads within the current transaction's snapshot, so it will not observe newly written data until you commit. Access the context through `getContext()` and either commit the current transaction (`getContext().transaction.commit()`) or run the read inside a fresh `transaction(...)` to see the latest data. This matters most for code executing outside the context of a Harper request.
|
|
2551
|
+
|
|
2552
|
+
5. **Register spawnable commands**: Spawning processes is now tightly controlled. `spawn`, `exec`, and `execFile` may only run executables listed in the `applications.allowedSpawnCommands` configuration, and each call must pass a `name` in its `options` so that only a single named process is started across Harper's multiple threads. Use a distinct `name` when you deliberately need a separate process.
|
|
2553
|
+
|
|
2554
|
+
6. **Return Response-like objects to set headers**: If a REST method returns an object with a `headers` property, Harper uses it as the response headers.
|
|
2555
|
+
|
|
2556
|
+
7. **Replace `blob.save()`**: The `blob.save()` method has been removed. Pass the `saveBeforeCommit` flag in the options to the `Blob` constructor instead.
|
|
2557
|
+
|
|
2558
|
+
8. **Configure the VM module loader**: v5 loads application modules through Node.js's VM module API, giving each application its own module cache and an application-scoped `harper` module. All of this is controlled by the `applications` section of `harperdb-config.yaml`:
|
|
2559
|
+
- `moduleLoader` — `vm-current-context` (default), `vm`, `native`, or `compartment`. The default shares intrinsics with Harper for best compatibility; choose `vm` only if you need per-application intrinsics, and `native` to disable the VM loader entirely (restores pre-v5 loading, but per-app `logger`/`config` context is unavailable).
|
|
2560
|
+
- `lockdown` — `freeze-after-load` (default), `freeze`, `ses`, or `none`. Freezing intrinsics prevents prototype-pollution attacks; set `lockdown: none` only as a temporary workaround if a dependency mutates built-in prototypes.
|
|
2561
|
+
- `allowedDirectory` — `app` (default) restricts module loading to the application's own directory tree; set `any` if the app must load files from outside it in production.
|
|
2562
|
+
- `allowedBuiltinModules` — an optional allowlist restricting which Node.js built-ins the application may import (all are allowed if omitted).
|
|
2563
|
+
- `dependencyLoader` — `auto` (default), `app`, or `native`, controlling how npm dependencies are loaded through or around the VM loader.
|
|
2564
|
+
|
|
2565
|
+
#### Examples
|
|
2566
|
+
|
|
2567
|
+
**Updating `Table.get` and its cache check:**
|
|
2568
|
+
|
|
2569
|
+
```javascript
|
|
2570
|
+
// Old (v4.x)
|
|
2571
|
+
const record = await Table.get(id);
|
|
2572
|
+
if (record.wasLoadedFromSource()) {
|
|
2573
|
+
// loaded from origin, not cache
|
|
2574
|
+
}
|
|
2575
|
+
|
|
2576
|
+
// New (v5)
|
|
2577
|
+
const target = new RequestTarget(); // passed in when overriding `get`
|
|
2578
|
+
target.id = id;
|
|
2579
|
+
const record = await Table.get(target);
|
|
2580
|
+
if (target.loadedFromSource) {
|
|
2581
|
+
// loaded from origin, not cache
|
|
2582
|
+
}
|
|
2583
|
+
```
|
|
2584
|
+
|
|
2585
|
+
**Committing the transaction to read fresh data:**
|
|
2586
|
+
|
|
2587
|
+
```javascript
|
|
2588
|
+
import { setTimeout as delay } from 'node:timers/promises';
|
|
2589
|
+
import { getContext, transaction } from 'harper';
|
|
2590
|
+
|
|
2591
|
+
class MyResource {
|
|
2592
|
+
static async get(target) {
|
|
2593
|
+
// The current transaction is a consistent snapshot; commit it to see updates.
|
|
2594
|
+
await getContext().transaction.commit();
|
|
2595
|
+
while ((await transaction(() => Table.get(target))).status !== 'ready') {
|
|
2596
|
+
delay(100);
|
|
2597
|
+
}
|
|
2598
|
+
return Table.get(target);
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
```
|
|
2602
|
+
|
|
2603
|
+
**Module loader and security configuration in `harperdb-config.yaml`:**
|
|
2604
|
+
|
|
2605
|
+
```yaml
|
|
2606
|
+
applications:
|
|
2607
|
+
lockdown: freeze-after-load # default
|
|
2608
|
+
moduleLoader: vm-current-context # vm-current-context (default) | vm | native | compartment
|
|
2609
|
+
dependencyLoader: auto # auto (default) | app | native
|
|
2610
|
+
allowedDirectory: app # app (default) | any
|
|
2611
|
+
allowedSpawnCommands:
|
|
2612
|
+
- npm
|
|
2613
|
+
- node
|
|
2614
|
+
# allowedBuiltinModules: [] # if omitted, all Node.js built-ins are allowed
|
|
2615
|
+
```
|
|
2616
|
+
|
|
2617
|
+
#### Recommended Changes
|
|
2618
|
+
|
|
2619
|
+
Beyond the required fixes above, Harper v5 encourages these patterns for new and migrated code:
|
|
2620
|
+
|
|
2621
|
+
- Implement endpoints with `static` methods on Resources/Tables, reading request information from the request `target` argument (or from `getContext()`).
|
|
2622
|
+
- Rely on automatic context propagation rather than threading context through every call manually; access it via `getContext()` exported from `harper`.
|
|
2623
|
+
- Access Harper functions and APIs through the `harper` package rather than through global variables.
|
|
@@ -83,6 +83,7 @@ See the concrete examples embedded in each rule subsection below (GraphQL schema
|
|
|
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
85
|
- `load-env` — How to load environment variables from .env files into a Harper application using the loadEnv plugin.
|
|
86
|
+
- `v5-upgrade` — Breaking changes and recommended updates when migrating a Harper application to v5.
|
|
86
87
|
|
|
87
88
|
<!-- END GENERATED INDEX -->
|
|
88
89
|
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: v5-upgrade
|
|
3
|
+
description: >-
|
|
4
|
+
Breaking changes and recommended updates when migrating a Harper application
|
|
5
|
+
to v5.
|
|
6
|
+
metadata:
|
|
7
|
+
mode: generate
|
|
8
|
+
sources:
|
|
9
|
+
- release-notes/v5-lincoln/v5-migration.md
|
|
10
|
+
sourceCommit: de2aaf1c759a7ff5b93e862ba704153e2a392fcb
|
|
11
|
+
inputHash: 80314689f3a7f42e
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Upgrading a Harper Application to v5
|
|
15
|
+
|
|
16
|
+
Instructions for the agent to follow when migrating an existing Harper application to version 5, addressing the breaking changes and adopting the recommended patterns.
|
|
17
|
+
|
|
18
|
+
## When to Use
|
|
19
|
+
|
|
20
|
+
Apply this rule when upgrading a Harper application from v4.x (or earlier) to v5, or when code written against older APIs behaves differently after a v5 upgrade — for example a record that can no longer be mutated, a query that returns stale data, or a `spawn` call that now throws. Harper v5 introduces breaking changes; applications built on documented APIs need the updates below, while code relying on undocumented behavior or timing may need broader review.
|
|
21
|
+
|
|
22
|
+
## How It Works
|
|
23
|
+
|
|
24
|
+
1. **Adopt the `harper` package name**: HarperDB is now Harper, and the package was renamed. Install the open source edition with `npm i -g harper` and the pro edition with `npm i -g @harperfast/harper-pro`. Update application imports from `harperdb` to `harper`:
|
|
25
|
+
|
|
26
|
+
```javascript
|
|
27
|
+
import { tables } from 'harper';
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
2. **Opt in to install scripts when required**: Harper now installs packages with `--ignore-scripts` to guard against accidental script execution, a common security risk. If an application genuinely needs install scripts to run (for example to build native binaries), pass the `allowInstallScripts` option when deploying.
|
|
31
|
+
|
|
32
|
+
3. **Update `Table.get` return-value handling**: `Table.get` now returns a plain, frozen record object rather than an instance of the table class, so instance methods are no longer available on the result. The commonly used `wasLoadedFromSource()` method is gone; cache-vs-origin information now lives on the request `target` as `target.loadedFromSource`. Pass a `RequestTarget` to `Table.get` and read the flag from it. Because the record is frozen, create a copy instead of mutating it in place.
|
|
33
|
+
|
|
34
|
+
4. **Account for automatic transaction context**: With RocksDB, transactions are fully supported by the storage engine, and Harper v5 uses asynchronous context tracking to carry the current transaction across calls automatically. A nested `Table.get` now reads within the current transaction's snapshot, so it will not observe newly written data until you commit. Access the context through `getContext()` and either commit the current transaction (`getContext().transaction.commit()`) or run the read inside a fresh `transaction(...)` to see the latest data. This matters most for code executing outside the context of a Harper request.
|
|
35
|
+
|
|
36
|
+
5. **Register spawnable commands**: Spawning processes is now tightly controlled. `spawn`, `exec`, and `execFile` may only run executables listed in the `applications.allowedSpawnCommands` configuration, and each call must pass a `name` in its `options` so that only a single named process is started across Harper's multiple threads. Use a distinct `name` when you deliberately need a separate process.
|
|
37
|
+
|
|
38
|
+
6. **Return Response-like objects to set headers**: If a REST method returns an object with a `headers` property, Harper uses it as the response headers.
|
|
39
|
+
|
|
40
|
+
7. **Replace `blob.save()`**: The `blob.save()` method has been removed. Pass the `saveBeforeCommit` flag in the options to the `Blob` constructor instead.
|
|
41
|
+
|
|
42
|
+
8. **Configure the VM module loader**: v5 loads application modules through Node.js's VM module API, giving each application its own module cache and an application-scoped `harper` module. All of this is controlled by the `applications` section of `harperdb-config.yaml`:
|
|
43
|
+
- `moduleLoader` — `vm-current-context` (default), `vm`, `native`, or `compartment`. The default shares intrinsics with Harper for best compatibility; choose `vm` only if you need per-application intrinsics, and `native` to disable the VM loader entirely (restores pre-v5 loading, but per-app `logger`/`config` context is unavailable).
|
|
44
|
+
- `lockdown` — `freeze-after-load` (default), `freeze`, `ses`, or `none`. Freezing intrinsics prevents prototype-pollution attacks; set `lockdown: none` only as a temporary workaround if a dependency mutates built-in prototypes.
|
|
45
|
+
- `allowedDirectory` — `app` (default) restricts module loading to the application's own directory tree; set `any` if the app must load files from outside it in production.
|
|
46
|
+
- `allowedBuiltinModules` — an optional allowlist restricting which Node.js built-ins the application may import (all are allowed if omitted).
|
|
47
|
+
- `dependencyLoader` — `auto` (default), `app`, or `native`, controlling how npm dependencies are loaded through or around the VM loader.
|
|
48
|
+
|
|
49
|
+
## Examples
|
|
50
|
+
|
|
51
|
+
**Updating `Table.get` and its cache check:**
|
|
52
|
+
|
|
53
|
+
```javascript
|
|
54
|
+
// Old (v4.x)
|
|
55
|
+
const record = await Table.get(id);
|
|
56
|
+
if (record.wasLoadedFromSource()) {
|
|
57
|
+
// loaded from origin, not cache
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// New (v5)
|
|
61
|
+
const target = new RequestTarget(); // passed in when overriding `get`
|
|
62
|
+
target.id = id;
|
|
63
|
+
const record = await Table.get(target);
|
|
64
|
+
if (target.loadedFromSource) {
|
|
65
|
+
// loaded from origin, not cache
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Committing the transaction to read fresh data:**
|
|
70
|
+
|
|
71
|
+
```javascript
|
|
72
|
+
import { setTimeout as delay } from 'node:timers/promises';
|
|
73
|
+
import { getContext, transaction } from 'harper';
|
|
74
|
+
|
|
75
|
+
class MyResource {
|
|
76
|
+
static async get(target) {
|
|
77
|
+
// The current transaction is a consistent snapshot; commit it to see updates.
|
|
78
|
+
await getContext().transaction.commit();
|
|
79
|
+
while ((await transaction(() => Table.get(target))).status !== 'ready') {
|
|
80
|
+
delay(100);
|
|
81
|
+
}
|
|
82
|
+
return Table.get(target);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Module loader and security configuration in `harperdb-config.yaml`:**
|
|
88
|
+
|
|
89
|
+
```yaml
|
|
90
|
+
applications:
|
|
91
|
+
lockdown: freeze-after-load # default
|
|
92
|
+
moduleLoader: vm-current-context # vm-current-context (default) | vm | native | compartment
|
|
93
|
+
dependencyLoader: auto # auto (default) | app | native
|
|
94
|
+
allowedDirectory: app # app (default) | any
|
|
95
|
+
allowedSpawnCommands:
|
|
96
|
+
- npm
|
|
97
|
+
- node
|
|
98
|
+
# allowedBuiltinModules: [] # if omitted, all Node.js built-ins are allowed
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Recommended Changes
|
|
102
|
+
|
|
103
|
+
Beyond the required fixes above, Harper v5 encourages these patterns for new and migrated code:
|
|
104
|
+
|
|
105
|
+
- Implement endpoints with `static` methods on Resources/Tables, reading request information from the request `target` argument (or from `getContext()`).
|
|
106
|
+
- Rely on automatic context propagation rather than threading context through every call manually; access it via `getContext()` exported from `harper`.
|
|
107
|
+
- Access Harper functions and APIs through the `harper` package rather than through global variables.
|
|
@@ -402,3 +402,23 @@ rules:
|
|
|
402
402
|
- 'process.env'
|
|
403
403
|
- 'override'
|
|
404
404
|
- 'config.yaml'
|
|
405
|
+
|
|
406
|
+
- rule: v5-upgrade
|
|
407
|
+
description: Breaking changes and recommended updates when migrating a Harper application to v5.
|
|
408
|
+
category: ops
|
|
409
|
+
priority: 4
|
|
410
|
+
order: 7
|
|
411
|
+
mode: generate
|
|
412
|
+
sources:
|
|
413
|
+
- path: release-notes/v5-lincoln/v5-migration.md
|
|
414
|
+
role: primary
|
|
415
|
+
must_cover:
|
|
416
|
+
- "from 'harper'"
|
|
417
|
+
- 'allowInstallScripts'
|
|
418
|
+
- 'loadedFromSource'
|
|
419
|
+
- 'getContext'
|
|
420
|
+
- 'allowedSpawnCommands'
|
|
421
|
+
- 'saveBeforeCommit'
|
|
422
|
+
- 'moduleLoader'
|
|
423
|
+
- 'lockdown'
|
|
424
|
+
- 'Table.get'
|
|
@@ -2526,3 +2526,98 @@ loadEnv:
|
|
|
2526
2526
|
- Because Harper is a single-process application, variables loaded onto `process.env` are shared across all components.
|
|
2527
2527
|
- Without `override: true`, variables already set in the shell or container environment will not be overwritten by values in `.env` files.
|
|
2528
2528
|
- `files` is the only required option; omitting it will produce an invalid configuration.
|
|
2529
|
+
|
|
2530
|
+
### 4.7 Upgrading a Harper Application to v5
|
|
2531
|
+
|
|
2532
|
+
Instructions for the agent to follow when migrating an existing Harper application to version 5, addressing the breaking changes and adopting the recommended patterns.
|
|
2533
|
+
|
|
2534
|
+
#### When to Use
|
|
2535
|
+
|
|
2536
|
+
Apply this rule when upgrading a Harper application from v4.x (or earlier) to v5, or when code written against older APIs behaves differently after a v5 upgrade — for example a record that can no longer be mutated, a query that returns stale data, or a `spawn` call that now throws. Harper v5 introduces breaking changes; applications built on documented APIs need the updates below, while code relying on undocumented behavior or timing may need broader review.
|
|
2537
|
+
|
|
2538
|
+
#### How It Works
|
|
2539
|
+
|
|
2540
|
+
1. **Adopt the `harper` package name**: HarperDB is now Harper, and the package was renamed. Install the open source edition with `npm i -g harper` and the pro edition with `npm i -g @harperfast/harper-pro`. Update application imports from `harperdb` to `harper`:
|
|
2541
|
+
|
|
2542
|
+
```javascript
|
|
2543
|
+
import { tables } from 'harper';
|
|
2544
|
+
```
|
|
2545
|
+
|
|
2546
|
+
2. **Opt in to install scripts when required**: Harper now installs packages with `--ignore-scripts` to guard against accidental script execution, a common security risk. If an application genuinely needs install scripts to run (for example to build native binaries), pass the `allowInstallScripts` option when deploying.
|
|
2547
|
+
|
|
2548
|
+
3. **Update `Table.get` return-value handling**: `Table.get` now returns a plain, frozen record object rather than an instance of the table class, so instance methods are no longer available on the result. The commonly used `wasLoadedFromSource()` method is gone; cache-vs-origin information now lives on the request `target` as `target.loadedFromSource`. Pass a `RequestTarget` to `Table.get` and read the flag from it. Because the record is frozen, create a copy instead of mutating it in place.
|
|
2549
|
+
|
|
2550
|
+
4. **Account for automatic transaction context**: With RocksDB, transactions are fully supported by the storage engine, and Harper v5 uses asynchronous context tracking to carry the current transaction across calls automatically. A nested `Table.get` now reads within the current transaction's snapshot, so it will not observe newly written data until you commit. Access the context through `getContext()` and either commit the current transaction (`getContext().transaction.commit()`) or run the read inside a fresh `transaction(...)` to see the latest data. This matters most for code executing outside the context of a Harper request.
|
|
2551
|
+
|
|
2552
|
+
5. **Register spawnable commands**: Spawning processes is now tightly controlled. `spawn`, `exec`, and `execFile` may only run executables listed in the `applications.allowedSpawnCommands` configuration, and each call must pass a `name` in its `options` so that only a single named process is started across Harper's multiple threads. Use a distinct `name` when you deliberately need a separate process.
|
|
2553
|
+
|
|
2554
|
+
6. **Return Response-like objects to set headers**: If a REST method returns an object with a `headers` property, Harper uses it as the response headers.
|
|
2555
|
+
|
|
2556
|
+
7. **Replace `blob.save()`**: The `blob.save()` method has been removed. Pass the `saveBeforeCommit` flag in the options to the `Blob` constructor instead.
|
|
2557
|
+
|
|
2558
|
+
8. **Configure the VM module loader**: v5 loads application modules through Node.js's VM module API, giving each application its own module cache and an application-scoped `harper` module. All of this is controlled by the `applications` section of `harperdb-config.yaml`:
|
|
2559
|
+
- `moduleLoader` — `vm-current-context` (default), `vm`, `native`, or `compartment`. The default shares intrinsics with Harper for best compatibility; choose `vm` only if you need per-application intrinsics, and `native` to disable the VM loader entirely (restores pre-v5 loading, but per-app `logger`/`config` context is unavailable).
|
|
2560
|
+
- `lockdown` — `freeze-after-load` (default), `freeze`, `ses`, or `none`. Freezing intrinsics prevents prototype-pollution attacks; set `lockdown: none` only as a temporary workaround if a dependency mutates built-in prototypes.
|
|
2561
|
+
- `allowedDirectory` — `app` (default) restricts module loading to the application's own directory tree; set `any` if the app must load files from outside it in production.
|
|
2562
|
+
- `allowedBuiltinModules` — an optional allowlist restricting which Node.js built-ins the application may import (all are allowed if omitted).
|
|
2563
|
+
- `dependencyLoader` — `auto` (default), `app`, or `native`, controlling how npm dependencies are loaded through or around the VM loader.
|
|
2564
|
+
|
|
2565
|
+
#### Examples
|
|
2566
|
+
|
|
2567
|
+
**Updating `Table.get` and its cache check:**
|
|
2568
|
+
|
|
2569
|
+
```javascript
|
|
2570
|
+
// Old (v4.x)
|
|
2571
|
+
const record = await Table.get(id);
|
|
2572
|
+
if (record.wasLoadedFromSource()) {
|
|
2573
|
+
// loaded from origin, not cache
|
|
2574
|
+
}
|
|
2575
|
+
|
|
2576
|
+
// New (v5)
|
|
2577
|
+
const target = new RequestTarget(); // passed in when overriding `get`
|
|
2578
|
+
target.id = id;
|
|
2579
|
+
const record = await Table.get(target);
|
|
2580
|
+
if (target.loadedFromSource) {
|
|
2581
|
+
// loaded from origin, not cache
|
|
2582
|
+
}
|
|
2583
|
+
```
|
|
2584
|
+
|
|
2585
|
+
**Committing the transaction to read fresh data:**
|
|
2586
|
+
|
|
2587
|
+
```javascript
|
|
2588
|
+
import { setTimeout as delay } from 'node:timers/promises';
|
|
2589
|
+
import { getContext, transaction } from 'harper';
|
|
2590
|
+
|
|
2591
|
+
class MyResource {
|
|
2592
|
+
static async get(target) {
|
|
2593
|
+
// The current transaction is a consistent snapshot; commit it to see updates.
|
|
2594
|
+
await getContext().transaction.commit();
|
|
2595
|
+
while ((await transaction(() => Table.get(target))).status !== 'ready') {
|
|
2596
|
+
delay(100);
|
|
2597
|
+
}
|
|
2598
|
+
return Table.get(target);
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
```
|
|
2602
|
+
|
|
2603
|
+
**Module loader and security configuration in `harperdb-config.yaml`:**
|
|
2604
|
+
|
|
2605
|
+
```yaml
|
|
2606
|
+
applications:
|
|
2607
|
+
lockdown: freeze-after-load # default
|
|
2608
|
+
moduleLoader: vm-current-context # vm-current-context (default) | vm | native | compartment
|
|
2609
|
+
dependencyLoader: auto # auto (default) | app | native
|
|
2610
|
+
allowedDirectory: app # app (default) | any
|
|
2611
|
+
allowedSpawnCommands:
|
|
2612
|
+
- npm
|
|
2613
|
+
- node
|
|
2614
|
+
# allowedBuiltinModules: [] # if omitted, all Node.js built-ins are allowed
|
|
2615
|
+
```
|
|
2616
|
+
|
|
2617
|
+
#### Recommended Changes
|
|
2618
|
+
|
|
2619
|
+
Beyond the required fixes above, Harper v5 encourages these patterns for new and migrated code:
|
|
2620
|
+
|
|
2621
|
+
- Implement endpoints with `static` methods on Resources/Tables, reading request information from the request `target` argument (or from `getContext()`).
|
|
2622
|
+
- Rely on automatic context propagation rather than threading context through every call manually; access it via `getContext()` exported from `harper`.
|
|
2623
|
+
- Access Harper functions and APIs through the `harper` package rather than through global variables.
|
|
@@ -76,6 +76,7 @@ See the concrete examples embedded in each rule subsection below (GraphQL schema
|
|
|
76
76
|
- `serving-web-content` — How to serve static files and integrated Vite/React applications in Harper.
|
|
77
77
|
- `logging` — Best practices for logging in Harper, including console capture, the granular logger interface, and programmatic log retrieval.
|
|
78
78
|
- `load-env` — How to load environment variables from .env files into a Harper application using the loadEnv plugin.
|
|
79
|
+
- `v5-upgrade` — Breaking changes and recommended updates when migrating a Harper application to v5.
|
|
79
80
|
|
|
80
81
|
<!-- END GENERATED INDEX -->
|
|
81
82
|
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: v5-upgrade
|
|
3
|
+
description: >-
|
|
4
|
+
Breaking changes and recommended updates when migrating a Harper application
|
|
5
|
+
to v5.
|
|
6
|
+
metadata:
|
|
7
|
+
mode: generate
|
|
8
|
+
sources:
|
|
9
|
+
- release-notes/v5-lincoln/v5-migration.md
|
|
10
|
+
sourceCommit: de2aaf1c759a7ff5b93e862ba704153e2a392fcb
|
|
11
|
+
inputHash: 80314689f3a7f42e
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Upgrading a Harper Application to v5
|
|
15
|
+
|
|
16
|
+
Instructions for the agent to follow when migrating an existing Harper application to version 5, addressing the breaking changes and adopting the recommended patterns.
|
|
17
|
+
|
|
18
|
+
## When to Use
|
|
19
|
+
|
|
20
|
+
Apply this rule when upgrading a Harper application from v4.x (or earlier) to v5, or when code written against older APIs behaves differently after a v5 upgrade — for example a record that can no longer be mutated, a query that returns stale data, or a `spawn` call that now throws. Harper v5 introduces breaking changes; applications built on documented APIs need the updates below, while code relying on undocumented behavior or timing may need broader review.
|
|
21
|
+
|
|
22
|
+
## How It Works
|
|
23
|
+
|
|
24
|
+
1. **Adopt the `harper` package name**: HarperDB is now Harper, and the package was renamed. Install the open source edition with `npm i -g harper` and the pro edition with `npm i -g @harperfast/harper-pro`. Update application imports from `harperdb` to `harper`:
|
|
25
|
+
|
|
26
|
+
```javascript
|
|
27
|
+
import { tables } from 'harper';
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
2. **Opt in to install scripts when required**: Harper now installs packages with `--ignore-scripts` to guard against accidental script execution, a common security risk. If an application genuinely needs install scripts to run (for example to build native binaries), pass the `allowInstallScripts` option when deploying.
|
|
31
|
+
|
|
32
|
+
3. **Update `Table.get` return-value handling**: `Table.get` now returns a plain, frozen record object rather than an instance of the table class, so instance methods are no longer available on the result. The commonly used `wasLoadedFromSource()` method is gone; cache-vs-origin information now lives on the request `target` as `target.loadedFromSource`. Pass a `RequestTarget` to `Table.get` and read the flag from it. Because the record is frozen, create a copy instead of mutating it in place.
|
|
33
|
+
|
|
34
|
+
4. **Account for automatic transaction context**: With RocksDB, transactions are fully supported by the storage engine, and Harper v5 uses asynchronous context tracking to carry the current transaction across calls automatically. A nested `Table.get` now reads within the current transaction's snapshot, so it will not observe newly written data until you commit. Access the context through `getContext()` and either commit the current transaction (`getContext().transaction.commit()`) or run the read inside a fresh `transaction(...)` to see the latest data. This matters most for code executing outside the context of a Harper request.
|
|
35
|
+
|
|
36
|
+
5. **Register spawnable commands**: Spawning processes is now tightly controlled. `spawn`, `exec`, and `execFile` may only run executables listed in the `applications.allowedSpawnCommands` configuration, and each call must pass a `name` in its `options` so that only a single named process is started across Harper's multiple threads. Use a distinct `name` when you deliberately need a separate process.
|
|
37
|
+
|
|
38
|
+
6. **Return Response-like objects to set headers**: If a REST method returns an object with a `headers` property, Harper uses it as the response headers.
|
|
39
|
+
|
|
40
|
+
7. **Replace `blob.save()`**: The `blob.save()` method has been removed. Pass the `saveBeforeCommit` flag in the options to the `Blob` constructor instead.
|
|
41
|
+
|
|
42
|
+
8. **Configure the VM module loader**: v5 loads application modules through Node.js's VM module API, giving each application its own module cache and an application-scoped `harper` module. All of this is controlled by the `applications` section of `harperdb-config.yaml`:
|
|
43
|
+
- `moduleLoader` — `vm-current-context` (default), `vm`, `native`, or `compartment`. The default shares intrinsics with Harper for best compatibility; choose `vm` only if you need per-application intrinsics, and `native` to disable the VM loader entirely (restores pre-v5 loading, but per-app `logger`/`config` context is unavailable).
|
|
44
|
+
- `lockdown` — `freeze-after-load` (default), `freeze`, `ses`, or `none`. Freezing intrinsics prevents prototype-pollution attacks; set `lockdown: none` only as a temporary workaround if a dependency mutates built-in prototypes.
|
|
45
|
+
- `allowedDirectory` — `app` (default) restricts module loading to the application's own directory tree; set `any` if the app must load files from outside it in production.
|
|
46
|
+
- `allowedBuiltinModules` — an optional allowlist restricting which Node.js built-ins the application may import (all are allowed if omitted).
|
|
47
|
+
- `dependencyLoader` — `auto` (default), `app`, or `native`, controlling how npm dependencies are loaded through or around the VM loader.
|
|
48
|
+
|
|
49
|
+
## Examples
|
|
50
|
+
|
|
51
|
+
**Updating `Table.get` and its cache check:**
|
|
52
|
+
|
|
53
|
+
```javascript
|
|
54
|
+
// Old (v4.x)
|
|
55
|
+
const record = await Table.get(id);
|
|
56
|
+
if (record.wasLoadedFromSource()) {
|
|
57
|
+
// loaded from origin, not cache
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// New (v5)
|
|
61
|
+
const target = new RequestTarget(); // passed in when overriding `get`
|
|
62
|
+
target.id = id;
|
|
63
|
+
const record = await Table.get(target);
|
|
64
|
+
if (target.loadedFromSource) {
|
|
65
|
+
// loaded from origin, not cache
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Committing the transaction to read fresh data:**
|
|
70
|
+
|
|
71
|
+
```javascript
|
|
72
|
+
import { setTimeout as delay } from 'node:timers/promises';
|
|
73
|
+
import { getContext, transaction } from 'harper';
|
|
74
|
+
|
|
75
|
+
class MyResource {
|
|
76
|
+
static async get(target) {
|
|
77
|
+
// The current transaction is a consistent snapshot; commit it to see updates.
|
|
78
|
+
await getContext().transaction.commit();
|
|
79
|
+
while ((await transaction(() => Table.get(target))).status !== 'ready') {
|
|
80
|
+
delay(100);
|
|
81
|
+
}
|
|
82
|
+
return Table.get(target);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Module loader and security configuration in `harperdb-config.yaml`:**
|
|
88
|
+
|
|
89
|
+
```yaml
|
|
90
|
+
applications:
|
|
91
|
+
lockdown: freeze-after-load # default
|
|
92
|
+
moduleLoader: vm-current-context # vm-current-context (default) | vm | native | compartment
|
|
93
|
+
dependencyLoader: auto # auto (default) | app | native
|
|
94
|
+
allowedDirectory: app # app (default) | any
|
|
95
|
+
allowedSpawnCommands:
|
|
96
|
+
- npm
|
|
97
|
+
- node
|
|
98
|
+
# allowedBuiltinModules: [] # if omitted, all Node.js built-ins are allowed
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Recommended Changes
|
|
102
|
+
|
|
103
|
+
Beyond the required fixes above, Harper v5 encourages these patterns for new and migrated code:
|
|
104
|
+
|
|
105
|
+
- Implement endpoints with `static` methods on Resources/Tables, reading request information from the request `target` argument (or from `getContext()`).
|
|
106
|
+
- Rely on automatic context propagation rather than threading context through every call manually; access it via `getContext()` exported from `harper`.
|
|
107
|
+
- Access Harper functions and APIs through the `harper` package rather than through global variables.
|
|
@@ -402,3 +402,23 @@ rules:
|
|
|
402
402
|
- 'process.env'
|
|
403
403
|
- 'override'
|
|
404
404
|
- 'config.yaml'
|
|
405
|
+
|
|
406
|
+
- rule: v5-upgrade
|
|
407
|
+
description: Breaking changes and recommended updates when migrating a Harper application to v5.
|
|
408
|
+
category: ops
|
|
409
|
+
priority: 4
|
|
410
|
+
order: 7
|
|
411
|
+
mode: generate
|
|
412
|
+
sources:
|
|
413
|
+
- path: release-notes/v5-lincoln/v5-migration.md
|
|
414
|
+
role: primary
|
|
415
|
+
must_cover:
|
|
416
|
+
- "from 'harper'"
|
|
417
|
+
- 'allowInstallScripts'
|
|
418
|
+
- 'loadedFromSource'
|
|
419
|
+
- 'getContext'
|
|
420
|
+
- 'allowedSpawnCommands'
|
|
421
|
+
- 'saveBeforeCommit'
|
|
422
|
+
- 'moduleLoader'
|
|
423
|
+
- 'lockdown'
|
|
424
|
+
- 'Table.get'
|
package/package.json
CHANGED
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": "
|
|
8
|
+
"computedHash": "2293a12dd5c59704c4d6ea0a6c54314a9c31af2d06015ddb63dcb6dbee5f8b79"
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
11
|
}
|