@spfn/core 0.2.0-beta.9 → 0.3.0-beta.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/LICENSE +1 -1
- package/README.md +444 -305
- package/dist/authz/index.d.ts +34 -0
- package/dist/authz/index.js +810 -0
- package/dist/authz/index.js.map +1 -0
- package/dist/{boss-DI1r4kTS.d.ts → boss-D16fO2oG.d.ts} +41 -1
- package/dist/cache/index.js +42 -30
- package/dist/cache/index.js.map +1 -1
- package/dist/codegen/index.d.ts +121 -13
- package/dist/codegen/index.js +212 -15
- package/dist/codegen/index.js.map +1 -1
- package/dist/config/index.d.ts +615 -6
- package/dist/config/index.js +124 -5
- package/dist/config/index.js.map +1 -1
- package/dist/contract/index.d.ts +220 -0
- package/dist/contract/index.js +558 -0
- package/dist/contract/index.js.map +1 -0
- package/dist/db/index.d.ts +528 -85
- package/dist/db/index.js +831 -122
- package/dist/db/index.js.map +1 -1
- package/dist/define-middleware-DfDP39Nq.d.ts +167 -0
- package/dist/env/index.d.ts +26 -2
- package/dist/env/index.js +15 -5
- package/dist/env/index.js.map +1 -1
- package/dist/env/loader.d.ts +26 -19
- package/dist/env/loader.js +32 -25
- package/dist/env/loader.js.map +1 -1
- package/dist/errors/index.d.ts +10 -0
- package/dist/errors/index.js +418 -5
- package/dist/errors/index.js.map +1 -1
- package/dist/event/index.d.ts +33 -3
- package/dist/event/index.js +24 -3
- package/dist/event/index.js.map +1 -1
- package/dist/event/sse/client.d.ts +42 -3
- package/dist/event/sse/client.js +128 -45
- package/dist/event/sse/client.js.map +1 -1
- package/dist/event/sse/index.d.ts +12 -5
- package/dist/event/sse/index.js +280 -32
- package/dist/event/sse/index.js.map +1 -1
- package/dist/event/ws/client.d.ts +59 -0
- package/dist/event/ws/client.js +273 -0
- package/dist/event/ws/client.js.map +1 -0
- package/dist/event/ws/index.d.ts +94 -0
- package/dist/event/ws/index.js +272 -0
- package/dist/event/ws/index.js.map +1 -0
- package/dist/job/index.d.ts +2 -2
- package/dist/job/index.js +155 -42
- package/dist/job/index.js.map +1 -1
- package/dist/logger/index.d.ts +5 -0
- package/dist/logger/index.js +14 -0
- package/dist/logger/index.js.map +1 -1
- package/dist/middleware/index.d.ts +347 -9
- package/dist/middleware/index.js +1462 -15
- package/dist/middleware/index.js.map +1 -1
- package/dist/nextjs/index.d.ts +2 -2
- package/dist/nextjs/index.js +42 -28
- package/dist/nextjs/index.js.map +1 -1
- package/dist/nextjs/server.d.ts +35 -51
- package/dist/nextjs/server.js +126 -60
- package/dist/nextjs/server.js.map +1 -1
- package/dist/ops/index.d.ts +107 -0
- package/dist/ops/index.js +476 -0
- package/dist/ops/index.js.map +1 -0
- package/dist/route/index.d.ts +8 -694
- package/dist/route/index.js +111 -22
- package/dist/route/index.js.map +1 -1
- package/dist/router-ukNdAZcN.d.ts +676 -0
- package/dist/security/index.d.ts +83 -0
- package/dist/security/index.js +173 -0
- package/dist/security/index.js.map +1 -0
- package/dist/server/index.d.ts +491 -22
- package/dist/server/index.js +1887 -308
- package/dist/server/index.js.map +1 -1
- package/dist/token-manager-BT5EnUAR.d.ts +278 -0
- package/dist/types-2AbaW4Ie.d.ts +205 -0
- package/dist/{types-BOPTApC2.d.ts → types-9oszaJqp.d.ts} +7 -2
- package/dist/types-Bvvig_tT.d.ts +115 -0
- package/dist/types-ZQODsBft.d.ts +282 -0
- package/package.json +244 -208
- package/dist/router-Di7ENoah.d.ts +0 -151
- package/dist/types-B-e_f2dQ.d.ts +0 -121
- package/docs/cache.md +0 -133
- package/docs/codegen.md +0 -74
- package/docs/database.md +0 -346
- package/docs/entity.md +0 -539
- package/docs/env.md +0 -477
- package/docs/errors.md +0 -319
- package/docs/event.md +0 -116
- package/docs/job.md +0 -131
- package/docs/logger.md +0 -108
- package/docs/middleware.md +0 -337
- package/docs/nextjs.md +0 -241
- package/docs/repository.md +0 -496
- package/docs/route.md +0 -497
- package/docs/server.md +0 -307
package/dist/route/index.js
CHANGED
|
@@ -11,6 +11,7 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
11
11
|
_interceptor;
|
|
12
12
|
_middlewares;
|
|
13
13
|
_skipMiddlewares;
|
|
14
|
+
_contract;
|
|
14
15
|
/**
|
|
15
16
|
* Create a new RouteBuilder with copied properties and optional overrides
|
|
16
17
|
*/
|
|
@@ -22,6 +23,7 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
22
23
|
builder._interceptor = overrides?.interceptor ?? this._interceptor;
|
|
23
24
|
builder._middlewares = overrides?.middlewares ?? this._middlewares;
|
|
24
25
|
builder._skipMiddlewares = overrides?.skipMiddlewares ?? this._skipMiddlewares;
|
|
26
|
+
builder._contract = overrides?.contract ?? this._contract;
|
|
25
27
|
return builder;
|
|
26
28
|
}
|
|
27
29
|
/**
|
|
@@ -159,6 +161,39 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
159
161
|
skip(middlewareNames) {
|
|
160
162
|
return this.clone({ skipMiddlewares: middlewareNames });
|
|
161
163
|
}
|
|
164
|
+
/**
|
|
165
|
+
* Publish this route as a versioned contract operation
|
|
166
|
+
*
|
|
167
|
+
* Marks the route as a promise to clients that are compiled and deployed
|
|
168
|
+
* separately from the server — a mobile app, an external API consumer.
|
|
169
|
+
* The `@spfn/core:contract` generator writes every contracted route into
|
|
170
|
+
* `contracts/current.json`, and the build refuses a change that would break
|
|
171
|
+
* an already-released client.
|
|
172
|
+
*
|
|
173
|
+
* Routes without `.contract()` are unaffected: they simply do not appear in
|
|
174
|
+
* the contract. A web client needs nothing here — it derives its types from
|
|
175
|
+
* the router in the same build.
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```ts
|
|
179
|
+
* export const getUser = route.get('/users/:id')
|
|
180
|
+
* .input({ params: Type.Object({ id: Type.String() }) })
|
|
181
|
+
* .contract({
|
|
182
|
+
* since: '1.2.0',
|
|
183
|
+
* auth: 'clientProofV1',
|
|
184
|
+
* requiresSession: true,
|
|
185
|
+
* response: Type.Object({
|
|
186
|
+
* id: Type.String(),
|
|
187
|
+
* name: Type.String(),
|
|
188
|
+
* email: Type.Optional(Type.String()),
|
|
189
|
+
* }),
|
|
190
|
+
* })
|
|
191
|
+
* .handler(async (c) => { ... });
|
|
192
|
+
* ```
|
|
193
|
+
*/
|
|
194
|
+
contract(contract) {
|
|
195
|
+
return this.clone({ contract });
|
|
196
|
+
}
|
|
162
197
|
/**
|
|
163
198
|
* Define handler function
|
|
164
199
|
*
|
|
@@ -213,6 +248,7 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
213
248
|
interceptor: this._interceptor,
|
|
214
249
|
middlewares: this._middlewares,
|
|
215
250
|
skipMiddlewares: this._skipMiddlewares,
|
|
251
|
+
contract: this._contract,
|
|
216
252
|
handler: fn,
|
|
217
253
|
_input: {},
|
|
218
254
|
_interceptor: {},
|
|
@@ -237,12 +273,13 @@ var route = {
|
|
|
237
273
|
};
|
|
238
274
|
|
|
239
275
|
// src/route/router.ts
|
|
240
|
-
function createRouterInstance(routes, packageRouters = [], globalMiddlewares = []) {
|
|
276
|
+
function createRouterInstance(routes, packageRouters = [], globalMiddlewares = [], contractVersion = null) {
|
|
241
277
|
return {
|
|
242
278
|
routes,
|
|
243
279
|
_routes: routes,
|
|
244
280
|
_packageRouters: packageRouters,
|
|
245
281
|
_globalMiddlewares: globalMiddlewares,
|
|
282
|
+
_contractVersion: contractVersion,
|
|
246
283
|
packages(routers) {
|
|
247
284
|
const newPackageRouters = [...this._packageRouters, ...routers];
|
|
248
285
|
for (const pkgRouter of routers) {
|
|
@@ -250,13 +287,39 @@ function createRouterInstance(routes, packageRouters = [], globalMiddlewares = [
|
|
|
250
287
|
newPackageRouters.push(...pkgRouter._packageRouters);
|
|
251
288
|
}
|
|
252
289
|
}
|
|
253
|
-
return createRouterInstance(
|
|
290
|
+
return createRouterInstance(
|
|
291
|
+
this.routes,
|
|
292
|
+
newPackageRouters,
|
|
293
|
+
this._globalMiddlewares,
|
|
294
|
+
this._contractVersion
|
|
295
|
+
);
|
|
254
296
|
},
|
|
255
297
|
use(middlewares) {
|
|
256
|
-
return createRouterInstance(
|
|
298
|
+
return createRouterInstance(
|
|
299
|
+
this.routes,
|
|
300
|
+
this._packageRouters,
|
|
301
|
+
[...this._globalMiddlewares, ...middlewares],
|
|
302
|
+
this._contractVersion
|
|
303
|
+
);
|
|
304
|
+
},
|
|
305
|
+
contractVersion(version) {
|
|
306
|
+
assertContractVersion(version);
|
|
307
|
+
return createRouterInstance(
|
|
308
|
+
this.routes,
|
|
309
|
+
this._packageRouters,
|
|
310
|
+
this._globalMiddlewares,
|
|
311
|
+
version
|
|
312
|
+
);
|
|
257
313
|
}
|
|
258
314
|
};
|
|
259
315
|
}
|
|
316
|
+
function assertContractVersion(version) {
|
|
317
|
+
if (!/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)*$/.test(version)) {
|
|
318
|
+
throw new Error(
|
|
319
|
+
`contractVersion("${version}") is not a version of the form major.minor.patch. The released snapshot is named from this value and releases are compared by it.`
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
260
323
|
function defineRouter(routes) {
|
|
261
324
|
return createRouterInstance(routes);
|
|
262
325
|
}
|
|
@@ -575,7 +638,7 @@ function registerRoutes(app, router, namedMiddlewares, collectedRoutes) {
|
|
|
575
638
|
return routes;
|
|
576
639
|
}
|
|
577
640
|
function registerRoute(app, name, routeDef, namedMiddlewares) {
|
|
578
|
-
const { method, path, input, middlewares = [], skipMiddlewares, handler } = routeDef;
|
|
641
|
+
const { method, path, input, interceptor, middlewares = [], skipMiddlewares, handler } = routeDef;
|
|
579
642
|
if (!method || !path) {
|
|
580
643
|
logger.warn(`Route "${name}" is missing method or path - skipping`, {
|
|
581
644
|
method,
|
|
@@ -584,7 +647,7 @@ function registerRoute(app, name, routeDef, namedMiddlewares) {
|
|
|
584
647
|
return null;
|
|
585
648
|
}
|
|
586
649
|
const wrappedHandler = async (c) => {
|
|
587
|
-
const { context, responseMeta } = await createRouteBuilderContext(c, input || {});
|
|
650
|
+
const { context, responseMeta } = await createRouteBuilderContext(c, input || {}, interceptor);
|
|
588
651
|
const result = await handler(context);
|
|
589
652
|
if (result instanceof Response) {
|
|
590
653
|
return result;
|
|
@@ -602,18 +665,30 @@ function registerRoute(app, name, routeDef, namedMiddlewares) {
|
|
|
602
665
|
const registeredNames = /* @__PURE__ */ new Set();
|
|
603
666
|
const registeredHandlers = /* @__PURE__ */ new Set();
|
|
604
667
|
const skipAll = skipMiddlewares === "*";
|
|
668
|
+
const autoSkips = /* @__PURE__ */ new Set();
|
|
669
|
+
for (const mw of middlewares) {
|
|
670
|
+
if (isNamedMiddleware(mw) && mw.skips) {
|
|
671
|
+
for (const skipName of mw.skips) {
|
|
672
|
+
autoSkips.add(skipName);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
}
|
|
605
676
|
if (namedMiddlewares && namedMiddlewares.length > 0) {
|
|
606
677
|
if (skipAll) {
|
|
607
678
|
logger.debug(`\u23ED\uFE0F Skipping all middlewares (*) for route: ${method} ${path}`, { name });
|
|
608
679
|
} else {
|
|
609
680
|
const skipSet = new Set(Array.isArray(skipMiddlewares) ? skipMiddlewares : []);
|
|
610
681
|
for (const middleware of namedMiddlewares) {
|
|
611
|
-
if (
|
|
682
|
+
if (skipSet.has(middleware.name)) {
|
|
683
|
+
logger.debug(`\u23ED\uFE0F Skipping middleware '${middleware.name}' for route: ${method} ${path}`, { name });
|
|
684
|
+
} else if (autoSkips.has(middleware.name)) {
|
|
685
|
+
logger.debug(`\u23ED\uFE0F Auto-skipping middleware '${middleware.name}' for route: ${method} ${path}`, { name });
|
|
686
|
+
} else if (middleware.name && registeredNames.has(middleware.name)) {
|
|
687
|
+
logger.debug(`\u{1F504} Skipping duplicate middleware '${middleware.name}' for route: ${method} ${path}`, { name });
|
|
688
|
+
} else {
|
|
612
689
|
allMiddlewares.push(middleware.handler);
|
|
613
690
|
registeredNames.add(middleware.name);
|
|
614
691
|
registeredHandlers.add(middleware.handler);
|
|
615
|
-
} else {
|
|
616
|
-
logger.debug(`\u23ED\uFE0F Skipping middleware '${middleware.name}' for route: ${method} ${path}`, { name });
|
|
617
692
|
}
|
|
618
693
|
}
|
|
619
694
|
}
|
|
@@ -636,29 +711,32 @@ function registerRoute(app, name, routeDef, namedMiddlewares) {
|
|
|
636
711
|
}
|
|
637
712
|
}
|
|
638
713
|
const methodLower = method.toLowerCase();
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
} else {
|
|
642
|
-
app[methodLower](path, wrappedHandler);
|
|
643
|
-
}
|
|
714
|
+
const handlers = [...allMiddlewares, wrappedHandler];
|
|
715
|
+
app.on([methodLower], [path], ...handlers);
|
|
644
716
|
logger.debug(`Registered route: ${method} ${path}`, { name });
|
|
645
717
|
return { method, path, name };
|
|
646
718
|
}
|
|
647
|
-
|
|
719
|
+
function methodCarriesBody(method) {
|
|
720
|
+
return method !== "GET" && method !== "HEAD";
|
|
721
|
+
}
|
|
722
|
+
async function createRouteBuilderContext(c, input, interceptor) {
|
|
648
723
|
const params = validateField(input.params, c.req.param(), "path parameters");
|
|
649
724
|
const query = validateField(input.query, extractQueryParams(c), "query parameters");
|
|
650
725
|
const headers = validateField(input.headers, extractHeaders(c), "headers");
|
|
651
726
|
const cookies = validateField(input.cookies, extractCookies(c), "cookies");
|
|
652
727
|
let body = {};
|
|
653
728
|
let formData = {};
|
|
654
|
-
|
|
729
|
+
const injected = methodCarriesBody(c.req.method) ? interceptor : void 0;
|
|
730
|
+
const expectsBody = input.body ?? injected?.body;
|
|
731
|
+
const expectsFormData = input.formData ?? injected?.formData;
|
|
732
|
+
if (expectsBody || expectsFormData) {
|
|
655
733
|
const contentType = c.req.header("content-type") || "";
|
|
656
|
-
if (contentType.includes("multipart/form-data") &&
|
|
734
|
+
if (contentType.includes("multipart/form-data") && expectsFormData) {
|
|
657
735
|
const rawFormData = await parseFormData(c);
|
|
658
|
-
formData = validateFormData(input.formData, rawFormData, "form data");
|
|
659
|
-
} else if (
|
|
736
|
+
formData = input.formData ? validateFormData(input.formData, rawFormData, "form data") : rawFormData;
|
|
737
|
+
} else if (expectsBody) {
|
|
660
738
|
const rawBody = await parseJsonBody(c);
|
|
661
|
-
body = validateField(input.body, rawBody, "request body");
|
|
739
|
+
body = input.body ? validateField(input.body, rawBody, "request body") : rawBody;
|
|
662
740
|
}
|
|
663
741
|
}
|
|
664
742
|
let cachedData = null;
|
|
@@ -720,14 +798,16 @@ async function createRouteBuilderContext(c, input) {
|
|
|
720
798
|
}
|
|
721
799
|
|
|
722
800
|
// src/route/define-middleware.ts
|
|
723
|
-
function defineMiddleware(name, handlerOrFactory) {
|
|
801
|
+
function defineMiddleware(name, handlerOrFactory, options) {
|
|
802
|
+
const skips = options?.skips;
|
|
724
803
|
if (typeof handlerOrFactory === "function") {
|
|
725
804
|
const paramCount = handlerOrFactory.length;
|
|
726
805
|
if (paramCount === 2) {
|
|
727
806
|
return {
|
|
728
807
|
name,
|
|
729
808
|
handler: handlerOrFactory,
|
|
730
|
-
_name: name
|
|
809
|
+
_name: name,
|
|
810
|
+
...skips && { skips }
|
|
731
811
|
};
|
|
732
812
|
} else {
|
|
733
813
|
const factory = handlerOrFactory;
|
|
@@ -744,13 +824,22 @@ function defineMiddleware(name, handlerOrFactory) {
|
|
|
744
824
|
enumerable: false,
|
|
745
825
|
configurable: true
|
|
746
826
|
});
|
|
827
|
+
if (skips) {
|
|
828
|
+
Object.defineProperty(wrapper, "skips", {
|
|
829
|
+
value: skips,
|
|
830
|
+
writable: false,
|
|
831
|
+
enumerable: false,
|
|
832
|
+
configurable: true
|
|
833
|
+
});
|
|
834
|
+
}
|
|
747
835
|
return wrapper;
|
|
748
836
|
}
|
|
749
837
|
}
|
|
750
838
|
return {
|
|
751
839
|
name,
|
|
752
840
|
handler: handlerOrFactory,
|
|
753
|
-
_name: name
|
|
841
|
+
_name: name,
|
|
842
|
+
...skips && { skips }
|
|
754
843
|
};
|
|
755
844
|
}
|
|
756
845
|
function defineMiddlewareFactory(name, factory) {
|