@holo-js/adapter-shared 0.3.28 → 0.4.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/dist/.holo-build-fingerprint +1 -0
- package/dist/build.d.ts +10 -4
- package/dist/build.mjs +1 -1
- package/dist/{chunk-6FHRFQPC.mjs → chunk-YDL2S5BT.mjs} +208 -41
- package/dist/client.d.ts +2 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/next/request-context.d.ts +2 -1
- package/dist/realtime-directories.d.ts +5 -0
- package/dist/realtime-directories.mjs +57 -0
- package/dist/server-errors.d.ts +14 -1
- package/dist/server-errors.mjs +18 -2
- package/dist/sveltekit/request-context.d.ts +6 -1
- package/package.json +18 -7
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Holo-JS contributors
|
|
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.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
122e52661fefc2883aa2e049b26b8a1bad6018b5c8d8ca45bc0a0278ab8323a5
|
package/dist/build.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ type RealtimeDefinitionSourceMap = {
|
|
|
6
6
|
readonly version: 3;
|
|
7
7
|
readonly file: string;
|
|
8
8
|
readonly sources: readonly string[];
|
|
9
|
-
readonly sourcesContent
|
|
9
|
+
readonly sourcesContent?: readonly string[];
|
|
10
10
|
readonly names: readonly string[];
|
|
11
11
|
readonly mappings: string;
|
|
12
12
|
};
|
|
@@ -17,8 +17,14 @@ type RealtimeDefinitionTransformResult = {
|
|
|
17
17
|
type RealtimeDefinitionTransformOptions = {
|
|
18
18
|
readonly preserveServerHandlers?: boolean;
|
|
19
19
|
};
|
|
20
|
+
type RealtimeDefinitionTransformInput = RealtimeDefinitionTransformOptions & {
|
|
21
|
+
readonly source: string;
|
|
22
|
+
readonly importTarget: string;
|
|
23
|
+
readonly filePath: string;
|
|
24
|
+
};
|
|
20
25
|
declare function stripRealtimeServerHandlers(source: string): string;
|
|
21
|
-
declare function createRealtimeClientDefinitionModule(
|
|
22
|
-
declare function createRealtimeClientDefinitionTransform(
|
|
26
|
+
declare function createRealtimeClientDefinitionModule(input: Omit<RealtimeDefinitionTransformInput, 'preserveServerHandlers'>): string;
|
|
27
|
+
declare function createRealtimeClientDefinitionTransform(input: RealtimeDefinitionTransformInput): RealtimeDefinitionTransformResult;
|
|
23
28
|
|
|
24
|
-
export {
|
|
29
|
+
export { compileBrowserValidation, compileNextRoute, createRealtimeClientDefinitionModule, createRealtimeClientDefinitionTransform, stripRealtimeServerHandlers };
|
|
30
|
+
export type { RealtimeDefinitionSourceMap, RealtimeDefinitionTransformInput, RealtimeDefinitionTransformOptions, RealtimeDefinitionTransformResult };
|
package/dist/build.mjs
CHANGED
|
@@ -245,41 +245,200 @@ function propertyName(property) {
|
|
|
245
245
|
if (!("name" in property) || !property.name) return void 0;
|
|
246
246
|
return ts3.isIdentifier(property.name) || ts3.isStringLiteral(property.name) ? property.name.text : void 0;
|
|
247
247
|
}
|
|
248
|
-
|
|
248
|
+
var realtimeFactoryExports = /* @__PURE__ */ new Map([
|
|
249
|
+
["query", "query"],
|
|
250
|
+
["mutation", "mutation"],
|
|
251
|
+
["defineRealtimeQuery", "query"],
|
|
252
|
+
["defineRealtimeMutation", "mutation"]
|
|
253
|
+
]);
|
|
254
|
+
function referenceRoot(expression) {
|
|
255
|
+
let current = unwrapExpression(expression);
|
|
256
|
+
while (ts3.isPropertyAccessExpression(current) || ts3.isElementAccessExpression(current)) {
|
|
257
|
+
current = unwrapExpression(current.expression);
|
|
258
|
+
}
|
|
259
|
+
return ts3.isIdentifier(current) ? current : void 0;
|
|
260
|
+
}
|
|
261
|
+
function boundNames(name) {
|
|
262
|
+
if (ts3.isIdentifier(name)) return [name.text];
|
|
263
|
+
return name.elements.flatMap((element) => ts3.isBindingElement(element) ? boundNames(element.name) : []);
|
|
264
|
+
}
|
|
265
|
+
function collectRealtimeBindings(sourceFile, importTarget) {
|
|
249
266
|
const factories = /* @__PURE__ */ new Map([
|
|
250
267
|
["query", "query"],
|
|
251
268
|
["mutation", "mutation"]
|
|
252
269
|
]);
|
|
270
|
+
const namespaces = /* @__PURE__ */ new Set();
|
|
271
|
+
const aliases = /* @__PURE__ */ new Set();
|
|
253
272
|
for (const statement of sourceFile.statements) {
|
|
254
|
-
if (!ts3.isImportDeclaration(statement) || !statement.importClause
|
|
255
|
-
if (!ts3.isStringLiteral(statement.moduleSpecifier) || statement.moduleSpecifier.text !== "@holo-js/realtime") continue;
|
|
256
|
-
|
|
257
|
-
|
|
273
|
+
if (!ts3.isImportDeclaration(statement) || !statement.importClause || statement.importClause.isTypeOnly) continue;
|
|
274
|
+
if (!ts3.isStringLiteral(statement.moduleSpecifier) || statement.moduleSpecifier.text !== "@holo-js/realtime" && statement.moduleSpecifier.text !== importTarget) continue;
|
|
275
|
+
const { name, namedBindings } = statement.importClause;
|
|
276
|
+
if (name) namespaces.add(name.text);
|
|
277
|
+
if (namedBindings && ts3.isNamespaceImport(namedBindings)) namespaces.add(namedBindings.name.text);
|
|
278
|
+
if (!namedBindings || !ts3.isNamedImports(namedBindings)) continue;
|
|
279
|
+
for (const element of namedBindings.elements) {
|
|
280
|
+
if (element.isTypeOnly) continue;
|
|
258
281
|
const importedName = element.propertyName?.text ?? element.name.text;
|
|
259
|
-
if (importedName === "
|
|
260
|
-
|
|
282
|
+
if (importedName === "default") {
|
|
283
|
+
namespaces.add(element.name.text);
|
|
284
|
+
continue;
|
|
261
285
|
}
|
|
286
|
+
const factory = realtimeFactoryExports.get(importedName);
|
|
287
|
+
if (factory) factories.set(element.name.text, factory);
|
|
262
288
|
}
|
|
263
289
|
}
|
|
264
|
-
|
|
290
|
+
for (const statement of sourceFile.statements) {
|
|
291
|
+
if (!ts3.isVariableStatement(statement)) continue;
|
|
292
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
293
|
+
const root = declaration.initializer && referenceRoot(declaration.initializer);
|
|
294
|
+
if (root && (factories.has(root.text) || namespaces.has(root.text) || aliases.has(root.text))) {
|
|
295
|
+
for (const name of boundNames(declaration.name)) aliases.add(name);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return { factories, namespaces, aliases };
|
|
265
300
|
}
|
|
266
|
-
function
|
|
267
|
-
|
|
268
|
-
const
|
|
301
|
+
function namespaceMember(callee, bindings) {
|
|
302
|
+
if (!ts3.isPropertyAccessExpression(callee) && !ts3.isElementAccessExpression(callee)) return void 0;
|
|
303
|
+
const namespace = unwrapExpression(callee.expression);
|
|
304
|
+
if (!ts3.isIdentifier(namespace) || !bindings.namespaces.has(namespace.text)) return void 0;
|
|
305
|
+
if (ts3.isPropertyAccessExpression(callee)) return callee.name.text;
|
|
306
|
+
return ts3.isStringLiteralLike(callee.argumentExpression) ? callee.argumentExpression.text : void 0;
|
|
307
|
+
}
|
|
308
|
+
function resolveFactory(wrappedCallee, bindings) {
|
|
309
|
+
const callee = unwrapExpression(wrappedCallee);
|
|
310
|
+
if (ts3.isIdentifier(callee)) return bindings.factories.get(callee.text);
|
|
311
|
+
const member = namespaceMember(callee, bindings);
|
|
312
|
+
return member === void 0 ? void 0 : realtimeFactoryExports.get(member);
|
|
313
|
+
}
|
|
314
|
+
function unwrapExpression(expression) {
|
|
315
|
+
let current = expression;
|
|
316
|
+
while (ts3.isParenthesizedExpression(current) || ts3.isAsExpression(current) || ts3.isSatisfiesExpression(current) || ts3.isTypeAssertionExpression(current) || ts3.isNonNullExpression(current)) {
|
|
317
|
+
current = current.expression;
|
|
318
|
+
}
|
|
319
|
+
return current;
|
|
320
|
+
}
|
|
321
|
+
function containsFactoryCall(node, bindings) {
|
|
322
|
+
if (ts3.isCallExpression(node) && resolveFactory(node.expression, bindings)) return true;
|
|
323
|
+
return ts3.forEachChild(node, (child) => containsFactoryCall(child, bindings) || void 0) ?? false;
|
|
324
|
+
}
|
|
325
|
+
function containsRealtimeReference(node, bindings) {
|
|
326
|
+
return containsFactoryCall(node, bindings) || referencesName(node, /* @__PURE__ */ new Set([...bindings.namespaces, ...bindings.aliases]));
|
|
327
|
+
}
|
|
328
|
+
function collectStringConstants(sourceFile) {
|
|
329
|
+
const constants = /* @__PURE__ */ new Map();
|
|
269
330
|
for (const statement of sourceFile.statements) {
|
|
270
|
-
if (!ts3.isVariableStatement(statement) || !statement.modifiers?.some((modifier) => modifier.kind === ts3.SyntaxKind.
|
|
331
|
+
if (!ts3.isVariableStatement(statement) || !(statement.declarationList.flags & ts3.NodeFlags.Const) || statement.modifiers?.some((modifier) => modifier.kind === ts3.SyntaxKind.DeclareKeyword)) continue;
|
|
271
332
|
for (const declaration of statement.declarationList.declarations) {
|
|
272
|
-
if (
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
333
|
+
if (ts3.isIdentifier(declaration.name) && declaration.initializer && ts3.isStringLiteralLike(declaration.initializer)) {
|
|
334
|
+
constants.set(declaration.name.text, declaration.initializer);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return constants;
|
|
339
|
+
}
|
|
340
|
+
function definitionKey(property) {
|
|
341
|
+
if (!property.name) return void 0;
|
|
342
|
+
if (ts3.isComputedPropertyName(property.name)) {
|
|
343
|
+
const expression = unwrapExpression(property.name.expression);
|
|
344
|
+
return ts3.isStringLiteralLike(expression) ? expression.text : void 0;
|
|
345
|
+
}
|
|
346
|
+
return ts3.isIdentifier(property.name) || ts3.isStringLiteral(property.name) || ts3.isNumericLiteral(property.name) ? property.name.text : void 0;
|
|
347
|
+
}
|
|
348
|
+
function definitionNameValue(property, constants) {
|
|
349
|
+
const value = ts3.isShorthandPropertyAssignment(property) ? property.name : ts3.isPropertyAssignment(property) ? unwrapExpression(property.initializer) : void 0;
|
|
350
|
+
const literal2 = value && (ts3.isStringLiteralLike(value) ? value : ts3.isIdentifier(value) ? constants.get(value.text) : void 0);
|
|
351
|
+
return literal2 ? { known: true, literal: literal2 } : { known: false };
|
|
352
|
+
}
|
|
353
|
+
function resolveDefinitionName(definitionNode, constants) {
|
|
354
|
+
let name = { known: true };
|
|
355
|
+
for (const property of definitionNode.properties) {
|
|
356
|
+
if (ts3.isSpreadAssignment(property)) {
|
|
357
|
+
name = { known: false };
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
const key = definitionKey(property);
|
|
361
|
+
if (key === "name") {
|
|
362
|
+
name = definitionNameValue(property, constants);
|
|
363
|
+
} else if (key === void 0 && property.name && ts3.isComputedPropertyName(property.name)) {
|
|
364
|
+
name = { known: false };
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return name;
|
|
368
|
+
}
|
|
369
|
+
function referencesName(node, names) {
|
|
370
|
+
if (ts3.isIdentifier(node) && names.has(node.text)) {
|
|
371
|
+
const parent = node.parent;
|
|
372
|
+
const isPropertyName = ts3.isPropertyAccessExpression(parent) && parent.name === node || (ts3.isPropertyAssignment(parent) || ts3.isMethodDeclaration(parent) || ts3.isPropertyDeclaration(parent) || ts3.isGetAccessorDeclaration(parent) || ts3.isSetAccessorDeclaration(parent)) && parent.name === node;
|
|
373
|
+
if (!isPropertyName) return true;
|
|
374
|
+
}
|
|
375
|
+
return ts3.forEachChild(node, (child) => referencesName(child, names) || void 0) ?? false;
|
|
376
|
+
}
|
|
377
|
+
function collectDefinitionLocals(sourceFile, bindings) {
|
|
378
|
+
const locals = /* @__PURE__ */ new Set();
|
|
379
|
+
const declarations = sourceFile.statements.filter(ts3.isVariableStatement).flatMap((statement) => [...statement.declarationList.declarations]);
|
|
380
|
+
let changed = true;
|
|
381
|
+
while (changed) {
|
|
382
|
+
changed = false;
|
|
383
|
+
for (const declaration of declarations) {
|
|
384
|
+
if (!declaration.initializer) continue;
|
|
385
|
+
if (!containsRealtimeReference(declaration.initializer, bindings) && !referencesName(declaration.initializer, locals)) continue;
|
|
386
|
+
for (const name of boundNames(declaration.name)) {
|
|
387
|
+
if (!locals.has(name)) {
|
|
388
|
+
locals.add(name);
|
|
389
|
+
changed = true;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
return locals;
|
|
395
|
+
}
|
|
396
|
+
function unreducibleDefinitionError(filePath, exportedName) {
|
|
397
|
+
return new Error(`${filePath} exports ${exportedName} through a query or mutation call that cannot be reduced to a browser definition. Export each definition directly, as export const name = query({ name: 'posts.list', ... }) or export default query({ ... }).`);
|
|
398
|
+
}
|
|
399
|
+
function collectDefinitions(sourceFile, filePath, importTarget) {
|
|
400
|
+
const definitions = [];
|
|
401
|
+
const bindings = collectRealtimeBindings(sourceFile, importTarget);
|
|
402
|
+
const constants = collectStringConstants(sourceFile);
|
|
403
|
+
const definitionLocals = collectDefinitionLocals(sourceFile, bindings);
|
|
404
|
+
const recordDefinition = (exportedName, expression, node) => {
|
|
405
|
+
const call = unwrapExpression(expression);
|
|
406
|
+
const factory = ts3.isCallExpression(call) ? resolveFactory(call.expression, bindings) : void 0;
|
|
407
|
+
if (!ts3.isCallExpression(call) || !factory) {
|
|
408
|
+
if (containsRealtimeReference(expression, bindings) || referencesName(expression, definitionLocals)) {
|
|
409
|
+
throw unreducibleDefinitionError(filePath, exportedName);
|
|
410
|
+
}
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
const definitionNode = call.arguments[0];
|
|
414
|
+
if (!definitionNode || !ts3.isObjectLiteralExpression(definitionNode)) throw unreducibleDefinitionError(filePath, exportedName);
|
|
415
|
+
const name = resolveDefinitionName(definitionNode, constants);
|
|
416
|
+
if (!name.known) {
|
|
417
|
+
throw new Error(`${filePath} defines ${exportedName} with a name that is not a string literal, so it cannot be sent to the browser.`);
|
|
418
|
+
}
|
|
419
|
+
const sourceLine = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line;
|
|
420
|
+
definitions.push({ exportedName, factory, sourceLine, ...name.literal ? { name: name.literal.getText(sourceFile) } : {} });
|
|
421
|
+
};
|
|
422
|
+
for (const statement of sourceFile.statements) {
|
|
423
|
+
if (ts3.isVariableStatement(statement)) {
|
|
424
|
+
if (!statement.modifiers?.some((modifier) => modifier.kind === ts3.SyntaxKind.ExportKeyword)) continue;
|
|
425
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
426
|
+
if (!declaration.initializer) continue;
|
|
427
|
+
if (!ts3.isIdentifier(declaration.name)) {
|
|
428
|
+
if (boundNames(declaration.name).some((name) => definitionLocals.has(name))) {
|
|
429
|
+
throw unreducibleDefinitionError(filePath, declaration.name.getText(sourceFile));
|
|
430
|
+
}
|
|
431
|
+
continue;
|
|
432
|
+
}
|
|
433
|
+
recordDefinition(declaration.name.text, declaration.initializer, declaration);
|
|
434
|
+
}
|
|
435
|
+
} else if (ts3.isExportAssignment(statement) && !statement.isExportEquals) {
|
|
436
|
+
recordDefinition("default", statement.expression, statement);
|
|
437
|
+
} else if (ts3.isExportDeclaration(statement) && !statement.moduleSpecifier && !statement.isTypeOnly && statement.exportClause && ts3.isNamedExports(statement.exportClause)) {
|
|
438
|
+
for (const element of statement.exportClause.elements) {
|
|
439
|
+
const localName = element.propertyName?.text ?? element.name.text;
|
|
440
|
+
if (!element.isTypeOnly && definitionLocals.has(localName)) throw unreducibleDefinitionError(filePath, element.name.text);
|
|
441
|
+
}
|
|
283
442
|
}
|
|
284
443
|
}
|
|
285
444
|
return Object.freeze(definitions);
|
|
@@ -296,7 +455,7 @@ function encodeVlq(value) {
|
|
|
296
455
|
} while (remaining > 0);
|
|
297
456
|
return encoded;
|
|
298
457
|
}
|
|
299
|
-
function createSourceMap(
|
|
458
|
+
function createSourceMap(sourceLines, sourcesContent) {
|
|
300
459
|
let previousSourceLine = 0;
|
|
301
460
|
const mappings = sourceLines.map((sourceLine) => {
|
|
302
461
|
if (typeof sourceLine === "undefined") return "";
|
|
@@ -308,7 +467,7 @@ function createSourceMap(source, sourceLines) {
|
|
|
308
467
|
version: 3,
|
|
309
468
|
file: "realtime.client.ts",
|
|
310
469
|
sources: ["realtime.ts"],
|
|
311
|
-
sourcesContent:
|
|
470
|
+
...sourcesContent ? { sourcesContent } : {},
|
|
312
471
|
names: [],
|
|
313
472
|
mappings
|
|
314
473
|
};
|
|
@@ -369,36 +528,44 @@ function stripRealtimeServerHandlers(source) {
|
|
|
369
528
|
result.dispose();
|
|
370
529
|
}
|
|
371
530
|
}
|
|
372
|
-
function createRealtimeClientDefinitionModule(
|
|
373
|
-
return createRealtimeClientDefinitionTransform(
|
|
531
|
+
function createRealtimeClientDefinitionModule(input) {
|
|
532
|
+
return createRealtimeClientDefinitionTransform(input).code;
|
|
374
533
|
}
|
|
375
|
-
function createRealtimeClientDefinitionTransform(
|
|
376
|
-
if (
|
|
534
|
+
function createRealtimeClientDefinitionTransform(input) {
|
|
535
|
+
if (typeof input !== "object" || input === null || typeof input.source !== "string" || typeof input.importTarget !== "string" || typeof input.filePath !== "string") {
|
|
536
|
+
throw new TypeError("createRealtimeClientDefinitionTransform takes one object with source, importTarget, and filePath strings, and an optional preserveServerHandlers flag.");
|
|
537
|
+
}
|
|
538
|
+
const { source, importTarget, filePath } = input;
|
|
539
|
+
if (input.preserveServerHandlers) {
|
|
377
540
|
const code = retargetRealtimeImports(source, importTarget);
|
|
378
541
|
const sourceLineCount = source.split("\n").length;
|
|
379
542
|
return Object.freeze({
|
|
380
543
|
code,
|
|
381
|
-
map: createSourceMap(
|
|
544
|
+
map: createSourceMap(code.split("\n").map((_, index) => Math.min(index, sourceLineCount - 1)), [source])
|
|
382
545
|
});
|
|
383
546
|
}
|
|
384
547
|
const sourceFile = parseRealtimeSource(source);
|
|
385
|
-
const definitions = collectDefinitions(sourceFile);
|
|
548
|
+
const definitions = collectDefinitions(sourceFile, filePath, importTarget);
|
|
386
549
|
if (definitions.length === 0) {
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
550
|
+
throw new Error(`${filePath} has no query or mutation definitions, so it cannot be sent to the browser. Keep server-only code out of server/realtime, or move it out of that folder.`);
|
|
551
|
+
}
|
|
552
|
+
const exportedNames = new Set(definitions.map((definition) => definition.exportedName));
|
|
553
|
+
const factoryLocals = /* @__PURE__ */ new Map();
|
|
554
|
+
for (const definition of definitions) {
|
|
555
|
+
if (factoryLocals.has(definition.factory)) continue;
|
|
556
|
+
let local = definition.factory;
|
|
557
|
+
while (exportedNames.has(local)) local = `_${local}`;
|
|
558
|
+
factoryLocals.set(definition.factory, local);
|
|
393
559
|
}
|
|
394
|
-
const
|
|
560
|
+
const importSpecifiers = [...factoryLocals].map(([factory, local]) => factory === local ? factory : `${factory} as ${local}`);
|
|
395
561
|
const outputLines = [
|
|
396
|
-
`import { ${
|
|
562
|
+
`import { ${importSpecifiers.join(", ")} } from '${importTarget}'`,
|
|
397
563
|
""
|
|
398
564
|
];
|
|
399
565
|
const sourceLines = [void 0, void 0];
|
|
400
566
|
for (const definition of definitions) {
|
|
401
|
-
|
|
567
|
+
const factory = factoryLocals.get(definition.factory);
|
|
568
|
+
outputLines.push(definition.exportedName === "default" ? `export default ${factory}({` : `export const ${definition.exportedName} = ${factory}({`);
|
|
402
569
|
sourceLines.push(definition.sourceLine);
|
|
403
570
|
if (definition.name) {
|
|
404
571
|
outputLines.push(` name: ${definition.name},`);
|
|
@@ -409,7 +576,7 @@ function createRealtimeClientDefinitionTransform(source, importTarget, options =
|
|
|
409
576
|
}
|
|
410
577
|
return Object.freeze({
|
|
411
578
|
code: outputLines.join("\n"),
|
|
412
|
-
map: createSourceMap(
|
|
579
|
+
map: createSourceMap(sourceLines)
|
|
413
580
|
});
|
|
414
581
|
}
|
|
415
582
|
|
package/dist/client.d.ts
CHANGED
|
@@ -7,4 +7,5 @@ type ClientErrorPageOptions = {
|
|
|
7
7
|
};
|
|
8
8
|
declare function renderClientHttpErrorPage(error: NormalizedHoloHttpError, options: ClientErrorPageOptions): void;
|
|
9
9
|
|
|
10
|
-
export {
|
|
10
|
+
export { renderClientHttpErrorPage };
|
|
11
|
+
export type { ClientErrorPageOptions };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { HoloHttpErrorStatus, NormalizedHoloHttpError, isHoloHttpErrorStatus, normalizeHoloHttpError } from '@holo-js/kernel/http-errors';
|
|
2
2
|
export { ClientErrorPageOptions, renderClientHttpErrorPage } from './client.js';
|
|
3
|
-
export { RealtimeDefinitionSourceMap, RealtimeDefinitionTransformOptions, RealtimeDefinitionTransformResult, compileBrowserValidation, compileNextRoute, createRealtimeClientDefinitionModule, createRealtimeClientDefinitionTransform, stripRealtimeServerHandlers } from './build.js';
|
|
3
|
+
export { RealtimeDefinitionSourceMap, RealtimeDefinitionTransformInput, RealtimeDefinitionTransformOptions, RealtimeDefinitionTransformResult, compileBrowserValidation, compileNextRoute, createRealtimeClientDefinitionModule, createRealtimeClientDefinitionTransform, stripRealtimeServerHandlers } from './build.js';
|
package/dist/index.mjs
CHANGED
|
@@ -11,4 +11,5 @@ type NextRequestLike = {
|
|
|
11
11
|
declare function getCurrentNextRequest(): NextRequestLike | undefined;
|
|
12
12
|
declare function runWithNextRequest<TValue>(request: NextRequestLike, callback: () => TValue): TValue;
|
|
13
13
|
|
|
14
|
-
export {
|
|
14
|
+
export { getCurrentNextRequest, runWithNextRequest };
|
|
15
|
+
export type { NextRequestLike };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
declare function assertRealtimeDefinitionTree(rootDir: string): void;
|
|
2
|
+
declare function resolveRealtimeDefinitionDirectories(rootDir: string): readonly string[];
|
|
3
|
+
declare function isInRealtimeDefinitionDirectory(directories: readonly string[], id: string): boolean;
|
|
4
|
+
|
|
5
|
+
export { assertRealtimeDefinitionTree, isInRealtimeDefinitionDirectory, resolveRealtimeDefinitionDirectories };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// src/realtime-directories.ts
|
|
2
|
+
import { existsSync, readdirSync, realpathSync, statSync } from "fs";
|
|
3
|
+
import { join, posix, relative, resolve, win32 } from "path";
|
|
4
|
+
function normalizeDirectory(path) {
|
|
5
|
+
return path.replaceAll("\\", "/").replace(/\/+$/, "");
|
|
6
|
+
}
|
|
7
|
+
function resolveConfiguredRoot(rootDir) {
|
|
8
|
+
return posix.isAbsolute(rootDir) || win32.isAbsolute(rootDir) ? rootDir : resolve(rootDir);
|
|
9
|
+
}
|
|
10
|
+
function symlinkTargetStaysInTree(linkPath, tree) {
|
|
11
|
+
if (!existsSync(linkPath)) return false;
|
|
12
|
+
const target = realpathSync.native(linkPath);
|
|
13
|
+
return statSync(target).isDirectory() && normalizeDirectory(target).startsWith(`${normalizeDirectory(tree)}/`);
|
|
14
|
+
}
|
|
15
|
+
function symlinkError(tree, linkPath) {
|
|
16
|
+
const displayPath = `server/realtime/${normalizeDirectory(relative(tree, linkPath))}`;
|
|
17
|
+
const replacement = existsSync(linkPath) && statSync(linkPath).isDirectory() ? "folder" : "file";
|
|
18
|
+
return new Error(`${displayPath} is a symbolic link; Holo can't guarantee its server code stays out of the browser bundle. Replace it with a regular ${replacement}.`);
|
|
19
|
+
}
|
|
20
|
+
function assertTreeEntries(tree, directory) {
|
|
21
|
+
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
|
22
|
+
const path = join(directory, entry.name);
|
|
23
|
+
if (entry.isSymbolicLink()) {
|
|
24
|
+
if (!symlinkTargetStaysInTree(path, tree)) throw symlinkError(tree, path);
|
|
25
|
+
} else if (entry.isDirectory()) {
|
|
26
|
+
assertTreeEntries(tree, path);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function assertRealtimeDefinitionTree(rootDir) {
|
|
31
|
+
const configured = join(resolveConfiguredRoot(rootDir), "server", "realtime");
|
|
32
|
+
if (!existsSync(configured)) return;
|
|
33
|
+
const tree = realpathSync.native(configured);
|
|
34
|
+
assertTreeEntries(tree, tree);
|
|
35
|
+
}
|
|
36
|
+
function resolveRealtimeDefinitionDirectories(rootDir) {
|
|
37
|
+
const configuredRoot = resolveConfiguredRoot(rootDir);
|
|
38
|
+
const configured = join(configuredRoot, "server", "realtime");
|
|
39
|
+
assertRealtimeDefinitionTree(rootDir);
|
|
40
|
+
const directories = /* @__PURE__ */ new Set([`${normalizeDirectory(configuredRoot)}/server/realtime`]);
|
|
41
|
+
if (existsSync(configuredRoot)) {
|
|
42
|
+
directories.add(`${normalizeDirectory(realpathSync.native(configuredRoot))}/server/realtime`);
|
|
43
|
+
}
|
|
44
|
+
if (existsSync(configured)) {
|
|
45
|
+
directories.add(normalizeDirectory(realpathSync.native(configured)));
|
|
46
|
+
}
|
|
47
|
+
return [...directories];
|
|
48
|
+
}
|
|
49
|
+
function isInRealtimeDefinitionDirectory(directories, id) {
|
|
50
|
+
const path = id.split("?")[0].replaceAll("\\", "/");
|
|
51
|
+
return directories.some((directory) => path.startsWith(`${directory}/`));
|
|
52
|
+
}
|
|
53
|
+
export {
|
|
54
|
+
assertRealtimeDefinitionTree,
|
|
55
|
+
isInRealtimeDefinitionDirectory,
|
|
56
|
+
resolveRealtimeDefinitionDirectories
|
|
57
|
+
};
|
package/dist/server-errors.d.ts
CHANGED
|
@@ -10,6 +10,19 @@ type RateLimitFailure = {
|
|
|
10
10
|
readonly values: Readonly<Record<string, never>>;
|
|
11
11
|
readonly retryAfterSeconds?: number;
|
|
12
12
|
};
|
|
13
|
+
type RequestBodyTooLargeFailure = {
|
|
14
|
+
readonly ok: false;
|
|
15
|
+
readonly valid: false;
|
|
16
|
+
readonly status: 413;
|
|
17
|
+
readonly bag: 'default';
|
|
18
|
+
readonly message: string;
|
|
19
|
+
readonly errors: {
|
|
20
|
+
readonly _root: readonly string[];
|
|
21
|
+
};
|
|
22
|
+
readonly values: Readonly<Record<string, never>>;
|
|
23
|
+
readonly retryAfterSeconds?: undefined;
|
|
24
|
+
};
|
|
25
|
+
declare function serializeRequestBodyTooLargeError(error: unknown): RequestBodyTooLargeFailure | undefined;
|
|
13
26
|
declare function serializeRateLimitError(error: unknown): RateLimitFailure | undefined;
|
|
14
27
|
|
|
15
|
-
export { serializeRateLimitError };
|
|
28
|
+
export { serializeRateLimitError, serializeRequestBodyTooLargeError };
|
package/dist/server-errors.mjs
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
// src/server-errors.ts
|
|
2
|
-
import { normalizeHoloHttpError } from "@holo-js/kernel
|
|
2
|
+
import { HoloRequestBodyTooLargeError, normalizeHoloHttpError } from "@holo-js/kernel";
|
|
3
|
+
function serializeRequestBodyTooLargeError(error) {
|
|
4
|
+
if (!(error instanceof HoloRequestBodyTooLargeError) && !(error instanceof Error && error.name === "HoloRequestBodyTooLargeError")) {
|
|
5
|
+
const cause = error && typeof error === "object" && "cause" in error ? error.cause : void 0;
|
|
6
|
+
return cause === void 0 ? void 0 : serializeRequestBodyTooLargeError(cause);
|
|
7
|
+
}
|
|
8
|
+
return {
|
|
9
|
+
ok: false,
|
|
10
|
+
valid: false,
|
|
11
|
+
status: 413,
|
|
12
|
+
bag: "default",
|
|
13
|
+
message: error.message,
|
|
14
|
+
errors: { _root: [error.message] },
|
|
15
|
+
values: {}
|
|
16
|
+
};
|
|
17
|
+
}
|
|
3
18
|
function serializeRateLimitError(error) {
|
|
4
19
|
const normalized = normalizeHoloHttpError(error);
|
|
5
20
|
if (!normalized || normalized.status !== 429) return void 0;
|
|
@@ -20,5 +35,6 @@ function serializeRateLimitError(error) {
|
|
|
20
35
|
};
|
|
21
36
|
}
|
|
22
37
|
export {
|
|
23
|
-
serializeRateLimitError
|
|
38
|
+
serializeRateLimitError,
|
|
39
|
+
serializeRequestBodyTooLargeError
|
|
24
40
|
};
|
|
@@ -3,11 +3,15 @@ type SvelteKitRequestEvent = {
|
|
|
3
3
|
readonly cookies: {
|
|
4
4
|
get(name: string): string | undefined;
|
|
5
5
|
set(name: string, value: string, options: SvelteKitCookieOptions): void;
|
|
6
|
+
delete(name: string, options: {
|
|
7
|
+
readonly path: string;
|
|
8
|
+
}): void;
|
|
6
9
|
};
|
|
7
10
|
readonly request: {
|
|
8
11
|
readonly method?: string;
|
|
9
12
|
readonly headers: Headers;
|
|
10
13
|
};
|
|
14
|
+
readonly getClientAddress?: () => string;
|
|
11
15
|
};
|
|
12
16
|
type SvelteKitCookieOptions = {
|
|
13
17
|
path: string;
|
|
@@ -22,4 +26,5 @@ type SvelteKitCookieOptions = {
|
|
|
22
26
|
declare function getCurrentSvelteKitRequestEvent(): SvelteKitRequestEvent | undefined;
|
|
23
27
|
declare function runWithSvelteKitRequestEvent<TValue>(event: SvelteKitRequestEvent, callback: () => TValue): TValue;
|
|
24
28
|
|
|
25
|
-
export {
|
|
29
|
+
export { getCurrentSvelteKitRequestEvent, runWithSvelteKitRequestEvent };
|
|
30
|
+
export type { SvelteKitRequestEvent };
|
package/package.json
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@holo-js/adapter-shared",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Holo-JS Framework - shared framework adapter infrastructure",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/cobraprojects/holo-js.git",
|
|
10
|
+
"directory": "packages/adapter-shared"
|
|
11
|
+
},
|
|
7
12
|
"exports": {
|
|
13
|
+
"./realtime-directories": {
|
|
14
|
+
"types": "./dist/realtime-directories.d.ts",
|
|
15
|
+
"import": "./dist/realtime-directories.mjs",
|
|
16
|
+
"default": "./dist/realtime-directories.mjs"
|
|
17
|
+
},
|
|
8
18
|
"./server-errors": {
|
|
9
19
|
"types": "./dist/server-errors.d.ts",
|
|
10
20
|
"import": "./dist/server-errors.mjs",
|
|
@@ -42,7 +52,8 @@
|
|
|
42
52
|
"main": "./dist/index.mjs",
|
|
43
53
|
"types": "./dist/index.d.ts",
|
|
44
54
|
"files": [
|
|
45
|
-
"dist"
|
|
55
|
+
"dist",
|
|
56
|
+
"LICENSE"
|
|
46
57
|
],
|
|
47
58
|
"scripts": {
|
|
48
59
|
"build": "tsup",
|
|
@@ -51,14 +62,14 @@
|
|
|
51
62
|
"test": "vitest --run"
|
|
52
63
|
},
|
|
53
64
|
"dependencies": {
|
|
54
|
-
"@holo-js/kernel": "^0.
|
|
55
|
-
"typescript": "^
|
|
65
|
+
"@holo-js/kernel": "^0.4.0",
|
|
66
|
+
"typescript": "^6.0.3"
|
|
56
67
|
},
|
|
57
68
|
"devDependencies": {
|
|
58
|
-
"tsup": "^
|
|
59
|
-
"vitest": "^
|
|
69
|
+
"tsup": "^9.0.0",
|
|
70
|
+
"vitest": "^5.0.5"
|
|
60
71
|
},
|
|
61
72
|
"engines": {
|
|
62
|
-
"node": "^22.
|
|
73
|
+
"node": "^22.18.0 || ^24.0.0 || ^26.0.0"
|
|
63
74
|
}
|
|
64
75
|
}
|