@componentonce/react 0.1.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +23 -0
- package/dist/index.d.ts +82 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +94 -0
- package/dist/index.js.map +1 -0
- package/examples/two-hosts.tsx +66 -0
- package/package.json +44 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# @componentonce/react
|
|
2
|
+
|
|
3
|
+
React adapter for trusted ComponentOnce modules.
|
|
4
|
+
|
|
5
|
+
React is a peer dependency. Dynamically compiled modules must use the host application's actual React and JSX-runtime instances rather than bundling another React copy.
|
|
6
|
+
|
|
7
|
+
## Define and render
|
|
8
|
+
|
|
9
|
+
defineReactComponent<Props, HostContext, Payload> keeps persisted props, arbitrary host context, and per-render payload distinct.
|
|
10
|
+
|
|
11
|
+
Typed rendering does not revalidate values by default. Raw JSON/editor/storage boundaries can use validateReactComponentBoundary or renderReactComponentBoundary to validate props and payload once.
|
|
12
|
+
|
|
13
|
+
## React runtime compatibility
|
|
14
|
+
|
|
15
|
+
createReactRequirement(version) creates the generic core requirement named react.
|
|
16
|
+
|
|
17
|
+
When a definition declares requirements, renderReactComponent checks them against hostCapabilities before calling React createElement. Exact compatibility is the default. The host may supply capabilityCompatibility when it deliberately supports a version range.
|
|
18
|
+
|
|
19
|
+
This matters because sharing the host React singleton prevents duplicate-React hook failures, but it does not make a React-19-authored module compatible with a React-18 host automatically.
|
|
20
|
+
|
|
21
|
+
## Host-specific helpers
|
|
22
|
+
|
|
23
|
+
createReactHostHelpers<HostContext, Payload>() fixes application context/payload types without importing application code into ComponentOnce. Each component still chooses its own Props type.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { type ComponentType, type ReactElement } from "react";
|
|
2
|
+
import { type ComponentOnceCapability, type ComponentOnceCapabilityCompatibility, type ComponentOnceDefinition, type ComponentOnceManifest, type ComponentOnceRequirement, type ComponentOnceValidator } from "@componentonce/core";
|
|
3
|
+
/** Stable core capability name used for the host React runtime. */
|
|
4
|
+
export declare const REACT_CAPABILITY_NAME = "react";
|
|
5
|
+
/** Create one generic core requirement for a React runtime version. */
|
|
6
|
+
export declare function createReactRequirement(version: string): ComponentOnceRequirement;
|
|
7
|
+
/** Props passed to one trusted React implementation by its host. */
|
|
8
|
+
export interface ComponentOnceReactRenderInput<TProps, THostContext, TPayload> {
|
|
9
|
+
readonly props: TProps;
|
|
10
|
+
readonly context: THostContext;
|
|
11
|
+
readonly payload: TPayload;
|
|
12
|
+
}
|
|
13
|
+
/** React implementation shape registered with ComponentOnce. */
|
|
14
|
+
export type ComponentOnceReactComponent<TProps, THostContext, TPayload> = ComponentType<ComponentOnceReactRenderInput<TProps, THostContext, TPayload>>;
|
|
15
|
+
/** A core definition whose implementation is a typed React component. */
|
|
16
|
+
export type ComponentOnceReactDefinition<TProps, THostContext, TPayload> = ComponentOnceDefinition<ComponentOnceReactComponent<TProps, THostContext, TPayload>, TProps, THostContext, TPayload>;
|
|
17
|
+
/** Input used to define one typed React component. */
|
|
18
|
+
export interface DefineReactComponentInput<TProps, THostContext, TPayload> {
|
|
19
|
+
readonly manifest: ComponentOnceManifest;
|
|
20
|
+
readonly component: ComponentOnceReactComponent<TProps, THostContext, TPayload>;
|
|
21
|
+
readonly validateProps?: ComponentOnceValidator<TProps>;
|
|
22
|
+
readonly validatePayload?: ComponentOnceValidator<TPayload>;
|
|
23
|
+
}
|
|
24
|
+
/** Selects typed values that the renderer should explicitly revalidate. */
|
|
25
|
+
export interface ComponentOnceReactValidationRequest {
|
|
26
|
+
readonly props?: boolean;
|
|
27
|
+
readonly payload?: boolean;
|
|
28
|
+
}
|
|
29
|
+
/** Input used to render an already typed exact React definition. */
|
|
30
|
+
export interface ComponentOnceReactRendererInput<TProps, THostContext, TPayload> extends ComponentOnceReactRenderInput<TProps, THostContext, TPayload> {
|
|
31
|
+
readonly definition: ComponentOnceReactDefinition<TProps, THostContext, TPayload>;
|
|
32
|
+
/** Validation is off by default; `true` requests both validators. */
|
|
33
|
+
readonly validation?: boolean | ComponentOnceReactValidationRequest;
|
|
34
|
+
/** Runtime/application capabilities exposed by the host. */
|
|
35
|
+
readonly hostCapabilities?: readonly ComponentOnceCapability[];
|
|
36
|
+
/** Optional host-defined compatibility policy; exact matching is the core default. */
|
|
37
|
+
readonly capabilityCompatibility?: ComponentOnceCapabilityCompatibility;
|
|
38
|
+
}
|
|
39
|
+
/** Unknown props and payload received at an untyped host boundary. */
|
|
40
|
+
export interface ComponentOnceReactBoundaryInput<THostContext> {
|
|
41
|
+
readonly props: unknown;
|
|
42
|
+
readonly context: THostContext;
|
|
43
|
+
readonly payload: unknown;
|
|
44
|
+
}
|
|
45
|
+
/** The definition and raw values needed to validate an untyped render boundary. */
|
|
46
|
+
export interface ComponentOnceReactBoundaryRenderInput<TProps, THostContext, TPayload> extends ComponentOnceReactBoundaryInput<THostContext> {
|
|
47
|
+
readonly definition: ComponentOnceReactDefinition<TProps, THostContext, TPayload>;
|
|
48
|
+
/** Runtime/application capabilities exposed by the host. */
|
|
49
|
+
readonly hostCapabilities?: readonly ComponentOnceCapability[];
|
|
50
|
+
/** Optional host-defined compatibility policy; exact matching is the core default. */
|
|
51
|
+
readonly capabilityCompatibility?: ComponentOnceCapabilityCompatibility;
|
|
52
|
+
}
|
|
53
|
+
/** A definition field that can carry an optional boundary validator. */
|
|
54
|
+
export type ComponentOnceReactValidationField = "props" | "payload";
|
|
55
|
+
/** Thrown when a caller requests boundary validation that a definition does not provide. */
|
|
56
|
+
export declare class ComponentOnceReactValidatorMissingError extends Error {
|
|
57
|
+
readonly field: ComponentOnceReactValidationField;
|
|
58
|
+
readonly manifest: ComponentOnceManifest;
|
|
59
|
+
constructor(field: ComponentOnceReactValidationField, manifest: ComponentOnceManifest);
|
|
60
|
+
}
|
|
61
|
+
/** Helpers with host context and payload types fixed for one application integration. */
|
|
62
|
+
export interface ComponentOnceReactHostHelpers<THostContext, TPayload> {
|
|
63
|
+
/** Define a component while inferring only its persisted props type. */
|
|
64
|
+
define<TProps>(input: DefineReactComponentInput<TProps, THostContext, TPayload>): ComponentOnceReactDefinition<TProps, THostContext, TPayload>;
|
|
65
|
+
/** Render typed values without validation unless the request explicitly enables it. */
|
|
66
|
+
render<TProps>(input: ComponentOnceReactRendererInput<TProps, THostContext, TPayload>): ReactElement;
|
|
67
|
+
/** Validate unknown props and payload once and preserve the host context unchanged. */
|
|
68
|
+
validateBoundary<TProps>(definition: ComponentOnceReactDefinition<TProps, THostContext, TPayload>, input: ComponentOnceReactBoundaryInput<THostContext>): ComponentOnceReactRenderInput<TProps, THostContext, TPayload>;
|
|
69
|
+
/** Validate and render values received from an untyped boundary. */
|
|
70
|
+
renderBoundary<TProps>(input: ComponentOnceReactBoundaryRenderInput<TProps, THostContext, TPayload>): ReactElement;
|
|
71
|
+
}
|
|
72
|
+
/** Define one typed React component without teaching core anything about React. */
|
|
73
|
+
export declare function defineReactComponent<TProps, THostContext, TPayload>(input: DefineReactComponentInput<TProps, THostContext, TPayload>): ComponentOnceReactDefinition<TProps, THostContext, TPayload>;
|
|
74
|
+
/** Render an exact React definition, with optional validation requested by the host. */
|
|
75
|
+
export declare function renderReactComponent<TProps, THostContext, TPayload>(input: ComponentOnceReactRendererInput<TProps, THostContext, TPayload>): ReactElement;
|
|
76
|
+
/** Validate unknown props and payload once at a host boundary. */
|
|
77
|
+
export declare function validateReactComponentBoundary<TProps, THostContext, TPayload>(definition: ComponentOnceReactDefinition<TProps, THostContext, TPayload>, input: ComponentOnceReactBoundaryInput<THostContext>): ComponentOnceReactRenderInput<TProps, THostContext, TPayload>;
|
|
78
|
+
/** Validate unknown boundary values and render the resulting typed React input. */
|
|
79
|
+
export declare function renderReactComponentBoundary<TProps, THostContext, TPayload>(input: ComponentOnceReactBoundaryRenderInput<TProps, THostContext, TPayload>): ReactElement;
|
|
80
|
+
/** Create concise definition and rendering helpers pinned to one host's own types. */
|
|
81
|
+
export declare function createReactHostHelpers<THostContext, TPayload>(): ComponentOnceReactHostHelpers<THostContext, TPayload>;
|
|
82
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { createElement } from "react";
|
|
2
|
+
import { assertComponentOnceCompatible, } from "@componentonce/core";
|
|
3
|
+
/** Stable core capability name used for the host React runtime. */
|
|
4
|
+
export const REACT_CAPABILITY_NAME = "react";
|
|
5
|
+
/** Create one generic core requirement for a React runtime version. */
|
|
6
|
+
export function createReactRequirement(version) {
|
|
7
|
+
return { name: REACT_CAPABILITY_NAME, version };
|
|
8
|
+
}
|
|
9
|
+
/** Thrown when a caller requests boundary validation that a definition does not provide. */
|
|
10
|
+
export class ComponentOnceReactValidatorMissingError extends Error {
|
|
11
|
+
field;
|
|
12
|
+
manifest;
|
|
13
|
+
constructor(field, manifest) {
|
|
14
|
+
super(`Component "${manifest.id}" version "${manifest.version}" has no ${field} validator.`);
|
|
15
|
+
this.name = new.target.name;
|
|
16
|
+
this.field = field;
|
|
17
|
+
this.manifest = manifest;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** Define one typed React component without teaching core anything about React. */
|
|
21
|
+
export function defineReactComponent(input) {
|
|
22
|
+
return {
|
|
23
|
+
manifest: input.manifest,
|
|
24
|
+
implementation: input.component,
|
|
25
|
+
...(input.validateProps === undefined ? {} : { validateProps: input.validateProps }),
|
|
26
|
+
...(input.validatePayload === undefined ? {} : { validatePayload: input.validatePayload }),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/** Render an exact React definition, with optional validation requested by the host. */
|
|
30
|
+
export function renderReactComponent(input) {
|
|
31
|
+
assertComponentOnceCompatible(input.definition.manifest, input.hostCapabilities ?? [], input.capabilityCompatibility);
|
|
32
|
+
const validation = normalizeValidation(input.validation);
|
|
33
|
+
const props = validation.props
|
|
34
|
+
? validateField(input.definition, "props", input.props)
|
|
35
|
+
: input.props;
|
|
36
|
+
const payload = validation.payload
|
|
37
|
+
? validateField(input.definition, "payload", input.payload)
|
|
38
|
+
: input.payload;
|
|
39
|
+
return createElement(input.definition.implementation, {
|
|
40
|
+
props,
|
|
41
|
+
context: input.context,
|
|
42
|
+
payload,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
/** Validate unknown props and payload once at a host boundary. */
|
|
46
|
+
export function validateReactComponentBoundary(definition, input) {
|
|
47
|
+
return {
|
|
48
|
+
props: validateField(definition, "props", input.props),
|
|
49
|
+
context: input.context,
|
|
50
|
+
payload: validateField(definition, "payload", input.payload),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/** Validate unknown boundary values and render the resulting typed React input. */
|
|
54
|
+
export function renderReactComponentBoundary(input) {
|
|
55
|
+
const validated = validateReactComponentBoundary(input.definition, input);
|
|
56
|
+
return renderReactComponent({
|
|
57
|
+
definition: input.definition,
|
|
58
|
+
...validated,
|
|
59
|
+
...(input.hostCapabilities === undefined
|
|
60
|
+
? {}
|
|
61
|
+
: { hostCapabilities: input.hostCapabilities }),
|
|
62
|
+
...(input.capabilityCompatibility === undefined
|
|
63
|
+
? {}
|
|
64
|
+
: { capabilityCompatibility: input.capabilityCompatibility }),
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
/** Create concise definition and rendering helpers pinned to one host's own types. */
|
|
68
|
+
export function createReactHostHelpers() {
|
|
69
|
+
return {
|
|
70
|
+
define: (input) => defineReactComponent(input),
|
|
71
|
+
render: (input) => renderReactComponent(input),
|
|
72
|
+
validateBoundary: (definition, input) => validateReactComponentBoundary(definition, input),
|
|
73
|
+
renderBoundary: (input) => renderReactComponentBoundary(input),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function normalizeValidation(validation) {
|
|
77
|
+
if (validation === true)
|
|
78
|
+
return { props: true, payload: true };
|
|
79
|
+
if (validation === false || validation === undefined) {
|
|
80
|
+
return { props: false, payload: false };
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
props: validation.props ?? false,
|
|
84
|
+
payload: validation.payload ?? false,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function validateField(definition, field, value) {
|
|
88
|
+
const validator = field === "props" ? definition.validateProps : definition.validatePayload;
|
|
89
|
+
if (validator === undefined) {
|
|
90
|
+
throw new ComponentOnceReactValidatorMissingError(field, definition.manifest);
|
|
91
|
+
}
|
|
92
|
+
return validator(value);
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { renderReactComponent, defineReactComponent } from "@componentonce/react";
|
|
2
|
+
|
|
3
|
+
interface BannerProps {
|
|
4
|
+
readonly prefix: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
interface BrowserHostContext {
|
|
8
|
+
readonly kind: "browser";
|
|
9
|
+
readonly locale: string;
|
|
10
|
+
readonly navigate: (path: string) => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface WorkerHostContext {
|
|
14
|
+
readonly kind: "worker";
|
|
15
|
+
readonly jobName: string;
|
|
16
|
+
readonly retry: (jobId: number) => Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface PagePayload {
|
|
20
|
+
readonly kind: "page";
|
|
21
|
+
readonly pathname: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface JobPayload {
|
|
25
|
+
readonly kind: "job";
|
|
26
|
+
readonly jobId: number;
|
|
27
|
+
readonly attempt: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type HostContext = BrowserHostContext | WorkerHostContext;
|
|
31
|
+
type Payload = PagePayload | JobPayload;
|
|
32
|
+
|
|
33
|
+
// One exact module accepts the two host-owned type pairs without ComponentOnce
|
|
34
|
+
// knowing either shape.
|
|
35
|
+
const statusBanner = defineReactComponent<BannerProps, HostContext, Payload>({
|
|
36
|
+
manifest: { id: "example/status-banner", version: "1.0.0" },
|
|
37
|
+
component: ({ props, context, payload }) => {
|
|
38
|
+
const host = context.kind === "browser" ? context.locale : context.jobName;
|
|
39
|
+
const value = payload.kind === "page" ? payload.pathname : `attempt ${payload.attempt}`;
|
|
40
|
+
return <strong>{props.prefix}: {host} / {value}</strong>;
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
/** The same exact definition rendered inside a browser application. */
|
|
45
|
+
export const browserElement = renderReactComponent({
|
|
46
|
+
definition: statusBanner,
|
|
47
|
+
props: { prefix: "Status" },
|
|
48
|
+
context: {
|
|
49
|
+
kind: "browser",
|
|
50
|
+
locale: "en-GB",
|
|
51
|
+
navigate: () => undefined,
|
|
52
|
+
},
|
|
53
|
+
payload: { kind: "page", pathname: "/reports" },
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
/** The same exact definition rendered inside a background worker application. */
|
|
57
|
+
export const workerElement = renderReactComponent({
|
|
58
|
+
definition: statusBanner,
|
|
59
|
+
props: { prefix: "Status" },
|
|
60
|
+
context: {
|
|
61
|
+
kind: "worker",
|
|
62
|
+
jobName: "monthly-report",
|
|
63
|
+
retry: async () => undefined,
|
|
64
|
+
},
|
|
65
|
+
payload: { kind: "job", jobId: 81, attempt: 2 },
|
|
66
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@componentonce/react",
|
|
3
|
+
"version": "0.1.0-beta.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist",
|
|
7
|
+
"examples",
|
|
8
|
+
"README.md"
|
|
9
|
+
],
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@componentonce/core": "0.1.0-beta.0"
|
|
18
|
+
},
|
|
19
|
+
"peerDependencies": {
|
|
20
|
+
"react": ">=18"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/react-dom": "^19.2.2",
|
|
24
|
+
"@types/react": "^19.2.2",
|
|
25
|
+
"react": "^19.2.0",
|
|
26
|
+
"react-dom": "^19.2.0",
|
|
27
|
+
"typescript": "^5.9.3",
|
|
28
|
+
"vitest": "^4.0.5"
|
|
29
|
+
},
|
|
30
|
+
"description": "React adapter for trusted ComponentOnce components using the host React runtime.",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public",
|
|
34
|
+
"tag": "beta"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"precheck": "pnpm --filter @componentonce/core build",
|
|
38
|
+
"check": "tsc --noEmit -p tsconfig.json && tsc --noEmit -p tsconfig.test.json",
|
|
39
|
+
"pretest": "pnpm --filter @componentonce/core build",
|
|
40
|
+
"test": "vitest run",
|
|
41
|
+
"prebuild": "pnpm --filter @componentonce/core build",
|
|
42
|
+
"build": "tsc -p tsconfig.json"
|
|
43
|
+
}
|
|
44
|
+
}
|