@ultimat3/cli 25.0.0 → 25.1.0
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/package.json +28 -28
- package/src/role-start.ts +2 -2
- package/src/role-wake.ts +2 -3
- package/src/runtime-queue.ts +7 -18
- package/src/runtime-services.ts +3 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ultimat3/cli",
|
|
3
|
-
"version": "25.
|
|
3
|
+
"version": "25.1.0",
|
|
4
4
|
"description": "The `x` binary: new, dev, build, verify, generate, db, mcp, doctor, deploy",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -39,33 +39,33 @@
|
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@babel/core": "^8.0.1",
|
|
42
|
-
"@ultimat3/action": "25.
|
|
43
|
-
"@ultimat3/admin": "25.
|
|
44
|
-
"@ultimat3/ai": "25.
|
|
45
|
-
"@ultimat3/auth": "25.
|
|
46
|
-
"@ultimat3/cache": "25.
|
|
47
|
-
"@ultimat3/core": "25.
|
|
48
|
-
"@ultimat3/db": "25.
|
|
49
|
-
"@ultimat3/entity": "25.
|
|
50
|
-
"@ultimat3/flags": "25.
|
|
51
|
-
"@ultimat3/http": "25.
|
|
52
|
-
"@ultimat3/i18n": "25.
|
|
53
|
-
"@ultimat3/jobs": "25.
|
|
54
|
-
"@ultimat3/mail": "25.
|
|
55
|
-
"@ultimat3/manifest": "25.
|
|
56
|
-
"@ultimat3/mcp": "25.
|
|
57
|
-
"@ultimat3/money": "25.
|
|
58
|
-
"@ultimat3/notify": "25.
|
|
59
|
-
"@ultimat3/policy": "25.
|
|
60
|
-
"@ultimat3/pwa": "25.
|
|
61
|
-
"@ultimat3/query": "25.
|
|
62
|
-
"@ultimat3/realtime": "25.
|
|
63
|
-
"@ultimat3/render": "25.
|
|
64
|
-
"@ultimat3/schema": "25.
|
|
65
|
-
"@ultimat3/seo": "25.
|
|
66
|
-
"@ultimat3/storage": "25.
|
|
67
|
-
"@ultimat3/testing": "25.
|
|
68
|
-
"@ultimat3/time": "25.
|
|
42
|
+
"@ultimat3/action": "25.1.0",
|
|
43
|
+
"@ultimat3/admin": "25.1.0",
|
|
44
|
+
"@ultimat3/ai": "25.1.0",
|
|
45
|
+
"@ultimat3/auth": "25.1.0",
|
|
46
|
+
"@ultimat3/cache": "25.1.0",
|
|
47
|
+
"@ultimat3/core": "25.1.0",
|
|
48
|
+
"@ultimat3/db": "25.1.0",
|
|
49
|
+
"@ultimat3/entity": "25.1.0",
|
|
50
|
+
"@ultimat3/flags": "25.1.0",
|
|
51
|
+
"@ultimat3/http": "25.1.0",
|
|
52
|
+
"@ultimat3/i18n": "25.1.0",
|
|
53
|
+
"@ultimat3/jobs": "25.1.0",
|
|
54
|
+
"@ultimat3/mail": "25.1.0",
|
|
55
|
+
"@ultimat3/manifest": "25.1.0",
|
|
56
|
+
"@ultimat3/mcp": "25.1.0",
|
|
57
|
+
"@ultimat3/money": "25.1.0",
|
|
58
|
+
"@ultimat3/notify": "25.1.0",
|
|
59
|
+
"@ultimat3/policy": "25.1.0",
|
|
60
|
+
"@ultimat3/pwa": "25.1.0",
|
|
61
|
+
"@ultimat3/query": "25.1.0",
|
|
62
|
+
"@ultimat3/realtime": "25.1.0",
|
|
63
|
+
"@ultimat3/render": "25.1.0",
|
|
64
|
+
"@ultimat3/schema": "25.1.0",
|
|
65
|
+
"@ultimat3/seo": "25.1.0",
|
|
66
|
+
"@ultimat3/storage": "25.1.0",
|
|
67
|
+
"@ultimat3/testing": "25.1.0",
|
|
68
|
+
"@ultimat3/time": "25.1.0",
|
|
69
69
|
"babel-preset-solid": "^1.9.15"
|
|
70
70
|
}
|
|
71
71
|
}
|
package/src/role-start.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import type { Role } from '@ultimat3/core';
|
|
10
10
|
import { ctxOf, isRole, logger, markReady, ROLES } from '@ultimat3/core';
|
|
11
|
+
import { dbExecutor } from '@ultimat3/db';
|
|
11
12
|
import type { RateLimitStore, Route, ServerHandle, WebSocketMount } from '@ultimat3/http';
|
|
12
13
|
import {
|
|
13
14
|
adoptRateLimitStore,
|
|
@@ -43,7 +44,6 @@ import { startWorkerWake } from './role-wake';
|
|
|
43
44
|
import { devHooks } from './runtime-hooks';
|
|
44
45
|
import { workerOptionsFor } from './runtime-jobs';
|
|
45
46
|
import { startLiveFeed } from './runtime-live-feed';
|
|
46
|
-
import { pgExecutorFor } from './runtime-queue';
|
|
47
47
|
import { type RunningServices, releaseOrThrow } from './runtime-services';
|
|
48
48
|
import { inlineScriptSources } from './script-csp';
|
|
49
49
|
import { inlineStyleSources } from './style-csp';
|
|
@@ -359,7 +359,7 @@ export async function startRoles(options: StartRolesOptions): Promise<RunningRol
|
|
|
359
359
|
// SESSION-scoped, and the session ends the moment the connection goes back to the pool, so
|
|
360
360
|
// every node reads itself as leader anyway. An expiring row is correct on the executor this
|
|
361
361
|
// package is actually handed.
|
|
362
|
-
const executor =
|
|
362
|
+
const executor = dbExecutor(() => options.runtime.db);
|
|
363
363
|
const scheduler = selected.includes('scheduler')
|
|
364
364
|
? jobScheduler({
|
|
365
365
|
driver: options.runtime.jobs,
|
package/src/role-wake.ts
CHANGED
|
@@ -5,10 +5,9 @@
|
|
|
5
5
|
|
|
6
6
|
import { gauge } from '@ultimat3/core';
|
|
7
7
|
import type { DbClient } from '@ultimat3/db';
|
|
8
|
-
import { canListen } from '@ultimat3/db';
|
|
8
|
+
import { canListen, dbExecutor } from '@ultimat3/db';
|
|
9
9
|
import type { QueueWake } from '@ultimat3/jobs';
|
|
10
10
|
import { startQueueWake } from '@ultimat3/jobs';
|
|
11
|
-
import { pgExecutorFor } from './runtime-queue';
|
|
12
11
|
|
|
13
12
|
// The wake the gauge reads. One observer for the life of the process: a gauge redeclared with a
|
|
14
13
|
// different `observe` is refused, and `x dev` starts the roles again on every restart-in-place.
|
|
@@ -32,7 +31,7 @@ export function startWorkerWake(db: DbClient): QueueWake | null {
|
|
|
32
31
|
observe: wakeLive,
|
|
33
32
|
});
|
|
34
33
|
}
|
|
35
|
-
const wake = startQueueWake({ listener: db, executor:
|
|
34
|
+
const wake = startQueueWake({ listener: db, executor: dbExecutor(() => db) });
|
|
36
35
|
current = wake;
|
|
37
36
|
return {
|
|
38
37
|
live: () => wake.live(),
|
package/src/runtime-queue.ts
CHANGED
|
@@ -11,17 +11,18 @@ import {
|
|
|
11
11
|
resetIdempotency,
|
|
12
12
|
setIdempotencyStore,
|
|
13
13
|
} from '@ultimat3/action';
|
|
14
|
-
import type {
|
|
14
|
+
import type { PgliteClient, PostgresClient } from '@ultimat3/db';
|
|
15
15
|
import {
|
|
16
16
|
baseClient,
|
|
17
17
|
currentTx,
|
|
18
|
+
dbExecutor,
|
|
18
19
|
pgliteClient,
|
|
19
20
|
pgliteDataDir,
|
|
20
21
|
postgresClient,
|
|
21
22
|
setDbClient,
|
|
22
23
|
} from '@ultimat3/db';
|
|
23
24
|
import type { Tx } from '@ultimat3/entity';
|
|
24
|
-
import type { EventBus, JobDriver, OutboxStore
|
|
25
|
+
import type { EventBus, JobDriver, OutboxStore } from '@ultimat3/jobs';
|
|
25
26
|
import {
|
|
26
27
|
outboxJobsFacade,
|
|
27
28
|
postgresEventBus,
|
|
@@ -109,20 +110,6 @@ export function startDb(services: DevServices, env: ReplicaEnv): StartedDb {
|
|
|
109
110
|
return { client, replica: attached.replica };
|
|
110
111
|
}
|
|
111
112
|
|
|
112
|
-
/**
|
|
113
|
-
* `@ultimat3/jobs` deliberately depends on no database package: Postgres reaches it as an
|
|
114
|
-
* injected `PgExecutor`. Boot code is what supplies one, and this is the boot.
|
|
115
|
-
*
|
|
116
|
-
* The fragment is assembled by hand rather than through `sql`` ` because the driver hands over
|
|
117
|
-
* `$1..$n` text it wrote itself plus already-bound values — there is no interpolation to guard.
|
|
118
|
-
*/
|
|
119
|
-
export function pgExecutorFor(client: DbClient): PgExecutor {
|
|
120
|
-
return {
|
|
121
|
-
query: <R>(text: string, values: readonly unknown[]): Promise<readonly R[]> =>
|
|
122
|
-
client.query<R>({ text, values } satisfies SqlFragment),
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
|
|
126
113
|
/**
|
|
127
114
|
* Every table this process's framework packages own, applied before anything reads one.
|
|
128
115
|
*
|
|
@@ -183,13 +170,15 @@ async function startJobs(
|
|
|
183
170
|
schema: SchemaMode,
|
|
184
171
|
): Promise<RunningQueue> {
|
|
185
172
|
await applySchema(client, schema);
|
|
186
|
-
|
|
173
|
+
// Bound to `client`, never the ambient `db()`: the queue, the event bus and the idempotency
|
|
174
|
+
// reservations stay on the boot's pool whatever transaction is open.
|
|
175
|
+
const executor = dbExecutor(() => client);
|
|
187
176
|
const driver = overrides?.jobs ?? postgresJobDriver({ executor });
|
|
188
177
|
setJobDriver(driver);
|
|
189
178
|
const outbox = postgresOutboxStore({
|
|
190
179
|
executor,
|
|
191
180
|
// The open transaction is a client on its own connection; the `Tx` token is not that object.
|
|
192
|
-
txExecutor: () =>
|
|
181
|
+
txExecutor: () => dbExecutor(() => currentTx() ?? client),
|
|
193
182
|
});
|
|
194
183
|
setJobsFacade(
|
|
195
184
|
outboxJobsFacade({ store: outbox, driver }, () => currentTx() as unknown as Tx | undefined),
|
package/src/runtime-services.ts
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
resolveEnvironment,
|
|
16
16
|
systemClock,
|
|
17
17
|
} from '@ultimat3/core';
|
|
18
|
+
import { dbExecutor } from '@ultimat3/db';
|
|
18
19
|
import type { RateLimitStore } from '@ultimat3/http';
|
|
19
20
|
import { adoptRateLimitStore, postgresRateLimitStore } from '@ultimat3/http';
|
|
20
21
|
import type { EventBus, JobDriver, OutboxStore } from '@ultimat3/jobs';
|
|
@@ -40,7 +41,7 @@ import { inboxRetentionOf } from './runtime-notify-retention';
|
|
|
40
41
|
import type { RuntimeOverrides } from './runtime-overrides';
|
|
41
42
|
import { installRetentionSweep } from './runtime-purge';
|
|
42
43
|
import type { DevDbClient, SchemaMode } from './runtime-queue';
|
|
43
|
-
import {
|
|
44
|
+
import { startQueue } from './runtime-queue';
|
|
44
45
|
import { realtimeConfigOf } from './runtime-realtime';
|
|
45
46
|
|
|
46
47
|
export interface RunningServices {
|
|
@@ -351,7 +352,7 @@ export async function startServices(
|
|
|
351
352
|
// The same executor the jobs driver, the outbox, the event bus and the idempotency store run
|
|
352
353
|
// on — one pool, one `Bun.sql` that does NOT satisfy `PgExecutor` (`Bun.sql.query` is
|
|
353
354
|
// `undefined`), one wrapper.
|
|
354
|
-
const executor =
|
|
355
|
+
const executor = dbExecutor(() => db);
|
|
355
356
|
const rateLimitStore = postgresRateLimitStore({ executor });
|
|
356
357
|
// Boot is a sequence of external resources, and every step after the first can reject — the
|
|
357
358
|
// queue is already up, so from here an unwind must release it exactly like everything after it.
|