@stacksjs/types 0.72.56 → 0.72.60

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/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- function x(p){return typeof p==="object"&&p!==null&&"id"in p&&"userId"in p&&"clientId"in p&&"scopes"in p}function H(p){return x(p)&&"abilities"in p}function N(p){return typeof p==="object"&&p!==null&&"id"in p&&"name"in p&&"secret"in p&&"redirect"in p}var F;((D)=>{D.Second="* * * * * *";D.FiveSeconds="*/5 * * * * *";D.TenSeconds="*/10 * * * * *";D.ThirtySeconds="*/30 * * * * *";D.Minute="* * * * *";D.TwoMinutes="*/2 * * * *";D.FiveMinutes="*/5 * * * *";D.TenMinutes="*/10 * * * *";D.FifteenMinutes="*/15 * * * *";D.ThirtyMinutes="*/30 * * * *";D.Hour="0 * * * *";D.HalfHour="0,30 * * * *";D.Day="0 0 * * *";D.Week="0 0 * * 0";D.Weekday="0 0 * * 1-5";D.Weekend="0 0 * * 0,6";D.Month="0 0 1 * *";D.Year="0 0 1 1 *"})(F||={});var U;((B)=>{B.Bluesky="bluesky";B.Discord="discord";B.Facebook="facebook";B.GitHub="github";B.Instagram="instagram";B.LinkedIn="linkedin";B.Mastodon="mastodon";B.Slack="slack";B.Twitter="twitter";B.YouTube="youtube"})(U||={});var _;((O)=>{O[O.Success=0]="Success";O[O.FatalError=1]="FatalError";O[O.InvalidArgument=9]="InvalidArgument"})(_||={});import{toString as G}from"@stacksjs/strings";function K(p){if(p===null)return"null";let P=G(p).slice(8,-1).toLowerCase();return typeof p==="object"||typeof p==="function"?P:typeof p}function Q(p){return p}function R(p){return p}var W={development:{default:"sync",connections:{sync:{driver:"sync"}},failed:{driver:"database",table:"failed_jobs"}},production:{default:"redis",connections:{redis:{driver:"redis",prefix:"stacks:queue",concurrency:5,distributedLock:!0,metrics:{enabled:!0},defaultDeadLetterOptions:{enabled:!0,maxRetries:3}}},failed:{driver:"redis",prefix:"stacks:failed"},worker:{concurrency:5,shutdownTimeout:30000}},highPerformance:{default:"redis",connections:{redis:{driver:"redis",prefix:"stacks:queue",concurrency:20,distributedLock:!0,metrics:{enabled:!0,collectInterval:5000},horizontalScaling:{enabled:!0,maxWorkersPerInstance:20,jobsPerWorker:50},defaultDeadLetterOptions:{enabled:!0,maxRetries:5}}},failed:{driver:"redis",prefix:"stacks:failed"},worker:{concurrency:20,shutdownTimeout:60000}},database:{default:"database",connections:{database:{driver:"database",table:"jobs",queue:"default",retryAfter:90}},failed:{driver:"database",table:"failed_jobs"}}};var Z={server:{development:{enabled:!0,mode:"server",debug:!0,server:{host:"localhost",port:6001,scheme:"ws",driver:"bun",rateLimit:{enabled:!1},healthCheck:{enabled:!0,path:"/health"}},channels:{public:!0,private:!0,presence:!0}},production:{enabled:!0,mode:"server",debug:!1,server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",redis:{enabled:!0,prefix:"stacks:realtime:"},rateLimit:{enabled:!0,maxConnectionsPerIp:100,maxMessagesPerSecond:50,maxPayloadSize:65536},loadManagement:{maxConnections:1e4,backpressureThreshold:1000,messageQueueSize:1e4,gracefulShutdownTimeout:30000},autoScaling:{min:2,max:10,targetCPU:70},healthCheck:{enabled:!0,path:"/health",interval:30},metrics:{enabled:!0,port:9090,path:"/metrics"}},channels:{public:!0,private:!0,presence:!0}},highPerformance:{enabled:!0,mode:"server",server:{driver:"bun",redis:{enabled:!0,cluster:!0},rateLimit:{enabled:!0,maxConnectionsPerIp:500,maxMessagesPerSecond:200,maxPayloadSize:131072},loadManagement:{maxConnections:1e5,backpressureThreshold:5000,messageQueueSize:50000,gracefulShutdownTimeout:60000},autoScaling:{min:4,max:50,targetCPU:60}}},chat:{enabled:!0,mode:"server",server:{driver:"bun",redis:{enabled:!0},rateLimit:{enabled:!0,maxConnectionsPerIp:10,maxMessagesPerSecond:20},loadManagement:{maxConnections:50000}},channels:{public:!0,private:!0,presence:{enabled:!0,maxMembersPerChannel:500,memberInfoTtl:60}}},gaming:{enabled:!0,mode:"server",server:{driver:"bun",redis:{enabled:!0,cluster:!0},rateLimit:{enabled:!0,maxConnectionsPerIp:50,maxMessagesPerSecond:100},loadManagement:{maxConnections:50000,backpressureThreshold:2000,messageQueueSize:20000},autoScaling:{min:2,max:20,targetCPU:50}},channels:{public:!0,private:!0,presence:!0}}},serverless:{development:{enabled:!0,mode:"serverless",debug:!0,serverless:{connectionTimeout:3600,idleTimeout:600,stageName:"dev",memorySize:256,timeout:30},channels:{public:!0,private:!0,presence:!0}},production:{enabled:!0,mode:"serverless",debug:!1,serverless:{connectionTimeout:3600,idleTimeout:600,stageName:"production",memorySize:512,timeout:30,provisionedConcurrency:2},channels:{public:!0,private:!0,presence:!0}},notifications:{enabled:!0,mode:"serverless",serverless:{connectionTimeout:7200,idleTimeout:1800,memorySize:256,timeout:15},channels:{public:!0,private:!0,presence:!1}}}};var A={calendar:{github:"stacksjs/calendar",package:"@stacksjs/calendar",description:"Calendar links, ICS generation, and an STX calendar component"},table:{github:"stacksjs/table",package:"@stacksjs/table",description:"Typed table drivers and an STX data table component"}};export{A as stackExtensionRegistry,H as isPersonalAccessToken,N as isOAuthClient,x as isAccessToken,K as getTypeName,R as defineModels,Q as defineModel,U as SocialLinkIcon,Z as RealtimePresets,W as QueuePresets,_ as ExitCode,F as Every};
2
+ function a(e){return typeof e==="object"&&e!==null&&"id"in e&&"userId"in e&&"clientId"in e&&"scopes"in e}function c(e){return a(e)&&"abilities"in e}function d(e){return typeof e==="object"&&e!==null&&"id"in e&&"name"in e&&"secret"in e&&"redirect"in e}var i;((t)=>{t.Second="* * * * * *";t.FiveSeconds="*/5 * * * * *";t.TenSeconds="*/10 * * * * *";t.ThirtySeconds="*/30 * * * * *";t.Minute="* * * * *";t.TwoMinutes="*/2 * * * *";t.FiveMinutes="*/5 * * * *";t.TenMinutes="*/10 * * * *";t.FifteenMinutes="*/15 * * * *";t.ThirtyMinutes="*/30 * * * *";t.Hour="0 * * * *";t.HalfHour="0,30 * * * *";t.Day="0 0 * * *";t.Week="0 0 * * 0";t.Weekday="0 0 * * 1-5";t.Weekend="0 0 * * 0,6";t.Month="0 0 1 * *";t.Year="0 0 1 1 *"})(i||={});var s;((r)=>{r.Bluesky="bluesky";r.Discord="discord";r.Facebook="facebook";r.GitHub="github";r.Instagram="instagram";r.LinkedIn="linkedin";r.Mastodon="mastodon";r.Slack="slack";r.Twitter="twitter";r.YouTube="youtube"})(s||={});var l;((n)=>{n[n.Success=0]="Success";n[n.FatalError=1]="FatalError";n[n.InvalidArgument=9]="InvalidArgument"})(l||={});import{toString as p}from"@stacksjs/strings";function y(e){if(e===null)return"null";let o=p(e).slice(8,-1).toLowerCase();return typeof e==="object"||typeof e==="function"?o:typeof e}function h(e){return e}function T(e){return e}var C={development:{default:"sync",connections:{sync:{driver:"sync"}},failed:{driver:"database",table:"failed_jobs"}},production:{default:"redis",connections:{redis:{driver:"redis",prefix:"stacks:queue",concurrency:5,distributedLock:!0,metrics:{enabled:!0},defaultDeadLetterOptions:{enabled:!0,maxRetries:3}}},failed:{driver:"redis",prefix:"stacks:failed"},worker:{concurrency:5,shutdownTimeout:30000}},highPerformance:{default:"redis",connections:{redis:{driver:"redis",prefix:"stacks:queue",concurrency:20,distributedLock:!0,metrics:{enabled:!0,collectInterval:5000},horizontalScaling:{enabled:!0,maxWorkersPerInstance:20,jobsPerWorker:50},defaultDeadLetterOptions:{enabled:!0,maxRetries:5}}},failed:{driver:"redis",prefix:"stacks:failed"},worker:{concurrency:20,shutdownTimeout:60000}},database:{default:"database",connections:{database:{driver:"database",table:"jobs",queue:"default",retryAfter:90}},failed:{driver:"database",table:"failed_jobs"}}};var M={server:{development:{enabled:!0,mode:"server",debug:!0,server:{host:"localhost",port:6001,scheme:"ws",driver:"bun",rateLimit:{enabled:!1},healthCheck:{enabled:!0,path:"/health"}},channels:{public:!0,private:!0,presence:!0}},production:{enabled:!0,mode:"server",debug:!1,server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",redis:{enabled:!0,prefix:"stacks:realtime:"},rateLimit:{enabled:!0,maxConnectionsPerIp:100,maxMessagesPerSecond:50,maxPayloadSize:65536},loadManagement:{maxConnections:1e4,backpressureThreshold:1000,messageQueueSize:1e4,gracefulShutdownTimeout:30000},autoScaling:{min:2,max:10,targetCPU:70},healthCheck:{enabled:!0,path:"/health",interval:30},metrics:{enabled:!0,port:9090,path:"/metrics"}},channels:{public:!0,private:!0,presence:!0}},highPerformance:{enabled:!0,mode:"server",server:{driver:"bun",redis:{enabled:!0,cluster:!0},rateLimit:{enabled:!0,maxConnectionsPerIp:500,maxMessagesPerSecond:200,maxPayloadSize:131072},loadManagement:{maxConnections:1e5,backpressureThreshold:5000,messageQueueSize:50000,gracefulShutdownTimeout:60000},autoScaling:{min:4,max:50,targetCPU:60}}},chat:{enabled:!0,mode:"server",server:{driver:"bun",redis:{enabled:!0},rateLimit:{enabled:!0,maxConnectionsPerIp:10,maxMessagesPerSecond:20},loadManagement:{maxConnections:50000}},channels:{public:!0,private:!0,presence:{enabled:!0,maxMembersPerChannel:500,memberInfoTtl:60}}},gaming:{enabled:!0,mode:"server",server:{driver:"bun",redis:{enabled:!0,cluster:!0},rateLimit:{enabled:!0,maxConnectionsPerIp:50,maxMessagesPerSecond:100},loadManagement:{maxConnections:50000,backpressureThreshold:2000,messageQueueSize:20000},autoScaling:{min:2,max:20,targetCPU:50}},channels:{public:!0,private:!0,presence:!0}}},serverless:{development:{enabled:!0,mode:"serverless",debug:!0,serverless:{connectionTimeout:3600,idleTimeout:600,stageName:"dev",memorySize:256,timeout:30},channels:{public:!0,private:!0,presence:!0}},production:{enabled:!0,mode:"serverless",debug:!1,serverless:{connectionTimeout:3600,idleTimeout:600,stageName:"production",memorySize:512,timeout:30,provisionedConcurrency:2},channels:{public:!0,private:!0,presence:!0}},notifications:{enabled:!0,mode:"serverless",serverless:{connectionTimeout:7200,idleTimeout:1800,memorySize:256,timeout:15},channels:{public:!0,private:!0,presence:!1}}}};var S={calendar:{github:"stacksjs/calendar",package:"@stacksjs/calendar",description:"Calendar links, ICS generation, and an STX calendar component"},table:{github:"stacksjs/table",package:"@stacksjs/table",description:"Typed table drivers and an STX data table component"}};export{i as Every,l as ExitCode,C as QueuePresets,M as RealtimePresets,s as SocialLinkIcon,h as defineModel,T as defineModels,y as getTypeName,a as isAccessToken,d as isOAuthClient,c as isPersonalAccessToken,S as stackExtensionRegistry};
package/dist/request.d.ts CHANGED
@@ -1,18 +1,27 @@
1
1
  import { User } from '@stacksjs/orm';
2
2
  import type { AuthToken } from '@stacksjs/types';
3
- import type { Infer } from '@stacksjs/ts-validation';
3
+ import type { Infer, IsRequired } from '@stacksjs/ts-validation';
4
4
  import type { UploadedFile } from '@stacksjs/storage';
5
5
  declare interface RequestData {
6
6
  [key: string]: any
7
7
  }
8
8
  /**
9
9
  * Cookie-access helper exposed via `request.cookies` on
10
- * {@link RequestInstance}. The methods mirror bun-router's
11
- * `CookieAccessor` — duplicated locally so this package doesn't
12
- * have to depend on bun-router for a single type. Keep the surface
13
- * in sync if bun-router extends its accessor.
10
+ * {@link RequestInstance}. Mirrors bun-router's `CookieAccessor` —
11
+ * duplicated locally so this package doesn't have to depend on bun-router
12
+ * for a single type.
13
+ *
14
+ * "Keep the surface in sync" used to be the whole instruction here, and it
15
+ * drifted the moment bun-router's accessor grew: the runtime object is
16
+ * callable and carries its entries directly, and this said it was four
17
+ * methods. A comment cannot notice that. `cookie-accessor-parity.test-d.ts`
18
+ * in `@stacksjs/router` — a package that already depends on bun-router — now
19
+ * asserts the two are mutually assignable, so drift is a build failure
20
+ * instead of a note.
14
21
  */
15
22
  export declare interface RequestCookies {
23
+ (): Record<string, string>
24
+ [name: string]: unknown
16
25
  get: (name: string) => string | undefined
17
26
  set: (name: string, value: string, options?: {
18
27
  path?: string
@@ -80,9 +89,9 @@ export declare interface RequestInstance<TFields extends Record<string, any> = R
80
89
  body?: ReadableStream<Uint8Array> | null
81
90
  getUrl?: () => string
82
91
  cookies?: RequestCookies
83
- get<K extends keyof TFields & string>(key: K, defaultValue?: TFields[K]): TFields[K]
92
+ get<K extends keyof TInput<TFields, TParams> & string>(key: K, defaultValue?: TInput<TFields, TParams>[K]): TInput<TFields, TParams>[K]
84
93
  get<T = any>(key: string, defaultValue?: T): T
85
- input<K extends keyof TFields & string>(key: K, defaultValue?: TFields[K]): TFields[K]
94
+ input<K extends keyof TInput<TFields, TParams> & string>(key: K, defaultValue?: TInput<TFields, TParams>[K]): TInput<TFields, TParams>[K]
86
95
  input<T = any>(key: string, defaultValue?: T): T
87
96
  all: () => TFields
88
97
  only<K extends keyof TFields & string>(keys: K[]): Pick<TFields, K>
@@ -236,9 +245,64 @@ export type ActionRequest<TFields extends Record<string, any> = Record<string, a
236
245
  * type Body = InferValidations<typeof validations>
237
246
  * // → { email: string, password: string, remember: boolean }
238
247
  */
239
- export type InferValidations<V extends Record<string, { rule: any }>> = {
240
- [K in keyof V]: Infer<V[K]['rule']>
241
- }
248
+ /**
249
+ * Resolve a computed type to its final shape, for display.
250
+ *
251
+ * A named alias over a generic is shown by TypeScript as the alias: hovering
252
+ * `handle`'s parameter reported
253
+ *
254
+ * InferValidations<{ id: { rule: WithConditionals<NumberValidatorType> }; … }>
255
+ *
256
+ * which is the machinery, not the answer. It says nothing about what `id`
257
+ * actually is - the reader has to go and resolve it themselves, which is
258
+ * exactly the work the inference was supposed to save. Mapping the type through
259
+ * a fresh object literal forces it to be displayed evaluated, so the same hover
260
+ * reports `{ id: number, name: string }`.
261
+ *
262
+ * Display only: `Resolved<T>` and `T` are the same type.
263
+ */
264
+ export type Resolved<T> = T extends infer U ? { [K in keyof U]: U[K] } : never;
265
+ /**
266
+ * The shape a set of validation rules describes.
267
+ *
268
+ * Optionality comes from the rules themselves: a field whose rule went through
269
+ * `.required()` is a required key, and everything else is optional. Before
270
+ * ts-validation 0.5.6 there was nothing to read - `required()` returned `this`
271
+ * and `isRequired` was a runtime boolean - so every field typed as present,
272
+ * including the ones a handler has to guard. `user.name` was `string` on a
273
+ * payload where it could be absent, which is the type saying something the
274
+ * runtime does not.
275
+ *
276
+ * Written as two mapped types rather than one with an optional modifier,
277
+ * because `?` cannot be applied conditionally per key.
278
+ */
279
+ export type InferValidations<V extends Record<string, { rule: any }>> = Resolved<
280
+ & { [K in keyof V as IsRequired<V[K]['rule']> extends true ? K : never]: Infer<V[K]['rule']> }
281
+ & { [K in keyof V as IsRequired<V[K]['rule']> extends true ? never : K]?: Infer<V[K]['rule']> }
282
+ >;
283
+ /**
284
+ * What `get()` and `input()` can actually be asked for.
285
+ *
286
+ * They read one merged bag — `getAllInputFor` folds query, then body, then
287
+ * route params, in that order — so a path param is as reachable through
288
+ * `request.get('id')` as a validated body field is. The declarations were keyed
289
+ * on `TFields` alone, which meant `request.params.id` was `string` while
290
+ * `request.get('id')` right beside it was `any`: the same value, typed on one
291
+ * route and not the other.
292
+ *
293
+ * Params override fields where the names collide, because that is the order the
294
+ * runtime merges in.
295
+ */
296
+ export type TInput<TFields extends Record<string, any>, TParams extends Record<string, string>,> = string extends keyof TParams
297
+ /*
298
+ * No path was declared, so `TParams` is the wide `Record<string, string>`
299
+ * default and its `keyof` is `string`. Merging that would `Omit` every key
300
+ * from `TFields` and leave the fields typed as strings - so an action with
301
+ * validations but no `path:` would have had its inferred body erased. When
302
+ * nothing is known about the params, the fields are the whole answer.
303
+ */
304
+ ? TFields
305
+ : Omit<TFields, keyof TParams> & TParams;
242
306
  export type RequestValidationRules = Record<string, string | {
243
307
  rule: { validate: (value: any) => any }
244
308
  message?: string | Record<string, string>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stacksjs/types",
3
3
  "type": "module",
4
- "version": "0.72.56",
4
+ "version": "0.72.60",
5
5
  "description": "The Stacks framework types.",
6
6
  "author": "Chris Breuer",
7
7
  "contributors": [
@@ -59,7 +59,7 @@
59
59
  "@stacksjs/bunpress": "^0.2.8",
60
60
  "@stacksjs/clapp": "^0.2.12",
61
61
  "@stacksjs/stx": "^0.2.219",
62
- "@stacksjs/ts-validation": "^0.5.5",
62
+ "@stacksjs/ts-validation": "^0.5.6",
63
63
  "bun-query-builder": "^0.2.53"
64
64
  },
65
65
  "peerDependencies": {
@@ -71,7 +71,7 @@
71
71
  }
72
72
  },
73
73
  "devDependencies": {
74
- "@stacksjs/validation": "0.72.56",
74
+ "@stacksjs/validation": "0.72.60",
75
75
  "better-dx": "^0.2.24",
76
76
  "meilisearch": "^0.59.0"
77
77
  },