@adminiumjs/meta 0.2.2-rc.0 → 0.2.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/dist/ids.d.ts +6 -0
- package/dist/ids.d.ts.map +1 -1
- package/dist/ids.js +14 -0
- package/dist/ids.js.map +1 -1
- package/dist/migrations/0014_public_surface.d.ts +40 -0
- package/dist/migrations/0014_public_surface.d.ts.map +1 -0
- package/dist/migrations/0014_public_surface.js +186 -0
- package/dist/migrations/0014_public_surface.js.map +1 -0
- package/dist/migrations/0015_connection_tenant_config.d.ts +42 -0
- package/dist/migrations/0015_connection_tenant_config.d.ts.map +1 -0
- package/dist/migrations/0015_connection_tenant_config.js +53 -0
- package/dist/migrations/0015_connection_tenant_config.js.map +1 -0
- package/dist/migrations/0016_audit_entity.d.ts +33 -0
- package/dist/migrations/0016_audit_entity.d.ts.map +1 -0
- package/dist/migrations/0016_audit_entity.js +137 -0
- package/dist/migrations/0016_audit_entity.js.map +1 -0
- package/dist/migrations/0017_surface_binding.d.ts +23 -0
- package/dist/migrations/0017_surface_binding.d.ts.map +1 -0
- package/dist/migrations/0017_surface_binding.js +37 -0
- package/dist/migrations/0017_surface_binding.js.map +1 -0
- package/dist/migrations/0018_connection_timezone_source.d.ts +44 -0
- package/dist/migrations/0018_connection_timezone_source.d.ts.map +1 -0
- package/dist/migrations/0018_connection_timezone_source.js +51 -0
- package/dist/migrations/0018_connection_timezone_source.js.map +1 -0
- package/dist/migrations/0019_connection_disabled.d.ts +38 -0
- package/dist/migrations/0019_connection_disabled.d.ts.map +1 -0
- package/dist/migrations/0019_connection_disabled.js +43 -0
- package/dist/migrations/0019_connection_disabled.js.map +1 -0
- package/dist/migrations/0020_manifests_add_on.d.ts +71 -0
- package/dist/migrations/0020_manifests_add_on.d.ts.map +1 -0
- package/dist/migrations/0020_manifests_add_on.js +111 -0
- package/dist/migrations/0020_manifests_add_on.js.map +1 -0
- package/dist/migrations/0021_add_on_credentials.d.ts +50 -0
- package/dist/migrations/0021_add_on_credentials.d.ts.map +1 -0
- package/dist/migrations/0021_add_on_credentials.js +80 -0
- package/dist/migrations/0021_add_on_credentials.js.map +1 -0
- package/dist/migrations/0022_studio_namespace.d.ts +44 -0
- package/dist/migrations/0022_studio_namespace.d.ts.map +1 -0
- package/dist/migrations/0022_studio_namespace.js +113 -0
- package/dist/migrations/0022_studio_namespace.js.map +1 -0
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/migrations/index.js +18 -0
- package/dist/migrations/index.js.map +1 -1
- package/dist/relocate.d.ts +1 -1
- package/dist/relocate.js +1 -1
- package/dist/repos/audit.d.ts.map +1 -1
- package/dist/repos/audit.js +8 -2
- package/dist/repos/audit.js.map +1 -1
- package/dist/repos/connections.d.ts +62 -0
- package/dist/repos/connections.d.ts.map +1 -1
- package/dist/repos/connections.js +104 -0
- package/dist/repos/connections.js.map +1 -1
- package/dist/repos/index.d.ts +2 -0
- package/dist/repos/index.d.ts.map +1 -1
- package/dist/repos/index.js +2 -0
- package/dist/repos/index.js.map +1 -1
- package/dist/repos/manifests.d.ts +139 -0
- package/dist/repos/manifests.d.ts.map +1 -0
- package/dist/repos/manifests.js +279 -0
- package/dist/repos/manifests.js.map +1 -0
- package/dist/repos/pages.d.ts +7 -0
- package/dist/repos/pages.d.ts.map +1 -1
- package/dist/repos/pages.js +39 -8
- package/dist/repos/pages.js.map +1 -1
- package/dist/repos/public-api.d.ts +140 -0
- package/dist/repos/public-api.d.ts.map +1 -0
- package/dist/repos/public-api.js +299 -0
- package/dist/repos/public-api.js.map +1 -0
- package/dist/schema/json-payloads.d.ts +27 -2
- package/dist/schema/json-payloads.d.ts.map +1 -1
- package/dist/schema/json-payloads.js +41 -2
- package/dist/schema/json-payloads.js.map +1 -1
- package/dist/schema/settings-registry.d.ts +65 -0
- package/dist/schema/settings-registry.d.ts.map +1 -1
- package/dist/schema/settings-registry.js +183 -0
- package/dist/schema/settings-registry.js.map +1 -1
- package/dist/schema/tables.d.ts +177 -1
- package/dist/schema/tables.d.ts.map +1 -1
- package/dist/schema/tables.js +6 -0
- package/dist/schema/tables.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* publicScopesRepo / publicKeysRepo — the public surface's meta rows
|
|
3
|
+
* (28-public-surface.md §3.2–§3.3, migration `0014_public_surface`).
|
|
4
|
+
*
|
|
5
|
+
* Deliberately NOT part of `apiKeysRepo`. A publishable key differs from an
|
|
6
|
+
* `adm_sk_` key in two ways that both reach the storage layer: its secret is
|
|
7
|
+
* re-readable, and it must never be resolvable as an `RbacPrincipal` (D3).
|
|
8
|
+
* Sharing a repo would put both kinds one `where` clause apart, which is how a
|
|
9
|
+
* later "unify the key lookup" change would quietly break the property the
|
|
10
|
+
* whole off switch rests on.
|
|
11
|
+
*/
|
|
12
|
+
import type { Selectable } from 'kysely';
|
|
13
|
+
import type { MetaDb } from '../connect.js';
|
|
14
|
+
import type { AdminiumPublicKeysTable, AdminiumPublicScopesTable, AdminiumPublicSessionsTable } from '../schema/tables.js';
|
|
15
|
+
export type PublicScope = Selectable<AdminiumPublicScopesTable>;
|
|
16
|
+
export type PublicKey = Selectable<AdminiumPublicKeysTable>;
|
|
17
|
+
export type PublicSession = Selectable<AdminiumPublicSessionsTable>;
|
|
18
|
+
export interface CreatePublicScopeInput {
|
|
19
|
+
connectionId: string;
|
|
20
|
+
side: string;
|
|
21
|
+
name: string;
|
|
22
|
+
/** Canonical IANA zone; the compiler refuses anything else. */
|
|
23
|
+
timezone: string;
|
|
24
|
+
/** The scope document, already serialized. */
|
|
25
|
+
document: string;
|
|
26
|
+
proposedFromManifest?: string | null;
|
|
27
|
+
createdBy?: string | null;
|
|
28
|
+
}
|
|
29
|
+
export declare function publicScopesRepo(meta: MetaDb): {
|
|
30
|
+
create(input: CreatePublicScopeInput, at?: number): Promise<PublicScope>;
|
|
31
|
+
findById(id: string): Promise<PublicScope | null>;
|
|
32
|
+
list(): Promise<PublicScope[]>;
|
|
33
|
+
listByConnection(connectionId: string): Promise<PublicScope[]>;
|
|
34
|
+
update(id: string, patch: {
|
|
35
|
+
name?: string;
|
|
36
|
+
timezone?: string;
|
|
37
|
+
document?: string;
|
|
38
|
+
}, at?: number): Promise<boolean>;
|
|
39
|
+
/**
|
|
40
|
+
* Deleting a scope is refused while a key points at it — the FK is
|
|
41
|
+
* `restrict`, so this surfaces the constraint as `false` rather than as a
|
|
42
|
+
* driver error. Revoking the key first is the intended order, because it
|
|
43
|
+
* makes the operator see what they are about to break.
|
|
44
|
+
*/
|
|
45
|
+
remove(id: string): Promise<boolean>;
|
|
46
|
+
};
|
|
47
|
+
export interface CreatePublicKeyInput {
|
|
48
|
+
name: string;
|
|
49
|
+
/** Display/lookup fragment, e.g. `adm_pub_4f2a91cd`. */
|
|
50
|
+
prefix: string;
|
|
51
|
+
tokenHash: string;
|
|
52
|
+
/** AES-GCM envelope of the full token — the re-readable copy. */
|
|
53
|
+
tokenEncrypted: string;
|
|
54
|
+
scopeId: string;
|
|
55
|
+
side: string;
|
|
56
|
+
/** Hosted app surface this key is bound to (29 D10), or absent/null. */
|
|
57
|
+
appKey?: string | null;
|
|
58
|
+
/** JSON array narrowing the instance origin list; `[]` = no narrowing. */
|
|
59
|
+
origins?: string[];
|
|
60
|
+
createdBy?: string | null;
|
|
61
|
+
expiresAt?: number | null;
|
|
62
|
+
}
|
|
63
|
+
export declare function publicKeysRepo(meta: MetaDb): {
|
|
64
|
+
create(input: CreatePublicKeyInput, at?: number): Promise<PublicKey>;
|
|
65
|
+
/**
|
|
66
|
+
* The AUTH lookup, by prefix.
|
|
67
|
+
*
|
|
68
|
+
* Returns every candidate rather than filtering on the hash in SQL, because
|
|
69
|
+
* the caller compares hashes in CONSTANT TIME. A `where tokenHash = ?`
|
|
70
|
+
* makes the database do a byte comparison whose timing an attacker can
|
|
71
|
+
* measure; the prefix is a public display fragment and leaks nothing.
|
|
72
|
+
*
|
|
73
|
+
* Revocation and expiry are NOT filtered here either — the caller decides,
|
|
74
|
+
* so it can answer every failure identically on the wire (§3.2) instead of
|
|
75
|
+
* letting "no row" and "revoked row" take different code paths.
|
|
76
|
+
*/
|
|
77
|
+
findByPrefix(prefix: string): Promise<PublicKey[]>;
|
|
78
|
+
findById(id: string): Promise<PublicKey | null>;
|
|
79
|
+
listByScope(scopeId: string): Promise<PublicKey[]>;
|
|
80
|
+
/**
|
|
81
|
+
* The `surface-config.json` lookup (29 D10): the newest key for this app's
|
|
82
|
+
* side that is neither revoked nor expired. Rotation keeps the row (and so
|
|
83
|
+
* the binding); revoking the newest key falls back to the next live one, so
|
|
84
|
+
* an operator can stage a replacement before killing the old key.
|
|
85
|
+
*/
|
|
86
|
+
/**
|
|
87
|
+
* The newest live key for an app whose SCOPE points at one connection.
|
|
88
|
+
*
|
|
89
|
+
* What `newestLiveByApp` answers once per app, this answers once per
|
|
90
|
+
* database — the customer half of app instances (29 D9). A customer surface
|
|
91
|
+
* has never named its connection directly and does not start now: its key
|
|
92
|
+
* names a scope and the scope names the connection, so selecting the right
|
|
93
|
+
* key IS selecting the right database, and nothing new has to be kept in
|
|
94
|
+
* sync with anything.
|
|
95
|
+
*
|
|
96
|
+
* A join, not two queries: the pair "newest, and belonging to this
|
|
97
|
+
* connection" has to be decided together, or a scope moved between
|
|
98
|
+
* connections could hand back a key that was newest but no longer relevant.
|
|
99
|
+
*/
|
|
100
|
+
newestLiveByAppAndConnection(appKey: string, side: string, connectionId: string, at?: number): Promise<PublicKey | null>;
|
|
101
|
+
newestLiveByApp(appKey: string, side: string, at?: number): Promise<PublicKey | null>;
|
|
102
|
+
list(): Promise<PublicKey[]>;
|
|
103
|
+
/** Rotation: a new secret against the same row, keeping scope and origins. */
|
|
104
|
+
rotate(id: string, next: {
|
|
105
|
+
prefix: string;
|
|
106
|
+
tokenHash: string;
|
|
107
|
+
tokenEncrypted: string;
|
|
108
|
+
}, at?: number): Promise<boolean>;
|
|
109
|
+
revoke(id: string, at?: number): Promise<boolean>;
|
|
110
|
+
/** Throttled by the caller, like session and api-key touches. */
|
|
111
|
+
touchLastUsed(id: string, at?: number): Promise<void>;
|
|
112
|
+
};
|
|
113
|
+
export interface CreatePublicSessionInput {
|
|
114
|
+
keyId: string;
|
|
115
|
+
tokenHash: string;
|
|
116
|
+
/** The RESOLVED claim — see the table comment on why it is not re-derived. */
|
|
117
|
+
grants: string;
|
|
118
|
+
expiresAt: number;
|
|
119
|
+
}
|
|
120
|
+
export declare function publicSessionsRepo(meta: MetaDb): {
|
|
121
|
+
create(input: CreatePublicSessionInput, at?: number): Promise<PublicSession>;
|
|
122
|
+
/**
|
|
123
|
+
* Resolve a session token.
|
|
124
|
+
*
|
|
125
|
+
* Unlike `publicKeysRepo.findByPrefix`, matching on the hash in SQL is fine
|
|
126
|
+
* here: a session token has no public display fragment to look up by, so
|
|
127
|
+
* there is nothing to narrow on first. Expiry IS filtered, because an
|
|
128
|
+
* expired session and an unknown one are the same thing to the caller and
|
|
129
|
+
* there is no reason to carry the difference back up.
|
|
130
|
+
*/
|
|
131
|
+
findValid(tokenHash: string, at?: number): Promise<PublicSession | null>;
|
|
132
|
+
touch(id: string, at?: number): Promise<void>;
|
|
133
|
+
remove(tokenHash: string): Promise<boolean>;
|
|
134
|
+
/** Housekeeping: drop everything that has lapsed. */
|
|
135
|
+
purgeExpired(at?: number): Promise<number>;
|
|
136
|
+
};
|
|
137
|
+
export type PublicSessionsRepo = ReturnType<typeof publicSessionsRepo>;
|
|
138
|
+
export type PublicScopesRepo = ReturnType<typeof publicScopesRepo>;
|
|
139
|
+
export type PublicKeysRepo = ReturnType<typeof publicKeysRepo>;
|
|
140
|
+
//# sourceMappingURL=public-api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public-api.d.ts","sourceRoot":"","sources":["../../src/repos/public-api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
/**
|
|
3
|
+
* publicScopesRepo / publicKeysRepo — the public surface's meta rows
|
|
4
|
+
* (28-public-surface.md §3.2–§3.3, migration `0014_public_surface`).
|
|
5
|
+
*
|
|
6
|
+
* Deliberately NOT part of `apiKeysRepo`. A publishable key differs from an
|
|
7
|
+
* `adm_sk_` key in two ways that both reach the storage layer: its secret is
|
|
8
|
+
* re-readable, and it must never be resolvable as an `RbacPrincipal` (D3).
|
|
9
|
+
* Sharing a repo would put both kinds one `where` clause apart, which is how a
|
|
10
|
+
* later "unify the key lookup" change would quietly break the property the
|
|
11
|
+
* whole off switch rests on.
|
|
12
|
+
*/
|
|
13
|
+
import { newId } from '../ids.js';
|
|
14
|
+
/**
|
|
15
|
+
* A `json` column does not come back the same shape on every store.
|
|
16
|
+
*
|
|
17
|
+
* postgres and mysql hand back a PARSED value; sqlite hands back the text it
|
|
18
|
+
* stored. `PublicScope.document` is declared `string` and every caller treats
|
|
19
|
+
* it as one — `resolve.ts` calls `JSON.parse` on it, and the admin route
|
|
20
|
+
* returns it under a `z.string()` response schema — so on the two production
|
|
21
|
+
* stores that parse threw and that response failed validation, while the whole
|
|
22
|
+
* suite stayed green on sqlite. Found by CI, which runs all three; the local
|
|
23
|
+
* run skipped 334 store-gated tests.
|
|
24
|
+
*
|
|
25
|
+
* Normalising here rather than at each caller is the point of a repo layer:
|
|
26
|
+
* the driver difference is this file's business and nobody else's.
|
|
27
|
+
*/
|
|
28
|
+
function jsonText(value) {
|
|
29
|
+
return typeof value === "string" ? value : JSON.stringify(value);
|
|
30
|
+
}
|
|
31
|
+
/** One scope row, with its document normalised to text whatever the store did. */
|
|
32
|
+
function scopeRow(row) {
|
|
33
|
+
return { ...row, document: jsonText(row.document) };
|
|
34
|
+
}
|
|
35
|
+
export function publicScopesRepo(meta) {
|
|
36
|
+
const { db } = meta;
|
|
37
|
+
return {
|
|
38
|
+
async create(input, at = Date.now()) {
|
|
39
|
+
const row = {
|
|
40
|
+
id: newId('psc'),
|
|
41
|
+
connectionId: input.connectionId,
|
|
42
|
+
side: input.side,
|
|
43
|
+
name: input.name,
|
|
44
|
+
timezone: input.timezone,
|
|
45
|
+
document: input.document,
|
|
46
|
+
proposedFromManifest: input.proposedFromManifest ?? null,
|
|
47
|
+
createdBy: input.createdBy ?? null,
|
|
48
|
+
createdAt: at,
|
|
49
|
+
updatedAt: at,
|
|
50
|
+
};
|
|
51
|
+
await db.insertInto('adminium_public_scopes').values(row).execute();
|
|
52
|
+
return row;
|
|
53
|
+
},
|
|
54
|
+
async findById(id) {
|
|
55
|
+
const row = await db
|
|
56
|
+
.selectFrom('adminium_public_scopes')
|
|
57
|
+
.selectAll()
|
|
58
|
+
.where('id', '=', id)
|
|
59
|
+
.executeTakeFirst();
|
|
60
|
+
return row === undefined ? null : scopeRow(row);
|
|
61
|
+
},
|
|
62
|
+
async list() {
|
|
63
|
+
const rows = await db
|
|
64
|
+
.selectFrom('adminium_public_scopes')
|
|
65
|
+
.selectAll()
|
|
66
|
+
.orderBy('createdAt', 'desc')
|
|
67
|
+
.execute();
|
|
68
|
+
return rows.map(scopeRow);
|
|
69
|
+
},
|
|
70
|
+
async listByConnection(connectionId) {
|
|
71
|
+
const rows = await db
|
|
72
|
+
.selectFrom('adminium_public_scopes')
|
|
73
|
+
.selectAll()
|
|
74
|
+
.where('connectionId', '=', connectionId)
|
|
75
|
+
.orderBy('createdAt', 'desc')
|
|
76
|
+
.execute();
|
|
77
|
+
return rows.map(scopeRow);
|
|
78
|
+
},
|
|
79
|
+
async update(id, patch, at = Date.now()) {
|
|
80
|
+
const res = await db
|
|
81
|
+
.updateTable('adminium_public_scopes')
|
|
82
|
+
.set({ ...patch, updatedAt: at })
|
|
83
|
+
.where('id', '=', id)
|
|
84
|
+
.executeTakeFirst();
|
|
85
|
+
return Number(res.numUpdatedRows) === 1;
|
|
86
|
+
},
|
|
87
|
+
/**
|
|
88
|
+
* Deleting a scope is refused while a key points at it — the FK is
|
|
89
|
+
* `restrict`, so this surfaces the constraint as `false` rather than as a
|
|
90
|
+
* driver error. Revoking the key first is the intended order, because it
|
|
91
|
+
* makes the operator see what they are about to break.
|
|
92
|
+
*/
|
|
93
|
+
async remove(id) {
|
|
94
|
+
const attached = await db
|
|
95
|
+
.selectFrom('adminium_public_keys')
|
|
96
|
+
.select('id')
|
|
97
|
+
.where('scopeId', '=', id)
|
|
98
|
+
.executeTakeFirst();
|
|
99
|
+
if (attached !== undefined)
|
|
100
|
+
return false;
|
|
101
|
+
const res = await db
|
|
102
|
+
.deleteFrom('adminium_public_scopes')
|
|
103
|
+
.where('id', '=', id)
|
|
104
|
+
.executeTakeFirst();
|
|
105
|
+
return Number(res.numDeletedRows) === 1;
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
export function publicKeysRepo(meta) {
|
|
110
|
+
const { db } = meta;
|
|
111
|
+
return {
|
|
112
|
+
async create(input, at = Date.now()) {
|
|
113
|
+
const row = {
|
|
114
|
+
id: newId('pbk'),
|
|
115
|
+
name: input.name,
|
|
116
|
+
prefix: input.prefix,
|
|
117
|
+
tokenHash: input.tokenHash,
|
|
118
|
+
tokenEncrypted: input.tokenEncrypted,
|
|
119
|
+
scopeId: input.scopeId,
|
|
120
|
+
side: input.side,
|
|
121
|
+
appKey: input.appKey ?? null,
|
|
122
|
+
origins: JSON.stringify(input.origins ?? []),
|
|
123
|
+
expiresAt: input.expiresAt ?? null,
|
|
124
|
+
revokedAt: null,
|
|
125
|
+
lastUsedAt: null,
|
|
126
|
+
createdBy: input.createdBy ?? null,
|
|
127
|
+
createdAt: at,
|
|
128
|
+
updatedAt: at,
|
|
129
|
+
};
|
|
130
|
+
await db.insertInto('adminium_public_keys').values(row).execute();
|
|
131
|
+
return row;
|
|
132
|
+
},
|
|
133
|
+
/**
|
|
134
|
+
* The AUTH lookup, by prefix.
|
|
135
|
+
*
|
|
136
|
+
* Returns every candidate rather than filtering on the hash in SQL, because
|
|
137
|
+
* the caller compares hashes in CONSTANT TIME. A `where tokenHash = ?`
|
|
138
|
+
* makes the database do a byte comparison whose timing an attacker can
|
|
139
|
+
* measure; the prefix is a public display fragment and leaks nothing.
|
|
140
|
+
*
|
|
141
|
+
* Revocation and expiry are NOT filtered here either — the caller decides,
|
|
142
|
+
* so it can answer every failure identically on the wire (§3.2) instead of
|
|
143
|
+
* letting "no row" and "revoked row" take different code paths.
|
|
144
|
+
*/
|
|
145
|
+
async findByPrefix(prefix) {
|
|
146
|
+
return db
|
|
147
|
+
.selectFrom('adminium_public_keys')
|
|
148
|
+
.selectAll()
|
|
149
|
+
.where('prefix', '=', prefix)
|
|
150
|
+
.execute();
|
|
151
|
+
},
|
|
152
|
+
async findById(id) {
|
|
153
|
+
const row = await db
|
|
154
|
+
.selectFrom('adminium_public_keys')
|
|
155
|
+
.selectAll()
|
|
156
|
+
.where('id', '=', id)
|
|
157
|
+
.executeTakeFirst();
|
|
158
|
+
return row ?? null;
|
|
159
|
+
},
|
|
160
|
+
async listByScope(scopeId) {
|
|
161
|
+
return db
|
|
162
|
+
.selectFrom('adminium_public_keys')
|
|
163
|
+
.selectAll()
|
|
164
|
+
.where('scopeId', '=', scopeId)
|
|
165
|
+
.orderBy('createdAt', 'desc')
|
|
166
|
+
.execute();
|
|
167
|
+
},
|
|
168
|
+
/**
|
|
169
|
+
* The `surface-config.json` lookup (29 D10): the newest key for this app's
|
|
170
|
+
* side that is neither revoked nor expired. Rotation keeps the row (and so
|
|
171
|
+
* the binding); revoking the newest key falls back to the next live one, so
|
|
172
|
+
* an operator can stage a replacement before killing the old key.
|
|
173
|
+
*/
|
|
174
|
+
/**
|
|
175
|
+
* The newest live key for an app whose SCOPE points at one connection.
|
|
176
|
+
*
|
|
177
|
+
* What `newestLiveByApp` answers once per app, this answers once per
|
|
178
|
+
* database — the customer half of app instances (29 D9). A customer surface
|
|
179
|
+
* has never named its connection directly and does not start now: its key
|
|
180
|
+
* names a scope and the scope names the connection, so selecting the right
|
|
181
|
+
* key IS selecting the right database, and nothing new has to be kept in
|
|
182
|
+
* sync with anything.
|
|
183
|
+
*
|
|
184
|
+
* A join, not two queries: the pair "newest, and belonging to this
|
|
185
|
+
* connection" has to be decided together, or a scope moved between
|
|
186
|
+
* connections could hand back a key that was newest but no longer relevant.
|
|
187
|
+
*/
|
|
188
|
+
async newestLiveByAppAndConnection(appKey, side, connectionId, at = Date.now()) {
|
|
189
|
+
const row = await db
|
|
190
|
+
.selectFrom('adminium_public_keys')
|
|
191
|
+
.innerJoin('adminium_public_scopes', 'adminium_public_scopes.id', 'adminium_public_keys.scopeId')
|
|
192
|
+
.selectAll('adminium_public_keys')
|
|
193
|
+
.where('adminium_public_keys.appKey', '=', appKey)
|
|
194
|
+
.where('adminium_public_keys.side', '=', side)
|
|
195
|
+
.where('adminium_public_scopes.connectionId', '=', connectionId)
|
|
196
|
+
.where('adminium_public_keys.revokedAt', 'is', null)
|
|
197
|
+
.where((eb) => eb.or([
|
|
198
|
+
eb('adminium_public_keys.expiresAt', 'is', null),
|
|
199
|
+
eb('adminium_public_keys.expiresAt', '>', at),
|
|
200
|
+
]))
|
|
201
|
+
.orderBy('adminium_public_keys.createdAt', 'desc')
|
|
202
|
+
.executeTakeFirst();
|
|
203
|
+
return row ?? null;
|
|
204
|
+
},
|
|
205
|
+
async newestLiveByApp(appKey, side, at = Date.now()) {
|
|
206
|
+
const row = await db
|
|
207
|
+
.selectFrom('adminium_public_keys')
|
|
208
|
+
.selectAll()
|
|
209
|
+
.where('appKey', '=', appKey)
|
|
210
|
+
.where('side', '=', side)
|
|
211
|
+
.where('revokedAt', 'is', null)
|
|
212
|
+
.where((eb) => eb.or([eb('expiresAt', 'is', null), eb('expiresAt', '>', at)]))
|
|
213
|
+
.orderBy('createdAt', 'desc')
|
|
214
|
+
.executeTakeFirst();
|
|
215
|
+
return row ?? null;
|
|
216
|
+
},
|
|
217
|
+
async list() {
|
|
218
|
+
return db.selectFrom('adminium_public_keys').selectAll().orderBy('createdAt', 'desc').execute();
|
|
219
|
+
},
|
|
220
|
+
/** Rotation: a new secret against the same row, keeping scope and origins. */
|
|
221
|
+
async rotate(id, next, at = Date.now()) {
|
|
222
|
+
const res = await db
|
|
223
|
+
.updateTable('adminium_public_keys')
|
|
224
|
+
.set({ ...next, updatedAt: at })
|
|
225
|
+
.where('id', '=', id)
|
|
226
|
+
.where('revokedAt', 'is', null)
|
|
227
|
+
.executeTakeFirst();
|
|
228
|
+
return Number(res.numUpdatedRows) === 1;
|
|
229
|
+
},
|
|
230
|
+
async revoke(id, at = Date.now()) {
|
|
231
|
+
const res = await db
|
|
232
|
+
.updateTable('adminium_public_keys')
|
|
233
|
+
.set({ revokedAt: at, updatedAt: at })
|
|
234
|
+
.where('id', '=', id)
|
|
235
|
+
.where('revokedAt', 'is', null)
|
|
236
|
+
.executeTakeFirst();
|
|
237
|
+
return Number(res.numUpdatedRows) === 1;
|
|
238
|
+
},
|
|
239
|
+
/** Throttled by the caller, like session and api-key touches. */
|
|
240
|
+
async touchLastUsed(id, at = Date.now()) {
|
|
241
|
+
await db.updateTable('adminium_public_keys').set({ lastUsedAt: at }).where('id', '=', id).execute();
|
|
242
|
+
},
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
export function publicSessionsRepo(meta) {
|
|
246
|
+
const { db } = meta;
|
|
247
|
+
return {
|
|
248
|
+
async create(input, at = Date.now()) {
|
|
249
|
+
const row = {
|
|
250
|
+
id: newId('pss'),
|
|
251
|
+
keyId: input.keyId,
|
|
252
|
+
tokenHash: input.tokenHash,
|
|
253
|
+
grants: input.grants,
|
|
254
|
+
expiresAt: input.expiresAt,
|
|
255
|
+
createdAt: at,
|
|
256
|
+
lastSeenAt: null,
|
|
257
|
+
};
|
|
258
|
+
await db.insertInto('adminium_public_sessions').values(row).execute();
|
|
259
|
+
return row;
|
|
260
|
+
},
|
|
261
|
+
/**
|
|
262
|
+
* Resolve a session token.
|
|
263
|
+
*
|
|
264
|
+
* Unlike `publicKeysRepo.findByPrefix`, matching on the hash in SQL is fine
|
|
265
|
+
* here: a session token has no public display fragment to look up by, so
|
|
266
|
+
* there is nothing to narrow on first. Expiry IS filtered, because an
|
|
267
|
+
* expired session and an unknown one are the same thing to the caller and
|
|
268
|
+
* there is no reason to carry the difference back up.
|
|
269
|
+
*/
|
|
270
|
+
async findValid(tokenHash, at = Date.now()) {
|
|
271
|
+
const row = await db
|
|
272
|
+
.selectFrom('adminium_public_sessions')
|
|
273
|
+
.selectAll()
|
|
274
|
+
.where('tokenHash', '=', tokenHash)
|
|
275
|
+
.where('expiresAt', '>', at)
|
|
276
|
+
.executeTakeFirst();
|
|
277
|
+
return row ?? null;
|
|
278
|
+
},
|
|
279
|
+
async touch(id, at = Date.now()) {
|
|
280
|
+
await db.updateTable('adminium_public_sessions').set({ lastSeenAt: at }).where('id', '=', id).execute();
|
|
281
|
+
},
|
|
282
|
+
async remove(tokenHash) {
|
|
283
|
+
const res = await db
|
|
284
|
+
.deleteFrom('adminium_public_sessions')
|
|
285
|
+
.where('tokenHash', '=', tokenHash)
|
|
286
|
+
.executeTakeFirst();
|
|
287
|
+
return Number(res.numDeletedRows) > 0;
|
|
288
|
+
},
|
|
289
|
+
/** Housekeeping: drop everything that has lapsed. */
|
|
290
|
+
async purgeExpired(at = Date.now()) {
|
|
291
|
+
const res = await db
|
|
292
|
+
.deleteFrom('adminium_public_sessions')
|
|
293
|
+
.where('expiresAt', '<=', at)
|
|
294
|
+
.executeTakeFirst();
|
|
295
|
+
return Number(res.numDeletedRows);
|
|
296
|
+
},
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
//# sourceMappingURL=public-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public-api.js","sourceRoot":"","sources":["../../src/repos/public-api.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC;;;;;;;;;;GAUG;AAKH,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAuBlC;;;;;;;;;;;;;GAaG;AACH,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AACnE,CAAC;AAED,kFAAkF;AAClF,SAAS,QAAQ,CAAC,GAAgB;IAChC,OAAO,EAAE,GAAG,GAAG,EAAE,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,MAAM,EAAE,EAAE,EAAE,GAAG,IAAI,CAAC;IACpB,OAAO;QACL,KAAK,CAAC,MAAM,CAAC,KAA6B,EAAE,KAAa,IAAI,CAAC,GAAG,EAAE;YACjE,MAAM,GAAG,GAAgB;gBACvB,EAAE,EAAE,KAAK,CAAC,KAAK,CAAC;gBAChB,YAAY,EAAE,KAAK,CAAC,YAAY;gBAChC,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,oBAAoB,EAAE,KAAK,CAAC,oBAAoB,IAAI,IAAI;gBACxD,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,IAAI;gBAClC,SAAS,EAAE,EAAE;gBACb,SAAS,EAAE,EAAE;aACd,CAAC;YACF,MAAM,EAAE,CAAC,UAAU,CAAC,wBAAwB,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC;YACpE,OAAO,GAAG,CAAC;QACb,CAAC;QAED,KAAK,CAAC,QAAQ,CAAC,EAAU;YACvB,MAAM,GAAG,GAAG,MAAM,EAAE;iBACjB,UAAU,CAAC,wBAAwB,CAAC;iBACpC,SAAS,EAAE;iBACX,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;iBACpB,gBAAgB,EAAE,CAAC;YACtB,OAAO,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAClD,CAAC;QAED,KAAK,CAAC,IAAI;YACR,MAAM,IAAI,GAAG,MAAM,EAAE;iBAClB,UAAU,CAAC,wBAAwB,CAAC;iBACpC,SAAS,EAAE;iBACX,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC;iBAC5B,OAAO,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC5B,CAAC;QAED,KAAK,CAAC,gBAAgB,CAAC,YAAoB;YACzC,MAAM,IAAI,GAAG,MAAM,EAAE;iBAClB,UAAU,CAAC,wBAAwB,CAAC;iBACpC,SAAS,EAAE;iBACX,KAAK,CAAC,cAAc,EAAE,GAAG,EAAE,YAAY,CAAC;iBACxC,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC;iBAC5B,OAAO,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC5B,CAAC;QAED,KAAK,CAAC,MAAM,CACV,EAAU,EACV,KAA8D,EAC9D,KAAa,IAAI,CAAC,GAAG,EAAE;YAEvB,MAAM,GAAG,GAAG,MAAM,EAAE;iBACjB,WAAW,CAAC,wBAAwB,CAAC;iBACrC,GAAG,CAAC,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;iBAChC,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;iBACpB,gBAAgB,EAAE,CAAC;YACtB,OAAO,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QAC1C,CAAC;QAED;;;;;WAKG;QACH,KAAK,CAAC,MAAM,CAAC,EAAU;YACrB,MAAM,QAAQ,GAAG,MAAM,EAAE;iBACtB,UAAU,CAAC,sBAAsB,CAAC;iBAClC,MAAM,CAAC,IAAI,CAAC;iBACZ,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,EAAE,CAAC;iBACzB,gBAAgB,EAAE,CAAC;YACtB,IAAI,QAAQ,KAAK,SAAS;gBAAE,OAAO,KAAK,CAAC;YACzC,MAAM,GAAG,GAAG,MAAM,EAAE;iBACjB,UAAU,CAAC,wBAAwB,CAAC;iBACpC,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;iBACpB,gBAAgB,EAAE,CAAC;YACtB,OAAO,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QAC1C,CAAC;KACF,CAAC;AACJ,CAAC;AAmBD,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,EAAE,EAAE,EAAE,GAAG,IAAI,CAAC;IACpB,OAAO;QACL,KAAK,CAAC,MAAM,CAAC,KAA2B,EAAE,KAAa,IAAI,CAAC,GAAG,EAAE;YAC/D,MAAM,GAAG,GAAc;gBACrB,EAAE,EAAE,KAAK,CAAC,KAAK,CAAC;gBAChB,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,cAAc,EAAE,KAAK,CAAC,cAAc;gBACpC,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,IAAI;gBAC5B,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC;gBAC5C,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,IAAI;gBAClC,SAAS,EAAE,IAAI;gBACf,UAAU,EAAE,IAAI;gBAChB,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,IAAI;gBAClC,SAAS,EAAE,EAAE;gBACb,SAAS,EAAE,EAAE;aACd,CAAC;YACF,MAAM,EAAE,CAAC,UAAU,CAAC,sBAAsB,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC;YAClE,OAAO,GAAG,CAAC;QACb,CAAC;QAED;;;;;;;;;;;WAWG;QACH,KAAK,CAAC,YAAY,CAAC,MAAc;YAC/B,OAAO,EAAE;iBACN,UAAU,CAAC,sBAAsB,CAAC;iBAClC,SAAS,EAAE;iBACX,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,MAAM,CAAC;iBAC5B,OAAO,EAAE,CAAC;QACf,CAAC;QAED,KAAK,CAAC,QAAQ,CAAC,EAAU;YACvB,MAAM,GAAG,GAAG,MAAM,EAAE;iBACjB,UAAU,CAAC,sBAAsB,CAAC;iBAClC,SAAS,EAAE;iBACX,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;iBACpB,gBAAgB,EAAE,CAAC;YACtB,OAAO,GAAG,IAAI,IAAI,CAAC;QACrB,CAAC;QAED,KAAK,CAAC,WAAW,CAAC,OAAe;YAC/B,OAAO,EAAE;iBACN,UAAU,CAAC,sBAAsB,CAAC;iBAClC,SAAS,EAAE;iBACX,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,OAAO,CAAC;iBAC9B,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC;iBAC5B,OAAO,EAAE,CAAC;QACf,CAAC;QAED;;;;;WAKG;QACH;;;;;;;;;;;;;WAaG;QACH,KAAK,CAAC,4BAA4B,CAChC,MAAc,EACd,IAAY,EACZ,YAAoB,EACpB,KAAa,IAAI,CAAC,GAAG,EAAE;YAEvB,MAAM,GAAG,GAAG,MAAM,EAAE;iBACjB,UAAU,CAAC,sBAAsB,CAAC;iBAClC,SAAS,CACR,wBAAwB,EACxB,2BAA2B,EAC3B,8BAA8B,CAC/B;iBACA,SAAS,CAAC,sBAAsB,CAAC;iBACjC,KAAK,CAAC,6BAA6B,EAAE,GAAG,EAAE,MAAM,CAAC;iBACjD,KAAK,CAAC,2BAA2B,EAAE,GAAG,EAAE,IAAI,CAAC;iBAC7C,KAAK,CAAC,qCAAqC,EAAE,GAAG,EAAE,YAAY,CAAC;iBAC/D,KAAK,CAAC,gCAAgC,EAAE,IAAI,EAAE,IAAI,CAAC;iBACnD,KAAK,CAAC,CAAC,EAAE,EAAE,EAAE,CACZ,EAAE,CAAC,EAAE,CAAC;gBACJ,EAAE,CAAC,gCAAgC,EAAE,IAAI,EAAE,IAAI,CAAC;gBAChD,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE,EAAE,CAAC;aAC9C,CAAC,CACH;iBACA,OAAO,CAAC,gCAAgC,EAAE,MAAM,CAAC;iBACjD,gBAAgB,EAAE,CAAC;YACtB,OAAO,GAAG,IAAI,IAAI,CAAC;QACrB,CAAC;QAED,KAAK,CAAC,eAAe,CACnB,MAAc,EACd,IAAY,EACZ,KAAa,IAAI,CAAC,GAAG,EAAE;YAEvB,MAAM,GAAG,GAAG,MAAM,EAAE;iBACjB,UAAU,CAAC,sBAAsB,CAAC;iBAClC,SAAS,EAAE;iBACX,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,MAAM,CAAC;iBAC5B,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC;iBACxB,KAAK,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,CAAC;iBAC9B,KAAK,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,WAAW,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;iBAC7E,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC;iBAC5B,gBAAgB,EAAE,CAAC;YACtB,OAAO,GAAG,IAAI,IAAI,CAAC;QACrB,CAAC;QAED,KAAK,CAAC,IAAI;YACR,OAAO,EAAE,CAAC,UAAU,CAAC,sBAAsB,CAAC,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC;QAClG,CAAC;QAED,8EAA8E;QAC9E,KAAK,CAAC,MAAM,CACV,EAAU,EACV,IAAmE,EACnE,KAAa,IAAI,CAAC,GAAG,EAAE;YAEvB,MAAM,GAAG,GAAG,MAAM,EAAE;iBACjB,WAAW,CAAC,sBAAsB,CAAC;iBACnC,GAAG,CAAC,EAAE,GAAG,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;iBAC/B,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;iBACpB,KAAK,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,CAAC;iBAC9B,gBAAgB,EAAE,CAAC;YACtB,OAAO,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QAC1C,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,EAAU,EAAE,KAAa,IAAI,CAAC,GAAG,EAAE;YAC9C,MAAM,GAAG,GAAG,MAAM,EAAE;iBACjB,WAAW,CAAC,sBAAsB,CAAC;iBACnC,GAAG,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;iBACrC,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;iBACpB,KAAK,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,CAAC;iBAC9B,gBAAgB,EAAE,CAAC;YACtB,OAAO,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QAC1C,CAAC;QAED,iEAAiE;QACjE,KAAK,CAAC,aAAa,CAAC,EAAU,EAAE,KAAa,IAAI,CAAC,GAAG,EAAE;YACrD,MAAM,EAAE,CAAC,WAAW,CAAC,sBAAsB,CAAC,CAAC,GAAG,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;QACtG,CAAC;KACF,CAAC;AACJ,CAAC;AAUD,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,MAAM,EAAE,EAAE,EAAE,GAAG,IAAI,CAAC;IACpB,OAAO;QACL,KAAK,CAAC,MAAM,CAAC,KAA+B,EAAE,KAAa,IAAI,CAAC,GAAG,EAAE;YACnE,MAAM,GAAG,GAAkB;gBACzB,EAAE,EAAE,KAAK,CAAC,KAAK,CAAC;gBAChB,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,SAAS,EAAE,EAAE;gBACb,UAAU,EAAE,IAAI;aACjB,CAAC;YACF,MAAM,EAAE,CAAC,UAAU,CAAC,0BAA0B,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC;YACtE,OAAO,GAAG,CAAC;QACb,CAAC;QAED;;;;;;;;WAQG;QACH,KAAK,CAAC,SAAS,CAAC,SAAiB,EAAE,KAAa,IAAI,CAAC,GAAG,EAAE;YACxD,MAAM,GAAG,GAAG,MAAM,EAAE;iBACjB,UAAU,CAAC,0BAA0B,CAAC;iBACtC,SAAS,EAAE;iBACX,KAAK,CAAC,WAAW,EAAE,GAAG,EAAE,SAAS,CAAC;iBAClC,KAAK,CAAC,WAAW,EAAE,GAAG,EAAE,EAAE,CAAC;iBAC3B,gBAAgB,EAAE,CAAC;YACtB,OAAO,GAAG,IAAI,IAAI,CAAC;QACrB,CAAC;QAED,KAAK,CAAC,KAAK,CAAC,EAAU,EAAE,KAAa,IAAI,CAAC,GAAG,EAAE;YAC7C,MAAM,EAAE,CAAC,WAAW,CAAC,0BAA0B,CAAC,CAAC,GAAG,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;QAC1G,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,SAAiB;YAC5B,MAAM,GAAG,GAAG,MAAM,EAAE;iBACjB,UAAU,CAAC,0BAA0B,CAAC;iBACtC,KAAK,CAAC,WAAW,EAAE,GAAG,EAAE,SAAS,CAAC;iBAClC,gBAAgB,EAAE,CAAC;YACtB,OAAO,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;QACxC,CAAC;QAED,qDAAqD;QACrD,KAAK,CAAC,YAAY,CAAC,KAAa,IAAI,CAAC,GAAG,EAAE;YACxC,MAAM,GAAG,GAAG,MAAM,EAAE;iBACjB,UAAU,CAAC,0BAA0B,CAAC;iBACtC,KAAK,CAAC,WAAW,EAAE,IAAI,EAAE,EAAE,CAAC;iBAC5B,gBAAgB,EAAE,CAAC;YACtB,OAAO,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QACpC,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -16,6 +16,30 @@ export declare const recordRefSchema: z.ZodObject<{
|
|
|
16
16
|
label: z.ZodString;
|
|
17
17
|
}, z.core.$strip>;
|
|
18
18
|
export type RecordRef = z.infer<typeof recordRefSchema>;
|
|
19
|
+
/**
|
|
20
|
+
* Width of the denormalized `adminium_audit_log.entity_table` / `entity_id`
|
|
21
|
+
* columns (30-record-pages.md WS-A). 200 chars keeps the composite index
|
|
22
|
+
* inside MySQL's 3072-byte InnoDB cap under utf8mb4 (2 × 200 × 4 + 8).
|
|
23
|
+
*/
|
|
24
|
+
export declare const AUDIT_ENTITY_KEY_MAX = 200;
|
|
25
|
+
/**
|
|
26
|
+
* Canonical clamp for one audit entity key part. Applied on the WRITE side
|
|
27
|
+
* (append + backfill) and again on the QUERY side, so an over-long id still
|
|
28
|
+
* matches the row it wrote — truncation is consistent, never one-sided.
|
|
29
|
+
*/
|
|
30
|
+
export declare function auditEntityKeyPart(value: string): string;
|
|
31
|
+
/**
|
|
32
|
+
* The denormalized per-record audit key derived from a RecordRef (30 WS-A).
|
|
33
|
+
*
|
|
34
|
+
* `entityId` reproduces the canonical `:recordId` string both sides already
|
|
35
|
+
* use — `pkLabel` on the server, `rowIdOf` in the grid: a single-column PK is
|
|
36
|
+
* its stringified value, a composite PK is the JSON tuple of its values in pk
|
|
37
|
+
* insertion order (the order both writers build the map in).
|
|
38
|
+
*/
|
|
39
|
+
export declare function auditEntityKeyOf(ref: Pick<RecordRef, 'table' | 'pk'>): {
|
|
40
|
+
entityTable: string;
|
|
41
|
+
entityId: string;
|
|
42
|
+
};
|
|
19
43
|
/** The eight COMPILED locales. Still a closed set — see `builtinLocaleSchema`. */
|
|
20
44
|
export declare const LOCALES: readonly ["en_US", "de_DE", "ar_EG", "zh_CN", "zh_TW", "cs_CZ", "da_DK", "fr_FR"];
|
|
21
45
|
export declare const builtinLocaleSchema: z.ZodEnum<{
|
|
@@ -140,7 +164,7 @@ export declare const systemActionKeySchema: z.ZodEnum<{
|
|
|
140
164
|
* {@link GRANTABLE_SYSTEM_ACTION_KEYS}; move a key out of here in the same
|
|
141
165
|
* change that lands its first enforcement point.
|
|
142
166
|
*/
|
|
143
|
-
export declare const RESERVED_SYSTEM_ACTION_KEYS: readonly ["automations.manage", "webhooks.manage", "
|
|
167
|
+
export declare const RESERVED_SYSTEM_ACTION_KEYS: readonly ["automations.manage", "webhooks.manage", "sql.run"];
|
|
144
168
|
export type ReservedSystemActionKey = (typeof RESERVED_SYSTEM_ACTION_KEYS)[number];
|
|
145
169
|
/**
|
|
146
170
|
* What a role editor / permissions surface may offer: the closed set minus
|
|
@@ -169,6 +193,7 @@ export declare const auditCategorySchema: z.ZodEnum<{
|
|
|
169
193
|
rbac: "rbac";
|
|
170
194
|
connection: "connection";
|
|
171
195
|
llm: "llm";
|
|
196
|
+
"add-on": "add-on";
|
|
172
197
|
}>;
|
|
173
198
|
export type AuditCategory = z.infer<typeof auditCategorySchema>;
|
|
174
199
|
/** `{ before, after }` images; PII-masked upstream; capped at 16 KB serialized. */
|
|
@@ -376,11 +401,11 @@ export declare const llmValidationStatusSchema: z.ZodEnum<{
|
|
|
376
401
|
*/
|
|
377
402
|
export declare const llmRunStatusSchema: z.ZodEnum<{
|
|
378
403
|
draft: "draft";
|
|
379
|
-
applied: "applied";
|
|
380
404
|
running: "running";
|
|
381
405
|
failed: "failed";
|
|
382
406
|
awaiting_response: "awaiting_response";
|
|
383
407
|
validated: "validated";
|
|
408
|
+
applied: "applied";
|
|
384
409
|
partially_applied: "partially_applied";
|
|
385
410
|
discarded: "discarded";
|
|
386
411
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-payloads.d.ts","sourceRoot":"","sources":["../../src/schema/json-payloads.ts"],"names":[],"mappings":"AACA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,0EAA0E;AAC1E,eAAO,MAAM,eAAe;;;;;iBAQ1B,CAAC;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAExD,kFAAkF;AAClF,eAAO,MAAM,OAAO,mFAAoF,CAAC;AACzG,eAAO,MAAM,mBAAmB;;;;;;;;;EAAkB,CAAC;AACnD,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,8EAA8E;AAC9E,eAAO,MAAM,YAAY,QAAyC,CAAC;AAEnE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,YAAY,aAAgD,CAAC;AAC1E,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAElD,eAAO,MAAM,WAAW;;;;EAAsC,CAAC;AAC/D,eAAO,MAAM,YAAY;;;;;;;;;EAAiF,CAAC;AAC3G,eAAO,MAAM,aAAa;;;EAAqC,CAAC;AAChE,eAAO,MAAM,SAAS;;;EAAyB,CAAC;AAIhD,eAAO,MAAM,gBAAgB;;;;EAA6C,CAAC;AAC3E,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D,gCAAgC;AAChC,eAAO,MAAM,mBAAmB,yBAAsB,CAAC;AAEvD,sFAAsF;AACtF,eAAO,MAAM,aAAa,wCAAoC,CAAC;AAI/D,eAAO,MAAM,kBAAkB;;;;EAAsC,CAAC;AACtE,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,eAAO,MAAM,kBAAkB;;;;;;;iBAO7B,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,eAAO,MAAM,iBAAiB;;;iBAG5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,+DAA+D;AAC/D,eAAO,MAAM,mBAAmB;;iBAE9B,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,MAAM,MAAM,iBAAiB,GAAG,YAAY,GAAG,WAAW,GAAG,aAAa,CAAC;AAE3E,0EAA0E;AAC1E,eAAO,MAAM,kBAAkB,0TAkCrB,CAAC;AACX,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AAClE,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;EAA6B,CAAC;AAEhE;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,2BAA2B,
|
|
1
|
+
{"version":3,"file":"json-payloads.d.ts","sourceRoot":"","sources":["../../src/schema/json-payloads.ts"],"names":[],"mappings":"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"}
|
|
@@ -20,6 +20,33 @@ export const recordRefSchema = z.object({
|
|
|
20
20
|
/** Display snapshot taken at write time. */
|
|
21
21
|
label: z.string(),
|
|
22
22
|
});
|
|
23
|
+
/**
|
|
24
|
+
* Width of the denormalized `adminium_audit_log.entity_table` / `entity_id`
|
|
25
|
+
* columns (30-record-pages.md WS-A). 200 chars keeps the composite index
|
|
26
|
+
* inside MySQL's 3072-byte InnoDB cap under utf8mb4 (2 × 200 × 4 + 8).
|
|
27
|
+
*/
|
|
28
|
+
export const AUDIT_ENTITY_KEY_MAX = 200;
|
|
29
|
+
/**
|
|
30
|
+
* Canonical clamp for one audit entity key part. Applied on the WRITE side
|
|
31
|
+
* (append + backfill) and again on the QUERY side, so an over-long id still
|
|
32
|
+
* matches the row it wrote — truncation is consistent, never one-sided.
|
|
33
|
+
*/
|
|
34
|
+
export function auditEntityKeyPart(value) {
|
|
35
|
+
return value.length > AUDIT_ENTITY_KEY_MAX ? value.slice(0, AUDIT_ENTITY_KEY_MAX) : value;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The denormalized per-record audit key derived from a RecordRef (30 WS-A).
|
|
39
|
+
*
|
|
40
|
+
* `entityId` reproduces the canonical `:recordId` string both sides already
|
|
41
|
+
* use — `pkLabel` on the server, `rowIdOf` in the grid: a single-column PK is
|
|
42
|
+
* its stringified value, a composite PK is the JSON tuple of its values in pk
|
|
43
|
+
* insertion order (the order both writers build the map in).
|
|
44
|
+
*/
|
|
45
|
+
export function auditEntityKeyOf(ref) {
|
|
46
|
+
const values = Object.values(ref.pk);
|
|
47
|
+
const id = values.length === 1 ? String(values[0]) : JSON.stringify(values);
|
|
48
|
+
return { entityTable: auditEntityKeyPart(ref.table), entityId: auditEntityKeyPart(id) };
|
|
49
|
+
}
|
|
23
50
|
/** The eight COMPILED locales. Still a closed set — see `builtinLocaleSchema`. */
|
|
24
51
|
export const LOCALES = ['en_US', 'de_DE', 'ar_EG', 'zh_CN', 'zh_TW', 'cs_CZ', 'da_DK', 'fr_FR'];
|
|
25
52
|
export const builtinLocaleSchema = z.enum(LOCALES);
|
|
@@ -77,7 +104,7 @@ export const SYSTEM_ACTION_KEYS = [
|
|
|
77
104
|
'automations.manage', // reserved — deferred feature, no v1 enforcement (RESERVED_SYSTEM_ACTION_KEYS)
|
|
78
105
|
'webhooks.manage', // reserved — deferred feature, no v1 enforcement (RESERVED_SYSTEM_ACTION_KEYS)
|
|
79
106
|
'api-keys.manage',
|
|
80
|
-
'manifests.manage', //
|
|
107
|
+
'manifests.manage', // add-on + micro-SaaS install/connect/uninstall (26 D3)
|
|
81
108
|
'audit.read',
|
|
82
109
|
'sql.run', // reserved — deferred feature, no v1 enforcement (RESERVED_SYSTEM_ACTION_KEYS)
|
|
83
110
|
// M7 wave 2 — data-io (T5) + scheduled reports (T6). `exports.manage` /
|
|
@@ -119,7 +146,11 @@ export const systemActionKeySchema = z.enum(SYSTEM_ACTION_KEYS);
|
|
|
119
146
|
export const RESERVED_SYSTEM_ACTION_KEYS = [
|
|
120
147
|
'automations.manage',
|
|
121
148
|
'webhooks.manage',
|
|
122
|
-
|
|
149
|
+
// `manifests.manage` UN-RESERVED 2026-08-29 (26-add-on-runtime.md D3, 26-T05)
|
|
150
|
+
// in the same change that landed its first enforcement point — the
|
|
151
|
+
// `/api/v1/add-ons` routes. That is the rule this list documents, honoured
|
|
152
|
+
// rather than quoted: a key becomes grantable when something checks it, and
|
|
153
|
+
// not one commit earlier.
|
|
123
154
|
'sql.run',
|
|
124
155
|
];
|
|
125
156
|
/**
|
|
@@ -153,6 +184,14 @@ export const auditCategorySchema = z.enum([
|
|
|
153
184
|
'automation',
|
|
154
185
|
'export',
|
|
155
186
|
'system',
|
|
187
|
+
// Add-on acquisition and lifecycle (32-add-on-distribution.md §4.3): catalog
|
|
188
|
+
// refresh, download, verify- and unpack-refusals, upload, staged, deleted,
|
|
189
|
+
// upgraded. Its own category rather than a `system` action because an add-on
|
|
190
|
+
// ships a server half that runs in-process (24 D13) — "what code arrived on
|
|
191
|
+
// this deployment, from where, and did anything refuse it" is the question an
|
|
192
|
+
// operator asks on its own, and it should not have to be sieved out of the
|
|
193
|
+
// system log.
|
|
194
|
+
'add-on',
|
|
156
195
|
]);
|
|
157
196
|
/** `{ before, after }` images; PII-masked upstream; capped at 16 KB serialized. */
|
|
158
197
|
export const auditChangesSchema = z.object({
|