242 lines
7.5 KiB
TypeScript
242 lines
7.5 KiB
TypeScript
import {
|
|
defineBrowserRpcOperation,
|
|
defineBrowserRpcProviderProfile,
|
|
defineBrowserRpcRequestEncoder,
|
|
type BrowserRpcOperationV3,
|
|
type BrowserRpcProviderProfile,
|
|
} from "../../../src/contracts/browser-rpc.ts";
|
|
import {
|
|
mappingSuccess,
|
|
type InstalledBoundaryMapper,
|
|
} from "../../../src/contracts/boundary-mapper.ts";
|
|
import type { RuntimeSchemaCodec } from "../../../src/contracts/schema-registry.ts";
|
|
|
|
export const DESCRIPTOR_DIGEST = "a".repeat(64);
|
|
export const RUNTIME_DIGEST = "b".repeat(64);
|
|
|
|
export type ResourceView = Readonly<{ id: string; label: string }>;
|
|
|
|
export function unaryProfile(
|
|
overrides: Partial<BrowserRpcProviderProfile> = {},
|
|
): BrowserRpcProviderProfile {
|
|
return defineBrowserRpcProviderProfile({
|
|
runtimeProfileId: "CONNECT_REFERENCE_UNARY",
|
|
providerId: "REFERENCE_RPC",
|
|
fixedBaseUrl: "https://rpc.example.test/base/",
|
|
runtimeId: "connect-es-web",
|
|
runtimeVersion: "2.1.0",
|
|
runtimeDigest: RUNTIME_DIGEST,
|
|
protocol: "CONNECT_HTTP",
|
|
runtimeKind: "CONNECT_WEB_FETCH",
|
|
clientApiKind: "PROMISE_UNARY",
|
|
rpcKind: "UNARY",
|
|
messageEncoding: "PROTO",
|
|
framing: "CONNECT_BARE",
|
|
requestMethod: "POST",
|
|
descriptorArtifactId: "buf.example.resource.v1",
|
|
descriptorDigest: DESCRIPTOR_DIGEST,
|
|
allowedProcedures: ["example.resource.v1.ResourceService/GetResource"],
|
|
authProfileId: "REFERENCE_EXTERNAL_BEARER",
|
|
csrfProfileId: "NO_CSRF_BEARER",
|
|
corsProfileId: "SAME_ORIGIN_RPC",
|
|
errorProfileId: "CONNECT_ERROR_V1",
|
|
deadlineProfileId: "RPC_TOTAL_5S",
|
|
retryProfileId: "RPC_RETRY_NONE",
|
|
retryOwner: "NONE",
|
|
maxAttempts: 1,
|
|
backoffMs: [],
|
|
retryableFailures: [],
|
|
maxRetryAfterMs: 0,
|
|
deadlineDialect: "CONNECT_TIMEOUT_MS",
|
|
cancelDialect: "ABORT_SIGNAL",
|
|
rawByteCeilingOwner: "EDGE_AND_TRANSPORT",
|
|
streamMessageCompression: "IDENTITY_ONLY",
|
|
...overrides,
|
|
});
|
|
}
|
|
|
|
export function unaryOperation(
|
|
overrides: Partial<BrowserRpcOperationV3> = {},
|
|
): BrowserRpcOperationV3 {
|
|
return defineBrowserRpcOperation({
|
|
contractVersion: 3,
|
|
operationId: "GET_RPC_RESOURCE",
|
|
owner: "feature-browser-rpc-test",
|
|
protocol: "CONNECT_HTTP",
|
|
semantics: "QUERY",
|
|
replayPolicy: "SAFE",
|
|
idempotencyKeyPolicy: "NONE",
|
|
idempotencyLevel: "IDEMPOTENT",
|
|
dataClassification: "INTERNAL",
|
|
runtimeProfileId: "CONNECT_REFERENCE_UNARY",
|
|
providerId: "REFERENCE_RPC",
|
|
fullyQualifiedService: "example.resource.v1.ResourceService",
|
|
method: "GetResource",
|
|
rpcKind: "UNARY",
|
|
requestMessageId: "example.resource.v1.GetResourceRequest",
|
|
responseMessageId: "example.resource.v1.Resource",
|
|
descriptorArtifactId: "buf.example.resource.v1",
|
|
descriptorDigest: DESCRIPTOR_DIGEST,
|
|
requestSchemaId: "RpcResourceRequest",
|
|
responseSchemaId: "RpcResourceResponse",
|
|
requestEncoderId: "RpcResourceRequestEncoder",
|
|
mapperId: "RpcResourceMapper",
|
|
authProfileId: "REFERENCE_EXTERNAL_BEARER",
|
|
csrfProfileId: "NO_CSRF_BEARER",
|
|
errorProfileId: "CONNECT_ERROR_V1",
|
|
deadlineProfileId: "RPC_TOTAL_5S",
|
|
retryProfileId: "RPC_RETRY_NONE",
|
|
serverStateProfileId: "RpcResourceQuery",
|
|
maxRequestMessageBytes: 1_024,
|
|
maxResponseMessageBytes: 4_096,
|
|
maxResponseMessages: 1,
|
|
maxTotalResponseBytes: 4_096,
|
|
maxBufferedBytes: 4_096,
|
|
idleDeadlineMs: null,
|
|
totalDeadlineMs: 5_000,
|
|
...overrides,
|
|
});
|
|
}
|
|
|
|
export function streamProfile(
|
|
overrides: Partial<BrowserRpcProviderProfile> = {},
|
|
): BrowserRpcProviderProfile {
|
|
return defineBrowserRpcProviderProfile({
|
|
...unaryProfile(),
|
|
runtimeProfileId: "CONNECT_REFERENCE_STREAM",
|
|
clientApiKind: "ASYNC_ITERABLE",
|
|
rpcKind: "SERVER_STREAM",
|
|
framing: "CONNECT_ENVELOPE",
|
|
allowedProcedures: [
|
|
"example.resource.v1.ResourceService/WatchResources",
|
|
],
|
|
retryProfileId: "RPC_STREAM_RETRY_NONE",
|
|
...overrides,
|
|
});
|
|
}
|
|
|
|
export function streamOperation(
|
|
overrides: Partial<BrowserRpcOperationV3> = {},
|
|
): BrowserRpcOperationV3 {
|
|
return defineBrowserRpcOperation({
|
|
...unaryOperation(),
|
|
operationId: "WATCH_RPC_RESOURCES",
|
|
semantics: "SERVER_STREAM",
|
|
runtimeProfileId: "CONNECT_REFERENCE_STREAM",
|
|
method: "WatchResources",
|
|
rpcKind: "SERVER_STREAM",
|
|
requestEncoderId: "RpcResourceStreamRequestEncoder",
|
|
retryProfileId: "RPC_STREAM_RETRY_NONE",
|
|
serverStateProfileId: null,
|
|
maxResponseMessages: 4,
|
|
maxTotalResponseBytes: 16_384,
|
|
maxBufferedBytes: 8_192,
|
|
idleDeadlineMs: 1_000,
|
|
totalDeadlineMs: 10_000,
|
|
...overrides,
|
|
});
|
|
}
|
|
|
|
export const SCHEMA_CODECS = Object.freeze({
|
|
RpcResourceRequest: Object.freeze({
|
|
schemaId: "RpcResourceRequest",
|
|
parse(value: unknown) {
|
|
if (
|
|
value &&
|
|
typeof value === "object" &&
|
|
typeof (value as { resourceId?: unknown }).resourceId === "string"
|
|
) {
|
|
return Object.freeze({
|
|
success: true,
|
|
data: Object.freeze({
|
|
resourceId: (value as { resourceId: string }).resourceId,
|
|
}),
|
|
});
|
|
}
|
|
return Object.freeze({
|
|
success: false,
|
|
issues: Object.freeze([
|
|
Object.freeze({ path: "resourceId", code: "INVALID_STRING" }),
|
|
]),
|
|
});
|
|
},
|
|
}),
|
|
RpcResourceResponse: Object.freeze({
|
|
schemaId: "RpcResourceResponse",
|
|
parse(value: unknown) {
|
|
if (
|
|
value &&
|
|
typeof value === "object" &&
|
|
typeof (value as { id?: unknown }).id === "string" &&
|
|
typeof (value as { name?: unknown }).name === "string"
|
|
) {
|
|
return Object.freeze({
|
|
success: true,
|
|
data: Object.freeze({
|
|
id: (value as { id: string }).id,
|
|
name: (value as { name: string }).name,
|
|
}),
|
|
});
|
|
}
|
|
return Object.freeze({
|
|
success: false,
|
|
issues: Object.freeze([
|
|
Object.freeze({ path: "", code: "INVALID_RESOURCE" }),
|
|
]),
|
|
});
|
|
},
|
|
}),
|
|
} satisfies Readonly<Record<string, RuntimeSchemaCodec>>);
|
|
|
|
export const MAPPERS = Object.freeze({
|
|
RpcResourceMapper: Object.freeze({
|
|
mapperId: "RpcResourceMapper",
|
|
mapperVersion: 1,
|
|
inputSchemaId: "RpcResourceResponse",
|
|
outputContractId: "ResourceView",
|
|
owner: "feature-browser-rpc-test",
|
|
maxOutputItems: 1,
|
|
map(input: unknown) {
|
|
const resource = input as Readonly<{ id: string; name: string }>;
|
|
return mappingSuccess<ResourceView>(
|
|
Object.freeze({ id: resource.id, label: resource.name }),
|
|
);
|
|
},
|
|
}),
|
|
} satisfies Readonly<Record<string, InstalledBoundaryMapper>>);
|
|
|
|
export const UNARY_ENCODER = defineBrowserRpcRequestEncoder({
|
|
encoderId: "RpcResourceRequestEncoder",
|
|
operationId: "GET_RPC_RESOURCE",
|
|
encode(value) {
|
|
const request = value as Readonly<{ resourceId: string }>;
|
|
return Object.freeze({
|
|
ok: true,
|
|
value: Object.freeze({ resourceId: request.resourceId }),
|
|
encodedBytes: request.resourceId.length,
|
|
});
|
|
},
|
|
});
|
|
|
|
export const STREAM_ENCODER = defineBrowserRpcRequestEncoder({
|
|
encoderId: "RpcResourceStreamRequestEncoder",
|
|
operationId: "WATCH_RPC_RESOURCES",
|
|
encode(value) {
|
|
const request = value as Readonly<{ resourceId: string }>;
|
|
return Object.freeze({
|
|
ok: true,
|
|
value: Object.freeze({ resourceId: request.resourceId }),
|
|
encodedBytes: request.resourceId.length,
|
|
});
|
|
},
|
|
});
|
|
|
|
export function isResourceView(value: unknown): value is ResourceView {
|
|
return (
|
|
!!value &&
|
|
typeof value === "object" &&
|
|
typeof (value as { id?: unknown }).id === "string" &&
|
|
typeof (value as { label?: unknown }).label === "string"
|
|
);
|
|
}
|