Skip to content

Commit 5b235e6

Browse files
Setup the initial repository and implement ApiKeyProvider
This sets up tsc, prettier, and github actions for the project In addition, the ApiKeyProvider methods are all defined This provider is used for creating, and validating a user via api key
1 parent 56f2d25 commit 5b235e6

11 files changed

Lines changed: 324 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
13+
strategy:
14+
matrix:
15+
node-version: [22.x, 24.x]
16+
17+
steps:
18+
- name: Checkout code
19+
uses: actions/checkout@v4
20+
21+
- name: Setup Node.js ${{ matrix.node-version }}
22+
uses: actions/setup-node@v4
23+
with:
24+
node-version: ${{ matrix.node-version }}
25+
cache: 'npm'
26+
27+
- name: Install dependencies
28+
run: npm ci
29+
30+
- name: Check formatting
31+
run: npm run format:check
32+
33+
- name: Build project
34+
run: npm run build

.github/workflows/publish.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: Publish Package to npmjs
2+
on:
3+
release:
4+
types: [published]
5+
jobs:
6+
build:
7+
runs-on: ubuntu-latest
8+
permissions:
9+
contents: read
10+
id-token: write
11+
environment: production
12+
steps:
13+
- uses: actions/checkout@v4
14+
- uses: actions/setup-node@v4
15+
with:
16+
node-version: '24.x'
17+
registry-url: 'https://registry.npmjs.org'
18+
- run: npm ci
19+
- run: npm run build
20+
- name: Publish the package
21+
run: npm publish --provenance --access public

.prettierignore

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Build outputs
2+
dist/
3+
build/
4+
*.min.js
5+
6+
# Dependencies
7+
node_modules/
8+
9+
# Package files
10+
package-lock.json
11+
yarn.lock
12+
pnpm-lock.yaml
13+
14+
# Generated files
15+
*.d.ts.map
16+
17+
# Logs
18+
*.log
19+
20+
# Environment files
21+
.env
22+
.env.local
23+
.env.*.local
24+
25+
# IDE files
26+
.vscode/
27+
.idea/
28+
29+
# OS files
30+
.DS_Store
31+
Thumbs.db

.prettierrc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"semi": true,
3+
"trailingComma": "es5",
4+
"singleQuote": true,
5+
"printWidth": 120,
6+
"tabWidth": 2,
7+
"useTabs": false,
8+
"bracketSpacing": true,
9+
"arrowParens": "avoid",
10+
"endOfLine": "lf"
11+
}

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
# extensions
2+
23
Interface and shared code for building extensions for the runt ecosystem

package-lock.json

Lines changed: 69 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"name": "@runtimed/extensions",
3+
"version": "0.1.0",
4+
"description": "Interfaces and shared code for building extensions to the runt ecosystem",
5+
"keywords": [
6+
"runtimed",
7+
"runt"
8+
],
9+
"homepage": "https://github.com/runtimed/extensions#readme",
10+
"bugs": {
11+
"url": "https://github.com/runtimed/extensions/issues"
12+
},
13+
"repository": {
14+
"type": "git",
15+
"url": "git+https://github.com/runtimed/extensions.git"
16+
},
17+
"license": "BSD-3-Clause",
18+
"author": "Anil Kulkarni",
19+
"type": "module",
20+
"main": "dist/index.js",
21+
"types": "./dist/index.d.ts",
22+
"exports": {
23+
".": {
24+
"import": "./dist/index.js",
25+
"types": "./dist/index.d.ts"
26+
}
27+
},
28+
"files": [
29+
"dist",
30+
"README.md",
31+
"LICENSE"
32+
],
33+
"scripts": {
34+
"test": "echo \"Error: no test specified\" && exit 1",
35+
"format": "prettier --write .",
36+
"format:check": "prettier --check .",
37+
"build": "npx tsc"
38+
},
39+
"devDependencies": {
40+
"jose": "^6.0.12",
41+
"prettier": "^3.6.2",
42+
"typescript": "^5.9.2"
43+
},
44+
"peerDependencies": {
45+
"@cloudflare/workers-types": "^4.20250810.0"
46+
}
47+
}

src/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import type { ApiKeyProvider } from './providers/api_key';
2+
export type * from './providers/shared';
3+
4+
export type BackendExtension = {
5+
apiKey?: ApiKeyProvider;
6+
};

src/providers/api_key.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import type { Response as WorkerResponse } from '@cloudflare/workers-types';
2+
import type { Passport, ProviderContext, Scope, Resource } from './shared';
3+
4+
export enum ApiKeyCapabilities {
5+
Revoke = 'revoke',
6+
Delete = 'delete',
7+
CreateWithResources = 'create_with_resources',
8+
}
9+
10+
export type CreateApiKeyRequest = {
11+
scopes: Scope[];
12+
resources?: Resource[];
13+
expiresAt: string;
14+
name?: string;
15+
userGenerated: boolean;
16+
};
17+
18+
export type ApiKey = CreateApiKeyRequest & {
19+
id: string;
20+
userId: string;
21+
revoked: boolean;
22+
};
23+
24+
export type ApiKeyProvider = {
25+
capabilities: Set<ApiKeyCapabilities>;
26+
overrideHandler?: (context: ProviderContext) => Promise<false | WorkerResponse>; // Any routes the provider wants to fully implement. Return false for any route not handled
27+
isApiKey(context: ProviderContext): boolean; // Returns true if the auth token appears to be an API key (whether or not it is valid)
28+
validateApiKey(context: ProviderContext): Promise<Passport>; // Ensure the API key is valid, and returns the Passport. Raise an error otherwise
29+
createApiKey: (context: ProviderContext, request: CreateApiKeyRequest) => Promise<string>;
30+
getApiKey: (context: ProviderContext, id: string) => Promise<ApiKey>; // Returns the API key matching the specific api key id
31+
listApiKeys: (context: ProviderContext) => Promise<ApiKey[]>; // Return a list of all API keys for a user
32+
revokeApiKey: (context: ProviderContext, id: string) => Promise<void>; // set the revoked flag for an API key, such that it will no longer be valid
33+
deleteApiKey: (context: ProviderContext, id: string) => Promise<void>; // Delete an API key from the database
34+
};

src/providers/shared.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import type { JWTPayload } from 'jose';
2+
import type {
3+
Request as WorkerRequest,
4+
IncomingRequestCfProperties,
5+
D1Database,
6+
ExecutionContext,
7+
} from '@cloudflare/workers-types';
8+
9+
export type ProviderEnv = {
10+
DB: D1Database;
11+
AUTH_ISSUER: string;
12+
};
13+
14+
export enum AuthType {
15+
OAuth = 'oauth',
16+
ApiKey = 'api_key',
17+
}
18+
19+
export type Scope = 'runt:read' | 'runt:execute';
20+
21+
export type User = {
22+
id: string;
23+
email: string;
24+
name?: string;
25+
givenName?: string;
26+
familyName: string;
27+
};
28+
29+
export type Resource = {
30+
id: string;
31+
type: string;
32+
};
33+
34+
export type Passport = {
35+
type: AuthType;
36+
user: User;
37+
claims: JWTPayload;
38+
scopes: Scope[] | null;
39+
resources: Resource[] | null;
40+
};
41+
42+
export type ProviderContext = {
43+
request: WorkerRequest<unknown, IncomingRequestCfProperties<unknown>>;
44+
env: ProviderEnv;
45+
ctx: ExecutionContext;
46+
bearerToken: string | null;
47+
passport: Passport | null;
48+
};

0 commit comments

Comments
 (0)