@getstrata/core 0.5.100 → 0.7.3
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/CHANGELOG.md +67 -32
- package/README.md +16 -35
- package/dist/core/auth/abilityCatalog.d.ts +2 -2
- package/dist/core/auth/basicAuthGuard.d.ts +9 -0
- package/dist/core/auth/guard.d.ts +6 -0
- package/dist/core/auth/jwt.d.ts +19 -0
- package/dist/core/auth/jwtGuard.d.ts +14 -0
- package/dist/core/auth/tokenAbilityChecker.d.ts +5 -0
- package/dist/core/cache/tags.d.ts +6 -0
- package/dist/core/contracts/authUserDirectory.d.ts +4 -0
- package/dist/core/database/baseRepository.d.ts +5 -1
- package/dist/core/database/dialect.d.ts +18 -0
- package/dist/core/database/factory.d.ts +1 -0
- package/dist/core/database/index.d.ts +11 -3
- package/dist/core/database/model.d.ts +21 -2
- package/dist/core/database/mysqlConnection.d.ts +12 -0
- package/dist/core/database/namedConnections.d.ts +15 -0
- package/dist/core/database/relationQuery.d.ts +22 -3
- package/dist/core/database/relationships.d.ts +22 -2
- package/dist/core/database/repositoryQuery.d.ts +5 -1
- package/dist/core/database/sqliteConnection.d.ts +7 -0
- package/dist/core/http/loginThrottleMiddleware.d.ts +5 -2
- package/dist/core/http/resources.d.ts +2 -2
- package/dist/core/http/response.d.ts +2 -1
- package/dist/core/http/statelessAuth.d.ts +8 -0
- package/dist/core/http/throttleResponse.d.ts +2 -0
- package/dist/core/runtime/frontendMode.d.ts +10 -2
- package/dist/entries/auth/basicAuthGuard.js +137 -0
- package/dist/entries/auth/jwt.js +135 -0
- package/dist/entries/auth/jwtGuard.js +203 -0
- package/dist/entries/auth/sessionGuard.js +3 -21
- package/dist/entries/auth/tokenAbilityChecker.js +24 -0
- package/dist/entries/cache/tags.js +7 -1
- package/dist/entries/database/connectionContext.js +1 -0
- package/dist/entries/database/dialect.js +1 -0
- package/dist/entries/database/factory.js +5 -4
- package/dist/entries/database/model.js +189 -33
- package/dist/entries/database/mysqlConnection.js +35 -0
- package/dist/entries/database/namedConnections.js +1 -0
- package/dist/entries/database/query.js +28 -15
- package/dist/entries/database/relationships.js +43 -6
- package/dist/entries/database/repositoryQuery.js +142 -73
- package/dist/entries/database/schema.js +28 -15
- package/dist/entries/database/sqliteConnection.js +34 -0
- package/dist/entries/facades.js +1 -1
- package/dist/entries/http/contentNegotiation.js +5 -2
- package/dist/entries/http/csrfMiddleware.js +45 -0
- package/dist/entries/http/loginThrottleMiddleware.js +246 -7
- package/dist/entries/http/memoryThrottleMiddleware.js +208 -6
- package/dist/entries/http/requireAbilityMiddleware.js +35 -11
- package/dist/entries/http/requirePasswordConfirmMiddleware.js +5 -2
- package/dist/entries/http/requireVerifiedMiddleware.js +5 -2
- package/dist/entries/http/requireWebAuthMiddleware.js +12 -3
- package/dist/entries/http/resources.js +4 -1
- package/dist/entries/http/response.js +46 -12
- package/dist/entries/http/statelessAuth.js +48 -0
- package/dist/entries/http/throttleMiddleware.js +208 -6
- package/dist/entries/http/webErrorResponse.js +35 -11
- package/dist/entries/http/webFormRequest.js +5 -2
- package/dist/entries/mail/mailer.js +1 -1
- package/dist/entries/openapi/generator.js +48 -5
- package/dist/entries/runtime/frontendMode.js +39 -10
- package/dist/framework/public-api.d.ts +11 -1
- package/dist/index.js +1068 -250
- package/package.json +56 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# @getstrata/core changelog
|
|
2
2
|
|
|
3
|
+
## 0.7.3
|
|
4
|
+
|
|
5
|
+
- `JsonResource.whenLoaded` returns `null` when a relation is loaded but empty. It does not call the transform, so `new PositionResource(value).toArray()` cannot crash on a missing belongsTo.
|
|
6
|
+
|
|
7
|
+
## 0.7.2
|
|
8
|
+
|
|
9
|
+
- `withJsonErrorHandling` always maps thrown errors to JSON. `requestPrefersJson` treats `/api/` as JSON even when `Accept` is HTML, so hybrid staff HTML cannot remap JSON API errors.
|
|
10
|
+
|
|
11
|
+
## 0.7.1
|
|
12
|
+
|
|
13
|
+
- `readSpaPrefix` / `normalizeSpaPrefix` own `SPA_PREFIX` (default `/app`). Apps set the env value. They do not copy a second static-file server.
|
|
14
|
+
- The log mail driver records `htmlBytes` instead of dumping the HTML document onto stdout.
|
|
15
|
+
|
|
16
|
+
## 0.7.0
|
|
17
|
+
|
|
18
|
+
- `FRONTEND_MODE=hybrid` turns on staff HTML and the candidate SPA together. Views are on for `server-htmx` and `hybrid`. The SPA is on for `spa-react` and `hybrid`.
|
|
19
|
+
- `parseFrontendMode`, `FRONTEND_MODES`, and `FRONTEND_MODE_PATTERN` are the allowed-value list. Apps should reuse that pattern in env schemas.
|
|
20
|
+
- Named database connections: `registerNamedConnection`, `runOnNamedConnection`, SQLite (`bun:sqlite`), and MySQL (`mysql2`). `runWithSqlDialect` keeps the dialect across `await` via AsyncLocalStorage.
|
|
21
|
+
- New subpaths: `database/namedConnections`, `database/sqliteConnection`, `database/mysqlConnection`, `database/connectionContext`.
|
|
22
|
+
- OpenAPI treats `POST /api/apply/login` as unauthenticated.
|
|
23
|
+
|
|
24
|
+
## 0.6.0
|
|
25
|
+
|
|
26
|
+
- **Breaking:** cookie session signatures use HMAC-SHA256. Existing HMAC cookies signed with the previous digest will not verify. Rotate `SESSION_SECRET` or sign users in again.
|
|
27
|
+
- **Breaking:** default `MEMBER_ABILITIES` are profile and token scopes (`profile:read`, `auth:tokens:*`), not org/project/task. Apps replace the catalog with `configureAbilityCatalog`. HiroApp maps admin / recruiter / candidate.
|
|
28
|
+
- Named auth guards: opaque Bearer tokens, JWT HS256, HTTP Basic, and cookie sessions. `AuthManager` picks a guard from the `Authorization` scheme. CSRF is skipped for Bearer and Basic.
|
|
29
|
+
- OpenAPI treats HiroApp login, JWT mint (`POST /api/auth/token`), and public careers as unauthenticated. Partner ping and audit export require credentials.
|
|
30
|
+
- SQL dialect helpers (`pgsql`, `mysql`, `sqlite`) for placeholders, quoting, `ILIKE`/`LIKE`, `RETURNING`, and `NULLS LAST`. Full-text `tsMatch` stays Postgres-only and throws on other engines.
|
|
31
|
+
- HiroApp is the only in-repo example product. The leftover `src/db` schema is a test fixture, not a second app.
|
|
32
|
+
- New subpaths: `auth/jwt`, `auth/jwtGuard`, `auth/basicAuthGuard`, `auth/tokenAbilityChecker`, `database/dialect`, `http/statelessAuth`.
|
|
33
|
+
|
|
34
|
+
## 0.5.101
|
|
35
|
+
|
|
36
|
+
- Tenant middleware falls back with explicit branches when a member, admin, or guest tenant lookup misses, so the request still scopes to the default tenant.
|
|
37
|
+
|
|
3
38
|
## 0.5.100
|
|
4
39
|
|
|
5
40
|
HiroApp dogfood of 0.5.99: eager `with()` / nested `load("a.b")` missed related rows when a Postgres int4 PK arrived as a JS `number` and an int8 FK as a `bigint`. Map matching used `===`.
|
|
@@ -12,12 +47,12 @@ Still non-conforming (honest): Bun cannot infer `morphTo()` method names. `hashe
|
|
|
12
47
|
|
|
13
48
|
## 0.5.99
|
|
14
49
|
|
|
15
|
-
HiroApp dogfood of 0.5.98 found lookalike APIs. This release matches
|
|
50
|
+
HiroApp dogfood of 0.5.98 found lookalike APIs. This release matches the previous PHP framework call shape and SQL, not just export names.
|
|
16
51
|
|
|
17
52
|
- Relation queries are thenable: `await user.applications()` delegates to `get()`.
|
|
18
53
|
- `Model.with()` / `where()` / `whereHas()` return a `ModelQuery` that hydrates models and chains into `where` / `find` / `findOrFail` / `first` / `get`. `first()` / `find()` use `LIMIT` / PK lookup.
|
|
19
54
|
- `belongsTo.where()` threads constraints into `whereHas` EXISTS (HiroApp application search).
|
|
20
|
-
- `{ ilike }` uses the value as-is (
|
|
55
|
+
- `{ ilike }` uses the value as-is (the previous PHP framework). Pass `%term%` yourself; the operator no longer wraps extra `%`.
|
|
21
56
|
- Morph type defaults to `$morphClass` / class name, not `table.name`. Override with `$morphClass = "App\\Models\\User"` or the last `morphMany` argument. `morphTo()` no longer silently defaults to `imageable_*`.
|
|
22
57
|
- `primaryKey()` defaults to the table PK (`id`).
|
|
23
58
|
- Nested `load("a.b")` / `with("a.b")` skip already-loaded heads and batch the next level.
|
|
@@ -37,7 +72,7 @@ Still non-conforming (honest): Bun cannot infer `morphTo()` method names (`debug
|
|
|
37
72
|
- `Model.where()`, `firstOrNew()`, `firstOrCreate()`, and `updateOrCreate()`.
|
|
38
73
|
- Factory `count`/`state`/`sequence`/`for`/`has`/`recycle` plus `afterMaking`/`afterCreating`.
|
|
39
74
|
- `JsonResource` (`wrap`, `whenLoaded`, `additional`, `collection`).
|
|
40
|
-
-
|
|
75
|
+
- the previous PHP framework aliases: container `make`/`instance`, EventBus `on`/`emit`, query `whereNull`/`whereIn`/`whereExists`.
|
|
41
76
|
- Parity audit reports design score separately. Horizon/Nova/CLI stay Bun-native stand-ins.
|
|
42
77
|
|
|
43
78
|
## 0.5.97
|
|
@@ -55,10 +90,10 @@ Still non-conforming (honest): Bun cannot infer `morphTo()` method names (`debug
|
|
|
55
90
|
|
|
56
91
|
## 0.5.90
|
|
57
92
|
|
|
58
|
-
- **Breaking identity defaults:** `appKeyPrefix()` is `strata` and `appDisplayName()` is `Strata` when `APP_KEY_PREFIX` / `APP_NAME` are unset (were `
|
|
93
|
+
- **Breaking identity defaults:** `appKeyPrefix()` is `strata` and `appDisplayName()` is `Strata` when `APP_KEY_PREFIX` / `APP_NAME` are unset (were `strata` / `the previous in-repo app`). the previous in-repo app pins those env vars.
|
|
59
94
|
- `Schedule.command()` rejects cron strings other than `* * * * *` and `*/N * * * *` instead of silently never running them.
|
|
60
95
|
- OpenAPI marks `GET /users/me/*` as bearer-authenticated.
|
|
61
|
-
- OpenAPI `/users/me/current-organization` summaries no longer say
|
|
96
|
+
- OpenAPI `/users/me/current-organization` summaries no longer say team invitations.
|
|
62
97
|
|
|
63
98
|
## 0.5.89
|
|
64
99
|
|
|
@@ -66,16 +101,16 @@ Still non-conforming (honest): Bun cannot infer `morphTo()` method names (`debug
|
|
|
66
101
|
|
|
67
102
|
## 0.5.88
|
|
68
103
|
|
|
69
|
-
- Exported cookie name constants (`SESSION_COOKIE`, `CSRF_COOKIE`, `FLASH_COOKIE`, `INTENDED_URL_COOKIE`, `PASSWORD_CONFIRM_COOKIE`) are `appCookieName(...)` so they match the default prefix instead of a hardcoded `
|
|
70
|
-
- `@getstrata/core/jobs/dispatchWebhookJob` is a deprecated compatibility re-export of the
|
|
104
|
+
- Exported cookie name constants (`SESSION_COOKIE`, `CSRF_COOKIE`, `FLASH_COOKIE`, `INTENDED_URL_COOKIE`, `PASSWORD_CONFIRM_COOKIE`) are `appCookieName(...)` so they match the default prefix instead of a hardcoded `strata_` string.
|
|
105
|
+
- `@getstrata/core/jobs/dispatchWebhookJob` is a deprecated compatibility re-export of the the previous in-repo app webhook job.
|
|
71
106
|
|
|
72
107
|
## 0.5.87
|
|
73
108
|
|
|
74
|
-
- `AuthUserDirectory.hasActiveBrowserSession?(userId, issuedAt)` is optional. `SessionGuard` calls it after `session_valid_after` and rejects the HMAC cookie when it returns false so
|
|
109
|
+
- `AuthUserDirectory.hasActiveBrowserSession?(userId, issuedAt)` is optional. `SessionGuard` calls it after `session_valid_after` and rejects the HMAC cookie when it returns false so the previous in-repo app can revoke a single browser session by deleting the `sessions` row.
|
|
75
110
|
|
|
76
111
|
## 0.5.86
|
|
77
112
|
|
|
78
|
-
- `createSessionCookieDetails()` returns the HMAC session header plus `issuedAt` / `ttlSeconds` so apps can persist
|
|
113
|
+
- `createSessionCookieDetails()` returns the HMAC session header plus `issuedAt` / `ttlSeconds` so apps can persist team invitations browser-session rows without changing the cookie format.
|
|
79
114
|
|
|
80
115
|
## 0.5.85
|
|
81
116
|
|
|
@@ -87,24 +122,24 @@ Still non-conforming (honest): Bun cannot infer `morphTo()` method names (`debug
|
|
|
87
122
|
|
|
88
123
|
## 0.5.83
|
|
89
124
|
|
|
90
|
-
- `MEMBER_ABILITIES` includes `auth:tokens:delete` so
|
|
125
|
+
- `MEMBER_ABILITIES` includes `auth:tokens:delete` so team invitations-style personal access token revoke works for members (`DELETE /auth/tokens/:id`). HTML `/account/tokens/:id/revoke` was already authenticated-only.
|
|
91
126
|
- `buildOtpauthUrl()` defaults the issuer through `appDisplayName()` (`APP_NAME`).
|
|
92
127
|
|
|
93
128
|
## 0.5.82
|
|
94
129
|
|
|
95
|
-
- `MEMBER_ABILITIES` includes `organizations:create` so
|
|
130
|
+
- `MEMBER_ABILITIES` includes `organizations:create` so team invitations-style extra teams work for members (HTML `POST /organizations` and JSON `POST /organizations`). `OrganizationPolicy.create` already allowed any authenticated user.
|
|
96
131
|
|
|
97
132
|
## 0.5.81
|
|
98
133
|
|
|
99
|
-
- `@getstrata/core/auth/intendedUrlCookie` (`createIntendedUrlCookie`, `readIntendedUrl`, `clearIntendedUrlCookie`, `createIntendedUrlCookieFromRequest`).
|
|
134
|
+
- `@getstrata/core/auth/intendedUrlCookie` (`createIntendedUrlCookie`, `readIntendedUrl`, `clearIntendedUrlCookie`, `createIntendedUrlCookieFromRequest`). HTML auth intended URL after HTML email verification: register with `redirect=` and the previous PHP framework `verified` HTML redirects stash `${APP_KEY_PREFIX}_intended` (`INTENDED_URL_COOKIE_NAME`, default `strata_intended`; TTL `INTENDED_URL_TTL_SECONDS`, default 86400s). `GET /verify-email` honors and clears it.
|
|
100
135
|
|
|
101
136
|
## 0.5.80
|
|
102
137
|
|
|
103
|
-
- `appCookieName()` / `appDevSecret()` on `@getstrata/core/runtime/appKeyPrefix`. HMAC session, CSRF, flash, password-confirm, signed-URL, OAuth-state, and token-pepper fallbacks follow `APP_KEY_PREFIX` (
|
|
138
|
+
- `appCookieName()` / `appDevSecret()` on `@getstrata/core/runtime/appKeyPrefix`. HMAC session, CSRF, flash, password-confirm, signed-URL, OAuth-state, and token-pepper fallbacks follow `APP_KEY_PREFIX` (the previous in-repo app defaults unchanged).
|
|
104
139
|
|
|
105
140
|
## 0.5.79
|
|
106
141
|
|
|
107
|
-
- `readSession()` returns `{ userId, issuedAt }` from the HMAC session cookie. `isSessionInvalidated(issuedAt, session_valid_after)` lets `SessionGuard` reject cookies issued before `AuthUserRecord.session_valid_after` (
|
|
142
|
+
- `readSession()` returns `{ userId, issuedAt }` from the HMAC session cookie. `isSessionInvalidated(issuedAt, session_valid_after)` lets `SessionGuard` reject cookies issued before `AuthUserRecord.session_valid_after` (team invitations logout-other-devices / password change).
|
|
108
143
|
|
|
109
144
|
## 0.5.78
|
|
110
145
|
|
|
@@ -112,7 +147,7 @@ Still non-conforming (honest): Bun cannot infer `morphTo()` method names (`debug
|
|
|
112
147
|
|
|
113
148
|
## 0.5.77
|
|
114
149
|
|
|
115
|
-
- `@getstrata/core/security/recoveryCodes` (`generateRecoveryCodes`, `hashRecoveryCode`, `recoveryCodeMatches`).
|
|
150
|
+
- `@getstrata/core/security/recoveryCodes` (`generateRecoveryCodes`, `hashRecoveryCode`, `recoveryCodeMatches`). HTML auth-style one-time MFA backup codes (`abcd-efgh`).
|
|
116
151
|
|
|
117
152
|
## 0.5.76
|
|
118
153
|
|
|
@@ -120,12 +155,12 @@ Still non-conforming (honest): Bun cannot infer `morphTo()` method names (`debug
|
|
|
120
155
|
|
|
121
156
|
## 0.5.75
|
|
122
157
|
|
|
123
|
-
-
|
|
158
|
+
- the previous PHP framework `password.confirm`: `@getstrata/core/auth/passwordConfirmCookie` (`createPasswordConfirmCookie`, `hasFreshPasswordConfirmation`, `clearPasswordConfirmCookie`) and `createRequirePasswordConfirmMiddleware()` (HTML 302 `/confirm-password`, JSON 423). Cookie name `PASSWORD_CONFIRM_COOKIE_NAME` (default `strata_password_confirmed`), TTL `PASSWORD_CONFIRM_TIMEOUT` (default 10800s).
|
|
124
159
|
|
|
125
160
|
## 0.5.74
|
|
126
161
|
|
|
127
162
|
- `AuthUser.emailVerifiedAt` and `@getstrata/core/auth/emailVerification` (`isEmailVerificationRequired`, `hasVerifiedEmail`). `null` means unverified; missing is treated as verified (GuestGuard / legacy).
|
|
128
|
-
- `createRequireVerifiedMiddleware()` is
|
|
163
|
+
- `createRequireVerifiedMiddleware()` is the previous PHP framework `verified` (HTML 302 `/email/verify`, JSON 403).
|
|
129
164
|
|
|
130
165
|
## 0.5.73
|
|
131
166
|
|
|
@@ -150,40 +185,40 @@ Still non-conforming (honest): Bun cannot infer `morphTo()` method names (`debug
|
|
|
150
185
|
|
|
151
186
|
## 0.5.68
|
|
152
187
|
|
|
153
|
-
- Published core no longer imports
|
|
188
|
+
- Published core no longer imports the previous in-repo app `src/config`. Frontend mode, queue retries, CORS, and upload limits read env (`FRONTEND_MODE`, `QUEUE_*`, `CORS_ALLOWED_ORIGINS`, `MAX_UPLOAD_BYTES`).
|
|
154
189
|
- `@getstrata/core/runtime/frontendMode` exports `readFrontendMode` / `isViewsEnabled` / `isSpaEnabled`.
|
|
155
190
|
|
|
156
191
|
## 0.5.67
|
|
157
192
|
|
|
158
|
-
- OpenAPI title, server URLs, and generated SDK class name come from `APP_NAME` / `APP_URL` / `API_PREFIX` / `APP_SDK_CLASS` instead of importing
|
|
159
|
-
- `appEnv()`, `appUrl()`, `apiPrefix()`, and `sdkClientClassName()` live on `@getstrata/core/runtime/appKeyPrefix`. SIEM export, HSTS, and `safeFetch` DNS resolve use `appEnv()` instead of
|
|
193
|
+
- OpenAPI title, server URLs, and generated SDK class name come from `APP_NAME` / `APP_URL` / `API_PREFIX` / `APP_SDK_CLASS` instead of importing the previous in-repo app `src/config/app`.
|
|
194
|
+
- `appEnv()`, `appUrl()`, `apiPrefix()`, and `sdkClientClassName()` live on `@getstrata/core/runtime/appKeyPrefix`. SIEM export, HSTS, and `safeFetch` DNS resolve use `appEnv()` instead of the previous in-repo app `appConfig`.
|
|
160
195
|
|
|
161
196
|
## 0.5.66
|
|
162
197
|
|
|
163
|
-
- `createValidateSignatureMiddleware()` on `@getstrata/core/http/signedUrl` is
|
|
198
|
+
- `createValidateSignatureMiddleware()` on `@getstrata/core/http/signedUrl` is the previous PHP framework's `signed` / `ValidateSignature` middleware. Invalid or expired links throw `ForbiddenError`.
|
|
164
199
|
|
|
165
200
|
## 0.5.65
|
|
166
201
|
|
|
167
|
-
- Identity helpers on `@getstrata/core/runtime/appKeyPrefix` (`smtpEhloHost`, `siemEventType`, `appUserAgent`, `otelServiceName`, `appDisplayName`, `webhookSignatureHeader`) so sibling apps are not stuck with
|
|
168
|
-
- SIEM `event_type` and CEF vendor follow `SIEM_EVENT_TYPE` / `APP_NAME` (defaults stay `
|
|
202
|
+
- Identity helpers on `@getstrata/core/runtime/appKeyPrefix` (`smtpEhloHost`, `siemEventType`, `appUserAgent`, `otelServiceName`, `appDisplayName`, `webhookSignatureHeader`) so sibling apps are not stuck with the previous in-repo app SMTP/SIEM/OTEL/OAuth names.
|
|
203
|
+
- SIEM `event_type` and CEF vendor follow `SIEM_EVENT_TYPE` / `APP_NAME` (defaults stay `strata.audit` / `the previous in-repo app`).
|
|
169
204
|
|
|
170
205
|
## 0.5.64
|
|
171
206
|
|
|
172
|
-
- `APP_KEY_PREFIX` (default `
|
|
173
|
-
- `DispatchWebhookJob` implementation lives in the
|
|
207
|
+
- `APP_KEY_PREFIX` (default `strata`) namespaces Redis cache, queue, and throttle keys so sibling apps do not share the previous in-repo app's keyspace.
|
|
208
|
+
- `DispatchWebhookJob` implementation lives in the the previous in-repo app webhook module. `@getstrata/core/jobs/dispatchWebhookJob` remains a compatibility re-export.
|
|
174
209
|
|
|
175
210
|
## 0.5.63
|
|
176
211
|
|
|
177
|
-
- Flash cookies honor `FLASH_COOKIE_NAME` (default `
|
|
212
|
+
- Flash cookies honor `FLASH_COOKIE_NAME` (default `strata_flash`) so sibling apps do not inherit the previous in-repo app's cookie name.
|
|
178
213
|
|
|
179
214
|
## 0.5.62
|
|
180
215
|
|
|
181
|
-
|
|
216
|
+
the previous PHP framework URL signing, Bun-native markdown mail, and session-auth cleanup.
|
|
182
217
|
|
|
183
218
|
- `temporarySignedUrl` / `signedUrl` / `hasValidSignature` / `assertValidSignature` on `@getstrata/core/http/signedUrl`. HMAC uses `SIGNED_URL_SECRET` or `SESSION_SECRET`. Paths must be same-origin (`/` only; reject `//` and `://`).
|
|
184
219
|
- `markdownToHtml()` uses `Bun.markdown.html()` plus `sanitizeMailHtml` (allowlist). Scripts, `javascript:` links, and unknown tags are stripped.
|
|
185
220
|
- `ExportAuditLogsJob` (`@getstrata/core/jobs/exportAuditLogsJob`) wraps SIEM export so the scheduler can dispatch a real job.
|
|
186
|
-
- `DispatchWebhookJob` reads `APP_ENV` and `WEBHOOK_SIGNATURE_HEADER` instead of
|
|
221
|
+
- `DispatchWebhookJob` reads `APP_ENV` and `WEBHOOK_SIGNATURE_HEADER` instead of the previous in-repo app `appConfig`.
|
|
187
222
|
- `createRequireWebAuthMiddleware` runs the handler inside `runWithAuthUser` so `currentAuthUser()` works on HTMX session routes.
|
|
188
223
|
- `generateTotpSecret()` / `buildOtpauthUrl()` on `@getstrata/core/security/totp`.
|
|
189
224
|
- `createRequireAbilityMiddleware` rethrows `ForbiddenError` for HTML views so HTMX routes render a styled 403 instead of JSON.
|
|
@@ -207,13 +242,13 @@ HTMX HTML kernel gaps that sibling apps could not work around without weakening
|
|
|
207
242
|
|
|
208
243
|
## 0.5.59
|
|
209
244
|
|
|
210
|
-
Sibling HTMX apps can consume published packages without
|
|
245
|
+
Sibling HTMX apps can consume published packages without the previous in-repo app-only glue.
|
|
211
246
|
|
|
212
247
|
- Emit `@getstrata/core/facades` types at `dist/core/facades/index.d.ts` (CI checks every `exports.*.types` path after build).
|
|
213
|
-
- Session and CSRF cookie names are configurable (`SESSION_COOKIE_NAME`, `CSRF_COOKIE_NAME`). Defaults remain `
|
|
248
|
+
- Session and CSRF cookie names are configurable (`SESSION_COOKIE_NAME`, `CSRF_COOKIE_NAME`). Defaults remain `strata_session` and `strata_csrf` for the previous in-repo app.
|
|
214
249
|
- Split `CORE_ABILITY_CHECKER_TOKEN` and `CORE_AUTH_USER_DIRECTORY_TOKEN` from `CORE_TOKEN_SERVICE_TOKEN`. HttpKernel prefers the ability-checker token; HMAC `SessionGuard` / layout data prefer the user directory. A compatibility shim uses `CORE_TOKEN_SERVICE_TOKEN` only when the bound value matches the requested type.
|
|
215
|
-
- `configureWebLayoutData` lets apps choose `currentUser` vs `authUser`, a custom user loader, and extra template fields.
|
|
250
|
+
- `configureWebLayoutData` lets apps choose `currentUser` vs `authUser`, a custom user loader, and extra template fields. the previous in-repo app still gets `{ authUser, csrfToken, flash }`.
|
|
216
251
|
- `redirectResponse`, `notFoundHtmlResponse`, `textResponse`, and `xmlResponse` join `htmlResponse` / `isHtmxRequest` on `@getstrata/core/view`.
|
|
217
252
|
- `LOGIN_RATE_LIMIT_WINDOW_MS` is a deprecated alias for `LOGIN_RATE_LIMIT_WINDOW_SECONDS`.
|
|
218
253
|
|
|
219
|
-
HMAC `SessionGuard` is unchanged for
|
|
254
|
+
HMAC `SessionGuard` is unchanged for the previous in-repo app API/token apps. Sibling HTMX apps should use `@getstrata/bootstrap` `CookieSessionStore` + `createCookieSessionAuthManager`.
|
package/README.md
CHANGED
|
@@ -2,73 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
Stable **Strata** framework surface for application modules.
|
|
4
4
|
|
|
5
|
-
**Source:** `src/framework/public-api.ts` (monorepo)
|
|
5
|
+
**Source:** `src/framework/public-api.ts` (monorepo)
|
|
6
6
|
**Repository:** [EyK-26/strata](https://github.com/EyK-26/strata), directory `packages/strata-core`
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
HiroApp is the example product. Import this package from your own modules. HTML cookie apps: [docs/BUILDING-APPS.md](../../docs/BUILDING-APPS.md). Auth choices: [docs/AUTH.md](../../docs/AUTH.md). SQL engines: [docs/DATABASE.md](../../docs/DATABASE.md).
|
|
9
9
|
|
|
10
10
|
## Usage
|
|
11
11
|
|
|
12
|
-
Set `DATABASE_URL` before importing (connection is created lazily on first query):
|
|
12
|
+
Set `DATABASE_URL` before importing (the connection is created lazily on first query):
|
|
13
13
|
|
|
14
14
|
```typescript
|
|
15
15
|
process.env.DATABASE_URL ??= "postgresql://postgres:postgres@localhost:5432/myapp";
|
|
16
16
|
|
|
17
|
-
import { AdminResourceRegistry } from "@getstrata/core/admin/registry";
|
|
18
|
-
import { formatAdminValue } from "@getstrata/core/admin/formatValue";
|
|
19
17
|
import { Policy } from "@getstrata/core/auth/policy";
|
|
20
18
|
import { BaseRepository } from "@getstrata/core/database/baseRepository";
|
|
21
|
-
import { mail } from "@getstrata/core/facades";
|
|
22
19
|
import { FormRequest } from "@getstrata/core/http/formRequest";
|
|
23
20
|
import { withErrorHandling } from "@getstrata/core/http/response";
|
|
24
|
-
import { mailer } from "@getstrata/core/mail/mailer";
|
|
25
|
-
import { storage } from "@getstrata/core/facades";
|
|
26
21
|
import { EtaViewEngine } from "@getstrata/core/view";
|
|
27
22
|
```
|
|
28
23
|
|
|
29
|
-
`.eta` files are **HTML + Eta tags** (`<% %>`, `<%= %>`, `<%~ include() %>`), not
|
|
24
|
+
`.eta` files are **HTML + Eta tags** (`<% %>`, `<%= %>`, `<%~ include() %>`), not another template language. Class/attribute shorthand such as `section.section` or `a href=` fails at render time with the template name.
|
|
30
25
|
|
|
31
|
-
**Dependency:** `eta` is
|
|
26
|
+
**Dependency:** `eta` is a direct dependency of `@getstrata/core`. Apps do not need to list it separately. The database **engine** is your choice. HiroApp uses **Bun's built-in `Bun.sql`** (Postgres). Create and bind it with `createBunSqlPool()` / `bindBunSql()`, or call `bindDatabaseConnection()` yourself. Extra engines register with `registerNamedConnection` (`database/namedConnections`, `database/sqliteConnection`, `database/mysqlConnection`).
|
|
32
27
|
|
|
33
|
-
`orderBy` accepts
|
|
28
|
+
`orderBy` accepts `{ column, direction }` objects or column shorthand such as `{ published_at: "desc" }`. `{ ilike }` uses the value as-is. Pass `%term%` yourself.
|
|
34
29
|
|
|
35
30
|
## Admin and queue helpers
|
|
36
31
|
|
|
37
|
-
Exports for admin dashboards and queue recovery:
|
|
38
|
-
|
|
39
32
|
- `AdminResourceRegistry`, `formatAdminValue`: read-only resource browsers
|
|
40
33
|
- `createFailedJobService`, `FailedJobService.delete()`: failed job persistence and cleanup
|
|
41
34
|
- `runQueueJob`, `jobRegistry`: dispatch retried jobs from admin UIs
|
|
42
35
|
|
|
36
|
+
HiroApp uses failed-job recovery in the staff dashboard. You do not have to use the admin registry.
|
|
37
|
+
|
|
43
38
|
## Build and verify (monorepo root)
|
|
44
39
|
|
|
45
40
|
```bash
|
|
46
41
|
bun run build:framework
|
|
47
|
-
bun run verify:framework
|
|
48
|
-
bun run verify:shared-subpaths
|
|
42
|
+
bun run verify:framework
|
|
43
|
+
bun run verify:shared-subpaths
|
|
49
44
|
```
|
|
50
45
|
|
|
51
46
|
## Subpath imports
|
|
52
47
|
|
|
53
|
-
`@getstrata/core` publishes
|
|
54
|
-
`@getstrata/core/database/migrations`). Prefer subpaths over the root import in apps, bootstrap, and tests.
|
|
48
|
+
`@getstrata/core` publishes many subpaths (for example `@getstrata/core/http/authMiddleware`, `@getstrata/core/database/migrations`). Prefer subpaths over the root import in apps, bootstrap, and tests.
|
|
55
49
|
|
|
56
|
-
Some subpaths **re-export the main bundle** so singleton state stays shared (database pool
|
|
57
|
-
|
|
58
|
-
`instanceof
|
|
59
|
-
`scripts/verify-core-shared-subpaths.ts` after each framework build.
|
|
50
|
+
Some subpaths **re-export the main bundle** so singleton state stays shared (database pool, dialect override, async-local auth/tenant, `HttpError` for `instanceof`). The list lives in `scripts/core-shared-subpaths.ts`.
|
|
51
|
+
|
|
52
|
+
When adding a subpath that owns process-wide state or base classes used with `instanceof`, append it to `CORE_SHARED_SUBPATHS`, run `bun scripts/sync-package-subpaths.ts`, and rebuild.
|
|
60
53
|
|
|
61
|
-
When adding a subpath that owns process-wide state or base classes used with `instanceof`, append it to
|
|
62
|
-
`CORE_SHARED_SUBPATHS`, run `bun scripts/sync-package-subpaths.ts`, and rebuild. Non-shared subpath
|
|
63
|
-
bundles are built with generated `--external @getstrata/core/*` flags (all 144+ subpaths) so framework
|
|
64
|
-
source can import shared modules via package self-imports (`scripts/codemod-core-self-imports.ts`).
|
|
65
|
-
Bootstrap subpath builds externalize all `@getstrata/bootstrap/*` and `@getstrata/core/*` entries.
|
|
66
54
|
`scripts/verify-no-root-imports.ts` blocks root `@getstrata/core` imports in application source.
|
|
67
|
-
`scripts/verify-no-shared-barrel-imports.ts` blocks `@getstrata/core/database` and
|
|
68
|
-
`@getstrata/core/http` barrel imports in application source.
|
|
69
|
-
`scripts/audit-public-api-surface.ts` reports root exports with no in-repo root import usage.
|
|
70
|
-
`scripts/verify-bundled-subpaths.ts` ensures entries like `http/webFormRequest` do not inline
|
|
71
|
-
`ValidationError`.
|
|
72
55
|
|
|
73
56
|
```typescript
|
|
74
57
|
import { createAuthMiddleware } from "@getstrata/core/http/authMiddleware";
|
|
@@ -82,9 +65,7 @@ import type { Migration } from "@getstrata/core/database/migrations/types";
|
|
|
82
65
|
Package name: **`@getstrata/core`** (npm org [`@getstrata`](https://www.npmjs.com/org/getstrata)).
|
|
83
66
|
|
|
84
67
|
1. Add `NPM_TOKEN` to GitHub repository secrets.
|
|
85
|
-
2. Tag a release: `git tag v0.
|
|
68
|
+
2. Tag a release: `git tag v0.7.3 && git push origin v0.7.3`
|
|
86
69
|
3. [Release workflow](../../.github/workflows/release.yml) builds and runs `npm publish --access public`.
|
|
87
70
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
See [docs/PACKAGING.md](../../docs/PACKAGING.md) for boundaries and future extraction.
|
|
71
|
+
See [docs/PACKAGING.md](../../docs/PACKAGING.md).
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
declare const MEMBER_ABILITIES: readonly ["
|
|
2
|
-
declare const ADMIN_ABILITIES: readonly ["
|
|
1
|
+
declare const MEMBER_ABILITIES: readonly ["profile:read", "auth:tokens:read", "auth:tokens:write", "auth:tokens:delete"];
|
|
2
|
+
declare const ADMIN_ABILITIES: readonly ["profile:read", "auth:tokens:read", "auth:tokens:write", "auth:tokens:delete", "webhooks:read", "webhooks:write", "audit:read", "audit:export"];
|
|
3
3
|
declare const PLATFORM_ADMIN_ABILITIES: readonly ["*"];
|
|
4
4
|
interface AbilityCatalog {
|
|
5
5
|
member: readonly string[];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ServiceContainerLike } from "../contracts/serviceContainer";
|
|
2
|
+
import type { AuthUser } from "./authContext";
|
|
3
|
+
import type { AuthGuard } from "./guard";
|
|
4
|
+
declare class BasicAuthGuard implements AuthGuard {
|
|
5
|
+
private readonly container;
|
|
6
|
+
constructor(container: ServiceContainerLike);
|
|
7
|
+
resolve(request: Request): Promise<AuthUser | null>;
|
|
8
|
+
}
|
|
9
|
+
export { BasicAuthGuard };
|
|
@@ -26,11 +26,17 @@ declare class CompositeGuard implements AuthGuard {
|
|
|
26
26
|
}
|
|
27
27
|
declare class AuthManager {
|
|
28
28
|
private readonly guard;
|
|
29
|
+
private readonly namedGuards;
|
|
29
30
|
constructor(guard: AuthGuard);
|
|
31
|
+
registerGuard(name: string, next: AuthGuard): this;
|
|
32
|
+
use(name?: string): AuthGuard;
|
|
33
|
+
guardNames(): string[];
|
|
30
34
|
resolve(request?: Request): Promise<AuthUser | null>;
|
|
31
35
|
user(request?: Request): Promise<AuthUser | null>;
|
|
32
36
|
check(request?: Request): Promise<boolean>;
|
|
33
37
|
requireUser(request?: Request): Promise<AuthUser>;
|
|
38
|
+
private authenticateRequest;
|
|
39
|
+
private tryNamedGuards;
|
|
34
40
|
}
|
|
35
41
|
export type { AuthGuard, AuthUser };
|
|
36
42
|
export { ApiTokenGuard, AuthManager, CompositeGuard, DatabaseTokenGuard, GuestGuard };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
interface JwtPayload {
|
|
2
|
+
sub: string | number;
|
|
3
|
+
role?: string;
|
|
4
|
+
abilities?: string[];
|
|
5
|
+
emailVerifiedAt?: Date | string | null;
|
|
6
|
+
iat?: number;
|
|
7
|
+
exp?: number;
|
|
8
|
+
[key: string]: unknown;
|
|
9
|
+
}
|
|
10
|
+
interface SignJwtOptions {
|
|
11
|
+
secret?: string;
|
|
12
|
+
ttlSeconds?: number;
|
|
13
|
+
}
|
|
14
|
+
declare function resolveJwtSecret(secret?: string): string;
|
|
15
|
+
declare function jwtTtlSeconds(override?: number): number;
|
|
16
|
+
declare function signJwt(payload: JwtPayload, options?: SignJwtOptions): string;
|
|
17
|
+
declare function verifyJwt(token: string, secret?: string): JwtPayload | null;
|
|
18
|
+
export type { JwtPayload, SignJwtOptions };
|
|
19
|
+
export { jwtTtlSeconds, resolveJwtSecret, signJwt, verifyJwt };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AuthUser } from "./authContext";
|
|
2
|
+
import type { AuthGuard } from "./guard";
|
|
3
|
+
import { type JwtPayload } from "./jwt";
|
|
4
|
+
interface JwtGuardOptions {
|
|
5
|
+
secret?: string;
|
|
6
|
+
}
|
|
7
|
+
declare function authUserFromJwt(payload: JwtPayload): AuthUser;
|
|
8
|
+
declare class JwtGuard implements AuthGuard {
|
|
9
|
+
private readonly options;
|
|
10
|
+
constructor(options?: JwtGuardOptions);
|
|
11
|
+
resolve(request: Request): AuthUser | null;
|
|
12
|
+
}
|
|
13
|
+
export type { JwtGuardOptions };
|
|
14
|
+
export { authUserFromJwt, JwtGuard };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { AbilityChecker } from "./abilityChecker";
|
|
2
|
+
import type { AuthUser } from "./authContext";
|
|
3
|
+
declare function tokenCan(user: AuthUser | null, ability: string): boolean;
|
|
4
|
+
declare function createTokenAbilityChecker(): AbilityChecker;
|
|
5
|
+
export { createTokenAbilityChecker, tokenCan };
|
|
@@ -5,6 +5,12 @@ declare const CACHE_TAGS: {
|
|
|
5
5
|
readonly comments: "comments";
|
|
6
6
|
readonly attachments: "attachments";
|
|
7
7
|
readonly reports: "reports";
|
|
8
|
+
readonly users: "users";
|
|
9
|
+
readonly departments: "departments";
|
|
10
|
+
readonly positions: "positions";
|
|
11
|
+
readonly applications: "applications";
|
|
12
|
+
readonly careers: "careers";
|
|
13
|
+
readonly offers: "offers";
|
|
8
14
|
};
|
|
9
15
|
type CacheTag = (typeof CACHE_TAGS)[keyof typeof CACHE_TAGS];
|
|
10
16
|
export type { CacheTag };
|
|
@@ -10,5 +10,9 @@ interface AuthUserDirectory {
|
|
|
10
10
|
resolveUserFromToken(token: string): Promise<AuthUser | null>;
|
|
11
11
|
findByIdOrThrow(id: number): Promise<AuthUserRecord>;
|
|
12
12
|
hasActiveBrowserSession?(userId: number, issuedAt: number): Promise<boolean>;
|
|
13
|
+
findByEmail?(email: string): Promise<(AuthUserRecord & {
|
|
14
|
+
password?: string | null;
|
|
15
|
+
}) | null>;
|
|
16
|
+
verifyCredentials?(email: string, password: string): Promise<AuthUser | null>;
|
|
13
17
|
}
|
|
14
18
|
export type { AuthUserDirectory, AuthUserRecord };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type CursorPaginatedResult, type PaginatedResult } from "../pagination/index.ts";
|
|
2
|
-
import { type BelongsToManyRelation, type BelongsToRelation, type HasManyRelation, type MorphManyRelation, type MorphOneRelation, type MorphToRelation } from "./relationships.ts";
|
|
2
|
+
import { type BelongsToManyRelation, type BelongsToRelation, type HasManyRelation, type HasManyThroughRelation, type MorphManyRelation, type MorphOneRelation, type MorphToRelation } from "./relationships.ts";
|
|
3
3
|
import { RepositoryQuery } from "./repositoryQuery.ts";
|
|
4
4
|
import type { TableDefinition } from "./table.ts";
|
|
5
5
|
import type { MutationValues, QueryOptions, QueryWhere, UpdateValues } from "./types.ts";
|
|
@@ -59,6 +59,10 @@ declare class BaseRepository<TEntity extends object, PrimaryKey extends keyof TE
|
|
|
59
59
|
}>>;
|
|
60
60
|
findByHasManyRelation<TParent extends object, LocalKey extends keyof TParent & string, ForeignKey extends keyof TEntity & string>(relation: HasManyRelation<TParent, TEntity, LocalKey, ForeignKey>, parentId: TParent[LocalKey], options?: Omit<QueryOptions<TEntity>, "where">): Promise<TEntity[]>;
|
|
61
61
|
loadHasManyForParents<TParent extends object, LocalKey extends keyof TParent & string, ForeignKey extends keyof TEntity & string>(parents: readonly TParent[], relation: HasManyRelation<TParent, TEntity, LocalKey, ForeignKey>, options?: Omit<QueryOptions<TEntity>, "where">): Promise<Map<TParent[LocalKey], TEntity[]>>;
|
|
62
|
+
findHasManyThrough<TParent extends object, LocalKey extends keyof TParent & string, FirstKey extends string, SecondLocalKey extends string, SecondKey extends keyof TEntity & string>(parentId: unknown, relation: HasManyThroughRelation<TParent, TEntity, LocalKey, FirstKey, SecondLocalKey, SecondKey>, options?: QueryOptions<TEntity>): Promise<TEntity[]>;
|
|
63
|
+
loadHasManyThroughForParents<TParent extends object, LocalKey extends keyof TParent & string, FirstKey extends string, SecondLocalKey extends string, SecondKey extends keyof TEntity & string>(parents: readonly TParent[], relation: HasManyThroughRelation<TParent, TEntity, LocalKey, FirstKey, SecondLocalKey, SecondKey>, options?: QueryOptions<TEntity>): Promise<Map<TParent[LocalKey], TEntity[]>>;
|
|
64
|
+
private throughSoftDeleteClause;
|
|
65
|
+
private buildThroughWhere;
|
|
62
66
|
loadBelongsToForParents<TChild extends object, TParent extends object, ForeignKey extends keyof TChild & string, OwnerKey extends keyof TParent & string>(children: readonly TChild[], relation: BelongsToRelation<TChild, TParent, ForeignKey, OwnerKey>, parentRepository: BaseRepository<TParent, OwnerKey>, options?: Omit<QueryOptions<TParent>, "where">): Promise<Map<TChild[ForeignKey], TParent>>;
|
|
63
67
|
loadMorphManyForParents<TParent extends object, LocalKey extends keyof TParent & string, MorphTypeKey extends keyof TEntity & string, MorphIdKey extends keyof TEntity & string>(parents: readonly TParent[], relation: MorphManyRelation<TParent, TEntity, LocalKey, MorphTypeKey, MorphIdKey>, options?: Omit<QueryOptions<TEntity>, "where">): Promise<Map<TParent[LocalKey], TEntity[]>>;
|
|
64
68
|
loadMorphOneForParents<TParent extends object, LocalKey extends keyof TParent & string, MorphTypeKey extends keyof TEntity & string, MorphIdKey extends keyof TEntity & string>(parents: readonly TParent[], relation: MorphOneRelation<TParent, TEntity, LocalKey, MorphTypeKey, MorphIdKey>, options?: Omit<QueryOptions<TEntity>, "where">): Promise<Map<TParent[LocalKey], TEntity | undefined>>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type DatabaseDriver } from "./schema/driver.ts";
|
|
2
|
+
interface SqlDialect {
|
|
3
|
+
readonly driver: DatabaseDriver;
|
|
4
|
+
placeholder(index: number): string;
|
|
5
|
+
quoteIdentifier(identifier: string): string;
|
|
6
|
+
nowExpression(): string;
|
|
7
|
+
returningClause(columns: string): string;
|
|
8
|
+
ilikeOperator(): "ILIKE" | "LIKE";
|
|
9
|
+
nullsLastSuffix(): string;
|
|
10
|
+
castToText(expression: string): string;
|
|
11
|
+
}
|
|
12
|
+
declare function dialectFor(driver: DatabaseDriver): SqlDialect;
|
|
13
|
+
declare function currentSqlDialect(): SqlDialect;
|
|
14
|
+
declare function useSqlDialect(driver: DatabaseDriver): SqlDialect;
|
|
15
|
+
declare function resetSqlDialect(): void;
|
|
16
|
+
declare function runWithSqlDialect<T>(driver: DatabaseDriver, callback: () => T | Promise<T>): T | Promise<T>;
|
|
17
|
+
export type { SqlDialect };
|
|
18
|
+
export { currentSqlDialect, dialectFor, resetSqlDialect, runWithSqlDialect, useSqlDialect };
|
|
@@ -44,6 +44,7 @@ declare class Factory<TRecord extends object, Counted extends boolean = false> {
|
|
|
44
44
|
create(overrides?: Partial<TRecord>): Promise<FactoryMakeResult<TRecord, Counted>>;
|
|
45
45
|
protected makeOne(overrides?: Partial<TRecord>): TRecord;
|
|
46
46
|
protected createOne(overrides?: Partial<TRecord>): Promise<TRecord>;
|
|
47
|
+
protected persistCreated(record: TRecord): Promise<TRecord>;
|
|
47
48
|
protected insertable(record: TRecord): Partial<TRecord>;
|
|
48
49
|
protected persist(values: Partial<TRecord>): Promise<TRecord>;
|
|
49
50
|
}
|
|
@@ -1,17 +1,25 @@
|
|
|
1
1
|
export type { DatabaseConnection } from "./baseRepository.ts";
|
|
2
2
|
export { default as BaseRepository } from "./baseRepository.ts";
|
|
3
3
|
export { createDatabaseConnection } from "./connection.ts";
|
|
4
|
+
export type { ActiveDatabaseHandle } from "./connectionContext.ts";
|
|
5
|
+
export { getActiveDatabaseConnection, hasActiveDatabaseConnection, runWithDatabaseConnection, } from "./connectionContext.ts";
|
|
6
|
+
export type { SqlDialect } from "./dialect.ts";
|
|
7
|
+
export { currentSqlDialect, dialectFor, resetSqlDialect, runWithSqlDialect, useSqlDialect, } from "./dialect.ts";
|
|
4
8
|
export { mapDatabaseError, withDatabaseErrorHandling } from "./errors.ts";
|
|
5
9
|
export { Factory } from "./factory.ts";
|
|
6
10
|
export { foreignKeyFromTable, pivotTableName, singularize } from "./inflection.ts";
|
|
7
11
|
export type { CastType, GlobalScopeFn, ModelConstructor } from "./model.ts";
|
|
8
|
-
export { applyCasts, BelongsToManyRelationQuery, BelongsToRelationQuery, dehydrateValue, filterMassAssignable, HasManyRelationQuery, HasOneRelationQuery, hydrateValue, Model, ModelQuery, MorphManyRelationQuery, MorphOneRelationQuery, MorphToRelationQuery, registerModelClass, registerModelRepository, } from "./model.ts";
|
|
12
|
+
export { applyCasts, BelongsToManyRelationQuery, BelongsToRelationQuery, dehydrateValue, filterMassAssignable, HasManyRelationQuery, HasManyThroughRelationQuery, HasOneRelationQuery, hydrateValue, Model, ModelQuery, MorphManyRelationQuery, MorphOneRelationQuery, MorphToRelationQuery, registerModelClass, registerModelRepository, } from "./model.ts";
|
|
13
|
+
export { createMysqlConnection, createMysqlConnectionFromPool } from "./mysqlConnection.ts";
|
|
14
|
+
export type { NamedConnectionEntry } from "./namedConnections.ts";
|
|
15
|
+
export { getNamedConnection, hasNamedConnection, registerNamedConnection, resetNamedConnections, runOnNamedConnection, unregisterNamedConnection, } from "./namedConnections.ts";
|
|
9
16
|
export { buildAdvancedWhereClause, buildCountQuery, buildDeleteByIdQuery, buildGroupedCountQuery, buildInsertQuery, buildJoinClause, buildOrderByClause, buildProjectionQuery, buildQueryWhereClause, buildRestoreByIdQuery, buildSelectQuery, buildSoftDeleteByIdQuery, buildUpdateQuery, buildWhereClause, parseQualifiedColumn, qualifyColumn, quoteIdentifier, resolveQualifiedColumn, resolveSoftDeleteColumn, } from "./query.ts";
|
|
10
|
-
export type { BelongsToManyRelation, BelongsToRelation, HasManyRelation, HasOneRelation, MorphManyRelation, MorphOneRelation, MorphToRelation, } from "./relationships.ts";
|
|
11
|
-
export { belongsTo, belongsToMany, hasMany, hasOne, indexBelongsToManyRelation, indexBelongsToRelation, indexHasManyRelation, indexHasOneRelation, indexMorphManyRelation, indexMorphOneRelation, indexMorphToRelation, morphMany, morphOne, morphTo, } from "./relationships.ts";
|
|
17
|
+
export type { BelongsToManyRelation, BelongsToRelation, HasManyRelation, HasManyThroughRelation, HasOneRelation, MorphManyRelation, MorphOneRelation, MorphToRelation, } from "./relationships.ts";
|
|
18
|
+
export { belongsTo, belongsToMany, hasMany, hasManyThrough, hasOne, indexBelongsToManyRelation, indexBelongsToRelation, indexHasManyRelation, indexHasManyThroughRelation, indexHasOneRelation, indexMorphManyRelation, indexMorphOneRelation, indexMorphToRelation, morphMany, morphOne, morphTo, } from "./relationships.ts";
|
|
12
19
|
export { RepositoryQuery } from "./repositoryQuery.ts";
|
|
13
20
|
export type { BlueprintAction, BlueprintCallback, ColumnKind, DatabaseDriver, ForeignKeyOptions, Grammar, IndexDefinition, IndexKind, ResolveDatabaseDriverOptions, SchemaBuilder, } from "./schema/index.ts";
|
|
14
21
|
export { Blueprint, ColumnDefinition, compileBlueprint, createSchemaBuilder, ForeignIdColumnDefinition, grammarForDriver, inferReferencedTable, MySqlGrammar, PostgresGrammar, resolveDatabaseDriver, Schema, SqliteGrammar, UnsupportedSchemaFeatureError, } from "./schema/index.ts";
|
|
22
|
+
export { createSqliteConnection } from "./sqliteConnection.ts";
|
|
15
23
|
export type { TableDefinition } from "./table.ts";
|
|
16
24
|
export { defineTable } from "./table.ts";
|
|
17
25
|
export { runInTransaction } from "./transaction.ts";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type BaseRepository from "./baseRepository.ts";
|
|
2
2
|
import type { AnyRelationQuery, RelatedModelClass } from "./relationQuery.ts";
|
|
3
|
-
import { BelongsToManyRelationQuery, BelongsToRelationQuery, HasManyRelationQuery, HasOneRelationQuery, MorphManyRelationQuery, MorphOneRelationQuery, MorphToRelationQuery } from "./relationQuery.ts";
|
|
3
|
+
import { BelongsToManyRelationQuery, BelongsToRelationQuery, HasManyRelationQuery, HasManyThroughRelationQuery, HasOneRelationQuery, MorphManyRelationQuery, MorphOneRelationQuery, MorphToRelationQuery } from "./relationQuery.ts";
|
|
4
4
|
import type { BelongsToManyRelation, BelongsToRelation, HasManyRelation, HasOneRelation } from "./relationships.ts";
|
|
5
5
|
import type { RepositoryQuery } from "./repositoryQuery.ts";
|
|
6
6
|
import type { QueryOptions, QueryWhere } from "./types.ts";
|
|
@@ -56,6 +56,9 @@ declare class ModelQuery {
|
|
|
56
56
|
withMorphMany(...args: Parameters<RepositoryQuery<Record<string, unknown>, "id">["withMorphMany"]>): this;
|
|
57
57
|
withMorphOne(...args: Parameters<RepositoryQuery<Record<string, unknown>, "id">["withMorphOne"]>): this;
|
|
58
58
|
withMorphTo(...args: Parameters<RepositoryQuery<Record<string, unknown>, "id">["withMorphTo"]>): this;
|
|
59
|
+
withHasManyThrough(...args: Parameters<RepositoryQuery<Record<string, unknown>, "id">["withHasManyThrough"]>): this;
|
|
60
|
+
withTrashed(): this;
|
|
61
|
+
onlyTrashed(): this;
|
|
59
62
|
get(): Promise<Array<Model<Record<string, unknown>, "id">>>;
|
|
60
63
|
first(): Promise<Model<Record<string, unknown>, "id"> | null>;
|
|
61
64
|
find(id: unknown): Promise<Model<Record<string, unknown>, "id"> | null>;
|
|
@@ -103,6 +106,21 @@ declare class Model<TEntity extends object, PrimaryKey extends keyof TEntity & s
|
|
|
103
106
|
static newFromRecord(this: object, record: object, exists?: boolean): Model<Record<string, unknown>, "id">;
|
|
104
107
|
static create(this: object, attributes: Record<string, unknown>, forced?: Record<string, unknown>): Promise<Model<Record<string, unknown>, "id">>;
|
|
105
108
|
static with(this: object, ...relations: string[]): ModelQuery;
|
|
109
|
+
static withTrashed(this: object): ModelQuery;
|
|
110
|
+
static onlyTrashed(this: object): ModelQuery;
|
|
111
|
+
static chunk(this: object, count: number, callback: (models: Array<Model<Record<string, unknown>, "id">>) => Promise<boolean | void>): Promise<void>;
|
|
112
|
+
static cursorPaginate(this: object, options: {
|
|
113
|
+
perPage: number;
|
|
114
|
+
cursor?: unknown;
|
|
115
|
+
}): Promise<{
|
|
116
|
+
data: Array<Model<Record<string, unknown>, "id">>;
|
|
117
|
+
meta: {
|
|
118
|
+
per_page: number;
|
|
119
|
+
next_cursor: unknown;
|
|
120
|
+
prev_cursor: unknown;
|
|
121
|
+
has_more: boolean;
|
|
122
|
+
};
|
|
123
|
+
}>;
|
|
106
124
|
static whereHas(this: object, name: string, constrain?: (query: AnyRelationQuery) => void): ModelQuery;
|
|
107
125
|
static has(this: object, name: string): ModelQuery;
|
|
108
126
|
static doesntHave(this: object, name: string): ModelQuery;
|
|
@@ -127,6 +145,7 @@ declare class Model<TEntity extends object, PrimaryKey extends keyof TEntity & s
|
|
|
127
145
|
hasMany<TRelated extends object, RelatedKey extends keyof TRelated & string>(related: RelatedRef<TRelated, RelatedKey>, foreignKey?: keyof TRelated & string, localKey?: PrimaryKey): HasManyRelationQuery<TEntity, PrimaryKey, TRelated, RelatedKey>;
|
|
128
146
|
hasOne<TRelated extends object, RelatedKey extends keyof TRelated & string>(related: RelatedRef<TRelated, RelatedKey>, foreignKey?: keyof TRelated & string, localKey?: PrimaryKey): HasOneRelationQuery<TEntity, PrimaryKey, TRelated, RelatedKey>;
|
|
129
147
|
belongsTo<TRelated extends object, RelatedKey extends keyof TRelated & string>(related: RelatedRef<TRelated, RelatedKey>, foreignKey?: keyof TEntity & string, ownerKey?: RelatedKey): BelongsToRelationQuery<TEntity, PrimaryKey, TRelated, RelatedKey>;
|
|
148
|
+
hasManyThrough<TRelated extends object, TThrough extends object, RelatedKey extends keyof TRelated & string, ThroughKey extends keyof TThrough & string>(related: RelatedRef<TRelated, RelatedKey>, through: RelatedRef<TThrough, ThroughKey>, firstKey?: string, secondKey?: keyof TRelated & string, localKey?: PrimaryKey, secondLocalKey?: ThroughKey): HasManyThroughRelationQuery<TEntity, PrimaryKey, TRelated, RelatedKey>;
|
|
130
149
|
belongsToMany<TRelated extends object, RelatedKey extends keyof TRelated & string, Pivot extends object = Record<string, unknown>>(related: RelatedRef<TRelated, RelatedKey>, pivotTable?: string, foreignPivotKey?: keyof Pivot & string, relatedPivotKey?: keyof Pivot & string): BelongsToManyRelationQuery<TEntity, PrimaryKey, TRelated, RelatedKey, Pivot>;
|
|
131
150
|
morphMany<TRelated extends object, RelatedKey extends keyof TRelated & string>(related: RelatedRef<TRelated, RelatedKey>, morphName: string, typeKey?: keyof TRelated & string, idKey?: keyof TRelated & string, morphType?: string): MorphManyRelationQuery<TEntity, PrimaryKey, TRelated, RelatedKey>;
|
|
132
151
|
morphOne<TRelated extends object, RelatedKey extends keyof TRelated & string>(related: RelatedRef<TRelated, RelatedKey>, morphName: string, typeKey?: keyof TRelated & string, idKey?: keyof TRelated & string, morphType?: string): MorphOneRelationQuery<TEntity, PrimaryKey, TRelated, RelatedKey>;
|
|
@@ -138,6 +157,6 @@ declare class Model<TEntity extends object, PrimaryKey extends keyof TEntity & s
|
|
|
138
157
|
}
|
|
139
158
|
/** Binds a Model class to its table/connection and names it for `hasMany("User")`. */
|
|
140
159
|
declare function registerModelRepository<TModelClass>(model: TModelClass, repository: object): TModelClass;
|
|
141
|
-
export { BelongsToManyRelationQuery, BelongsToRelationQuery, HasManyRelationQuery, HasOneRelationQuery, MorphManyRelationQuery, MorphOneRelationQuery, MorphToRelationQuery, } from "./relationQuery.ts";
|
|
160
|
+
export { BelongsToManyRelationQuery, BelongsToRelationQuery, HasManyRelationQuery, HasManyThroughRelationQuery, HasOneRelationQuery, MorphManyRelationQuery, MorphOneRelationQuery, MorphToRelationQuery, } from "./relationQuery.ts";
|
|
142
161
|
export type { CastType, GlobalScopeFn, ModelClassType, ModelConstructor };
|
|
143
162
|
export { applyCasts, dehydrateValue, filterMassAssignable, hydrateValue, Model, ModelQuery, registerModelClass, registerModelRepository, };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ActiveDatabaseHandle } from "./connectionContext.ts";
|
|
2
|
+
type MysqlExecutable = {
|
|
3
|
+
execute: (sql: string, params?: unknown[]) => Promise<[unknown, unknown]>;
|
|
4
|
+
end?: () => Promise<void>;
|
|
5
|
+
};
|
|
6
|
+
type MysqlConnection = ActiveDatabaseHandle & {
|
|
7
|
+
close(): Promise<void>;
|
|
8
|
+
};
|
|
9
|
+
declare function createMysqlConnectionFromPool(pool: MysqlExecutable): MysqlConnection;
|
|
10
|
+
declare function createMysqlConnection(url: string): MysqlConnection;
|
|
11
|
+
export type { MysqlConnection, MysqlExecutable };
|
|
12
|
+
export { createMysqlConnection, createMysqlConnectionFromPool };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type ActiveDatabaseHandle } from "./connectionContext.ts";
|
|
2
|
+
import type { DatabaseDriver } from "./schema/driver.ts";
|
|
3
|
+
type NamedConnectionEntry = {
|
|
4
|
+
name: string;
|
|
5
|
+
driver: DatabaseDriver;
|
|
6
|
+
connection: ActiveDatabaseHandle;
|
|
7
|
+
};
|
|
8
|
+
declare function registerNamedConnection(name: string, driver: DatabaseDriver, connection: ActiveDatabaseHandle): void;
|
|
9
|
+
declare function unregisterNamedConnection(name: string): boolean;
|
|
10
|
+
declare function hasNamedConnection(name: string): boolean;
|
|
11
|
+
declare function getNamedConnection(name: string): NamedConnectionEntry;
|
|
12
|
+
declare function resetNamedConnections(): void;
|
|
13
|
+
declare function runOnNamedConnection<T>(name: string, callback: () => T | Promise<T>): T | Promise<T>;
|
|
14
|
+
export type { NamedConnectionEntry };
|
|
15
|
+
export { getNamedConnection, hasNamedConnection, registerNamedConnection, resetNamedConnections, runOnNamedConnection, unregisterNamedConnection, };
|