@meekojs/meeko 0.0.3 → 0.1.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/README.md +35 -16
- package/dist/autoimports-ts.d.ts +26 -0
- package/dist/autoimports-ts.js +183 -0
- package/dist/autoimports-ts.js.map +1 -0
- package/dist/autoimports.d.ts +21 -0
- package/dist/autoimports.js +301 -0
- package/dist/autoimports.js.map +1 -0
- package/dist/check.js +74 -33
- package/dist/check.js.map +1 -0
- package/dist/cli.js +67 -5
- package/dist/cli.js.map +1 -0
- package/dist/compiler/events.d.ts +2 -0
- package/dist/compiler/events.js +6 -0
- package/dist/compiler/events.js.map +1 -0
- package/dist/compiler/import-graph.d.ts +8 -0
- package/dist/compiler/import-graph.js +33 -0
- package/dist/compiler/import-graph.js.map +1 -0
- package/dist/compiler/mapping.js +1 -0
- package/dist/compiler/mapping.js.map +1 -0
- package/dist/compiler/project-root.d.ts +2 -0
- package/dist/compiler/project-root.js +18 -0
- package/dist/compiler/project-root.js.map +1 -0
- package/dist/compiler/props.d.ts +12 -0
- package/dist/compiler/props.js +32 -0
- package/dist/compiler/props.js.map +1 -0
- package/dist/compiler/sfc.js +1 -0
- package/dist/compiler/sfc.js.map +1 -0
- package/dist/compiler/sourcemap.d.ts +3 -0
- package/dist/compiler/sourcemap.js +75 -0
- package/dist/compiler/sourcemap.js.map +1 -0
- package/dist/compiler/template.js +1 -0
- package/dist/compiler/template.js.map +1 -0
- package/dist/compiler.js +66 -17
- package/dist/compiler.js.map +1 -0
- package/dist/component-errors.d.ts +18 -0
- package/dist/component-errors.js +65 -0
- package/dist/component-errors.js.map +1 -0
- package/dist/devtools-ui/index.js +1 -0
- package/dist/devtools-ui/index.js.map +1 -0
- package/dist/devtools.js +3 -4
- package/dist/devtools.js.map +1 -0
- package/dist/dom.d.ts +18 -5
- package/dist/dom.js +295 -90
- package/dist/dom.js.map +1 -0
- package/dist/error-observer.d.ts +6 -0
- package/dist/error-observer.js +41 -0
- package/dist/error-observer.js.map +1 -0
- package/dist/framework/check-app.d.ts +5 -0
- package/dist/framework/check-app.js +214 -0
- package/dist/framework/check-app.js.map +1 -0
- package/dist/framework/check-project.d.ts +4 -0
- package/dist/framework/check-project.js +42 -0
- package/dist/framework/check-project.js.map +1 -0
- package/dist/framework/client.d.ts +48 -0
- package/dist/framework/client.js +249 -0
- package/dist/framework/client.js.map +1 -0
- package/dist/framework/clients.d.ts +82 -0
- package/dist/framework/clients.js +190 -0
- package/dist/framework/clients.js.map +1 -0
- package/dist/framework/config-type.d.ts +10 -0
- package/dist/framework/config-type.js +4 -0
- package/dist/framework/config-type.js.map +1 -0
- package/dist/framework/config.d.ts +15 -0
- package/dist/framework/config.js +138 -0
- package/dist/framework/config.js.map +1 -0
- package/dist/framework/contracts-generate.d.ts +8 -0
- package/dist/framework/contracts-generate.js +290 -0
- package/dist/framework/contracts-generate.js.map +1 -0
- package/dist/framework/generate.d.ts +7 -0
- package/dist/framework/generate.js +67 -0
- package/dist/framework/generate.js.map +1 -0
- package/dist/framework/init.d.ts +2 -0
- package/dist/framework/init.js +183 -0
- package/dist/framework/init.js.map +1 -0
- package/dist/framework/middleware.d.ts +14 -0
- package/dist/framework/middleware.js +16 -0
- package/dist/framework/middleware.js.map +1 -0
- package/dist/framework/modules.d.ts +22 -0
- package/dist/framework/modules.js +29 -0
- package/dist/framework/modules.js.map +1 -0
- package/dist/framework/page-contracts-check.d.ts +8 -0
- package/dist/framework/page-contracts-check.js +110 -0
- package/dist/framework/page-contracts-check.js.map +1 -0
- package/dist/framework/page-contracts-generate.d.ts +2 -0
- package/dist/framework/page-contracts-generate.js +94 -0
- package/dist/framework/page-contracts-generate.js.map +1 -0
- package/dist/framework/page.d.ts +64 -0
- package/dist/framework/page.js +44 -0
- package/dist/framework/page.js.map +1 -0
- package/dist/framework/prerender.d.ts +14 -0
- package/dist/framework/prerender.js +110 -0
- package/dist/framework/prerender.js.map +1 -0
- package/dist/framework/project-templates.d.ts +3 -0
- package/dist/framework/project-templates.js +119 -0
- package/dist/framework/project-templates.js.map +1 -0
- package/dist/framework/project.d.ts +9 -0
- package/dist/framework/project.js +272 -0
- package/dist/framework/project.js.map +1 -0
- package/dist/framework/router.d.ts +41 -0
- package/dist/framework/router.js +259 -0
- package/dist/framework/router.js.map +1 -0
- package/dist/framework/server.d.ts +65 -0
- package/dist/framework/server.js +239 -0
- package/dist/framework/server.js.map +1 -0
- package/dist/framework/socket-contracts-generate.d.ts +5 -0
- package/dist/framework/socket-contracts-generate.js +162 -0
- package/dist/framework/socket-contracts-generate.js.map +1 -0
- package/dist/framework/socket.d.ts +72 -0
- package/dist/framework/socket.js +252 -0
- package/dist/framework/socket.js.map +1 -0
- package/dist/framework/standard-schema-types.d.ts +7 -0
- package/dist/framework/standard-schema-types.js +69 -0
- package/dist/framework/standard-schema-types.js.map +1 -0
- package/dist/framework/state.d.ts +22 -0
- package/dist/framework/state.js +136 -0
- package/dist/framework/state.js.map +1 -0
- package/dist/framework/styles.d.ts +2 -0
- package/dist/framework/styles.js +6 -0
- package/dist/framework/styles.js.map +1 -0
- package/dist/framework/type-declarations.d.ts +5 -0
- package/dist/framework/type-declarations.js +84 -0
- package/dist/framework/type-declarations.js.map +1 -0
- package/dist/framework-server/auto-clients.d.ts +3 -0
- package/dist/framework-server/auto-clients.js +27 -0
- package/dist/framework-server/auto-clients.js.map +1 -0
- package/dist/framework-server/context.d.ts +21 -0
- package/dist/framework-server/context.js +22 -0
- package/dist/framework-server/context.js.map +1 -0
- package/dist/framework-server/contracts.d.ts +73 -0
- package/dist/framework-server/contracts.js +184 -0
- package/dist/framework-server/contracts.js.map +1 -0
- package/dist/framework-server/discovery.d.ts +43 -0
- package/dist/framework-server/discovery.js +257 -0
- package/dist/framework-server/discovery.js.map +1 -0
- package/dist/framework-server/local.d.ts +21 -0
- package/dist/framework-server/local.js +100 -0
- package/dist/framework-server/local.js.map +1 -0
- package/dist/framework-server/middleware.d.ts +4 -0
- package/dist/framework-server/middleware.js +56 -0
- package/dist/framework-server/middleware.js.map +1 -0
- package/dist/framework-server/node-upgrade.d.ts +23 -0
- package/dist/framework-server/node-upgrade.js +96 -0
- package/dist/framework-server/node-upgrade.js.map +1 -0
- package/dist/framework-server/node-websocket.d.ts +16 -0
- package/dist/framework-server/node-websocket.js +127 -0
- package/dist/framework-server/node-websocket.js.map +1 -0
- package/dist/framework-server/openapi.d.ts +17 -0
- package/dist/framework-server/openapi.js +118 -0
- package/dist/framework-server/openapi.js.map +1 -0
- package/dist/framework-server/session-stores.d.ts +73 -0
- package/dist/framework-server/session-stores.js +122 -0
- package/dist/framework-server/session-stores.js.map +1 -0
- package/dist/framework-server/sessions.d.ts +70 -0
- package/dist/framework-server/sessions.js +167 -0
- package/dist/framework-server/sessions.js.map +1 -0
- package/dist/framework-server/socket.d.ts +83 -0
- package/dist/framework-server/socket.js +196 -0
- package/dist/framework-server/socket.js.map +1 -0
- package/dist/framework-server.d.ts +23 -0
- package/dist/framework-server.js +13 -0
- package/dist/framework-server.js.map +1 -0
- package/dist/framework.d.ts +31 -0
- package/dist/framework.js +14 -0
- package/dist/framework.js.map +1 -0
- package/dist/hmr.js +75 -24
- package/dist/hmr.js.map +1 -0
- package/dist/index.d.ts +5 -3
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -0
- package/dist/init.js +31 -3
- package/dist/init.js.map +1 -0
- package/dist/internal.d.ts +2 -2
- package/dist/internal.js +3 -2
- package/dist/internal.js.map +1 -0
- package/dist/node.d.ts +16 -0
- package/dist/node.js +122 -0
- package/dist/node.js.map +1 -0
- package/dist/reactivity.d.ts +22 -1
- package/dist/reactivity.js +132 -18
- package/dist/reactivity.js.map +1 -0
- package/dist/server.js +1 -0
- package/dist/server.js.map +1 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.js +26 -9
- package/dist/types.js.map +1 -0
- package/dist/vite.js +112 -7
- package/dist/vite.js.map +1 -0
- package/package.json +15 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"socket-contracts-generate.js","sourceRoot":"","sources":["../../src/framework/socket-contracts-generate.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname, isAbsolute, join, relative, resolve, sep } from \"node:path\";\nimport ts from \"@typescript/typescript6\";\nimport { discoverServerManifest } from \"../framework-server/discovery.js\";\nimport { standardSchemaTypes } from \"./standard-schema-types.js\";\n\ninterface ImportedSymbol { file: string; exported: string; }\ninterface SchemaReference { file: string; exported: string; }\n\nfunction inside(parent: string, child: string): boolean {\n const path = relative(parent, child);\n return path === \"\" || (path !== \"..\" && !path.startsWith(`..${sep}`) && !isAbsolute(path));\n}\n\nfunction compilerOptions(root: string): ts.CompilerOptions {\n const config = ts.findConfigFile(root, ts.sys.fileExists, \"tsconfig.json\");\n if (!config) return { module: ts.ModuleKind.NodeNext, moduleResolution: ts.ModuleResolutionKind.NodeNext };\n const loaded = ts.readConfigFile(config, ts.sys.readFile);\n if (loaded.error) throw new Error(ts.flattenDiagnosticMessageText(loaded.error.messageText, \"\\n\"));\n return ts.parseJsonConfigFileContent(loaded.config, ts.sys, dirname(config)).options;\n}\n\nfunction resolveImport(specifier: string, importer: string, options: ts.CompilerOptions): string {\n const target = ts.resolveModuleName(specifier, importer, options, ts.sys).resolvedModule?.resolvedFileName;\n if (!target) throw new Error(`${importer}: unresolved import ${specifier}`);\n return target;\n}\n\nfunction validateSharedGraph(file: string, root: string, shared: string, options: ts.CompilerOptions, seen: Set<string>): void {\n if (seen.has(file)) return;\n seen.add(file);\n if (!inside(shared, file)) throw new Error(`${file}: public Socket schema must stay inside shared/`);\n const source = ts.sys.readFile(file);\n if (source === undefined) throw new Error(`${file}: Socket schema file missing`);\n const ast = ts.createSourceFile(file, source, ts.ScriptTarget.Latest, true);\n const check = (specifier: string): void => {\n const target = resolveImport(specifier, file, options);\n if (inside(root, target) && !relative(root, target).split(sep).includes(\"node_modules\")) validateSharedGraph(target, root, shared, options, seen);\n };\n for (const statement of ast.statements) {\n if ((ts.isImportDeclaration(statement) || ts.isExportDeclaration(statement)) && statement.moduleSpecifier && ts.isStringLiteral(statement.moduleSpecifier)) check(statement.moduleSpecifier.text);\n }\n const visit = (node: ts.Node): void => {\n if (ts.isImportTypeNode(node) && ts.isLiteralTypeNode(node.argument) && ts.isStringLiteral(node.argument.literal)) check(node.argument.literal.text);\n ts.forEachChild(node, visit);\n };\n visit(ast);\n}\n\nfunction property(object: ts.ObjectLiteralExpression, name: string): ts.Expression | undefined {\n const entry = object.properties.find((candidate) => (ts.isPropertyAssignment(candidate) || ts.isShorthandPropertyAssignment(candidate)) && candidate.name && (ts.isIdentifier(candidate.name) || ts.isStringLiteral(candidate.name)) && candidate.name.text === name);\n if (!entry) return undefined;\n return ts.isPropertyAssignment(entry) ? entry.initializer : ts.isShorthandPropertyAssignment(entry) ? entry.name : undefined;\n}\n\nfunction publicSchemas(file: string, root: string, options: ts.CompilerOptions, program: ts.Program, checker: ts.TypeChecker): { clientToServer: Record<string, SchemaReference>; serverToClient: Record<string, SchemaReference> } {\n const ast = program.getSourceFile(file);\n if (!ast) throw new Error(`${file}: Socket channel file missing`);\n const imports = new Map<string, ImportedSymbol>();\n for (const statement of ast.statements) {\n if (!ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier)) continue;\n const clause = statement.importClause;\n if (!clause || clause.isTypeOnly) continue;\n const target = resolveImport(statement.moduleSpecifier.text, file, options);\n if (clause.name) imports.set(clause.name.text, { file: target, exported: \"default\" });\n if (clause.namedBindings && ts.isNamedImports(clause.namedBindings)) {\n for (const element of clause.namedBindings.elements) {\n if (!element.isTypeOnly) imports.set(element.name.text, { file: target, exported: element.propertyName?.text ?? element.name.text });\n }\n }\n if (clause.namedBindings && ts.isNamespaceImport(clause.namedBindings)) imports.set(clause.namedBindings.name.text, { file: target, exported: \"*\" });\n }\n const assignment = ast.statements.find((statement): statement is ts.ExportAssignment => ts.isExportAssignment(statement) && !statement.isExportEquals);\n const call = assignment?.expression;\n if (!call || !ts.isCallExpression(call) || !ts.isIdentifier(call.expression) || call.expression.text !== \"defineSocketChannel\" || !call.arguments[0] || !ts.isObjectLiteralExpression(call.arguments[0])) {\n throw new Error(`${file}: public Socket contract requires export default defineSocketChannel({...})`);\n }\n const shared = join(root, \"shared\");\n const seen = new Set<string>();\n const direction = (name: \"clientToServer\" | \"serverToClient\"): Record<string, SchemaReference> => {\n const object = property(call.arguments[0] as ts.ObjectLiteralExpression, name);\n if (!object || !ts.isObjectLiteralExpression(object)) throw new Error(`${file}: ${name} must be a static object`);\n const result: Record<string, SchemaReference> = Object.create(null);\n for (const entry of object.properties) {\n if (!ts.isPropertyAssignment(entry) || !(ts.isIdentifier(entry.name) || ts.isStringLiteral(entry.name))) throw new Error(`${file}: ${name} requires named schema properties`);\n const event = entry.name.text;\n const value = entry.initializer;\n let local: string;\n let member: string | undefined;\n if (ts.isIdentifier(value)) local = value.text;\n else if (ts.isPropertyAccessExpression(value) && ts.isIdentifier(value.expression)) { local = value.expression.text; member = value.name.text; }\n else throw new Error(`${file}: ${name}.${event} must reference an imported shared schema`);\n const imported = imports.get(local);\n if (!imported || !inside(shared, imported.file)) throw new Error(`${file}: ${name}.${event} must come from shared/`);\n const exported = imported.exported === \"*\" ? member : imported.exported;\n if (!exported || (member && imported.exported !== \"*\")) throw new Error(`${file}: ${name}.${event} must reference one shared export`);\n standardSchemaTypes(value, checker, () => new Error(`${file}: ${name}.${event} must expose concrete Standard Schema input and output types`));\n validateSharedGraph(imported.file, root, shared, options, seen);\n if (result[event]) throw new Error(`${file}: duplicate Socket event ${name}.${event}`);\n result[event] = { file: imported.file, exported };\n }\n return result;\n };\n return { clientToServer: direction(\"clientToServer\"), serverToClient: direction(\"serverToClient\") };\n}\n\n/** Emits browser-safe, inferred Socket contracts from server channel definitions. */\nexport async function generateSocketContracts(projectRoot: string): Promise<{ file: string; count: number }> {\n const root = resolve(projectRoot);\n const manifest = await discoverServerManifest(root);\n const output = join(root, \".meeko\", \"generated\", \"socket-contracts.ts\");\n const options = compilerOptions(root);\n const program = ts.createProgram((manifest.socket ?? []).map((endpoint) => endpoint.file), { ...options, noEmit: true });\n const checker = program.getTypeChecker();\n const channels = (manifest.socket ?? []).map((endpoint) => ({ name: endpoint.name, schemas: publicSchemas(endpoint.file, root, options, program, checker) }));\n const sources = [...new Set(channels.flatMap(({ schemas }) => [...Object.values(schemas.clientToServer), ...Object.values(schemas.serverToClient)].map((entry) => entry.file)))].sort();\n const aliases = new Map(sources.map((file, index) => [file, `__schema${index}`]));\n const lines = sources.map((file) => {\n const target = relative(dirname(output), file).replaceAll(\"\\\\\", \"/\").replace(/\\.(?:ts|mts|cts)$/, (suffix) => suffix === \".mts\" ? \".mjs\" : suffix === \".cts\" ? \".cjs\" : \".js\");\n return `import * as ${aliases.get(file)} from ${JSON.stringify(target.startsWith(\".\") ? target : `./${target}`)};`;\n });\n lines.push(\"export const socketContracts = {\");\n for (const channel of channels) {\n lines.push(` ${JSON.stringify(channel.name)}: {`);\n for (const direction of [\"clientToServer\", \"serverToClient\"] as const) {\n lines.push(` ${direction}: {`);\n for (const [event, schema] of Object.entries(channel.schemas[direction])) lines.push(` ${JSON.stringify(event)}: ${aliases.get(schema.file)}[${JSON.stringify(schema.exported)}],`);\n lines.push(\" },\");\n }\n lines.push(\" },\");\n }\n lines.push(\"} as const;\", \"\");\n const code = lines.join(\"\\n\");\n let previous: string | undefined;\n try { previous = await readFile(output, \"utf8\"); } catch { /* First generation. */ }\n if (previous !== code) { await mkdir(dirname(output), { recursive: true }); await writeFile(output, code); }\n return { file: output, count: channels.length };\n}\n"]}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { ReadonlySignal } from "../reactivity.js";
|
|
2
|
+
export interface SocketSchema<I = unknown, O = I> {
|
|
3
|
+
readonly "~standard": {
|
|
4
|
+
readonly version: 1;
|
|
5
|
+
readonly validate: (value: unknown) => {
|
|
6
|
+
value: O;
|
|
7
|
+
issues?: undefined;
|
|
8
|
+
} | {
|
|
9
|
+
issues: readonly unknown[];
|
|
10
|
+
} | Promise<{
|
|
11
|
+
value: O;
|
|
12
|
+
issues?: undefined;
|
|
13
|
+
} | {
|
|
14
|
+
issues: readonly unknown[];
|
|
15
|
+
}>;
|
|
16
|
+
readonly types?: {
|
|
17
|
+
readonly input: I;
|
|
18
|
+
readonly output: O;
|
|
19
|
+
} | undefined;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
type SchemaInput<T> = T extends {
|
|
23
|
+
readonly "~standard": {
|
|
24
|
+
readonly types?: infer U;
|
|
25
|
+
};
|
|
26
|
+
} ? NonNullable<U> extends {
|
|
27
|
+
readonly input: infer I;
|
|
28
|
+
} ? I : never : T extends SocketSchema<infer I, unknown> ? I : never;
|
|
29
|
+
type SchemaOutput<T> = T extends {
|
|
30
|
+
readonly "~standard": {
|
|
31
|
+
readonly types?: infer U;
|
|
32
|
+
};
|
|
33
|
+
} ? NonNullable<U> extends {
|
|
34
|
+
readonly output: infer O;
|
|
35
|
+
} ? O : never : T extends SocketSchema<unknown, infer O> ? O : never;
|
|
36
|
+
type Events = Record<string, SocketSchema>;
|
|
37
|
+
export interface SocketContract<ClientToServer extends Events = Events, ServerToClient extends Events = Events> {
|
|
38
|
+
readonly clientToServer: ClientToServer;
|
|
39
|
+
readonly serverToClient: ServerToClient;
|
|
40
|
+
}
|
|
41
|
+
export interface SocketClient<C extends SocketContract> {
|
|
42
|
+
readonly state: ReadonlySignal<"connecting" | "open" | "closed">;
|
|
43
|
+
emit<K extends keyof C["clientToServer"] & string>(event: K, data: SchemaInput<C["clientToServer"][K]>): Promise<void>;
|
|
44
|
+
on<K extends keyof C["serverToClient"] & string>(event: K, listener: (data: SchemaOutput<C["serverToClient"][K]>) => void): () => void;
|
|
45
|
+
close(): void;
|
|
46
|
+
}
|
|
47
|
+
export interface SocketClientOptions {
|
|
48
|
+
readonly retryMs?: number;
|
|
49
|
+
readonly maxRetryMs?: number;
|
|
50
|
+
readonly maxMessageBytes?: number;
|
|
51
|
+
readonly webSocketFactory?: (url: string) => WebSocket;
|
|
52
|
+
/** Receives invalid inbound messages and consumer listener failures. */
|
|
53
|
+
readonly onError?: (error: unknown) => void;
|
|
54
|
+
}
|
|
55
|
+
export interface SocketRegistryOptions extends SocketClientOptions {
|
|
56
|
+
/** HTTP(S) or WS(S) base URL. Defaults to the current browser origin. */
|
|
57
|
+
readonly baseUrl?: string;
|
|
58
|
+
readonly pathnamePrefix?: string;
|
|
59
|
+
readonly roomId?: string;
|
|
60
|
+
}
|
|
61
|
+
export type SocketRegistry<C extends Record<string, SocketContract>> = {
|
|
62
|
+
readonly [K in keyof C]: SocketClient<C[K]>;
|
|
63
|
+
};
|
|
64
|
+
/** Native WebSocket client: no offline queue and no automatic replay. */
|
|
65
|
+
export declare function createSocketClient<C extends SocketContract>(url: string, contract: C, options?: SocketClientOptions): SocketClient<C>;
|
|
66
|
+
/** Binds socket lifetime to a Meeko root; SSR never opens a connection. */
|
|
67
|
+
export declare function useSocket<C extends SocketContract>(url: string, contract: C, options?: SocketClientOptions): SocketClient<C>;
|
|
68
|
+
/** Creates lazily connected, typed channel clients from public shared schemas. */
|
|
69
|
+
export declare function createSocketRegistry<C extends Record<string, SocketContract>>(contracts: C, options?: SocketRegistryOptions): SocketRegistry<C>;
|
|
70
|
+
/** Creates a channel scoped to the current component root. */
|
|
71
|
+
export declare function useSocketChannel<C extends Record<string, SocketContract>, K extends keyof C & string>(contracts: C, name: K, options?: SocketRegistryOptions): SocketClient<C[K]>;
|
|
72
|
+
export {};
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { currentEffectOwner, onCleanup, signal } from "../reactivity.js";
|
|
2
|
+
import { logClientError, observeCallback } from "../error-observer.js";
|
|
3
|
+
import { currentAppErrorChannel, currentComponentErrorHandler } from "../component-errors.js";
|
|
4
|
+
import { serializeJson } from "../server.js";
|
|
5
|
+
function socketUrl(name, options) {
|
|
6
|
+
if (typeof window === "undefined")
|
|
7
|
+
throw new Error("Socket connections are unavailable during SSR");
|
|
8
|
+
const prefix = options.pathnamePrefix ?? "/_meeko/socket";
|
|
9
|
+
if (!prefix.startsWith("/") || prefix.endsWith("/"))
|
|
10
|
+
throw new TypeError("Invalid socket pathname prefix");
|
|
11
|
+
const url = new URL(`${prefix}/${encodeURIComponent(name)}`, options.baseUrl ?? window.location.href);
|
|
12
|
+
if (url.protocol === "http:")
|
|
13
|
+
url.protocol = "ws:";
|
|
14
|
+
else if (url.protocol === "https:")
|
|
15
|
+
url.protocol = "wss:";
|
|
16
|
+
else if (url.protocol !== "ws:" && url.protocol !== "wss:")
|
|
17
|
+
throw new TypeError("Invalid socket URL protocol");
|
|
18
|
+
if (options.roomId !== undefined)
|
|
19
|
+
url.searchParams.set("room", options.roomId);
|
|
20
|
+
return url.href;
|
|
21
|
+
}
|
|
22
|
+
async function validate(schema, value) {
|
|
23
|
+
const result = await schema["~standard"].validate(value);
|
|
24
|
+
if ("issues" in result && result.issues)
|
|
25
|
+
throw new TypeError("Invalid socket event payload");
|
|
26
|
+
return result.value;
|
|
27
|
+
}
|
|
28
|
+
/** Native WebSocket client: no offline queue and no automatic replay. */
|
|
29
|
+
export function createSocketClient(url, contract, options = {}) {
|
|
30
|
+
const state = signal("connecting");
|
|
31
|
+
const listeners = new Map();
|
|
32
|
+
const factory = options.webSocketFactory ?? ((address) => new WebSocket(address));
|
|
33
|
+
const maxBytes = options.maxMessageBytes ?? 64 * 1024;
|
|
34
|
+
let socket;
|
|
35
|
+
let retry;
|
|
36
|
+
let attempts = 0;
|
|
37
|
+
let closed = false;
|
|
38
|
+
const reportError = (error) => {
|
|
39
|
+
if (!options.onError) {
|
|
40
|
+
logClientError("Meeko socket client error", error);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
observeCallback(() => options.onError(error), (observerError) => logClientError("Meeko socket error observer failed", error, observerError));
|
|
44
|
+
};
|
|
45
|
+
const setState = (next) => {
|
|
46
|
+
try {
|
|
47
|
+
state.value = next;
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
reportError(error);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
const closePeer = (peer, code, reason) => {
|
|
54
|
+
try {
|
|
55
|
+
peer?.close(code, reason);
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
reportError(error);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
const scheduleRetry = () => {
|
|
62
|
+
if (closed)
|
|
63
|
+
return;
|
|
64
|
+
const delay = Math.min((options.retryMs ?? 500) * 2 ** attempts++, options.maxRetryMs ?? 30_000);
|
|
65
|
+
retry = setTimeout(() => {
|
|
66
|
+
retry = undefined;
|
|
67
|
+
try {
|
|
68
|
+
connect();
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
reportError(error);
|
|
72
|
+
setState("closed");
|
|
73
|
+
scheduleRetry();
|
|
74
|
+
}
|
|
75
|
+
}, delay);
|
|
76
|
+
};
|
|
77
|
+
const connect = () => {
|
|
78
|
+
if (closed)
|
|
79
|
+
return;
|
|
80
|
+
setState("connecting");
|
|
81
|
+
const peer = factory(url);
|
|
82
|
+
socket = peer;
|
|
83
|
+
let transportErrorReported = false;
|
|
84
|
+
peer.addEventListener("open", () => { if (peer === socket) {
|
|
85
|
+
attempts = 0;
|
|
86
|
+
setState("open");
|
|
87
|
+
} });
|
|
88
|
+
peer.addEventListener("error", () => {
|
|
89
|
+
if (peer !== socket || closed || transportErrorReported)
|
|
90
|
+
return;
|
|
91
|
+
transportErrorReported = true;
|
|
92
|
+
reportError(new Error("Socket transport error"));
|
|
93
|
+
});
|
|
94
|
+
peer.addEventListener("message", (message) => {
|
|
95
|
+
if (peer !== socket || closed)
|
|
96
|
+
return;
|
|
97
|
+
if (typeof message.data !== "string" || new TextEncoder().encode(message.data).byteLength > maxBytes) {
|
|
98
|
+
reportError(new RangeError("Socket message too large or not text"));
|
|
99
|
+
closed = true;
|
|
100
|
+
setState("closed");
|
|
101
|
+
listeners.clear();
|
|
102
|
+
closePeer(peer, 1009, "Message too large");
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
void (async () => {
|
|
106
|
+
const decoded = JSON.parse(message.data);
|
|
107
|
+
if (typeof decoded !== "object" || decoded === null || !("event" in decoded) || !("payload" in decoded) || typeof decoded.event !== "string")
|
|
108
|
+
throw new TypeError("Invalid socket message");
|
|
109
|
+
const schema = contract.serverToClient[decoded.event];
|
|
110
|
+
if (!schema)
|
|
111
|
+
throw new TypeError("Unknown socket event");
|
|
112
|
+
const value = await validate(schema, decoded.payload);
|
|
113
|
+
if (peer !== socket || closed)
|
|
114
|
+
return;
|
|
115
|
+
for (const listener of listeners.get(decoded.event) ?? []) {
|
|
116
|
+
if (peer !== socket || closed)
|
|
117
|
+
return;
|
|
118
|
+
observeCallback(() => listener(value), reportError);
|
|
119
|
+
}
|
|
120
|
+
})().catch((error) => {
|
|
121
|
+
if (peer !== socket || closed)
|
|
122
|
+
return;
|
|
123
|
+
reportError(error);
|
|
124
|
+
closed = true;
|
|
125
|
+
setState("closed");
|
|
126
|
+
listeners.clear();
|
|
127
|
+
closePeer(peer, 1008, "Invalid event");
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
peer.addEventListener("close", (event) => {
|
|
131
|
+
if (peer !== socket || closed)
|
|
132
|
+
return;
|
|
133
|
+
setState("closed");
|
|
134
|
+
if ([1008, 1009].includes(event.code)) {
|
|
135
|
+
closed = true;
|
|
136
|
+
listeners.clear();
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
scheduleRetry();
|
|
140
|
+
});
|
|
141
|
+
};
|
|
142
|
+
connect();
|
|
143
|
+
return {
|
|
144
|
+
state,
|
|
145
|
+
async emit(event, data) {
|
|
146
|
+
if (closed || socket?.readyState !== WebSocket.OPEN)
|
|
147
|
+
throw new Error("Socket is disconnected");
|
|
148
|
+
const schema = contract.clientToServer[event];
|
|
149
|
+
if (!schema)
|
|
150
|
+
throw new TypeError(`Unknown socket event: ${event}`);
|
|
151
|
+
const value = await validate(schema, data);
|
|
152
|
+
if (closed || socket.readyState !== WebSocket.OPEN)
|
|
153
|
+
throw new Error("Socket is disconnected");
|
|
154
|
+
const message = serializeJson({ event, payload: value });
|
|
155
|
+
if (new TextEncoder().encode(message).byteLength > maxBytes)
|
|
156
|
+
throw new RangeError("Socket message too large");
|
|
157
|
+
socket.send(message);
|
|
158
|
+
},
|
|
159
|
+
on(event, listener) {
|
|
160
|
+
const set = listeners.get(event) ?? new Set();
|
|
161
|
+
set.add(listener);
|
|
162
|
+
listeners.set(event, set);
|
|
163
|
+
const unsubscribe = () => { set.delete(listener); if (set.size === 0)
|
|
164
|
+
listeners.delete(event); };
|
|
165
|
+
if (currentEffectOwner())
|
|
166
|
+
onCleanup(unsubscribe);
|
|
167
|
+
return unsubscribe;
|
|
168
|
+
},
|
|
169
|
+
close() {
|
|
170
|
+
if (closed) {
|
|
171
|
+
listeners.clear();
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
closed = true;
|
|
175
|
+
if (retry)
|
|
176
|
+
clearTimeout(retry);
|
|
177
|
+
closePeer(socket, 1000, "Client closed");
|
|
178
|
+
listeners.clear();
|
|
179
|
+
setState("closed");
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
/** Binds socket lifetime to a Meeko root; SSR never opens a connection. */
|
|
184
|
+
export function useSocket(url, contract, options = {}) {
|
|
185
|
+
if (typeof window === "undefined")
|
|
186
|
+
throw new Error("useSocket() is only available in the browser");
|
|
187
|
+
const onError = options.onError ?? currentComponentErrorHandler();
|
|
188
|
+
const client = createSocketClient(url, contract, onError ? { ...options, onError } : options);
|
|
189
|
+
try {
|
|
190
|
+
onCleanup(() => client.close());
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
client.close();
|
|
194
|
+
throw error;
|
|
195
|
+
}
|
|
196
|
+
return client;
|
|
197
|
+
}
|
|
198
|
+
/** Creates lazily connected, typed channel clients from public shared schemas. */
|
|
199
|
+
export function createSocketRegistry(contracts, options = {}) {
|
|
200
|
+
const result = Object.create(null);
|
|
201
|
+
for (const name of Object.keys(contracts)) {
|
|
202
|
+
let client;
|
|
203
|
+
const appClients = new WeakMap();
|
|
204
|
+
const rootClients = new WeakMap();
|
|
205
|
+
Object.defineProperty(result, name, {
|
|
206
|
+
enumerable: true,
|
|
207
|
+
get() {
|
|
208
|
+
const channel = currentAppErrorChannel();
|
|
209
|
+
if (channel) {
|
|
210
|
+
let scoped = appClients.get(channel);
|
|
211
|
+
if (!scoped) {
|
|
212
|
+
const onError = options.onError ?? ((error) => {
|
|
213
|
+
const handler = channel.current();
|
|
214
|
+
if (handler)
|
|
215
|
+
return handler(error);
|
|
216
|
+
logClientError("Meeko socket client error", error);
|
|
217
|
+
});
|
|
218
|
+
scoped = createSocketClient(socketUrl(name, options), contracts[name], { ...options, onError });
|
|
219
|
+
appClients.set(channel, scoped);
|
|
220
|
+
const owned = scoped;
|
|
221
|
+
channel.track(() => { owned.close(); appClients.delete(channel); });
|
|
222
|
+
}
|
|
223
|
+
return scoped;
|
|
224
|
+
}
|
|
225
|
+
const owner = currentEffectOwner();
|
|
226
|
+
if (owner) {
|
|
227
|
+
let scoped = rootClients.get(owner);
|
|
228
|
+
if (!scoped) {
|
|
229
|
+
const onError = options.onError ?? currentComponentErrorHandler();
|
|
230
|
+
scoped = createSocketClient(socketUrl(name, options), contracts[name], onError ? { ...options, onError } : options);
|
|
231
|
+
rootClients.set(owner, scoped);
|
|
232
|
+
const owned = scoped;
|
|
233
|
+
onCleanup(() => { owned.close(); rootClients.delete(owner); });
|
|
234
|
+
}
|
|
235
|
+
return scoped;
|
|
236
|
+
}
|
|
237
|
+
if (!client)
|
|
238
|
+
client = createSocketClient(socketUrl(name, options), contracts[name], options);
|
|
239
|
+
return client;
|
|
240
|
+
},
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
return result;
|
|
244
|
+
}
|
|
245
|
+
/** Creates a channel scoped to the current component root. */
|
|
246
|
+
export function useSocketChannel(contracts, name, options = {}) {
|
|
247
|
+
const contract = contracts[name];
|
|
248
|
+
if (!contract)
|
|
249
|
+
throw new TypeError(`Unknown socket channel: ${name}`);
|
|
250
|
+
return useSocket(socketUrl(name, options), contract, options);
|
|
251
|
+
}
|
|
252
|
+
//# sourceMappingURL=socket.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"socket.js","sourceRoot":"","sources":["../../src/framework/socket.ts"],"names":[],"mappings":"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","sourcesContent":["import { currentEffectOwner, onCleanup, signal } from \"../reactivity.js\";\nimport type { ReadonlySignal } from \"../reactivity.js\";\nimport { logClientError, observeCallback } from \"../error-observer.js\";\nimport { currentAppErrorChannel, currentComponentErrorHandler } from \"../component-errors.js\";\nimport { serializeJson } from \"../server.js\";\n\nexport interface SocketSchema<I = unknown, O = I> {\n readonly \"~standard\": {\n readonly version: 1;\n readonly validate: (value: unknown) => { value: O; issues?: undefined } | { issues: readonly unknown[] } | Promise<{ value: O; issues?: undefined } | { issues: readonly unknown[] }>;\n readonly types?: { readonly input: I; readonly output: O } | undefined;\n };\n}\n\ntype SchemaInput<T> = T extends { readonly \"~standard\": { readonly types?: infer U } }\n ? NonNullable<U> extends { readonly input: infer I } ? I : never\n : T extends SocketSchema<infer I, unknown> ? I : never;\ntype SchemaOutput<T> = T extends { readonly \"~standard\": { readonly types?: infer U } }\n ? NonNullable<U> extends { readonly output: infer O } ? O : never\n : T extends SocketSchema<unknown, infer O> ? O : never;\ntype Events = Record<string, SocketSchema>;\n\nexport interface SocketContract<ClientToServer extends Events = Events, ServerToClient extends Events = Events> {\n readonly clientToServer: ClientToServer;\n readonly serverToClient: ServerToClient;\n}\n\nexport interface SocketClient<C extends SocketContract> {\n readonly state: ReadonlySignal<\"connecting\" | \"open\" | \"closed\">;\n emit<K extends keyof C[\"clientToServer\"] & string>(event: K, data: SchemaInput<C[\"clientToServer\"][K]>): Promise<void>;\n on<K extends keyof C[\"serverToClient\"] & string>(event: K, listener: (data: SchemaOutput<C[\"serverToClient\"][K]>) => void): () => void;\n close(): void;\n}\n\nexport interface SocketClientOptions {\n readonly retryMs?: number;\n readonly maxRetryMs?: number;\n readonly maxMessageBytes?: number;\n readonly webSocketFactory?: (url: string) => WebSocket;\n /** Receives invalid inbound messages and consumer listener failures. */\n readonly onError?: (error: unknown) => void;\n}\n\nexport interface SocketRegistryOptions extends SocketClientOptions {\n /** HTTP(S) or WS(S) base URL. Defaults to the current browser origin. */\n readonly baseUrl?: string;\n readonly pathnamePrefix?: string;\n readonly roomId?: string;\n}\n\nexport type SocketRegistry<C extends Record<string, SocketContract>> = {\n readonly [K in keyof C]: SocketClient<C[K]>;\n};\n\nfunction socketUrl(name: string, options: SocketRegistryOptions): string {\n if (typeof window === \"undefined\") throw new Error(\"Socket connections are unavailable during SSR\");\n const prefix = options.pathnamePrefix ?? \"/_meeko/socket\";\n if (!prefix.startsWith(\"/\") || prefix.endsWith(\"/\")) throw new TypeError(\"Invalid socket pathname prefix\");\n const url = new URL(`${prefix}/${encodeURIComponent(name)}`, options.baseUrl ?? window.location.href);\n if (url.protocol === \"http:\") url.protocol = \"ws:\";\n else if (url.protocol === \"https:\") url.protocol = \"wss:\";\n else if (url.protocol !== \"ws:\" && url.protocol !== \"wss:\") throw new TypeError(\"Invalid socket URL protocol\");\n if (options.roomId !== undefined) url.searchParams.set(\"room\", options.roomId);\n return url.href;\n}\n\nasync function validate<T extends SocketSchema>(schema: T, value: unknown): Promise<SchemaOutput<T>> {\n const result = await schema[\"~standard\"].validate(value);\n if (\"issues\" in result && result.issues) throw new TypeError(\"Invalid socket event payload\");\n return (result as { value: SchemaOutput<T> }).value;\n}\n\n/** Native WebSocket client: no offline queue and no automatic replay. */\nexport function createSocketClient<C extends SocketContract>(url: string, contract: C, options: SocketClientOptions = {}): SocketClient<C> {\n const state = signal<\"connecting\" | \"open\" | \"closed\">(\"connecting\");\n const listeners = new Map<string, Set<(value: unknown) => void>>();\n const factory = options.webSocketFactory ?? ((address: string) => new WebSocket(address));\n const maxBytes = options.maxMessageBytes ?? 64 * 1024;\n let socket: WebSocket | undefined;\n let retry: ReturnType<typeof setTimeout> | undefined;\n let attempts = 0;\n let closed = false;\n const reportError = (error: unknown) => {\n if (!options.onError) { logClientError(\"Meeko socket client error\", error); return; }\n observeCallback(() => options.onError!(error),\n (observerError) => logClientError(\"Meeko socket error observer failed\", error, observerError));\n };\n const setState = (next: \"connecting\" | \"open\" | \"closed\") => {\n try { state.value = next; }\n catch (error) { reportError(error); }\n };\n const closePeer = (peer: WebSocket | undefined, code: number, reason: string) => {\n try { peer?.close(code, reason); }\n catch (error) { reportError(error); }\n };\n const scheduleRetry = () => {\n if (closed) return;\n const delay = Math.min((options.retryMs ?? 500) * 2 ** attempts++, options.maxRetryMs ?? 30_000);\n retry = setTimeout(() => {\n retry = undefined;\n try { connect(); }\n catch (error) {\n reportError(error);\n setState(\"closed\");\n scheduleRetry();\n }\n }, delay);\n };\n\n const connect = () => {\n if (closed) return;\n setState(\"connecting\");\n const peer = factory(url);\n socket = peer;\n let transportErrorReported = false;\n peer.addEventListener(\"open\", () => { if (peer === socket) { attempts = 0; setState(\"open\"); } });\n peer.addEventListener(\"error\", () => {\n if (peer !== socket || closed || transportErrorReported) return;\n transportErrorReported = true;\n reportError(new Error(\"Socket transport error\"));\n });\n peer.addEventListener(\"message\", (message) => {\n if (peer !== socket || closed) return;\n if (typeof message.data !== \"string\" || new TextEncoder().encode(message.data).byteLength > maxBytes) {\n reportError(new RangeError(\"Socket message too large or not text\"));\n closed = true;\n setState(\"closed\");\n listeners.clear();\n closePeer(peer, 1009, \"Message too large\");\n return;\n }\n void (async () => {\n const decoded: unknown = JSON.parse(message.data as string);\n if (typeof decoded !== \"object\" || decoded === null || !(\"event\" in decoded) || !(\"payload\" in decoded) || typeof decoded.event !== \"string\") throw new TypeError(\"Invalid socket message\");\n const schema = contract.serverToClient[decoded.event];\n if (!schema) throw new TypeError(\"Unknown socket event\");\n const value = await validate(schema, decoded.payload);\n if (peer !== socket || closed) return;\n for (const listener of listeners.get(decoded.event) ?? []) {\n if (peer !== socket || closed) return;\n observeCallback(() => listener(value), reportError);\n }\n })().catch((error: unknown) => {\n if (peer !== socket || closed) return;\n reportError(error);\n closed = true;\n setState(\"closed\");\n listeners.clear();\n closePeer(peer, 1008, \"Invalid event\");\n });\n });\n peer.addEventListener(\"close\", (event) => {\n if (peer !== socket || closed) return;\n setState(\"closed\");\n if ([1008, 1009].includes((event as CloseEvent).code)) { closed = true; listeners.clear(); return; }\n scheduleRetry();\n });\n };\n connect();\n return {\n state,\n async emit(event, data) {\n if (closed || socket?.readyState !== WebSocket.OPEN) throw new Error(\"Socket is disconnected\");\n const schema = contract.clientToServer[event];\n if (!schema) throw new TypeError(`Unknown socket event: ${event}`);\n const value = await validate(schema, data);\n if (closed || socket.readyState !== WebSocket.OPEN) throw new Error(\"Socket is disconnected\");\n const message = serializeJson({ event, payload: value });\n if (new TextEncoder().encode(message).byteLength > maxBytes) throw new RangeError(\"Socket message too large\");\n socket.send(message);\n },\n on(event, listener) {\n const set = listeners.get(event) ?? new Set();\n set.add(listener as (value: unknown) => void);\n listeners.set(event, set);\n const unsubscribe = () => { set.delete(listener as (value: unknown) => void); if (set.size === 0) listeners.delete(event); };\n if (currentEffectOwner()) onCleanup(unsubscribe);\n return unsubscribe;\n },\n close() {\n if (closed) { listeners.clear(); return; }\n closed = true;\n if (retry) clearTimeout(retry);\n closePeer(socket, 1000, \"Client closed\");\n listeners.clear();\n setState(\"closed\");\n },\n };\n}\n\n/** Binds socket lifetime to a Meeko root; SSR never opens a connection. */\nexport function useSocket<C extends SocketContract>(url: string, contract: C, options: SocketClientOptions = {}): SocketClient<C> {\n if (typeof window === \"undefined\") throw new Error(\"useSocket() is only available in the browser\");\n const onError = options.onError ?? currentComponentErrorHandler();\n const client = createSocketClient(url, contract, onError ? { ...options, onError } : options);\n try { onCleanup(() => client.close()); }\n catch (error) { client.close(); throw error; }\n return client;\n}\n\n/** Creates lazily connected, typed channel clients from public shared schemas. */\nexport function createSocketRegistry<C extends Record<string, SocketContract>>(contracts: C, options: SocketRegistryOptions = {}): SocketRegistry<C> {\n const result: Record<string, unknown> = Object.create(null);\n for (const name of Object.keys(contracts)) {\n let client: SocketClient<SocketContract> | undefined;\n const appClients = new WeakMap<NonNullable<ReturnType<typeof currentAppErrorChannel>>, SocketClient<SocketContract>>();\n const rootClients = new WeakMap<object, SocketClient<SocketContract>>();\n Object.defineProperty(result, name, {\n enumerable: true,\n get() {\n const channel = currentAppErrorChannel();\n if (channel) {\n let scoped = appClients.get(channel);\n if (!scoped) {\n const onError = options.onError ?? ((error: unknown) => {\n const handler = channel.current();\n if (handler) return handler(error);\n logClientError(\"Meeko socket client error\", error);\n });\n scoped = createSocketClient(socketUrl(name, options), contracts[name]!, { ...options, onError });\n appClients.set(channel, scoped);\n const owned = scoped;\n channel.track(() => { owned.close(); appClients.delete(channel); });\n }\n return scoped;\n }\n const owner = currentEffectOwner();\n if (owner) {\n let scoped = rootClients.get(owner);\n if (!scoped) {\n const onError = options.onError ?? currentComponentErrorHandler();\n scoped = createSocketClient(socketUrl(name, options), contracts[name]!, onError ? { ...options, onError } : options);\n rootClients.set(owner, scoped);\n const owned = scoped;\n onCleanup(() => { owned.close(); rootClients.delete(owner); });\n }\n return scoped;\n }\n if (!client) client = createSocketClient(socketUrl(name, options), contracts[name]!, options);\n return client;\n },\n });\n }\n return result as SocketRegistry<C>;\n}\n\n/** Creates a channel scoped to the current component root. */\nexport function useSocketChannel<C extends Record<string, SocketContract>, K extends keyof C & string>(contracts: C, name: K, options: SocketRegistryOptions = {}): SocketClient<C[K]> {\n const contract = contracts[name];\n if (!contract) throw new TypeError(`Unknown socket channel: ${name}`);\n return useSocket(socketUrl(name, options), contract, options);\n}\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import ts from "@typescript/typescript6";
|
|
2
|
+
export interface StandardSchemaTypes {
|
|
3
|
+
readonly input: ts.Type;
|
|
4
|
+
readonly output: ts.Type;
|
|
5
|
+
}
|
|
6
|
+
/** Resolve the public Standard Schema contract without allowing erased client types. */
|
|
7
|
+
export declare function standardSchemaTypes(expression: ts.Expression, checker: ts.TypeChecker, invalid: () => Error): StandardSchemaTypes;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import ts from "@typescript/typescript6";
|
|
2
|
+
const unsafeFlags = ts.TypeFlags.Any | ts.TypeFlags.Unknown | ts.TypeFlags.Never | ts.TypeFlags.TypeParameter;
|
|
3
|
+
function isErased(type) {
|
|
4
|
+
return (type.flags & unsafeFlags) !== 0;
|
|
5
|
+
}
|
|
6
|
+
function isUnsafe(type, checker, location, seen) {
|
|
7
|
+
if (isErased(type))
|
|
8
|
+
return true;
|
|
9
|
+
if (seen.has(type))
|
|
10
|
+
return false;
|
|
11
|
+
seen.add(type);
|
|
12
|
+
if ((type.isUnionOrIntersection() && type.types.some((part) => isUnsafe(part, checker, location, seen)))
|
|
13
|
+
|| type.aliasTypeArguments?.some((argument) => isUnsafe(argument, checker, location, seen)))
|
|
14
|
+
return true;
|
|
15
|
+
if (type.flags & ts.TypeFlags.Object) {
|
|
16
|
+
const object = type;
|
|
17
|
+
if ((object.objectFlags & ts.ObjectFlags.Reference) !== 0
|
|
18
|
+
&& checker.getTypeArguments(object).some((argument) => isUnsafe(argument, checker, location, seen)))
|
|
19
|
+
return true;
|
|
20
|
+
const numberIndex = checker.getIndexTypeOfType(type, ts.IndexKind.Number);
|
|
21
|
+
if (numberIndex && isUnsafe(numberIndex, checker, location, seen))
|
|
22
|
+
return true;
|
|
23
|
+
const stringIndex = checker.getIndexTypeOfType(type, ts.IndexKind.String);
|
|
24
|
+
if (stringIndex && isUnsafe(stringIndex, checker, location, seen))
|
|
25
|
+
return true;
|
|
26
|
+
// Array and tuple methods contain library-level generics that are not part
|
|
27
|
+
// of the serialized payload. Their element/type arguments above are.
|
|
28
|
+
if (!checker.isArrayLikeType(type)) {
|
|
29
|
+
for (const property of checker.getPropertiesOfType(type)) {
|
|
30
|
+
if (isUnsafe(checker.getTypeOfSymbolAtLocation(property, location), checker, location, seen))
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
for (const signature of [...checker.getSignaturesOfType(type, ts.SignatureKind.Call), ...checker.getSignaturesOfType(type, ts.SignatureKind.Construct)]) {
|
|
34
|
+
if (signature.getParameters().some((parameter) => isUnsafe(checker.getTypeOfSymbolAtLocation(parameter, location), checker, location, seen))
|
|
35
|
+
|| isUnsafe(signature.getReturnType(), checker, location, seen))
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
/** Resolve the public Standard Schema contract without allowing erased client types. */
|
|
43
|
+
export function standardSchemaTypes(expression, checker, invalid) {
|
|
44
|
+
const schemaType = checker.getTypeAtLocation(expression);
|
|
45
|
+
if (isErased(schemaType))
|
|
46
|
+
throw invalid();
|
|
47
|
+
const standard = checker.getPropertyOfType(schemaType, "~standard");
|
|
48
|
+
if (!standard)
|
|
49
|
+
throw invalid();
|
|
50
|
+
const standardType = checker.getTypeOfSymbolAtLocation(standard, expression);
|
|
51
|
+
if (isErased(standardType))
|
|
52
|
+
throw invalid();
|
|
53
|
+
const types = checker.getPropertyOfType(standardType, "types");
|
|
54
|
+
if (!types)
|
|
55
|
+
throw invalid();
|
|
56
|
+
const typesType = checker.getNonNullableType(checker.getTypeOfSymbolAtLocation(types, expression));
|
|
57
|
+
if (isErased(typesType))
|
|
58
|
+
throw invalid();
|
|
59
|
+
const input = checker.getPropertyOfType(typesType, "input");
|
|
60
|
+
const output = checker.getPropertyOfType(typesType, "output");
|
|
61
|
+
if (!input || !output)
|
|
62
|
+
throw invalid();
|
|
63
|
+
const inputType = checker.getTypeOfSymbolAtLocation(input, expression);
|
|
64
|
+
const outputType = checker.getTypeOfSymbolAtLocation(output, expression);
|
|
65
|
+
if (isUnsafe(inputType, checker, expression, new Set()) || isUnsafe(outputType, checker, expression, new Set()))
|
|
66
|
+
throw invalid();
|
|
67
|
+
return { input: inputType, output: outputType };
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=standard-schema-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"standard-schema-types.js","sourceRoot":"","sources":["../../src/framework/standard-schema-types.ts"],"names":[],"mappings":"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","sourcesContent":["import ts from \"@typescript/typescript6\";\n\nexport interface StandardSchemaTypes {\n readonly input: ts.Type;\n readonly output: ts.Type;\n}\n\nconst unsafeFlags = ts.TypeFlags.Any | ts.TypeFlags.Unknown | ts.TypeFlags.Never | ts.TypeFlags.TypeParameter;\n\nfunction isErased(type: ts.Type): boolean {\n return (type.flags & unsafeFlags) !== 0;\n}\n\nfunction isUnsafe(type: ts.Type, checker: ts.TypeChecker, location: ts.Node, seen: Set<ts.Type>): boolean {\n if (isErased(type)) return true;\n if (seen.has(type)) return false;\n seen.add(type);\n\n if ((type.isUnionOrIntersection() && type.types.some((part) => isUnsafe(part, checker, location, seen)))\n || type.aliasTypeArguments?.some((argument) => isUnsafe(argument, checker, location, seen))) return true;\n\n if (type.flags & ts.TypeFlags.Object) {\n const object = type as ts.ObjectType;\n if ((object.objectFlags & ts.ObjectFlags.Reference) !== 0\n && checker.getTypeArguments(object as ts.TypeReference).some((argument) => isUnsafe(argument, checker, location, seen))) return true;\n\n const numberIndex = checker.getIndexTypeOfType(type, ts.IndexKind.Number);\n if (numberIndex && isUnsafe(numberIndex, checker, location, seen)) return true;\n const stringIndex = checker.getIndexTypeOfType(type, ts.IndexKind.String);\n if (stringIndex && isUnsafe(stringIndex, checker, location, seen)) return true;\n\n // Array and tuple methods contain library-level generics that are not part\n // of the serialized payload. Their element/type arguments above are.\n if (!checker.isArrayLikeType(type)) {\n for (const property of checker.getPropertiesOfType(type)) {\n if (isUnsafe(checker.getTypeOfSymbolAtLocation(property, location), checker, location, seen)) return true;\n }\n for (const signature of [...checker.getSignaturesOfType(type, ts.SignatureKind.Call), ...checker.getSignaturesOfType(type, ts.SignatureKind.Construct)]) {\n if (signature.getParameters().some((parameter) =>\n isUnsafe(checker.getTypeOfSymbolAtLocation(parameter, location), checker, location, seen))\n || isUnsafe(signature.getReturnType(), checker, location, seen)) return true;\n }\n }\n }\n return false;\n}\n\n/** Resolve the public Standard Schema contract without allowing erased client types. */\nexport function standardSchemaTypes(\n expression: ts.Expression,\n checker: ts.TypeChecker,\n invalid: () => Error,\n): StandardSchemaTypes {\n const schemaType = checker.getTypeAtLocation(expression);\n if (isErased(schemaType)) throw invalid();\n const standard = checker.getPropertyOfType(schemaType, \"~standard\");\n if (!standard) throw invalid();\n const standardType = checker.getTypeOfSymbolAtLocation(standard, expression);\n if (isErased(standardType)) throw invalid();\n const types = checker.getPropertyOfType(standardType, \"types\");\n if (!types) throw invalid();\n const typesType = checker.getNonNullableType(checker.getTypeOfSymbolAtLocation(types, expression));\n if (isErased(typesType)) throw invalid();\n const input = checker.getPropertyOfType(typesType, \"input\");\n const output = checker.getPropertyOfType(typesType, \"output\");\n if (!input || !output) throw invalid();\n const inputType = checker.getTypeOfSymbolAtLocation(input, expression);\n const outputType = checker.getTypeOfSymbolAtLocation(output, expression);\n if (isUnsafe(inputType, checker, expression, new Set()) || isUnsafe(outputType, checker, expression, new Set())) throw invalid();\n return { input: inputType, output: outputType };\n}\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Signal } from "../reactivity.js";
|
|
2
|
+
export declare class StateStore {
|
|
3
|
+
private readonly values;
|
|
4
|
+
constructor(initial?: Readonly<Record<string, unknown>>);
|
|
5
|
+
get<T>(key: string, factory: () => T): Signal<T>;
|
|
6
|
+
/** Seeds values returned by a later server navigation without replacing local state. */
|
|
7
|
+
seed(values: Readonly<Record<string, unknown>>): void;
|
|
8
|
+
/** Applies navigation state only if the synchronous DOM commit succeeds. */
|
|
9
|
+
seedForNavigation<T>(values: Readonly<Record<string, unknown>>, commit: () => T): T;
|
|
10
|
+
/** Gives an async client loader isolated signals until its route commits. */
|
|
11
|
+
navigationDraft(): {
|
|
12
|
+
state: StateStore;
|
|
13
|
+
commit<T>(work: () => T): T;
|
|
14
|
+
};
|
|
15
|
+
snapshot(): Record<string, unknown>;
|
|
16
|
+
}
|
|
17
|
+
/** One keyed signal per application request or browser app instance. */
|
|
18
|
+
export declare function useState<T>(key: string, factory: () => T): Signal<T>;
|
|
19
|
+
/** Runs synchronous SSR rendering with a state provider and releases its root. */
|
|
20
|
+
export declare function withStateStore<T>(store: StateStore, render: () => T): T;
|
|
21
|
+
/** Keeps the provider alive until the hydrated component is released. */
|
|
22
|
+
export declare function hydrateWithStateStore(store: StateStore, hydrate: () => () => void): () => void;
|