Skip to content

Commit e4ce96c

Browse files
authored
Merge branch 'DouglasNeuroInformatics:main' into improve-error-desc
2 parents dd30176 + d207b24 commit e4ce96c

34 files changed

Lines changed: 316 additions & 280 deletions

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,6 @@ apps/outreach/src/content/docs/en/runtime-core-docs/
6262
# docker dbs
6363
mongo/
6464
sqlite/
65+
66+
# runtime core intermediate build
67+
packages/runtime-core/lib/

.nvmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
lts/iron
1+
lts/jod

apps/api/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM node:iron AS base
1+
FROM node:lts-jod AS base
22
WORKDIR /app
33
ARG RELEASE_VERSION
44
ENV GATEWAY_DATABASE_URL="file:/dev/null"

apps/gateway/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM node:iron AS base
1+
FROM node:lts-jod AS base
22
WORKDIR /app
33
ARG RELEASE_VERSION
44
ENV GATEWAY_DATABASE_URL=file:/app/sqlite/gateway.db

apps/outreach/astro.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export default defineConfig({
6262
},
6363
plugins: [
6464
starlightTypeDocPlugin({
65-
entryPoints: [path.resolve(runtimeCoreRoot, 'src/index.d.ts')],
65+
entryPoints: [path.resolve(runtimeCoreRoot, 'lib/index.d.ts')],
6666
locale: 'en',
6767
output: 'runtime-core-docs',
6868
sidebar: {

apps/web/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM node:iron AS base
1+
FROM node:lts-jod AS base
22
ARG RELEASE_VERSION
33
WORKDIR /app
44
ENV PNPM_HOME="/pnpm"
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
---
2+
title: Runtime Execution Context
3+
slug: en/docs/concepts/runtime-execution-context
4+
sidebar:
5+
order: 3
6+
---
7+
8+
In JavaScript, the global object varies depending on the execution environment. In the browser, the global object is `window`, which includes properties like `document`. In Node.js, the global object is `global`. This object is specific to Node.js and is not available in browsers.
9+
10+
For example, you cannot access `process.env` in a browser environment because it is specific to Node.js. Similarly, calling `document.createElement` on a server does not work, as it is intended for the client-side. Attempting either will result in a runtime error.
11+
12+
In Open Data Capture, code runs on both the client and server. You should therefore not access browser-specific APIs, like `document` or `window` unless you are within functions named `render`, which execute exclusively on the client. For those familiar with Next.js, think of these functions as rendering a component with a "use client" directive within a React Server Component.
13+
14+
## Example of Problematic Instrument
15+
16+
```ts
17+
import { defineInstrument } from '/runtime/v1/@opendatacapture/runtime-core';
18+
import { z } from '/runtime/v1/zod@3.23.x';
19+
20+
const button = document.createElement('button');
21+
button.textContent = 'Submit Instrument';
22+
document.body.appendChild(button);
23+
24+
export default defineInstrument({
25+
// ...
26+
kind: 'INTERACTIVE',
27+
content: {
28+
render(done) {
29+
button.addEventListener('click', () => {
30+
done({ message: 'Hello World' });
31+
});
32+
}
33+
}
34+
// ...
35+
});
36+
```
37+
38+
## Fixing This Instrument
39+
40+
To fix the instrument, there are two options:
41+
42+
1. Move the browser-specific code directly within the render function
43+
2. Wrap the browser-specific code in a function. This function can be defined outside the render function but must only be called within it.
44+
45+
**Example**
46+
47+
```ts
48+
import { defineInstrument } from '/runtime/v1/@opendatacapture/runtime-core';
49+
import { z } from '/runtime/v1/zod@3.23.x';
50+
51+
function createButton() {
52+
const button = document.createElement('button');
53+
button.textContent = 'Submit Instrument';
54+
document.body.appendChild(button);
55+
return button;
56+
}
57+
58+
export default defineInstrument({
59+
// ...
60+
kind: 'INTERACTIVE',
61+
content: {
62+
render(done) {
63+
const button = createButton();
64+
button.addEventListener('click', () => {
65+
done({ message: 'Hello World' });
66+
});
67+
}
68+
}
69+
// ...
70+
});
71+
```

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
{
22
"name": "opendatacapture",
33
"type": "module",
4-
"version": "1.8.5",
4+
"version": "1.8.6",
55
"private": true,
66
"packageManager": "pnpm@9.15.4",
77
"license": "Apache-2.0",
88
"engines": {
9-
"node": ">=v20.17.0"
9+
"node": ">=v22.11.0"
1010
},
1111
"scripts": {
1212
"build": "env-cmd turbo run build",
@@ -53,7 +53,7 @@
5353
"@swc/helpers": "^0.5.15",
5454
"@types/github-script": "https://github.com/actions/github-script/archive/refs/tags/v7.0.1.tar.gz",
5555
"@types/js-yaml": "^4.0.9",
56-
"@types/node": "^20.14.2",
56+
"@types/node": "22.x",
5757
"@vitest/browser": "^2.0.5",
5858
"@vitest/coverage-v8": "^2.0.5",
5959
"dotenv": "^16.4.7",

packages/instrument-bundler/src/__tests__/repositories/interactive/index.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { defineInstrument } from '/runtime/v1/@opendatacapture/runtime-core';
22
import { createRoot } from '/runtime/v1/react-dom@18.x/client';
33
import { z } from '/runtime/v1/zod@3.23.x';
44

5+
const { sum } = await import('/runtime/v1/lodash-es@4.x');
6+
57
import './styles.css';
68
import '/runtime/v1/normalize.css@8.x/normalize.css';
79

@@ -18,7 +20,7 @@ export default defineInstrument({
1820
root.render(
1921
<div>
2022
<h1>Interactive Task</h1>
21-
<button onClick={() => done({})}>Done</button>
23+
<button onClick={() => done({ value: sum([1, 2, 3]) })}>Done</button>
2224
</div>
2325
);
2426
}

packages/instrument-bundler/src/__tests__/transform.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,24 @@ import { transformImports } from '../transform.js';
44

55
describe('transformImports', () => {
66
it('should transform a default import', () => {
7-
expect(transformImports("import React from 'react';")).toBe("const { default: React } = await import('react');");
7+
expect(transformImports("import React from 'react';")).toBe("const { default: React } = await __import('react');");
88
});
99
it('should transform named imports', () => {
1010
expect(transformImports("import { useEffect, useState } from 'react';")).toBe(
11-
"const { useEffect, useState } = await import('react');"
11+
"const { useEffect, useState } = await __import('react');"
1212
);
1313
});
1414
it('should transform named and default imports from the same source', () => {
1515
expect(transformImports("import React, { useState } from 'react';")).toBe(
16-
"const { useState, default: React } = await import('react');"
16+
"const { useState, default: React } = await __import('react');"
1717
);
1818
});
1919
it('should transform a namespace import', () => {
20-
expect(transformImports("import * as React from 'react';")).toBe("const React = await import('react');");
20+
expect(transformImports("import * as React from 'react';")).toBe("const React = await __import('react');");
2121
});
2222
it('should transform named and default imports from the same source', () => {
2323
expect(transformImports("import _ from 'lodash'; import { useEffect, useState } from 'react';")).toBe(
24-
"const { default: _ } = await import('lodash'); const { useEffect, useState } = await import('react');"
24+
"const { default: _ } = await __import('lodash'); const { useEffect, useState } = await __import('react');"
2525
);
2626
});
2727
});

0 commit comments

Comments
 (0)