@stacksjs/database 0.72.22 → 0.72.24
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/framework-schema.d.ts +2032 -0
- package/dist/framework-schema.js +0 -0
- package/dist/index.d.ts +2 -1
- package/dist/utils.d.ts +216 -108
- package/dist/utils.js +1 -1
- package/package.json +10 -10
|
File without changes
|
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,8 @@ export type {
|
|
|
10
10
|
PostgresConfig,
|
|
11
11
|
SqliteConfig,
|
|
12
12
|
} from './driver-config';
|
|
13
|
+
// Core database utilities and default instance
|
|
14
|
+
export type { FrameworkSchema } from './framework-schema';
|
|
13
15
|
export type { SchemaDriftColumn, SchemaDriftReport } from './schema-drift';
|
|
14
16
|
export type { DeclaredFK, FkAuditResult, FkOrphan, FkOrphanReport, LiveFK } from './fk-audit';
|
|
15
17
|
export type { DeclaredUnique, LiveUniqueIndex, UniqueAuditResult } from './unique-audit';
|
|
@@ -74,7 +76,6 @@ export {
|
|
|
74
76
|
mergeWithDefaults,
|
|
75
77
|
validateDriverConfig,
|
|
76
78
|
} from './driver-config';
|
|
77
|
-
// Core database utilities and default instance
|
|
78
79
|
export * from './utils';
|
|
79
80
|
// Types (compatibility layer for Kysely types)
|
|
80
81
|
export * from './types';
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { createQueryBuilder, setConfig } from '@stacksjs/query-builder';
|
|
2
|
+
import type { FrameworkSchema } from './framework-schema';
|
|
2
3
|
import type { QueryHooks } from '@stacksjs/query-builder';
|
|
3
4
|
export declare function acquireDbConfigLock(): Promise<() => void>;
|
|
4
5
|
// Function to initialize the config when it's available
|
|
5
6
|
export declare function initializeDbConfig(config: any): void;
|
|
6
7
|
export declare function createDatabaseQueryHooks(dispatch: (event: DatabaseQueryLogEvent) => void | Promise<void>): QueryHooks;
|
|
7
|
-
declare function ensureConfigLoaded(): Promise<void>;
|
|
8
8
|
export declare function ensureDatabaseConfigLoaded(): Promise<void>;
|
|
9
|
-
declare function getDb(): ReturnType<typeof createQueryBuilder>;
|
|
10
9
|
/**
|
|
11
10
|
* Discard every cached database client after the underlying query-builder
|
|
12
11
|
* connection is reset.
|
|
@@ -19,24 +18,46 @@ declare function getDb(): ReturnType<typeof createQueryBuilder>;
|
|
|
19
18
|
*/
|
|
20
19
|
export declare function resetDatabaseConnection(): void;
|
|
21
20
|
/**
|
|
22
|
-
*
|
|
21
|
+
* Fluent chain returned by entry-point methods like `selectFrom`/`updateTable`.
|
|
22
|
+
*
|
|
23
|
+
* bun-query-builder marks legacy chain methods (e.g. `selectAll`, `whereILike`,
|
|
24
|
+
* `selectAllRelations`) as optional in its declarations even though they're
|
|
25
|
+
* always present at runtime. Re-typing them here avoids forcing every call
|
|
26
|
+
* site to use `?.()` or `!` on the chain.
|
|
27
|
+
*
|
|
28
|
+
* **The chain carries its row type.** `TRow` comes from the augmented
|
|
29
|
+
* `DatabaseSchema` that `buddy generate:db-types` writes, so
|
|
30
|
+
* `db.selectFrom('users').executeTakeFirst()` answers a `users` row rather than
|
|
31
|
+
* `any` - and `select(['id', 'handle'])` narrows it to those two columns.
|
|
32
|
+
*
|
|
33
|
+
* Every terminal used to be `Promise<any>`, and the cost was not theoretical:
|
|
34
|
+
* an application on top of this ends up annotating every result `any` to say
|
|
35
|
+
* what it already knows, which is a thousand places the compiler has been told
|
|
36
|
+
* to stop looking. A row it cannot type is `Record<string, unknown>` instead -
|
|
37
|
+
* still a value the caller has to narrow, but one narrowing it is checked.
|
|
23
38
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* carve-outs exists.
|
|
39
|
+
* A join or an aliased select list widens the row to
|
|
40
|
+
* `Record<string, unknown>`: the shape then depends on the aliases rather than
|
|
41
|
+
* on any one table, and claiming otherwise would be worse than not knowing.
|
|
28
42
|
*/
|
|
29
|
-
declare function getReadDb(): ReturnType<typeof createQueryBuilder>;
|
|
30
43
|
/**
|
|
31
|
-
*
|
|
44
|
+
* State the shape of rows this package knows and the query cannot.
|
|
45
|
+
*
|
|
46
|
+
* A raw query answers `Record<string, unknown>` when the table is not in the
|
|
47
|
+
* generated `DatabaseSchema` - which is always true *inside* the framework,
|
|
48
|
+
* because an application's schema does not exist at framework build time. The
|
|
49
|
+
* package that ships the model does know the shape, and this is where that
|
|
50
|
+
* knowledge is written down: once, at the boundary, named and greppable.
|
|
51
|
+
*
|
|
52
|
+
* It is an assertion, and deliberately an obvious one. What it replaces is a
|
|
53
|
+
* `Promise<any>` that spread the same claim silently through every caller.
|
|
32
54
|
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* result. It still respects the transaction carve-out, because a read
|
|
36
|
-
* inside a transaction must see that transaction's own writes no matter
|
|
37
|
-
* how it was requested.
|
|
55
|
+
* Application code should not need it: `buddy generate:db-types` gives `db` the
|
|
56
|
+
* real column types, and a row that arrives typed does not want asserting.
|
|
38
57
|
*/
|
|
39
|
-
declare function
|
|
58
|
+
export declare function asRows<TRow>(rows: ReadonlyArray<Record<string, unknown>>): TRow[];
|
|
59
|
+
/** The single-row form of {@link asRows}. */
|
|
60
|
+
export declare function asRow<TRow>(row: Record<string, unknown> | undefined): TRow | undefined;
|
|
40
61
|
/**
|
|
41
62
|
* Update bun-query-builder configuration
|
|
42
63
|
*/
|
|
@@ -64,15 +85,11 @@ export declare const RAW_QUERY_SOFT_DELETE_CONFIG: {
|
|
|
64
85
|
column: 'deleted_at';
|
|
65
86
|
defaultFilter: true
|
|
66
87
|
};
|
|
67
|
-
/** Statements that mutate, for the read-your-writes tracking in `./replicas`. */
|
|
68
|
-
declare const WRITE_ENTRY_POINTS: Set<any>;
|
|
69
|
-
/** Reads that are candidates for replica routing. */
|
|
70
|
-
declare const READ_ENTRY_POINTS: Set<any>;
|
|
71
88
|
/**
|
|
72
89
|
* Lazy proxy for the query builder - connection is only made when first used.
|
|
73
90
|
* This is the main entry point for database operations.
|
|
74
91
|
*/
|
|
75
|
-
export declare const db:
|
|
92
|
+
export declare const db: Db;
|
|
76
93
|
/**
|
|
77
94
|
* Replica-routed handle exposed as `db.read`.
|
|
78
95
|
*
|
|
@@ -80,7 +97,7 @@ export declare const db: Proxy;
|
|
|
80
97
|
* available behind it (`db.read.selectFrom(...).where(...)`) without
|
|
81
98
|
* re-declaring every chain entry point.
|
|
82
99
|
*/
|
|
83
|
-
export declare const readDb:
|
|
100
|
+
export declare const readDb: Omit<Db, 'read'>;
|
|
84
101
|
export declare interface DatabaseQueryLogEvent {
|
|
85
102
|
query: {
|
|
86
103
|
sql: string
|
|
@@ -90,90 +107,97 @@ export declare interface DatabaseQueryLogEvent {
|
|
|
90
107
|
error?: unknown
|
|
91
108
|
}
|
|
92
109
|
/**
|
|
93
|
-
*
|
|
110
|
+
* What an insert reports when it was not asked to return rows.
|
|
94
111
|
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
112
|
+
* Every field optional and every one differently named, because drivers
|
|
113
|
+
* disagree: Postgres answers a count, SQLite a `changes`, MySQL an `insertId`.
|
|
114
|
+
* Typing this as the row - which is what the query builder's own declarations
|
|
115
|
+
* do - is how framework code came to read `insertId` off a value that is not a
|
|
116
|
+
* row and cannot have one.
|
|
99
117
|
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
* typing one step into a chain (the underlying query builder is constructed
|
|
103
|
-
* with no schema). Tests cover the runtime semantics.
|
|
118
|
+
* `returning(...)` is the way to get rows out of an insert, and it changes the
|
|
119
|
+
* chain's kind so the types follow.
|
|
104
120
|
*/
|
|
105
|
-
export declare interface
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
121
|
+
export declare interface InsertReceipt {
|
|
122
|
+
insertId?: number | bigint
|
|
123
|
+
numInsertedOrUpdatedRows?: number | bigint
|
|
124
|
+
numAffectedRows?: number | bigint
|
|
125
|
+
affectedRows?: number
|
|
126
|
+
changes?: number
|
|
127
|
+
}
|
|
128
|
+
export declare interface BaseFluentChain<TRow = Record<string, unknown>, TKind extends ChainKind = 'select'> {
|
|
129
|
+
where(callback: (eb: import('./types').StacksExpressionBuilder) => unknown): FluentChain<TRow, TKind>
|
|
130
|
+
where(...args: unknown[]): FluentChain<TRow, TKind>
|
|
131
|
+
whereNull: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
132
|
+
whereNotNull: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
133
|
+
whereIn: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
134
|
+
whereNotIn: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
135
|
+
whereLike: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
136
|
+
whereNotLike: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
137
|
+
whereILike: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
138
|
+
whereNotILike: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
139
|
+
whereBetween: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
140
|
+
whereNotBetween: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
141
|
+
whereRaw: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
142
|
+
whereColumn: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
143
|
+
orWhere: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
144
|
+
orWhereNull: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
145
|
+
orWhereNotNull: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
146
|
+
orWhereIn: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
147
|
+
orWhereNotIn: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
148
|
+
orWhereLike: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
149
|
+
orWhereNotLike: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
150
|
+
orWhereILike: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
151
|
+
orWhereColumn: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
152
|
+
andWhere: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
153
|
+
whereAny: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
154
|
+
whereAll: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
155
|
+
whereNone: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
156
|
+
having: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
157
|
+
groupBy: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
158
|
+
orderBy: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
159
|
+
limit: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
160
|
+
offset: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
161
|
+
select<K extends KnownKeys<TRow> & string>(columns: readonly K[]): FluentChain<Pick<TRow, K>, TKind>
|
|
162
|
+
select(selection: ((eb: import('./types').StacksExpressionBuilder) => unknown) | ReadonlyArray<string | ((eb: import('./types').StacksExpressionBuilder) => unknown) | unknown>): FluentChain<Record<string, unknown>, TKind>
|
|
163
|
+
select(...args: unknown[]): FluentChain<Record<string, unknown>, TKind>
|
|
164
|
+
selectAll: () => FluentChain<TRow, TKind>
|
|
165
|
+
selectAllRelations: () => FluentChain<Record<string, unknown>, TKind>
|
|
166
|
+
selectRaw: (...args: unknown[]) => FluentChain<Record<string, unknown>, TKind>
|
|
167
|
+
distinct: () => FluentChain<TRow, TKind>
|
|
168
|
+
distinctOn: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
169
|
+
innerJoin: (...args: unknown[]) => FluentChain<Record<string, unknown>, TKind>
|
|
170
|
+
leftJoin: (...args: unknown[]) => FluentChain<Record<string, unknown>, TKind>
|
|
171
|
+
rightJoin: (...args: unknown[]) => FluentChain<Record<string, unknown>, TKind>
|
|
172
|
+
fullJoin: (...args: unknown[]) => FluentChain<Record<string, unknown>, TKind>
|
|
173
|
+
crossJoin: (...args: unknown[]) => FluentChain<Record<string, unknown>, TKind>
|
|
174
|
+
with: (...args: unknown[]) => FluentChain<Record<string, unknown>, TKind>
|
|
175
|
+
union: (...args: unknown[]) => FluentChain<Record<string, unknown>, TKind>
|
|
176
|
+
unionAll: (...args: unknown[]) => FluentChain<Record<string, unknown>, TKind>
|
|
177
|
+
values: (values: Partial<TRow> | ReadonlyArray<Partial<TRow>> | object | readonly object[]) => FluentChain<TRow, TKind>
|
|
178
|
+
set: (values: Partial<TRow> | object) => FluentChain<TRow, TKind>
|
|
179
|
+
returning<K extends KnownKeys<TRow> & string>(columns: readonly K[]): FluentChain<Pick<TRow, K>, 'returning'>
|
|
180
|
+
returning(...args: unknown[]): FluentChain<Record<string, unknown>, 'returning'>
|
|
181
|
+
returningAll: () => FluentChain<TRow, 'returning'>
|
|
182
|
+
onConflict: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
183
|
+
onDuplicateKeyUpdate: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
184
|
+
onConflictDoNothing: (...args: unknown[]) => FluentChain<TRow, TKind>
|
|
185
|
+
onDuplicateKeyIgnore: () => FluentChain<TRow, TKind>
|
|
186
|
+
forUpdate: () => FluentChain<TRow, TKind>
|
|
187
|
+
forShare: () => FluentChain<TRow, TKind>
|
|
163
188
|
toSQL: () => string
|
|
164
|
-
execute: () => Promise<
|
|
165
|
-
executeTakeFirst: () => Promise<
|
|
166
|
-
executeTakeFirstOrThrow: () => Promise<
|
|
167
|
-
pluck: (...args:
|
|
168
|
-
count: (...args:
|
|
169
|
-
sum: (...args:
|
|
170
|
-
avg: (...args:
|
|
171
|
-
min: (...args:
|
|
172
|
-
max: (...args:
|
|
189
|
+
execute: () => Promise<ResultOf<TRow, TKind>>
|
|
190
|
+
executeTakeFirst: () => Promise<FirstOf<TRow, TKind>>
|
|
191
|
+
executeTakeFirstOrThrow: () => Promise<NonNullable<FirstOf<TRow, TKind>>>
|
|
192
|
+
pluck: (...args: unknown[]) => Promise<unknown[]>
|
|
193
|
+
count: (...args: unknown[]) => Promise<number>
|
|
194
|
+
sum: (...args: unknown[]) => Promise<number>
|
|
195
|
+
avg: (...args: unknown[]) => Promise<number>
|
|
196
|
+
min: (...args: unknown[]) => Promise<unknown>
|
|
197
|
+
max: (...args: unknown[]) => Promise<unknown>
|
|
173
198
|
exists: () => Promise<boolean>
|
|
174
199
|
doesntExist: () => Promise<boolean>
|
|
175
|
-
$call: (callback: (query: FluentChain) => FluentChain) => FluentChain
|
|
176
|
-
[key: string]: any
|
|
200
|
+
$call: (callback: (query: FluentChain<TRow, TKind>) => FluentChain<TRow, TKind>) => FluentChain<TRow, TKind>
|
|
177
201
|
}
|
|
178
202
|
/*.ts` and
|
|
179
203
|
* emits `database/types.d.ts` containing:
|
|
@@ -197,20 +221,83 @@ export declare interface FluentChain {
|
|
|
197
221
|
export declare interface DatabaseSchema {}
|
|
198
222
|
declare interface Db extends Pick<Required<RawQueryBuilder>, GenericPassthroughKeys> {
|
|
199
223
|
fn: import('./types').ExpressionFunctions
|
|
200
|
-
selectFrom: (table:
|
|
201
|
-
insertInto: (table:
|
|
202
|
-
updateTable: (table:
|
|
203
|
-
deleteFrom: (table:
|
|
204
|
-
table: (table:
|
|
205
|
-
selectFromSub: (sub:
|
|
206
|
-
select: (table:
|
|
207
|
-
unsafe: (query: string, params?:
|
|
224
|
+
selectFrom: <T extends TableName>(table: T) => FluentChain<RowOf<T>, 'select'>
|
|
225
|
+
insertInto: <T extends TableName>(table: T) => FluentChain<RowOf<T>, 'insert'>
|
|
226
|
+
updateTable: <T extends TableName>(table: T) => FluentChain<RowOf<T>, 'update'>
|
|
227
|
+
deleteFrom: <T extends TableName>(table: T) => FluentChain<RowOf<T>, 'delete'>
|
|
228
|
+
table: <T extends TableName>(table: T) => FluentChain<RowOf<T>, 'select'>
|
|
229
|
+
selectFromSub: (sub: unknown, alias: string) => FluentChain<Record<string, unknown>>
|
|
230
|
+
select: <T extends TableName>(table: T, ...columns: string[]) => FluentChain<Record<string, unknown>>
|
|
231
|
+
unsafe: (query: string, params?: unknown[]) => UnsafeReturn
|
|
208
232
|
read: Omit<Db, 'read'>
|
|
209
233
|
}
|
|
210
234
|
// The bun-query-builder types `unsafe()` as returning `Promise<any>`, but at
|
|
211
235
|
// runtime it returns a Bun SQL Statement that has `.execute()`. This interface
|
|
212
236
|
// corrects the return type so callers can chain `.execute()` without type errors.
|
|
213
237
|
declare type UnsafeReturn = Promise<any> & { execute: () => Promise<any> }
|
|
238
|
+
/**
|
|
239
|
+
* The keys a row type actually declares, or `never` for a loose record.
|
|
240
|
+
*
|
|
241
|
+
* `keyof Record<string, unknown>` is `string`, so a narrowing overload written
|
|
242
|
+
* against it will happily accept *anything* as a column - including
|
|
243
|
+
* `'menu_items.id as id'`, which then becomes a property name in the result
|
|
244
|
+
* type. That is worse than not narrowing: the row type looks specific and every
|
|
245
|
+
* key in it is fiction.
|
|
246
|
+
*/
|
|
247
|
+
export type KnownKeys<T> = string extends keyof T ? never : keyof T;
|
|
248
|
+
/**
|
|
249
|
+
* Which verb started a chain, so its terminals can answer the right thing.
|
|
250
|
+
*
|
|
251
|
+
* `returning` is its own kind rather than a flag on the others: a mutation with
|
|
252
|
+
* `RETURNING` answers rows, and that is the difference between reading
|
|
253
|
+
* `rows[0].id` and reading a count.
|
|
254
|
+
*/
|
|
255
|
+
export type ChainKind = 'select' | 'insert' | 'update' | 'delete' | 'returning';
|
|
256
|
+
/** What `execute()` resolves to for each verb. */
|
|
257
|
+
export type ResultOf<TRow, TKind extends ChainKind> = TKind extends 'select' | 'returning'
|
|
258
|
+
? TRow[]
|
|
259
|
+
: number;
|
|
260
|
+
/**
|
|
261
|
+
* What `executeTakeFirst()` resolves to for each verb.
|
|
262
|
+
*
|
|
263
|
+
* The counts are *required*, because the runtime always sets them: an update
|
|
264
|
+
* that changed nothing answers `{ numUpdatedRows: 0 }`. Declaring them optional
|
|
265
|
+
* would make every caller write `?? 0` for a case that cannot happen.
|
|
266
|
+
*/
|
|
267
|
+
export type FirstOf<TRow, TKind extends ChainKind> = TKind extends 'select' | 'returning'
|
|
268
|
+
? TRow | undefined
|
|
269
|
+
: TKind extends 'insert'
|
|
270
|
+
? InsertReceipt | undefined
|
|
271
|
+
: TKind extends 'update'
|
|
272
|
+
? { numUpdatedRows: number }
|
|
273
|
+
: { numDeletedRows: number }
|
|
274
|
+
/** `created_at` -> `CreatedAt`, for the dynamic helper names below. */
|
|
275
|
+
declare type SnakeToPascal<S extends string> = S extends `${infer Head}_${infer Tail}`
|
|
276
|
+
? `${Capitalize<Head>}${SnakeToPascal<Tail>}`
|
|
277
|
+
: Capitalize<S>;
|
|
278
|
+
/**
|
|
279
|
+
* The dynamic `where<Column>` helpers bun-query-builder generates.
|
|
280
|
+
*
|
|
281
|
+
* Derived from the row type rather than allowed by an index signature. The
|
|
282
|
+
* index signature that used to be here (`[key: string]: any`) made every
|
|
283
|
+
* misspelling legal and every result `any`: `whereHndle('a')` compiled, and so
|
|
284
|
+
* did reading a property that does not exist.
|
|
285
|
+
*/
|
|
286
|
+
export type DynamicWhereMethods<TRow, TKind extends ChainKind = 'select'> = {
|
|
287
|
+
[K in keyof TRow & string as `where${SnakeToPascal<K>}`]: (value: TRow[K]) => FluentChain<TRow, TKind>
|
|
288
|
+
} & {
|
|
289
|
+
[K in keyof TRow & string as `orWhere${SnakeToPascal<K>}`]: (value: TRow[K]) => FluentChain<TRow, TKind>
|
|
290
|
+
} & {
|
|
291
|
+
[K in keyof TRow & string as `andWhere${SnakeToPascal<K>}`]: (value: TRow[K]) => FluentChain<TRow, TKind>
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* A chain over one table's rows: the methods, plus the generated helpers.
|
|
295
|
+
*
|
|
296
|
+
* A type alias rather than an interface because the helper half is a mapped
|
|
297
|
+
* type over `TRow`, and an interface can only extend members TypeScript knows
|
|
298
|
+
* statically.
|
|
299
|
+
*/
|
|
300
|
+
export type FluentChain<TRow = Record<string, unknown>, TKind extends ChainKind = 'select'> = BaseFluentChain<TRow, TKind> & DynamicWhereMethods<TRow, TKind>;
|
|
214
301
|
/**
|
|
215
302
|
* Top-level surface of the lazy `db` proxy. Methods that return a chainable
|
|
216
303
|
* builder are typed as `FluentChain` to flatten the optional-method noise
|
|
@@ -261,7 +348,28 @@ declare type GenericPassthroughKeys = | 'transaction'
|
|
|
261
348
|
* well-documented LiteralUnion trick.
|
|
262
349
|
*/
|
|
263
350
|
// eslint-disable-next-line ts/no-empty-object-type
|
|
264
|
-
export type TableName = (keyof DatabaseSchema & string) | (string & {});
|
|
351
|
+
export type TableName = (keyof DatabaseSchema & string) | (keyof FrameworkSchema & string) | (string & {});
|
|
352
|
+
/**
|
|
353
|
+
* The row type of a registered table, or an unknown-valued record.
|
|
354
|
+
*
|
|
355
|
+
* A table the generated `DatabaseSchema` knows answers its own columns. One it
|
|
356
|
+
* does not - an app that has never run `buddy generate:db-types`, or a table
|
|
357
|
+
* that lives outside a model - answers `Record<string, unknown>`: still a value
|
|
358
|
+
* the caller narrows, but narrowing it is checked rather than waved through.
|
|
359
|
+
*/
|
|
360
|
+
export type RowOf<T extends TableName> = T extends keyof DatabaseSchema
|
|
361
|
+
? Shape<DatabaseSchema[T]>
|
|
362
|
+
: T extends keyof FrameworkSchema
|
|
363
|
+
? Shape<FrameworkSchema[T]>
|
|
364
|
+
: Record<string, unknown>;
|
|
365
|
+
/**
|
|
366
|
+
* A generated entry, whichever of the two shapes it was written in.
|
|
367
|
+
*
|
|
368
|
+
* The app generator has emitted a flat column record for a while; the
|
|
369
|
+
* `{ columns }` form is what the query builder's own schema type uses. Both are
|
|
370
|
+
* accepted so an app does not have to regenerate to keep compiling.
|
|
371
|
+
*/
|
|
372
|
+
declare type Shape<T> = T extends { columns: infer C } ? C : T;
|
|
265
373
|
// SQLite bootstrap pragmas (stacksjs/stacks#1951) now live in
|
|
266
374
|
// @stacksjs/query-builder — the one chokepoint every framework
|
|
267
375
|
// query-builder instance is created through — so EVERY fresh sqlite
|
package/dist/utils.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{AsyncLocalStorage}from"node:async_hooks";import{createQueryBuilder,registerPersistentQueryHooks,resetConnection as resetQueryBuilderConnection,setConfig}from"@stacksjs/query-builder";import{SQL}from"bun";import{env as envVars}from"@stacksjs/env";import{getConnectionDefaults}from"./defaults";import{isMysqlWire,isVitessSharded,toQueryBuilderDialect}from"./dialect";import{relativeMigrationDirectory,resolveMigrationDirectory}from"./migration-path";import{contextInTransaction,markContextWrote,resolveReplicaConnection,selectReplica,shouldRouteToReplica,withTransactionContext}from"./replicas";import{aggregateFunctions}from"./types";const sqliteDefaults=getConnectionDefaults("sqlite",envVars),mysqlDefaults=getConnectionDefaults("mysql",envVars),postgresDefaults=getConnectionDefaults("postgres",envVars);let appEnv=envVars.APP_ENV||"local",dbDriver=envVars.DB_CONNECTION||"sqlite",dbConfig={connections:{sqlite:{database:sqliteDefaults.database,prefix:""},mysql:{name:mysqlDefaults.database,host:mysqlDefaults.host,username:mysqlDefaults.username,password:mysqlDefaults.password,port:mysqlDefaults.port,prefix:""},singlestore:{name:mysqlDefaults.database,host:mysqlDefaults.host,username:mysqlDefaults.username,password:mysqlDefaults.password,port:mysqlDefaults.port,prefix:""},vitess:{name:mysqlDefaults.database,host:mysqlDefaults.host,username:mysqlDefaults.username,password:mysqlDefaults.password,port:15306,prefix:"",sharded:isVitessSharded()},postgres:{name:postgresDefaults.database,host:postgresDefaults.host,username:postgresDefaults.username,password:postgresDefaults.password,port:postgresDefaults.port,prefix:""}}},dbConfigLockTail=Promise.resolve();export function acquireDbConfigLock(){let release=()=>{};const held=new Promise((resolve)=>{release=resolve}),acquired=dbConfigLockTail.then(()=>release);dbConfigLockTail=dbConfigLockTail.then(()=>held);return acquired}export function initializeDbConfig(config){if(config?.app?.env)appEnv=config.app.env;if(config?.database?.default)dbDriver=config.database.default;if(config?.database)dbConfig=config.database;updateQueryBuilderConfig();_dbInstance=null;_replicaInstances=new Map}function getEnv(){return appEnv}function getDriver(){return dbDriver}function getDatabaseConfig(){return dbConfig}function getDialect(){return toQueryBuilderDialect(getDriver())}function getDbConfig(){const driver=getDriver(),database=getDatabaseConfig(),env=getEnv();if(driver==="sqlite"){const defaultName=env!=="testing"?"database/stacks.sqlite":"database/stacks_testing.sqlite";return{database:database.connections?.sqlite?.database??defaultName}}if(driver==="mysql")return{database:database.connections?.mysql?.name||"stacks",host:database.connections?.mysql?.host??"127.0.0.1",username:database.connections?.mysql?.username??"root",password:database.connections?.mysql?.password??"",port:database.connections?.mysql?.port??3306};if(driver==="singlestore")return{database:database.connections?.singlestore?.name||"stacks",host:database.connections?.singlestore?.host??"127.0.0.1",username:database.connections?.singlestore?.username??"root",password:database.connections?.singlestore?.password??"",port:database.connections?.singlestore?.port??3306};if(driver==="vitess")return{database:database.connections?.vitess?.name||"stacks",host:database.connections?.vitess?.host??"127.0.0.1",username:database.connections?.vitess?.username??"root",password:database.connections?.vitess?.password??"",port:database.connections?.vitess?.port??15306};if(driver==="postgres"){const dbName=database.connections?.postgres?.name??"stacks";return{database:env==="testing"?`${dbName}_testing`:dbName,host:database.connections?.postgres?.host??"127.0.0.1",username:database.connections?.postgres?.username??"",password:database.connections?.postgres?.password??"",port:database.connections?.postgres?.port??5432}}return{database:":memory:"}}export const QB_SNAPSHOT_DIR="storage/framework/database",RAW_QUERY_SOFT_DELETE_CONFIG={enabled:!1,column:"deleted_at",defaultFilter:!0};export function createDatabaseQueryHooks(dispatch){function forward(event){try{Promise.resolve(dispatch(event)).catch(()=>{})}catch{}}return{onQueryEnd:(event)=>forward({query:{sql:event.sql,parameters:event.params},queryDurationMillis:event.durationMs}),onQueryError:(event)=>forward({query:{sql:event.sql,parameters:event.params},queryDurationMillis:event.durationMs,error:event.error})}}function forwardDatabaseQuery(event){import("./query-logger").then(({logQuery})=>logQuery(event)).catch(()=>{})}registerPersistentQueryHooks(createDatabaseQueryHooks(forwardDatabaseQuery));function getPoolConfig(){const driver=getDriver();if(driver==="sqlite")return;return getDatabaseConfig().connections?.[driver]?.pool}function getReplicas(){const driver=getDriver();if(driver==="sqlite")return[];return getDatabaseConfig().connections?.[driver]?.replicas??[]}function getReadPolicy(){return getDatabaseConfig().reads??{}}function toBunPoolOptions(pool){if(!pool)return{};const options={};if(pool.max!==void 0)options.max=pool.max;if(pool.idleTimeoutMs!==void 0)options.idleTimeout=Math.round(pool.idleTimeoutMs/1000);if(pool.acquireTimeoutMs!==void 0)options.connectionTimeout=Math.round(pool.acquireTimeoutMs/1000);if(pool.maxLifetimeMs!==void 0)options.maxLifetime=Math.round(pool.maxLifetimeMs/1000);return options}function updateQueryBuilderConfig(){const dialect=getDialect(),dbConfigForQb=getDbConfig(),pool=getPoolConfig();setConfig({dialect,vitess:{sharded:isVitessSharded(dbConfig.connections.vitess?.sharded)},database:pool?{...dbConfigForQb,pool}:dbConfigForQb,verbose:getEnv()!=="production",snapshotDir:QB_SNAPSHOT_DIR,migrationDir:relativeMigrationDirectory(resolveMigrationDirectory(toQueryBuilderDialect(dialect),{snapshotDir:QB_SNAPSHOT_DIR})),timestamps:{createdAt:"created_at",updatedAt:"updated_at",defaultOrderColumn:"created_at"},softDeletes:RAW_QUERY_SOFT_DELETE_CONFIG})}updateQueryBuilderConfig();let _dbInstance=null,_configInitPromise=null;function ensureConfigLoaded(){if(!_configInitPromise)_configInitPromise=(async()=>{try{const{config,overridesReady}=await import("@stacksjs/config");await overridesReady;if(config){initializeDbConfig(config);_dbInstance=null}}catch{}})();return _configInitPromise}export async function ensureDatabaseConfigLoaded(){await ensureConfigLoaded()}export{applySqlitePragmas,SQLITE_BOOTSTRAP_PRAGMAS}from"@stacksjs/query-builder";const sqliteTxOwner=new AsyncLocalStorage;let sqliteTxTail=Promise.resolve();function serializeSqliteTransaction(run){if(sqliteTxOwner.getStore())return run();const result=sqliteTxTail.then(()=>sqliteTxOwner.run(!0,run));sqliteTxTail=result.then(()=>{return},()=>{return});return result}function applySqliteTransactionSerialization(instance){const original=instance.transaction.bind(instance);instance.transaction=(...args)=>serializeSqliteTransaction(()=>original(...args))}function applyTransactionRoutingContext(instance){const original=instance.transaction.bind(instance);instance.transaction=(...args)=>withTransactionContext(()=>original(...args))}function getDb(){if(!_dbInstance){updateQueryBuilderConfig();_dbInstance=createQueryBuilder();if(getDialect()==="sqlite")applySqliteTransactionSerialization(_dbInstance);applyTransactionRoutingContext(_dbInstance)}return _dbInstance}let _replicaInstances=new Map;export function resetDatabaseConnection(){resetQueryBuilderConnection();_dbInstance=null;_replicaInstances=new Map}function getReplicaDb(replica){const primary=getDbConfig(),resolved=resolveReplicaConnection(replica,primary),key=`${resolved.host}:${resolved.port??""}`,cached=_replicaInstances.get(key);if(cached)return cached;const scheme=isMysqlWire(getDriver())?"mysql":"postgres",auth=resolved.username?`${encodeURIComponent(resolved.username)}:${encodeURIComponent(resolved.password??"")}@`:"",url=`${scheme}://${auth}${resolved.host}:${resolved.port}/${resolved.database}`,sql=new SQL({url,...toBunPoolOptions(getPoolConfig())}),instance=createQueryBuilder({sql});_replicaInstances.set(key,instance);return instance}function getReadDb(){const replicas=getReplicas(),policy=getReadPolicy();if(!shouldRouteToReplica({policy,replicas}))return getDb();const replica=selectReplica(replicas,policy.strategy);return replica?getReplicaDb(replica):getDb()}function getExplicitReadDb(){const replicas=getReplicas();if(!replicas.length||contextInTransaction())return getDb();const replica=selectReplica(replicas,getReadPolicy().strategy);return replica?getReplicaDb(replica):getDb()}const WRITE_ENTRY_POINTS=new Set(["insertInto","updateTable","deleteFrom","create","createMany","insertOrIgnore","insertGetId","updateOrInsert","upsert"]),READ_ENTRY_POINTS=new Set(["selectFrom","selectFromSub","select"]);ensureConfigLoaded();export const db=new Proxy({},{get(_target,prop){if(prop==="fn")return aggregateFunctions;if(prop==="read")return readDb;if(typeof prop==="string"&&WRITE_ENTRY_POINTS.has(prop))markContextWrote();const instance=typeof prop==="string"&&READ_ENTRY_POINTS.has(prop)?getReadDb():getDb(),value=instance[prop];if(typeof value==="function")return value.bind(instance);return value}}),readDb=new Proxy({},{get(_target,prop){if(prop==="fn")return aggregateFunctions;const instance=getExplicitReadDb(),value=instance[prop];if(typeof value==="function")return value.bind(instance);return value}});export{setConfig};
|
|
1
|
+
import{AsyncLocalStorage}from"node:async_hooks";import{createQueryBuilder,registerPersistentQueryHooks,resetConnection as resetQueryBuilderConnection,setConfig}from"@stacksjs/query-builder";import{SQL}from"bun";import{env as envVars}from"@stacksjs/env";import{getConnectionDefaults}from"./defaults";import{isMysqlWire,isVitessSharded,toQueryBuilderDialect}from"./dialect";import{relativeMigrationDirectory,resolveMigrationDirectory}from"./migration-path";import{contextInTransaction,markContextWrote,resolveReplicaConnection,selectReplica,shouldRouteToReplica,withTransactionContext}from"./replicas";import{aggregateFunctions}from"./types";const sqliteDefaults=getConnectionDefaults("sqlite",envVars),mysqlDefaults=getConnectionDefaults("mysql",envVars),postgresDefaults=getConnectionDefaults("postgres",envVars);let appEnv=envVars.APP_ENV||"local",dbDriver=envVars.DB_CONNECTION||"sqlite",dbConfig={connections:{sqlite:{database:sqliteDefaults.database,prefix:""},mysql:{name:mysqlDefaults.database,host:mysqlDefaults.host,username:mysqlDefaults.username,password:mysqlDefaults.password,port:mysqlDefaults.port,prefix:""},singlestore:{name:mysqlDefaults.database,host:mysqlDefaults.host,username:mysqlDefaults.username,password:mysqlDefaults.password,port:mysqlDefaults.port,prefix:""},vitess:{name:mysqlDefaults.database,host:mysqlDefaults.host,username:mysqlDefaults.username,password:mysqlDefaults.password,port:15306,prefix:"",sharded:isVitessSharded()},postgres:{name:postgresDefaults.database,host:postgresDefaults.host,username:postgresDefaults.username,password:postgresDefaults.password,port:postgresDefaults.port,prefix:""}}},dbConfigLockTail=Promise.resolve();export function acquireDbConfigLock(){let release=()=>{};const held=new Promise((resolve)=>{release=resolve}),acquired=dbConfigLockTail.then(()=>release);dbConfigLockTail=dbConfigLockTail.then(()=>held);return acquired}export function initializeDbConfig(config){if(config?.app?.env)appEnv=config.app.env;if(config?.database?.default)dbDriver=config.database.default;if(config?.database)dbConfig=config.database;updateQueryBuilderConfig();_dbInstance=null;_replicaInstances=new Map}function getEnv(){return appEnv}function getDriver(){return dbDriver}function getDatabaseConfig(){return dbConfig}function getDialect(){return toQueryBuilderDialect(getDriver())}function getDbConfig(){const driver=getDriver(),database=getDatabaseConfig(),env=getEnv();if(driver==="sqlite"){const defaultName=env!=="testing"?"database/stacks.sqlite":"database/stacks_testing.sqlite";return{database:database.connections?.sqlite?.database??defaultName}}if(driver==="mysql")return{database:database.connections?.mysql?.name||"stacks",host:database.connections?.mysql?.host??"127.0.0.1",username:database.connections?.mysql?.username??"root",password:database.connections?.mysql?.password??"",port:database.connections?.mysql?.port??3306};if(driver==="singlestore")return{database:database.connections?.singlestore?.name||"stacks",host:database.connections?.singlestore?.host??"127.0.0.1",username:database.connections?.singlestore?.username??"root",password:database.connections?.singlestore?.password??"",port:database.connections?.singlestore?.port??3306};if(driver==="vitess")return{database:database.connections?.vitess?.name||"stacks",host:database.connections?.vitess?.host??"127.0.0.1",username:database.connections?.vitess?.username??"root",password:database.connections?.vitess?.password??"",port:database.connections?.vitess?.port??15306};if(driver==="postgres"){const dbName=database.connections?.postgres?.name??"stacks";return{database:env==="testing"?`${dbName}_testing`:dbName,host:database.connections?.postgres?.host??"127.0.0.1",username:database.connections?.postgres?.username??"",password:database.connections?.postgres?.password??"",port:database.connections?.postgres?.port??5432}}return{database:":memory:"}}export const QB_SNAPSHOT_DIR="storage/framework/database",RAW_QUERY_SOFT_DELETE_CONFIG={enabled:!1,column:"deleted_at",defaultFilter:!0};export function createDatabaseQueryHooks(dispatch){function forward(event){try{Promise.resolve(dispatch(event)).catch(()=>{})}catch{}}return{onQueryEnd:(event)=>forward({query:{sql:event.sql,parameters:event.params},queryDurationMillis:event.durationMs}),onQueryError:(event)=>forward({query:{sql:event.sql,parameters:event.params},queryDurationMillis:event.durationMs,error:event.error})}}function forwardDatabaseQuery(event){import("./query-logger").then(({logQuery})=>logQuery(event)).catch(()=>{})}registerPersistentQueryHooks(createDatabaseQueryHooks(forwardDatabaseQuery));function getPoolConfig(){const driver=getDriver();if(driver==="sqlite")return;return getDatabaseConfig().connections?.[driver]?.pool}function getReplicas(){const driver=getDriver();if(driver==="sqlite")return[];return getDatabaseConfig().connections?.[driver]?.replicas??[]}function getReadPolicy(){return getDatabaseConfig().reads??{}}function toBunPoolOptions(pool){if(!pool)return{};const options={};if(pool.max!==void 0)options.max=pool.max;if(pool.idleTimeoutMs!==void 0)options.idleTimeout=Math.round(pool.idleTimeoutMs/1000);if(pool.acquireTimeoutMs!==void 0)options.connectionTimeout=Math.round(pool.acquireTimeoutMs/1000);if(pool.maxLifetimeMs!==void 0)options.maxLifetime=Math.round(pool.maxLifetimeMs/1000);return options}function updateQueryBuilderConfig(){const dialect=getDialect(),dbConfigForQb=getDbConfig(),pool=getPoolConfig();setConfig({dialect,vitess:{sharded:isVitessSharded(dbConfig.connections.vitess?.sharded)},database:pool?{...dbConfigForQb,pool}:dbConfigForQb,verbose:getEnv()!=="production",snapshotDir:QB_SNAPSHOT_DIR,migrationDir:relativeMigrationDirectory(resolveMigrationDirectory(toQueryBuilderDialect(dialect),{snapshotDir:QB_SNAPSHOT_DIR})),timestamps:{createdAt:"created_at",updatedAt:"updated_at",defaultOrderColumn:"created_at"},softDeletes:RAW_QUERY_SOFT_DELETE_CONFIG})}updateQueryBuilderConfig();let _dbInstance=null,_configInitPromise=null;function ensureConfigLoaded(){if(!_configInitPromise)_configInitPromise=(async()=>{try{const{config,overridesReady}=await import("@stacksjs/config");await overridesReady;if(config){initializeDbConfig(config);_dbInstance=null}}catch{}})();return _configInitPromise}export async function ensureDatabaseConfigLoaded(){await ensureConfigLoaded()}export{applySqlitePragmas,SQLITE_BOOTSTRAP_PRAGMAS}from"@stacksjs/query-builder";const sqliteTxOwner=new AsyncLocalStorage;let sqliteTxTail=Promise.resolve();function serializeSqliteTransaction(run){if(sqliteTxOwner.getStore())return run();const result=sqliteTxTail.then(()=>sqliteTxOwner.run(!0,run));sqliteTxTail=result.then(()=>{return},()=>{return});return result}function applySqliteTransactionSerialization(instance){const original=instance.transaction.bind(instance);instance.transaction=(...args)=>serializeSqliteTransaction(()=>original(...args))}function applyTransactionRoutingContext(instance){const original=instance.transaction.bind(instance);instance.transaction=(...args)=>withTransactionContext(()=>original(...args))}function getDb(){if(!_dbInstance){updateQueryBuilderConfig();_dbInstance=createQueryBuilder();if(getDialect()==="sqlite")applySqliteTransactionSerialization(_dbInstance);applyTransactionRoutingContext(_dbInstance)}return _dbInstance}let _replicaInstances=new Map;export function resetDatabaseConnection(){resetQueryBuilderConnection();_dbInstance=null;_replicaInstances=new Map}function getReplicaDb(replica){const primary=getDbConfig(),resolved=resolveReplicaConnection(replica,primary),key=`${resolved.host}:${resolved.port??""}`,cached=_replicaInstances.get(key);if(cached)return cached;const scheme=isMysqlWire(getDriver())?"mysql":"postgres",auth=resolved.username?`${encodeURIComponent(resolved.username)}:${encodeURIComponent(resolved.password??"")}@`:"",url=`${scheme}://${auth}${resolved.host}:${resolved.port}/${resolved.database}`,sql=new SQL({url,...toBunPoolOptions(getPoolConfig())}),instance=createQueryBuilder({sql});_replicaInstances.set(key,instance);return instance}function getReadDb(){const replicas=getReplicas(),policy=getReadPolicy();if(!shouldRouteToReplica({policy,replicas}))return getDb();const replica=selectReplica(replicas,policy.strategy);return replica?getReplicaDb(replica):getDb()}function getExplicitReadDb(){const replicas=getReplicas();if(!replicas.length||contextInTransaction())return getDb();const replica=selectReplica(replicas,getReadPolicy().strategy);return replica?getReplicaDb(replica):getDb()}const WRITE_ENTRY_POINTS=new Set(["insertInto","updateTable","deleteFrom","create","createMany","insertOrIgnore","insertGetId","updateOrInsert","upsert"]),READ_ENTRY_POINTS=new Set(["selectFrom","selectFromSub","select"]);ensureConfigLoaded();export function asRows(rows){return rows}export function asRow(row){return row}export const db=new Proxy({},{get(_target,prop){if(prop==="fn")return aggregateFunctions;if(prop==="read")return readDb;if(typeof prop==="string"&&WRITE_ENTRY_POINTS.has(prop))markContextWrote();const instance=typeof prop==="string"&&READ_ENTRY_POINTS.has(prop)?getReadDb():getDb(),value=instance[prop];if(typeof value==="function")return value.bind(instance);return value}}),readDb=new Proxy({},{get(_target,prop){if(prop==="fn")return aggregateFunctions;const instance=getExplicitReadDb(),value=instance[prop];if(typeof value==="function")return value.bind(instance);return value}});export{setConfig};
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/database",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.72.
|
|
5
|
+
"version": "0.72.24",
|
|
6
6
|
"description": "The Stacks database integration.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -65,15 +65,15 @@
|
|
|
65
65
|
"dynamodb-tooling": "^0.3.2"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
|
-
"@stacksjs/cli": "0.72.
|
|
69
|
-
"@stacksjs/config": "0.72.
|
|
70
|
-
"@stacksjs/logging": "0.72.
|
|
71
|
-
"@stacksjs/router": "0.72.
|
|
68
|
+
"@stacksjs/cli": "0.72.24",
|
|
69
|
+
"@stacksjs/config": "0.72.24",
|
|
70
|
+
"@stacksjs/logging": "0.72.24",
|
|
71
|
+
"@stacksjs/router": "0.72.24",
|
|
72
72
|
"better-dx": "^0.2.23",
|
|
73
|
-
"@stacksjs/path": "0.72.
|
|
74
|
-
"@stacksjs/query-builder": "0.72.
|
|
75
|
-
"@stacksjs/storage": "0.72.
|
|
76
|
-
"@stacksjs/strings": "0.72.
|
|
77
|
-
"@stacksjs/utils": "0.72.
|
|
73
|
+
"@stacksjs/path": "0.72.24",
|
|
74
|
+
"@stacksjs/query-builder": "0.72.24",
|
|
75
|
+
"@stacksjs/storage": "0.72.24",
|
|
76
|
+
"@stacksjs/strings": "0.72.24",
|
|
77
|
+
"@stacksjs/utils": "0.72.24"
|
|
78
78
|
}
|
|
79
79
|
}
|