@cogenta/auth 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api-keys.d.ts +19 -0
- package/dist/api-keys.d.ts.map +1 -0
- package/dist/api-keys.js +112 -0
- package/dist/api-keys.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/store.d.ts +5 -0
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +4 -0
- package/dist/store.js.map +1 -1
- package/dist/tables.d.ts +1 -0
- package/dist/tables.d.ts.map +1 -1
- package/dist/tables.js +24 -0
- package/dist/tables.js.map +1 -1
- package/dist/types.d.ts +30 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type DatabaseHandle } from '@cogenta/core';
|
|
2
|
+
import type { ApiKey, CreateApiKeyInput, IssuedApiKey } from './types.js';
|
|
3
|
+
/** A raw bearer token is an API key only if it has this shape — checked before any DB lookup. */
|
|
4
|
+
export declare function looksLikeApiKey(token: string): boolean;
|
|
5
|
+
export interface ApiKeyStore {
|
|
6
|
+
/** Mints a key and returns the raw secret once. It is never stored or returned again. */
|
|
7
|
+
create(input: CreateApiKeyInput): Promise<IssuedApiKey>;
|
|
8
|
+
/** Never the raw key or its hash — a prefix is all a list ever shows. */
|
|
9
|
+
list(): Promise<readonly ApiKey[]>;
|
|
10
|
+
revoke(id: string): Promise<void>;
|
|
11
|
+
/**
|
|
12
|
+
* Resolves a raw bearer token to the key it names, or `null` if it does not
|
|
13
|
+
* exist, is revoked, or has expired. Touches `lastUsedAt` on success, the
|
|
14
|
+
* same sliding-window courtesy a session gets.
|
|
15
|
+
*/
|
|
16
|
+
verify(rawKey: string): Promise<ApiKey | null>;
|
|
17
|
+
}
|
|
18
|
+
export declare function createApiKeyStore(db: DatabaseHandle, now?: () => number): ApiKeyStore;
|
|
19
|
+
//# sourceMappingURL=api-keys.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-keys.d.ts","sourceRoot":"","sources":["../src/api-keys.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,KAAK,cAAc,EAA0B,MAAM,eAAe,CAAA;AAEzF,OAAO,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAkCzE,iGAAiG;AACjG,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEtD;AAsCD,MAAM,WAAW,WAAW;IAC1B,yFAAyF;IACzF,MAAM,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;IACvD,yEAAyE;IACzE,IAAI,IAAI,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAAA;IAClC,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACjC;;;;OAIG;IACH,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;CAC/C;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,cAAc,EAAE,GAAG,GAAE,MAAM,MAAiB,GAAG,WAAW,CA8D/F"}
|
package/dist/api-keys.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
2
|
+
import { CogentaError, identifier, newId, sql } from '@cogenta/core';
|
|
3
|
+
import { TABLES } from './tables.js';
|
|
4
|
+
/**
|
|
5
|
+
* Machine-to-machine bearer credentials (L13 task 8).
|
|
6
|
+
*
|
|
7
|
+
* `resolveActor` in `@cogenta/api` already recognises one bearer-token shape:
|
|
8
|
+
* a session, minted at sign-in for a human. This store mints the other
|
|
9
|
+
* shape — a long-lived key, minted once by an admin for a script or an
|
|
10
|
+
* integration — kept deliberately close to `sessions.ts` in every way that
|
|
11
|
+
* matters: an opaque random secret, hashed before it ever reaches disk, and
|
|
12
|
+
* looked up by that hash, never by the secret itself.
|
|
13
|
+
*
|
|
14
|
+
* A key is not a password. A password is chosen by a person and has to
|
|
15
|
+
* survive being typed and remembered, which is exactly what makes it
|
|
16
|
+
* guessable and worth slowing down with scrypt. A key is generated here,
|
|
17
|
+
* 256 bits of randomness no human ever picks — the same property a session
|
|
18
|
+
* token has — so it is hashed the same fast way a session is, and the
|
|
19
|
+
* defence against guessing is the key space, not the hash cost.
|
|
20
|
+
*/
|
|
21
|
+
const KEY_BYTES = 32;
|
|
22
|
+
const KEY_PREFIX = 'cogenta_sk_';
|
|
23
|
+
/** How much of the raw key stays visible forever, so a list of keys is recognisable. */
|
|
24
|
+
const VISIBLE_PREFIX_LENGTH = 12;
|
|
25
|
+
function issueKey() {
|
|
26
|
+
return `${KEY_PREFIX}${randomBytes(KEY_BYTES).toString('base64url')}`;
|
|
27
|
+
}
|
|
28
|
+
/** Stored hashed, like a session token — a leaked table hands out nothing live. */
|
|
29
|
+
function hashKey(key) {
|
|
30
|
+
return createHash('sha256').update(key).digest('base64url');
|
|
31
|
+
}
|
|
32
|
+
/** A raw bearer token is an API key only if it has this shape — checked before any DB lookup. */
|
|
33
|
+
export function looksLikeApiKey(token) {
|
|
34
|
+
return token.startsWith(KEY_PREFIX) && token.length > KEY_PREFIX.length;
|
|
35
|
+
}
|
|
36
|
+
function fromRow(row) {
|
|
37
|
+
return {
|
|
38
|
+
id: row.id,
|
|
39
|
+
name: row.name,
|
|
40
|
+
prefix: row.key_prefix,
|
|
41
|
+
scope: JSON.parse(row.scope),
|
|
42
|
+
createdBy: row.created_by,
|
|
43
|
+
createdAt: row.created_at,
|
|
44
|
+
expiresAt: row.expires_at ?? undefined,
|
|
45
|
+
revokedAt: row.revoked_at ?? undefined,
|
|
46
|
+
lastUsedAt: row.last_used_at ?? undefined,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function assertScope(scope) {
|
|
50
|
+
if (scope.length === 0 || scope.some((role) => role.trim().length === 0)) {
|
|
51
|
+
throw new CogentaError({
|
|
52
|
+
code: 'QUERY_INVALID',
|
|
53
|
+
message: 'An API key must be granted at least one non-empty role name.',
|
|
54
|
+
hint: 'A key with no role can authenticate and do nothing at all — pass at least one role in "scope".',
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export function createApiKeyStore(db, now = Date.now) {
|
|
59
|
+
const table = identifier(TABLES.apiKeys, db.dialect);
|
|
60
|
+
return {
|
|
61
|
+
create: async (input) => {
|
|
62
|
+
assertScope(input.scope);
|
|
63
|
+
const key = issueKey();
|
|
64
|
+
const id = newId(now);
|
|
65
|
+
const created = new Date(now()).toISOString();
|
|
66
|
+
const prefix = key.slice(0, VISIBLE_PREFIX_LENGTH);
|
|
67
|
+
await db.query(sql `
|
|
68
|
+
insert into ${table}
|
|
69
|
+
(id, name, key_hash, key_prefix, scope, created_by, created_at, expires_at, revoked_at, last_used_at)
|
|
70
|
+
values
|
|
71
|
+
(${id}, ${input.name}, ${hashKey(key)}, ${prefix}, ${JSON.stringify(input.scope)},
|
|
72
|
+
${input.createdBy}, ${created}, ${input.expiresAt ?? null}, ${null}, ${null})`);
|
|
73
|
+
return {
|
|
74
|
+
id,
|
|
75
|
+
name: input.name,
|
|
76
|
+
prefix,
|
|
77
|
+
scope: input.scope,
|
|
78
|
+
createdBy: input.createdBy,
|
|
79
|
+
createdAt: created,
|
|
80
|
+
expiresAt: input.expiresAt,
|
|
81
|
+
revokedAt: undefined,
|
|
82
|
+
lastUsedAt: undefined,
|
|
83
|
+
key,
|
|
84
|
+
};
|
|
85
|
+
},
|
|
86
|
+
list: async () => {
|
|
87
|
+
const result = await db.query(sql `select * from ${table} order by created_at desc`);
|
|
88
|
+
return result.rows.map(fromRow);
|
|
89
|
+
},
|
|
90
|
+
revoke: async (id) => {
|
|
91
|
+
const revokedAt = new Date(now()).toISOString();
|
|
92
|
+
await db.query(sql `update ${table} set revoked_at = ${revokedAt} where id = ${id} and revoked_at is null`);
|
|
93
|
+
},
|
|
94
|
+
verify: async (rawKey) => {
|
|
95
|
+
if (!looksLikeApiKey(rawKey))
|
|
96
|
+
return null;
|
|
97
|
+
const targetHash = hashKey(rawKey);
|
|
98
|
+
const result = await db.query(sql `select * from ${table} where key_hash = ${targetHash}`);
|
|
99
|
+
const row = result.rows[0];
|
|
100
|
+
if (row === undefined)
|
|
101
|
+
return null;
|
|
102
|
+
if (row.revoked_at !== null)
|
|
103
|
+
return null;
|
|
104
|
+
if (row.expires_at !== null && new Date(row.expires_at).getTime() <= now())
|
|
105
|
+
return null;
|
|
106
|
+
const lastUsedAt = new Date(now()).toISOString();
|
|
107
|
+
await db.query(sql `update ${table} set last_used_at = ${lastUsedAt} where id = ${row.id}`);
|
|
108
|
+
return fromRow({ ...row, last_used_at: lastUsedAt });
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=api-keys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-keys.js","sourceRoot":"","sources":["../src/api-keys.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
* bearer sessions, login-attempt backoff, MFA enforcement for sensitive
|
|
8
8
|
* roles, and the hash-chained audit log L4's agents will write to as well.
|
|
9
9
|
*/
|
|
10
|
+
export type { ApiKeyStore } from './api-keys.js';
|
|
11
|
+
export { createApiKeyStore, looksLikeApiKey } from './api-keys.js';
|
|
10
12
|
export type { AuditFilter, AuditLog } from './audit.js';
|
|
11
13
|
export { createAuditLog } from './audit.js';
|
|
12
14
|
export type { CredentialStore, WebAuthnCredentialData } from './credentials.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAC3C,YAAY,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAA;AAC/E,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAA;AACxD,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AACtD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAC5D,YAAY,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AACvE,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAA;AAC5E,YAAY,EACV,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAC7E,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAClD,YAAY,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,IAAI,WAAW,EAAE,MAAM,aAAa,CAAA;AACrE,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,EACL,sBAAsB,EACtB,kBAAkB,EAClB,OAAO,EACP,UAAU,GACX,MAAM,WAAW,CAAA;AAClB,cAAc,YAAY,CAAA;AAC1B,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAC5C,YAAY,EACV,qBAAqB,EACrB,mBAAmB,EACnB,4BAA4B,EAC5B,cAAc,GACf,MAAM,eAAe,CAAA;AACtB,OAAO,EACL,2BAA2B,EAC3B,yBAAyB,EACzB,8BAA8B,EAC9B,4BAA4B,GAC7B,MAAM,eAAe,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAClE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAC3C,YAAY,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAA;AAC/E,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAA;AACxD,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AACtD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAC5D,YAAY,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AACvE,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAA;AAC5E,YAAY,EACV,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAC7E,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAClD,YAAY,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,IAAI,WAAW,EAAE,MAAM,aAAa,CAAA;AACrE,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,EACL,sBAAsB,EACtB,kBAAkB,EAClB,OAAO,EACP,UAAU,GACX,MAAM,WAAW,CAAA;AAClB,cAAc,YAAY,CAAA;AAC1B,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAC5C,YAAY,EACV,qBAAqB,EACrB,mBAAmB,EACnB,4BAA4B,EAC5B,cAAc,GACf,MAAM,eAAe,CAAA;AACtB,OAAO,EACL,2BAA2B,EAC3B,yBAAyB,EACzB,8BAA8B,EAC9B,4BAA4B,GAC7B,MAAM,eAAe,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* bearer sessions, login-attempt backoff, MFA enforcement for sensitive
|
|
8
8
|
* roles, and the hash-chained audit log L4's agents will write to as well.
|
|
9
9
|
*/
|
|
10
|
+
export { createApiKeyStore, looksLikeApiKey } from './api-keys.js';
|
|
10
11
|
export { createAuditLog } from './audit.js';
|
|
11
12
|
export { createCredentialStore } from './credentials.js';
|
|
12
13
|
export { createAuthService } from './login.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAE3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAA;AAExD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AACtD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAE5D,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAA;AAM5E,OAAO,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAE7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAElD,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,IAAI,WAAW,EAAE,MAAM,aAAa,CAAA;AAErE,OAAO,EACL,sBAAsB,EACtB,kBAAkB,EAClB,OAAO,EACP,UAAU,GACX,MAAM,WAAW,CAAA;AAClB,cAAc,YAAY,CAAA;AAE1B,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAO5C,OAAO,EACL,2BAA2B,EAC3B,yBAAyB,EACzB,8BAA8B,EAC9B,4BAA4B,GAC7B,MAAM,eAAe,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAElE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAE3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAA;AAExD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AACtD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAE5D,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAA;AAM5E,OAAO,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAE7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAElD,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,IAAI,WAAW,EAAE,MAAM,aAAa,CAAA;AAErE,OAAO,EACL,sBAAsB,EACtB,kBAAkB,EAClB,OAAO,EACP,UAAU,GACX,MAAM,WAAW,CAAA;AAClB,cAAc,YAAY,CAAA;AAE1B,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAO5C,OAAO,EACL,2BAA2B,EAC3B,yBAAyB,EACzB,8BAA8B,EAC9B,4BAA4B,GAC7B,MAAM,eAAe,CAAA"}
|
package/dist/store.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { DatabaseHandle } from '@cogenta/core';
|
|
2
2
|
import type { CollectionDefinition } from '@cogenta/schema';
|
|
3
|
+
import { createApiKeyStore } from './api-keys.js';
|
|
3
4
|
import { createAuditLog } from './audit.js';
|
|
4
5
|
import { createCredentialStore } from './credentials.js';
|
|
5
6
|
import { createAuthService } from './login.js';
|
|
6
7
|
import { createRateLimiter } from './rate-limit.js';
|
|
8
|
+
import { createPasswordResetStore } from './resets.js';
|
|
7
9
|
import { createSessionStore } from './sessions.js';
|
|
8
10
|
import { createUserStore } from './users.js';
|
|
9
11
|
import type { WebAuthnConfig } from './webauthn.js';
|
|
@@ -25,6 +27,9 @@ export interface AuthStore {
|
|
|
25
27
|
readonly audit: ReturnType<typeof createAuditLog>;
|
|
26
28
|
readonly rateLimit: ReturnType<typeof createRateLimiter>;
|
|
27
29
|
readonly login: ReturnType<typeof createAuthService>;
|
|
30
|
+
/** Self-service "forgot password" tokens (L13's HTTP route, `resets.ts`). */
|
|
31
|
+
readonly resets: ReturnType<typeof createPasswordResetStore>;
|
|
32
|
+
readonly apiKeys: ReturnType<typeof createApiKeyStore>;
|
|
28
33
|
}
|
|
29
34
|
export declare function createAuthStore(options: AuthStoreOptions): Promise<AuthStore>;
|
|
30
35
|
//# sourceMappingURL=store.d.ts.map
|
package/dist/store.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AACnD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAA;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAElD,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAEnD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,EAAE,cAAc,CAAA;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,WAAW,EAAE,SAAS,oBAAoB,EAAE,CAAA;IACrD,sFAAsF;IACtF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,qCAAqC;IACrC,QAAQ,CAAC,QAAQ,CAAC,EAAE,cAAc,CAAA;IAClC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CAC5B;AAED,0EAA0E;AAC1E,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC,OAAO,eAAe,CAAC,CAAA;IAClD,QAAQ,CAAC,WAAW,EAAE,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAA;IAC9D,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAA;IACxD,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAA;IACjD,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAA;IACxD,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AACnD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAA;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAA;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAElD,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAEnD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,EAAE,cAAc,CAAA;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,WAAW,EAAE,SAAS,oBAAoB,EAAE,CAAA;IACrD,sFAAsF;IACtF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,qCAAqC;IACrC,QAAQ,CAAC,QAAQ,CAAC,EAAE,cAAc,CAAA;IAClC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CAC5B;AAED,0EAA0E;AAC1E,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC,OAAO,eAAe,CAAC,CAAA;IAClD,QAAQ,CAAC,WAAW,EAAE,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAA;IAC9D,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAA;IACxD,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAA;IACjD,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAA;IACxD,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAA;IACpD,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,wBAAwB,CAAC,CAAA;IAC5D,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAA;CACvD;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,SAAS,CAAC,CAqBnF"}
|
package/dist/store.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { createApiKeyStore } from './api-keys.js';
|
|
1
2
|
import { createAuditLog } from './audit.js';
|
|
2
3
|
import { createCredentialStore } from './credentials.js';
|
|
3
4
|
import { createAuthService } from './login.js';
|
|
4
5
|
import { createRateLimiter } from './rate-limit.js';
|
|
6
|
+
import { createPasswordResetStore } from './resets.js';
|
|
5
7
|
import { createSessionStore } from './sessions.js';
|
|
6
8
|
import { ensureAuthTables } from './tables.js';
|
|
7
9
|
import { createUserStore } from './users.js';
|
|
@@ -14,6 +16,8 @@ export async function createAuthStore(options) {
|
|
|
14
16
|
sessions: createSessionStore(options.db, now),
|
|
15
17
|
audit: createAuditLog(options.db, now),
|
|
16
18
|
rateLimit: createRateLimiter(options.db, now),
|
|
19
|
+
resets: createPasswordResetStore(options.db, now),
|
|
20
|
+
apiKeys: createApiKeyStore(options.db, now),
|
|
17
21
|
login: createAuthService({
|
|
18
22
|
db: options.db,
|
|
19
23
|
signingKey: options.signingKey,
|
package/dist/store.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAA;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAA;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAA;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AA2B5C,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAAyB;IAC7D,MAAM,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IAClC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAA;IAEnC,OAAO;QACL,KAAK,EAAE,eAAe,CAAC,OAAO,CAAC,EAAE,EAAE,GAAG,CAAC;QACvC,WAAW,EAAE,qBAAqB,CAAC,OAAO,CAAC,EAAE,EAAE,GAAG,CAAC;QACnD,QAAQ,EAAE,kBAAkB,CAAC,OAAO,CAAC,EAAE,EAAE,GAAG,CAAC;QAC7C,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,EAAE,EAAE,GAAG,CAAC;QACtC,SAAS,EAAE,iBAAiB,CAAC,OAAO,CAAC,EAAE,EAAE,GAAG,CAAC;QAC7C,MAAM,EAAE,wBAAwB,CAAC,OAAO,CAAC,EAAE,EAAE,GAAG,CAAC;QACjD,OAAO,EAAE,iBAAiB,CAAC,OAAO,CAAC,EAAE,EAAE,GAAG,CAAC;QAC3C,KAAK,EAAE,iBAAiB,CAAC;YACvB,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,GAAG;YACH,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;YACnE,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC;SAC1E,CAAC;KACH,CAAA;AACH,CAAC"}
|
package/dist/tables.d.ts
CHANGED
package/dist/tables.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tables.d.ts","sourceRoot":"","sources":["../src/tables.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EAKpB,MAAM,eAAe,CAAA;AAEtB,eAAO,MAAM,MAAM;aACjB,KAAK,EAAE,eAAe;aACtB,WAAW,EAAE,qBAAqB;aAClC,QAAQ,EAAE,kBAAkB;aAC5B,aAAa,EAAE,wBAAwB;aACvC,cAAc,EAAE,yBAAyB;aACzC,QAAQ,EAAE,mBAAmB;
|
|
1
|
+
{"version":3,"file":"tables.d.ts","sourceRoot":"","sources":["../src/tables.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EAKpB,MAAM,eAAe,CAAA;AAEtB,eAAO,MAAM,MAAM;aACjB,KAAK,EAAE,eAAe;aACtB,WAAW,EAAE,qBAAqB;aAClC,QAAQ,EAAE,kBAAkB;aAC5B,aAAa,EAAE,wBAAwB;aACvC,cAAc,EAAE,yBAAyB;aACzC,QAAQ,EAAE,mBAAmB;aAC7B,OAAO,EAAE,kBAAkB;CACnB,CAAA;AAWV;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CAAC,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA6HxE"}
|
package/dist/tables.js
CHANGED
|
@@ -6,6 +6,7 @@ export const TABLES = {
|
|
|
6
6
|
loginAttempts: 'cogenta_login_attempts',
|
|
7
7
|
passwordResets: 'cogenta_password_resets',
|
|
8
8
|
auditLog: 'cogenta_audit_log',
|
|
9
|
+
apiKeys: 'cogenta_api_keys',
|
|
9
10
|
};
|
|
10
11
|
/** `varchar` on Postgres/MySQL, `text` on SQLite — encapsulated once, here. */
|
|
11
12
|
function textColumn(dialect, length) {
|
|
@@ -29,6 +30,7 @@ export async function ensureAuthTables(db) {
|
|
|
29
30
|
const loginAttempts = identifier(TABLES.loginAttempts, d);
|
|
30
31
|
const passwordResets = identifier(TABLES.passwordResets, d);
|
|
31
32
|
const auditLog = identifier(TABLES.auditLog, d);
|
|
33
|
+
const apiKeys = identifier(TABLES.apiKeys, d);
|
|
32
34
|
const t512 = textColumn(d, 512);
|
|
33
35
|
const t255 = textColumn(d, 255);
|
|
34
36
|
const t64 = textColumn(d, 64);
|
|
@@ -106,6 +108,28 @@ export async function ensureAuthTables(db) {
|
|
|
106
108
|
hash ${t64} not null,
|
|
107
109
|
previous_hash ${t64}
|
|
108
110
|
)`);
|
|
111
|
+
await db.query(sql `
|
|
112
|
+
create table if not exists ${apiKeys} (
|
|
113
|
+
id ${t64} not null primary key,
|
|
114
|
+
name ${t255} not null,
|
|
115
|
+
-- Hashed like a session token (sha256 over a 256-bit random secret):
|
|
116
|
+
-- unlike a password, this secret is never chosen by a person, so there
|
|
117
|
+
-- is no low-entropy guess for a slow, memory-hard hash to protect
|
|
118
|
+
-- against. A leaked table still hands out nothing live.
|
|
119
|
+
key_hash ${t512} not null unique,
|
|
120
|
+
-- The first 12 characters of the raw key, stored in the clear so a
|
|
121
|
+
-- list of keys is recognisable without ever showing the rest again.
|
|
122
|
+
key_prefix ${t64} not null,
|
|
123
|
+
-- An open set of role names, exactly like a user's roles (contract A)
|
|
124
|
+
-- — a key acts as a machine actor scoped to exactly these roles, never
|
|
125
|
+
-- to more than it was granted.
|
|
126
|
+
scope text not null,
|
|
127
|
+
created_by ${t64},
|
|
128
|
+
created_at ${t64} not null,
|
|
129
|
+
expires_at ${t64},
|
|
130
|
+
revoked_at ${t64},
|
|
131
|
+
last_used_at ${t64}
|
|
132
|
+
)`);
|
|
109
133
|
await createIndexIfMissing(db, 'cogenta_credentials_user', credentials, sql `(user_id)`);
|
|
110
134
|
await createIndexIfMissing(db, 'cogenta_sessions_user', sessions, sql `(user_id)`);
|
|
111
135
|
await createIndexIfMissing(db, 'cogenta_login_attempts_subject_at', loginAttempts, sql `(subject, at)`);
|
package/dist/tables.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tables.js","sourceRoot":"","sources":["../src/tables.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,UAAU,EAEV,GAAG,EACH,SAAS,GACV,MAAM,eAAe,CAAA;AAEtB,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,KAAK,EAAE,eAAe;IACtB,WAAW,EAAE,qBAAqB;IAClC,QAAQ,EAAE,kBAAkB;IAC5B,aAAa,EAAE,wBAAwB;IACvC,cAAc,EAAE,yBAAyB;IACzC,QAAQ,EAAE,mBAAmB;
|
|
1
|
+
{"version":3,"file":"tables.js","sourceRoot":"","sources":["../src/tables.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -61,4 +61,34 @@ export interface RecordAuditInput {
|
|
|
61
61
|
readonly entryId?: string | undefined;
|
|
62
62
|
readonly diff?: Readonly<Record<string, unknown>> | undefined;
|
|
63
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* A machine-to-machine bearer credential (L13 task 8).
|
|
66
|
+
*
|
|
67
|
+
* A key is scoped to an explicit, open set of role names — exactly like a
|
|
68
|
+
* user's `roles` — chosen once at creation and never derived from the
|
|
69
|
+
* account that created it. A key can act with fewer permissions than an
|
|
70
|
+
* admin has, but never with more than it was granted.
|
|
71
|
+
*/
|
|
72
|
+
export interface ApiKey {
|
|
73
|
+
readonly id: string;
|
|
74
|
+
readonly name: string;
|
|
75
|
+
/** The first 12 characters of the raw key, safe to show forever. */
|
|
76
|
+
readonly prefix: string;
|
|
77
|
+
readonly scope: readonly string[];
|
|
78
|
+
readonly createdBy: string | null;
|
|
79
|
+
readonly createdAt: string;
|
|
80
|
+
readonly expiresAt: string | undefined;
|
|
81
|
+
readonly revokedAt: string | undefined;
|
|
82
|
+
readonly lastUsedAt: string | undefined;
|
|
83
|
+
}
|
|
84
|
+
export interface CreateApiKeyInput {
|
|
85
|
+
readonly name: string;
|
|
86
|
+
readonly scope: readonly string[];
|
|
87
|
+
readonly createdBy: string | null;
|
|
88
|
+
readonly expiresAt?: string | undefined;
|
|
89
|
+
}
|
|
90
|
+
/** An API key as returned once, at creation — `key` is never stored or shown again. */
|
|
91
|
+
export interface IssuedApiKey extends ApiKey {
|
|
92
|
+
readonly key: string;
|
|
93
|
+
}
|
|
64
94
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,eAAO,MAAM,gBAAgB,YAAI,UAAU,EAAE,MAAM,EAAE,UAAU,CAAU,CAAA;AACzE,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAA;AAE9D,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,mFAAmF;IACnF,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,UAAU,CAAA;IACtC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;CAClC;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,8EAA8E;IAC9E,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;CACnC;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAc,SAAQ,OAAO;IAC5C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,oEAAoE;IACpE,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAA;IACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,IAAI,CAAA;IACvD,2EAA2E;IAC3E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;CACrC;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAA;IACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACxC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACrC,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,SAAS,CAAA;CAC9D"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cogenta/auth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Identity, sessions and credentials: password, TOTP and WebAuthn, plus the append-only audit log.",
|
|
5
5
|
"license": "MPL-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@simplewebauthn/server": "^13.3.2",
|
|
31
|
-
"@cogenta/core": "0.
|
|
32
|
-
"@cogenta/schema": "0.
|
|
31
|
+
"@cogenta/core": "0.4.0",
|
|
32
|
+
"@cogenta/schema": "0.3.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"typescript": "^7.0.2",
|