@oimlsmart/platform-server 0.2.9 → 0.2.10
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 +1 -1
- package/src/store/d1.ts +33 -0
- package/src/store/sqlite/consent-grants-store.ts +9 -0
- package/src/store/sqlite/op-store.ts +19 -0
- package/src/store/sqlite.ts +12 -0
- package/src/store.ts +19 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oimlsmart/platform-server",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.10",
|
|
4
4
|
"description": "The OIML SMART platform server kernel: the store seam (ServerStore + the D1 and SQLite implementations), the canonical D1 migration set both deployments apply, the instance profile, the mailer, the RBAC map, the OIDC/OAuth client cones, and the shared role/permission vocabulary. Consumed by the smart monorepo (browser/) and the identity service.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
package/src/store/d1.ts
CHANGED
|
@@ -1456,6 +1456,16 @@ export class D1ServerStore implements ServerStore {
|
|
|
1456
1456
|
return (res.meta.changes ?? 0) > 0
|
|
1457
1457
|
}
|
|
1458
1458
|
|
|
1459
|
+
/** The governance view's population read: the client's LIVE access-token
|
|
1460
|
+
* count (unexpired — the row's absence IS the revocation). */
|
|
1461
|
+
async countOidcAccessTokensForClient(clientId: string): Promise<number> {
|
|
1462
|
+
await this.ensureMembershipSupport()
|
|
1463
|
+
const row = await this.stmt(
|
|
1464
|
+
"SELECT COUNT(*) AS n FROM oidc_access_tokens WHERE client_id = ? AND datetime(expires_at) > datetime('now')", clientId,
|
|
1465
|
+
).first<{ n: number }>()
|
|
1466
|
+
return row?.n ?? 0
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1459
1469
|
private static toRefreshToken(row: Record<string, unknown>): OidcRefreshToken {
|
|
1460
1470
|
return {
|
|
1461
1471
|
token: row.token as string,
|
|
@@ -1546,6 +1556,18 @@ export class D1ServerStore implements ServerStore {
|
|
|
1546
1556
|
return res.meta.changes ?? 0
|
|
1547
1557
|
}
|
|
1548
1558
|
|
|
1559
|
+
/** The governance view's population read: the client's LIVE refresh-token
|
|
1560
|
+
* count (unconsumed AND unexpired — a revoked family is deleted
|
|
1561
|
+
* wholesale, so a live row's presence is the offline grant's standing). */
|
|
1562
|
+
async countOidcRefreshTokensForClient(clientId: string): Promise<number> {
|
|
1563
|
+
await this.ensureMembershipSupport()
|
|
1564
|
+
await this.ensureOidcRefreshTokenSupport()
|
|
1565
|
+
const row = await this.stmt(
|
|
1566
|
+
"SELECT COUNT(*) AS n FROM oidc_refresh_tokens WHERE client_id = ? AND consumed_at IS NULL AND datetime(expires_at) > datetime('now')", clientId,
|
|
1567
|
+
).first<{ n: number }>()
|
|
1568
|
+
return row?.n ?? 0
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1549
1571
|
async listOidcKeys(): Promise<OidcKeyRow[]> {
|
|
1550
1572
|
const res = await this.stmt('SELECT * FROM oidc_keys ORDER BY created_at, kid').all<Record<string, unknown>>()
|
|
1551
1573
|
return res.results.map(row => ({
|
|
@@ -1639,6 +1661,17 @@ export class D1ServerStore implements ServerStore {
|
|
|
1639
1661
|
return (res.meta.changes ?? 0) > 0
|
|
1640
1662
|
}
|
|
1641
1663
|
|
|
1664
|
+
/** The client-registry governance view's per-client read: EVERY grant row
|
|
1665
|
+
* the client holds — live AND revoked, newest first. */
|
|
1666
|
+
async listOidcConsentGrantsForClient(clientId: string): Promise<OidcConsentGrant[]> {
|
|
1667
|
+
await this.ensureConsentGrantSupport()
|
|
1668
|
+
const res = await this.stmt(
|
|
1669
|
+
'SELECT * FROM oidc_consent_grants WHERE client_id = ? ORDER BY created_at DESC, rowid DESC',
|
|
1670
|
+
clientId,
|
|
1671
|
+
).all<Record<string, unknown>>()
|
|
1672
|
+
return res.results.map(D1ServerStore.toConsentGrant)
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1642
1675
|
// ── the upstream providers (TODO.identity/08) ─────────────────────
|
|
1643
1676
|
// The provider + link rows port directly (D1 is SQLite).
|
|
1644
1677
|
|
|
@@ -77,6 +77,15 @@ export function listConsentGrants(userId: string): OidcConsentGrant[] {
|
|
|
77
77
|
return rows.map(toConsentGrant)
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
/** The client-registry governance view's per-client read: EVERY grant row
|
|
81
|
+
* the client holds — live AND revoked, newest first. */
|
|
82
|
+
export function listOidcConsentGrantsForClient(clientId: string): OidcConsentGrant[] {
|
|
83
|
+
const rows = getDb().prepare(
|
|
84
|
+
'SELECT * FROM oidc_consent_grants WHERE client_id = ? ORDER BY created_at DESC, rowid DESC',
|
|
85
|
+
).all(clientId) as Array<Record<string, unknown>>
|
|
86
|
+
return rows.map(toConsentGrant)
|
|
87
|
+
}
|
|
88
|
+
|
|
80
89
|
/** The guarded revoke: the owner's LIVE row flips, once. */
|
|
81
90
|
export function revokeConsentGrant(id: string, userId: string): boolean {
|
|
82
91
|
return getDb().prepare(
|
|
@@ -275,6 +275,15 @@ export function deleteOidcAccessToken(token: string, clientId: string): boolean
|
|
|
275
275
|
return res.changes > 0
|
|
276
276
|
}
|
|
277
277
|
|
|
278
|
+
/** The governance view's population read: the client's LIVE access-token
|
|
279
|
+
* count (unexpired — the row's absence IS the revocation). */
|
|
280
|
+
export function countOidcAccessTokensForClient(clientId: string): number {
|
|
281
|
+
const row = getDb().prepare(
|
|
282
|
+
"SELECT COUNT(*) AS n FROM oidc_access_tokens WHERE client_id = ? AND datetime(expires_at) > datetime('now')",
|
|
283
|
+
).get(clientId) as { n: number }
|
|
284
|
+
return row.n
|
|
285
|
+
}
|
|
286
|
+
|
|
278
287
|
function toOidcRefreshToken(row: Record<string, unknown>): OidcRefreshToken {
|
|
279
288
|
return {
|
|
280
289
|
token: row.token as string,
|
|
@@ -354,6 +363,16 @@ export function deleteOidcRefreshTokensForUserClient(userId: string, clientId: s
|
|
|
354
363
|
return getDb().prepare('DELETE FROM oidc_refresh_tokens WHERE user_id = ? AND client_id = ?').run(userId, clientId).changes
|
|
355
364
|
}
|
|
356
365
|
|
|
366
|
+
/** The governance view's population read: the client's LIVE refresh-token
|
|
367
|
+
* count (unconsumed AND unexpired — a revoked family is deleted wholesale,
|
|
368
|
+
* so a live row's presence is the offline grant's standing). */
|
|
369
|
+
export function countOidcRefreshTokensForClient(clientId: string): number {
|
|
370
|
+
const row = getDb().prepare(
|
|
371
|
+
"SELECT COUNT(*) AS n FROM oidc_refresh_tokens WHERE client_id = ? AND consumed_at IS NULL AND datetime(expires_at) > datetime('now')",
|
|
372
|
+
).get(clientId) as { n: number }
|
|
373
|
+
return row.n
|
|
374
|
+
}
|
|
375
|
+
|
|
357
376
|
/** The amr column's honest parse (a JSON array of strings, else null —
|
|
358
377
|
* the provenance is absent on rows that predate the wave). */
|
|
359
378
|
function parseJsonStringList(raw: unknown): string[] | null {
|
package/src/store/sqlite.ts
CHANGED
|
@@ -120,6 +120,8 @@ import {
|
|
|
120
120
|
import {
|
|
121
121
|
consumeOidcCode,
|
|
122
122
|
consumeOidcRefreshToken,
|
|
123
|
+
countOidcAccessTokensForClient,
|
|
124
|
+
countOidcRefreshTokensForClient,
|
|
123
125
|
createOidcAccessToken,
|
|
124
126
|
createOidcAuthorization,
|
|
125
127
|
createOidcCode,
|
|
@@ -223,6 +225,7 @@ import {
|
|
|
223
225
|
import {
|
|
224
226
|
getConsentGrant,
|
|
225
227
|
listConsentGrants,
|
|
228
|
+
listOidcConsentGrantsForClient,
|
|
226
229
|
recordConsentGrant,
|
|
227
230
|
revokeConsentGrant,
|
|
228
231
|
} from './sqlite/consent-grants-store'
|
|
@@ -672,6 +675,9 @@ export function createSqliteServerStore(): ServerStore {
|
|
|
672
675
|
async deleteOidcAccessToken(token: string, clientId: string): Promise<boolean> {
|
|
673
676
|
return deleteOidcAccessToken(token, clientId)
|
|
674
677
|
},
|
|
678
|
+
async countOidcAccessTokensForClient(clientId: string): Promise<number> {
|
|
679
|
+
return countOidcAccessTokensForClient(clientId)
|
|
680
|
+
},
|
|
675
681
|
async createOidcRefreshToken(input: {
|
|
676
682
|
token: string
|
|
677
683
|
userId: string
|
|
@@ -694,6 +700,9 @@ export function createSqliteServerStore(): ServerStore {
|
|
|
694
700
|
async deleteOidcRefreshTokensForUserClient(userId: string, clientId: string): Promise<number> {
|
|
695
701
|
return deleteOidcRefreshTokensForUserClient(userId, clientId)
|
|
696
702
|
},
|
|
703
|
+
async countOidcRefreshTokensForClient(clientId: string): Promise<number> {
|
|
704
|
+
return countOidcRefreshTokensForClient(clientId)
|
|
705
|
+
},
|
|
697
706
|
async listOidcKeys(): Promise<OidcKeyRow[]> {
|
|
698
707
|
return listOidcKeys()
|
|
699
708
|
},
|
|
@@ -717,6 +726,9 @@ export function createSqliteServerStore(): ServerStore {
|
|
|
717
726
|
async revokeConsentGrant(id: string, userId: string): Promise<boolean> {
|
|
718
727
|
return revokeConsentGrant(id, userId)
|
|
719
728
|
},
|
|
729
|
+
async listOidcConsentGrantsForClient(clientId: string): Promise<OidcConsentGrant[]> {
|
|
730
|
+
return listOidcConsentGrantsForClient(clientId)
|
|
731
|
+
},
|
|
720
732
|
|
|
721
733
|
// ── the upstream providers (TODO.identity/08) ──
|
|
722
734
|
async listIdentityProviders(): Promise<IdentityProvider[]> {
|
package/src/store.ts
CHANGED
|
@@ -1684,6 +1684,12 @@ export interface ServerStore {
|
|
|
1684
1684
|
* client answers false). An absent row answers false too (the endpoint
|
|
1685
1685
|
* masks both behind its 200). */
|
|
1686
1686
|
deleteOidcAccessToken(token: string, clientId: string): Promise<boolean>
|
|
1687
|
+
/** The client-registry governance view's population read: the count of
|
|
1688
|
+
* the client's LIVE access tokens (unexpired — the row's absence IS the
|
|
1689
|
+
* revocation, so presence + liveness is standing). A count, never the
|
|
1690
|
+
* rows: the governance console answers "how many sessions stand behind
|
|
1691
|
+
* this client", never a token value. */
|
|
1692
|
+
countOidcAccessTokensForClient(clientId: string): Promise<number>
|
|
1687
1693
|
/** The refresh tokens (migration 0025 — the SSO wave-C token surface).
|
|
1688
1694
|
* The mint: token is the opaque value the route generated, familyId the
|
|
1689
1695
|
* rotation lineage (a fresh id at the code exchange's first mint, the
|
|
@@ -1717,6 +1723,12 @@ export interface ServerStore {
|
|
|
1717
1723
|
* (account, client) pair goes — the "Revoke access" act ends the
|
|
1718
1724
|
* offline half with the remembered consent. Answers the count. */
|
|
1719
1725
|
deleteOidcRefreshTokensForUserClient(userId: string, clientId: string): Promise<number>
|
|
1726
|
+
/** The client-registry governance view's population read: the count of
|
|
1727
|
+
* the client's LIVE refresh tokens (unconsumed AND unexpired — a
|
|
1728
|
+
* revoked family is DELETED wholesale, so a live row's presence is the
|
|
1729
|
+
* grant's standing). A count, never the rows: the console answers "how
|
|
1730
|
+
* many offline grants stand", never a token value. */
|
|
1731
|
+
countOidcRefreshTokensForClient(clientId: string): Promise<number>
|
|
1720
1732
|
/** The key rotation history (public halves). */
|
|
1721
1733
|
listOidcKeys(): Promise<OidcKeyRow[]>
|
|
1722
1734
|
upsertOidcKey(input: { kid: string; publicJwk: string }): Promise<void>
|
|
@@ -1743,6 +1755,13 @@ export interface ServerStore {
|
|
|
1743
1755
|
* live row — a second revoke or another account's row answers false
|
|
1744
1756
|
* (the PAT guard's posture). The row STAYS. */
|
|
1745
1757
|
revokeConsentGrant(id: string, userId: string): Promise<boolean>
|
|
1758
|
+
/** The client-registry governance view's per-client read: EVERY grant
|
|
1759
|
+
* row the client holds — live AND revoked (the account console's
|
|
1760
|
+
* listConsentGrants hides the revoked half; the governance view shows
|
|
1761
|
+
* the history the audit chain would otherwise carry alone), newest
|
|
1762
|
+
* first. Read-only: the acts stay on the account console and the
|
|
1763
|
+
* dashboard's revoke routes. */
|
|
1764
|
+
listOidcConsentGrantsForClient(clientId: string): Promise<OidcConsentGrant[]>
|
|
1746
1765
|
|
|
1747
1766
|
// ── the upstream providers (TODO.identity/08) ──
|
|
1748
1767
|
/** The upstream registry (admin-managed; OP_UPSTREAM_SEED bootstraps).
|