@spfn/core 0.3.0-beta.2 → 0.3.0-beta.21

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.
Files changed (94) hide show
  1. package/README.md +343 -16
  2. package/dist/app-config/index.d.ts +134 -0
  3. package/dist/app-config/index.js +58 -0
  4. package/dist/app-config/index.js.map +1 -0
  5. package/dist/authz/index.js +1 -381
  6. package/dist/authz/index.js.map +1 -1
  7. package/dist/{boss-D16fO2oG.d.ts → boss-BiDCbbAQ.d.ts} +60 -7
  8. package/dist/codegen/index.d.ts +93 -15
  9. package/dist/codegen/index.js +626 -165
  10. package/dist/codegen/index.js.map +1 -1
  11. package/dist/config/index.d.ts +0 -63
  12. package/dist/config/index.js +15 -15
  13. package/dist/config/index.js.map +1 -1
  14. package/dist/contract/index.d.ts +40 -17
  15. package/dist/contract/index.js +147 -23
  16. package/dist/contract/index.js.map +1 -1
  17. package/dist/db/index.d.ts +201 -34
  18. package/dist/db/index.js +294 -158
  19. package/dist/db/index.js.map +1 -1
  20. package/dist/{define-middleware-DfDP39Nq.d.ts → define-middleware-CVKgqo8S.d.ts} +1 -1
  21. package/dist/env/index.d.ts +6 -442
  22. package/dist/env/index.js +13 -16
  23. package/dist/env/index.js.map +1 -1
  24. package/dist/env/loader.js +24 -1
  25. package/dist/env/loader.js.map +1 -1
  26. package/dist/error-TsUIjp_x.d.ts +157 -0
  27. package/dist/errors/index.js +1 -381
  28. package/dist/errors/index.js.map +1 -1
  29. package/dist/event/index.d.ts +5 -5
  30. package/dist/event/index.js +32 -1
  31. package/dist/event/index.js.map +1 -1
  32. package/dist/event/sse/client.d.ts +18 -4
  33. package/dist/event/sse/client.js +38 -2
  34. package/dist/event/sse/client.js.map +1 -1
  35. package/dist/event/sse/index.d.ts +5 -4
  36. package/dist/event/ws/client.d.ts +3 -2
  37. package/dist/event/ws/index.d.ts +4 -3
  38. package/dist/job/index.d.ts +48 -3
  39. package/dist/job/index.js +131 -52
  40. package/dist/job/index.js.map +1 -1
  41. package/dist/logger/index.js +0 -12
  42. package/dist/logger/index.js.map +1 -1
  43. package/dist/middleware/index.d.ts +6 -2
  44. package/dist/middleware/index.js +7 -388
  45. package/dist/middleware/index.js.map +1 -1
  46. package/dist/nextjs/index.d.ts +88 -8
  47. package/dist/nextjs/index.js +138 -62
  48. package/dist/nextjs/index.js.map +1 -1
  49. package/dist/nextjs/server.d.ts +45 -7
  50. package/dist/nextjs/server.js +14 -0
  51. package/dist/nextjs/server.js.map +1 -1
  52. package/dist/ops/index.d.ts +62 -43
  53. package/dist/ops/index.js +638 -97
  54. package/dist/ops/index.js.map +1 -1
  55. package/dist/registry-C2KQCh0m.d.ts +473 -0
  56. package/dist/route/index.d.ts +6 -3
  57. package/dist/route/index.js +97 -28
  58. package/dist/route/index.js.map +1 -1
  59. package/dist/route/types.d.ts +7 -1
  60. package/dist/{router-Qbssr11H.d.ts → route-builder-DRW-MSCJ.d.ts} +52 -127
  61. package/dist/router-4YoIy5fN.d.ts +172 -0
  62. package/dist/{token-manager-BT5EnUAR.d.ts → router-CysBmgv3.d.ts} +81 -127
  63. package/dist/server/index.d.ts +185 -14
  64. package/dist/server/index.js +883 -78
  65. package/dist/server/index.js.map +1 -1
  66. package/dist/surface/index.d.ts +115 -0
  67. package/dist/surface/index.js +1003 -0
  68. package/dist/surface/index.js.map +1 -0
  69. package/dist/token-manager-Ckjt2-qq.d.ts +122 -0
  70. package/dist/{types-D1c57Ko-.d.ts → types-5Rl11_Nb.d.ts} +43 -4
  71. package/dist/{types-ZQODsBft.d.ts → types-B8zAxFsE.d.ts} +2 -1
  72. package/dist/types-CxhPH4s_.d.ts +375 -0
  73. package/dist/{types-2AbaW4Ie.d.ts → types-W4u_S0lF.d.ts} +4 -3
  74. package/docs/file-upload.md +195 -333
  75. package/package.json +20 -9
  76. package/src/cache/README.md +330 -0
  77. package/src/codegen/README.md +634 -0
  78. package/src/config/README.md +333 -0
  79. package/src/contract/README.md +440 -0
  80. package/src/db/README.md +589 -0
  81. package/src/db/manager/README.md +500 -0
  82. package/src/db/schema/README.md +354 -0
  83. package/src/db/transaction/README.md +822 -0
  84. package/src/env/README.md +787 -0
  85. package/src/errors/README.md +429 -0
  86. package/src/event/README.md +789 -0
  87. package/src/job/README.md +613 -0
  88. package/src/logger/README.md +321 -0
  89. package/src/middleware/README.md +634 -0
  90. package/src/nextjs/README.md +688 -0
  91. package/src/route/README.md +763 -0
  92. package/src/security/README.md +100 -0
  93. package/src/server/README.md +704 -0
  94. package/dist/types-9oszaJqp.d.ts +0 -250
@@ -5,13 +5,20 @@ import { serve } from '@hono/node-server';
5
5
  import { NamedMiddleware, Router } from '@spfn/core/route';
6
6
  import { OnErrorContext, ProxyGuardConfig, RateLimitOptions } from '@spfn/core/middleware';
7
7
  import { SafeFetchPolicy } from '@spfn/core/security';
8
- import { c as JobRouter, e as BossOptions } from '../boss-D16fO2oG.js';
9
- import { b as EventRouterDef, E as EventDef } from '../token-manager-BT5EnUAR.js';
10
- import { d as SSEHandlerConfig, e as SSEAuthConfig } from '../types-ZQODsBft.js';
11
- import { W as WSRouterDef, f as WSHandlerConfig, e as WSMessageHandlers, g as WSAuthConfig } from '../types-2AbaW4Ie.js';
8
+ import { c as JobRouter, f as BossOptions } from '../boss-BiDCbbAQ.js';
9
+ import { E as EventRouterDef, a as EventDef } from '../router-CysBmgv3.js';
10
+ import { d as SSEHandlerConfig, e as SSEAuthConfig } from '../types-B8zAxFsE.js';
11
+ import { W as WSRouterDef, f as WSHandlerConfig, e as WSMessageHandlers, g as WSAuthConfig } from '../types-W4u_S0lF.js';
12
12
  import { DatabaseProvider, MigrationStatus, MigrationStatusDb } from '@spfn/core/db';
13
- import '@sinclair/typebox';
13
+ import * as _sinclair_typebox from '@sinclair/typebox';
14
+ import { Static } from '@sinclair/typebox';
15
+ import { R as RouteDef } from '../route-builder-DRW-MSCJ.js';
16
+ import { a as EnvRegistry } from '../registry-C2KQCh0m.js';
14
17
  import 'pg-boss';
18
+ import '../token-manager-Ckjt2-qq.js';
19
+ import '../define-middleware-CVKgqo8S.js';
20
+ import 'hono/utils/http-status';
21
+ import '../route/types.js';
15
22
 
16
23
  /**
17
24
  * @deprecated Use `loadEnv` from '@spfn/core/env/loader' instead.
@@ -22,6 +29,33 @@ import 'pg-boss';
22
29
  */
23
30
  declare function loadEnvFiles(): void;
24
31
 
32
+ /** Stable operation identity used by separately deployed clients. */
33
+ declare const CORE_TIME_OPERATION_ID = "core.time";
34
+ /**
35
+ * Closed response shape for the server-time wire capability.
36
+ *
37
+ * Millisecond timestamps use integers throughout SPFN's external contracts.
38
+ */
39
+ declare const ServerTimeResponseSchema: _sinclair_typebox.TObject<{
40
+ serverTimeMillis: _sinclair_typebox.TInteger;
41
+ }>;
42
+ type ServerTimeResponse = Static<typeof ServerTimeResponseSchema>;
43
+ /** Injectable source of Unix epoch milliseconds. */
44
+ interface ServerClock {
45
+ now(): number;
46
+ }
47
+ /**
48
+ * Build the route from a clock so tests and alternate runtimes can supply the
49
+ * epoch source without replacing global time.
50
+ */
51
+ declare function createCoreTimeRoute(clock?: ServerClock): RouteDef<{}, {}, {
52
+ serverTimeMillis: number;
53
+ }>;
54
+ /** The production route and the public wire-contract source of truth. */
55
+ declare const CORE_TIME_ROUTE: RouteDef<{}, {}, {
56
+ serverTimeMillis: number;
57
+ }>;
58
+
25
59
  /**
26
60
  * Workflow router interface for @spfn/core integration
27
61
  *
@@ -202,6 +236,8 @@ interface ServerConfig {
202
236
  * Jobs defined with job()...handler() style
203
237
  * Uses pg-boss for PostgreSQL-based job queue
204
238
  *
239
+ * Merged across every `.jobs()` call, so this holds all of them.
240
+ *
205
241
  * @example
206
242
  * ```typescript
207
243
  * import { job, defineJobRouter } from '@spfn/core/job';
@@ -454,7 +490,9 @@ interface ServerConfig {
454
490
  };
455
491
  /**
456
492
  * Health check endpoint configuration
457
- * Provides monitoring endpoints for Kubernetes probes and load balancers
493
+ *
494
+ * The endpoint answers at `/_core/health`, which no app route can take from
495
+ * it. Point Kubernetes probes and load balancers there.
458
496
  */
459
497
  healthCheck?: {
460
498
  /**
@@ -464,9 +502,19 @@ interface ServerConfig {
464
502
  */
465
503
  enabled?: boolean;
466
504
  /**
467
- * Health check endpoint path
468
- * @default '/health'
469
- * @env HEALTH_CHECK_PATH
505
+ * An additional path to answer on, for a deployment whose probe path is
506
+ * fixed somewhere you cannot change it.
507
+ *
508
+ * BREAKING (@spfn/core 0.4): unset, the endpoint answers at
509
+ * `/_core/health` and nowhere else. It used to default to `/health` and
510
+ * swallow any app route declared there. `/health` now belongs to your
511
+ * app; set this to `'/health'` to have the built-in answer there again.
512
+ *
513
+ * The path is registered before app routes, so an app route on the same
514
+ * path will not run and the server says so at boot.
515
+ *
516
+ * @default undefined — `/_core/health` only
517
+ * @example '/health'
470
518
  */
471
519
  path?: string;
472
520
  /**
@@ -477,6 +525,15 @@ interface ServerConfig {
477
525
  */
478
526
  detailed?: boolean;
479
527
  };
528
+ /**
529
+ * Server-time capability dependencies.
530
+ *
531
+ * The endpoint is always enabled at `GET /_core/time`. Supplying a clock is
532
+ * primarily a deterministic test seam; production defaults to `Date.now()`.
533
+ */
534
+ serverTime?: {
535
+ clock?: ServerClock;
536
+ };
480
537
  /**
481
538
  * Migration boot gate
482
539
  *
@@ -498,20 +555,55 @@ interface ServerConfig {
498
555
  */
499
556
  allowPending?: boolean;
500
557
  };
558
+ /**
559
+ * Environment boot check
560
+ *
561
+ * Before serving, the server validates every variable of `@spfn/core`'s
562
+ * registry and of the registries listed here: a required variable must be
563
+ * set, and a set variable must pass its `validator`. On failure it logs
564
+ * each key with the reason — never a value — and refuses to start.
565
+ * `SKIP_ENV_VALIDATION` does not skip this check.
566
+ *
567
+ * @example
568
+ * ```typescript
569
+ * // src/server/config/env.config.ts
570
+ * export const envSchema = defineEnvSchema({ ... });
571
+ * export const envRegistry = createEnvRegistry(envSchema);
572
+ * export const env = envRegistry.validate();
573
+ *
574
+ * // src/server/server.config.ts
575
+ * export default defineServerConfig()
576
+ * .env({ registries: [envRegistry] })
577
+ * .build();
578
+ * ```
579
+ */
580
+ env?: {
581
+ /**
582
+ * Registries checked alongside `@spfn/core`'s: the app's own, and any
583
+ * package registry the app wants held to the same gate.
584
+ */
585
+ registries?: EnvRegistry<any>[];
586
+ };
501
587
  /**
502
588
  * Infrastructure initialization control
503
589
  * Controls automatic initialization of database and Redis
504
- * @default Both enabled if credentials exist
590
+ *
591
+ * Both are initialized unless set to `false` — the credentials are not
592
+ * sniffed. A server that needs no database must say so, otherwise boot
593
+ * fails with `No database configuration found`. A component set to `false`
594
+ * is reported as `disabled` by the health endpoint and never degrades it.
595
+ *
596
+ * @default Both enabled
505
597
  */
506
598
  infrastructure?: {
507
599
  /**
508
600
  * Enable/disable automatic database initialization
509
- * @default true if DATABASE_URL exists
601
+ * @default true
510
602
  */
511
603
  database?: boolean;
512
604
  /**
513
605
  * Enable/disable automatic Redis initialization
514
- * @default true if REDIS_URL exists
606
+ * @default true
515
607
  */
516
608
  redis?: boolean;
517
609
  };
@@ -710,6 +802,43 @@ declare module 'hono' {
710
802
  */
711
803
  declare function createServer(config?: ServerConfig): Promise<Hono>;
712
804
 
805
+ /**
806
+ * The paths `@spfn/core` registers for itself.
807
+ *
808
+ * Its own module because both `create-server.ts` (which registers them) and
809
+ * `helpers.ts` (which reports them in the startup banner) need them, and
810
+ * `create-server.ts` already imports `helpers.ts` — putting them in either file
811
+ * would close a cycle, which `pnpm check:circular` fails the build on.
812
+ *
813
+ * @module server/namespace
814
+ */
815
+ /**
816
+ * The path prefix `@spfn/core` registers its own endpoints under.
817
+ *
818
+ * An app declaring a route in here is declaring something it does not own, and
819
+ * the route will not run — core's endpoints are registered before app routes.
820
+ * `@spfn/auth` (`/_auth/`) and ops routes (`/_ops/`) follow the same convention,
821
+ * and neither has ever had a shadowing defect.
822
+ */
823
+ declare const CORE_NAMESPACE = "/_core";
824
+ /**
825
+ * Where the built-in health endpoint always answers.
826
+ *
827
+ * Point a readiness probe, a Dockerfile `HEALTHCHECK` or an uptime monitor here
828
+ * rather than at `/health`: no app route can claim this path, so the answer does
829
+ * not depend on what the app happens to declare. A probe's path is fixed in
830
+ * places this repository cannot change — a GitOps manifest, a Dockerfile, a load
831
+ * balancer console — and a version bump migrates none of them.
832
+ */
833
+ declare const CORE_HEALTH_PATH = "/_core/health";
834
+ /**
835
+ * Where clients obtain the server's current Unix epoch in milliseconds.
836
+ *
837
+ * This endpoint is registered before application routes and application auth
838
+ * middleware so a client can call it before it has a proof or session.
839
+ */
840
+ declare const CORE_TIME_PATH = "/_core/time";
841
+
713
842
  /**
714
843
  * Start SPFN Server
715
844
  *
@@ -720,6 +849,8 @@ declare function createServer(config?: ServerConfig): Promise<Hono>;
720
849
  * Start SPFN server
721
850
  *
722
851
  * Automatically loads server.config.ts if exists
852
+ * Validates the environment (core's registry + `config.env.registries`) and
853
+ * exits with code 1 when a variable is missing or invalid
723
854
  * Automatically initializes Database and Redis from environment
724
855
  * Sets up graceful shutdown handlers for SIGTERM and SIGINT
725
856
  *
@@ -863,6 +994,9 @@ declare function getShutdownManager(): ShutdownManager;
863
994
  * - does NOT run seed/RBAC provisioning per cold start — that moves to a
864
995
  * deploy-time step, see {@link provisionInfrastructure}.
865
996
  *
997
+ * Like {@link startServer}, it runs the environment boot check before building
998
+ * the app; a failure rejects the returned promise instead of exiting.
999
+ *
866
1000
  * `startServer()` / `spfn start` (the always-on path) is unchanged by this module.
867
1001
  */
868
1002
 
@@ -1049,6 +1183,20 @@ declare class ServerConfigBuilder {
1049
1183
  /**
1050
1184
  * Register background jobs router
1051
1185
  *
1186
+ * May be called once per domain router: repeated calls **merge** into one
1187
+ * router, the way `.routes()` composes. Calling it several times used to
1188
+ * keep only the last router and register nothing else, without warning.
1189
+ *
1190
+ * The pg-boss `config` is per server, so pass it on one call only.
1191
+ *
1192
+ * Two names can collide, and both fail loudly:
1193
+ * - a router **key** present in two calls throws here, at config time;
1194
+ * - two jobs sharing a **`job.name`** (the pg-boss queue name) throw in
1195
+ * `registerJobs()` at boot, before any queue or worker is created.
1196
+ *
1197
+ * @throws if a router key was already registered by an earlier call
1198
+ * @throws if `config` is given when an earlier call already gave one
1199
+ *
1052
1200
  * @example
1053
1201
  * ```typescript
1054
1202
  * import { job, defineJobRouter } from '@spfn/core/job';
@@ -1061,7 +1209,8 @@ declare class ServerConfigBuilder {
1061
1209
  *
1062
1210
  * export default defineServerConfig()
1063
1211
  * .routes(appRouter)
1064
- * .jobs(jobRouter)
1212
+ * .jobs(jobRouter, { clearOnStart: isDev }) // config on one call only
1213
+ * .jobs(billingJobRouter) // merged, not replaced
1065
1214
  * .build();
1066
1215
  * ```
1067
1216
  */
@@ -1149,6 +1298,12 @@ declare class ServerConfigBuilder {
1149
1298
  * Configure health check endpoint
1150
1299
  */
1151
1300
  healthCheck(healthCheck: ServerConfig['healthCheck']): this;
1301
+ /**
1302
+ * Supply the clock used by the built-in `GET /_core/time` capability.
1303
+ * Production servers normally keep the default `Date.now()` clock; this is
1304
+ * exposed so tests can assert an exact wire value without replacing globals.
1305
+ */
1306
+ serverTime(serverTime: ServerConfig['serverTime']): this;
1152
1307
  /**
1153
1308
  * Configure infrastructure initialization
1154
1309
  */
@@ -1165,6 +1320,22 @@ declare class ServerConfigBuilder {
1165
1320
  * ```
1166
1321
  */
1167
1322
  migrations(migrations: ServerConfig['migrations']): this;
1323
+ /**
1324
+ * Hand the app's env registries to the boot check
1325
+ *
1326
+ * `@spfn/core`'s own registry is always checked; the registries given here
1327
+ * are checked with it, before the server listens.
1328
+ *
1329
+ * @example
1330
+ * ```typescript
1331
+ * import { envRegistry } from '@/server/config/env.config';
1332
+ *
1333
+ * export default defineServerConfig()
1334
+ * .env({ registries: [envRegistry] })
1335
+ * .build();
1336
+ * ```
1337
+ */
1338
+ env(env: ServerConfig['env']): this;
1168
1339
  /**
1169
1340
  * Register workflow router for workflow orchestration
1170
1341
  *
@@ -1225,4 +1396,4 @@ declare class ServerConfigBuilder {
1225
1396
  */
1226
1397
  declare function defineServerConfig(): ServerConfigBuilder;
1227
1398
 
1228
- export { type AppFactory, type MigrationSnapshot, PendingMigrationsError, type ServerConfig, type ServerInstance, type ShutdownHookOptions, createServer, createServerlessApp, defineServerConfig, getMigrationSnapshot, getShutdownManager, loadEnvFiles, provisionInfrastructure, resetMigrationSnapshot, resetServerlessApp, startServer };
1399
+ export { type AppFactory, CORE_HEALTH_PATH, CORE_NAMESPACE, CORE_TIME_OPERATION_ID, CORE_TIME_PATH, CORE_TIME_ROUTE, type MigrationSnapshot, PendingMigrationsError, type ServerClock, type ServerConfig, type ServerInstance, type ServerTimeResponse, ServerTimeResponseSchema, type ShutdownHookOptions, createCoreTimeRoute, createServer, createServerlessApp, defineServerConfig, getMigrationSnapshot, getShutdownManager, loadEnvFiles, provisionInfrastructure, resetMigrationSnapshot, resetServerlessApp, startServer };