@reactionary/source 0.0.41 → 0.0.48
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/.claude/settings.local.json +28 -0
- package/.env-template +8 -5
- package/.vscode/settings.json +5 -0
- package/README.md +41 -0
- package/core/package.json +3 -1
- package/core/src/cache/cache.interface.ts +14 -18
- package/core/src/cache/memory-cache.ts +56 -0
- package/core/src/cache/noop-cache.ts +5 -23
- package/core/src/cache/redis-cache.ts +28 -38
- package/core/src/client/client-builder.ts +3 -3
- package/core/src/client/client.ts +11 -9
- package/core/src/decorators/reactionary.decorator.ts +80 -8
- package/core/src/index.ts +5 -29
- package/core/src/initialization.ts +43 -0
- package/core/src/providers/analytics.provider.ts +1 -1
- package/core/src/providers/base.provider.ts +61 -25
- package/core/src/providers/cart-payment.provider.ts +57 -0
- package/core/src/providers/cart.provider.ts +131 -8
- package/core/src/providers/category.provider.ts +9 -9
- package/core/src/providers/identity.provider.ts +8 -7
- package/core/src/providers/index.ts +12 -0
- package/core/src/providers/inventory.provider.ts +4 -4
- package/core/src/providers/price.provider.ts +7 -7
- package/core/src/providers/product.provider.ts +17 -5
- package/core/src/providers/profile.provider.ts +22 -0
- package/core/src/providers/search.provider.ts +4 -4
- package/core/src/providers/store.provider.ts +14 -0
- package/core/src/schemas/capabilities.schema.ts +3 -1
- package/core/src/schemas/models/analytics.model.ts +1 -1
- package/core/src/schemas/models/cart.model.ts +16 -3
- package/core/src/schemas/models/identifiers.model.ts +90 -22
- package/core/src/schemas/models/identity.model.ts +23 -7
- package/core/src/schemas/models/index.ts +15 -0
- package/core/src/schemas/models/payment.model.ts +41 -0
- package/core/src/schemas/models/profile.model.ts +35 -0
- package/core/src/schemas/models/shipping-method.model.ts +14 -0
- package/core/src/schemas/models/store.model.ts +11 -0
- package/core/src/schemas/mutations/cart-payment.mutation.ts +21 -0
- package/core/src/schemas/mutations/cart.mutation.ts +62 -3
- package/core/src/schemas/mutations/identity.mutation.ts +8 -1
- package/core/src/schemas/mutations/index.ts +10 -0
- package/core/src/schemas/mutations/profile.mutation.ts +9 -0
- package/core/src/schemas/queries/cart-payment.query.ts +12 -0
- package/core/src/schemas/queries/cart.query.ts +1 -1
- package/core/src/schemas/queries/identity.query.ts +1 -1
- package/core/src/schemas/queries/index.ts +3 -0
- package/core/src/schemas/queries/inventory.query.ts +4 -12
- package/core/src/schemas/queries/price.query.ts +1 -1
- package/core/src/schemas/queries/profile.query.ts +7 -0
- package/core/src/schemas/queries/search.query.ts +1 -1
- package/core/src/schemas/queries/store.query.ts +11 -0
- package/core/src/schemas/session.schema.ts +31 -6
- package/eslint.config.mjs +7 -0
- package/examples/next/src/app/page.tsx +4 -12
- package/examples/node/package.json +1 -3
- package/examples/node/src/basic/basic-node-provider-model-extension.spec.ts +9 -8
- package/examples/node/src/basic/basic-node-provider-query-extension.spec.ts +4 -3
- package/examples/node/src/basic/basic-node-setup.spec.ts +4 -5
- package/nx.json +1 -0
- package/otel/src/metrics.ts +2 -1
- package/otel/src/provider-instrumentation.ts +2 -1
- package/otel/src/tracer.ts +7 -6
- package/otel/src/trpc-middleware.ts +3 -2
- package/package.json +2 -1
- package/providers/algolia/src/core/initialize.ts +4 -3
- package/providers/algolia/src/providers/product.provider.ts +15 -13
- package/providers/algolia/src/providers/search.provider.ts +9 -9
- package/providers/algolia/src/schema/capabilities.schema.ts +1 -1
- package/providers/algolia/src/test/search.provider.spec.ts +10 -10
- package/providers/algolia/src/test/test-utils.ts +9 -4
- package/providers/commercetools/README.md +27 -0
- package/providers/commercetools/src/core/client.ts +164 -117
- package/providers/commercetools/src/core/initialize.ts +24 -14
- package/providers/commercetools/src/providers/cart-payment.provider.ts +193 -0
- package/providers/commercetools/src/providers/cart.provider.ts +402 -125
- package/providers/commercetools/src/providers/category.provider.ts +35 -35
- package/providers/commercetools/src/providers/identity.provider.ts +23 -75
- package/providers/commercetools/src/providers/index.ts +2 -0
- package/providers/commercetools/src/providers/inventory.provider.ts +69 -40
- package/providers/commercetools/src/providers/price.provider.ts +79 -47
- package/providers/commercetools/src/providers/product.provider.ts +36 -30
- package/providers/commercetools/src/providers/profile.provider.ts +61 -0
- package/providers/commercetools/src/providers/search.provider.ts +16 -12
- package/providers/commercetools/src/providers/store.provider.ts +78 -0
- package/providers/commercetools/src/schema/capabilities.schema.ts +3 -1
- package/providers/commercetools/src/schema/commercetools.schema.ts +18 -0
- package/providers/commercetools/src/schema/configuration.schema.ts +2 -1
- package/providers/commercetools/src/test/cart-payment.provider.spec.ts +145 -0
- package/providers/commercetools/src/test/cart.provider.spec.ts +82 -22
- package/providers/commercetools/src/test/category.provider.spec.ts +18 -17
- package/providers/commercetools/src/test/identity.provider.spec.ts +88 -0
- package/providers/commercetools/src/test/inventory.provider.spec.ts +41 -0
- package/providers/commercetools/src/test/price.provider.spec.ts +9 -8
- package/providers/commercetools/src/test/product.provider.spec.ts +33 -5
- package/providers/commercetools/src/test/profile.provider.spec.ts +49 -0
- package/providers/commercetools/src/test/search.provider.spec.ts +8 -7
- package/providers/commercetools/src/test/store.provider.spec.ts +37 -0
- package/providers/commercetools/src/test/test-utils.ts +7 -31
- package/providers/fake/src/core/initialize.ts +96 -38
- package/providers/fake/src/providers/analytics.provider.ts +6 -5
- package/providers/fake/src/providers/cart.provider.ts +66 -19
- package/providers/fake/src/providers/category.provider.ts +12 -12
- package/providers/fake/src/providers/identity.provider.ts +22 -14
- package/providers/fake/src/providers/index.ts +1 -0
- package/providers/fake/src/providers/inventory.provider.ts +13 -13
- package/providers/fake/src/providers/price.provider.ts +13 -13
- package/providers/fake/src/providers/product.provider.ts +13 -10
- package/providers/fake/src/providers/search.provider.ts +7 -5
- package/providers/fake/src/providers/store.provider.ts +47 -0
- package/providers/fake/src/schema/capabilities.schema.ts +4 -1
- package/providers/fake/src/test/cart.provider.spec.ts +18 -18
- package/providers/fake/src/test/category.provider.spec.ts +55 -37
- package/providers/fake/src/test/price.provider.spec.ts +9 -14
- package/providers/fake/src/test/product.provider.spec.ts +27 -0
- package/providers/fake/src/test/test-utils.ts +2 -28
- package/providers/posthog/src/core/initialize.ts +3 -3
- package/providers/posthog/src/schema/capabilities.schema.ts +1 -1
- package/trpc/src/client.ts +42 -41
- package/trpc/src/index.ts +4 -3
- package/trpc/src/integration.spec.ts +11 -11
- package/trpc/src/server.ts +26 -24
- package/trpc/src/test-utils.ts +9 -4
- package/trpc/src/types.ts +24 -22
- package/core/src/cache/cache-evaluation.interface.ts +0 -19
- package/examples/node/src/test-utils.ts +0 -26
package/trpc/src/client.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Client,
|
|
1
|
+
import type { Client, RequestContext} from '@reactionary/core';
|
|
2
|
+
import { Session } from '@reactionary/core';
|
|
2
3
|
import type { TransparentClient } from './types';
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -6,72 +7,72 @@ import type { TransparentClient } from './types';
|
|
|
6
7
|
*/
|
|
7
8
|
export interface TRPCClientOptions {
|
|
8
9
|
/** Default session to use if not provided in method calls */
|
|
9
|
-
|
|
10
|
-
/** Whether to automatically provide
|
|
11
|
-
|
|
10
|
+
defaultRequestContext?: RequestContext
|
|
11
|
+
/** Whether to automatically provide request context from defaultRequestContext\ */
|
|
12
|
+
autoRequestContext?: boolean;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Create a type-safe client proxy that uses the original client's type interface
|
|
16
17
|
* while routing all calls through TRPC
|
|
17
|
-
*
|
|
18
|
+
*
|
|
18
19
|
* @example
|
|
19
20
|
* ```typescript
|
|
20
21
|
* import { createTRPCProxyClient } from '@trpc/client';
|
|
21
22
|
* import { createTRPCClient } from '@reactionary/trpc/client';
|
|
22
|
-
*
|
|
23
|
+
*
|
|
23
24
|
* const trpc = createTRPCProxyClient<AppRouter>({
|
|
24
25
|
* url: 'http://localhost:3000',
|
|
25
26
|
* });
|
|
26
|
-
*
|
|
27
|
+
*
|
|
27
28
|
* // Pass the original client type as the generic parameter
|
|
28
29
|
* const client = createTRPCClient<typeof serverClient>(trpc, {
|
|
29
30
|
* defaultSession: mySession,
|
|
30
31
|
* autoSession: true
|
|
31
32
|
* });
|
|
32
|
-
*
|
|
33
|
+
*
|
|
33
34
|
* // Fully typed using the original client interface!
|
|
34
|
-
* const product = await client.product.getById({ id: '123' },
|
|
35
|
+
* const product = await client.product.getById({ id: '123' }, reqCtx);
|
|
35
36
|
* ```
|
|
36
37
|
*/
|
|
37
38
|
export function createTRPCClient<TOriginalClient extends Partial<Client>>(
|
|
38
39
|
trpcClient: any,
|
|
39
40
|
options: TRPCClientOptions = {}
|
|
40
41
|
): TransparentClient<TOriginalClient> {
|
|
41
|
-
const {
|
|
42
|
-
|
|
42
|
+
const { defaultRequestContext, autoRequestContext = false } = options;
|
|
43
|
+
|
|
43
44
|
return new Proxy({} as TransparentClient<TOriginalClient>, {
|
|
44
45
|
get(target, providerName: string | symbol) {
|
|
45
46
|
if (typeof providerName !== 'string') {
|
|
46
47
|
return undefined;
|
|
47
48
|
}
|
|
48
|
-
|
|
49
|
+
|
|
49
50
|
// Return a typed proxy for the provider that intercepts method calls
|
|
50
51
|
return new Proxy({}, {
|
|
51
52
|
get(providerTarget, methodName: string | symbol) {
|
|
52
53
|
if (typeof methodName !== 'string') {
|
|
53
54
|
return undefined;
|
|
54
55
|
}
|
|
55
|
-
|
|
56
|
+
|
|
56
57
|
// Only expose methods that are marked with TRPC decorators
|
|
57
58
|
// This eliminates the need to filter TRPC-specific properties
|
|
58
|
-
return async (payload: any,
|
|
59
|
-
// Determine
|
|
60
|
-
let
|
|
61
|
-
if (!
|
|
62
|
-
|
|
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;
|
|
63
64
|
}
|
|
64
|
-
|
|
65
|
+
|
|
65
66
|
// Prepare input for TRPC call
|
|
66
67
|
const input = {
|
|
67
68
|
payload,
|
|
68
|
-
|
|
69
|
+
reqCtx
|
|
69
70
|
};
|
|
70
|
-
|
|
71
|
-
// Access TRPC provider and method lazily
|
|
71
|
+
|
|
72
|
+
// Access TRPC provider and method lazily
|
|
72
73
|
const trpcProvider = trpcClient[providerName];
|
|
73
74
|
const trpcMethod = trpcProvider[methodName];
|
|
74
|
-
|
|
75
|
+
|
|
75
76
|
// Use decorator metadata to determine if this is a query or mutation
|
|
76
77
|
// Note: We can't directly check the original provider here since we only have
|
|
77
78
|
// the TRPC client, so we'll fall back to the router's procedure type detection
|
|
@@ -93,20 +94,20 @@ export function createTRPCClient<TOriginalClient extends Partial<Client>>(
|
|
|
93
94
|
* Session provider interface for dependency injection
|
|
94
95
|
*/
|
|
95
96
|
export interface SessionProvider {
|
|
96
|
-
|
|
97
|
+
getRequestContext(): Promise<RequestContext> | RequestContext;
|
|
97
98
|
}
|
|
98
99
|
|
|
99
100
|
/**
|
|
100
101
|
* Create a TRPC client with session provider for automatic session management
|
|
101
|
-
*
|
|
102
|
+
*
|
|
102
103
|
* @example
|
|
103
104
|
* ```typescript
|
|
104
105
|
* const sessionProvider: SessionProvider = {
|
|
105
106
|
* getSession: () => getCurrentUserSession()
|
|
106
107
|
* };
|
|
107
|
-
*
|
|
108
|
-
* const client = createTRPCClientWithSessionProvider(trpc,
|
|
109
|
-
*
|
|
108
|
+
*
|
|
109
|
+
* const client = createTRPCClientWithSessionProvider(trpc, reqCtxProvider);
|
|
110
|
+
*
|
|
110
111
|
* // Session is automatically provided, fully typed
|
|
111
112
|
* const product = await client.product.getById({ id: '123' });
|
|
112
113
|
* ```
|
|
@@ -120,29 +121,29 @@ export function createTRPCClientWithSessionProvider<TOriginalClient extends Part
|
|
|
120
121
|
if (typeof providerName !== 'string') {
|
|
121
122
|
return undefined;
|
|
122
123
|
}
|
|
123
|
-
|
|
124
|
+
|
|
124
125
|
return new Proxy({}, {
|
|
125
126
|
get(providerTarget, methodName: string | symbol) {
|
|
126
127
|
if (typeof methodName !== 'string') {
|
|
127
128
|
return undefined;
|
|
128
129
|
}
|
|
129
|
-
|
|
130
|
-
return async (payload: any,
|
|
130
|
+
|
|
131
|
+
return async (payload: any, reqCtxArg?: RequestContext) => {
|
|
131
132
|
// If no session provided, get from provider
|
|
132
|
-
let
|
|
133
|
-
if (!
|
|
134
|
-
|
|
133
|
+
let reqCtx = reqCtxArg;
|
|
134
|
+
if (!reqCtx) {
|
|
135
|
+
reqCtx = await sessionProvider.getRequestContext();
|
|
135
136
|
}
|
|
136
|
-
|
|
137
|
+
|
|
137
138
|
const input = {
|
|
138
139
|
payload,
|
|
139
|
-
|
|
140
|
+
reqCtx
|
|
140
141
|
};
|
|
141
|
-
|
|
142
|
+
|
|
142
143
|
// Access TRPC provider and method lazily
|
|
143
144
|
const trpcProvider = trpcClient[providerName];
|
|
144
145
|
const trpcMethod = trpcProvider[methodName];
|
|
145
|
-
|
|
146
|
+
|
|
146
147
|
// Use TRPC client's procedure type detection
|
|
147
148
|
if (trpcMethod?.query) {
|
|
148
149
|
return await trpcMethod.query(input);
|
|
@@ -161,14 +162,14 @@ export function createTRPCClientWithSessionProvider<TOriginalClient extends Part
|
|
|
161
162
|
/**
|
|
162
163
|
* Type alias for creating typed TRPC clients
|
|
163
164
|
* Use the original client type, not the router type
|
|
164
|
-
*
|
|
165
|
+
*
|
|
165
166
|
* @example
|
|
166
167
|
* ```typescript
|
|
167
168
|
* type MyClient = typeof serverClient;
|
|
168
|
-
*
|
|
169
|
+
*
|
|
169
170
|
* function useClient(): MyClient {
|
|
170
171
|
* return createTRPCClient<MyClient>(trpcProxyClient);
|
|
171
172
|
* }
|
|
172
173
|
* ```
|
|
173
174
|
*/
|
|
174
|
-
export type TRPCClientFromRouter<TOriginalClient> = TOriginalClient;
|
|
175
|
+
export type TRPCClientFromRouter<TOriginalClient> = TOriginalClient;
|
package/trpc/src/index.ts
CHANGED
|
@@ -7,7 +7,7 @@ export {
|
|
|
7
7
|
type TRPCRouterFromClient
|
|
8
8
|
} from './server';
|
|
9
9
|
|
|
10
|
-
// Re-export client utilities
|
|
10
|
+
// Re-export client utilities
|
|
11
11
|
export {
|
|
12
12
|
createTRPCClient,
|
|
13
13
|
createTRPCClientWithSessionProvider,
|
|
@@ -29,10 +29,11 @@ export {
|
|
|
29
29
|
|
|
30
30
|
// Legacy exports for backward compatibility
|
|
31
31
|
import { initTRPC } from '@trpc/server';
|
|
32
|
-
import { Client,
|
|
32
|
+
import type { Client, RequestContext} from '@reactionary/core';
|
|
33
|
+
import { Session } from '@reactionary/core';
|
|
33
34
|
import { createTRPCTracing } from '@reactionary/otel';
|
|
34
35
|
|
|
35
|
-
const t = initTRPC.context<{ client: Client;
|
|
36
|
+
const t = initTRPC.context<{ client: Client; reqCtx: RequestContext }>().create({});
|
|
36
37
|
|
|
37
38
|
// Always apply tracing middleware - exporters controlled via OTEL env vars
|
|
38
39
|
const basePublicProcedure = t.procedure;
|
|
@@ -6,7 +6,7 @@ import type { TransparentClient } from './types';
|
|
|
6
6
|
import { createTRPCProxyClient, httpBatchLink } from '@trpc/client';
|
|
7
7
|
import { createHTTPHandler } from '@trpc/server/adapters/standalone';
|
|
8
8
|
import * as http from 'http';
|
|
9
|
-
import {
|
|
9
|
+
import { createInitialRequestContext } from '@reactionary/core';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Integration test that actually starts an HTTP server and makes real network calls
|
|
@@ -99,7 +99,7 @@ xdescribe('TRPC Integration Test - Real HTTP Server', () => {
|
|
|
99
99
|
}
|
|
100
100
|
});
|
|
101
101
|
|
|
102
|
-
const
|
|
102
|
+
const reqCtx = createInitialRequestContext();
|
|
103
103
|
|
|
104
104
|
describe('Product Provider via HTTP', () => {
|
|
105
105
|
it('should fetch product by slug through real HTTP calls', async () => {
|
|
@@ -108,13 +108,13 @@ xdescribe('TRPC Integration Test - Real HTTP Server', () => {
|
|
|
108
108
|
// Get result from transparent client (through HTTP/TRPC)
|
|
109
109
|
const trpcResult = await transparentClient.product.getBySlug(
|
|
110
110
|
{ slug },
|
|
111
|
-
|
|
111
|
+
reqCtx
|
|
112
112
|
);
|
|
113
113
|
|
|
114
114
|
// Get result from server client (direct call)
|
|
115
115
|
const directResult = await serverClient.product.getBySlug(
|
|
116
116
|
{ slug },
|
|
117
|
-
|
|
117
|
+
reqCtx
|
|
118
118
|
);
|
|
119
119
|
|
|
120
120
|
// Results should have the same structure
|
|
@@ -133,12 +133,12 @@ xdescribe('TRPC Integration Test - Real HTTP Server', () => {
|
|
|
133
133
|
|
|
134
134
|
const trpcResult = await transparentClient.product.getById(
|
|
135
135
|
{ id: productId },
|
|
136
|
-
|
|
136
|
+
reqCtx
|
|
137
137
|
);
|
|
138
138
|
|
|
139
139
|
const directResult = await serverClient.product.getById(
|
|
140
140
|
{ id: productId },
|
|
141
|
-
|
|
141
|
+
reqCtx
|
|
142
142
|
);
|
|
143
143
|
|
|
144
144
|
expect(trpcResult).toBeDefined();
|
|
@@ -164,7 +164,7 @@ xdescribe('TRPC Integration Test - Real HTTP Server', () => {
|
|
|
164
164
|
facets: []
|
|
165
165
|
}
|
|
166
166
|
},
|
|
167
|
-
|
|
167
|
+
reqCtx
|
|
168
168
|
);
|
|
169
169
|
|
|
170
170
|
const directResult = await serverClient.search.queryByTerm(
|
|
@@ -176,7 +176,7 @@ xdescribe('TRPC Integration Test - Real HTTP Server', () => {
|
|
|
176
176
|
facets: []
|
|
177
177
|
}
|
|
178
178
|
},
|
|
179
|
-
|
|
179
|
+
reqCtx
|
|
180
180
|
);
|
|
181
181
|
|
|
182
182
|
expect(trpcResult).toBeDefined();
|
|
@@ -194,7 +194,7 @@ xdescribe('TRPC Integration Test - Real HTTP Server', () => {
|
|
|
194
194
|
// This should work normally first
|
|
195
195
|
const result = await transparentClient.product.getById(
|
|
196
196
|
{ id: 'test-error-handling' },
|
|
197
|
-
|
|
197
|
+
reqCtx
|
|
198
198
|
);
|
|
199
199
|
expect(result).toBeDefined();
|
|
200
200
|
});
|
|
@@ -208,9 +208,9 @@ xdescribe('TRPC Integration Test - Real HTTP Server', () => {
|
|
|
208
208
|
const [trpcResult, directResult] = await Promise.all([
|
|
209
209
|
transparentClient.product.getById(
|
|
210
210
|
{ id: testId },
|
|
211
|
-
|
|
211
|
+
reqCtx
|
|
212
212
|
),
|
|
213
|
-
serverClient.product.getById({ id: testId },
|
|
213
|
+
serverClient.product.getById({ id: testId }, reqCtx)
|
|
214
214
|
]);
|
|
215
215
|
|
|
216
216
|
// Results should be structurally equivalent
|
package/trpc/src/server.ts
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { initTRPC } from '@trpc/server';
|
|
2
|
-
import { Client, Session } from '@reactionary/core';
|
|
2
|
+
import type { Client, RequestContext, Session } from '@reactionary/core';
|
|
3
3
|
import superjson from 'superjson';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { createTRPCTracing } from '@reactionary/otel';
|
|
6
|
-
import {
|
|
7
|
-
introspectClient,
|
|
6
|
+
import type {
|
|
8
7
|
MethodInfo
|
|
9
8
|
} from './types';
|
|
9
|
+
import {
|
|
10
|
+
introspectClient
|
|
11
|
+
} from './types';
|
|
10
12
|
|
|
11
13
|
// Initialize TRPC with context containing session (no transformer for testing)
|
|
12
|
-
const t = initTRPC.context<{
|
|
14
|
+
const t = initTRPC.context<{ reqCtx?: RequestContext }>().create();
|
|
13
15
|
|
|
14
16
|
export const router = t.router;
|
|
15
17
|
export const mergeRouters = t.mergeRouters;
|
|
@@ -21,19 +23,19 @@ const baseProcedure = t.procedure.use(createTRPCTracing());
|
|
|
21
23
|
* Create a TRPC router from a built client instance
|
|
22
24
|
* This function introspects the client and automatically creates TRPC procedures
|
|
23
25
|
* for all provider methods while maintaining type safety
|
|
24
|
-
*
|
|
26
|
+
*
|
|
25
27
|
* @example
|
|
26
28
|
* ```typescript
|
|
27
29
|
* const client = buildClient([
|
|
28
30
|
* withFakeCapabilities(config, { product: true, search: true })
|
|
29
31
|
* ]);
|
|
30
|
-
*
|
|
32
|
+
*
|
|
31
33
|
* const router = createTRPCServerRouter(client);
|
|
32
34
|
* ```
|
|
33
35
|
*/
|
|
34
36
|
export function createTRPCServerRouter<T extends Partial<Client>>(client: T) {
|
|
35
37
|
const methods = introspectClient(client);
|
|
36
|
-
|
|
38
|
+
|
|
37
39
|
// Group methods by provider
|
|
38
40
|
const providerMethods = methods.reduce((acc, method) => {
|
|
39
41
|
if (!acc[method.providerName]) {
|
|
@@ -42,21 +44,21 @@ export function createTRPCServerRouter<T extends Partial<Client>>(client: T) {
|
|
|
42
44
|
acc[method.providerName].push(method);
|
|
43
45
|
return acc;
|
|
44
46
|
}, {} as Record<string, MethodInfo[]>);
|
|
45
|
-
|
|
47
|
+
|
|
46
48
|
// Build router structure
|
|
47
49
|
const routes: Record<string, any> = {};
|
|
48
|
-
|
|
50
|
+
|
|
49
51
|
for (const [providerName, providerMethodsList] of Object.entries(providerMethods)) {
|
|
50
52
|
const providerRoutes: Record<string, any> = {};
|
|
51
|
-
|
|
53
|
+
|
|
52
54
|
for (const methodInfo of providerMethodsList) {
|
|
53
55
|
const procedure = createProcedureForMethod(methodInfo);
|
|
54
56
|
providerRoutes[methodInfo.name] = procedure;
|
|
55
57
|
}
|
|
56
|
-
|
|
58
|
+
|
|
57
59
|
routes[providerName] = t.router(providerRoutes);
|
|
58
60
|
}
|
|
59
|
-
|
|
61
|
+
|
|
60
62
|
return t.router(routes);
|
|
61
63
|
}
|
|
62
64
|
|
|
@@ -68,18 +70,18 @@ function createProcedureForMethod(methodInfo: MethodInfo) {
|
|
|
68
70
|
// the original method signatures without requiring schema definitions
|
|
69
71
|
const inputSchema = z.object({
|
|
70
72
|
payload: z.any(), // The actual payload from the provider method
|
|
71
|
-
|
|
73
|
+
reqCtx: z.any().optional(), // Session is optional in input since it might come from context
|
|
72
74
|
});
|
|
73
|
-
|
|
75
|
+
|
|
74
76
|
const procedureWithInput = baseProcedure.input(inputSchema);
|
|
75
|
-
|
|
77
|
+
|
|
76
78
|
if (methodInfo.isQuery) {
|
|
77
79
|
return procedureWithInput.query(async ({ input, ctx }) => {
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
+
const reqCtx = input.reqCtx || ctx.reqCtx;
|
|
81
|
+
|
|
80
82
|
// Call the original provider method
|
|
81
|
-
if (
|
|
82
|
-
return await methodInfo.method(input.payload,
|
|
83
|
+
if (reqCtx) {
|
|
84
|
+
return await methodInfo.method(input.payload, reqCtx);
|
|
83
85
|
} else {
|
|
84
86
|
// Some methods might not require session
|
|
85
87
|
return await methodInfo.method(input.payload);
|
|
@@ -87,11 +89,11 @@ function createProcedureForMethod(methodInfo: MethodInfo) {
|
|
|
87
89
|
});
|
|
88
90
|
} else if (methodInfo.isMutation) {
|
|
89
91
|
return procedureWithInput.mutation(async ({ input, ctx }) => {
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
+
const reqCtx = input.reqCtx || ctx.reqCtx;
|
|
93
|
+
|
|
92
94
|
// Call the original provider method
|
|
93
|
-
if (
|
|
94
|
-
return await methodInfo.method(input.payload,
|
|
95
|
+
if (reqCtx) {
|
|
96
|
+
return await methodInfo.method(input.payload, reqCtx);
|
|
95
97
|
} else {
|
|
96
98
|
// Some methods might not require session
|
|
97
99
|
return await methodInfo.method(input.payload);
|
|
@@ -120,4 +122,4 @@ export function createTRPCContext(_opts: { req?: any; res?: any }) {
|
|
|
120
122
|
}
|
|
121
123
|
|
|
122
124
|
// Create publicProcedure here to avoid circular imports
|
|
123
|
-
export const publicProcedure = baseProcedure;
|
|
125
|
+
export const publicProcedure = baseProcedure;
|
package/trpc/src/test-utils.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Session } from '@reactionary/core';
|
|
1
|
+
import type { Session } from '@reactionary/core';
|
|
2
2
|
|
|
3
3
|
export function createAnonymousTestSession(): Session {
|
|
4
4
|
return {
|
|
@@ -9,10 +9,15 @@ export function createAnonymousTestSession(): Session {
|
|
|
9
9
|
cache: { hit: false, key: '' },
|
|
10
10
|
placeholder: false,
|
|
11
11
|
},
|
|
12
|
-
id: '',
|
|
12
|
+
id: { userId: 'anonymous' },
|
|
13
13
|
token: undefined,
|
|
14
14
|
issued: new Date(),
|
|
15
|
-
expiry: new Date(new Date().getTime() + 3600 * 1000),
|
|
15
|
+
expiry: new Date(new Date().getTime() + 3600 * 1000),
|
|
16
|
+
logonId: "",
|
|
17
|
+
createdAt: "",
|
|
18
|
+
updatedAt: "",
|
|
19
|
+
keyring: [],
|
|
20
|
+
currentService: undefined
|
|
16
21
|
},
|
|
17
22
|
languageContext: {
|
|
18
23
|
locale: 'en-US',
|
|
@@ -23,4 +28,4 @@ export function createAnonymousTestSession(): Session {
|
|
|
23
28
|
key: 'the-good-store',
|
|
24
29
|
},
|
|
25
30
|
};
|
|
26
|
-
}
|
|
31
|
+
}
|
package/trpc/src/types.ts
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
Session
|
|
1
|
+
import type {
|
|
2
|
+
Client,
|
|
3
|
+
RequestContext,
|
|
4
|
+
Session} from '@reactionary/core';
|
|
5
|
+
import {
|
|
6
|
+
BaseProvider
|
|
5
7
|
} from '@reactionary/core';
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
10
|
* Extract method names from a provider that match TRPC patterns
|
|
9
11
|
*/
|
|
10
|
-
export type ProviderMethods<T> = T extends BaseProvider
|
|
12
|
+
export type ProviderMethods<T> = T extends BaseProvider
|
|
11
13
|
? {
|
|
12
|
-
[K in keyof T]: T[K] extends (...args: any[]) => any
|
|
14
|
+
[K in keyof T]: T[K] extends (...args: any[]) => any
|
|
13
15
|
? K extends `get${string}` | `query${string}` | 'add' | 'remove' | 'changeQuantity' | 'login' | 'logout' | 'getSelf'
|
|
14
|
-
? K
|
|
16
|
+
? K
|
|
15
17
|
: never
|
|
16
18
|
: never
|
|
17
19
|
}[keyof T]
|
|
@@ -20,8 +22,8 @@ export type ProviderMethods<T> = T extends BaseProvider
|
|
|
20
22
|
/**
|
|
21
23
|
* Extract method signature from a provider method
|
|
22
24
|
*/
|
|
23
|
-
export type ProviderMethodSignature<T, K extends keyof T> =
|
|
24
|
-
T[K] extends (...args: infer Args) => infer Return
|
|
25
|
+
export type ProviderMethodSignature<T, K extends keyof T> =
|
|
26
|
+
T[K] extends (...args: infer Args) => infer Return
|
|
25
27
|
? (...args: Args) => Return
|
|
26
28
|
: never;
|
|
27
29
|
|
|
@@ -29,7 +31,7 @@ export type ProviderMethodSignature<T, K extends keyof T> =
|
|
|
29
31
|
* Map all methods of all providers in a client
|
|
30
32
|
*/
|
|
31
33
|
export type ClientMethodMap<T extends Partial<Client>> = {
|
|
32
|
-
[K in keyof T]: T[K] extends BaseProvider
|
|
34
|
+
[K in keyof T]: T[K] extends BaseProvider
|
|
33
35
|
? {
|
|
34
36
|
[M in ProviderMethods<T[K]>]: ProviderMethodSignature<T[K], M>
|
|
35
37
|
}
|
|
@@ -41,7 +43,7 @@ export type ClientMethodMap<T extends Partial<Client>> = {
|
|
|
41
43
|
* Create transparent client that only includes methods matching TRPC patterns
|
|
42
44
|
*/
|
|
43
45
|
export type TransparentClient<T extends Partial<Client>> = {
|
|
44
|
-
[K in keyof T]: T[K] extends BaseProvider
|
|
46
|
+
[K in keyof T]: T[K] extends BaseProvider
|
|
45
47
|
? {
|
|
46
48
|
[M in ProviderMethods<T[K]>]: ProviderMethodSignature<T[K], M>
|
|
47
49
|
}
|
|
@@ -64,7 +66,7 @@ export interface MethodInfo {
|
|
|
64
66
|
* Utility to determine if a method is a query or mutation based on naming convention
|
|
65
67
|
*/
|
|
66
68
|
export function isQueryMethod(methodName: string): boolean {
|
|
67
|
-
return methodName.startsWith('get') ||
|
|
69
|
+
return methodName.startsWith('get') ||
|
|
68
70
|
methodName.startsWith('query') ||
|
|
69
71
|
methodName === 'getSelf';
|
|
70
72
|
}
|
|
@@ -84,7 +86,7 @@ export function isMutationMethod(methodName: string): boolean {
|
|
|
84
86
|
*/
|
|
85
87
|
export function introspectClient<T extends Partial<Client>>(client: T): MethodInfo[] {
|
|
86
88
|
const methods: MethodInfo[] = [];
|
|
87
|
-
|
|
89
|
+
|
|
88
90
|
for (const [providerName, provider] of Object.entries(client)) {
|
|
89
91
|
if (provider instanceof BaseProvider) {
|
|
90
92
|
// Get all methods that match our naming patterns
|
|
@@ -104,7 +106,7 @@ export function introspectClient<T extends Partial<Client>>(client: T): MethodIn
|
|
|
104
106
|
}
|
|
105
107
|
}
|
|
106
108
|
}
|
|
107
|
-
|
|
109
|
+
|
|
108
110
|
return methods;
|
|
109
111
|
}
|
|
110
112
|
|
|
@@ -119,24 +121,24 @@ export interface TRPCMethodInput<TPayload = any> {
|
|
|
119
121
|
/**
|
|
120
122
|
* Helper to extract payload type from a provider method
|
|
121
123
|
*/
|
|
122
|
-
export type ExtractPayloadType<T> = T extends (payload: infer P,
|
|
123
|
-
? P
|
|
124
|
-
: T extends (payload: infer P) => any
|
|
124
|
+
export type ExtractPayloadType<T> = T extends (payload: infer P, reqCtx: RequestContext) => any
|
|
125
|
+
? P
|
|
126
|
+
: T extends (payload: infer P) => any
|
|
125
127
|
? P
|
|
126
128
|
: never;
|
|
127
129
|
|
|
128
130
|
/**
|
|
129
131
|
* Helper to extract return type from a provider method
|
|
130
132
|
*/
|
|
131
|
-
export type ExtractReturnType<T> = T extends (...args: any[]) => infer R
|
|
132
|
-
? R
|
|
133
|
+
export type ExtractReturnType<T> = T extends (...args: any[]) => infer R
|
|
134
|
+
? R
|
|
133
135
|
: never;
|
|
134
136
|
|
|
135
137
|
/**
|
|
136
138
|
* Create a TRPC-compatible method signature from a provider method
|
|
137
139
|
*/
|
|
138
|
-
export type TRPCMethodSignature<T> = T extends (payload: infer P,
|
|
140
|
+
export type TRPCMethodSignature<T> = T extends (payload: infer P, reqCtx: RequestContext) => infer R
|
|
139
141
|
? (input: TRPCMethodInput<P>) => R
|
|
140
142
|
: T extends (payload: infer P) => infer R
|
|
141
|
-
? (input: TRPCMethodInput<P>) => R
|
|
142
|
-
: never;
|
|
143
|
+
? (input: TRPCMethodInput<P>) => R
|
|
144
|
+
: never;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cache evaluation result that determines how and if a query should be cached
|
|
3
|
-
*/
|
|
4
|
-
export interface CacheEvaluation {
|
|
5
|
-
/**
|
|
6
|
-
* The cache key to use for storing/retrieving the value
|
|
7
|
-
*/
|
|
8
|
-
key: string;
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* How long to cache the value in seconds
|
|
12
|
-
*/
|
|
13
|
-
cacheDurationInSeconds: number;
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Whether this query result can be cached
|
|
17
|
-
*/
|
|
18
|
-
canCache: boolean;
|
|
19
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { 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: '',
|
|
13
|
-
token: undefined,
|
|
14
|
-
issued: new Date(),
|
|
15
|
-
expiry: new Date(new Date().getTime() + 3600 * 1000), // 1 hour from now
|
|
16
|
-
},
|
|
17
|
-
languageContext: {
|
|
18
|
-
locale: 'en-US',
|
|
19
|
-
currencyCode: 'USD',
|
|
20
|
-
countryCode: 'US',
|
|
21
|
-
},
|
|
22
|
-
storeIdentifier: {
|
|
23
|
-
key: 'the-good-store',
|
|
24
|
-
},
|
|
25
|
-
};
|
|
26
|
-
}
|