Skip to content

Commit

Permalink
feat: rm upload-api-proxy ability to route to separate environment au…
Browse files Browse the repository at this point in the history
…diences (#407)

Motivation:
* #406
* tl;dr remove some code/behavior that's not strictly needed and
@hugomrdias asked me to remove
  • Loading branch information
gobengo authored Feb 6, 2023
1 parent 4d72ba3 commit 5cfe274
Show file tree
Hide file tree
Showing 7 changed files with 32 additions and 82 deletions.
8 changes: 2 additions & 6 deletions packages/access-api/src/bindings.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { Email } from './utils/email.js'
import { Spaces } from './models/spaces.js'
import { Validations } from './models/validations.js'
import { loadConfig } from './config.js'
import { Signer as EdSigner } from '@ucanto/principal/ed25519'
import { ConnectionView, Signer as EdSigner } from '@ucanto/principal/ed25519'
import { Accounts } from './models/accounts.js'

export {}
Expand All @@ -35,7 +35,6 @@ export interface Env {
DID: `did:web:${string}`
// URLs to upload-api so we proxy invocations to it
UPLOAD_API_URL: string
UPLOAD_API_URL_STAGING: string
// secrets
PRIVATE_KEY: string
SENTRY_DSN: string
Expand All @@ -60,10 +59,7 @@ export interface RouteContext {
validations: Validations
accounts: Accounts
}
uploadApi: {
production?: URL
staging?: URL
}
uploadApi: ConnectionView
}

export type Handler = _Handler<RouteContext>
Expand Down
3 changes: 1 addition & 2 deletions packages/access-api/src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@ export function loadConfig(env) {
PRIVATE_KEY: vars.PRIVATE_KEY,
DID: DID.parse(vars.DID).did(),

UPLOAD_API_URL: env.UPLOAD_API_URL,
UPLOAD_API_URL_STAGING: env.UPLOAD_API_URL_STAGING,
UPLOAD_API_URL: env.UPLOAD_API_URL || 'https://up.web3.storage/',
// bindings
METRICS:
/** @type {import("./bindings").AnalyticsEngine} */ (
Expand Down
70 changes: 12 additions & 58 deletions packages/access-api/src/service/upload-api-proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,13 @@ function createProxyService(options) {
*/

/**
* Create a ucanto connection to an upload api url.
* Assumes upload-api at that URL decodes requests as CAR and encodes responses as CBOR.
*
* @param {UcantoHttpConnectionOptions} options
* @returns {Ucanto.ConnectionView<any>}
*/
function createUcantoHttpConnection(options) {
export function createUploadApiConnection(options) {
return Client.connect({
id: DID.parse(options.audience),
encoder: CAR,
Expand All @@ -52,79 +55,30 @@ function createUcantoHttpConnection(options) {
})
}

const uploadApiEnvironments = {
production: {
audience: /** @type {const} */ ('did:web:web3.storage'),
// dont use up.web3.storage because it won't resolve from inside cloudflare workers
// until resolution of https://github.com/web3-storage/w3protocol/issues/363
url: new URL('https://3bd9h7xn3j.execute-api.us-west-2.amazonaws.com/'),
},
staging: {
audience: /** @type {const} */ ('did:web:staging.web3.storage'),
url: new URL('https://staging.up.web3.storage'),
},
}

/**
* @typedef {keyof typeof uploadApiEnvironments} UploadApiEnvironmentName
* @typedef {typeof uploadApiEnvironments[UploadApiEnvironmentName]['audience']} UploadApiAudience
*/

/**
* @param {object} options
* @param {typeof globalThis.fetch} [options.fetch]
* @param {object} options.uploadApi
* @param {URL} [options.uploadApi.production]
* @param {URL} [options.uploadApi.staging]
*/
function getDefaultConnections(options) {
const { fetch = globalThis.fetch.bind(globalThis), uploadApi } = options
return {
default: createUcantoHttpConnection({
...uploadApiEnvironments.production,
...(uploadApi.production && { url: uploadApi.production }),
fetch,
}),
[uploadApiEnvironments.staging.audience]: createUcantoHttpConnection({
...uploadApiEnvironments.staging,
url: uploadApi.staging ?? uploadApiEnvironments.staging.url,
fetch,
}),
}
}

/**
* @template {Ucanto.ConnectionView<any>} [Connection=Ucanto.ConnectionView<any>]
* @param {object} options
* @param {typeof globalThis.fetch} [options.fetch]
* @param {{ default: Connection, [K: Ucanto.UCAN.DID]: Connection }} [options.connections]
* @param {Record<Ucanto.UCAN.DID, URL>} [options.audienceToUrl]
* @param {object} options.uploadApi
* @param {URL} [options.uploadApi.production]
* @param {URL} [options.uploadApi.staging]
* @param {import('../bindings.js').RouteContext['uploadApi']} options.uploadApi
*/
export function createUploadProxy(options) {
return createProxyService({
...options,
connections: options.connections || getDefaultConnections(options),
connections: {
default: options.uploadApi,
},
methods: ['list', 'add', 'remove', 'upload'],
})
}

/**
* @template {Ucanto.ConnectionView<any>} [Connection=Ucanto.ConnectionView<any>]
* @param {object} options
* @param {typeof globalThis.fetch} [options.fetch]
* @param {{ default: Connection, [K: Ucanto.UCAN.DID]: Connection }} [options.connections]
* @param {Record<Ucanto.UCAN.DID, URL>} [options.audienceToUrl]
* @param {object} options.uploadApi
* @param {URL} [options.uploadApi.production]
* @param {URL} [options.uploadApi.staging]
* @param {import('../bindings.js').RouteContext['uploadApi']} options.uploadApi
*/
export function createStoreProxy(options) {
return createProxyService({
...options,
connections: options.connections || getDefaultConnections(options),
connections: {
default: options.uploadApi,
},
methods: ['list', 'add', 'remove', 'store'],
})
}
15 changes: 7 additions & 8 deletions packages/access-api/src/utils/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { Accounts } from '../models/accounts.js'
import { Spaces } from '../models/spaces.js'
import { Validations } from '../models/validations.js'
import { Email } from './email.js'
import { createUploadApiConnection } from '../service/upload-api-proxy.js'
import { DID } from '@ucanto/core'

/**
* Obtains a route context object.
Expand Down Expand Up @@ -57,13 +59,10 @@ export function getContext(request, env, ctx) {
accounts: new Accounts(config.DB),
},
email: new Email({ token: config.POSTMARK_TOKEN }),
uploadApi: {
production: config.UPLOAD_API_URL
? new URL(config.UPLOAD_API_URL)
: undefined,
staging: config.UPLOAD_API_URL_STAGING
? new URL(config.UPLOAD_API_URL_STAGING)
: undefined,
},
uploadApi: createUploadApiConnection({
audience: DID.parse(config.DID).did(),
url: new URL(config.UPLOAD_API_URL),
fetch: globalThis.fetch.bind(globalThis),
}),
}
}
1 change: 0 additions & 1 deletion packages/access-api/test/helpers/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ function createBindings(env) {
LOGTAIL_TOKEN: env.LOGTAIL_TOKEN || '',
W3ACCESS_METRICS: createAnalyticsEngine(),
UPLOAD_API_URL: env.UPLOAD_API_URL || '',
UPLOAD_API_URL_STAGING: env.UPLOAD_API_URL_STAGING || '',
}
}

Expand Down
4 changes: 1 addition & 3 deletions packages/access-api/test/store-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ import {

describe('proxy store/list invocations to upload-api', function () {
for (const web3storageDid of /** @type {const} */ ([
'did:web:web3.storage',
'did:web:staging.web3.storage',
'did:web:test.web3.storage',
])) {
it(`forwards invocations with aud=${web3storageDid}`, async function () {
const mockUpstream = createMockUploadApiServer({
Expand Down Expand Up @@ -47,7 +46,6 @@ describe('proxy store/list invocations to upload-api', function () {
// @ts-ignore
PRIVATE_KEY: privateKeyFromEnv ?? process.env.PRIVATE_KEY,
UPLOAD_API_URL: mockUpstreamUrl.toString(),
UPLOAD_API_URL_STAGING: mockUpstreamUrl.toString(),
})
const spaceCreation = await createSpace(
issuer,
Expand Down
13 changes: 9 additions & 4 deletions packages/access-api/wrangler.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ database_id = "7c676e0c-b9e7-4711-97c8-7b1c8eb229ae"
ENV = "dev"
DEBUG = "true"
DID = "did:web:local.web3.storage"
UPLOAD_API_URL = "https://up.web3.storage"

[build]
command = "scripts/cli.js build"
Expand All @@ -37,12 +38,11 @@ watch_dir = "src"
[miniflare]
d1_persist = ".wrangler/miniflare"


# Dev
[env.dev]
name = "w3access-dev"
workers_dev = true
vars = { ENV = "dev", DEBUG = "false", DID = "did:web:dev.web3.storage" }
vars = { ENV = "dev", DEBUG = "false", DID = "did:web:dev.web3.storage", UPLOAD_API_URL = "https://staging.up.web3.storage" }
build = { command = "scripts/cli.js build --env dev", watch_dir = "src" }
kv_namespaces = [
{ binding = "SPACES", id = "5697e95e1aaa436788e6d697fd3350be" },
Expand All @@ -60,7 +60,7 @@ unsafe = { bindings = [
[env.staging]
name = "w3access-staging"
workers_dev = true
vars = { ENV = "staging", DEBUG = "false", DID = "did:web:staging.web3.storage" }
vars = { ENV = "staging", DEBUG = "false", DID = "did:web:staging.web3.storage", UPLOAD_API_URL = "https://staging.up.web3.storage" }
build = { command = "scripts/cli.js build --env staging", watch_dir = "src" }
kv_namespaces = [
{ binding = "SPACES", id = "b0e5ca990dda4e3784a1741dfa28a52e" },
Expand All @@ -78,7 +78,6 @@ unsafe = { bindings = [
[env.production]
name = "w3access"
routes = [{ pattern = "access.web3.storage", custom_domain = true }]
vars = { ENV = "production", DEBUG = "false", DID = "did:web:web3.storage" }
build = { command = "scripts/cli.js build --env production", watch_dir = "src" }
kv_namespaces = [
{ binding = "SPACES", id = "5437954e8cfd4f7d98557132b0a2e93f" },
Expand All @@ -90,3 +89,9 @@ d1_databases = [
unsafe = { bindings = [
{ type = "analytics_engine", dataset = "W3ACCESS_METRICS", name = "W3ACCESS_METRICS" },
] }
[env.production.vars]
DEBUG = "false"
DID = "did:web:web3.storage"
ENV = "production"
# production upload-api - bypass up.web3.storage due to cloudflare dns issue https://github.com/web3-storage/w3protocol/issues/363#issuecomment-1410887488
UPLOAD_API_URL = "https://3bd9h7xn3j.execute-api.us-west-2.amazonaws.com/"

0 comments on commit 5cfe274

Please sign in to comment.