chore: initialize from frontend template 4dc033c

This commit is contained in:
DongHyeonka
2026-08-13 18:23:26 +09:00
commit 40107eec84
897 changed files with 234824 additions and 0 deletions
@@ -0,0 +1,264 @@
import { describe, expect, it } from "vitest";
import {
composeBrowserRpcOperationRegistry,
composeBrowserRpcProviderProfileRegistry,
composeBrowserRpcRequestEncoderRegistry,
defineBrowserRpcOperation,
defineBrowserRpcProviderProfile,
validateBrowserRpcContractBindings,
type BrowserRpcProviderProfile,
} from "../../../src/contracts/browser-rpc.ts";
import {
DESCRIPTOR_DIGEST,
MAPPERS,
RUNTIME_DIGEST,
SCHEMA_CODECS,
STREAM_ENCODER,
UNARY_ENCODER,
streamOperation,
streamProfile,
unaryOperation,
unaryProfile,
} from "./fixture.ts";
describe("Browser RPC contract registry", () => {
it("closes exact operation, provider, schema, mapper and encoder bindings", () => {
const operation = unaryOperation();
const profile = unaryProfile();
const operations = composeBrowserRpcOperationRegistry([
{ GET_RPC_RESOURCE: operation },
]);
const profiles = composeBrowserRpcProviderProfileRegistry([
{ CONNECT_REFERENCE_UNARY: profile },
]);
const encoders = composeBrowserRpcRequestEncoderRegistry([
{ RpcResourceRequestEncoder: UNARY_ENCODER },
]);
expect(
validateBrowserRpcContractBindings({
operations,
profiles,
schemaCodecs: SCHEMA_CODECS,
mappers: MAPPERS,
requestEncoders: encoders,
}),
).toBe(true);
expect(Object.isFrozen(operations)).toBe(true);
expect(Object.isFrozen(profiles.CONNECT_REFERENCE_UNARY)).toBe(true);
expect(
Object.isFrozen(
profiles.CONNECT_REFERENCE_UNARY?.allowedProcedures,
),
).toBe(true);
});
it("rejects duplicate rows and descriptor/provider drift", () => {
const operation = unaryOperation();
expect(() =>
composeBrowserRpcOperationRegistry([
{ GET_RPC_RESOURCE: operation },
{ GET_RPC_RESOURCE: operation },
]),
).toThrow("duplicate Browser RPC operation");
expect(() =>
validateBrowserRpcContractBindings({
operations: { GET_RPC_RESOURCE: operation },
profiles: {
CONNECT_REFERENCE_UNARY: unaryProfile({
descriptorDigest: "c".repeat(64),
}),
},
schemaCodecs: SCHEMA_CODECS,
mappers: MAPPERS,
requestEncoders: {
RpcResourceRequestEncoder: UNARY_ENCODER,
},
}),
).toThrow("provider binding is invalid");
});
it("permits only a public headerless NO_SIDE_EFFECTS Connect GET", () => {
const getProfile = defineBrowserRpcProviderProfile({
...unaryProfile(),
runtimeProfileId: "CONNECT_PUBLIC_GET",
requestMethod: "GET",
authProfileId: "ANONYMOUS",
csrfProfileId: "NONE",
allowedProcedures: [
"example.resource.v1.ResourceService/GetResource",
],
});
const validGet = defineBrowserRpcOperation({
...unaryOperation(),
runtimeProfileId: "CONNECT_PUBLIC_GET",
authProfileId: "ANONYMOUS",
csrfProfileId: "NONE",
idempotencyLevel: "NO_SIDE_EFFECTS",
dataClassification: "PUBLIC",
});
expect(
validateBrowserRpcContractBindings({
operations: { GET_RPC_RESOURCE: validGet },
profiles: { CONNECT_PUBLIC_GET: getProfile },
schemaCodecs: SCHEMA_CODECS,
mappers: MAPPERS,
requestEncoders: {
RpcResourceRequestEncoder: UNARY_ENCODER,
},
}),
).toBe(true);
expect(() =>
validateBrowserRpcContractBindings({
operations: {
GET_RPC_RESOURCE: defineBrowserRpcOperation({
...validGet,
dataClassification: "CONFIDENTIAL",
}),
},
profiles: { CONNECT_PUBLIC_GET: getProfile },
schemaCodecs: SCHEMA_CODECS,
mappers: MAPPERS,
requestEncoders: {
RpcResourceRequestEncoder: UNARY_ENCODER,
},
}),
).toThrow("GET binding is invalid");
});
it("separates official grpc-web, Connect-Web and Connect tuples", () => {
expect(() =>
defineBrowserRpcProviderProfile({
...streamProfile(),
runtimeProfileId: "OFFICIAL_BINARY_STREAM",
runtimeId: "official-grpc-web",
runtimeVersion: "1.5.0",
runtimeDigest: RUNTIME_DIGEST,
protocol: "GRPC_WEB",
runtimeKind: "OFFICIAL_GRPC_WEB_XHR",
clientApiKind: "CALLBACK_STREAM",
messageEncoding: "PROTO",
framing: "GRPC_WEB_BINARY_ENVELOPE",
deadlineDialect: "OFFICIAL_DEADLINE_METADATA",
cancelDialect: "CLIENT_READABLE_STREAM_CANCEL",
descriptorDigest: DESCRIPTOR_DIGEST,
}),
).toThrow("provider profile is invalid");
expect(() =>
defineBrowserRpcProviderProfile({
...unaryProfile(),
framing: "GRPC_WEB_BINARY_ENVELOPE",
}),
).toThrow("provider profile is invalid");
expect(
defineBrowserRpcProviderProfile({
...unaryProfile(),
runtimeProfileId: "CONNECT_GRPC_WEB_UNARY",
protocol: "GRPC_WEB",
framing: "GRPC_WEB_BINARY_ENVELOPE",
deadlineDialect: "GRPC_TIMEOUT",
}),
).toMatchObject({
protocol: "GRPC_WEB",
runtimeKind: "CONNECT_WEB_FETCH",
deadlineDialect: "GRPC_TIMEOUT",
});
});
it("revalidates raw registry rows instead of trusting TypeScript assertions", () => {
const invalidProfile = {
...unaryProfile(),
messageEncoding: "XML",
} as unknown as BrowserRpcProviderProfile;
expect(() =>
validateBrowserRpcContractBindings({
operations: { GET_RPC_RESOURCE: unaryOperation() },
profiles: { CONNECT_REFERENCE_UNARY: invalidProfile },
schemaCodecs: SCHEMA_CODECS,
mappers: MAPPERS,
requestEncoders: {
RpcResourceRequestEncoder: UNARY_ENCODER,
},
}),
).toThrow("provider profile is invalid");
expect(() =>
validateBrowserRpcContractBindings({
operations: { WRONG_REGISTRY_KEY: unaryOperation() },
profiles: { CONNECT_REFERENCE_UNARY: unaryProfile() },
schemaCodecs: SCHEMA_CODECS,
mappers: MAPPERS,
requestEncoders: {
RpcResourceRequestEncoder: UNARY_ENCODER,
},
}),
).toThrow("operation registry is invalid");
});
it("disallows frontend stream retry and unsafe unary replay", () => {
expect(() =>
defineBrowserRpcProviderProfile({
...streamProfile(),
retryOwner: "FRONTEND_ADAPTER",
maxAttempts: 2,
backoffMs: [10],
retryableFailures: ["UNAVAILABLE"],
}),
).toThrow("provider profile is invalid");
const retryProfile = unaryProfile({
retryProfileId: "RPC_RETRY_TWO",
retryOwner: "FRONTEND_ADAPTER",
maxAttempts: 2,
backoffMs: [10],
retryableFailures: ["UNAVAILABLE"],
});
expect(() =>
validateBrowserRpcContractBindings({
operations: {
CREATE_RPC_RESOURCE: defineBrowserRpcOperation({
...unaryOperation(),
operationId: "CREATE_RPC_RESOURCE",
semantics: "COMMAND",
replayPolicy: "NON_REPLAYABLE",
runtimeProfileId: retryProfile.runtimeProfileId,
retryProfileId: retryProfile.retryProfileId,
}),
},
profiles: { CONNECT_REFERENCE_UNARY: retryProfile },
schemaCodecs: SCHEMA_CODECS,
mappers: MAPPERS,
requestEncoders: {
RpcResourceRequestEncoder: {
...UNARY_ENCODER,
operationId: "CREATE_RPC_RESOURCE",
},
},
}),
).toThrow("retry binding is invalid");
});
it("supports a bounded Connect server-stream contract without composing it", () => {
expect(
validateBrowserRpcContractBindings({
operations: {
WATCH_RPC_RESOURCES: streamOperation(),
},
profiles: {
CONNECT_REFERENCE_STREAM: streamProfile(),
},
schemaCodecs: SCHEMA_CODECS,
mappers: MAPPERS,
requestEncoders: {
RpcResourceStreamRequestEncoder: STREAM_ENCODER,
},
}),
).toBe(true);
});
});
@@ -0,0 +1,451 @@
import { describe, expect, it } from "vitest";
import {
createBrowserRpcRuntime,
createUnavailableBrowserRpcTransport,
defineBrowserRpcTransport,
type BrowserRpcObservation,
type BrowserRpcStreamFrame,
type BrowserRpcTransport,
} from "../../../src/adapters/browser-rpc/index.ts";
import type { Result } from "../../../src/application/result.ts";
import type { AppFailure } from "../../../src/contracts/errors.ts";
import {
MAPPERS,
SCHEMA_CODECS,
STREAM_ENCODER,
UNARY_ENCODER,
isResourceView,
streamOperation,
streamProfile,
unaryOperation,
unaryProfile,
type ResourceView,
} from "./fixture.ts";
describe("Browser RPC provider-neutral runtime", () => {
it("validates, encodes, maps and admits only the typed unary result", async () => {
const observations: BrowserRpcObservation[] = [];
const transport = defineBrowserRpcTransport({
runtimeProfileId: "CONNECT_REFERENCE_UNARY",
providerId: "REFERENCE_RPC",
protocol: "CONNECT_HTTP",
rpcKind: "UNARY",
async invokeUnary(call) {
expect(call.request).toEqual({ resourceId: "resource-1" });
expect(call.timeoutMs).toBeGreaterThan(0);
return Object.freeze({
ok: true,
message: Object.freeze({ id: "resource-1", name: "Resource one" }),
encodedBytes: 48,
});
},
});
const port = unaryRuntime(transport, {
observe(value) {
observations.push(value);
},
}).bindUnary("GET_RPC_RESOURCE", isResourceView);
await expect(port.execute({ resourceId: "resource-1" })).resolves.toEqual({
ok: true,
value: { id: "resource-1", label: "Resource one" },
});
expect(observations).toEqual([
{
operationId: "GET_RPC_RESOURCE",
protocol: "CONNECT_HTTP",
runtimeProfileId: "CONNECT_REFERENCE_UNARY",
rpcKind: "UNARY",
outcome: "SUCCESS",
attemptCount: 1,
messageCount: 1,
},
]);
});
it("fails before transport on invalid input or unexpected idempotency metadata", async () => {
let calls = 0;
const transport = defineBrowserRpcTransport({
runtimeProfileId: "CONNECT_REFERENCE_UNARY",
providerId: "REFERENCE_RPC",
protocol: "CONNECT_HTTP",
rpcKind: "UNARY",
async invokeUnary() {
calls += 1;
return {
ok: false,
failure: { code: "UNAVAILABLE" },
};
},
});
const port = unaryRuntime(transport).bindUnary(
"GET_RPC_RESOURCE",
isResourceView,
);
const invalid = await port.execute({ resourceId: 42 });
expect(invalid).toMatchObject({
ok: false,
error: {
kind: "VALIDATION_REJECTED",
code: "RPC_REQUEST_SCHEMA_INVALID",
},
});
const metadata = await port.execute(
{ resourceId: "resource-1" },
{ idempotencyKey: "caller-key-is-not-allowed" },
);
expect(metadata).toMatchObject({
ok: false,
error: {
kind: "VALIDATION_REJECTED",
code: "RPC_IDEMPOTENCY_KEY_INVALID",
},
});
expect(calls).toBe(0);
});
it("keeps the frontend retry owner bounded by replay policy and one total deadline", async () => {
let calls = 0;
const profile = unaryProfile({
retryProfileId: "RPC_RETRY_TWO",
retryOwner: "FRONTEND_ADAPTER",
maxAttempts: 2,
backoffMs: [0],
retryableFailures: ["UNAVAILABLE"],
maxRetryAfterMs: 100,
});
const operation = unaryOperation({
retryProfileId: "RPC_RETRY_TWO",
});
const transport = defineBrowserRpcTransport({
runtimeProfileId: profile.runtimeProfileId,
providerId: profile.providerId,
protocol: profile.protocol,
rpcKind: profile.rpcKind,
async invokeUnary() {
calls += 1;
if (calls === 1) {
return {
ok: false,
failure: { code: "UNAVAILABLE" },
};
}
return {
ok: true,
message: { id: "resource-2", name: "Retried resource" },
encodedBytes: 32,
};
},
});
const runtime = createBrowserRpcRuntime({
operations: { GET_RPC_RESOURCE: operation },
profiles: { CONNECT_REFERENCE_UNARY: profile },
schemaCodecs: SCHEMA_CODECS,
mappers: MAPPERS,
requestEncoders: {
RpcResourceRequestEncoder: UNARY_ENCODER,
},
transports: { CONNECT_REFERENCE_UNARY: transport },
});
await expect(
runtime
.bindUnary("GET_RPC_RESOURCE", isResourceView)
.execute({ resourceId: "resource-2" }),
).resolves.toMatchObject({
ok: true,
value: { id: "resource-2", label: "Retried resource" },
});
expect(calls).toBe(2);
});
it("drops a late unary result after its scope generation changes", async () => {
const transport = defineBrowserRpcTransport({
runtimeProfileId: "CONNECT_REFERENCE_UNARY",
providerId: "REFERENCE_RPC",
protocol: "CONNECT_HTTP",
rpcKind: "UNARY",
async invokeUnary() {
return {
ok: true,
message: { id: "late", name: "Late resource" },
encodedBytes: 24,
};
},
});
const runtime = createBrowserRpcRuntime({
...baseDependencies(transport),
generationFence: {
capture: () => 1,
isCurrent: () => false,
},
});
await expect(
runtime
.bindUnary("GET_RPC_RESOURCE", isResourceView)
.execute({ resourceId: "late" }),
).resolves.toMatchObject({
ok: false,
error: {
kind: "SCOPE_GENERATION_CHANGED",
code: "RPC_SCOPE_GENERATION_CHANGED",
},
});
});
it("uses an explicit unavailable adapter without network fallback", async () => {
const transport = createUnavailableBrowserRpcTransport({
runtimeProfileId: "CONNECT_REFERENCE_UNARY",
providerId: "REFERENCE_RPC",
protocol: "CONNECT_HTTP",
rpcKind: "UNARY",
});
const result = await unaryRuntime(transport)
.bindUnary("GET_RPC_RESOURCE", isResourceView)
.execute({ resourceId: "resource-1" });
expect(result).toMatchObject({
ok: false,
error: {
kind: "SERVER_FAILURE",
code: "RPC_UNAVAILABLE",
},
});
});
it("classifies valid oversized transport metadata as a response limit", async () => {
const transport = defineBrowserRpcTransport({
runtimeProfileId: "CONNECT_REFERENCE_UNARY",
providerId: "REFERENCE_RPC",
protocol: "CONNECT_HTTP",
rpcKind: "UNARY",
async invokeUnary() {
return {
ok: true,
message: { id: "large", name: "Large resource" },
encodedBytes: 4_097,
};
},
});
await expect(
unaryRuntime(transport)
.bindUnary("GET_RPC_RESOURCE", isResourceView)
.execute({ resourceId: "large" }),
).resolves.toMatchObject({
ok: false,
error: {
kind: "RESPONSE_BODY_LIMIT",
code: "RPC_RESPONSE_MESSAGE_LIMIT",
},
});
});
it("rejects transports that expose the wrong call shape", () => {
expect(() =>
defineBrowserRpcTransport({
runtimeProfileId: "CONNECT_REFERENCE_UNARY",
providerId: "REFERENCE_RPC",
protocol: "CONNECT_HTTP",
rpcKind: "UNARY",
async invokeUnary() {
return {
ok: false,
failure: { code: "UNAVAILABLE" },
};
},
async *openServerStream() {
yield Object.freeze({ kind: "TERMINAL", ok: true });
},
}),
).toThrow("transport is invalid");
});
it("commits mapped stream messages only before one valid terminal envelope", async () => {
const transport = streamTransport(async function* () {
yield message("resource-1", "One", 24);
yield message("resource-2", "Two", 24);
yield Object.freeze({ kind: "TERMINAL", ok: true });
});
const observations: BrowserRpcObservation[] = [];
const stream = streamRuntime(transport, {
observe(value) {
observations.push(value);
},
})
.bindServerStream("WATCH_RPC_RESOURCES", isResourceView)
.open({ resourceId: "scope-1" });
await expect(collect(stream)).resolves.toEqual([
{
ok: true,
value: { id: "resource-1", label: "One" },
},
{
ok: true,
value: { id: "resource-2", label: "Two" },
},
]);
expect(observations).toEqual([
{
operationId: "WATCH_RPC_RESOURCES",
protocol: "CONNECT_HTTP",
runtimeProfileId: "CONNECT_REFERENCE_STREAM",
rpcKind: "SERVER_STREAM",
outcome: "SUCCESS",
attemptCount: 1,
messageCount: 2,
},
]);
});
it("rejects EOF without terminal and data after terminal", async () => {
const missingTerminal = streamTransport(async function* () {
yield message("resource-1", "One", 24);
});
const missingResults = await collect(
streamRuntime(missingTerminal)
.bindServerStream("WATCH_RPC_RESOURCES", isResourceView)
.open({ resourceId: "scope-1" }),
);
expect(missingResults.at(-1)).toMatchObject({
ok: false,
error: {
kind: "API_CONTRACT_MISMATCH",
code: "RPC_PROTOCOL_MISMATCH",
},
});
const afterTerminal = streamTransport(async function* () {
yield Object.freeze({ kind: "TERMINAL", ok: true });
yield message("resource-2", "Two", 24);
});
await expect(
collect(
streamRuntime(afterTerminal)
.bindServerStream("WATCH_RPC_RESOURCES", isResourceView)
.open({ resourceId: "scope-1" }),
),
).resolves.toMatchObject([
{
ok: false,
error: {
kind: "API_CONTRACT_MISMATCH",
code: "RPC_PROTOCOL_MISMATCH",
},
},
]);
});
it("aborts the transport when stream message limits are exceeded", async () => {
let cleaned = false;
const transport = streamTransport(async function* (signal) {
try {
yield message("resource-1", "One", 24);
yield message("resource-2", "Two", 24);
yield Object.freeze({ kind: "TERMINAL", ok: true });
} finally {
cleaned = signal.aborted;
}
});
const operation = streamOperation({ maxResponseMessages: 1 });
const results = await collect(
streamRuntime(transport, undefined, operation)
.bindServerStream("WATCH_RPC_RESOURCES", isResourceView)
.open({ resourceId: "scope-1" }),
);
expect(results.at(-1)).toMatchObject({
ok: false,
error: {
kind: "RESPONSE_BODY_LIMIT",
code: "RPC_STREAM_MESSAGE_LIMIT",
},
});
expect(cleaned).toBe(true);
});
});
function unaryRuntime(
transport: BrowserRpcTransport,
observations?: Readonly<{
observe(value: BrowserRpcObservation): void;
}>,
) {
return createBrowserRpcRuntime({
...baseDependencies(transport),
observations,
});
}
function baseDependencies(transport: BrowserRpcTransport) {
return {
operations: { GET_RPC_RESOURCE: unaryOperation() },
profiles: { CONNECT_REFERENCE_UNARY: unaryProfile() },
schemaCodecs: SCHEMA_CODECS,
mappers: MAPPERS,
requestEncoders: {
RpcResourceRequestEncoder: UNARY_ENCODER,
},
transports: { CONNECT_REFERENCE_UNARY: transport },
} as const;
}
function streamRuntime(
transport: BrowserRpcTransport,
observations?: Readonly<{
observe(value: BrowserRpcObservation): void;
}>,
operation = streamOperation(),
) {
return createBrowserRpcRuntime({
operations: { WATCH_RPC_RESOURCES: operation },
profiles: { CONNECT_REFERENCE_STREAM: streamProfile() },
schemaCodecs: SCHEMA_CODECS,
mappers: MAPPERS,
requestEncoders: {
RpcResourceStreamRequestEncoder: STREAM_ENCODER,
},
transports: { CONNECT_REFERENCE_STREAM: transport },
observations,
});
}
function streamTransport(
source: (
signal: AbortSignal,
) => AsyncIterable<BrowserRpcStreamFrame>,
): BrowserRpcTransport {
return defineBrowserRpcTransport({
runtimeProfileId: "CONNECT_REFERENCE_STREAM",
providerId: "REFERENCE_RPC",
protocol: "CONNECT_HTTP",
rpcKind: "SERVER_STREAM",
openServerStream(call) {
return source(call.signal);
},
});
}
function message(
id: string,
name: string,
encodedBytes: number,
): BrowserRpcStreamFrame {
return Object.freeze({
kind: "MESSAGE",
message: Object.freeze({ id, name }),
encodedBytes,
});
}
async function collect<Value>(
iterable: AsyncIterable<Result<Value, AppFailure>>,
): Promise<readonly Result<Value, AppFailure>[]> {
const values: Result<Value, AppFailure>[] = [];
for await (const value of iterable) values.push(value);
return values;
}
+241
View File
@@ -0,0 +1,241 @@
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"
);
}