@aws-blocks/core 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +229 -0
- package/dist/client/index.d.ts +4 -4
- package/dist/client/index.d.ts.map +1 -1
- package/dist/scripts/extract-ts-types.js +4 -4
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/src/client/index.ts +7 -7
- package/src/scripts/extract-ts-types.ts +4 -4
- package/src/version.ts +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# @aws-blocks/core
|
|
2
|
+
|
|
3
|
+
Core primitives for building full-stack applications with the AWS Blocks.
|
|
4
|
+
|
|
5
|
+
## Key Exports
|
|
6
|
+
|
|
7
|
+
### Scope
|
|
8
|
+
|
|
9
|
+
Defines the boundary for your backend resources. The `Scope` class docstring serves as an index to all available Building Blocks.
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { Scope } from '@aws-blocks/core';
|
|
13
|
+
|
|
14
|
+
const scope = new Scope('my-app');
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### ApiNamespace
|
|
18
|
+
|
|
19
|
+
Define type-safe APIs with automatic frontend/backend integration.
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { ApiNamespace } from '@aws-blocks/core';
|
|
23
|
+
|
|
24
|
+
export const api = new ApiNamespace(scope, 'api', (context) => ({
|
|
25
|
+
async greet(name: string) {
|
|
26
|
+
return { message: `Hello, ${name}!` };
|
|
27
|
+
}
|
|
28
|
+
}));
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Frontend usage (fully typed):
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { api } from 'aws-blocks';
|
|
35
|
+
|
|
36
|
+
const result = await api.greet('World');
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
#### Authentication — every method is a public endpoint
|
|
40
|
+
|
|
41
|
+
Each method you define becomes a public, internet-reachable RPC endpoint. There is **no authentication by default** — a method is callable by anyone until you gate it. Auth is opt-in, per method, by calling an auth Building Block at the top of the handler:
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
export const api = new ApiNamespace(scope, 'api', (context) => ({
|
|
45
|
+
// PUBLIC — intentionally callable by anyone.
|
|
46
|
+
async listPublicPosts() {
|
|
47
|
+
return db.posts.findPublished();
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
// GATED — requireAuth throws a 401 before the body runs.
|
|
51
|
+
async createPost(input: NewPost) {
|
|
52
|
+
const user = await auth.requireAuth(context);
|
|
53
|
+
return db.posts.create({ ...input, authorId: user.userId });
|
|
54
|
+
},
|
|
55
|
+
}));
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The local mock applies no auth either, so an ungated method passes every local check and still ships callable by anyone. See your auth block's README (e.g. `@aws-blocks/bb-auth-cognito`) for `requireAuth` / `requireRole`.
|
|
59
|
+
|
|
60
|
+
#### Calling the API over HTTP (JSON-RPC 2.0)
|
|
61
|
+
|
|
62
|
+
The typed `import { api } from 'aws-blocks'` client is the normal path. The HTTP form below is for manual verification (curl/Postman) and non-JS clients.
|
|
63
|
+
|
|
64
|
+
`POST` to the RPC path `/aws-blocks/api`:
|
|
65
|
+
|
|
66
|
+
- Local dev: `http://localhost:3001/aws-blocks/api`
|
|
67
|
+
- Deployed: the API Gateway stage URL + `/aws-blocks/api`
|
|
68
|
+
|
|
69
|
+
The body is JSON-RPC 2.0:
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{ "jsonrpc": "2.0", "method": "<namespace>.<methodName>", "params": [...], "id": 1 }
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
- `method` is `<namespace>.<methodName>`, where `<namespace>` is the **export variable name** from `aws-blocks/index.ts` (e.g., `export const api = ...` → `api`).
|
|
76
|
+
- `params` is a POSITIONAL array of the method's arguments. A named object also works (its values are used in order).
|
|
77
|
+
- Errors come back as HTTP `200` with an `error` object in the body (per JSON-RPC), not as a non-2xx status.
|
|
78
|
+
|
|
79
|
+
Working example:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
curl -X POST http://localhost:3001/aws-blocks/api \
|
|
83
|
+
-H 'Content-Type: application/json' \
|
|
84
|
+
-d '{"jsonrpc":"2.0","method":"api.greet","params":["World"],"id":1}'
|
|
85
|
+
# → {"jsonrpc":"2.0","result":{"message":"Hello, World!"},"id":1}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### ApiError / isBlocksError
|
|
89
|
+
|
|
90
|
+
Typed error handling across the wire.
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
import { ApiError, isBlocksError } from '@aws-blocks/core';
|
|
94
|
+
|
|
95
|
+
// Throw with HTTP status and error name
|
|
96
|
+
throw new ApiError('Not found', 404, { name: 'ItemNotFoundException' });
|
|
97
|
+
|
|
98
|
+
// Catch with type narrowing
|
|
99
|
+
catch (e) {
|
|
100
|
+
if (isBlocksError(e, 'ItemNotFoundException')) { ... }
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### RawRoute
|
|
105
|
+
|
|
106
|
+
Path-based HTTP routing Building Block for endpoints that need full request/response control — webhooks, REST APIs, health checks, file downloads. Use `ApiNamespace` (RPC) for typed function calls; use `RawRoute` when you need raw HTTP semantics.
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
import { RawRoute } from '@aws-blocks/blocks';
|
|
110
|
+
|
|
111
|
+
// Explicit path
|
|
112
|
+
new RawRoute(scope, 'GetUser', {
|
|
113
|
+
method: 'GET',
|
|
114
|
+
path: '/users/{id}',
|
|
115
|
+
handler: async (context) => {
|
|
116
|
+
const userId = context.request.params.id;
|
|
117
|
+
context.response.send({ id: userId });
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// Derived path — path omitted, becomes /health from scope chain
|
|
122
|
+
new RawRoute(scope, 'health', { method: 'GET', handler: async (ctx) => {
|
|
123
|
+
ctx.response.send({ status: 'ok' });
|
|
124
|
+
}});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Supports exact paths (`/health`), named parameters (`/users/{id}`), and wildcards (`/files/*`). Path can be omitted — it's derived from scope-chain IDs.
|
|
128
|
+
|
|
129
|
+
📖 **Full RawRoute documentation (see source repo)**
|
|
130
|
+
|
|
131
|
+
### Pipeline
|
|
132
|
+
|
|
133
|
+
CDK Pipelines-based CI/CD construct for multi-branch, multi-stage deployments. Creates self-mutating CodePipeline V2 instances with GitHub source via CodeConnections (OAuth).
|
|
134
|
+
|
|
135
|
+
📖 **Full Pipeline documentation (see source repo)**
|
|
136
|
+
|
|
137
|
+
### Hosting
|
|
138
|
+
|
|
139
|
+
CDK construct (from the `/cdk` entry point) that deploys a frontend on CloudFront + S3, with a single-origin API proxy when a backend stack is provided.
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
import { Hosting } from '@aws-blocks/core/cdk';
|
|
143
|
+
|
|
144
|
+
new Hosting(stack, 'Web', {
|
|
145
|
+
root: join(__dirname, '..'),
|
|
146
|
+
buildCommand: 'npm run build',
|
|
147
|
+
api: blocksStack,
|
|
148
|
+
});
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
The `framework` option selects the frontend type: `'spa' | 'static' | 'nextjs'`. When omitted, the framework is auto-detected by reading your app's OWN `package.json` (not `node_modules`): a `next` dependency → `nextjs`; otherwise `spa`; and `static` when there is no `package.json`. Set `framework: 'spa'` explicitly to override auto-detection — e.g. when a stray `next` dependency would otherwise trigger an unwanted Next.js/OpenNext build. Full reference lives in the source JSDoc.
|
|
152
|
+
|
|
153
|
+
## Building Blocks
|
|
154
|
+
|
|
155
|
+
Import Building Blocks from their specific packages (or from the `@aws-blocks/blocks` umbrella):
|
|
156
|
+
|
|
157
|
+
- `@aws-blocks/bb-kv-store` — Key-value storage
|
|
158
|
+
- `@aws-blocks/bb-distributed-table` — Tables with Zod schemas and indexes
|
|
159
|
+
- `@aws-blocks/auth-common` — Auth interfaces and Authenticator component
|
|
160
|
+
- `@aws-blocks/bb-auth-basic` — Username/password authentication
|
|
161
|
+
- `@aws-blocks/bb-data` — SQL database
|
|
162
|
+
- `@aws-blocks/bb-realtime` — Real-time pub/sub
|
|
163
|
+
|
|
164
|
+
### withAuth (SSR cookie forwarding)
|
|
165
|
+
|
|
166
|
+
Lives in the `@aws-blocks/core/server` entry point (also re-exported as `@aws-blocks/blocks/server`). During SSR (server components / loaders) the browser's cookies aren't automatically attached to AWS Blocks API calls — `withAuth` reads them and forwards them to every AWS Blocks API call made inside the callback.
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
import { withAuth } from '@aws-blocks/blocks/server';
|
|
170
|
+
|
|
171
|
+
// Auto-detects cookies (Next.js detection is built in)
|
|
172
|
+
const posts = await withAuth(() => api.listMyPosts());
|
|
173
|
+
|
|
174
|
+
// Other frameworks: pass cookies explicitly as the 2nd arg…
|
|
175
|
+
const posts = await withAuth(() => api.listMyPosts(), request.headers.get('cookie'));
|
|
176
|
+
// …or register a provider once via registerCookieProvider.
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**Note:** `withAuth` throws a `401` `ApiError` when no cookies are found. Full reference lives in the source JSDoc.
|
|
180
|
+
|
|
181
|
+
## Local Development
|
|
182
|
+
|
|
183
|
+
In local dev mode, Building Blocks use mock implementations. No AWS resources needed.
|
|
184
|
+
|
|
185
|
+
## CORS Configuration
|
|
186
|
+
|
|
187
|
+
By default, the Lambda handler does **not** set any `Access-Control-Allow-Origin` header. CORS behavior is controlled entirely by the `CORS_ALLOWED_ORIGINS` environment variable.
|
|
188
|
+
|
|
189
|
+
### When using Hosting (recommended)
|
|
190
|
+
|
|
191
|
+
If you use the `Hosting` construct with your API, CORS is handled automatically:
|
|
192
|
+
|
|
193
|
+
- **Same-origin requests** (frontend fetches through the CloudFront proxy at `/aws-blocks/api`) work without CORS headers since the browser treats them as same-origin.
|
|
194
|
+
- **Cross-origin requests** (e.g. direct API Gateway calls) are also covered: when you pass a `BlocksStack` or `BlocksBackend` as the `api` prop, the Hosting construct automatically adds the CloudFront distribution's domain to `CORS_ALLOWED_ORIGINS` on the backend Lambda. You do **not** need to configure CORS manually.
|
|
195
|
+
|
|
196
|
+
In sandbox mode, the localhost pattern is also preserved so your local dev frontend still works.
|
|
197
|
+
|
|
198
|
+
### Local development (`npm run dev`)
|
|
199
|
+
|
|
200
|
+
The dev server automatically allows `localhost` / `127.0.0.1` origins. No configuration needed.
|
|
201
|
+
|
|
202
|
+
### Sandbox deployments
|
|
203
|
+
|
|
204
|
+
The sandbox CLI automatically sets `CORS_ALLOWED_ORIGINS=^https?://(localhost|127\.0\.0\.1)(:\d+)?$` so your local frontend can reach the deployed sandbox API.
|
|
205
|
+
|
|
206
|
+
### Production (frontend hosted separately)
|
|
207
|
+
|
|
208
|
+
If your frontend is hosted on a different domain (e.g., Vercel, Netlify), set the `CORS_ALLOWED_ORIGINS` environment variable on your Lambda:
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
// aws-blocks/index.cdk.ts
|
|
212
|
+
blocksStack.handler.addEnvironment(
|
|
213
|
+
'CORS_ALLOWED_ORIGINS',
|
|
214
|
+
'https://myapp\\.com,https://staging\\.myapp\\.com'
|
|
215
|
+
);
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Each entry is treated as a **regex pattern** (anchored with `^` and `$`). Examples:
|
|
219
|
+
|
|
220
|
+
| Pattern | Matches |
|
|
221
|
+
|---------|---------|
|
|
222
|
+
| `https://myapp\\.com` | Exact match for `https://myapp.com` |
|
|
223
|
+
| `https://.*\\.myapp\\.com` | Any subdomain of `myapp.com` |
|
|
224
|
+
| `^https?://(localhost\|127\\.0\\.0\\.1)(:\\d+)?$` | Localhost/127.0.0.1, any port, http or https (sandbox) |
|
|
225
|
+
| `.*` | All origins (escape hatch — use with caution) |
|
|
226
|
+
|
|
227
|
+
Multiple patterns are comma-separated. If a pattern is invalid regex, it falls back to literal string match.
|
|
228
|
+
|
|
229
|
+
If an origin doesn't match any pattern, the handler omits the `Access-Control-Allow-Origin` header (browser blocks the response) and logs a `[CORS]` warning to CloudWatch.
|
package/dist/client/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ type AsyncAPI<T extends Record<string, (...args: any[]) => any>> = {
|
|
|
8
8
|
* Middleware can inspect or modify any of these properties before the
|
|
9
9
|
* request is dispatched to the server.
|
|
10
10
|
*/
|
|
11
|
-
export interface
|
|
11
|
+
export interface BlocksRequest {
|
|
12
12
|
/** The namespace name this call targets (e.g., 'api', 'auth'). Corresponds to the second argument of `new ApiNamespace(scope, name, handler)` in the backend. */
|
|
13
13
|
apiNamespace: string;
|
|
14
14
|
/** The method being called on the namespace (e.g., 'getUser', 'kvSet'). */
|
|
@@ -39,9 +39,9 @@ export interface KitRequest {
|
|
|
39
39
|
* });
|
|
40
40
|
* ```
|
|
41
41
|
*/
|
|
42
|
-
export interface
|
|
42
|
+
export interface BlocksMiddleware {
|
|
43
43
|
/** Transform the request before it's sent. Modify the request in place or return a new one. Can be async. */
|
|
44
|
-
onRequest?: (request:
|
|
44
|
+
onRequest?: (request: BlocksRequest) => BlocksRequest | void | Promise<BlocksRequest | void>;
|
|
45
45
|
/** Transform the response data after it's received. Used to hydrate __blocks descriptors. */
|
|
46
46
|
onResponse?: (data: unknown) => unknown;
|
|
47
47
|
}
|
|
@@ -64,7 +64,7 @@ export interface KitMiddleware {
|
|
|
64
64
|
* an explicit `attach(server)` pattern because they need the HTTP server
|
|
65
65
|
* instance passed to them — something unavailable at import time.
|
|
66
66
|
*/
|
|
67
|
-
export declare function registerMiddleware(middleware:
|
|
67
|
+
export declare function registerMiddleware(middleware: BlocksMiddleware): void;
|
|
68
68
|
/**
|
|
69
69
|
* Options for `ApiNamespaceClient`.
|
|
70
70
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,aAAa,GAAG,GAAG,CAAC;AAChC,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,IAAI,GAAG,CAAC;AAiBhF,KAAK,QAAQ,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,IAAI;KAChE,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,MAAM,IAAI,KAAK,MAAM,CAAC,GACzD,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GACtC,KAAK;CACV,CAAC;AAoHF;;;;GAIG;AACH,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,aAAa,GAAG,GAAG,CAAC;AAChC,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,IAAI,GAAG,CAAC;AAiBhF,KAAK,QAAQ,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,IAAI;KAChE,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,MAAM,IAAI,KAAK,MAAM,CAAC,GACzD,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GACtC,KAAK;CACV,CAAC;AAoHF;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,iKAAiK;IACjK,YAAY,EAAE,MAAM,CAAC;IACrB,2EAA2E;IAC3E,MAAM,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,wHAAwH;IACxH,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,gBAAgB;IAC/B,6GAA6G;IAC7G,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,aAAa,GAAG,IAAI,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IAC7F,6FAA6F;IAC7F,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC;CACzC;AAID;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAErE;AAqBD;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,8EAA8E;IAC9E,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,EAClF,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,yBAAyB,GAClC,QAAQ,CAAC,CAAC,CAAC,CAyDb;AAED,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,KAAK,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -20,7 +20,7 @@ import { existsSync } from 'fs';
|
|
|
20
20
|
* JSDoc parsers.
|
|
21
21
|
*/
|
|
22
22
|
export const BLOCKS_SKIP_CODEGEN_TAG = 'blocksSkipCodegen';
|
|
23
|
-
function
|
|
23
|
+
function hasBlocksSkipCodegenTag(node) {
|
|
24
24
|
for (const tag of ts.getJSDocTags(node)) {
|
|
25
25
|
if (tag.tagName.text === BLOCKS_SKIP_CODEGEN_TAG)
|
|
26
26
|
return true;
|
|
@@ -51,7 +51,7 @@ export function extractSkipCodegenMethods(sourcePath) {
|
|
|
51
51
|
if (ts.isMethodDeclaration(prop) &&
|
|
52
52
|
prop.name &&
|
|
53
53
|
ts.isIdentifier(prop.name) &&
|
|
54
|
-
|
|
54
|
+
hasBlocksSkipCodegenTag(prop)) {
|
|
55
55
|
result.add(prop.name.text);
|
|
56
56
|
}
|
|
57
57
|
}
|
|
@@ -253,7 +253,7 @@ function extractMethodTypeInfo(method, checker, sourceFile) {
|
|
|
253
253
|
transferable = detectTransferable(retType, checker, retTypeNode);
|
|
254
254
|
returnType = tsTypeToJsonSchema(retType, checker);
|
|
255
255
|
}
|
|
256
|
-
const skipCodegen =
|
|
256
|
+
const skipCodegen = hasBlocksSkipCodegenTag(method) || undefined;
|
|
257
257
|
return { params, returnType, transferable, skipCodegen };
|
|
258
258
|
}
|
|
259
259
|
/**
|
|
@@ -343,7 +343,7 @@ function extractMethodsFromResolvedType(type, checker, result) {
|
|
|
343
343
|
// the BB-helper file that minted the AsyncAPI<T> shape).
|
|
344
344
|
let skipCodegen;
|
|
345
345
|
const declaration = prop.valueDeclaration;
|
|
346
|
-
if (declaration &&
|
|
346
|
+
if (declaration && hasBlocksSkipCodegenTag(declaration)) {
|
|
347
347
|
skipCodegen = true;
|
|
348
348
|
}
|
|
349
349
|
result.set(propName, { params, returnType, transferable, skipCodegen });
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const CORE_VERSION = "0.1.
|
|
1
|
+
export declare const CORE_VERSION = "0.1.1";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Auto-generated by scripts/generate-version.mjs — do not edit manually
|
|
2
|
-
export const CORE_VERSION = '0.1.
|
|
2
|
+
export const CORE_VERSION = '0.1.1';
|
package/package.json
CHANGED
package/src/client/index.ts
CHANGED
|
@@ -144,7 +144,7 @@ async function resolveApiUrl(): Promise<string> {
|
|
|
144
144
|
* Middleware can inspect or modify any of these properties before the
|
|
145
145
|
* request is dispatched to the server.
|
|
146
146
|
*/
|
|
147
|
-
export interface
|
|
147
|
+
export interface BlocksRequest {
|
|
148
148
|
/** The namespace name this call targets (e.g., 'api', 'auth'). Corresponds to the second argument of `new ApiNamespace(scope, name, handler)` in the backend. */
|
|
149
149
|
apiNamespace: string;
|
|
150
150
|
/** The method being called on the namespace (e.g., 'getUser', 'kvSet'). */
|
|
@@ -176,14 +176,14 @@ export interface KitRequest {
|
|
|
176
176
|
* });
|
|
177
177
|
* ```
|
|
178
178
|
*/
|
|
179
|
-
export interface
|
|
179
|
+
export interface BlocksMiddleware {
|
|
180
180
|
/** Transform the request before it's sent. Modify the request in place or return a new one. Can be async. */
|
|
181
|
-
onRequest?: (request:
|
|
181
|
+
onRequest?: (request: BlocksRequest) => BlocksRequest | void | Promise<BlocksRequest | void>;
|
|
182
182
|
/** Transform the response data after it's received. Used to hydrate __blocks descriptors. */
|
|
183
183
|
onResponse?: (data: unknown) => unknown;
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
-
const middlewares:
|
|
186
|
+
const middlewares: BlocksMiddleware[] = [];
|
|
187
187
|
|
|
188
188
|
/**
|
|
189
189
|
* Register client middleware for request/response processing.
|
|
@@ -204,11 +204,11 @@ const middlewares: KitMiddleware[] = [];
|
|
|
204
204
|
* an explicit `attach(server)` pattern because they need the HTTP server
|
|
205
205
|
* instance passed to them — something unavailable at import time.
|
|
206
206
|
*/
|
|
207
|
-
export function registerMiddleware(middleware:
|
|
207
|
+
export function registerMiddleware(middleware: BlocksMiddleware): void {
|
|
208
208
|
middlewares.push(middleware);
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
async function processRequest(request:
|
|
211
|
+
async function processRequest(request: BlocksRequest): Promise<BlocksRequest> {
|
|
212
212
|
for (const mw of middlewares) {
|
|
213
213
|
if (mw.onRequest) {
|
|
214
214
|
const result = await mw.onRequest(request);
|
|
@@ -265,7 +265,7 @@ export function ApiNamespaceClient<T extends Record<string, (...args: any[]) =>
|
|
|
265
265
|
return async (...args: any[]) => {
|
|
266
266
|
const apiUrl = urlOverride ?? await getApiUrl();
|
|
267
267
|
|
|
268
|
-
let request:
|
|
268
|
+
let request: BlocksRequest = {
|
|
269
269
|
apiNamespace: name,
|
|
270
270
|
method,
|
|
271
271
|
args,
|
|
@@ -48,7 +48,7 @@ export interface MethodTypeInfo {
|
|
|
48
48
|
*/
|
|
49
49
|
export const BLOCKS_SKIP_CODEGEN_TAG = 'blocksSkipCodegen';
|
|
50
50
|
|
|
51
|
-
function
|
|
51
|
+
function hasBlocksSkipCodegenTag(node: ts.Node): boolean {
|
|
52
52
|
for (const tag of ts.getJSDocTags(node)) {
|
|
53
53
|
if (tag.tagName.text === BLOCKS_SKIP_CODEGEN_TAG) return true;
|
|
54
54
|
}
|
|
@@ -86,7 +86,7 @@ export function extractSkipCodegenMethods(sourcePath: string): Set<string> {
|
|
|
86
86
|
ts.isMethodDeclaration(prop) &&
|
|
87
87
|
prop.name &&
|
|
88
88
|
ts.isIdentifier(prop.name) &&
|
|
89
|
-
|
|
89
|
+
hasBlocksSkipCodegenTag(prop)
|
|
90
90
|
) {
|
|
91
91
|
result.add(prop.name.text);
|
|
92
92
|
}
|
|
@@ -328,7 +328,7 @@ function extractMethodTypeInfo(
|
|
|
328
328
|
returnType = tsTypeToJsonSchema(retType, checker);
|
|
329
329
|
}
|
|
330
330
|
|
|
331
|
-
const skipCodegen =
|
|
331
|
+
const skipCodegen = hasBlocksSkipCodegenTag(method) || undefined;
|
|
332
332
|
return { params, returnType, transferable, skipCodegen };
|
|
333
333
|
}
|
|
334
334
|
|
|
@@ -429,7 +429,7 @@ function extractMethodsFromResolvedType(
|
|
|
429
429
|
// the BB-helper file that minted the AsyncAPI<T> shape).
|
|
430
430
|
let skipCodegen: true | undefined;
|
|
431
431
|
const declaration = prop.valueDeclaration;
|
|
432
|
-
if (declaration &&
|
|
432
|
+
if (declaration && hasBlocksSkipCodegenTag(declaration)) {
|
|
433
433
|
skipCodegen = true;
|
|
434
434
|
}
|
|
435
435
|
|
package/src/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Auto-generated by scripts/generate-version.mjs — do not edit manually
|
|
2
|
-
export const CORE_VERSION = '0.1.
|
|
2
|
+
export const CORE_VERSION = '0.1.1';
|