@reactionary/source 0.0.48 → 0.0.52
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/core/package.json +4 -3
- package/core/src/cache/cache.interface.ts +1 -1
- package/core/src/cache/memory-cache.ts +2 -2
- package/core/src/cache/noop-cache.ts +1 -1
- package/core/src/cache/redis-cache.ts +1 -1
- package/core/src/client/client-builder.ts +4 -4
- package/core/src/client/client.ts +12 -12
- package/core/src/decorators/reactionary.decorator.ts +22 -2
- package/core/src/index.ts +14 -14
- package/core/src/initialization.ts +1 -1
- package/core/src/providers/analytics.provider.ts +2 -2
- package/core/src/providers/base.provider.ts +5 -5
- package/core/src/providers/cart.provider.ts +6 -6
- package/core/src/providers/category.provider.ts +4 -9
- package/core/src/providers/checkout.provider.ts +156 -0
- package/core/src/providers/identity.provider.ts +5 -5
- package/core/src/providers/index.ts +13 -12
- package/core/src/providers/inventory.provider.ts +4 -4
- package/core/src/providers/order.provider.ts +31 -0
- package/core/src/providers/price.provider.ts +5 -5
- package/core/src/providers/product.provider.ts +5 -5
- package/core/src/providers/profile.provider.ts +5 -5
- package/core/src/providers/search.provider.ts +4 -4
- package/core/src/providers/store.provider.ts +4 -4
- package/core/src/schemas/capabilities.schema.ts +2 -1
- package/core/src/schemas/models/analytics.model.ts +1 -1
- package/core/src/schemas/models/cart.model.ts +3 -28
- package/core/src/schemas/models/category.model.ts +2 -2
- package/core/src/schemas/models/checkout.model.ts +66 -0
- package/core/src/schemas/models/cost.model.ts +21 -0
- package/core/src/schemas/models/identifiers.model.ts +23 -2
- package/core/src/schemas/models/identity.model.ts +8 -5
- package/core/src/schemas/models/index.ts +19 -15
- package/core/src/schemas/models/inventory.model.ts +2 -2
- package/core/src/schemas/models/order.model.ts +46 -0
- package/core/src/schemas/models/payment.model.ts +5 -12
- package/core/src/schemas/models/price.model.ts +3 -3
- package/core/src/schemas/models/product.model.ts +6 -3
- package/core/src/schemas/models/profile.model.ts +2 -2
- package/core/src/schemas/models/search.model.ts +2 -3
- package/core/src/schemas/models/shipping-method.model.ts +34 -3
- package/core/src/schemas/models/store.model.ts +2 -2
- package/core/src/schemas/mutations/analytics.mutation.ts +2 -2
- package/core/src/schemas/mutations/cart.mutation.ts +5 -5
- package/core/src/schemas/mutations/checkout.mutation.ts +50 -0
- package/core/src/schemas/mutations/identity.mutation.ts +1 -1
- package/core/src/schemas/mutations/index.ts +10 -10
- package/core/src/schemas/mutations/profile.mutation.ts +1 -1
- package/core/src/schemas/queries/cart.query.ts +2 -2
- package/core/src/schemas/queries/category.query.ts +3 -3
- package/core/src/schemas/queries/checkout.query.ts +22 -0
- package/core/src/schemas/queries/identity.query.ts +1 -1
- package/core/src/schemas/queries/index.ts +13 -12
- package/core/src/schemas/queries/inventory.query.ts +2 -2
- package/core/src/schemas/queries/order.query.ts +9 -0
- package/core/src/schemas/queries/price.query.ts +2 -2
- package/core/src/schemas/queries/product.query.ts +9 -2
- package/core/src/schemas/queries/profile.query.ts +1 -1
- package/core/src/schemas/queries/search.query.ts +2 -2
- package/core/src/schemas/queries/store.query.ts +1 -1
- package/core/src/schemas/session.schema.ts +3 -3
- package/core/tsconfig.json +3 -2
- package/examples/next/next.config.js +17 -6
- package/examples/next/src/app/page.tsx +1 -2
- package/examples/node/package.json +2 -1
- package/examples/node/src/basic/basic-node-setup.spec.ts +1 -1
- package/examples/node/tsconfig.json +2 -1
- package/examples/node/tsconfig.spec.json +3 -2
- package/package.json +3 -1
- package/providers/algolia/package.json +2 -1
- package/providers/algolia/src/core/initialize.ts +5 -5
- package/providers/algolia/src/index.ts +5 -5
- package/providers/algolia/src/providers/product.provider.ts +8 -2
- package/providers/algolia/src/providers/search.provider.ts +1 -1
- package/providers/algolia/src/test/search.provider.spec.ts +1 -1
- package/providers/algolia/tsconfig.json +2 -1
- package/providers/algolia/tsconfig.spec.json +3 -2
- package/providers/commercetools/{jest.config.ts → jest.config.cjs} +1 -1
- package/providers/commercetools/package.json +3 -2
- package/providers/commercetools/src/core/client.ts +63 -32
- package/providers/commercetools/src/core/initialize.ts +20 -16
- package/providers/commercetools/src/index.ts +10 -10
- package/providers/commercetools/src/providers/cart.provider.ts +14 -19
- package/providers/commercetools/src/providers/category.provider.ts +3 -12
- package/providers/commercetools/src/providers/checkout.provider.ts +644 -0
- package/providers/commercetools/src/providers/identity.provider.ts +8 -8
- package/providers/commercetools/src/providers/index.ts +12 -9
- package/providers/commercetools/src/providers/inventory.provider.ts +2 -4
- package/providers/commercetools/src/providers/order.provider.ts +163 -0
- package/providers/commercetools/src/providers/price.provider.ts +3 -3
- package/providers/commercetools/src/providers/product.provider.ts +24 -6
- package/providers/commercetools/src/providers/profile.provider.ts +2 -2
- package/providers/commercetools/src/providers/search.provider.ts +3 -5
- package/providers/commercetools/src/providers/store.provider.ts +3 -3
- package/providers/commercetools/src/schema/capabilities.schema.ts +2 -1
- package/providers/commercetools/src/schema/commercetools.schema.ts +7 -5
- package/providers/commercetools/src/schema/configuration.schema.ts +2 -0
- package/providers/commercetools/src/test/cart.provider.spec.ts +24 -4
- package/providers/commercetools/src/test/category.provider.spec.ts +3 -3
- package/providers/commercetools/src/test/checkout.provider.spec.ts +312 -0
- package/providers/commercetools/src/test/identity.provider.spec.ts +3 -3
- package/providers/commercetools/src/test/inventory.provider.spec.ts +2 -2
- package/providers/commercetools/src/test/price.provider.spec.ts +4 -4
- package/providers/commercetools/src/test/product.provider.spec.ts +22 -5
- package/providers/commercetools/src/test/profile.provider.spec.ts +3 -3
- package/providers/commercetools/src/test/search.provider.spec.ts +2 -2
- package/providers/commercetools/src/test/store.provider.spec.ts +2 -2
- package/providers/commercetools/src/test/test-utils.ts +14 -0
- package/providers/commercetools/tsconfig.json +2 -1
- package/providers/commercetools/tsconfig.spec.json +4 -3
- package/providers/fake/{jest.config.ts → jest.config.cjs} +1 -1
- package/providers/fake/package.json +2 -2
- package/providers/fake/src/core/initialize.ts +6 -6
- package/providers/fake/src/index.ts +4 -4
- package/providers/fake/src/providers/analytics.provider.ts +1 -1
- package/providers/fake/src/providers/cart.provider.ts +2 -2
- package/providers/fake/src/providers/category.provider.ts +7 -3
- package/providers/fake/src/providers/identity.provider.ts +1 -1
- package/providers/fake/src/providers/index.ts +9 -9
- package/providers/fake/src/providers/inventory.provider.ts +1 -1
- package/providers/fake/src/providers/price.provider.ts +1 -1
- package/providers/fake/src/providers/product.provider.ts +10 -4
- package/providers/fake/src/providers/search.provider.ts +2 -5
- package/providers/fake/src/providers/store.provider.ts +2 -3
- package/providers/fake/src/test/cart.provider.spec.ts +3 -3
- package/providers/fake/src/test/category.provider.spec.ts +2 -2
- package/providers/fake/src/test/price.provider.spec.ts +2 -2
- package/providers/fake/src/test/product.provider.spec.ts +8 -8
- package/providers/fake/src/test/test-utils.ts +1 -1
- package/providers/fake/tsconfig.json +2 -1
- package/providers/fake/tsconfig.spec.json +1 -3
- package/providers/posthog/package.json +4 -4
- package/providers/posthog/project.json +2 -2
- package/providers/posthog/src/core/initialize.ts +2 -2
- package/providers/posthog/src/index.ts +3 -3
- package/providers/posthog/tsconfig.json +2 -1
- package/tsconfig.base.json +3 -4
- package/.claude/settings.local.json +0 -28
- package/core/src/providers/cart-payment.provider.ts +0 -57
- package/core/src/schemas/mutations/cart-payment.mutation.ts +0 -21
- package/core/src/schemas/queries/cart-payment.query.ts +0 -12
- package/otel/README.md +0 -227
- package/otel/eslint.config.mjs +0 -23
- package/otel/package.json +0 -11
- package/otel/pnpm-lock.yaml +0 -805
- package/otel/project.json +0 -33
- package/otel/src/index.ts +0 -22
- package/otel/src/metrics.ts +0 -76
- package/otel/src/provider-instrumentation.ts +0 -108
- package/otel/src/test/otel.spec.ts +0 -8
- package/otel/src/trace-decorator.ts +0 -226
- package/otel/src/tracer.ts +0 -83
- package/otel/src/trpc-middleware.ts +0 -128
- package/otel/tsconfig.json +0 -23
- package/otel/tsconfig.lib.json +0 -23
- package/otel/tsconfig.spec.json +0 -28
- package/otel/vite.config.ts +0 -24
- package/providers/commercetools/src/providers/cart-payment.provider.ts +0 -193
- package/providers/commercetools/src/test/cart-payment.provider.spec.ts +0 -145
- package/trpc/README.md +0 -7
- package/trpc/__mocks__/superjson.js +0 -25
- package/trpc/eslint.config.mjs +0 -19
- package/trpc/jest.config.ts +0 -14
- package/trpc/package.json +0 -14
- package/trpc/project.json +0 -31
- package/trpc/src/client.ts +0 -175
- package/trpc/src/index.ts +0 -44
- package/trpc/src/integration.spec.ts +0 -223
- package/trpc/src/server.ts +0 -125
- package/trpc/src/test-utils.ts +0 -31
- package/trpc/src/transparent-client.spec.ts +0 -162
- package/trpc/src/types.ts +0 -144
- package/trpc/tsconfig.json +0 -16
- package/trpc/tsconfig.lib.json +0 -10
- package/trpc/tsconfig.spec.json +0 -15
package/trpc/src/client.ts
DELETED
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
import type { Client, RequestContext} from '@reactionary/core';
|
|
2
|
-
import { Session } from '@reactionary/core';
|
|
3
|
-
import type { TransparentClient } from './types';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Configuration options for TRPC client creation
|
|
7
|
-
*/
|
|
8
|
-
export interface TRPCClientOptions {
|
|
9
|
-
/** Default session to use if not provided in method calls */
|
|
10
|
-
defaultRequestContext?: RequestContext
|
|
11
|
-
/** Whether to automatically provide request context from defaultRequestContext\ */
|
|
12
|
-
autoRequestContext?: boolean;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Create a type-safe client proxy that uses the original client's type interface
|
|
17
|
-
* while routing all calls through TRPC
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* ```typescript
|
|
21
|
-
* import { createTRPCProxyClient } from '@trpc/client';
|
|
22
|
-
* import { createTRPCClient } from '@reactionary/trpc/client';
|
|
23
|
-
*
|
|
24
|
-
* const trpc = createTRPCProxyClient<AppRouter>({
|
|
25
|
-
* url: 'http://localhost:3000',
|
|
26
|
-
* });
|
|
27
|
-
*
|
|
28
|
-
* // Pass the original client type as the generic parameter
|
|
29
|
-
* const client = createTRPCClient<typeof serverClient>(trpc, {
|
|
30
|
-
* defaultSession: mySession,
|
|
31
|
-
* autoSession: true
|
|
32
|
-
* });
|
|
33
|
-
*
|
|
34
|
-
* // Fully typed using the original client interface!
|
|
35
|
-
* const product = await client.product.getById({ id: '123' }, reqCtx);
|
|
36
|
-
* ```
|
|
37
|
-
*/
|
|
38
|
-
export function createTRPCClient<TOriginalClient extends Partial<Client>>(
|
|
39
|
-
trpcClient: any,
|
|
40
|
-
options: TRPCClientOptions = {}
|
|
41
|
-
): TransparentClient<TOriginalClient> {
|
|
42
|
-
const { defaultRequestContext, autoRequestContext = false } = options;
|
|
43
|
-
|
|
44
|
-
return new Proxy({} as TransparentClient<TOriginalClient>, {
|
|
45
|
-
get(target, providerName: string | symbol) {
|
|
46
|
-
if (typeof providerName !== 'string') {
|
|
47
|
-
return undefined;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Return a typed proxy for the provider that intercepts method calls
|
|
51
|
-
return new Proxy({}, {
|
|
52
|
-
get(providerTarget, methodName: string | symbol) {
|
|
53
|
-
if (typeof methodName !== 'string') {
|
|
54
|
-
return undefined;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Only expose methods that are marked with TRPC decorators
|
|
58
|
-
// This eliminates the need to filter TRPC-specific properties
|
|
59
|
-
return async (payload: any, reqCtxArg?: RequestContext) => {
|
|
60
|
-
// Determine request context to use
|
|
61
|
-
let reqCtx = reqCtxArg;
|
|
62
|
-
if (!reqCtx && autoRequestContext && defaultRequestContext) {
|
|
63
|
-
reqCtx = defaultRequestContext;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Prepare input for TRPC call
|
|
67
|
-
const input = {
|
|
68
|
-
payload,
|
|
69
|
-
reqCtx
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
// Access TRPC provider and method lazily
|
|
73
|
-
const trpcProvider = trpcClient[providerName];
|
|
74
|
-
const trpcMethod = trpcProvider[methodName];
|
|
75
|
-
|
|
76
|
-
// Use decorator metadata to determine if this is a query or mutation
|
|
77
|
-
// Note: We can't directly check the original provider here since we only have
|
|
78
|
-
// the TRPC client, so we'll fall back to the router's procedure type detection
|
|
79
|
-
if (trpcMethod?.query) {
|
|
80
|
-
return await trpcMethod.query(input);
|
|
81
|
-
} else if (trpcMethod?.mutate) {
|
|
82
|
-
return await trpcMethod.mutate(input);
|
|
83
|
-
} else {
|
|
84
|
-
throw new Error(`Method ${String(providerName)}.${String(methodName)} not found on TRPC client`);
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Session provider interface for dependency injection
|
|
95
|
-
*/
|
|
96
|
-
export interface SessionProvider {
|
|
97
|
-
getRequestContext(): Promise<RequestContext> | RequestContext;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Create a TRPC client with session provider for automatic session management
|
|
102
|
-
*
|
|
103
|
-
* @example
|
|
104
|
-
* ```typescript
|
|
105
|
-
* const sessionProvider: SessionProvider = {
|
|
106
|
-
* getSession: () => getCurrentUserSession()
|
|
107
|
-
* };
|
|
108
|
-
*
|
|
109
|
-
* const client = createTRPCClientWithSessionProvider(trpc, reqCtxProvider);
|
|
110
|
-
*
|
|
111
|
-
* // Session is automatically provided, fully typed
|
|
112
|
-
* const product = await client.product.getById({ id: '123' });
|
|
113
|
-
* ```
|
|
114
|
-
*/
|
|
115
|
-
export function createTRPCClientWithSessionProvider<TOriginalClient extends Partial<Client>>(
|
|
116
|
-
trpcClient: any,
|
|
117
|
-
sessionProvider: SessionProvider
|
|
118
|
-
): TransparentClient<TOriginalClient> {
|
|
119
|
-
return new Proxy({} as TransparentClient<TOriginalClient>, {
|
|
120
|
-
get(target, providerName: string | symbol) {
|
|
121
|
-
if (typeof providerName !== 'string') {
|
|
122
|
-
return undefined;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return new Proxy({}, {
|
|
126
|
-
get(providerTarget, methodName: string | symbol) {
|
|
127
|
-
if (typeof methodName !== 'string') {
|
|
128
|
-
return undefined;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return async (payload: any, reqCtxArg?: RequestContext) => {
|
|
132
|
-
// If no session provided, get from provider
|
|
133
|
-
let reqCtx = reqCtxArg;
|
|
134
|
-
if (!reqCtx) {
|
|
135
|
-
reqCtx = await sessionProvider.getRequestContext();
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
const input = {
|
|
139
|
-
payload,
|
|
140
|
-
reqCtx
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
// Access TRPC provider and method lazily
|
|
144
|
-
const trpcProvider = trpcClient[providerName];
|
|
145
|
-
const trpcMethod = trpcProvider[methodName];
|
|
146
|
-
|
|
147
|
-
// Use TRPC client's procedure type detection
|
|
148
|
-
if (trpcMethod?.query) {
|
|
149
|
-
return await trpcMethod.query(input);
|
|
150
|
-
} else if (trpcMethod?.mutate) {
|
|
151
|
-
return await trpcMethod.mutate(input);
|
|
152
|
-
} else {
|
|
153
|
-
throw new Error(`Method ${String(providerName)}.${String(methodName)} not found on TRPC client`);
|
|
154
|
-
}
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Type alias for creating typed TRPC clients
|
|
164
|
-
* Use the original client type, not the router type
|
|
165
|
-
*
|
|
166
|
-
* @example
|
|
167
|
-
* ```typescript
|
|
168
|
-
* type MyClient = typeof serverClient;
|
|
169
|
-
*
|
|
170
|
-
* function useClient(): MyClient {
|
|
171
|
-
* return createTRPCClient<MyClient>(trpcProxyClient);
|
|
172
|
-
* }
|
|
173
|
-
* ```
|
|
174
|
-
*/
|
|
175
|
-
export type TRPCClientFromRouter<TOriginalClient> = TOriginalClient;
|
package/trpc/src/index.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
// Re-export server utilities
|
|
2
|
-
export {
|
|
3
|
-
createTRPCServerRouter,
|
|
4
|
-
createTRPCContext,
|
|
5
|
-
router,
|
|
6
|
-
mergeRouters,
|
|
7
|
-
type TRPCRouterFromClient
|
|
8
|
-
} from './server';
|
|
9
|
-
|
|
10
|
-
// Re-export client utilities
|
|
11
|
-
export {
|
|
12
|
-
createTRPCClient,
|
|
13
|
-
createTRPCClientWithSessionProvider,
|
|
14
|
-
type TRPCClientOptions,
|
|
15
|
-
type SessionProvider,
|
|
16
|
-
type TRPCClientFromRouter
|
|
17
|
-
} from './client';
|
|
18
|
-
|
|
19
|
-
// Re-export type utilities
|
|
20
|
-
export {
|
|
21
|
-
type ClientMethodMap,
|
|
22
|
-
type MethodInfo,
|
|
23
|
-
type TRPCMethodInput,
|
|
24
|
-
type TransparentClient,
|
|
25
|
-
introspectClient,
|
|
26
|
-
isQueryMethod,
|
|
27
|
-
isMutationMethod
|
|
28
|
-
} from './types';
|
|
29
|
-
|
|
30
|
-
// Legacy exports for backward compatibility
|
|
31
|
-
import { initTRPC } from '@trpc/server';
|
|
32
|
-
import type { Client, RequestContext} from '@reactionary/core';
|
|
33
|
-
import { Session } from '@reactionary/core';
|
|
34
|
-
import { createTRPCTracing } from '@reactionary/otel';
|
|
35
|
-
|
|
36
|
-
const t = initTRPC.context<{ client: Client; reqCtx: RequestContext }>().create({});
|
|
37
|
-
|
|
38
|
-
// Always apply tracing middleware - exporters controlled via OTEL env vars
|
|
39
|
-
const basePublicProcedure = t.procedure;
|
|
40
|
-
export const publicProcedure = basePublicProcedure.use(createTRPCTracing());
|
|
41
|
-
|
|
42
|
-
// Legacy function - deprecated, use createTRPCServerRouter instead
|
|
43
|
-
import { createTRPCServerRouter } from './server';
|
|
44
|
-
export const createTRPCRouter = createTRPCServerRouter;
|
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
import { ClientBuilder, NoOpCache } from '@reactionary/core';
|
|
2
|
-
import { withFakeCapabilities } from '@reactionary/provider-fake';
|
|
3
|
-
import { createTRPCServerRouter, createTRPCContext } from './server';
|
|
4
|
-
import { createTRPCClient } from './client';
|
|
5
|
-
import type { TransparentClient } from './types';
|
|
6
|
-
import { createTRPCProxyClient, httpBatchLink } from '@trpc/client';
|
|
7
|
-
import { createHTTPHandler } from '@trpc/server/adapters/standalone';
|
|
8
|
-
import * as http from 'http';
|
|
9
|
-
import { createInitialRequestContext } from '@reactionary/core';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Integration test that actually starts an HTTP server and makes real network calls
|
|
13
|
-
* This is the real test that verifies the TRPC transparent transport works end-to-end
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
// Polyfill fetch for Node.js
|
|
17
|
-
global.fetch = global.fetch || require('node-fetch');
|
|
18
|
-
|
|
19
|
-
// Create the server-side client
|
|
20
|
-
const serverClient = new ClientBuilder()
|
|
21
|
-
.withCapability(
|
|
22
|
-
withFakeCapabilities(
|
|
23
|
-
{
|
|
24
|
-
jitter: {
|
|
25
|
-
mean: 0,
|
|
26
|
-
deviation: 0,
|
|
27
|
-
},
|
|
28
|
-
seeds: {
|
|
29
|
-
category: 1,
|
|
30
|
-
product: 1,
|
|
31
|
-
search: 1
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
{ search: true, product: true, identity: false }
|
|
35
|
-
)
|
|
36
|
-
)
|
|
37
|
-
.withCache(new NoOpCache())
|
|
38
|
-
.build();
|
|
39
|
-
|
|
40
|
-
// Create TRPC router from the client (do this at module level for type inference)
|
|
41
|
-
const router = createTRPCServerRouter(serverClient);
|
|
42
|
-
type AppRouter = typeof router;
|
|
43
|
-
|
|
44
|
-
xdescribe('TRPC Integration Test - Real HTTP Server', () => {
|
|
45
|
-
let server: http.Server;
|
|
46
|
-
let serverPort: number;
|
|
47
|
-
let trpcProxyClient: ReturnType<typeof createTRPCProxyClient<AppRouter>>;
|
|
48
|
-
let transparentClient: TransparentClient<typeof serverClient>;
|
|
49
|
-
|
|
50
|
-
beforeAll(async () => {
|
|
51
|
-
|
|
52
|
-
// Create TRPC HTTP handler
|
|
53
|
-
const handler = createHTTPHandler({
|
|
54
|
-
router,
|
|
55
|
-
createContext: createTRPCContext,
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
// Start HTTP server with TRPC handler
|
|
59
|
-
server = http.createServer(handler);
|
|
60
|
-
|
|
61
|
-
// Find available port
|
|
62
|
-
serverPort = 3001;
|
|
63
|
-
await new Promise<void>((resolve, reject) => {
|
|
64
|
-
const tryPort = (port: number) => {
|
|
65
|
-
server.listen(port, (err?: Error) => {
|
|
66
|
-
if (err) {
|
|
67
|
-
if (port < 3010) {
|
|
68
|
-
tryPort(port + 1);
|
|
69
|
-
} else {
|
|
70
|
-
reject(err);
|
|
71
|
-
}
|
|
72
|
-
} else {
|
|
73
|
-
serverPort = port;
|
|
74
|
-
resolve();
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
};
|
|
78
|
-
tryPort(serverPort);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
// Create real TRPC proxy client (no transformer for testing)
|
|
82
|
-
trpcProxyClient = createTRPCProxyClient<AppRouter>({
|
|
83
|
-
links: [
|
|
84
|
-
httpBatchLink({
|
|
85
|
-
url: `http://localhost:${serverPort}`,
|
|
86
|
-
}),
|
|
87
|
-
],
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
// Create transparent client using the real implementation - now properly typed!
|
|
91
|
-
transparentClient = createTRPCClient<typeof serverClient>(trpcProxyClient);
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
afterAll(async () => {
|
|
95
|
-
if (server) {
|
|
96
|
-
await new Promise<void>((resolve) => {
|
|
97
|
-
server.close(() => resolve());
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
const reqCtx = createInitialRequestContext();
|
|
103
|
-
|
|
104
|
-
describe('Product Provider via HTTP', () => {
|
|
105
|
-
it('should fetch product by slug through real HTTP calls', async () => {
|
|
106
|
-
const slug = 'integration-test-product';
|
|
107
|
-
|
|
108
|
-
// Get result from transparent client (through HTTP/TRPC)
|
|
109
|
-
const trpcResult = await transparentClient.product.getBySlug(
|
|
110
|
-
{ slug },
|
|
111
|
-
reqCtx
|
|
112
|
-
);
|
|
113
|
-
|
|
114
|
-
// Get result from server client (direct call)
|
|
115
|
-
const directResult = await serverClient.product.getBySlug(
|
|
116
|
-
{ slug },
|
|
117
|
-
reqCtx
|
|
118
|
-
);
|
|
119
|
-
|
|
120
|
-
// Results should have the same structure
|
|
121
|
-
expect(trpcResult).toBeDefined();
|
|
122
|
-
expect(trpcResult.slug).toBe(slug);
|
|
123
|
-
expect(trpcResult.name).toBeDefined();
|
|
124
|
-
expect(trpcResult.description).toBeDefined();
|
|
125
|
-
expect(trpcResult.image).toBeDefined();
|
|
126
|
-
|
|
127
|
-
// Both should have the same slug (faker uses seed for consistency)
|
|
128
|
-
expect(trpcResult.slug).toBe(directResult.slug);
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
it('should fetch product by id through real HTTP calls', async () => {
|
|
132
|
-
const productId = 'integration-test-id';
|
|
133
|
-
|
|
134
|
-
const trpcResult = await transparentClient.product.getById(
|
|
135
|
-
{ id: productId },
|
|
136
|
-
reqCtx
|
|
137
|
-
);
|
|
138
|
-
|
|
139
|
-
const directResult = await serverClient.product.getById(
|
|
140
|
-
{ id: productId },
|
|
141
|
-
reqCtx
|
|
142
|
-
);
|
|
143
|
-
|
|
144
|
-
expect(trpcResult).toBeDefined();
|
|
145
|
-
expect(trpcResult.identifier.key).toBe(productId);
|
|
146
|
-
expect(trpcResult.name).toBeDefined();
|
|
147
|
-
expect(trpcResult.description).toBeDefined();
|
|
148
|
-
|
|
149
|
-
// Should match direct call
|
|
150
|
-
expect(trpcResult.identifier?.key).toBe(directResult.identifier?.key);
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
describe('Search Provider via HTTP', () => {
|
|
155
|
-
it('should perform search through real HTTP calls', async () => {
|
|
156
|
-
const searchTerm = 'integration test search';
|
|
157
|
-
|
|
158
|
-
const trpcResult = await transparentClient.search.queryByTerm(
|
|
159
|
-
{
|
|
160
|
-
search: {
|
|
161
|
-
term: searchTerm,
|
|
162
|
-
page: 0,
|
|
163
|
-
pageSize: 10,
|
|
164
|
-
facets: []
|
|
165
|
-
}
|
|
166
|
-
},
|
|
167
|
-
reqCtx
|
|
168
|
-
);
|
|
169
|
-
|
|
170
|
-
const directResult = await serverClient.search.queryByTerm(
|
|
171
|
-
{
|
|
172
|
-
search: {
|
|
173
|
-
term: searchTerm,
|
|
174
|
-
page: 0,
|
|
175
|
-
pageSize: 10,
|
|
176
|
-
facets: []
|
|
177
|
-
}
|
|
178
|
-
},
|
|
179
|
-
reqCtx
|
|
180
|
-
);
|
|
181
|
-
|
|
182
|
-
expect(trpcResult).toBeDefined();
|
|
183
|
-
expect(trpcResult.products).toBeDefined();
|
|
184
|
-
expect(Array.isArray(trpcResult.products)).toBe(true);
|
|
185
|
-
expect(trpcResult.facets).toBeDefined();
|
|
186
|
-
|
|
187
|
-
// Should match direct call structure
|
|
188
|
-
expect(trpcResult.products.length).toBe(directResult.products.length);
|
|
189
|
-
});
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
describe('Network Error Handling', () => {
|
|
193
|
-
it('should handle HTTP errors gracefully', async () => {
|
|
194
|
-
// This should work normally first
|
|
195
|
-
const result = await transparentClient.product.getById(
|
|
196
|
-
{ id: 'test-error-handling' },
|
|
197
|
-
reqCtx
|
|
198
|
-
);
|
|
199
|
-
expect(result).toBeDefined();
|
|
200
|
-
});
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
describe('API Equivalence', () => {
|
|
204
|
-
it('should produce identical results for TRPC vs direct calls', async () => {
|
|
205
|
-
const testId = 'equivalence-test';
|
|
206
|
-
|
|
207
|
-
// Make same call through both paths
|
|
208
|
-
const [trpcResult, directResult] = await Promise.all([
|
|
209
|
-
transparentClient.product.getById(
|
|
210
|
-
{ id: testId },
|
|
211
|
-
reqCtx
|
|
212
|
-
),
|
|
213
|
-
serverClient.product.getById({ id: testId }, reqCtx)
|
|
214
|
-
]);
|
|
215
|
-
|
|
216
|
-
// Results should be structurally equivalent
|
|
217
|
-
expect(trpcResult.identifier.key).toBe(directResult.identifier.key);
|
|
218
|
-
expect(trpcResult.name).toBe(directResult.name);
|
|
219
|
-
expect(trpcResult.slug).toBe(directResult.slug);
|
|
220
|
-
expect(trpcResult.description).toBe(directResult.description);
|
|
221
|
-
});
|
|
222
|
-
});
|
|
223
|
-
});
|
package/trpc/src/server.ts
DELETED
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import { initTRPC } from '@trpc/server';
|
|
2
|
-
import type { Client, RequestContext, Session } from '@reactionary/core';
|
|
3
|
-
import superjson from 'superjson';
|
|
4
|
-
import { z } from 'zod';
|
|
5
|
-
import { createTRPCTracing } from '@reactionary/otel';
|
|
6
|
-
import type {
|
|
7
|
-
MethodInfo
|
|
8
|
-
} from './types';
|
|
9
|
-
import {
|
|
10
|
-
introspectClient
|
|
11
|
-
} from './types';
|
|
12
|
-
|
|
13
|
-
// Initialize TRPC with context containing session (no transformer for testing)
|
|
14
|
-
const t = initTRPC.context<{ reqCtx?: RequestContext }>().create();
|
|
15
|
-
|
|
16
|
-
export const router = t.router;
|
|
17
|
-
export const mergeRouters = t.mergeRouters;
|
|
18
|
-
|
|
19
|
-
// Apply tracing middleware
|
|
20
|
-
const baseProcedure = t.procedure.use(createTRPCTracing());
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Create a TRPC router from a built client instance
|
|
24
|
-
* This function introspects the client and automatically creates TRPC procedures
|
|
25
|
-
* for all provider methods while maintaining type safety
|
|
26
|
-
*
|
|
27
|
-
* @example
|
|
28
|
-
* ```typescript
|
|
29
|
-
* const client = buildClient([
|
|
30
|
-
* withFakeCapabilities(config, { product: true, search: true })
|
|
31
|
-
* ]);
|
|
32
|
-
*
|
|
33
|
-
* const router = createTRPCServerRouter(client);
|
|
34
|
-
* ```
|
|
35
|
-
*/
|
|
36
|
-
export function createTRPCServerRouter<T extends Partial<Client>>(client: T) {
|
|
37
|
-
const methods = introspectClient(client);
|
|
38
|
-
|
|
39
|
-
// Group methods by provider
|
|
40
|
-
const providerMethods = methods.reduce((acc, method) => {
|
|
41
|
-
if (!acc[method.providerName]) {
|
|
42
|
-
acc[method.providerName] = [];
|
|
43
|
-
}
|
|
44
|
-
acc[method.providerName].push(method);
|
|
45
|
-
return acc;
|
|
46
|
-
}, {} as Record<string, MethodInfo[]>);
|
|
47
|
-
|
|
48
|
-
// Build router structure
|
|
49
|
-
const routes: Record<string, any> = {};
|
|
50
|
-
|
|
51
|
-
for (const [providerName, providerMethodsList] of Object.entries(providerMethods)) {
|
|
52
|
-
const providerRoutes: Record<string, any> = {};
|
|
53
|
-
|
|
54
|
-
for (const methodInfo of providerMethodsList) {
|
|
55
|
-
const procedure = createProcedureForMethod(methodInfo);
|
|
56
|
-
providerRoutes[methodInfo.name] = procedure;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
routes[providerName] = t.router(providerRoutes);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return t.router(routes);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Create a TRPC procedure for a specific provider method
|
|
67
|
-
*/
|
|
68
|
-
function createProcedureForMethod(methodInfo: MethodInfo) {
|
|
69
|
-
// Create input schema - we use a flexible schema since we want to preserve
|
|
70
|
-
// the original method signatures without requiring schema definitions
|
|
71
|
-
const inputSchema = z.object({
|
|
72
|
-
payload: z.any(), // The actual payload from the provider method
|
|
73
|
-
reqCtx: z.any().optional(), // Session is optional in input since it might come from context
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
const procedureWithInput = baseProcedure.input(inputSchema);
|
|
77
|
-
|
|
78
|
-
if (methodInfo.isQuery) {
|
|
79
|
-
return procedureWithInput.query(async ({ input, ctx }) => {
|
|
80
|
-
const reqCtx = input.reqCtx || ctx.reqCtx;
|
|
81
|
-
|
|
82
|
-
// Call the original provider method
|
|
83
|
-
if (reqCtx) {
|
|
84
|
-
return await methodInfo.method(input.payload, reqCtx);
|
|
85
|
-
} else {
|
|
86
|
-
// Some methods might not require session
|
|
87
|
-
return await methodInfo.method(input.payload);
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
} else if (methodInfo.isMutation) {
|
|
91
|
-
return procedureWithInput.mutation(async ({ input, ctx }) => {
|
|
92
|
-
const reqCtx = input.reqCtx || ctx.reqCtx;
|
|
93
|
-
|
|
94
|
-
// Call the original provider method
|
|
95
|
-
if (reqCtx) {
|
|
96
|
-
return await methodInfo.method(input.payload, reqCtx);
|
|
97
|
-
} else {
|
|
98
|
-
// Some methods might not require session
|
|
99
|
-
return await methodInfo.method(input.payload);
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
} else {
|
|
103
|
-
throw new Error(`Method ${methodInfo.name} is neither query nor mutation`);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Type helper to extract the router type from a client
|
|
109
|
-
* This enables full type safety on the client side
|
|
110
|
-
*/
|
|
111
|
-
export type TRPCRouterFromClient<T extends Partial<Client>> = ReturnType<typeof createTRPCServerRouter<T>>;
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Context creator for TRPC server
|
|
115
|
-
* Override this to provide session from your authentication system
|
|
116
|
-
*/
|
|
117
|
-
export function createTRPCContext(_opts: { req?: any; res?: any }) {
|
|
118
|
-
// Default implementation - you should override this based on your auth system
|
|
119
|
-
return {
|
|
120
|
-
session: undefined as Session | undefined,
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Create publicProcedure here to avoid circular imports
|
|
125
|
-
export const publicProcedure = baseProcedure;
|
package/trpc/src/test-utils.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import type { Session } from '@reactionary/core';
|
|
2
|
-
|
|
3
|
-
export function createAnonymousTestSession(): Session {
|
|
4
|
-
return {
|
|
5
|
-
id: 'test-session-id',
|
|
6
|
-
identity: {
|
|
7
|
-
type: 'Anonymous',
|
|
8
|
-
meta: {
|
|
9
|
-
cache: { hit: false, key: '' },
|
|
10
|
-
placeholder: false,
|
|
11
|
-
},
|
|
12
|
-
id: { userId: 'anonymous' },
|
|
13
|
-
token: undefined,
|
|
14
|
-
issued: new Date(),
|
|
15
|
-
expiry: new Date(new Date().getTime() + 3600 * 1000),
|
|
16
|
-
logonId: "",
|
|
17
|
-
createdAt: "",
|
|
18
|
-
updatedAt: "",
|
|
19
|
-
keyring: [],
|
|
20
|
-
currentService: undefined
|
|
21
|
-
},
|
|
22
|
-
languageContext: {
|
|
23
|
-
locale: 'en-US',
|
|
24
|
-
currencyCode: 'USD',
|
|
25
|
-
countryCode: 'US',
|
|
26
|
-
},
|
|
27
|
-
storeIdentifier: {
|
|
28
|
-
key: 'the-good-store',
|
|
29
|
-
},
|
|
30
|
-
};
|
|
31
|
-
}
|