Skip to content

Commit

Permalink
feat: custom bindings for cloud-prem (part 1) (#868)
Browse files Browse the repository at this point in the history
Instead of having to provision resources directly from the config, we'd like to bind to existing resources in users' CF accounts. For example, you have an R2 bucket that you'd like to access from your partykit project. Now, you can add this to your `partykit.json`:

```jsonc
{
  //...
  "bindings": {
    "r2": {
      "myBucket": "my-bucket-name"
    }
  }
}
```

Inside your project, you can now access the r2 bucket with `room.context.bindings.r2.myBucket` (or `lobby.bindings.r2.myBucket`).

We'll add more types of bindings in the near future.
  • Loading branch information
threepointone committed Apr 10, 2024
1 parent 8d27fcb commit b337e86
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 8 deletions.
22 changes: 22 additions & 0 deletions .changeset/new-cycles-tease.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
"partykit": patch
---

feat: custom bindings for cloud-prem (part 1)

Instead of having to provision resources directly from the config, we'd like to bind to existing resources in users' CF accounts. For example, you have an R2 bucket that you'd like to access from your partykit project. Now, you can add this to your `partykit.json`:

```jsonc
{
//...
"bindings": {
"r2": {
"myBucket": "my-bucket-name"
}
}
}
```

Inside your project, you can now access the r2 bucket with `room.context.bindings.r2.myBucket` (or `lobby.bindings.r2.myBucket`).

We'll add more types of bindings in the near future.
18 changes: 18 additions & 0 deletions apps/site/public/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,24 @@
},
"analytics": {
"type": "string"
},
"bindings": {
"type": "object",
"properties": {
"r2": {
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"kv": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"additionalProperties": false
}
},
"additionalProperties": false,
Expand Down
49 changes: 42 additions & 7 deletions packages/partykit/facade/source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ declare const Worker: Party.PartyKitServer;

declare const PARTYKIT_HOST: string;

declare const __R2_BINDINGS__: string[];
declare const __KV_BINDINGS__: string[];

function assert(condition: unknown, msg?: string): asserts condition {
if (!condition) {
throw new Error(msg);
Expand Down Expand Up @@ -80,6 +83,31 @@ function isClassWorker(worker: unknown): worker is Party.Worker {
);
}

function getBindings(env: Env): {
r2: Record<string, R2Bucket>;
kv: Record<string, KVNamespace>;
} {
const r2Bindings = __R2_BINDINGS__;
const kvBindings = __KV_BINDINGS__;

return {
r2: r2Bindings.reduce(
(acc, name) => {
acc[name] = env[name] as unknown as R2Bucket;
return acc;
},
{} as Record<string, R2Bucket>
),
kv: kvBindings.reduce(
(acc, name) => {
acc[name] = env[name] as unknown as KVNamespace;
return acc;
},
{} as Record<string, KVNamespace>
)
};
}

class PartyDurable {}

type DurableObjectNamespaceEnv = {
Expand Down Expand Up @@ -372,7 +400,8 @@ function createDurable(
}
});
}
}
},
bindings: getBindings(env)
},
getConnection(id: string) {
if (self.connectionManager) {
Expand Down Expand Up @@ -774,7 +803,8 @@ export default {
},
parties,
vectorize: vectorizeBindings,
analytics: MockAnalyticsDataset
analytics: MockAnalyticsDataset,
bindings: getBindings(env)
},
ctx
);
Expand Down Expand Up @@ -824,7 +854,8 @@ export default {
}
},
vectorize: vectorizeBindings,
analytics: MockAnalyticsDataset
analytics: MockAnalyticsDataset,
bindings: getBindings(env)
},
ctx
);
Expand Down Expand Up @@ -878,7 +909,8 @@ export default {
fetch(path: string) {
return assetsFetch(path, env, ctx);
}
}
},
bindings: getBindings(env)
},
ctx
);
Expand Down Expand Up @@ -922,7 +954,8 @@ export default {
fetch(path: string) {
return assetsFetch(path, env, ctx);
}
}
},
bindings: getBindings(env)
},
ctx
);
Expand All @@ -944,7 +977,8 @@ export default {
fetch(path: string) {
return assetsFetch(path, env, ctx);
}
}
},
bindings: getBindings(env)
},
ctx
);
Expand Down Expand Up @@ -1031,7 +1065,8 @@ export default {
fetch(path: string) {
return assetsFetch(path, env, ctx);
}
}
},
bindings: getBindings(env)
},
ctx
);
Expand Down
18 changes: 18 additions & 0 deletions packages/partykit/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,24 @@
},
"analytics": {
"type": "string"
},
"bindings": {
"type": "object",
"properties": {
"r2": {
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"kv": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"additionalProperties": false
}
},
"additionalProperties": false,
Expand Down
4 changes: 4 additions & 0 deletions packages/partykit/src/cli.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -924,6 +924,10 @@ export const ${name} = ${name}Party;
form.set("analytics", config.analytics);
}

if (config.bindings) {
form.set("bindings", JSON.stringify(config.bindings));
}

// if (config.placement) {
// form.set("placement", JSON.stringify(config.placement));
// }
Expand Down
8 changes: 7 additions & 1 deletion packages/partykit/src/config-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,13 @@ export const schema = z
.optional(),
logpush: z.boolean().optional(),
tailConsumers: z.array(z.string()).optional(),
analytics: z.string().optional()
analytics: z.string().optional(),
bindings: z
.object({
r2: z.record(z.string()).optional(),
kv: z.record(z.string()).optional()
})
.optional()
// placement: z
// .object({
// mode: z.enum(["smart"])
Expand Down
14 changes: 14 additions & 0 deletions packages/partykit/src/dev.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -764,6 +764,14 @@ function useDev(options: DevProps): {
stdin: {
contents: workerFacade
.replace("__WORKER__", absoluteScriptPath)
.replace(
"__R2_BINDINGS__",
JSON.stringify(Object.keys(config.bindings?.r2 || []))
)
.replace(
"__KV_BINDINGS__",
JSON.stringify(Object.keys(config.bindings?.kv || []))
)
.replace(
"__PARTIES__",
Object.entries(config.parties || {})
Expand Down Expand Up @@ -939,6 +947,12 @@ Workers["${name}"] = ${name};
r2Persist: path.join(persistencePath, "r2"),
d1Persist: path.join(persistencePath, "d1")
}),
...(config.bindings?.r2
? { r2Buckets: Object.keys(config.bindings.r2) }
: {}),
...(config.bindings?.kv
? { kvNamespaces: Object.keys(config.bindings.kv) }
: {}),
// @ts-expect-error miniflare's types are wrong
modules: [
{
Expand Down
15 changes: 15 additions & 0 deletions packages/partykit/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import type {
Request as CFRequest,
DurableObjectState,
DurableObjectStorage,
KVNamespace,
R2Bucket,
ScheduledController,
VectorizeIndex,
WebSocket
Expand Down Expand Up @@ -83,6 +85,11 @@ export type Context = {
* A binding to fetch static assets
*/
assets: AssetFetcher;

/**
* Custom bindings
*/
bindings: CustomBindings;
};

export type AI = Record<string, never>;
Expand All @@ -94,6 +101,7 @@ export type FetchLobby = {
vectorize: Context["vectorize"];
analytics: AnalyticsEngineDataset;
assets: AssetFetcher;
bindings: CustomBindings;
};

export type CronLobby = {
Expand All @@ -103,6 +111,7 @@ export type CronLobby = {
vectorize: Context["vectorize"];
analytics: AnalyticsEngineDataset;
assets: AssetFetcher;
bindings: CustomBindings;
};

export type Lobby = {
Expand All @@ -113,6 +122,7 @@ export type Lobby = {
vectorize: Context["vectorize"];
analytics: AnalyticsEngineDataset;
assets: AssetFetcher;
bindings: CustomBindings;
};

export type ExecutionContext = CFExecutionContext;
Expand Down Expand Up @@ -167,6 +177,11 @@ export type Connection<TState = unknown> = WebSocket & {
deserializeAttachment<T = unknown>(): T | null;
};

type CustomBindings = {
r2: Record<string, R2Bucket>;
kv: Record<string, KVNamespace>;
};

/** Room represents a single, self-contained, long-lived session. */
export type Room = {
/** Room ID defined in the Party URL, e.g. /parties/:name/:id */
Expand Down

0 comments on commit b337e86

Please sign in to comment.