@harperfast/template-react-studio 1.2.2 → 1.3.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.
Files changed (42) hide show
  1. package/.agents/skills/harper-best-practices/AGENTS.md +284 -0
  2. package/.agents/skills/harper-best-practices/SKILL.md +90 -0
  3. package/.agents/skills/harper-best-practices/rules/adding-tables-with-schemas.md +40 -0
  4. package/.agents/skills/harper-best-practices/rules/automatic-apis.md +34 -0
  5. package/.agents/skills/harper-best-practices/rules/caching.md +46 -0
  6. package/.agents/skills/harper-best-practices/rules/checking-authentication.md +165 -0
  7. package/.agents/skills/harper-best-practices/rules/creating-harper-apps.md +46 -0
  8. package/.agents/skills/harper-best-practices/rules/custom-resources.md +35 -0
  9. package/.agents/skills/harper-best-practices/rules/defining-relationships.md +33 -0
  10. package/.agents/skills/harper-best-practices/rules/deploying-to-harper-fabric.md +24 -0
  11. package/.agents/skills/harper-best-practices/rules/extending-tables.md +37 -0
  12. package/.agents/skills/harper-best-practices/rules/handling-binary-data.md +43 -0
  13. package/.agents/skills/harper-best-practices/rules/programmatic-table-requests.md +39 -0
  14. package/.agents/skills/harper-best-practices/rules/querying-rest-apis.md +22 -0
  15. package/.agents/skills/harper-best-practices/rules/real-time-apps.md +37 -0
  16. package/.agents/skills/harper-best-practices/rules/serving-web-content.md +34 -0
  17. package/.agents/skills/harper-best-practices/rules/typescript-type-stripping.md +32 -0
  18. package/.agents/skills/harper-best-practices/rules/using-blob-datatype.md +36 -0
  19. package/.agents/skills/harper-best-practices/rules/vector-indexing.md +152 -0
  20. package/README.md +1 -1
  21. package/package.json +1 -1
  22. package/resources/README.md +3 -3
  23. package/schemas/README.md +2 -2
  24. package/skills-lock.json +10 -0
  25. package/AGENTS.md +0 -22
  26. package/skills/adding-tables-with-schemas.md +0 -34
  27. package/skills/automatic-apis.md +0 -53
  28. package/skills/automatic-rest-apis.md +0 -41
  29. package/skills/caching.md +0 -113
  30. package/skills/checking-authentication.md +0 -281
  31. package/skills/custom-resources.md +0 -86
  32. package/skills/defining-relationships.md +0 -71
  33. package/skills/deploying-to-harper-fabric.md +0 -20
  34. package/skills/extending-tables.md +0 -70
  35. package/skills/handling-binary-data.md +0 -67
  36. package/skills/programmatic-table-requests.md +0 -185
  37. package/skills/querying-rest-apis.md +0 -69
  38. package/skills/real-time-apps.md +0 -75
  39. package/skills/serving-web-content.md +0 -82
  40. package/skills/typescript-type-stripping.md +0 -47
  41. package/skills/using-blob-datatype.md +0 -131
  42. package/skills/vector-indexing.md +0 -215
@@ -1,20 +0,0 @@
1
- # Deploying to Harper Fabric
2
-
3
- To deploy your application to Harper Fabric, follow these steps:
4
-
5
- 1. **Sign up**: Create an account at [https://fabric.harper.fast](https://fabric.harper.fast) and create a cluster.
6
-
7
- 2. **Configure Environment**: Add your credentials and cluster URL to your `.env` file:
8
- ```bash
9
- # Deployments
10
- CLI_TARGET_USERNAME='YOUR_CLUSTER_USERNAME'
11
- CLI_TARGET_PASSWORD='YOUR_CLUSTER_PASSWORD'
12
- CLI_TARGET='YOUR_FABRIC.HARPER.FAST_CLUSTER_URL_HERE'
13
- ```
14
-
15
- 3. **Deploy Locally**: Run the following command to deploy from your local environment:
16
- ```bash
17
- npm run deploy
18
- ```
19
-
20
- 4. **Set up CI/CD**: Customize the included `.github/workflow/deploy.yaml` file and define your secrets in your GitHub repository's action settings to enable continuous deployment.
@@ -1,70 +0,0 @@
1
- # Extending Table Resources in Harper
2
-
3
- In Harper, when you define a table in GraphQL and export it, you can extend the automatically generated resource class to add custom logic, validation, or hooks to standard CRUD operations.
4
-
5
- ## Do you need to extend tables?
6
-
7
- Exported tables have [automatic APIs](./automatic-apis.md) as a part of them. These APIs may be sufficient for what you need.
8
-
9
- ## How to Extend a Table Resource
10
-
11
- 1. Identify the table you want to extend (e.g., `ExamplePeople`).
12
- 2. Create a TypeScript file in your `resources/` folder.
13
- 3. Export a class that extends `tables.YourTableName`.
14
- 4. Override the desired methods (e.g., `post`, `get`, `put`, `patch`, `delete`).
15
-
16
- ### Example: `resources/examplePeople.ts`
17
-
18
- ```typescript
19
- import { type RequestTargetOrId, tables } from 'harperdb';
20
-
21
- export interface ExamplePerson {
22
- id: string;
23
- name: string;
24
- tag: string;
25
- }
26
-
27
- // Extend the automatically generated table resource
28
- export class ExamplePeople extends tables.ExamplePeople<ExamplePerson> {
29
- // Override the custom POST handler
30
- async post(target: RequestTargetOrId, newRecord: Omit<ExamplePerson, 'id'>) {
31
- // Add custom validation or transformation logic
32
- if (!newRecord.name) {
33
- throw new Error('Name is required');
34
- }
35
-
36
- console.log(`Adding new person: ${newRecord.name}`);
37
-
38
- // Call the super method to perform the actual insertion
39
- return super.post(target, newRecord);
40
- }
41
-
42
- // Override the custom GET handler
43
- async get(target: RequestTargetOrId) {
44
- const record = await super.get(target);
45
- // Modify the record before returning if necessary
46
- return record;
47
- }
48
- }
49
- ```
50
-
51
- ## Why Extend Tables?
52
-
53
- - **Validation**: Ensure data meets specific criteria before it's saved to the database.
54
- - **Side Effects**: Send an email, trigger a webhook, or log an event when a record is created or updated.
55
- - **Data Transformation**: Format or enrich data before it's returned to the client.
56
- - **Access Control**: Add custom logic to determine if a user has permission to access or modify a specific record.
57
-
58
- ## Important Note
59
-
60
- When you extend a table resource, Harper uses your custom class for all REST API interactions with that table. Make sure to call `super[method]` if you still want the default behavior to occur after your custom logic.
61
-
62
- Extended tables do not need to be `@export`ed in their schema .graphql.
63
-
64
- ```graphql
65
- type ExamplePerson @table {
66
- id: ID @primaryKey
67
- name: String
68
- tag: String @indexed
69
- }
70
- ```
@@ -1,67 +0,0 @@
1
- # Handling Binary Data in Harper
2
-
3
- When working with binary data (such as images or audio files) in Harper, you often receive this data as base64-encoded strings through JSON REST APIs. To store this data efficiently in a `Blob` field, you should convert it to a `Buffer`.
4
-
5
- ## Storing Base64 Strings as Buffers
6
-
7
- In a custom resource or a table resource override, you can intercept the incoming record and convert base64 strings to buffers before saving them to the database.
8
-
9
- ### Example
10
-
11
- Suppose you have a table with a `Blob` field named `data`. You can use `Buffer.from(string, 'base64')` to perform the conversion to a buffer, and then use Harper's `createBlob` function to turn that buffer into a blob with a type such as `{ type: 'image/jpeg' }`.
12
-
13
- ```typescript
14
- import { RequestTargetOrId, Resource } from 'harperdb';
15
-
16
- export class MyResource extends Resource {
17
- async post(target: RequestTargetOrId, record: any) {
18
- if (record.data) {
19
- // Convert base64-encoded string to a Buffer
20
- record.data = createBlob(Buffer.from(record.artwork, 'base64'), {
21
- type: 'image/jpeg',
22
- });
23
- }
24
- // Call the super method to perform the actual storage
25
- return super.post(target, record);
26
- }
27
- }
28
- ```
29
-
30
- ## Responding with Binary Data
31
-
32
- When you want to serve binary data (like an image or an MP3 file) back to the client, you can return a response object from your resource's `get` method. This object should include the appropriate `status`, `headers`, and the binary data itself in the `body`.
33
-
34
- ### Example: Responding with a JPEG File
35
-
36
- In this example, we retrieve a thumbnail from the database. If it contains binary data in the `data` field, we return it with the `image/jpeg` content type.
37
-
38
- ```typescript
39
- import { RequestTarget, RequestTargetOrId, Resource } from 'harperdb';
40
-
41
- export class TrackResource extends Resource {
42
- async get(target: RequestTargetOrId) {
43
- const id = (target as RequestTarget)?.id;
44
- if (!id) {
45
- return super.get(target);
46
- }
47
- const thumbnail = await super.get(target);
48
- if (thumbnail?.data) {
49
- return {
50
- status: 200,
51
- headers: {
52
- 'Content-Type': 'image/jpeg',
53
- 'Content-Disposition': `inline; filename="${thumbnail.name}.jpg"`,
54
- },
55
- body: thumbnail.data,
56
- };
57
- }
58
- return thumbnail;
59
- }
60
- }
61
- ```
62
-
63
- ## Why Use Blobs?
64
-
65
- - **Efficiency**: `Blob` fields are optimized for storing binary data. Buffers are the standard way to handle binary data in Node.js.
66
- - **Compatibility**: Many Harper features and external libraries expect binary data to be in `Buffer` or `Uint8Array` format.
67
- - **Storage**: Storing data as binary is more compact than storing it as a base64-encoded string.
@@ -1,185 +0,0 @@
1
- # Programmatic Requests with Harper Tables
2
-
3
- In Harper, you can interact with your database tables programmatically using the global `tables` object. Each table defined in your schema is available as a property on this object.
4
-
5
- ## Basic Usage
6
-
7
- The `tables` object provides a direct way to perform CRUD operations from within your Harper resources or scripts.
8
-
9
- ```typescript
10
- const track = await tables.ExamplePeople.get(id) as ExamplePerson;
11
- ```
12
-
13
- ## Available Methods
14
-
15
- The following methods are available on each table object:
16
-
17
- ### `get(idOrQuery)`
18
-
19
- Retrieves a single record by ID or multiple records matching a query.
20
-
21
- - **By ID**:
22
- ```typescript
23
- const person = await tables.ExamplePeople.get('person-123');
24
- ```
25
- - **By Query**:
26
- ```typescript
27
- const albums = await tables.ExamplePeople.get({
28
- conditions: [{ attribute: 'name', value: 'John' }],
29
- });
30
- ```
31
-
32
- ### `put(id, record)`
33
-
34
- Replaces an entire record with the provided data. If the record doesn't exist, it will be created.
35
-
36
- ```typescript
37
- await tables.ExamplePeople.put('person-123', {
38
- name: 'Michael Jackson',
39
- tag: 'entertainer',
40
- });
41
- ```
42
-
43
- ### `patch(id, partialRecord)`
44
-
45
- Performs a partial update on a record. Only the specified fields will be updated.
46
-
47
- ```typescript
48
- await tables.ExamplePeople.patch('person-123', {
49
- tag: 'tragedy',
50
- });
51
- ```
52
-
53
- ### `delete(idOrQuery)`
54
-
55
- Deletes a record by ID or multiple records matching a query.
56
-
57
- ```typescript
58
- await tables.ExamplePeople.delete('person-123');
59
- ```
60
-
61
- ### `post(record)`
62
-
63
- Creates a new record. Use this when you want the database to auto-generate a primary key.
64
-
65
- ```typescript
66
- const newAlbum = await tables.ExamplePeople.post({
67
- name: 'John Smith',
68
- tag: 'anonymous',
69
- });
70
- ```
71
-
72
- ### `update(id, updates)`
73
-
74
- The `update` method is a versatile tool for modifying records. While it can perform simple partial updates like `patch`, its primary power lies in its ability to return an **Updatable Record** object for complex or atomic operations.
75
-
76
- #### Partial Update (like `patch`)
77
-
78
- When called with both an ID and an update object, it performs a partial update:
79
-
80
- ```typescript
81
- await tables.ExamplePeople.update('person-123', {
82
- name: 'Updated Name',
83
- });
84
- ```
85
-
86
- #### Getting an Updatable Record
87
-
88
- When called without an update object (only an ID), `update` returns a reference to the record that can be modified directly.
89
-
90
- ```typescript
91
- const person = await tables.ExamplePeople.update('person-123');
92
- person.name = 'New Person Name';
93
- // Properties can be assigned directly and are tracked
94
- ```
95
-
96
- #### Atomic Operations
97
-
98
- Updatable records provide methods for safe, atomic modifications, which are essential for avoiding race conditions during increments or decrements:
99
-
100
- - `addTo(attribute, value)`: Atomically adds to a numeric value.
101
- - `subtractFrom(attribute, value)`: Atomically subtracts from a numeric value.
102
-
103
- ```typescript
104
- const stats = await tables.Stats.update('daily');
105
- stats.addTo('viewCount', 1);
106
- ```
107
-
108
- #### Update without an ID or with Context
109
-
110
- Calling `update()` without an ID can be used when the target is implied by the context (e.g., inside a resource method) or when you want to get an updatable reference to a collection.
111
-
112
- ```typescript
113
- // Inside a custom resource method
114
- const record = await this.update();
115
- record.set('status', 'processed');
116
-
117
- // Passing specific context (like a transaction)
118
- const person = await tables.ExamplePeople.update('person-123', null, {
119
- transaction,
120
- });
121
- person.addTo('playCount', 1);
122
- ```
123
-
124
- ### `search(query)`
125
-
126
- Performs a search based on the provided query criteria. It returns an `AsyncIterable` which is efficient for streaming large result sets.
127
-
128
- ```typescript
129
- const results = await tables.ExamplePeople.search({
130
- conditions: [{ attribute: 'artist', value: 'Michael Jackson' }],
131
- });
132
-
133
- for await (const person of results) {
134
- console.log(person.name);
135
- }
136
- ```
137
-
138
- ### `subscribe(query)`
139
-
140
- Subscribes to real-time changes in the table. You can provide a query to filter which changes trigger a notification.
141
-
142
- ```typescript
143
- const subscription = await tables.ExamplePeople.subscribe({
144
- conditions: [{ attribute: 'name', value: 'Thriller' }],
145
- });
146
-
147
- for await (const event of subscription) {
148
- console.log('Record changed:', event.value);
149
- }
150
- ```
151
-
152
- ### `publish(id, message)`
153
-
154
- Publishes a message to a specific record or topic. This triggers any active subscriptions without necessarily persisting data to the table.
155
-
156
- ```typescript
157
- await tables.ExamplePeople.publish('person-123', {
158
- type: 'REVALIDATE',
159
- timestamp: Date.now(),
160
- });
161
- ```
162
-
163
- ## Querying Options
164
-
165
- Many methods accept a `Query` (or `RequestTarget`) object. Common options include:
166
-
167
- - `conditions`: Array of filter conditions.
168
- - `limit`: Number of records to return.
169
- - `offset`: Number of records to skip.
170
- - `sort`: Attribute and direction for sorting.
171
- - `select`: Array of specific attributes to return.
172
-
173
- Example of a complex query:
174
-
175
- ```typescript
176
- const recentAlbums = await tables.ExamplePeople.get({
177
- conditions: [{
178
- attribute: 'releaseDate',
179
- comparator: 'ge',
180
- value: '2020-01-01',
181
- }],
182
- sort: { attribute: 'releaseDate', descending: true },
183
- limit: 10,
184
- });
185
- ```
@@ -1,69 +0,0 @@
1
- # Querying through REST APIs in Harper
2
-
3
- Harper's automatic REST APIs support powerful querying capabilities directly through URL query parameters. This allows you to filter, sort, paginate, and join data without writing complex queries.
4
-
5
- ## Basic Filtering
6
-
7
- The simplest way to filter is by using attribute names as query parameters:
8
-
9
- `GET /ExamplePeople/?tag=friend`
10
-
11
- This returns all records where `tag` equals `friend`.
12
-
13
- ## Comparison Operators (FIQL-style)
14
-
15
- You can use standard comparison operators by appending them to the attribute name with an `=` sign:
16
-
17
- - `gt`: Greater than
18
- - `ge`: Greater than or equal to
19
- - `lt`: Less than
20
- - `le`: Less than or equal to
21
- - `ne`: Not equal
22
-
23
- Example:
24
- `GET /Products/?price=gt=100&price=lt=200`
25
-
26
- ## Logic Operators
27
-
28
- - **AND**: Use the `&` operator (default).
29
- - **OR**: Use the `|` operator.
30
-
31
- Example:
32
- `GET /Products/?rating=5|featured=true`
33
-
34
- ## Grouping
35
-
36
- Use parentheses `()` to group conditions and indicate order of operations.
37
-
38
- Example:
39
- `GET /Products/?(rating=5|featured=true)&price=lt=50`
40
-
41
- ## Selection
42
-
43
- Use `select()` to limit the returned fields:
44
-
45
- `GET /Products/?select(name,price)`
46
-
47
- ## Pagination
48
-
49
- Use `limit(start, end)` or `limit(end)`:
50
-
51
- - `limit(10)`: Returns the first 10 records.
52
- - `limit(20, 10)`: Skips the first 20 records and returns the next 10.
53
-
54
- Example:
55
- `GET /Products/?limit(0,20)`
56
-
57
- ## Sorting
58
-
59
- Use `sort()` with `+` (ascending) or `-` (descending) prefixes:
60
-
61
- `GET /Products/?sort(+price,-rating)`
62
-
63
- ## Joins and Chained Attributes
64
-
65
- If you have defined relationships in your schema using the `@relationship` directive, you can use dot syntax to query across tables. For more on defining these, see the [Defining Relationships](defining-relationships.md) skill.
66
-
67
- `GET /Book/?author.name=Harper`
68
-
69
- This will perform an automatic join and filter books based on the related author's name.
@@ -1,75 +0,0 @@
1
- # Real-time Applications in Harper
2
-
3
- Harper provides built-in support for real-time data synchronization using WebSockets and a Pub/Sub mechanism. This allows clients to receive immediate updates when data changes in the database.
4
-
5
- ## Automatic WebSockets
6
-
7
- For many use cases, the [Automatic APIs](automatic-apis.md) provided by Harper are more than enough. When you `@export` a table, Harper automatically provides a WebSocket endpoint that publishes events whenever data in that table is updated.
8
-
9
- ## Implementing a WebSocket Resource
10
-
11
- Customizing resources by implementing a `connect` method is only necessary when you want to come up with a more specific back-and-forth or custom message handling. To handle WebSocket connections, implement the `connect` method in your custom resource class.
12
-
13
- ### Example: `resources/exampleSocket.ts`
14
-
15
- ```typescript
16
- import {
17
- type IterableEventQueue,
18
- RequestTarget,
19
- Resource,
20
- tables,
21
- } from 'harperdb';
22
-
23
- export class ExampleSocket extends Resource {
24
- async *connect(
25
- target: RequestTarget,
26
- incomingMessages: IterableEventQueue<any>,
27
- ): AsyncIterable<any> {
28
- // Subscribe to changes in a specific table
29
- const subscription = await tables.ExamplePeople.subscribe(target);
30
-
31
- if (!incomingMessages) {
32
- // Server-Sent Events (SSE) mode: only outgoing messages
33
- return subscription;
34
- }
35
-
36
- // Handle incoming messages from the client
37
- for await (let message of incomingMessages) {
38
- // Process message and optionally yield responses
39
- yield { received: message };
40
- }
41
- }
42
- }
43
- ```
44
-
45
- ## Pub/Sub with `tables.subscribe()`
46
-
47
- You can subscribe to change events on any table using the `subscribe()` method. This is typically used within the `connect` method of a resource to stream updates to a connected client.
48
-
49
- - `tables.TableName.subscribe(target)`: Subscribes to all changes in the specified table.
50
- - The `target` parameter can include filters to only subscribe to a subset of changes.
51
-
52
- ## Server-Sent Events (SSE)
53
-
54
- If the client connects using a protocol that only supports one-way communication from the server (like standard SSE), the `incomingMessages` parameter will be null. Your `connect` method should handle this by only returning the subscription or yielding messages.
55
-
56
- ## Using WebSockets from the Client
57
-
58
- You can connect to your real-time resource using a standard WebSocket client.
59
-
60
- ```javascript
61
- const socket = new WebSocket('ws://your-harper-instance/ExampleSocket');
62
-
63
- socket.onmessage = (event) => {
64
- const data = JSON.parse(event.data);
65
- console.log('Real-time update:', data);
66
- };
67
-
68
- socket.send(JSON.stringify({ type: 'ping' }));
69
- ```
70
-
71
- ## Key Real-time Features
72
-
73
- - **Automatic Table Subscriptions**: Easily stream changes from any database table.
74
- - **Bi-directional Communication**: Send and receive messages in real-time.
75
- - **Scalable Pub/Sub**: Harper handles the efficient distribution of messages to subscribers.
@@ -1,82 +0,0 @@
1
- # Serving Web Content with Harper
2
-
3
- Harper provides two primary ways to include and serve HTTP web content such as HTML, CSS, JavaScript, and React applications. These methods are mutually exclusive.
4
-
5
- ## 1. Using the Static Plugin
6
-
7
- The `static` plugin is the simplest way to serve static files. It maps a directory on your filesystem to your Harper REST endpoint.
8
-
9
- ### Configuration
10
-
11
- Add the `static` configuration to your `config.yaml`:
12
-
13
- ```yaml
14
- static:
15
- files: 'web/*'
16
- ```
17
-
18
- ### Usage
19
-
20
- 1. Create a `web` folder in your project root.
21
- 2. Place your static files (e.g., `index.html`, `styles.css`, `app.js`) inside the `web` folder.
22
- 3. Your files will be accessible from your REST endpoint. For example, if Harper is running on `http://localhost:9926/`, your `index.html` will be available at that address.
23
-
24
- ### Key Characteristics
25
-
26
- - **Precedence**: Static files are searched first. If a matching file is found, it is served; otherwise, Harper proceeds to check your other resource and table APIs.
27
- - **No Directory Listings**: Browsing the directory structure via the browser is not supported.
28
- - **Simple Deployment**: Ideal for pre-built applications or simple static sites.
29
-
30
- ---
31
-
32
- ## 2. Using the Vite Plugin
33
-
34
- The Vite plugin integrates Vite's development server directly into Harper, providing features like Hot Module Replacement (HMR) during development.
35
-
36
- ### Configuration
37
-
38
- Add the Vite plugin to your `config.yaml`:
39
-
40
- ```yaml
41
- '@harperfast/vite-plugin':
42
- package: '@harperfast/vite-plugin'
43
- ```
44
-
45
- ### Setup
46
-
47
- This plugin expects a `vite.config.ts` and an `index.html` file in your project root. It handles rendering your app through Vite during development.
48
-
49
- ### Package Configuration
50
-
51
- To use the Vite plugin effectively, you should configure your `package.json` with the appropriate scripts and dependencies.
52
-
53
- #### Scripts
54
-
55
- Copy these script examples to manage your development and deployment workflows:
56
-
57
- ```json
58
- "scripts": {
59
- "dev": "harper run .",
60
- "build": "tsc -b && vite build",
61
- "build-and-deploy": "rm -Rf deploy && npm run build && mkdir deploy && mv web deploy/ && cp -R deploy-template/* deploy/ && dotenv -- npm run deploy-web && rm -Rf deploy",
62
- "deploy-web": "(cd deploy && harperdb deploy_component . project=web restart=rolling replicated=true)"
63
- }
64
- ```
65
-
66
- #### Dependencies and Overrides
67
-
68
- Include the Vite plugin and other related dependencies in your `devDependencies`:
69
-
70
- ```bash
71
- npm install --save-dev vite @harperfast/vite-plugin @vitejs/plugin-react dotenv-cli
72
- ```
73
-
74
- ### Deploying to Production
75
-
76
- Vite's HMR server is meant for development, not production. For that, the `build-and-deploy` script above builds the Vite app into a `web` folder, places the static handler, and then deploys that subdirectory as a Harper app to production.
77
-
78
- ### Key Characteristics
79
-
80
- - **Development Experience**: Provides Vite's HMR for a fast development cycle.
81
- - **Integrated Rendering**: Automatically handles the rendering of your React/Vite app.
82
- - **Mutual Exclusivity**: Use this approach **instead of** the static plugin if you want Vite integration.
@@ -1,47 +0,0 @@
1
- # TypeScript Type Stripping
2
-
3
- Harper supports using TypeScript directly without any additional build tools (like `tsc` or `esbuild`) by leveraging Node.js's native Type Stripping capability. This allows you to write `.ts` files for your Custom Resources and have them run directly in Harper.
4
-
5
- ## Requirements
6
-
7
- - **Node.js Version**: You must be running a version of Node.js that supports type stripping (Node.js v22.6.0 or higher).
8
- - **No Experimental Flags**: When running on supported Node.js versions, Harper can automatically handle type stripping for your resource files.
9
-
10
- ## Benefits
11
-
12
- - **Faster Development**: No need to wait for a build step or manage complex build pipelines.
13
- - **Simplified Tooling**: You don't need to install or configure `ts-node`, `tsx`, or other TypeScript execution engines for your Harper resources.
14
- - **Native Performance**: Leverages Node.js's built-in support for stripping types, which is highly efficient.
15
-
16
- ## Usage
17
-
18
- Simply name your resource files with a `.ts` extension in your `resources/` directory.
19
-
20
- ### Example: `resources/my-resource.ts`
21
-
22
- ```typescript
23
- import { Resource } from 'harperdb';
24
-
25
- export class MyResource extends Resource {
26
- async get() {
27
- return { message: 'This is running directly from TypeScript!' };
28
- }
29
- }
30
- ```
31
-
32
- When cross-referencing between modules, ensure that the file path contains the appropriate extension.
33
-
34
- ```typescript
35
- import { MyResource } from './my-resource.ts';
36
- ```
37
-
38
- ## Configuration
39
-
40
- In your `config.yaml`, ensure your `jsResource` points to your `.ts` files:
41
-
42
- ```yaml
43
- jsResource:
44
- files: 'resources/*.ts'
45
- ```
46
-
47
- When Harper starts, it will detect the `.ts` files and, if running on a compatible Node.js version, will execute them using type stripping.