trustline 0.1.0 → 0.1.1
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/README.md +5 -43
- package/dist/adapters/mysql/index.cjs.map +1 -1
- package/dist/adapters/mysql/index.d.cts +1 -1
- package/dist/adapters/mysql/index.d.ts +1 -1
- package/dist/adapters/postgres/index.cjs.map +1 -1
- package/dist/adapters/postgres/index.d.cts +1 -1
- package/dist/adapters/postgres/index.d.ts +1 -1
- package/dist/adapters/sqlite/index.cjs.map +1 -1
- package/dist/adapters/sqlite/index.d.cts +1 -1
- package/dist/adapters/sqlite/index.d.ts +1 -1
- package/dist/frameworks/express/index.cjs +35 -35
- package/dist/frameworks/express/index.cjs.map +1 -1
- package/dist/frameworks/express/index.d.cts +6 -6
- package/dist/frameworks/express/index.d.ts +6 -6
- package/dist/frameworks/express/index.js +35 -35
- package/dist/frameworks/express/index.js.map +1 -1
- package/dist/frameworks/hono/index.cjs +13 -5
- package/dist/frameworks/hono/index.cjs.map +1 -1
- package/dist/frameworks/hono/index.js +13 -5
- package/dist/frameworks/hono/index.js.map +1 -1
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# Trustline
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/trustline)
|
|
4
|
+
[](https://barddoo.github.io/trustline/)
|
|
5
|
+
|
|
3
6
|
Service identity and authorization for modern JavaScript runtimes.
|
|
4
7
|
|
|
5
8
|
Trustline is a machine-to-machine authentication library for internal services. It is designed around dedicated core and integration entry points:
|
|
@@ -11,39 +14,6 @@ Trustline is a machine-to-machine authentication library for internal services.
|
|
|
11
14
|
|
|
12
15
|
The package now ships the first full stack: provider, client, guard, framework adapters, memory storage, and SQL storage adapters for SQLite, Postgres, and MySQL.
|
|
13
16
|
|
|
14
|
-
## Current status
|
|
15
|
-
|
|
16
|
-
Available now:
|
|
17
|
-
|
|
18
|
-
- `createProvider(options)`
|
|
19
|
-
- `createClient(options)`
|
|
20
|
-
- `createGuard(options)`
|
|
21
|
-
- `memoryStorage()`
|
|
22
|
-
- `createExpressProvider(provider)`
|
|
23
|
-
- `createExpressGuard(guard)`
|
|
24
|
-
- `createFastifyProvider(provider)`
|
|
25
|
-
- `createFastifyGuard(guard)`
|
|
26
|
-
- `createHonoProvider(provider)`
|
|
27
|
-
- `createHonoGuard(guard)`
|
|
28
|
-
- `sqliteStorage(path | database)`
|
|
29
|
-
- `postgresStorage(pool)`
|
|
30
|
-
- `mysqlStorage(pool)`
|
|
31
|
-
|
|
32
|
-
Implemented behavior:
|
|
33
|
-
|
|
34
|
-
- client credentials token issuance
|
|
35
|
-
- JWKS publishing
|
|
36
|
-
- token caching with proactive refresh and request deduplication
|
|
37
|
-
- issuer, audience, scope, and environment verification
|
|
38
|
-
- JWKS discovery and caching
|
|
39
|
-
- Express, Fastify, and Hono adapters
|
|
40
|
-
|
|
41
|
-
Planned next:
|
|
42
|
-
|
|
43
|
-
- key rotation overlap windows
|
|
44
|
-
- token revocation workflows
|
|
45
|
-
- requested-scope narrowing during issuance
|
|
46
|
-
|
|
47
17
|
## Installation
|
|
48
18
|
|
|
49
19
|
Trustline is intended to be consumed as the `trustline` package:
|
|
@@ -69,16 +39,6 @@ npm install trustline better-sqlite3 kysely
|
|
|
69
39
|
|
|
70
40
|
If you are working from this repository before package publication, build the package locally and install or link it from the repo source.
|
|
71
41
|
|
|
72
|
-
## Releasing
|
|
73
|
-
|
|
74
|
-
Package releases are managed with Changesets and GitHub Actions. Add a changeset in each user-facing PR with:
|
|
75
|
-
|
|
76
|
-
```bash
|
|
77
|
-
bun run changeset
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
Merges to `main` update or create a release PR, and merging that release PR publishes to npm. See `RELEASING.md` for the full flow and npm trusted publishing setup.
|
|
81
|
-
|
|
82
42
|
## Quick start
|
|
83
43
|
|
|
84
44
|
Provider:
|
|
@@ -285,6 +245,8 @@ const mysql = mysqlStorage(createMysqlPool(process.env.DATABASE_URL!));
|
|
|
285
245
|
|
|
286
246
|
The VitePress docs site lives in `docs/`.
|
|
287
247
|
|
|
248
|
+
Runnable examples live under `examples/`. For a full Hono-based flow with a dedicated auth provider plus caller and receiver services, see `examples/hono-services/`.
|
|
249
|
+
|
|
288
250
|
Key pages:
|
|
289
251
|
|
|
290
252
|
- `docs/index.md`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/adapters/mysql/index.ts","../../../src/storage/mysql.ts","../../../src/storage/sql.ts"],"sourcesContent":["export { mysqlStorage } from \"../../storage/mysql\";\nexport type { SqlStorageOptions, StorageAdapter } from \"../../storage/interface\";\n","import { Kysely, MysqlDialect } from \"kysely\";\nimport type { Pool } from \"mysql2\";\n\nimport type { SqlStorageOptions, StorageAdapter } from \"./interface\";\nimport { createSqlStorage } from \"./sql\";\n\nexport function mysqlStorage(\n pool: Pool,\n options?: SqlStorageOptions,\n): StorageAdapter {\n return createSqlStorage(\n new Kysely({\n dialect: new MysqlDialect({\n pool,\n }),\n }),\n \"mysql\",\n options,\n );\n}\n","import { type Kysely, sql } from \"kysely\";\n\nimport type {\n ServiceClient,\n SigningKey,\n SqlStorageOptions,\n StorageAdapter,\n} from \"./interface\";\n\ntype SqlDialect = \"mysql\" | \"postgres\" | \"sqlite\";\n\ninterface SqlTables {\n clients: string;\n signingKeys: string;\n}\n\ninterface SqlDatabase {\n [tableName: string]: SqlRow;\n}\n\ninterface SqlRow {\n algorithm?: SigningKey[\"algorithm\"];\n client_id?: string;\n client_secret?: string;\n created_at: string;\n id?: string;\n key_id?: string;\n last_seen_at?: string | null;\n name?: string;\n private_key?: string;\n public_key?: string;\n retired_at?: string | null;\n scopes?: string;\n}\n\ninterface ClientRow {\n id: string;\n client_id: string;\n client_secret: string;\n name: string;\n scopes: string;\n created_at: string;\n last_seen_at: string | null;\n}\n\ninterface SigningKeyRow {\n key_id: string;\n algorithm: SigningKey[\"algorithm\"];\n private_key: string;\n public_key: string;\n created_at: string;\n retired_at: string | null;\n}\n\nexport function createSqlStorage(\n database: Kysely<SqlDatabase>,\n dialect: SqlDialect,\n options?: SqlStorageOptions,\n): StorageAdapter {\n const tables = resolveTables(options);\n let schemaPromise: Promise<void> | null = null;\n\n async function ensureSchema(): Promise<void> {\n if (!schemaPromise) {\n schemaPromise = createSchema(database, dialect, tables);\n }\n\n await schemaPromise;\n }\n\n return {\n async findClient(clientId) {\n await ensureSchema();\n\n const row = (await database\n .selectFrom(tables.clients)\n .selectAll()\n .where(\"client_id\", \"=\", clientId)\n .executeTakeFirst()) as ClientRow | undefined;\n\n return row ? mapClientRow(row) : null;\n },\n async createClient(client) {\n await ensureSchema();\n\n await database\n .insertInto(tables.clients)\n .values({\n id: client.id,\n client_id: client.clientId,\n client_secret: client.clientSecret,\n name: client.name,\n scopes: JSON.stringify(client.scopes),\n created_at: client.createdAt.toISOString(),\n last_seen_at: client.lastSeenAt?.toISOString() ?? null,\n })\n .execute();\n },\n async deleteClient(clientId) {\n await ensureSchema();\n\n await database\n .deleteFrom(tables.clients)\n .where(\"client_id\", \"=\", clientId)\n .execute();\n },\n async listClients() {\n await ensureSchema();\n\n const rows = (await database\n .selectFrom(tables.clients)\n .selectAll()\n .orderBy(\"created_at\", \"asc\")\n .execute()) as ClientRow[];\n\n return rows.map(mapClientRow);\n },\n async touchClient(clientId, lastSeenAt) {\n await ensureSchema();\n\n await database\n .updateTable(tables.clients)\n .set({\n last_seen_at: lastSeenAt.toISOString(),\n })\n .where(\"client_id\", \"=\", clientId)\n .execute();\n },\n async getSigningKeys() {\n await ensureSchema();\n\n const rows = (await database\n .selectFrom(tables.signingKeys)\n .selectAll()\n .orderBy(\"created_at\", \"asc\")\n .execute()) as SigningKeyRow[];\n\n return rows.map(mapSigningKeyRow);\n },\n async addSigningKey(key) {\n await ensureSchema();\n\n await database\n .insertInto(tables.signingKeys)\n .values({\n key_id: key.keyId,\n algorithm: key.algorithm,\n private_key: key.privateKey,\n public_key: key.publicKey,\n created_at: key.createdAt.toISOString(),\n retired_at: key.retiredAt?.toISOString() ?? null,\n })\n .execute();\n },\n async retireKey(keyId) {\n await ensureSchema();\n\n await database\n .updateTable(tables.signingKeys)\n .set({\n retired_at: new Date().toISOString(),\n })\n .where(\"key_id\", \"=\", keyId)\n .execute();\n },\n };\n}\n\nfunction resolveTables(options?: SqlStorageOptions): SqlTables {\n const prefix = options?.tablePrefix ?? \"trustline_\";\n\n return {\n clients: options?.tables?.clients ?? `${prefix}clients`,\n signingKeys: options?.tables?.signingKeys ?? `${prefix}signing_keys`,\n };\n}\n\nasync function createSchema(\n database: Kysely<SqlDatabase>,\n dialect: SqlDialect,\n tables: SqlTables,\n): Promise<void> {\n await createClientsTable(database, dialect, tables.clients);\n await createSigningKeysTable(database, dialect, tables.signingKeys);\n}\n\nasync function createClientsTable(\n database: Kysely<SqlDatabase>,\n dialect: SqlDialect,\n tableName: string,\n): Promise<void> {\n if (dialect === \"mysql\") {\n await sql`\n create table if not exists ${sql.table(tableName)} (\n id varchar(255) not null,\n client_id varchar(255) not null primary key,\n client_secret text not null,\n name varchar(255) not null,\n scopes text not null,\n created_at varchar(64) not null,\n last_seen_at varchar(64) null\n )\n `.execute(database);\n return;\n }\n\n await sql`\n create table if not exists ${sql.table(tableName)} (\n id varchar(255) not null,\n client_id varchar(255) not null primary key,\n client_secret text not null,\n name varchar(255) not null,\n scopes text not null,\n created_at varchar(64) not null,\n last_seen_at varchar(64)\n )\n `.execute(database);\n}\n\nasync function createSigningKeysTable(\n database: Kysely<SqlDatabase>,\n dialect: SqlDialect,\n tableName: string,\n): Promise<void> {\n if (dialect === \"mysql\") {\n await sql`\n create table if not exists ${sql.table(tableName)} (\n key_id varchar(255) not null primary key,\n algorithm varchar(32) not null,\n private_key text not null,\n public_key text not null,\n created_at varchar(64) not null,\n retired_at varchar(64) null\n )\n `.execute(database);\n return;\n }\n\n await sql`\n create table if not exists ${sql.table(tableName)} (\n key_id varchar(255) not null primary key,\n algorithm varchar(32) not null,\n private_key text not null,\n public_key text not null,\n created_at varchar(64) not null,\n retired_at varchar(64)\n )\n `.execute(database);\n}\n\nfunction mapClientRow(row: ClientRow): ServiceClient {\n return {\n id: row.id,\n clientId: row.client_id,\n clientSecret: row.client_secret,\n name: row.name,\n scopes: JSON.parse(row.scopes) as string[],\n createdAt: new Date(row.created_at),\n lastSeenAt: row.last_seen_at ? new Date(row.last_seen_at) : null,\n };\n}\n\nfunction mapSigningKeyRow(row: SigningKeyRow): SigningKey {\n return {\n keyId: row.key_id,\n algorithm: row.algorithm,\n privateKey: row.private_key,\n publicKey: row.public_key,\n createdAt: new Date(row.created_at),\n retiredAt: row.retired_at ? new Date(row.retired_at) : null,\n };\n}\n"],"mappings":"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","names":["import_kysely"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/adapters/mysql/index.ts","../../../src/storage/mysql.ts","../../../src/storage/sql.ts"],"sourcesContent":["export type {\n SqlStorageOptions,\n StorageAdapter,\n} from \"../../storage/interface\";\nexport { mysqlStorage } from \"../../storage/mysql\";\n","import { Kysely, MysqlDialect } from \"kysely\";\nimport type { Pool } from \"mysql2\";\n\nimport type { SqlStorageOptions, StorageAdapter } from \"./interface\";\nimport { createSqlStorage } from \"./sql\";\n\nexport function mysqlStorage(\n pool: Pool,\n options?: SqlStorageOptions,\n): StorageAdapter {\n return createSqlStorage(\n new Kysely({\n dialect: new MysqlDialect({\n pool,\n }),\n }),\n \"mysql\",\n options,\n );\n}\n","import { type Kysely, sql } from \"kysely\";\n\nimport type {\n ServiceClient,\n SigningKey,\n SqlStorageOptions,\n StorageAdapter,\n} from \"./interface\";\n\ntype SqlDialect = \"mysql\" | \"postgres\" | \"sqlite\";\n\ninterface SqlTables {\n clients: string;\n signingKeys: string;\n}\n\ninterface SqlDatabase {\n [tableName: string]: SqlRow;\n}\n\ninterface SqlRow {\n algorithm?: SigningKey[\"algorithm\"];\n client_id?: string;\n client_secret?: string;\n created_at: string;\n id?: string;\n key_id?: string;\n last_seen_at?: string | null;\n name?: string;\n private_key?: string;\n public_key?: string;\n retired_at?: string | null;\n scopes?: string;\n}\n\ninterface ClientRow {\n id: string;\n client_id: string;\n client_secret: string;\n name: string;\n scopes: string;\n created_at: string;\n last_seen_at: string | null;\n}\n\ninterface SigningKeyRow {\n key_id: string;\n algorithm: SigningKey[\"algorithm\"];\n private_key: string;\n public_key: string;\n created_at: string;\n retired_at: string | null;\n}\n\nexport function createSqlStorage(\n database: Kysely<SqlDatabase>,\n dialect: SqlDialect,\n options?: SqlStorageOptions,\n): StorageAdapter {\n const tables = resolveTables(options);\n let schemaPromise: Promise<void> | null = null;\n\n async function ensureSchema(): Promise<void> {\n if (!schemaPromise) {\n schemaPromise = createSchema(database, dialect, tables);\n }\n\n await schemaPromise;\n }\n\n return {\n async findClient(clientId) {\n await ensureSchema();\n\n const row = (await database\n .selectFrom(tables.clients)\n .selectAll()\n .where(\"client_id\", \"=\", clientId)\n .executeTakeFirst()) as ClientRow | undefined;\n\n return row ? mapClientRow(row) : null;\n },\n async createClient(client) {\n await ensureSchema();\n\n await database\n .insertInto(tables.clients)\n .values({\n id: client.id,\n client_id: client.clientId,\n client_secret: client.clientSecret,\n name: client.name,\n scopes: JSON.stringify(client.scopes),\n created_at: client.createdAt.toISOString(),\n last_seen_at: client.lastSeenAt?.toISOString() ?? null,\n })\n .execute();\n },\n async deleteClient(clientId) {\n await ensureSchema();\n\n await database\n .deleteFrom(tables.clients)\n .where(\"client_id\", \"=\", clientId)\n .execute();\n },\n async listClients() {\n await ensureSchema();\n\n const rows = (await database\n .selectFrom(tables.clients)\n .selectAll()\n .orderBy(\"created_at\", \"asc\")\n .execute()) as ClientRow[];\n\n return rows.map(mapClientRow);\n },\n async touchClient(clientId, lastSeenAt) {\n await ensureSchema();\n\n await database\n .updateTable(tables.clients)\n .set({\n last_seen_at: lastSeenAt.toISOString(),\n })\n .where(\"client_id\", \"=\", clientId)\n .execute();\n },\n async getSigningKeys() {\n await ensureSchema();\n\n const rows = (await database\n .selectFrom(tables.signingKeys)\n .selectAll()\n .orderBy(\"created_at\", \"asc\")\n .execute()) as SigningKeyRow[];\n\n return rows.map(mapSigningKeyRow);\n },\n async addSigningKey(key) {\n await ensureSchema();\n\n await database\n .insertInto(tables.signingKeys)\n .values({\n key_id: key.keyId,\n algorithm: key.algorithm,\n private_key: key.privateKey,\n public_key: key.publicKey,\n created_at: key.createdAt.toISOString(),\n retired_at: key.retiredAt?.toISOString() ?? null,\n })\n .execute();\n },\n async retireKey(keyId) {\n await ensureSchema();\n\n await database\n .updateTable(tables.signingKeys)\n .set({\n retired_at: new Date().toISOString(),\n })\n .where(\"key_id\", \"=\", keyId)\n .execute();\n },\n };\n}\n\nfunction resolveTables(options?: SqlStorageOptions): SqlTables {\n const prefix = options?.tablePrefix ?? \"trustline_\";\n\n return {\n clients: options?.tables?.clients ?? `${prefix}clients`,\n signingKeys: options?.tables?.signingKeys ?? `${prefix}signing_keys`,\n };\n}\n\nasync function createSchema(\n database: Kysely<SqlDatabase>,\n dialect: SqlDialect,\n tables: SqlTables,\n): Promise<void> {\n await createClientsTable(database, dialect, tables.clients);\n await createSigningKeysTable(database, dialect, tables.signingKeys);\n}\n\nasync function createClientsTable(\n database: Kysely<SqlDatabase>,\n dialect: SqlDialect,\n tableName: string,\n): Promise<void> {\n if (dialect === \"mysql\") {\n await sql`\n create table if not exists ${sql.table(tableName)} (\n id varchar(255) not null,\n client_id varchar(255) not null primary key,\n client_secret text not null,\n name varchar(255) not null,\n scopes text not null,\n created_at varchar(64) not null,\n last_seen_at varchar(64) null\n )\n `.execute(database);\n return;\n }\n\n await sql`\n create table if not exists ${sql.table(tableName)} (\n id varchar(255) not null,\n client_id varchar(255) not null primary key,\n client_secret text not null,\n name varchar(255) not null,\n scopes text not null,\n created_at varchar(64) not null,\n last_seen_at varchar(64)\n )\n `.execute(database);\n}\n\nasync function createSigningKeysTable(\n database: Kysely<SqlDatabase>,\n dialect: SqlDialect,\n tableName: string,\n): Promise<void> {\n if (dialect === \"mysql\") {\n await sql`\n create table if not exists ${sql.table(tableName)} (\n key_id varchar(255) not null primary key,\n algorithm varchar(32) not null,\n private_key text not null,\n public_key text not null,\n created_at varchar(64) not null,\n retired_at varchar(64) null\n )\n `.execute(database);\n return;\n }\n\n await sql`\n create table if not exists ${sql.table(tableName)} (\n key_id varchar(255) not null primary key,\n algorithm varchar(32) not null,\n private_key text not null,\n public_key text not null,\n created_at varchar(64) not null,\n retired_at varchar(64)\n )\n `.execute(database);\n}\n\nfunction mapClientRow(row: ClientRow): ServiceClient {\n return {\n id: row.id,\n clientId: row.client_id,\n clientSecret: row.client_secret,\n name: row.name,\n scopes: JSON.parse(row.scopes) as string[],\n createdAt: new Date(row.created_at),\n lastSeenAt: row.last_seen_at ? new Date(row.last_seen_at) : null,\n };\n}\n\nfunction mapSigningKeyRow(row: SigningKeyRow): SigningKey {\n return {\n keyId: row.key_id,\n algorithm: row.algorithm,\n privateKey: row.private_key,\n publicKey: row.public_key,\n createdAt: new Date(row.created_at),\n retiredAt: row.retired_at ? new Date(row.retired_at) : null,\n };\n}\n"],"mappings":"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","names":["import_kysely"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/adapters/postgres/index.ts","../../../src/storage/postgres.ts","../../../src/storage/sql.ts"],"sourcesContent":["export { postgresStorage } from \"../../storage/postgres\";\nexport type { SqlStorageOptions, StorageAdapter } from \"../../storage/interface\";\n","import { Kysely, PostgresDialect } from \"kysely\";\nimport type { Pool } from \"pg\";\n\nimport type { SqlStorageOptions, StorageAdapter } from \"./interface\";\nimport { createSqlStorage } from \"./sql\";\n\nexport function postgresStorage(\n pool: Pool,\n options?: SqlStorageOptions,\n): StorageAdapter {\n return createSqlStorage(\n new Kysely({\n dialect: new PostgresDialect({\n pool,\n }),\n }),\n \"postgres\",\n options,\n );\n}\n","import { type Kysely, sql } from \"kysely\";\n\nimport type {\n ServiceClient,\n SigningKey,\n SqlStorageOptions,\n StorageAdapter,\n} from \"./interface\";\n\ntype SqlDialect = \"mysql\" | \"postgres\" | \"sqlite\";\n\ninterface SqlTables {\n clients: string;\n signingKeys: string;\n}\n\ninterface SqlDatabase {\n [tableName: string]: SqlRow;\n}\n\ninterface SqlRow {\n algorithm?: SigningKey[\"algorithm\"];\n client_id?: string;\n client_secret?: string;\n created_at: string;\n id?: string;\n key_id?: string;\n last_seen_at?: string | null;\n name?: string;\n private_key?: string;\n public_key?: string;\n retired_at?: string | null;\n scopes?: string;\n}\n\ninterface ClientRow {\n id: string;\n client_id: string;\n client_secret: string;\n name: string;\n scopes: string;\n created_at: string;\n last_seen_at: string | null;\n}\n\ninterface SigningKeyRow {\n key_id: string;\n algorithm: SigningKey[\"algorithm\"];\n private_key: string;\n public_key: string;\n created_at: string;\n retired_at: string | null;\n}\n\nexport function createSqlStorage(\n database: Kysely<SqlDatabase>,\n dialect: SqlDialect,\n options?: SqlStorageOptions,\n): StorageAdapter {\n const tables = resolveTables(options);\n let schemaPromise: Promise<void> | null = null;\n\n async function ensureSchema(): Promise<void> {\n if (!schemaPromise) {\n schemaPromise = createSchema(database, dialect, tables);\n }\n\n await schemaPromise;\n }\n\n return {\n async findClient(clientId) {\n await ensureSchema();\n\n const row = (await database\n .selectFrom(tables.clients)\n .selectAll()\n .where(\"client_id\", \"=\", clientId)\n .executeTakeFirst()) as ClientRow | undefined;\n\n return row ? mapClientRow(row) : null;\n },\n async createClient(client) {\n await ensureSchema();\n\n await database\n .insertInto(tables.clients)\n .values({\n id: client.id,\n client_id: client.clientId,\n client_secret: client.clientSecret,\n name: client.name,\n scopes: JSON.stringify(client.scopes),\n created_at: client.createdAt.toISOString(),\n last_seen_at: client.lastSeenAt?.toISOString() ?? null,\n })\n .execute();\n },\n async deleteClient(clientId) {\n await ensureSchema();\n\n await database\n .deleteFrom(tables.clients)\n .where(\"client_id\", \"=\", clientId)\n .execute();\n },\n async listClients() {\n await ensureSchema();\n\n const rows = (await database\n .selectFrom(tables.clients)\n .selectAll()\n .orderBy(\"created_at\", \"asc\")\n .execute()) as ClientRow[];\n\n return rows.map(mapClientRow);\n },\n async touchClient(clientId, lastSeenAt) {\n await ensureSchema();\n\n await database\n .updateTable(tables.clients)\n .set({\n last_seen_at: lastSeenAt.toISOString(),\n })\n .where(\"client_id\", \"=\", clientId)\n .execute();\n },\n async getSigningKeys() {\n await ensureSchema();\n\n const rows = (await database\n .selectFrom(tables.signingKeys)\n .selectAll()\n .orderBy(\"created_at\", \"asc\")\n .execute()) as SigningKeyRow[];\n\n return rows.map(mapSigningKeyRow);\n },\n async addSigningKey(key) {\n await ensureSchema();\n\n await database\n .insertInto(tables.signingKeys)\n .values({\n key_id: key.keyId,\n algorithm: key.algorithm,\n private_key: key.privateKey,\n public_key: key.publicKey,\n created_at: key.createdAt.toISOString(),\n retired_at: key.retiredAt?.toISOString() ?? null,\n })\n .execute();\n },\n async retireKey(keyId) {\n await ensureSchema();\n\n await database\n .updateTable(tables.signingKeys)\n .set({\n retired_at: new Date().toISOString(),\n })\n .where(\"key_id\", \"=\", keyId)\n .execute();\n },\n };\n}\n\nfunction resolveTables(options?: SqlStorageOptions): SqlTables {\n const prefix = options?.tablePrefix ?? \"trustline_\";\n\n return {\n clients: options?.tables?.clients ?? `${prefix}clients`,\n signingKeys: options?.tables?.signingKeys ?? `${prefix}signing_keys`,\n };\n}\n\nasync function createSchema(\n database: Kysely<SqlDatabase>,\n dialect: SqlDialect,\n tables: SqlTables,\n): Promise<void> {\n await createClientsTable(database, dialect, tables.clients);\n await createSigningKeysTable(database, dialect, tables.signingKeys);\n}\n\nasync function createClientsTable(\n database: Kysely<SqlDatabase>,\n dialect: SqlDialect,\n tableName: string,\n): Promise<void> {\n if (dialect === \"mysql\") {\n await sql`\n create table if not exists ${sql.table(tableName)} (\n id varchar(255) not null,\n client_id varchar(255) not null primary key,\n client_secret text not null,\n name varchar(255) not null,\n scopes text not null,\n created_at varchar(64) not null,\n last_seen_at varchar(64) null\n )\n `.execute(database);\n return;\n }\n\n await sql`\n create table if not exists ${sql.table(tableName)} (\n id varchar(255) not null,\n client_id varchar(255) not null primary key,\n client_secret text not null,\n name varchar(255) not null,\n scopes text not null,\n created_at varchar(64) not null,\n last_seen_at varchar(64)\n )\n `.execute(database);\n}\n\nasync function createSigningKeysTable(\n database: Kysely<SqlDatabase>,\n dialect: SqlDialect,\n tableName: string,\n): Promise<void> {\n if (dialect === \"mysql\") {\n await sql`\n create table if not exists ${sql.table(tableName)} (\n key_id varchar(255) not null primary key,\n algorithm varchar(32) not null,\n private_key text not null,\n public_key text not null,\n created_at varchar(64) not null,\n retired_at varchar(64) null\n )\n `.execute(database);\n return;\n }\n\n await sql`\n create table if not exists ${sql.table(tableName)} (\n key_id varchar(255) not null primary key,\n algorithm varchar(32) not null,\n private_key text not null,\n public_key text not null,\n created_at varchar(64) not null,\n retired_at varchar(64)\n )\n `.execute(database);\n}\n\nfunction mapClientRow(row: ClientRow): ServiceClient {\n return {\n id: row.id,\n clientId: row.client_id,\n clientSecret: row.client_secret,\n name: row.name,\n scopes: JSON.parse(row.scopes) as string[],\n createdAt: new Date(row.created_at),\n lastSeenAt: row.last_seen_at ? new Date(row.last_seen_at) : null,\n };\n}\n\nfunction mapSigningKeyRow(row: SigningKeyRow): SigningKey {\n return {\n keyId: row.key_id,\n algorithm: row.algorithm,\n privateKey: row.private_key,\n publicKey: row.public_key,\n createdAt: new Date(row.created_at),\n retiredAt: row.retired_at ? new Date(row.retired_at) : null,\n };\n}\n"],"mappings":"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","names":["import_kysely"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/adapters/postgres/index.ts","../../../src/storage/postgres.ts","../../../src/storage/sql.ts"],"sourcesContent":["export type {\n SqlStorageOptions,\n StorageAdapter,\n} from \"../../storage/interface\";\nexport { postgresStorage } from \"../../storage/postgres\";\n","import { Kysely, PostgresDialect } from \"kysely\";\nimport type { Pool } from \"pg\";\n\nimport type { SqlStorageOptions, StorageAdapter } from \"./interface\";\nimport { createSqlStorage } from \"./sql\";\n\nexport function postgresStorage(\n pool: Pool,\n options?: SqlStorageOptions,\n): StorageAdapter {\n return createSqlStorage(\n new Kysely({\n dialect: new PostgresDialect({\n pool,\n }),\n }),\n \"postgres\",\n options,\n );\n}\n","import { type Kysely, sql } from \"kysely\";\n\nimport type {\n ServiceClient,\n SigningKey,\n SqlStorageOptions,\n StorageAdapter,\n} from \"./interface\";\n\ntype SqlDialect = \"mysql\" | \"postgres\" | \"sqlite\";\n\ninterface SqlTables {\n clients: string;\n signingKeys: string;\n}\n\ninterface SqlDatabase {\n [tableName: string]: SqlRow;\n}\n\ninterface SqlRow {\n algorithm?: SigningKey[\"algorithm\"];\n client_id?: string;\n client_secret?: string;\n created_at: string;\n id?: string;\n key_id?: string;\n last_seen_at?: string | null;\n name?: string;\n private_key?: string;\n public_key?: string;\n retired_at?: string | null;\n scopes?: string;\n}\n\ninterface ClientRow {\n id: string;\n client_id: string;\n client_secret: string;\n name: string;\n scopes: string;\n created_at: string;\n last_seen_at: string | null;\n}\n\ninterface SigningKeyRow {\n key_id: string;\n algorithm: SigningKey[\"algorithm\"];\n private_key: string;\n public_key: string;\n created_at: string;\n retired_at: string | null;\n}\n\nexport function createSqlStorage(\n database: Kysely<SqlDatabase>,\n dialect: SqlDialect,\n options?: SqlStorageOptions,\n): StorageAdapter {\n const tables = resolveTables(options);\n let schemaPromise: Promise<void> | null = null;\n\n async function ensureSchema(): Promise<void> {\n if (!schemaPromise) {\n schemaPromise = createSchema(database, dialect, tables);\n }\n\n await schemaPromise;\n }\n\n return {\n async findClient(clientId) {\n await ensureSchema();\n\n const row = (await database\n .selectFrom(tables.clients)\n .selectAll()\n .where(\"client_id\", \"=\", clientId)\n .executeTakeFirst()) as ClientRow | undefined;\n\n return row ? mapClientRow(row) : null;\n },\n async createClient(client) {\n await ensureSchema();\n\n await database\n .insertInto(tables.clients)\n .values({\n id: client.id,\n client_id: client.clientId,\n client_secret: client.clientSecret,\n name: client.name,\n scopes: JSON.stringify(client.scopes),\n created_at: client.createdAt.toISOString(),\n last_seen_at: client.lastSeenAt?.toISOString() ?? null,\n })\n .execute();\n },\n async deleteClient(clientId) {\n await ensureSchema();\n\n await database\n .deleteFrom(tables.clients)\n .where(\"client_id\", \"=\", clientId)\n .execute();\n },\n async listClients() {\n await ensureSchema();\n\n const rows = (await database\n .selectFrom(tables.clients)\n .selectAll()\n .orderBy(\"created_at\", \"asc\")\n .execute()) as ClientRow[];\n\n return rows.map(mapClientRow);\n },\n async touchClient(clientId, lastSeenAt) {\n await ensureSchema();\n\n await database\n .updateTable(tables.clients)\n .set({\n last_seen_at: lastSeenAt.toISOString(),\n })\n .where(\"client_id\", \"=\", clientId)\n .execute();\n },\n async getSigningKeys() {\n await ensureSchema();\n\n const rows = (await database\n .selectFrom(tables.signingKeys)\n .selectAll()\n .orderBy(\"created_at\", \"asc\")\n .execute()) as SigningKeyRow[];\n\n return rows.map(mapSigningKeyRow);\n },\n async addSigningKey(key) {\n await ensureSchema();\n\n await database\n .insertInto(tables.signingKeys)\n .values({\n key_id: key.keyId,\n algorithm: key.algorithm,\n private_key: key.privateKey,\n public_key: key.publicKey,\n created_at: key.createdAt.toISOString(),\n retired_at: key.retiredAt?.toISOString() ?? null,\n })\n .execute();\n },\n async retireKey(keyId) {\n await ensureSchema();\n\n await database\n .updateTable(tables.signingKeys)\n .set({\n retired_at: new Date().toISOString(),\n })\n .where(\"key_id\", \"=\", keyId)\n .execute();\n },\n };\n}\n\nfunction resolveTables(options?: SqlStorageOptions): SqlTables {\n const prefix = options?.tablePrefix ?? \"trustline_\";\n\n return {\n clients: options?.tables?.clients ?? `${prefix}clients`,\n signingKeys: options?.tables?.signingKeys ?? `${prefix}signing_keys`,\n };\n}\n\nasync function createSchema(\n database: Kysely<SqlDatabase>,\n dialect: SqlDialect,\n tables: SqlTables,\n): Promise<void> {\n await createClientsTable(database, dialect, tables.clients);\n await createSigningKeysTable(database, dialect, tables.signingKeys);\n}\n\nasync function createClientsTable(\n database: Kysely<SqlDatabase>,\n dialect: SqlDialect,\n tableName: string,\n): Promise<void> {\n if (dialect === \"mysql\") {\n await sql`\n create table if not exists ${sql.table(tableName)} (\n id varchar(255) not null,\n client_id varchar(255) not null primary key,\n client_secret text not null,\n name varchar(255) not null,\n scopes text not null,\n created_at varchar(64) not null,\n last_seen_at varchar(64) null\n )\n `.execute(database);\n return;\n }\n\n await sql`\n create table if not exists ${sql.table(tableName)} (\n id varchar(255) not null,\n client_id varchar(255) not null primary key,\n client_secret text not null,\n name varchar(255) not null,\n scopes text not null,\n created_at varchar(64) not null,\n last_seen_at varchar(64)\n )\n `.execute(database);\n}\n\nasync function createSigningKeysTable(\n database: Kysely<SqlDatabase>,\n dialect: SqlDialect,\n tableName: string,\n): Promise<void> {\n if (dialect === \"mysql\") {\n await sql`\n create table if not exists ${sql.table(tableName)} (\n key_id varchar(255) not null primary key,\n algorithm varchar(32) not null,\n private_key text not null,\n public_key text not null,\n created_at varchar(64) not null,\n retired_at varchar(64) null\n )\n `.execute(database);\n return;\n }\n\n await sql`\n create table if not exists ${sql.table(tableName)} (\n key_id varchar(255) not null primary key,\n algorithm varchar(32) not null,\n private_key text not null,\n public_key text not null,\n created_at varchar(64) not null,\n retired_at varchar(64)\n )\n `.execute(database);\n}\n\nfunction mapClientRow(row: ClientRow): ServiceClient {\n return {\n id: row.id,\n clientId: row.client_id,\n clientSecret: row.client_secret,\n name: row.name,\n scopes: JSON.parse(row.scopes) as string[],\n createdAt: new Date(row.created_at),\n lastSeenAt: row.last_seen_at ? new Date(row.last_seen_at) : null,\n };\n}\n\nfunction mapSigningKeyRow(row: SigningKeyRow): SigningKey {\n return {\n keyId: row.key_id,\n algorithm: row.algorithm,\n privateKey: row.private_key,\n publicKey: row.public_key,\n createdAt: new Date(row.created_at),\n retiredAt: row.retired_at ? new Date(row.retired_at) : null,\n };\n}\n"],"mappings":"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","names":["import_kysely"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/adapters/sqlite/index.ts","../../../src/storage/sqlite.ts","../../../src/storage/sql.ts"],"sourcesContent":["export { sqliteStorage } from \"../../storage/sqlite\";\nexport type { SqlStorageOptions, StorageAdapter } from \"../../storage/interface\";\n","import BetterSqlite3 from \"better-sqlite3\";\nimport { Kysely, SqliteDialect } from \"kysely\";\n\nimport type { SqlStorageOptions, StorageAdapter } from \"./interface\";\nimport { createSqlStorage } from \"./sql\";\n\nexport function sqliteStorage(\n pathOrDatabase: string | BetterSqlite3.Database,\n options?: SqlStorageOptions,\n): StorageAdapter {\n const database =\n typeof pathOrDatabase === \"string\"\n ? createSqliteDatabase(pathOrDatabase)\n : pathOrDatabase;\n\n return createSqlStorage(\n new Kysely({\n dialect: new SqliteDialect({\n database,\n }),\n }),\n \"sqlite\",\n options,\n );\n}\n\nfunction createSqliteDatabase(path: string): BetterSqlite3.Database {\n const database = new BetterSqlite3(path);\n database.pragma(\"journal_mode = WAL\");\n return database;\n}\n","import { type Kysely, sql } from \"kysely\";\n\nimport type {\n ServiceClient,\n SigningKey,\n SqlStorageOptions,\n StorageAdapter,\n} from \"./interface\";\n\ntype SqlDialect = \"mysql\" | \"postgres\" | \"sqlite\";\n\ninterface SqlTables {\n clients: string;\n signingKeys: string;\n}\n\ninterface SqlDatabase {\n [tableName: string]: SqlRow;\n}\n\ninterface SqlRow {\n algorithm?: SigningKey[\"algorithm\"];\n client_id?: string;\n client_secret?: string;\n created_at: string;\n id?: string;\n key_id?: string;\n last_seen_at?: string | null;\n name?: string;\n private_key?: string;\n public_key?: string;\n retired_at?: string | null;\n scopes?: string;\n}\n\ninterface ClientRow {\n id: string;\n client_id: string;\n client_secret: string;\n name: string;\n scopes: string;\n created_at: string;\n last_seen_at: string | null;\n}\n\ninterface SigningKeyRow {\n key_id: string;\n algorithm: SigningKey[\"algorithm\"];\n private_key: string;\n public_key: string;\n created_at: string;\n retired_at: string | null;\n}\n\nexport function createSqlStorage(\n database: Kysely<SqlDatabase>,\n dialect: SqlDialect,\n options?: SqlStorageOptions,\n): StorageAdapter {\n const tables = resolveTables(options);\n let schemaPromise: Promise<void> | null = null;\n\n async function ensureSchema(): Promise<void> {\n if (!schemaPromise) {\n schemaPromise = createSchema(database, dialect, tables);\n }\n\n await schemaPromise;\n }\n\n return {\n async findClient(clientId) {\n await ensureSchema();\n\n const row = (await database\n .selectFrom(tables.clients)\n .selectAll()\n .where(\"client_id\", \"=\", clientId)\n .executeTakeFirst()) as ClientRow | undefined;\n\n return row ? mapClientRow(row) : null;\n },\n async createClient(client) {\n await ensureSchema();\n\n await database\n .insertInto(tables.clients)\n .values({\n id: client.id,\n client_id: client.clientId,\n client_secret: client.clientSecret,\n name: client.name,\n scopes: JSON.stringify(client.scopes),\n created_at: client.createdAt.toISOString(),\n last_seen_at: client.lastSeenAt?.toISOString() ?? null,\n })\n .execute();\n },\n async deleteClient(clientId) {\n await ensureSchema();\n\n await database\n .deleteFrom(tables.clients)\n .where(\"client_id\", \"=\", clientId)\n .execute();\n },\n async listClients() {\n await ensureSchema();\n\n const rows = (await database\n .selectFrom(tables.clients)\n .selectAll()\n .orderBy(\"created_at\", \"asc\")\n .execute()) as ClientRow[];\n\n return rows.map(mapClientRow);\n },\n async touchClient(clientId, lastSeenAt) {\n await ensureSchema();\n\n await database\n .updateTable(tables.clients)\n .set({\n last_seen_at: lastSeenAt.toISOString(),\n })\n .where(\"client_id\", \"=\", clientId)\n .execute();\n },\n async getSigningKeys() {\n await ensureSchema();\n\n const rows = (await database\n .selectFrom(tables.signingKeys)\n .selectAll()\n .orderBy(\"created_at\", \"asc\")\n .execute()) as SigningKeyRow[];\n\n return rows.map(mapSigningKeyRow);\n },\n async addSigningKey(key) {\n await ensureSchema();\n\n await database\n .insertInto(tables.signingKeys)\n .values({\n key_id: key.keyId,\n algorithm: key.algorithm,\n private_key: key.privateKey,\n public_key: key.publicKey,\n created_at: key.createdAt.toISOString(),\n retired_at: key.retiredAt?.toISOString() ?? null,\n })\n .execute();\n },\n async retireKey(keyId) {\n await ensureSchema();\n\n await database\n .updateTable(tables.signingKeys)\n .set({\n retired_at: new Date().toISOString(),\n })\n .where(\"key_id\", \"=\", keyId)\n .execute();\n },\n };\n}\n\nfunction resolveTables(options?: SqlStorageOptions): SqlTables {\n const prefix = options?.tablePrefix ?? \"trustline_\";\n\n return {\n clients: options?.tables?.clients ?? `${prefix}clients`,\n signingKeys: options?.tables?.signingKeys ?? `${prefix}signing_keys`,\n };\n}\n\nasync function createSchema(\n database: Kysely<SqlDatabase>,\n dialect: SqlDialect,\n tables: SqlTables,\n): Promise<void> {\n await createClientsTable(database, dialect, tables.clients);\n await createSigningKeysTable(database, dialect, tables.signingKeys);\n}\n\nasync function createClientsTable(\n database: Kysely<SqlDatabase>,\n dialect: SqlDialect,\n tableName: string,\n): Promise<void> {\n if (dialect === \"mysql\") {\n await sql`\n create table if not exists ${sql.table(tableName)} (\n id varchar(255) not null,\n client_id varchar(255) not null primary key,\n client_secret text not null,\n name varchar(255) not null,\n scopes text not null,\n created_at varchar(64) not null,\n last_seen_at varchar(64) null\n )\n `.execute(database);\n return;\n }\n\n await sql`\n create table if not exists ${sql.table(tableName)} (\n id varchar(255) not null,\n client_id varchar(255) not null primary key,\n client_secret text not null,\n name varchar(255) not null,\n scopes text not null,\n created_at varchar(64) not null,\n last_seen_at varchar(64)\n )\n `.execute(database);\n}\n\nasync function createSigningKeysTable(\n database: Kysely<SqlDatabase>,\n dialect: SqlDialect,\n tableName: string,\n): Promise<void> {\n if (dialect === \"mysql\") {\n await sql`\n create table if not exists ${sql.table(tableName)} (\n key_id varchar(255) not null primary key,\n algorithm varchar(32) not null,\n private_key text not null,\n public_key text not null,\n created_at varchar(64) not null,\n retired_at varchar(64) null\n )\n `.execute(database);\n return;\n }\n\n await sql`\n create table if not exists ${sql.table(tableName)} (\n key_id varchar(255) not null primary key,\n algorithm varchar(32) not null,\n private_key text not null,\n public_key text not null,\n created_at varchar(64) not null,\n retired_at varchar(64)\n )\n `.execute(database);\n}\n\nfunction mapClientRow(row: ClientRow): ServiceClient {\n return {\n id: row.id,\n clientId: row.client_id,\n clientSecret: row.client_secret,\n name: row.name,\n scopes: JSON.parse(row.scopes) as string[],\n createdAt: new Date(row.created_at),\n lastSeenAt: row.last_seen_at ? new Date(row.last_seen_at) : null,\n };\n}\n\nfunction mapSigningKeyRow(row: SigningKeyRow): SigningKey {\n return {\n keyId: row.key_id,\n algorithm: row.algorithm,\n privateKey: row.private_key,\n publicKey: row.public_key,\n createdAt: new Date(row.created_at),\n retiredAt: row.retired_at ? new Date(row.retired_at) : null,\n };\n}\n"],"mappings":"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","names":["import_kysely","BetterSqlite3"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/adapters/sqlite/index.ts","../../../src/storage/sqlite.ts","../../../src/storage/sql.ts"],"sourcesContent":["export type {\n SqlStorageOptions,\n StorageAdapter,\n} from \"../../storage/interface\";\nexport { sqliteStorage } from \"../../storage/sqlite\";\n","import BetterSqlite3 from \"better-sqlite3\";\nimport { Kysely, SqliteDialect } from \"kysely\";\n\nimport type { SqlStorageOptions, StorageAdapter } from \"./interface\";\nimport { createSqlStorage } from \"./sql\";\n\nexport function sqliteStorage(\n pathOrDatabase: string | BetterSqlite3.Database,\n options?: SqlStorageOptions,\n): StorageAdapter {\n const database =\n typeof pathOrDatabase === \"string\"\n ? createSqliteDatabase(pathOrDatabase)\n : pathOrDatabase;\n\n return createSqlStorage(\n new Kysely({\n dialect: new SqliteDialect({\n database,\n }),\n }),\n \"sqlite\",\n options,\n );\n}\n\nfunction createSqliteDatabase(path: string): BetterSqlite3.Database {\n const database = new BetterSqlite3(path);\n database.pragma(\"journal_mode = WAL\");\n return database;\n}\n","import { type Kysely, sql } from \"kysely\";\n\nimport type {\n ServiceClient,\n SigningKey,\n SqlStorageOptions,\n StorageAdapter,\n} from \"./interface\";\n\ntype SqlDialect = \"mysql\" | \"postgres\" | \"sqlite\";\n\ninterface SqlTables {\n clients: string;\n signingKeys: string;\n}\n\ninterface SqlDatabase {\n [tableName: string]: SqlRow;\n}\n\ninterface SqlRow {\n algorithm?: SigningKey[\"algorithm\"];\n client_id?: string;\n client_secret?: string;\n created_at: string;\n id?: string;\n key_id?: string;\n last_seen_at?: string | null;\n name?: string;\n private_key?: string;\n public_key?: string;\n retired_at?: string | null;\n scopes?: string;\n}\n\ninterface ClientRow {\n id: string;\n client_id: string;\n client_secret: string;\n name: string;\n scopes: string;\n created_at: string;\n last_seen_at: string | null;\n}\n\ninterface SigningKeyRow {\n key_id: string;\n algorithm: SigningKey[\"algorithm\"];\n private_key: string;\n public_key: string;\n created_at: string;\n retired_at: string | null;\n}\n\nexport function createSqlStorage(\n database: Kysely<SqlDatabase>,\n dialect: SqlDialect,\n options?: SqlStorageOptions,\n): StorageAdapter {\n const tables = resolveTables(options);\n let schemaPromise: Promise<void> | null = null;\n\n async function ensureSchema(): Promise<void> {\n if (!schemaPromise) {\n schemaPromise = createSchema(database, dialect, tables);\n }\n\n await schemaPromise;\n }\n\n return {\n async findClient(clientId) {\n await ensureSchema();\n\n const row = (await database\n .selectFrom(tables.clients)\n .selectAll()\n .where(\"client_id\", \"=\", clientId)\n .executeTakeFirst()) as ClientRow | undefined;\n\n return row ? mapClientRow(row) : null;\n },\n async createClient(client) {\n await ensureSchema();\n\n await database\n .insertInto(tables.clients)\n .values({\n id: client.id,\n client_id: client.clientId,\n client_secret: client.clientSecret,\n name: client.name,\n scopes: JSON.stringify(client.scopes),\n created_at: client.createdAt.toISOString(),\n last_seen_at: client.lastSeenAt?.toISOString() ?? null,\n })\n .execute();\n },\n async deleteClient(clientId) {\n await ensureSchema();\n\n await database\n .deleteFrom(tables.clients)\n .where(\"client_id\", \"=\", clientId)\n .execute();\n },\n async listClients() {\n await ensureSchema();\n\n const rows = (await database\n .selectFrom(tables.clients)\n .selectAll()\n .orderBy(\"created_at\", \"asc\")\n .execute()) as ClientRow[];\n\n return rows.map(mapClientRow);\n },\n async touchClient(clientId, lastSeenAt) {\n await ensureSchema();\n\n await database\n .updateTable(tables.clients)\n .set({\n last_seen_at: lastSeenAt.toISOString(),\n })\n .where(\"client_id\", \"=\", clientId)\n .execute();\n },\n async getSigningKeys() {\n await ensureSchema();\n\n const rows = (await database\n .selectFrom(tables.signingKeys)\n .selectAll()\n .orderBy(\"created_at\", \"asc\")\n .execute()) as SigningKeyRow[];\n\n return rows.map(mapSigningKeyRow);\n },\n async addSigningKey(key) {\n await ensureSchema();\n\n await database\n .insertInto(tables.signingKeys)\n .values({\n key_id: key.keyId,\n algorithm: key.algorithm,\n private_key: key.privateKey,\n public_key: key.publicKey,\n created_at: key.createdAt.toISOString(),\n retired_at: key.retiredAt?.toISOString() ?? null,\n })\n .execute();\n },\n async retireKey(keyId) {\n await ensureSchema();\n\n await database\n .updateTable(tables.signingKeys)\n .set({\n retired_at: new Date().toISOString(),\n })\n .where(\"key_id\", \"=\", keyId)\n .execute();\n },\n };\n}\n\nfunction resolveTables(options?: SqlStorageOptions): SqlTables {\n const prefix = options?.tablePrefix ?? \"trustline_\";\n\n return {\n clients: options?.tables?.clients ?? `${prefix}clients`,\n signingKeys: options?.tables?.signingKeys ?? `${prefix}signing_keys`,\n };\n}\n\nasync function createSchema(\n database: Kysely<SqlDatabase>,\n dialect: SqlDialect,\n tables: SqlTables,\n): Promise<void> {\n await createClientsTable(database, dialect, tables.clients);\n await createSigningKeysTable(database, dialect, tables.signingKeys);\n}\n\nasync function createClientsTable(\n database: Kysely<SqlDatabase>,\n dialect: SqlDialect,\n tableName: string,\n): Promise<void> {\n if (dialect === \"mysql\") {\n await sql`\n create table if not exists ${sql.table(tableName)} (\n id varchar(255) not null,\n client_id varchar(255) not null primary key,\n client_secret text not null,\n name varchar(255) not null,\n scopes text not null,\n created_at varchar(64) not null,\n last_seen_at varchar(64) null\n )\n `.execute(database);\n return;\n }\n\n await sql`\n create table if not exists ${sql.table(tableName)} (\n id varchar(255) not null,\n client_id varchar(255) not null primary key,\n client_secret text not null,\n name varchar(255) not null,\n scopes text not null,\n created_at varchar(64) not null,\n last_seen_at varchar(64)\n )\n `.execute(database);\n}\n\nasync function createSigningKeysTable(\n database: Kysely<SqlDatabase>,\n dialect: SqlDialect,\n tableName: string,\n): Promise<void> {\n if (dialect === \"mysql\") {\n await sql`\n create table if not exists ${sql.table(tableName)} (\n key_id varchar(255) not null primary key,\n algorithm varchar(32) not null,\n private_key text not null,\n public_key text not null,\n created_at varchar(64) not null,\n retired_at varchar(64) null\n )\n `.execute(database);\n return;\n }\n\n await sql`\n create table if not exists ${sql.table(tableName)} (\n key_id varchar(255) not null primary key,\n algorithm varchar(32) not null,\n private_key text not null,\n public_key text not null,\n created_at varchar(64) not null,\n retired_at varchar(64)\n )\n `.execute(database);\n}\n\nfunction mapClientRow(row: ClientRow): ServiceClient {\n return {\n id: row.id,\n clientId: row.client_id,\n clientSecret: row.client_secret,\n name: row.name,\n scopes: JSON.parse(row.scopes) as string[],\n createdAt: new Date(row.created_at),\n lastSeenAt: row.last_seen_at ? new Date(row.last_seen_at) : null,\n };\n}\n\nfunction mapSigningKeyRow(row: SigningKeyRow): SigningKey {\n return {\n keyId: row.key_id,\n algorithm: row.algorithm,\n privateKey: row.private_key,\n publicKey: row.public_key,\n createdAt: new Date(row.created_at),\n retiredAt: row.retired_at ? new Date(row.retired_at) : null,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,4BAA0B;AAC1B,IAAAA,iBAAsC;;;ACDtC,oBAAiC;AAsD1B,SAAS,iBACd,UACA,SACA,SACgB;AAChB,QAAM,SAAS,cAAc,OAAO;AACpC,MAAI,gBAAsC;AAE1C,iBAAe,eAA8B;AAC3C,QAAI,CAAC,eAAe;AAClB,sBAAgB,aAAa,UAAU,SAAS,MAAM;AAAA,IACxD;AAEA,UAAM;AAAA,EACR;AAEA,SAAO;AAAA,IACL,MAAM,WAAW,UAAU;AACzB,YAAM,aAAa;AAEnB,YAAM,MAAO,MAAM,SAChB,WAAW,OAAO,OAAO,EACzB,UAAU,EACV,MAAM,aAAa,KAAK,QAAQ,EAChC,iBAAiB;AAEpB,aAAO,MAAM,aAAa,GAAG,IAAI;AAAA,IACnC;AAAA,IACA,MAAM,aAAa,QAAQ;AACzB,YAAM,aAAa;AAEnB,YAAM,SACH,WAAW,OAAO,OAAO,EACzB,OAAO;AAAA,QACN,IAAI,OAAO;AAAA,QACX,WAAW,OAAO;AAAA,QAClB,eAAe,OAAO;AAAA,QACtB,MAAM,OAAO;AAAA,QACb,QAAQ,KAAK,UAAU,OAAO,MAAM;AAAA,QACpC,YAAY,OAAO,UAAU,YAAY;AAAA,QACzC,cAAc,OAAO,YAAY,YAAY,KAAK;AAAA,MACpD,CAAC,EACA,QAAQ;AAAA,IACb;AAAA,IACA,MAAM,aAAa,UAAU;AAC3B,YAAM,aAAa;AAEnB,YAAM,SACH,WAAW,OAAO,OAAO,EACzB,MAAM,aAAa,KAAK,QAAQ,EAChC,QAAQ;AAAA,IACb;AAAA,IACA,MAAM,cAAc;AAClB,YAAM,aAAa;AAEnB,YAAM,OAAQ,MAAM,SACjB,WAAW,OAAO,OAAO,EACzB,UAAU,EACV,QAAQ,cAAc,KAAK,EAC3B,QAAQ;AAEX,aAAO,KAAK,IAAI,YAAY;AAAA,IAC9B;AAAA,IACA,MAAM,YAAY,UAAU,YAAY;AACtC,YAAM,aAAa;AAEnB,YAAM,SACH,YAAY,OAAO,OAAO,EAC1B,IAAI;AAAA,QACH,cAAc,WAAW,YAAY;AAAA,MACvC,CAAC,EACA,MAAM,aAAa,KAAK,QAAQ,EAChC,QAAQ;AAAA,IACb;AAAA,IACA,MAAM,iBAAiB;AACrB,YAAM,aAAa;AAEnB,YAAM,OAAQ,MAAM,SACjB,WAAW,OAAO,WAAW,EAC7B,UAAU,EACV,QAAQ,cAAc,KAAK,EAC3B,QAAQ;AAEX,aAAO,KAAK,IAAI,gBAAgB;AAAA,IAClC;AAAA,IACA,MAAM,cAAc,KAAK;AACvB,YAAM,aAAa;AAEnB,YAAM,SACH,WAAW,OAAO,WAAW,EAC7B,OAAO;AAAA,QACN,QAAQ,IAAI;AAAA,QACZ,WAAW,IAAI;AAAA,QACf,aAAa,IAAI;AAAA,QACjB,YAAY,IAAI;AAAA,QAChB,YAAY,IAAI,UAAU,YAAY;AAAA,QACtC,YAAY,IAAI,WAAW,YAAY,KAAK;AAAA,MAC9C,CAAC,EACA,QAAQ;AAAA,IACb;AAAA,IACA,MAAM,UAAU,OAAO;AACrB,YAAM,aAAa;AAEnB,YAAM,SACH,YAAY,OAAO,WAAW,EAC9B,IAAI;AAAA,QACH,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,MACrC,CAAC,EACA,MAAM,UAAU,KAAK,KAAK,EAC1B,QAAQ;AAAA,IACb;AAAA,EACF;AACF;AAEA,SAAS,cAAc,SAAwC;AAC7D,QAAM,SAAS,SAAS,eAAe;AAEvC,SAAO;AAAA,IACL,SAAS,SAAS,QAAQ,WAAW,GAAG,MAAM;AAAA,IAC9C,aAAa,SAAS,QAAQ,eAAe,GAAG,MAAM;AAAA,EACxD;AACF;AAEA,eAAe,aACb,UACA,SACA,QACe;AACf,QAAM,mBAAmB,UAAU,SAAS,OAAO,OAAO;AAC1D,QAAM,uBAAuB,UAAU,SAAS,OAAO,WAAW;AACpE;AAEA,eAAe,mBACb,UACA,SACA,WACe;AACf,MAAI,YAAY,SAAS;AACvB,UAAM;AAAA,mCACyB,kBAAI,MAAM,SAAS,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASjD,QAAQ,QAAQ;AAClB;AAAA,EACF;AAEA,QAAM;AAAA,iCACyB,kBAAI,MAAM,SAAS,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IASjD,QAAQ,QAAQ;AACpB;AAEA,eAAe,uBACb,UACA,SACA,WACe;AACf,MAAI,YAAY,SAAS;AACvB,UAAM;AAAA,mCACyB,kBAAI,MAAM,SAAS,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQjD,QAAQ,QAAQ;AAClB;AAAA,EACF;AAEA,QAAM;AAAA,iCACyB,kBAAI,MAAM,SAAS,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQjD,QAAQ,QAAQ;AACpB;AAEA,SAAS,aAAa,KAA+B;AACnD,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,UAAU,IAAI;AAAA,IACd,cAAc,IAAI;AAAA,IAClB,MAAM,IAAI;AAAA,IACV,QAAQ,KAAK,MAAM,IAAI,MAAM;AAAA,IAC7B,WAAW,IAAI,KAAK,IAAI,UAAU;AAAA,IAClC,YAAY,IAAI,eAAe,IAAI,KAAK,IAAI,YAAY,IAAI;AAAA,EAC9D;AACF;AAEA,SAAS,iBAAiB,KAAgC;AACxD,SAAO;AAAA,IACL,OAAO,IAAI;AAAA,IACX,WAAW,IAAI;AAAA,IACf,YAAY,IAAI;AAAA,IAChB,WAAW,IAAI;AAAA,IACf,WAAW,IAAI,KAAK,IAAI,UAAU;AAAA,IAClC,WAAW,IAAI,aAAa,IAAI,KAAK,IAAI,UAAU,IAAI;AAAA,EACzD;AACF;;;ADzQO,SAAS,cACd,gBACA,SACgB;AAChB,QAAM,WACJ,OAAO,mBAAmB,WACtB,qBAAqB,cAAc,IACnC;AAEN,SAAO;AAAA,IACL,IAAI,sBAAO;AAAA,MACT,SAAS,IAAI,6BAAc;AAAA,QACzB;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,IACD;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,qBAAqB,MAAsC;AAClE,QAAM,WAAW,IAAI,sBAAAC,QAAc,IAAI;AACvC,WAAS,OAAO,oBAAoB;AACpC,SAAO;AACT;","names":["import_kysely","BetterSqlite3"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import BetterSqlite3 from 'better-sqlite3';
|
|
2
1
|
import { S as SqlStorageOptions, a as StorageAdapter } from '../../interface-BzT_DC3u.cjs';
|
|
2
|
+
import BetterSqlite3 from 'better-sqlite3';
|
|
3
3
|
|
|
4
4
|
declare function sqliteStorage(pathOrDatabase: string | BetterSqlite3.Database, options?: SqlStorageOptions): StorageAdapter;
|
|
5
5
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import BetterSqlite3 from 'better-sqlite3';
|
|
2
1
|
import { S as SqlStorageOptions, a as StorageAdapter } from '../../interface-BzT_DC3u.js';
|
|
2
|
+
import BetterSqlite3 from 'better-sqlite3';
|
|
3
3
|
|
|
4
4
|
declare function sqliteStorage(pathOrDatabase: string | BetterSqlite3.Database, options?: SqlStorageOptions): StorageAdapter;
|
|
5
5
|
|
|
@@ -25,41 +25,6 @@ __export(express_exports, {
|
|
|
25
25
|
});
|
|
26
26
|
module.exports = __toCommonJS(express_exports);
|
|
27
27
|
|
|
28
|
-
// src/provider/express.ts
|
|
29
|
-
function createExpressProvider(provider) {
|
|
30
|
-
return async function trustlineProvider(request, response) {
|
|
31
|
-
const origin = `${request.protocol}://${request.get("host") ?? "localhost"}`;
|
|
32
|
-
const url = new URL(request.originalUrl || request.url, origin);
|
|
33
|
-
const body = request.method === "GET" || request.method === "HEAD" ? void 0 : await readBody(request);
|
|
34
|
-
const providerResponse = await provider.handle(
|
|
35
|
-
new Request(url.toString(), {
|
|
36
|
-
method: request.method,
|
|
37
|
-
headers: request.headers,
|
|
38
|
-
body
|
|
39
|
-
})
|
|
40
|
-
);
|
|
41
|
-
response.status(providerResponse.status);
|
|
42
|
-
providerResponse.headers.forEach((value, key) => {
|
|
43
|
-
response.setHeader(key, value);
|
|
44
|
-
});
|
|
45
|
-
response.send(await providerResponse.text());
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
function readBody(request) {
|
|
49
|
-
return new Promise((resolve, reject) => {
|
|
50
|
-
const chunks = [];
|
|
51
|
-
request.on("data", (chunk) => {
|
|
52
|
-
chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
|
|
53
|
-
});
|
|
54
|
-
request.on("end", () => {
|
|
55
|
-
resolve(
|
|
56
|
-
chunks.length > 0 ? Buffer.concat(chunks).toString("utf8") : void 0
|
|
57
|
-
);
|
|
58
|
-
});
|
|
59
|
-
request.on("error", reject);
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
|
|
63
28
|
// src/core/errors.ts
|
|
64
29
|
var AuthError = class extends Error {
|
|
65
30
|
code;
|
|
@@ -113,6 +78,41 @@ function getBearerToken(header) {
|
|
|
113
78
|
}
|
|
114
79
|
return value;
|
|
115
80
|
}
|
|
81
|
+
|
|
82
|
+
// src/provider/express.ts
|
|
83
|
+
function createExpressProvider(provider) {
|
|
84
|
+
return async function trustlineProvider(request, response) {
|
|
85
|
+
const origin = `${request.protocol}://${request.get("host") ?? "localhost"}`;
|
|
86
|
+
const url = new URL(request.originalUrl || request.url, origin);
|
|
87
|
+
const body = request.method === "GET" || request.method === "HEAD" ? void 0 : await readBody(request);
|
|
88
|
+
const providerResponse = await provider.handle(
|
|
89
|
+
new Request(url.toString(), {
|
|
90
|
+
method: request.method,
|
|
91
|
+
headers: request.headers,
|
|
92
|
+
body
|
|
93
|
+
})
|
|
94
|
+
);
|
|
95
|
+
response.status(providerResponse.status);
|
|
96
|
+
providerResponse.headers.forEach((value, key) => {
|
|
97
|
+
response.setHeader(key, value);
|
|
98
|
+
});
|
|
99
|
+
response.send(await providerResponse.text());
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function readBody(request) {
|
|
103
|
+
return new Promise((resolve, reject) => {
|
|
104
|
+
const chunks = [];
|
|
105
|
+
request.on("data", (chunk) => {
|
|
106
|
+
chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
|
|
107
|
+
});
|
|
108
|
+
request.on("end", () => {
|
|
109
|
+
resolve(
|
|
110
|
+
chunks.length > 0 ? Buffer.concat(chunks).toString("utf8") : void 0
|
|
111
|
+
);
|
|
112
|
+
});
|
|
113
|
+
request.on("error", reject);
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
116
|
// Annotate the CommonJS export names for ESM import in node:
|
|
117
117
|
0 && (module.exports = {
|
|
118
118
|
createExpressGuard,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/frameworks/express/index.ts","../../../src/
|
|
1
|
+
{"version":3,"sources":["../../../src/frameworks/express/index.ts","../../../src/core/errors.ts","../../../src/middleware/express.ts","../../../src/provider/express.ts"],"sourcesContent":["export {\n createExpressGuard,\n type TrustlineRequest,\n} from \"../../middleware/express\";\nexport {\n createExpressProvider,\n type WebHandler,\n} from \"../../provider/express\";\n","export type AuthErrorCode =\n | \"missing_token\"\n | \"invalid_token\"\n | \"invalid_issuer\"\n | \"invalid_audience\"\n | \"invalid_scope\"\n | \"invalid_env\"\n | \"jwks_fetch_failed\";\n\nexport class AuthError extends Error {\n public readonly code: AuthErrorCode;\n public readonly status: number;\n public readonly cause?: unknown;\n\n constructor(\n code: AuthErrorCode,\n message: string,\n status: number,\n cause?: unknown,\n ) {\n super(message);\n this.name = \"AuthError\";\n this.code = code;\n this.status = status;\n this.cause = cause;\n }\n}\n","import type { Request, RequestHandler, Response } from \"express\";\n\nimport { AuthError } from \"../core/errors\";\nimport type { ServiceIdentity } from \"../core/token\";\n\nexport interface GuardVerifier {\n verify(token: string): Promise<ServiceIdentity>;\n}\n\nexport interface TrustlineRequest extends Request {\n trustline?: ServiceIdentity;\n}\n\nexport function createExpressGuard(guard: GuardVerifier): RequestHandler {\n return async function trustlineGuard(\n request: Request,\n response: Response,\n next,\n ) {\n const token = getBearerToken(request.headers.authorization);\n\n if (!token) {\n response.status(401).json({\n error: \"missing_token\",\n message: \"Missing bearer token\",\n });\n return;\n }\n\n try {\n const identity = await guard.verify(token);\n (request as TrustlineRequest).trustline = identity;\n next();\n } catch (error) {\n const authError =\n error instanceof AuthError\n ? error\n : new AuthError(\n \"invalid_token\",\n \"Token verification failed\",\n 401,\n error,\n );\n response.status(authError.status).json({\n error: authError.code,\n message: authError.message,\n });\n }\n };\n}\n\nfunction getBearerToken(header: string | undefined): string | null {\n if (!header) {\n return null;\n }\n\n const [scheme, value] = header.split(/\\s+/, 2);\n if (scheme?.toLowerCase() !== \"bearer\" || !value) {\n return null;\n }\n\n return value;\n}\n","import type {\n Request as ExpressRequest,\n Response as ExpressResponse,\n RequestHandler,\n} from \"express\";\n\nexport interface WebHandler {\n handle(request: Request): Promise<Response>;\n}\n\nexport function createExpressProvider(provider: WebHandler): RequestHandler {\n return async function trustlineProvider(\n request: ExpressRequest,\n response: ExpressResponse,\n ) {\n const origin = `${request.protocol}://${request.get(\"host\") ?? \"localhost\"}`;\n const url = new URL(request.originalUrl || request.url, origin);\n const body =\n request.method === \"GET\" || request.method === \"HEAD\"\n ? undefined\n : await readBody(request);\n\n const providerResponse = await provider.handle(\n new Request(url.toString(), {\n method: request.method,\n headers: request.headers as HeadersInit,\n body,\n }),\n );\n\n response.status(providerResponse.status);\n providerResponse.headers.forEach((value, key) => {\n response.setHeader(key, value);\n });\n response.send(await providerResponse.text());\n };\n}\n\nfunction readBody(request: ExpressRequest): Promise<string | undefined> {\n return new Promise((resolve, reject) => {\n const chunks: Uint8Array[] = [];\n request.on(\"data\", (chunk) => {\n chunks.push(typeof chunk === \"string\" ? Buffer.from(chunk) : chunk);\n });\n request.on(\"end\", () => {\n resolve(\n chunks.length > 0 ? Buffer.concat(chunks).toString(\"utf8\") : undefined,\n );\n });\n request.on(\"error\", reject);\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACSO,IAAM,YAAN,cAAwB,MAAM;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EAEhB,YACE,MACA,SACA,QACA,OACA;AACA,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,QAAQ;AAAA,EACf;AACF;;;ACbO,SAAS,mBAAmB,OAAsC;AACvE,SAAO,eAAe,eACpB,SACA,UACA,MACA;AACA,UAAM,QAAQ,eAAe,QAAQ,QAAQ,aAAa;AAE1D,QAAI,CAAC,OAAO;AACV,eAAS,OAAO,GAAG,EAAE,KAAK;AAAA,QACxB,OAAO;AAAA,QACP,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AAEA,QAAI;AACF,YAAM,WAAW,MAAM,MAAM,OAAO,KAAK;AACzC,MAAC,QAA6B,YAAY;AAC1C,WAAK;AAAA,IACP,SAAS,OAAO;AACd,YAAM,YACJ,iBAAiB,YACb,QACA,IAAI;AAAA,QACF;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACN,eAAS,OAAO,UAAU,MAAM,EAAE,KAAK;AAAA,QACrC,OAAO,UAAU;AAAA,QACjB,SAAS,UAAU;AAAA,MACrB,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,SAAS,eAAe,QAA2C;AACjE,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AAEA,QAAM,CAAC,QAAQ,KAAK,IAAI,OAAO,MAAM,OAAO,CAAC;AAC7C,MAAI,QAAQ,YAAY,MAAM,YAAY,CAAC,OAAO;AAChD,WAAO;AAAA,EACT;AAEA,SAAO;AACT;;;ACpDO,SAAS,sBAAsB,UAAsC;AAC1E,SAAO,eAAe,kBACpB,SACA,UACA;AACA,UAAM,SAAS,GAAG,QAAQ,QAAQ,MAAM,QAAQ,IAAI,MAAM,KAAK,WAAW;AAC1E,UAAM,MAAM,IAAI,IAAI,QAAQ,eAAe,QAAQ,KAAK,MAAM;AAC9D,UAAM,OACJ,QAAQ,WAAW,SAAS,QAAQ,WAAW,SAC3C,SACA,MAAM,SAAS,OAAO;AAE5B,UAAM,mBAAmB,MAAM,SAAS;AAAA,MACtC,IAAI,QAAQ,IAAI,SAAS,GAAG;AAAA,QAC1B,QAAQ,QAAQ;AAAA,QAChB,SAAS,QAAQ;AAAA,QACjB;AAAA,MACF,CAAC;AAAA,IACH;AAEA,aAAS,OAAO,iBAAiB,MAAM;AACvC,qBAAiB,QAAQ,QAAQ,CAAC,OAAO,QAAQ;AAC/C,eAAS,UAAU,KAAK,KAAK;AAAA,IAC/B,CAAC;AACD,aAAS,KAAK,MAAM,iBAAiB,KAAK,CAAC;AAAA,EAC7C;AACF;AAEA,SAAS,SAAS,SAAsD;AACtE,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,SAAuB,CAAC;AAC9B,YAAQ,GAAG,QAAQ,CAAC,UAAU;AAC5B,aAAO,KAAK,OAAO,UAAU,WAAW,OAAO,KAAK,KAAK,IAAI,KAAK;AAAA,IACpE,CAAC;AACD,YAAQ,GAAG,OAAO,MAAM;AACtB;AAAA,QACE,OAAO,SAAS,IAAI,OAAO,OAAO,MAAM,EAAE,SAAS,MAAM,IAAI;AAAA,MAC/D;AAAA,IACF,CAAC;AACD,YAAQ,GAAG,SAAS,MAAM;AAAA,EAC5B,CAAC;AACH;","names":[]}
|
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Request as Request$1, RequestHandler } from 'express';
|
|
2
2
|
import { S as ServiceIdentity } from '../../token-BtfYGd9K.cjs';
|
|
3
3
|
import 'jose';
|
|
4
4
|
|
|
5
|
-
interface WebHandler {
|
|
6
|
-
handle(request: Request): Promise<Response>;
|
|
7
|
-
}
|
|
8
|
-
declare function createExpressProvider(provider: WebHandler): RequestHandler;
|
|
9
|
-
|
|
10
5
|
interface GuardVerifier {
|
|
11
6
|
verify(token: string): Promise<ServiceIdentity>;
|
|
12
7
|
}
|
|
@@ -15,4 +10,9 @@ interface TrustlineRequest extends Request$1 {
|
|
|
15
10
|
}
|
|
16
11
|
declare function createExpressGuard(guard: GuardVerifier): RequestHandler;
|
|
17
12
|
|
|
13
|
+
interface WebHandler {
|
|
14
|
+
handle(request: Request): Promise<Response>;
|
|
15
|
+
}
|
|
16
|
+
declare function createExpressProvider(provider: WebHandler): RequestHandler;
|
|
17
|
+
|
|
18
18
|
export { type TrustlineRequest, type WebHandler, createExpressGuard, createExpressProvider };
|
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Request as Request$1, RequestHandler } from 'express';
|
|
2
2
|
import { S as ServiceIdentity } from '../../token-BtfYGd9K.js';
|
|
3
3
|
import 'jose';
|
|
4
4
|
|
|
5
|
-
interface WebHandler {
|
|
6
|
-
handle(request: Request): Promise<Response>;
|
|
7
|
-
}
|
|
8
|
-
declare function createExpressProvider(provider: WebHandler): RequestHandler;
|
|
9
|
-
|
|
10
5
|
interface GuardVerifier {
|
|
11
6
|
verify(token: string): Promise<ServiceIdentity>;
|
|
12
7
|
}
|
|
@@ -15,4 +10,9 @@ interface TrustlineRequest extends Request$1 {
|
|
|
15
10
|
}
|
|
16
11
|
declare function createExpressGuard(guard: GuardVerifier): RequestHandler;
|
|
17
12
|
|
|
13
|
+
interface WebHandler {
|
|
14
|
+
handle(request: Request): Promise<Response>;
|
|
15
|
+
}
|
|
16
|
+
declare function createExpressProvider(provider: WebHandler): RequestHandler;
|
|
17
|
+
|
|
18
18
|
export { type TrustlineRequest, type WebHandler, createExpressGuard, createExpressProvider };
|
|
@@ -2,41 +2,6 @@ import {
|
|
|
2
2
|
AuthError
|
|
3
3
|
} from "../../chunk-GF3NKEEK.js";
|
|
4
4
|
|
|
5
|
-
// src/provider/express.ts
|
|
6
|
-
function createExpressProvider(provider) {
|
|
7
|
-
return async function trustlineProvider(request, response) {
|
|
8
|
-
const origin = `${request.protocol}://${request.get("host") ?? "localhost"}`;
|
|
9
|
-
const url = new URL(request.originalUrl || request.url, origin);
|
|
10
|
-
const body = request.method === "GET" || request.method === "HEAD" ? void 0 : await readBody(request);
|
|
11
|
-
const providerResponse = await provider.handle(
|
|
12
|
-
new Request(url.toString(), {
|
|
13
|
-
method: request.method,
|
|
14
|
-
headers: request.headers,
|
|
15
|
-
body
|
|
16
|
-
})
|
|
17
|
-
);
|
|
18
|
-
response.status(providerResponse.status);
|
|
19
|
-
providerResponse.headers.forEach((value, key) => {
|
|
20
|
-
response.setHeader(key, value);
|
|
21
|
-
});
|
|
22
|
-
response.send(await providerResponse.text());
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
function readBody(request) {
|
|
26
|
-
return new Promise((resolve, reject) => {
|
|
27
|
-
const chunks = [];
|
|
28
|
-
request.on("data", (chunk) => {
|
|
29
|
-
chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
|
|
30
|
-
});
|
|
31
|
-
request.on("end", () => {
|
|
32
|
-
resolve(
|
|
33
|
-
chunks.length > 0 ? Buffer.concat(chunks).toString("utf8") : void 0
|
|
34
|
-
);
|
|
35
|
-
});
|
|
36
|
-
request.on("error", reject);
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
|
|
40
5
|
// src/middleware/express.ts
|
|
41
6
|
function createExpressGuard(guard) {
|
|
42
7
|
return async function trustlineGuard(request, response, next) {
|
|
@@ -76,6 +41,41 @@ function getBearerToken(header) {
|
|
|
76
41
|
}
|
|
77
42
|
return value;
|
|
78
43
|
}
|
|
44
|
+
|
|
45
|
+
// src/provider/express.ts
|
|
46
|
+
function createExpressProvider(provider) {
|
|
47
|
+
return async function trustlineProvider(request, response) {
|
|
48
|
+
const origin = `${request.protocol}://${request.get("host") ?? "localhost"}`;
|
|
49
|
+
const url = new URL(request.originalUrl || request.url, origin);
|
|
50
|
+
const body = request.method === "GET" || request.method === "HEAD" ? void 0 : await readBody(request);
|
|
51
|
+
const providerResponse = await provider.handle(
|
|
52
|
+
new Request(url.toString(), {
|
|
53
|
+
method: request.method,
|
|
54
|
+
headers: request.headers,
|
|
55
|
+
body
|
|
56
|
+
})
|
|
57
|
+
);
|
|
58
|
+
response.status(providerResponse.status);
|
|
59
|
+
providerResponse.headers.forEach((value, key) => {
|
|
60
|
+
response.setHeader(key, value);
|
|
61
|
+
});
|
|
62
|
+
response.send(await providerResponse.text());
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function readBody(request) {
|
|
66
|
+
return new Promise((resolve, reject) => {
|
|
67
|
+
const chunks = [];
|
|
68
|
+
request.on("data", (chunk) => {
|
|
69
|
+
chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
|
|
70
|
+
});
|
|
71
|
+
request.on("end", () => {
|
|
72
|
+
resolve(
|
|
73
|
+
chunks.length > 0 ? Buffer.concat(chunks).toString("utf8") : void 0
|
|
74
|
+
);
|
|
75
|
+
});
|
|
76
|
+
request.on("error", reject);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
79
|
export {
|
|
80
80
|
createExpressGuard,
|
|
81
81
|
createExpressProvider
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/
|
|
1
|
+
{"version":3,"sources":["../../../src/middleware/express.ts","../../../src/provider/express.ts"],"sourcesContent":["import type { Request, RequestHandler, Response } from \"express\";\n\nimport { AuthError } from \"../core/errors\";\nimport type { ServiceIdentity } from \"../core/token\";\n\nexport interface GuardVerifier {\n verify(token: string): Promise<ServiceIdentity>;\n}\n\nexport interface TrustlineRequest extends Request {\n trustline?: ServiceIdentity;\n}\n\nexport function createExpressGuard(guard: GuardVerifier): RequestHandler {\n return async function trustlineGuard(\n request: Request,\n response: Response,\n next,\n ) {\n const token = getBearerToken(request.headers.authorization);\n\n if (!token) {\n response.status(401).json({\n error: \"missing_token\",\n message: \"Missing bearer token\",\n });\n return;\n }\n\n try {\n const identity = await guard.verify(token);\n (request as TrustlineRequest).trustline = identity;\n next();\n } catch (error) {\n const authError =\n error instanceof AuthError\n ? error\n : new AuthError(\n \"invalid_token\",\n \"Token verification failed\",\n 401,\n error,\n );\n response.status(authError.status).json({\n error: authError.code,\n message: authError.message,\n });\n }\n };\n}\n\nfunction getBearerToken(header: string | undefined): string | null {\n if (!header) {\n return null;\n }\n\n const [scheme, value] = header.split(/\\s+/, 2);\n if (scheme?.toLowerCase() !== \"bearer\" || !value) {\n return null;\n }\n\n return value;\n}\n","import type {\n Request as ExpressRequest,\n Response as ExpressResponse,\n RequestHandler,\n} from \"express\";\n\nexport interface WebHandler {\n handle(request: Request): Promise<Response>;\n}\n\nexport function createExpressProvider(provider: WebHandler): RequestHandler {\n return async function trustlineProvider(\n request: ExpressRequest,\n response: ExpressResponse,\n ) {\n const origin = `${request.protocol}://${request.get(\"host\") ?? \"localhost\"}`;\n const url = new URL(request.originalUrl || request.url, origin);\n const body =\n request.method === \"GET\" || request.method === \"HEAD\"\n ? undefined\n : await readBody(request);\n\n const providerResponse = await provider.handle(\n new Request(url.toString(), {\n method: request.method,\n headers: request.headers as HeadersInit,\n body,\n }),\n );\n\n response.status(providerResponse.status);\n providerResponse.headers.forEach((value, key) => {\n response.setHeader(key, value);\n });\n response.send(await providerResponse.text());\n };\n}\n\nfunction readBody(request: ExpressRequest): Promise<string | undefined> {\n return new Promise((resolve, reject) => {\n const chunks: Uint8Array[] = [];\n request.on(\"data\", (chunk) => {\n chunks.push(typeof chunk === \"string\" ? Buffer.from(chunk) : chunk);\n });\n request.on(\"end\", () => {\n resolve(\n chunks.length > 0 ? Buffer.concat(chunks).toString(\"utf8\") : undefined,\n );\n });\n request.on(\"error\", reject);\n });\n}\n"],"mappings":";;;;;AAaO,SAAS,mBAAmB,OAAsC;AACvE,SAAO,eAAe,eACpB,SACA,UACA,MACA;AACA,UAAM,QAAQ,eAAe,QAAQ,QAAQ,aAAa;AAE1D,QAAI,CAAC,OAAO;AACV,eAAS,OAAO,GAAG,EAAE,KAAK;AAAA,QACxB,OAAO;AAAA,QACP,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AAEA,QAAI;AACF,YAAM,WAAW,MAAM,MAAM,OAAO,KAAK;AACzC,MAAC,QAA6B,YAAY;AAC1C,WAAK;AAAA,IACP,SAAS,OAAO;AACd,YAAM,YACJ,iBAAiB,YACb,QACA,IAAI;AAAA,QACF;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACN,eAAS,OAAO,UAAU,MAAM,EAAE,KAAK;AAAA,QACrC,OAAO,UAAU;AAAA,QACjB,SAAS,UAAU;AAAA,MACrB,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,SAAS,eAAe,QAA2C;AACjE,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AAEA,QAAM,CAAC,QAAQ,KAAK,IAAI,OAAO,MAAM,OAAO,CAAC;AAC7C,MAAI,QAAQ,YAAY,MAAM,YAAY,CAAC,OAAO;AAChD,WAAO;AAAA,EACT;AAEA,SAAO;AACT;;;ACpDO,SAAS,sBAAsB,UAAsC;AAC1E,SAAO,eAAe,kBACpB,SACA,UACA;AACA,UAAM,SAAS,GAAG,QAAQ,QAAQ,MAAM,QAAQ,IAAI,MAAM,KAAK,WAAW;AAC1E,UAAM,MAAM,IAAI,IAAI,QAAQ,eAAe,QAAQ,KAAK,MAAM;AAC9D,UAAM,OACJ,QAAQ,WAAW,SAAS,QAAQ,WAAW,SAC3C,SACA,MAAM,SAAS,OAAO;AAE5B,UAAM,mBAAmB,MAAM,SAAS;AAAA,MACtC,IAAI,QAAQ,IAAI,SAAS,GAAG;AAAA,QAC1B,QAAQ,QAAQ;AAAA,QAChB,SAAS,QAAQ;AAAA,QACjB;AAAA,MACF,CAAC;AAAA,IACH;AAEA,aAAS,OAAO,iBAAiB,MAAM;AACvC,qBAAiB,QAAQ,QAAQ,CAAC,OAAO,QAAQ;AAC/C,eAAS,UAAU,KAAK,KAAK;AAAA,IAC/B,CAAC;AACD,aAAS,KAAK,MAAM,iBAAiB,KAAK,CAAC;AAAA,EAC7C;AACF;AAEA,SAAS,SAAS,SAAsD;AACtE,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,SAAuB,CAAC;AAC9B,YAAQ,GAAG,QAAQ,CAAC,UAAU;AAC5B,aAAO,KAAK,OAAO,UAAU,WAAW,OAAO,KAAK,KAAK,IAAI,KAAK;AAAA,IACpE,CAAC;AACD,YAAQ,GAAG,OAAO,MAAM;AACtB;AAAA,QACE,OAAO,SAAS,IAAI,OAAO,OAAO,MAAM,EAAE,SAAS,MAAM,IAAI;AAAA,MAC/D;AAAA,IACF,CAAC;AACD,YAAQ,GAAG,SAAS,MAAM;AAAA,EAC5B,CAAC;AACH;","names":[]}
|
|
@@ -56,11 +56,7 @@ function createHonoProvider(provider) {
|
|
|
56
56
|
app.post(
|
|
57
57
|
"/token",
|
|
58
58
|
async (context) => provider.handle(
|
|
59
|
-
|
|
60
|
-
method: "POST",
|
|
61
|
-
headers: context.req.raw.headers,
|
|
62
|
-
body: context.req.raw.body
|
|
63
|
-
})
|
|
59
|
+
createForwardedRequest(context.req.raw)
|
|
64
60
|
)
|
|
65
61
|
);
|
|
66
62
|
return app;
|
|
@@ -109,6 +105,18 @@ function getBearerToken(header) {
|
|
|
109
105
|
}
|
|
110
106
|
return token;
|
|
111
107
|
}
|
|
108
|
+
function createForwardedRequest(request) {
|
|
109
|
+
const hasBody = request.method !== "GET" && request.method !== "HEAD";
|
|
110
|
+
const init = {
|
|
111
|
+
method: request.method,
|
|
112
|
+
headers: request.headers
|
|
113
|
+
};
|
|
114
|
+
if (hasBody) {
|
|
115
|
+
init.body = request.body;
|
|
116
|
+
init.duplex = "half";
|
|
117
|
+
}
|
|
118
|
+
return new Request(request.url, init);
|
|
119
|
+
}
|
|
112
120
|
// Annotate the CommonJS export names for ESM import in node:
|
|
113
121
|
0 && (module.exports = {
|
|
114
122
|
createHonoGuard,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/frameworks/hono/index.ts","../../../src/core/errors.ts"],"sourcesContent":["import { Hono } from \"hono\";\nimport { createMiddleware } from \"hono/factory\";\n\nimport { AuthError } from \"../../core/errors\";\nimport type { ServiceIdentity } from \"../../core/token\";\nimport type { Provider } from \"../../provider\";\n\nexport interface GuardVerifier {\n verify(token: string): Promise<ServiceIdentity>;\n}\n\nexport function createHonoProvider(provider: Provider): Hono {\n const app = new Hono();\n\n app.get(\"/.well-known/jwks.json\", async (context) =>\n provider.handle(\n new Request(context.req.raw.url, {\n method: \"GET\",\n headers: context.req.raw.headers,\n }),\n ),\n );\n\n app.post(\"/token\", async (context) =>\n provider.handle(\n
|
|
1
|
+
{"version":3,"sources":["../../../src/frameworks/hono/index.ts","../../../src/core/errors.ts"],"sourcesContent":["import { Hono } from \"hono\";\nimport { createMiddleware } from \"hono/factory\";\n\nimport { AuthError } from \"../../core/errors\";\nimport type { ServiceIdentity } from \"../../core/token\";\nimport type { Provider } from \"../../provider\";\n\nexport interface GuardVerifier {\n verify(token: string): Promise<ServiceIdentity>;\n}\n\nexport function createHonoProvider(provider: Provider): Hono {\n const app = new Hono();\n\n app.get(\"/.well-known/jwks.json\", async (context) =>\n provider.handle(\n new Request(context.req.raw.url, {\n method: \"GET\",\n headers: context.req.raw.headers,\n }),\n ),\n );\n\n app.post(\"/token\", async (context) =>\n provider.handle(\n createForwardedRequest(context.req.raw),\n ),\n );\n\n return app;\n}\n\nexport function createHonoGuard(guard: GuardVerifier) {\n return createMiddleware(async (context, next) => {\n const header = context.req.header(\"authorization\");\n const token = getBearerToken(header);\n\n if (!token) {\n return context.json(\n {\n error: \"missing_token\",\n message: \"Missing bearer token\",\n },\n 401,\n );\n }\n\n try {\n const identity = await guard.verify(token);\n context.set(\"trustline\", identity);\n await next();\n } catch (error) {\n const authError =\n error instanceof AuthError\n ? error\n : new AuthError(\n \"invalid_token\",\n \"Token verification failed\",\n 401,\n error,\n );\n return context.json(\n {\n error: authError.code,\n message: authError.message,\n },\n authError.status as 401 | 403,\n );\n }\n });\n}\n\nfunction getBearerToken(header: string | undefined): string | null {\n if (!header) {\n return null;\n }\n\n const [scheme, token] = header.split(/\\s+/, 2);\n if (scheme?.toLowerCase() !== \"bearer\" || !token) {\n return null;\n }\n\n return token;\n}\n\nfunction createForwardedRequest(request: Request): Request {\n const hasBody = request.method !== \"GET\" && request.method !== \"HEAD\";\n const init: RequestInit & { duplex?: \"half\" } = {\n method: request.method,\n headers: request.headers,\n };\n\n if (hasBody) {\n init.body = request.body;\n init.duplex = \"half\";\n }\n\n return new Request(request.url, init);\n}\n","export type AuthErrorCode =\n | \"missing_token\"\n | \"invalid_token\"\n | \"invalid_issuer\"\n | \"invalid_audience\"\n | \"invalid_scope\"\n | \"invalid_env\"\n | \"jwks_fetch_failed\";\n\nexport class AuthError extends Error {\n public readonly code: AuthErrorCode;\n public readonly status: number;\n public readonly cause?: unknown;\n\n constructor(\n code: AuthErrorCode,\n message: string,\n status: number,\n cause?: unknown,\n ) {\n super(message);\n this.name = \"AuthError\";\n this.code = code;\n this.status = status;\n this.cause = cause;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAqB;AACrB,qBAAiC;;;ACQ1B,IAAM,YAAN,cAAwB,MAAM;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EAEhB,YACE,MACA,SACA,QACA,OACA;AACA,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,QAAQ;AAAA,EACf;AACF;;;ADfO,SAAS,mBAAmB,UAA0B;AAC3D,QAAM,MAAM,IAAI,iBAAK;AAErB,MAAI;AAAA,IAAI;AAAA,IAA0B,OAAO,YACvC,SAAS;AAAA,MACP,IAAI,QAAQ,QAAQ,IAAI,IAAI,KAAK;AAAA,QAC/B,QAAQ;AAAA,QACR,SAAS,QAAQ,IAAI,IAAI;AAAA,MAC3B,CAAC;AAAA,IACH;AAAA,EACF;AAEA,MAAI;AAAA,IAAK;AAAA,IAAU,OAAO,YACxB,SAAS;AAAA,MACP,uBAAuB,QAAQ,IAAI,GAAG;AAAA,IACxC;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,gBAAgB,OAAsB;AACpD,aAAO,iCAAiB,OAAO,SAAS,SAAS;AAC/C,UAAM,SAAS,QAAQ,IAAI,OAAO,eAAe;AACjD,UAAM,QAAQ,eAAe,MAAM;AAEnC,QAAI,CAAC,OAAO;AACV,aAAO,QAAQ;AAAA,QACb;AAAA,UACE,OAAO;AAAA,UACP,SAAS;AAAA,QACX;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,QAAI;AACF,YAAM,WAAW,MAAM,MAAM,OAAO,KAAK;AACzC,cAAQ,IAAI,aAAa,QAAQ;AACjC,YAAM,KAAK;AAAA,IACb,SAAS,OAAO;AACd,YAAM,YACJ,iBAAiB,YACb,QACA,IAAI;AAAA,QACF;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACN,aAAO,QAAQ;AAAA,QACb;AAAA,UACE,OAAO,UAAU;AAAA,UACjB,SAAS,UAAU;AAAA,QACrB;AAAA,QACA,UAAU;AAAA,MACZ;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEA,SAAS,eAAe,QAA2C;AACjE,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AAEA,QAAM,CAAC,QAAQ,KAAK,IAAI,OAAO,MAAM,OAAO,CAAC;AAC7C,MAAI,QAAQ,YAAY,MAAM,YAAY,CAAC,OAAO;AAChD,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,uBAAuB,SAA2B;AACzD,QAAM,UAAU,QAAQ,WAAW,SAAS,QAAQ,WAAW;AAC/D,QAAM,OAA0C;AAAA,IAC9C,QAAQ,QAAQ;AAAA,IAChB,SAAS,QAAQ;AAAA,EACnB;AAEA,MAAI,SAAS;AACX,SAAK,OAAO,QAAQ;AACpB,SAAK,SAAS;AAAA,EAChB;AAEA,SAAO,IAAI,QAAQ,QAAQ,KAAK,IAAI;AACtC;","names":[]}
|
|
@@ -19,11 +19,7 @@ function createHonoProvider(provider) {
|
|
|
19
19
|
app.post(
|
|
20
20
|
"/token",
|
|
21
21
|
async (context) => provider.handle(
|
|
22
|
-
|
|
23
|
-
method: "POST",
|
|
24
|
-
headers: context.req.raw.headers,
|
|
25
|
-
body: context.req.raw.body
|
|
26
|
-
})
|
|
22
|
+
createForwardedRequest(context.req.raw)
|
|
27
23
|
)
|
|
28
24
|
);
|
|
29
25
|
return app;
|
|
@@ -72,6 +68,18 @@ function getBearerToken(header) {
|
|
|
72
68
|
}
|
|
73
69
|
return token;
|
|
74
70
|
}
|
|
71
|
+
function createForwardedRequest(request) {
|
|
72
|
+
const hasBody = request.method !== "GET" && request.method !== "HEAD";
|
|
73
|
+
const init = {
|
|
74
|
+
method: request.method,
|
|
75
|
+
headers: request.headers
|
|
76
|
+
};
|
|
77
|
+
if (hasBody) {
|
|
78
|
+
init.body = request.body;
|
|
79
|
+
init.duplex = "half";
|
|
80
|
+
}
|
|
81
|
+
return new Request(request.url, init);
|
|
82
|
+
}
|
|
75
83
|
export {
|
|
76
84
|
createHonoGuard,
|
|
77
85
|
createHonoProvider
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/frameworks/hono/index.ts"],"sourcesContent":["import { Hono } from \"hono\";\nimport { createMiddleware } from \"hono/factory\";\n\nimport { AuthError } from \"../../core/errors\";\nimport type { ServiceIdentity } from \"../../core/token\";\nimport type { Provider } from \"../../provider\";\n\nexport interface GuardVerifier {\n verify(token: string): Promise<ServiceIdentity>;\n}\n\nexport function createHonoProvider(provider: Provider): Hono {\n const app = new Hono();\n\n app.get(\"/.well-known/jwks.json\", async (context) =>\n provider.handle(\n new Request(context.req.raw.url, {\n method: \"GET\",\n headers: context.req.raw.headers,\n }),\n ),\n );\n\n app.post(\"/token\", async (context) =>\n provider.handle(\n
|
|
1
|
+
{"version":3,"sources":["../../../src/frameworks/hono/index.ts"],"sourcesContent":["import { Hono } from \"hono\";\nimport { createMiddleware } from \"hono/factory\";\n\nimport { AuthError } from \"../../core/errors\";\nimport type { ServiceIdentity } from \"../../core/token\";\nimport type { Provider } from \"../../provider\";\n\nexport interface GuardVerifier {\n verify(token: string): Promise<ServiceIdentity>;\n}\n\nexport function createHonoProvider(provider: Provider): Hono {\n const app = new Hono();\n\n app.get(\"/.well-known/jwks.json\", async (context) =>\n provider.handle(\n new Request(context.req.raw.url, {\n method: \"GET\",\n headers: context.req.raw.headers,\n }),\n ),\n );\n\n app.post(\"/token\", async (context) =>\n provider.handle(\n createForwardedRequest(context.req.raw),\n ),\n );\n\n return app;\n}\n\nexport function createHonoGuard(guard: GuardVerifier) {\n return createMiddleware(async (context, next) => {\n const header = context.req.header(\"authorization\");\n const token = getBearerToken(header);\n\n if (!token) {\n return context.json(\n {\n error: \"missing_token\",\n message: \"Missing bearer token\",\n },\n 401,\n );\n }\n\n try {\n const identity = await guard.verify(token);\n context.set(\"trustline\", identity);\n await next();\n } catch (error) {\n const authError =\n error instanceof AuthError\n ? error\n : new AuthError(\n \"invalid_token\",\n \"Token verification failed\",\n 401,\n error,\n );\n return context.json(\n {\n error: authError.code,\n message: authError.message,\n },\n authError.status as 401 | 403,\n );\n }\n });\n}\n\nfunction getBearerToken(header: string | undefined): string | null {\n if (!header) {\n return null;\n }\n\n const [scheme, token] = header.split(/\\s+/, 2);\n if (scheme?.toLowerCase() !== \"bearer\" || !token) {\n return null;\n }\n\n return token;\n}\n\nfunction createForwardedRequest(request: Request): Request {\n const hasBody = request.method !== \"GET\" && request.method !== \"HEAD\";\n const init: RequestInit & { duplex?: \"half\" } = {\n method: request.method,\n headers: request.headers,\n };\n\n if (hasBody) {\n init.body = request.body;\n init.duplex = \"half\";\n }\n\n return new Request(request.url, init);\n}\n"],"mappings":";;;;;AAAA,SAAS,YAAY;AACrB,SAAS,wBAAwB;AAU1B,SAAS,mBAAmB,UAA0B;AAC3D,QAAM,MAAM,IAAI,KAAK;AAErB,MAAI;AAAA,IAAI;AAAA,IAA0B,OAAO,YACvC,SAAS;AAAA,MACP,IAAI,QAAQ,QAAQ,IAAI,IAAI,KAAK;AAAA,QAC/B,QAAQ;AAAA,QACR,SAAS,QAAQ,IAAI,IAAI;AAAA,MAC3B,CAAC;AAAA,IACH;AAAA,EACF;AAEA,MAAI;AAAA,IAAK;AAAA,IAAU,OAAO,YACxB,SAAS;AAAA,MACP,uBAAuB,QAAQ,IAAI,GAAG;AAAA,IACxC;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,gBAAgB,OAAsB;AACpD,SAAO,iBAAiB,OAAO,SAAS,SAAS;AAC/C,UAAM,SAAS,QAAQ,IAAI,OAAO,eAAe;AACjD,UAAM,QAAQ,eAAe,MAAM;AAEnC,QAAI,CAAC,OAAO;AACV,aAAO,QAAQ;AAAA,QACb;AAAA,UACE,OAAO;AAAA,UACP,SAAS;AAAA,QACX;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,QAAI;AACF,YAAM,WAAW,MAAM,MAAM,OAAO,KAAK;AACzC,cAAQ,IAAI,aAAa,QAAQ;AACjC,YAAM,KAAK;AAAA,IACb,SAAS,OAAO;AACd,YAAM,YACJ,iBAAiB,YACb,QACA,IAAI;AAAA,QACF;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACN,aAAO,QAAQ;AAAA,QACb;AAAA,UACE,OAAO,UAAU;AAAA,UACjB,SAAS,UAAU;AAAA,QACrB;AAAA,QACA,UAAU;AAAA,MACZ;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEA,SAAS,eAAe,QAA2C;AACjE,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AAEA,QAAM,CAAC,QAAQ,KAAK,IAAI,OAAO,MAAM,OAAO,CAAC;AAC7C,MAAI,QAAQ,YAAY,MAAM,YAAY,CAAC,OAAO;AAChD,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,uBAAuB,SAA2B;AACzD,QAAM,UAAU,QAAQ,WAAW,SAAS,QAAQ,WAAW;AAC/D,QAAM,OAA0C;AAAA,IAC9C,QAAQ,QAAQ;AAAA,IAChB,SAAS,QAAQ;AAAA,EACnB;AAEA,MAAI,SAAS;AACX,SAAK,OAAO,QAAQ;AACpB,SAAK,SAAS;AAAA,EAChB;AAEA,SAAO,IAAI,QAAQ,QAAQ,KAAK,IAAI;AACtC;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "trustline",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Service identity and authorization for modern JavaScript runtimes",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -61,6 +61,10 @@
|
|
|
61
61
|
"build": "tsup",
|
|
62
62
|
"check": "biome check .",
|
|
63
63
|
"changeset": "changeset",
|
|
64
|
+
"example:hono:auth": "node examples/hono-services/auth.js",
|
|
65
|
+
"example:hono:caller": "node examples/hono-services/caller.js",
|
|
66
|
+
"example:hono:receiver": "node examples/hono-services/receiver.js",
|
|
67
|
+
"example:hono:all": "npm run example:hono:auth & npm run example:hono:caller & npm run example:hono:receiver",
|
|
64
68
|
"format": "biome check --write .",
|
|
65
69
|
"lint": "biome lint .",
|
|
66
70
|
"release": "bun run release:check && changeset publish",
|