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 CHANGED
@@ -1,5 +1,8 @@
1
1
  # Trustline
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/trustline)](https://www.npmjs.com/package/trustline)
4
+ [![docs](https://img.shields.io/badge/docs-github%20pages-blue)](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,5 +1,5 @@
1
- import { Pool } from 'mysql2';
2
1
  import { S as SqlStorageOptions, a as StorageAdapter } from '../../interface-BzT_DC3u.cjs';
2
+ import { Pool } from 'mysql2';
3
3
 
4
4
  declare function mysqlStorage(pool: Pool, options?: SqlStorageOptions): StorageAdapter;
5
5
 
@@ -1,5 +1,5 @@
1
- import { Pool } from 'mysql2';
2
1
  import { S as SqlStorageOptions, a as StorageAdapter } from '../../interface-BzT_DC3u.js';
2
+ import { Pool } from 'mysql2';
3
3
 
4
4
  declare function mysqlStorage(pool: Pool, options?: SqlStorageOptions): StorageAdapter;
5
5
 
@@ -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,5 +1,5 @@
1
- import { Pool } from 'pg';
2
1
  import { S as SqlStorageOptions, a as StorageAdapter } from '../../interface-BzT_DC3u.cjs';
2
+ import { Pool } from 'pg';
3
3
 
4
4
  declare function postgresStorage(pool: Pool, options?: SqlStorageOptions): StorageAdapter;
5
5
 
@@ -1,5 +1,5 @@
1
- import { Pool } from 'pg';
2
1
  import { S as SqlStorageOptions, a as StorageAdapter } from '../../interface-BzT_DC3u.js';
2
+ import { Pool } from 'pg';
3
3
 
4
4
  declare function postgresStorage(pool: Pool, options?: SqlStorageOptions): StorageAdapter;
5
5
 
@@ -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":"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","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/provider/express.ts","../../../src/core/errors.ts","../../../src/middleware/express.ts"],"sourcesContent":["export {\n createExpressProvider,\n type WebHandler,\n} from \"../../provider/express\";\nexport {\n createExpressGuard,\n type TrustlineRequest,\n} from \"../../middleware/express\";\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","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"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACUO,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;;;AC1CO,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;","names":[]}
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 { RequestHandler, Request as Request$1 } from 'express';
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 { RequestHandler, Request as Request$1 } from 'express';
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/provider/express.ts","../../../src/middleware/express.ts"],"sourcesContent":["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","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"],"mappings":";;;;;AAUO,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;;;ACtCO,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;","names":[]}
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
- new Request(context.req.raw.url, {
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 new Request(context.req.raw.url, {\n method: \"POST\",\n headers: context.req.raw.headers,\n body: context.req.raw.body,\n }),\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","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,IAAI,QAAQ,QAAQ,IAAI,IAAI,KAAK;AAAA,QAC/B,QAAQ;AAAA,QACR,SAAS,QAAQ,IAAI,IAAI;AAAA,QACzB,MAAM,QAAQ,IAAI,IAAI;AAAA,MACxB,CAAC;AAAA,IACH;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;","names":[]}
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
- new Request(context.req.raw.url, {
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 new Request(context.req.raw.url, {\n method: \"POST\",\n headers: context.req.raw.headers,\n body: context.req.raw.body,\n }),\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"],"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,IAAI,QAAQ,QAAQ,IAAI,IAAI,KAAK;AAAA,QAC/B,QAAQ;AAAA,QACR,SAAS,QAAQ,IAAI,IAAI;AAAA,QACzB,MAAM,QAAQ,IAAI,IAAI;AAAA,MACxB,CAAC;AAAA,IACH;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;","names":[]}
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.0",
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",