@holo-js/adapter-shared 0.3.12 → 0.3.15
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/dist/build.d.ts +22 -0
- package/dist/build.mjs +12 -0
- package/dist/chunk-3GNER7MY.mjs +44 -0
- package/dist/chunk-NSZSPJAF.mjs +325 -0
- package/dist/client.d.ts +10 -0
- package/dist/client.mjs +10 -0
- package/dist/index.d.ts +2 -28
- package/dist/index.mjs +10 -210
- package/package.json +15 -2
package/dist/build.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
declare function compileBrowserValidation(source: string, fileName?: string): string | undefined;
|
|
2
|
+
|
|
3
|
+
type RealtimeDefinitionSourceMap = {
|
|
4
|
+
readonly version: 3;
|
|
5
|
+
readonly file: string;
|
|
6
|
+
readonly sources: readonly string[];
|
|
7
|
+
readonly sourcesContent: readonly string[];
|
|
8
|
+
readonly names: readonly string[];
|
|
9
|
+
readonly mappings: string;
|
|
10
|
+
};
|
|
11
|
+
type RealtimeDefinitionTransformResult = {
|
|
12
|
+
readonly code: string;
|
|
13
|
+
readonly map: RealtimeDefinitionSourceMap;
|
|
14
|
+
};
|
|
15
|
+
type RealtimeDefinitionTransformOptions = {
|
|
16
|
+
readonly preserveServerHandlers?: boolean;
|
|
17
|
+
};
|
|
18
|
+
declare function stripRealtimeServerHandlers(source: string): string;
|
|
19
|
+
declare function createRealtimeClientDefinitionModule(source: string, importTarget: string): string;
|
|
20
|
+
declare function createRealtimeClientDefinitionTransform(source: string, importTarget: string, options?: RealtimeDefinitionTransformOptions): RealtimeDefinitionTransformResult;
|
|
21
|
+
|
|
22
|
+
export { type RealtimeDefinitionSourceMap, type RealtimeDefinitionTransformOptions, type RealtimeDefinitionTransformResult, compileBrowserValidation, createRealtimeClientDefinitionModule, createRealtimeClientDefinitionTransform, stripRealtimeServerHandlers };
|
package/dist/build.mjs
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {
|
|
2
|
+
compileBrowserValidation,
|
|
3
|
+
createRealtimeClientDefinitionModule,
|
|
4
|
+
createRealtimeClientDefinitionTransform,
|
|
5
|
+
stripRealtimeServerHandlers
|
|
6
|
+
} from "./chunk-NSZSPJAF.mjs";
|
|
7
|
+
export {
|
|
8
|
+
compileBrowserValidation,
|
|
9
|
+
createRealtimeClientDefinitionModule,
|
|
10
|
+
createRealtimeClientDefinitionTransform,
|
|
11
|
+
stripRealtimeServerHandlers
|
|
12
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// src/client.ts
|
|
2
|
+
import {
|
|
3
|
+
isHoloHttpErrorStatus,
|
|
4
|
+
normalizeHoloHttpError
|
|
5
|
+
} from "@holo-js/kernel/http-errors";
|
|
6
|
+
|
|
7
|
+
// src/clientErrorPage.ts
|
|
8
|
+
function escapePage(error, options) {
|
|
9
|
+
const browserDocument = globalThis.document;
|
|
10
|
+
if (!browserDocument) return;
|
|
11
|
+
browserDocument.title = `${error.status}: ${error.message}`;
|
|
12
|
+
const existingRoot = browserDocument.getElementById(options.rootId);
|
|
13
|
+
const root = existingRoot ?? browserDocument.createElement("main");
|
|
14
|
+
root.id = options.rootId;
|
|
15
|
+
root.setAttribute("role", "alert");
|
|
16
|
+
root.style.cssText = "position:fixed;inset:0;z-index:2147483647;display:grid;place-items:center;margin:0;background:#fff;color:#000;font-family:Arial,Helvetica,sans-serif";
|
|
17
|
+
const wrapper = browserDocument.createElement("div");
|
|
18
|
+
wrapper.style.cssText = "display:flex;align-items:center;gap:1.5rem;padding:1.5rem";
|
|
19
|
+
const status = browserDocument.createElement("h1");
|
|
20
|
+
status.className = options.statusClassName;
|
|
21
|
+
status.textContent = String(error.status);
|
|
22
|
+
status.style.cssText = "display:inline-block;margin:0 1.25rem 0 0;padding:0 1.5rem 0 0;font-size:24px;font-weight:500;line-height:49px;vertical-align:top;border-right:1px solid rgba(0,0,0,.3)";
|
|
23
|
+
const description = browserDocument.createElement("div");
|
|
24
|
+
description.style.cssText = "display:inline-block;text-align:left;line-height:49px;height:49px;vertical-align:middle";
|
|
25
|
+
const message = browserDocument.createElement("h2");
|
|
26
|
+
message.textContent = error.message;
|
|
27
|
+
message.style.cssText = "font-size:14px;font-weight:400;line-height:49px;margin:0";
|
|
28
|
+
description.append(message);
|
|
29
|
+
wrapper.append(status, description);
|
|
30
|
+
root.replaceChildren(wrapper);
|
|
31
|
+
for (const child of Array.from(browserDocument.body.children)) {
|
|
32
|
+
if (child.id !== root.id) child.style.display = "none";
|
|
33
|
+
}
|
|
34
|
+
if (!existingRoot) browserDocument.body.append(root);
|
|
35
|
+
}
|
|
36
|
+
function renderClientHttpErrorPage(error, options) {
|
|
37
|
+
escapePage(error, options);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export {
|
|
41
|
+
renderClientHttpErrorPage,
|
|
42
|
+
isHoloHttpErrorStatus,
|
|
43
|
+
normalizeHoloHttpError
|
|
44
|
+
};
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
// src/build.ts
|
|
2
|
+
import ts2 from "typescript";
|
|
3
|
+
|
|
4
|
+
// src/validation-transform.ts
|
|
5
|
+
import ts from "typescript";
|
|
6
|
+
var primitives = /* @__PURE__ */ new Set(["string", "password", "number", "boolean", "date"]);
|
|
7
|
+
var flags = /* @__PURE__ */ new Set(["required", "optional", "nullable", "confirmed", "today", "beforeToday", "todayOrBefore", "beforeOrToday", "afterToday", "todayOrAfter", "afterOrToday"]);
|
|
8
|
+
var formats = /* @__PURE__ */ new Set(["email", "url", "uuid", "integer"]);
|
|
9
|
+
function literal(node) {
|
|
10
|
+
if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) return node.text;
|
|
11
|
+
if (ts.isNumericLiteral(node)) {
|
|
12
|
+
const value = Number(node.text);
|
|
13
|
+
return Number.isFinite(value) ? value : void 0;
|
|
14
|
+
}
|
|
15
|
+
if (node.kind === ts.SyntaxKind.TrueKeyword) return true;
|
|
16
|
+
if (node.kind === ts.SyntaxKind.FalseKeyword) return false;
|
|
17
|
+
if (node.kind === ts.SyntaxKind.NullKeyword) return null;
|
|
18
|
+
if (ts.isPrefixUnaryExpression(node) && node.operator === ts.SyntaxKind.MinusToken && ts.isNumericLiteral(node.operand)) {
|
|
19
|
+
const value = -Number(node.operand.text);
|
|
20
|
+
return Object.is(value, -0) || !Number.isFinite(value) ? void 0 : value;
|
|
21
|
+
}
|
|
22
|
+
return void 0;
|
|
23
|
+
}
|
|
24
|
+
function parseRule(name, nodes) {
|
|
25
|
+
const values = nodes.map(literal);
|
|
26
|
+
if (values.some((value) => value === void 0)) return void 0;
|
|
27
|
+
const args = values;
|
|
28
|
+
const noArgument = flags.has(name) || formats.has(name);
|
|
29
|
+
const numeric = name === "min" || name === "max" || name === "size";
|
|
30
|
+
if (!noArgument && !numeric && name !== "default") return void 0;
|
|
31
|
+
if (args.length > (noArgument ? 1 : 2)) return void 0;
|
|
32
|
+
if (numeric && (typeof args[0] !== "number" || !Number.isFinite(args[0]))) return void 0;
|
|
33
|
+
if (name === "default" && args.length === 0) return void 0;
|
|
34
|
+
const message = args[noArgument ? 0 : 1];
|
|
35
|
+
if (message !== void 0 && (typeof message !== "string" || !message.trim())) return void 0;
|
|
36
|
+
return {
|
|
37
|
+
name,
|
|
38
|
+
args: noArgument ? [] : args.slice(0, 1),
|
|
39
|
+
...typeof message === "string" ? { message: message.trim() } : {}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function compileField(node, fieldName, runtime, definitionReference) {
|
|
43
|
+
const rules = [];
|
|
44
|
+
let current = node;
|
|
45
|
+
while (ts.isCallExpression(current) && ts.isPropertyAccessExpression(current.expression)) {
|
|
46
|
+
const member = current.expression;
|
|
47
|
+
if (ts.isIdentifier(member.expression) && member.expression.text === fieldName) {
|
|
48
|
+
if (!primitives.has(member.name.text) || current.arguments.length !== 0) return void 0;
|
|
49
|
+
const kind = member.name.text === "password" ? "string" : member.name.text;
|
|
50
|
+
const definition = {
|
|
51
|
+
kind,
|
|
52
|
+
rules: rules.reverse(),
|
|
53
|
+
...member.name.text === "password" ? { sensitive: true } : {}
|
|
54
|
+
};
|
|
55
|
+
const actions = [];
|
|
56
|
+
for (const rule2 of definition.rules) {
|
|
57
|
+
if (formats.has(rule2.name)) actions.push(`${runtime}.${rule2.name}Action(${JSON.stringify(rule2.message)})`);
|
|
58
|
+
if (rule2.name === "min" || rule2.name === "max" || rule2.name === "size") {
|
|
59
|
+
const action = rule2.name === "size" ? "exactSizeAction" : `${rule2.name}Action`;
|
|
60
|
+
actions.push(`${runtime}.${action}(${definitionReference}, ${JSON.stringify(rule2.args[0])}, ${JSON.stringify(rule2.message)})`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
let code = `${runtime}.${kind}Schema()`;
|
|
64
|
+
if (actions.length > 0) code = `${runtime}.pipeAsync(${code}, ${actions.join(", ")})`;
|
|
65
|
+
const defaultRule = definition.rules.find((rule2) => rule2.name === "default");
|
|
66
|
+
const defaultValue = defaultRule ? JSON.stringify(defaultRule.args[0]) : "undefined";
|
|
67
|
+
if (definition.rules.some((rule2) => rule2.name === "nullable")) code = `${runtime}.nullable(${code}, ${defaultValue})`;
|
|
68
|
+
if (defaultRule || definition.rules.some((rule2) => rule2.name === "optional")) code = `${runtime}.optional(${code}, ${defaultValue})`;
|
|
69
|
+
return { definition, code };
|
|
70
|
+
}
|
|
71
|
+
const rule = parseRule(member.name.text, current.arguments);
|
|
72
|
+
if (!rule) return void 0;
|
|
73
|
+
rules.push(rule);
|
|
74
|
+
current = member.expression;
|
|
75
|
+
}
|
|
76
|
+
return void 0;
|
|
77
|
+
}
|
|
78
|
+
function compileShape(node, fieldName, runtime, path = "fields") {
|
|
79
|
+
if (node.properties.length === 0) return void 0;
|
|
80
|
+
const fields = [];
|
|
81
|
+
const schemas = [];
|
|
82
|
+
for (const property of node.properties) {
|
|
83
|
+
if (!ts.isPropertyAssignment(property) || !ts.isIdentifier(property.name) && !ts.isStringLiteral(property.name)) return void 0;
|
|
84
|
+
const key = property.name.text;
|
|
85
|
+
if (!key.trim() || ["__proto__", "constructor", "prototype"].includes(key)) return void 0;
|
|
86
|
+
if (ts.isObjectLiteralExpression(property.initializer)) {
|
|
87
|
+
const nested = compileShape(property.initializer, fieldName, runtime, `${path}[${JSON.stringify(key)}]`);
|
|
88
|
+
if (!nested) return void 0;
|
|
89
|
+
fields.push(`${JSON.stringify(key)}: ${nested.fields}`);
|
|
90
|
+
schemas.push(`${JSON.stringify(key)}: ${nested.code}`);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
const field = compileField(property.initializer, fieldName, runtime, `${path}[${JSON.stringify(key)}].definition`);
|
|
94
|
+
if (!field) return void 0;
|
|
95
|
+
const rules = field.definition.rules.map((rule) => `Object.freeze({name: ${JSON.stringify(rule.name)}, args: Object.freeze(${JSON.stringify(rule.args)})${rule.message ? `, message: ${JSON.stringify(rule.message)}` : ""}})`);
|
|
96
|
+
fields.push(`${JSON.stringify(key)}: Object.freeze({kind: 'field', definition: Object.freeze({kind: ${JSON.stringify(field.definition.kind)}, item: undefined, ${field.definition.sensitive ? "sensitive: true," : ""} rules: Object.freeze([${rules.join(",")}])})})`);
|
|
97
|
+
schemas.push(`${JSON.stringify(key)}: ${field.code}`);
|
|
98
|
+
}
|
|
99
|
+
return { fields: `Object.freeze({${fields.join(",")}})`, code: `${runtime}.objectAsync({${schemas.join(",")}})` };
|
|
100
|
+
}
|
|
101
|
+
function compileBrowserValidation(source, fileName = "schema.tsx") {
|
|
102
|
+
if (!source.includes("@holo-js/forms/schema") && !source.includes("@holo-js/validation")) return void 0;
|
|
103
|
+
const file = ts.createSourceFile(fileName, source, ts.ScriptTarget.Latest, true);
|
|
104
|
+
const diagnostics = ts.transpileModule(source, { fileName, reportDiagnostics: true, compilerOptions: { jsx: ts.JsxEmit.Preserve } }).diagnostics;
|
|
105
|
+
if (diagnostics?.some((diagnostic) => diagnostic.category === ts.DiagnosticCategory.Error)) return void 0;
|
|
106
|
+
let fieldName;
|
|
107
|
+
const schemaNames = /* @__PURE__ */ new Map();
|
|
108
|
+
for (const statement of file.statements) {
|
|
109
|
+
if (!ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier)) continue;
|
|
110
|
+
const packageName = statement.moduleSpecifier.text;
|
|
111
|
+
if (packageName !== "@holo-js/forms/schema" && packageName !== "@holo-js/validation") continue;
|
|
112
|
+
const bindings = statement.importClause?.namedBindings;
|
|
113
|
+
if (!bindings || !ts.isNamedImports(bindings) || statement.importClause?.isTypeOnly) continue;
|
|
114
|
+
for (const binding of bindings.elements) {
|
|
115
|
+
if (binding.isTypeOnly) continue;
|
|
116
|
+
const name = binding.propertyName?.text ?? binding.name.text;
|
|
117
|
+
if (name === "field") fieldName = binding.name.text;
|
|
118
|
+
if (name === "schema" || name === "defineSchema") schemaNames.set(binding.name.text, packageName === "@holo-js/forms/schema" && name === "schema");
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (!fieldName || schemaNames.size === 0) return void 0;
|
|
122
|
+
let runtime = "__holoValidation";
|
|
123
|
+
while (source.includes(runtime)) runtime += "_";
|
|
124
|
+
const replacements = [];
|
|
125
|
+
for (const statement of file.statements) {
|
|
126
|
+
if (!ts.isVariableStatement(statement) || !(statement.declarationList.flags & ts.NodeFlags.Const)) continue;
|
|
127
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
128
|
+
const call = declaration.initializer;
|
|
129
|
+
if (!call || !ts.isCallExpression(call) || !ts.isIdentifier(call.expression) || !schemaNames.has(call.expression.text) || call.arguments.length !== 1) continue;
|
|
130
|
+
const shape = call.arguments[0];
|
|
131
|
+
if (!shape || !ts.isObjectLiteralExpression(shape)) continue;
|
|
132
|
+
const compiled = compileShape(shape, fieldName, runtime);
|
|
133
|
+
if (!compiled) continue;
|
|
134
|
+
const mode = schemaNames.get(call.expression.text) ? "mode: 'form'," : "";
|
|
135
|
+
const code = `(() => { const fields = ${compiled.fields}; const compiled = ${compiled.code}; return Object.freeze({kind: 'schema', ${mode} fields, '~standard': {version: 1, vendor: 'holo-js', validate: ${runtime}.createSchemaStandardValidate(fields, () => compiled), types: undefined}}) })()`;
|
|
136
|
+
replacements.push({ start: call.getStart(file), end: call.end, code });
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (replacements.length === 0) return void 0;
|
|
140
|
+
let output = source;
|
|
141
|
+
for (const replacement of replacements.reverse()) output = output.slice(0, replacement.start) + replacement.code + output.slice(replacement.end);
|
|
142
|
+
return `${output}
|
|
143
|
+
import * as ${runtime} from '@holo-js/validation/internal/compiled'
|
|
144
|
+
`;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// src/build.ts
|
|
148
|
+
function propertyName(property) {
|
|
149
|
+
if (!("name" in property) || !property.name) return void 0;
|
|
150
|
+
return ts2.isIdentifier(property.name) || ts2.isStringLiteral(property.name) ? property.name.text : void 0;
|
|
151
|
+
}
|
|
152
|
+
function collectRealtimeFactories(sourceFile) {
|
|
153
|
+
const factories = /* @__PURE__ */ new Map([
|
|
154
|
+
["query", "query"],
|
|
155
|
+
["mutation", "mutation"]
|
|
156
|
+
]);
|
|
157
|
+
for (const statement of sourceFile.statements) {
|
|
158
|
+
if (!ts2.isImportDeclaration(statement) || !statement.importClause?.namedBindings) continue;
|
|
159
|
+
if (!ts2.isStringLiteral(statement.moduleSpecifier) || statement.moduleSpecifier.text !== "@holo-js/realtime") continue;
|
|
160
|
+
if (!ts2.isNamedImports(statement.importClause.namedBindings)) continue;
|
|
161
|
+
for (const element of statement.importClause.namedBindings.elements) {
|
|
162
|
+
const importedName = element.propertyName?.text ?? element.name.text;
|
|
163
|
+
if (importedName === "query" || importedName === "mutation") {
|
|
164
|
+
factories.set(element.name.text, importedName);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return factories;
|
|
169
|
+
}
|
|
170
|
+
function collectDefinitions(sourceFile) {
|
|
171
|
+
const definitions = [];
|
|
172
|
+
const factories = collectRealtimeFactories(sourceFile);
|
|
173
|
+
for (const statement of sourceFile.statements) {
|
|
174
|
+
if (!ts2.isVariableStatement(statement) || !statement.modifiers?.some((modifier) => modifier.kind === ts2.SyntaxKind.ExportKeyword)) continue;
|
|
175
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
176
|
+
if (!ts2.isIdentifier(declaration.name) || !declaration.initializer || !ts2.isCallExpression(declaration.initializer)) continue;
|
|
177
|
+
const factoryNode = declaration.initializer.expression;
|
|
178
|
+
if (!ts2.isIdentifier(factoryNode)) continue;
|
|
179
|
+
const factory = factories.get(factoryNode.text);
|
|
180
|
+
if (!factory) continue;
|
|
181
|
+
const definitionNode = declaration.initializer.arguments[0];
|
|
182
|
+
if (!definitionNode || !ts2.isObjectLiteralExpression(definitionNode)) continue;
|
|
183
|
+
const nameProperty = definitionNode.properties.find((property) => propertyName(property) === "name");
|
|
184
|
+
const name = nameProperty && ts2.isPropertyAssignment(nameProperty) ? nameProperty.initializer.getText(sourceFile) : void 0;
|
|
185
|
+
const sourceLine = sourceFile.getLineAndCharacterOfPosition(declaration.getStart(sourceFile)).line;
|
|
186
|
+
definitions.push({ exportedName: declaration.name.text, factory, sourceLine, ...name ? { name } : {} });
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return Object.freeze(definitions);
|
|
190
|
+
}
|
|
191
|
+
var base64VlqCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
192
|
+
function encodeVlq(value) {
|
|
193
|
+
let encoded = "";
|
|
194
|
+
let remaining = value < 0 ? (-value << 1) + 1 : value << 1;
|
|
195
|
+
do {
|
|
196
|
+
let digit = remaining & 31;
|
|
197
|
+
remaining >>>= 5;
|
|
198
|
+
if (remaining > 0) digit |= 32;
|
|
199
|
+
encoded += base64VlqCharacters[digit];
|
|
200
|
+
} while (remaining > 0);
|
|
201
|
+
return encoded;
|
|
202
|
+
}
|
|
203
|
+
function createSourceMap(source, sourceLines) {
|
|
204
|
+
let previousSourceLine = 0;
|
|
205
|
+
const mappings = sourceLines.map((sourceLine) => {
|
|
206
|
+
if (typeof sourceLine === "undefined") return "";
|
|
207
|
+
const segment = `${encodeVlq(0)}${encodeVlq(0)}${encodeVlq(sourceLine - previousSourceLine)}${encodeVlq(0)}`;
|
|
208
|
+
previousSourceLine = sourceLine;
|
|
209
|
+
return segment;
|
|
210
|
+
}).join(";");
|
|
211
|
+
return {
|
|
212
|
+
version: 3,
|
|
213
|
+
file: "realtime.client.ts",
|
|
214
|
+
sources: ["realtime.ts"],
|
|
215
|
+
sourcesContent: [source],
|
|
216
|
+
names: [],
|
|
217
|
+
mappings
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
function parseRealtimeSource(source) {
|
|
221
|
+
const result = ts2.transpileModule(source, {
|
|
222
|
+
compilerOptions: { module: ts2.ModuleKind.ESNext, target: ts2.ScriptTarget.ESNext },
|
|
223
|
+
reportDiagnostics: true
|
|
224
|
+
});
|
|
225
|
+
const diagnostic = result.diagnostics?.find((entry) => entry.category === ts2.DiagnosticCategory.Error);
|
|
226
|
+
if (diagnostic) {
|
|
227
|
+
throw new SyntaxError(ts2.flattenDiagnosticMessageText(diagnostic.messageText, "\n"));
|
|
228
|
+
}
|
|
229
|
+
return ts2.createSourceFile("realtime.ts", source, ts2.ScriptTarget.Latest, true, ts2.ScriptKind.TS);
|
|
230
|
+
}
|
|
231
|
+
function retargetRealtimeImports(source, importTarget) {
|
|
232
|
+
const sourceFile = parseRealtimeSource(source);
|
|
233
|
+
const transformer = (context) => (root) => {
|
|
234
|
+
const visit = (node) => {
|
|
235
|
+
if (ts2.isImportDeclaration(node) && ts2.isStringLiteral(node.moduleSpecifier) && node.moduleSpecifier.text === "@holo-js/realtime") {
|
|
236
|
+
return ts2.factory.updateImportDeclaration(
|
|
237
|
+
node,
|
|
238
|
+
node.modifiers,
|
|
239
|
+
node.importClause,
|
|
240
|
+
ts2.factory.createStringLiteral(importTarget),
|
|
241
|
+
node.attributes
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
return ts2.visitEachChild(node, visit, context);
|
|
245
|
+
};
|
|
246
|
+
return ts2.visitNode(root, visit);
|
|
247
|
+
};
|
|
248
|
+
const result = ts2.transform(sourceFile, [transformer]);
|
|
249
|
+
try {
|
|
250
|
+
return ts2.createPrinter({ newLine: ts2.NewLineKind.LineFeed }).printFile(result.transformed[0]);
|
|
251
|
+
} finally {
|
|
252
|
+
result.dispose();
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
function stripRealtimeServerHandlers(source) {
|
|
256
|
+
const sourceFile = parseRealtimeSource(source);
|
|
257
|
+
const transformer = (context) => (root) => {
|
|
258
|
+
const visit = (node) => {
|
|
259
|
+
if (ts2.isPropertyAssignment(node) && (propertyName(node) === "handler" || propertyName(node) === "authorize")) {
|
|
260
|
+
return ts2.factory.updatePropertyAssignment(node, node.name, ts2.factory.createIdentifier("undefined"));
|
|
261
|
+
}
|
|
262
|
+
if (ts2.isMethodDeclaration(node) && (propertyName(node) === "handler" || propertyName(node) === "authorize")) {
|
|
263
|
+
return ts2.factory.createPropertyAssignment(node.name, ts2.factory.createIdentifier("undefined"));
|
|
264
|
+
}
|
|
265
|
+
return ts2.visitEachChild(node, visit, context);
|
|
266
|
+
};
|
|
267
|
+
return ts2.visitNode(root, visit);
|
|
268
|
+
};
|
|
269
|
+
const result = ts2.transform(sourceFile, [transformer]);
|
|
270
|
+
try {
|
|
271
|
+
return ts2.createPrinter({ newLine: ts2.NewLineKind.LineFeed }).printFile(result.transformed[0]);
|
|
272
|
+
} finally {
|
|
273
|
+
result.dispose();
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
function createRealtimeClientDefinitionModule(source, importTarget) {
|
|
277
|
+
return createRealtimeClientDefinitionTransform(source, importTarget).code;
|
|
278
|
+
}
|
|
279
|
+
function createRealtimeClientDefinitionTransform(source, importTarget, options = {}) {
|
|
280
|
+
if (options.preserveServerHandlers) {
|
|
281
|
+
const code = retargetRealtimeImports(source, importTarget);
|
|
282
|
+
const sourceLineCount = source.split("\n").length;
|
|
283
|
+
return Object.freeze({
|
|
284
|
+
code,
|
|
285
|
+
map: createSourceMap(source, code.split("\n").map((_, index) => Math.min(index, sourceLineCount - 1)))
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
const sourceFile = parseRealtimeSource(source);
|
|
289
|
+
const definitions = collectDefinitions(sourceFile);
|
|
290
|
+
if (definitions.length === 0) {
|
|
291
|
+
const code = stripRealtimeServerHandlers(source);
|
|
292
|
+
const sourceLineCount = source.split("\n").length;
|
|
293
|
+
return Object.freeze({
|
|
294
|
+
code,
|
|
295
|
+
map: createSourceMap(source, code.split("\n").map((_, index) => Math.min(index, sourceLineCount - 1)))
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
const factories = [...new Set(definitions.map((definition) => definition.factory))];
|
|
299
|
+
const outputLines = [
|
|
300
|
+
`import { ${factories.join(", ")} } from '${importTarget}'`,
|
|
301
|
+
""
|
|
302
|
+
];
|
|
303
|
+
const sourceLines = [void 0, void 0];
|
|
304
|
+
for (const definition of definitions) {
|
|
305
|
+
outputLines.push(`export const ${definition.exportedName} = ${definition.factory}({`);
|
|
306
|
+
sourceLines.push(definition.sourceLine);
|
|
307
|
+
if (definition.name) {
|
|
308
|
+
outputLines.push(` name: ${definition.name},`);
|
|
309
|
+
sourceLines.push(definition.sourceLine);
|
|
310
|
+
}
|
|
311
|
+
outputLines.push(" handler: undefined,", "})", "");
|
|
312
|
+
sourceLines.push(definition.sourceLine, definition.sourceLine, void 0);
|
|
313
|
+
}
|
|
314
|
+
return Object.freeze({
|
|
315
|
+
code: outputLines.join("\n"),
|
|
316
|
+
map: createSourceMap(source, sourceLines)
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export {
|
|
321
|
+
compileBrowserValidation,
|
|
322
|
+
stripRealtimeServerHandlers,
|
|
323
|
+
createRealtimeClientDefinitionModule,
|
|
324
|
+
createRealtimeClientDefinitionTransform
|
|
325
|
+
};
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { NormalizedHoloHttpError } from '@holo-js/kernel/http-errors';
|
|
2
|
+
export { HoloHttpErrorStatus, NormalizedHoloHttpError, isHoloHttpErrorStatus, normalizeHoloHttpError } from '@holo-js/kernel/http-errors';
|
|
3
|
+
|
|
4
|
+
type ClientErrorPageOptions = {
|
|
5
|
+
readonly rootId: string;
|
|
6
|
+
readonly statusClassName: string;
|
|
7
|
+
};
|
|
8
|
+
declare function renderClientHttpErrorPage(error: NormalizedHoloHttpError, options: ClientErrorPageOptions): void;
|
|
9
|
+
|
|
10
|
+
export { type ClientErrorPageOptions, renderClientHttpErrorPage };
|
package/dist/client.mjs
ADDED
package/dist/index.d.ts
CHANGED
|
@@ -1,29 +1,3 @@
|
|
|
1
|
-
import { NormalizedHoloHttpError } from '@holo-js/kernel/http-errors';
|
|
2
1
|
export { HoloHttpErrorStatus, NormalizedHoloHttpError, isHoloHttpErrorStatus, normalizeHoloHttpError } from '@holo-js/kernel/http-errors';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
readonly rootId: string;
|
|
6
|
-
readonly statusClassName: string;
|
|
7
|
-
};
|
|
8
|
-
declare function renderClientHttpErrorPage(error: NormalizedHoloHttpError, options: ClientErrorPageOptions): void;
|
|
9
|
-
|
|
10
|
-
type RealtimeDefinitionSourceMap = {
|
|
11
|
-
readonly version: 3;
|
|
12
|
-
readonly file: string;
|
|
13
|
-
readonly sources: readonly string[];
|
|
14
|
-
readonly sourcesContent: readonly string[];
|
|
15
|
-
readonly names: readonly string[];
|
|
16
|
-
readonly mappings: string;
|
|
17
|
-
};
|
|
18
|
-
type RealtimeDefinitionTransformResult = {
|
|
19
|
-
readonly code: string;
|
|
20
|
-
readonly map: RealtimeDefinitionSourceMap;
|
|
21
|
-
};
|
|
22
|
-
type RealtimeDefinitionTransformOptions = {
|
|
23
|
-
readonly preserveServerHandlers?: boolean;
|
|
24
|
-
};
|
|
25
|
-
declare function stripRealtimeServerHandlers(source: string): string;
|
|
26
|
-
declare function createRealtimeClientDefinitionModule(source: string, importTarget: string): string;
|
|
27
|
-
declare function createRealtimeClientDefinitionTransform(source: string, importTarget: string, options?: RealtimeDefinitionTransformOptions): RealtimeDefinitionTransformResult;
|
|
28
|
-
|
|
29
|
-
export { type ClientErrorPageOptions, type RealtimeDefinitionSourceMap, type RealtimeDefinitionTransformOptions, type RealtimeDefinitionTransformResult, createRealtimeClientDefinitionModule, createRealtimeClientDefinitionTransform, renderClientHttpErrorPage, stripRealtimeServerHandlers };
|
|
2
|
+
export { ClientErrorPageOptions, renderClientHttpErrorPage } from './client.js';
|
|
3
|
+
export { RealtimeDefinitionSourceMap, RealtimeDefinitionTransformOptions, RealtimeDefinitionTransformResult, compileBrowserValidation, createRealtimeClientDefinitionModule, createRealtimeClientDefinitionTransform, stripRealtimeServerHandlers } from './build.js';
|
package/dist/index.mjs
CHANGED
|
@@ -1,216 +1,16 @@
|
|
|
1
|
-
// src/index.ts
|
|
2
|
-
import ts from "typescript";
|
|
3
1
|
import {
|
|
4
2
|
isHoloHttpErrorStatus,
|
|
5
|
-
normalizeHoloHttpError
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const root = existingRoot ?? browserDocument.createElement("main");
|
|
15
|
-
root.id = options.rootId;
|
|
16
|
-
root.setAttribute("role", "alert");
|
|
17
|
-
root.style.cssText = "position:fixed;inset:0;z-index:2147483647;display:grid;place-items:center;margin:0;background:#fff;color:#000;font-family:Arial,Helvetica,sans-serif";
|
|
18
|
-
const wrapper = browserDocument.createElement("div");
|
|
19
|
-
wrapper.style.cssText = "display:flex;align-items:center;gap:1.5rem;padding:1.5rem";
|
|
20
|
-
const status = browserDocument.createElement("h1");
|
|
21
|
-
status.className = options.statusClassName;
|
|
22
|
-
status.textContent = String(error.status);
|
|
23
|
-
status.style.cssText = "display:inline-block;margin:0 1.25rem 0 0;padding:0 1.5rem 0 0;font-size:24px;font-weight:500;line-height:49px;vertical-align:top;border-right:1px solid rgba(0,0,0,.3)";
|
|
24
|
-
const description = browserDocument.createElement("div");
|
|
25
|
-
description.style.cssText = "display:inline-block;text-align:left;line-height:49px;height:49px;vertical-align:middle";
|
|
26
|
-
const message = browserDocument.createElement("h2");
|
|
27
|
-
message.textContent = error.message;
|
|
28
|
-
message.style.cssText = "font-size:14px;font-weight:400;line-height:49px;margin:0";
|
|
29
|
-
description.append(message);
|
|
30
|
-
wrapper.append(status, description);
|
|
31
|
-
root.replaceChildren(wrapper);
|
|
32
|
-
for (const child of Array.from(browserDocument.body.children)) {
|
|
33
|
-
if (child.id !== root.id) child.style.display = "none";
|
|
34
|
-
}
|
|
35
|
-
if (!existingRoot) browserDocument.body.append(root);
|
|
36
|
-
}
|
|
37
|
-
function renderClientHttpErrorPage(error, options) {
|
|
38
|
-
escapePage(error, options);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// src/index.ts
|
|
42
|
-
function propertyName(property) {
|
|
43
|
-
if (!("name" in property) || !property.name) return void 0;
|
|
44
|
-
return ts.isIdentifier(property.name) || ts.isStringLiteral(property.name) ? property.name.text : void 0;
|
|
45
|
-
}
|
|
46
|
-
function collectRealtimeFactories(sourceFile) {
|
|
47
|
-
const factories = /* @__PURE__ */ new Map([
|
|
48
|
-
["query", "query"],
|
|
49
|
-
["mutation", "mutation"]
|
|
50
|
-
]);
|
|
51
|
-
for (const statement of sourceFile.statements) {
|
|
52
|
-
if (!ts.isImportDeclaration(statement) || !statement.importClause?.namedBindings) continue;
|
|
53
|
-
if (!ts.isStringLiteral(statement.moduleSpecifier) || statement.moduleSpecifier.text !== "@holo-js/realtime") continue;
|
|
54
|
-
if (!ts.isNamedImports(statement.importClause.namedBindings)) continue;
|
|
55
|
-
for (const element of statement.importClause.namedBindings.elements) {
|
|
56
|
-
const importedName = element.propertyName?.text ?? element.name.text;
|
|
57
|
-
if (importedName === "query" || importedName === "mutation") {
|
|
58
|
-
factories.set(element.name.text, importedName);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
return factories;
|
|
63
|
-
}
|
|
64
|
-
function collectDefinitions(sourceFile) {
|
|
65
|
-
const definitions = [];
|
|
66
|
-
const factories = collectRealtimeFactories(sourceFile);
|
|
67
|
-
for (const statement of sourceFile.statements) {
|
|
68
|
-
if (!ts.isVariableStatement(statement) || !statement.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword)) continue;
|
|
69
|
-
for (const declaration of statement.declarationList.declarations) {
|
|
70
|
-
if (!ts.isIdentifier(declaration.name) || !declaration.initializer || !ts.isCallExpression(declaration.initializer)) continue;
|
|
71
|
-
const factoryNode = declaration.initializer.expression;
|
|
72
|
-
if (!ts.isIdentifier(factoryNode)) continue;
|
|
73
|
-
const factory = factories.get(factoryNode.text);
|
|
74
|
-
if (!factory) continue;
|
|
75
|
-
const definitionNode = declaration.initializer.arguments[0];
|
|
76
|
-
if (!definitionNode || !ts.isObjectLiteralExpression(definitionNode)) continue;
|
|
77
|
-
const nameProperty = definitionNode.properties.find((property) => propertyName(property) === "name");
|
|
78
|
-
const name = nameProperty && ts.isPropertyAssignment(nameProperty) ? nameProperty.initializer.getText(sourceFile) : void 0;
|
|
79
|
-
const sourceLine = sourceFile.getLineAndCharacterOfPosition(declaration.getStart(sourceFile)).line;
|
|
80
|
-
definitions.push({ exportedName: declaration.name.text, factory, sourceLine, ...name ? { name } : {} });
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
return Object.freeze(definitions);
|
|
84
|
-
}
|
|
85
|
-
var base64VlqCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
86
|
-
function encodeVlq(value) {
|
|
87
|
-
let encoded = "";
|
|
88
|
-
let remaining = value < 0 ? (-value << 1) + 1 : value << 1;
|
|
89
|
-
do {
|
|
90
|
-
let digit = remaining & 31;
|
|
91
|
-
remaining >>>= 5;
|
|
92
|
-
if (remaining > 0) digit |= 32;
|
|
93
|
-
encoded += base64VlqCharacters[digit];
|
|
94
|
-
} while (remaining > 0);
|
|
95
|
-
return encoded;
|
|
96
|
-
}
|
|
97
|
-
function createSourceMap(source, sourceLines) {
|
|
98
|
-
let previousSourceLine = 0;
|
|
99
|
-
const mappings = sourceLines.map((sourceLine) => {
|
|
100
|
-
if (typeof sourceLine === "undefined") return "";
|
|
101
|
-
const segment = `${encodeVlq(0)}${encodeVlq(0)}${encodeVlq(sourceLine - previousSourceLine)}${encodeVlq(0)}`;
|
|
102
|
-
previousSourceLine = sourceLine;
|
|
103
|
-
return segment;
|
|
104
|
-
}).join(";");
|
|
105
|
-
return {
|
|
106
|
-
version: 3,
|
|
107
|
-
file: "realtime.client.ts",
|
|
108
|
-
sources: ["realtime.ts"],
|
|
109
|
-
sourcesContent: [source],
|
|
110
|
-
names: [],
|
|
111
|
-
mappings
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
function parseRealtimeSource(source) {
|
|
115
|
-
const result = ts.transpileModule(source, {
|
|
116
|
-
compilerOptions: { module: ts.ModuleKind.ESNext, target: ts.ScriptTarget.ESNext },
|
|
117
|
-
reportDiagnostics: true
|
|
118
|
-
});
|
|
119
|
-
const diagnostic = result.diagnostics?.find((entry) => entry.category === ts.DiagnosticCategory.Error);
|
|
120
|
-
if (diagnostic) {
|
|
121
|
-
throw new SyntaxError(ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n"));
|
|
122
|
-
}
|
|
123
|
-
return ts.createSourceFile("realtime.ts", source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
124
|
-
}
|
|
125
|
-
function retargetRealtimeImports(source, importTarget) {
|
|
126
|
-
const sourceFile = parseRealtimeSource(source);
|
|
127
|
-
const transformer = (context) => (root) => {
|
|
128
|
-
const visit = (node) => {
|
|
129
|
-
if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier) && node.moduleSpecifier.text === "@holo-js/realtime") {
|
|
130
|
-
return ts.factory.updateImportDeclaration(
|
|
131
|
-
node,
|
|
132
|
-
node.modifiers,
|
|
133
|
-
node.importClause,
|
|
134
|
-
ts.factory.createStringLiteral(importTarget),
|
|
135
|
-
node.attributes
|
|
136
|
-
);
|
|
137
|
-
}
|
|
138
|
-
return ts.visitEachChild(node, visit, context);
|
|
139
|
-
};
|
|
140
|
-
return ts.visitNode(root, visit);
|
|
141
|
-
};
|
|
142
|
-
const result = ts.transform(sourceFile, [transformer]);
|
|
143
|
-
try {
|
|
144
|
-
return ts.createPrinter({ newLine: ts.NewLineKind.LineFeed }).printFile(result.transformed[0]);
|
|
145
|
-
} finally {
|
|
146
|
-
result.dispose();
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
function stripRealtimeServerHandlers(source) {
|
|
150
|
-
const sourceFile = parseRealtimeSource(source);
|
|
151
|
-
const transformer = (context) => (root) => {
|
|
152
|
-
const visit = (node) => {
|
|
153
|
-
if (ts.isPropertyAssignment(node) && (propertyName(node) === "handler" || propertyName(node) === "authorize")) {
|
|
154
|
-
return ts.factory.updatePropertyAssignment(node, node.name, ts.factory.createIdentifier("undefined"));
|
|
155
|
-
}
|
|
156
|
-
if (ts.isMethodDeclaration(node) && (propertyName(node) === "handler" || propertyName(node) === "authorize")) {
|
|
157
|
-
return ts.factory.createPropertyAssignment(node.name, ts.factory.createIdentifier("undefined"));
|
|
158
|
-
}
|
|
159
|
-
return ts.visitEachChild(node, visit, context);
|
|
160
|
-
};
|
|
161
|
-
return ts.visitNode(root, visit);
|
|
162
|
-
};
|
|
163
|
-
const result = ts.transform(sourceFile, [transformer]);
|
|
164
|
-
try {
|
|
165
|
-
return ts.createPrinter({ newLine: ts.NewLineKind.LineFeed }).printFile(result.transformed[0]);
|
|
166
|
-
} finally {
|
|
167
|
-
result.dispose();
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
function createRealtimeClientDefinitionModule(source, importTarget) {
|
|
171
|
-
return createRealtimeClientDefinitionTransform(source, importTarget).code;
|
|
172
|
-
}
|
|
173
|
-
function createRealtimeClientDefinitionTransform(source, importTarget, options = {}) {
|
|
174
|
-
if (options.preserveServerHandlers) {
|
|
175
|
-
const code = retargetRealtimeImports(source, importTarget);
|
|
176
|
-
const sourceLineCount = source.split("\n").length;
|
|
177
|
-
return Object.freeze({
|
|
178
|
-
code,
|
|
179
|
-
map: createSourceMap(source, code.split("\n").map((_, index) => Math.min(index, sourceLineCount - 1)))
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
const sourceFile = parseRealtimeSource(source);
|
|
183
|
-
const definitions = collectDefinitions(sourceFile);
|
|
184
|
-
if (definitions.length === 0) {
|
|
185
|
-
const code = stripRealtimeServerHandlers(source);
|
|
186
|
-
const sourceLineCount = source.split("\n").length;
|
|
187
|
-
return Object.freeze({
|
|
188
|
-
code,
|
|
189
|
-
map: createSourceMap(source, code.split("\n").map((_, index) => Math.min(index, sourceLineCount - 1)))
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
const factories = [...new Set(definitions.map((definition) => definition.factory))];
|
|
193
|
-
const outputLines = [
|
|
194
|
-
`import { ${factories.join(", ")} } from '${importTarget}'`,
|
|
195
|
-
""
|
|
196
|
-
];
|
|
197
|
-
const sourceLines = [void 0, void 0];
|
|
198
|
-
for (const definition of definitions) {
|
|
199
|
-
outputLines.push(`export const ${definition.exportedName} = ${definition.factory}({`);
|
|
200
|
-
sourceLines.push(definition.sourceLine);
|
|
201
|
-
if (definition.name) {
|
|
202
|
-
outputLines.push(` name: ${definition.name},`);
|
|
203
|
-
sourceLines.push(definition.sourceLine);
|
|
204
|
-
}
|
|
205
|
-
outputLines.push(" handler: undefined,", "})", "");
|
|
206
|
-
sourceLines.push(definition.sourceLine, definition.sourceLine, void 0);
|
|
207
|
-
}
|
|
208
|
-
return Object.freeze({
|
|
209
|
-
code: outputLines.join("\n"),
|
|
210
|
-
map: createSourceMap(source, sourceLines)
|
|
211
|
-
});
|
|
212
|
-
}
|
|
3
|
+
normalizeHoloHttpError,
|
|
4
|
+
renderClientHttpErrorPage
|
|
5
|
+
} from "./chunk-3GNER7MY.mjs";
|
|
6
|
+
import {
|
|
7
|
+
compileBrowserValidation,
|
|
8
|
+
createRealtimeClientDefinitionModule,
|
|
9
|
+
createRealtimeClientDefinitionTransform,
|
|
10
|
+
stripRealtimeServerHandlers
|
|
11
|
+
} from "./chunk-NSZSPJAF.mjs";
|
|
213
12
|
export {
|
|
13
|
+
compileBrowserValidation,
|
|
214
14
|
createRealtimeClientDefinitionModule,
|
|
215
15
|
createRealtimeClientDefinitionTransform,
|
|
216
16
|
isHoloHttpErrorStatus,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@holo-js/adapter-shared",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.15",
|
|
4
4
|
"description": "Holo-JS Framework - shared framework adapter infrastructure",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -9,6 +9,16 @@
|
|
|
9
9
|
"types": "./dist/index.d.ts",
|
|
10
10
|
"import": "./dist/index.mjs",
|
|
11
11
|
"default": "./dist/index.mjs"
|
|
12
|
+
},
|
|
13
|
+
"./client": {
|
|
14
|
+
"types": "./dist/client.d.ts",
|
|
15
|
+
"import": "./dist/client.mjs",
|
|
16
|
+
"default": "./dist/client.mjs"
|
|
17
|
+
},
|
|
18
|
+
"./build": {
|
|
19
|
+
"types": "./dist/build.d.ts",
|
|
20
|
+
"import": "./dist/build.mjs",
|
|
21
|
+
"default": "./dist/build.mjs"
|
|
12
22
|
}
|
|
13
23
|
},
|
|
14
24
|
"main": "./dist/index.mjs",
|
|
@@ -23,11 +33,14 @@
|
|
|
23
33
|
"test": "vitest --run"
|
|
24
34
|
},
|
|
25
35
|
"dependencies": {
|
|
26
|
-
"@holo-js/kernel": "^0.3.
|
|
36
|
+
"@holo-js/kernel": "^0.3.15",
|
|
27
37
|
"typescript": "^5.7.2"
|
|
28
38
|
},
|
|
29
39
|
"devDependencies": {
|
|
30
40
|
"tsup": "^8.3.5",
|
|
31
41
|
"vitest": "^4.1.5"
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=22.12.0"
|
|
32
45
|
}
|
|
33
46
|
}
|