-
Notifications
You must be signed in to change notification settings - Fork 1.2k
feat: add Flagship binding support #13139
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
39 commits
Select commit
Hold shift + click to select a range
1412c56
[workers-utils] feat: add Flagship feature flag binding types and config
roerohan 1c08e92
[miniflare] feat: add Flagship remote-only plugin
roerohan 17b097b
[wrangler] feat: wire Flagship binding through deployment and dev pip…
roerohan 8756a6b
[wrangler] feat: add Flagship type generation and OAuth scopes
roerohan 48b61a1
chore: add changeset for Flagship binding support
roerohan f4b948a
Merge branch 'main' into roerohan/flagship
roerohan 1fc78cb
[miniflare] fix: flagship plugin getServices should always create ser…
roerohan a1a828c
[workers-utils] fix: add flagship to empty config defaults test expec…
roerohan 505ad9e
[workers-utils] fix: add flagship to safeBindings in validateUnsafeBi…
roerohan 0556a03
chore: fix lint and formatting issues
roerohan 07627ed
chore: bump changeset to minor for new feature
roerohan 8a3a1f7
[wrangler] fix: update OAuth scope snapshots for flagship scopes
roerohan 2c8a288
Merge branch 'main' into roerohan/flagship
roerohan 70b9069
[wrangler] fix: add flagship to type-generation test mock config
roerohan fe76547
[wrangler] fix: add FLAGS: Flags to type-generation test snapshots
roerohan 84f2895
Merge branch 'main' into roerohan/flagship
roerohan 7702b65
[wrangler] fix: restore missing 'Found Worker' lines in type-generati…
roerohan b47e65c
Merge branch 'main' into roerohan/flagship
roerohan dfeef2d
Merge remote-tracking branch 'upstream/main' into roerohan/flagship
roerohan bde6e72
fix: use import type for type-only imports in flagship plugin
roerohan 7887652
feat: add local JSRPC stub worker for flagship binding
roerohan aebf6f0
fix: use plain UUID for flagship app_id in test fixtures
roerohan 0da66f3
feat: add Miniflare class API and plugin test for flagship binding
roerohan f5b5804
fix: pass actual app_id to local worker config and mark binding as lo…
roerohan 3f637dd
Merge branch 'main' into roerohan/flagship
roerohan e7c6743
Update packages/miniflare/src/index.ts
roerohan 36ce133
fix: remove duplicate closing brace and simplify getFlagshipBinding r…
roerohan 94b9893
fix: restore full getFlagshipBinding return type with generic methods
roerohan 5bdd92d
Merge branch 'main' into roerohan/flagship
roerohan 79a9d9c
Merge branch 'main' into roerohan/flagship
roerohan 195176c
chore: update changeset
roerohan 5502d4b
fix: use Flags instead of FlagshipBinding
roerohan a307247
Merge branch 'main' into roerohan/flagship
roerohan 52be722
chore: remote bindings support
roerohan fef1869
Merge branch 'main' into roerohan/flagship
petebacondarwin 391103b
fix: address PR review comments for flagship binding
roerohan f40249e
chore: remote validity check
roerohan 5984a11
fix: add flagship to removeRemoteConfigFieldFromBindings, add tests
roerohan 5ce25e1
Merge branch 'main' into roerohan/flagship
roerohan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| --- | ||
| "miniflare": minor | ||
| "wrangler": minor | ||
| "@cloudflare/workers-utils": minor | ||
| --- | ||
|
|
||
| feat: add Flagship feature flag binding support | ||
|
roerohan marked this conversation as resolved.
|
||
|
|
||
| Adds end-to-end support for the Flagship feature flag binding, which allows Workers to evaluate feature flags from Cloudflare's Flagship service. Configure it in `wrangler.json` with a `flagship` array containing `binding` and `app_id` entries. In local dev, the binding returns default values for all flag evaluations; use `"remote": true` in the binding to evaluate flags against the live Flagship service. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| import BINDING_SCRIPT from "worker:flagship/binding"; | ||
| import { z } from "zod"; | ||
| import { | ||
| getUserBindingServiceName, | ||
| ProxyNodeBinding, | ||
| remoteProxyClientWorker, | ||
| } from "../shared"; | ||
| import type { Worker_Binding } from "../../runtime"; | ||
| import type { Plugin, RemoteProxyConnectionString } from "../shared"; | ||
|
|
||
| const FlagshipSchema = z.object({ | ||
| app_id: z.string(), | ||
| remoteProxyConnectionString: z | ||
| .custom<RemoteProxyConnectionString>() | ||
| .optional(), | ||
| }); | ||
|
|
||
| export const FlagshipOptionsSchema = z.object({ | ||
| flagship: z.record(FlagshipSchema).optional(), | ||
| }); | ||
|
|
||
| export const FLAGSHIP_PLUGIN_NAME = "flagship"; | ||
|
|
||
| export const FLAGSHIP_PLUGIN: Plugin<typeof FlagshipOptionsSchema> = { | ||
| options: FlagshipOptionsSchema, | ||
| async getBindings(options) { | ||
| if (!options.flagship) { | ||
| return []; | ||
| } | ||
|
|
||
| return Object.entries(options.flagship).map<Worker_Binding>( | ||
| ([name, config]) => ({ | ||
| name, | ||
| service: { | ||
| name: getUserBindingServiceName( | ||
| FLAGSHIP_PLUGIN_NAME, | ||
| name, | ||
| config.remoteProxyConnectionString | ||
| ), | ||
| entrypoint: "FlagshipBinding", | ||
| }, | ||
| }) | ||
| ); | ||
| }, | ||
| getNodeBindings(options: z.infer<typeof FlagshipOptionsSchema>) { | ||
| if (!options.flagship) { | ||
| return {}; | ||
| } | ||
| return Object.fromEntries( | ||
| Object.keys(options.flagship).map((name) => [ | ||
| name, | ||
| new ProxyNodeBinding(), | ||
| ]) | ||
| ); | ||
| }, | ||
| async getServices({ options }) { | ||
| if (!options.flagship) { | ||
| return []; | ||
| } | ||
|
|
||
| return Object.entries(options.flagship).map( | ||
| ([name, { remoteProxyConnectionString }]) => { | ||
| return { | ||
| name: getUserBindingServiceName( | ||
| FLAGSHIP_PLUGIN_NAME, | ||
| name, | ||
| remoteProxyConnectionString | ||
| ), | ||
| worker: remoteProxyConnectionString | ||
| ? remoteProxyClientWorker(remoteProxyConnectionString, name) | ||
| : { | ||
| compatibilityDate: "2025-03-17", | ||
| modules: [ | ||
| { | ||
| name: "binding.worker.js", | ||
| esModule: BINDING_SCRIPT(), | ||
| }, | ||
| ], | ||
| }, | ||
| }; | ||
| } | ||
| ); | ||
| }, | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
104 changes: 104 additions & 0 deletions
104
packages/miniflare/src/workers/flagship/binding.worker.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,104 @@ | ||
| // Local stub for Flagship feature flag binding. | ||
| // In local dev mode, all flag evaluations return the provided default value. | ||
| // Use `wrangler dev --remote` to evaluate flags against the real Flagship service. | ||
|
|
||
| import { WorkerEntrypoint } from "cloudflare:workers"; | ||
|
|
||
| interface EvaluationDetails<T> { | ||
| flagKey: string; | ||
| value: T; | ||
| variant?: string; | ||
| reason?: string; | ||
| errorCode?: string; | ||
| errorMessage?: string; | ||
| } | ||
|
|
||
| export class FlagshipBinding extends WorkerEntrypoint { | ||
| async get( | ||
| _flagKey: string, | ||
| defaultValue?: unknown, | ||
| _context?: Record<string, string | number | boolean> | ||
| ): Promise<unknown> { | ||
| return defaultValue; | ||
| } | ||
|
|
||
| async getBooleanValue( | ||
| _flagKey: string, | ||
| defaultValue: boolean, | ||
| _context?: Record<string, string | number | boolean> | ||
| ): Promise<boolean> { | ||
| return defaultValue; | ||
| } | ||
|
|
||
| async getStringValue( | ||
| _flagKey: string, | ||
| defaultValue: string, | ||
| _context?: Record<string, string | number | boolean> | ||
| ): Promise<string> { | ||
| return defaultValue; | ||
| } | ||
|
|
||
| async getNumberValue( | ||
| _flagKey: string, | ||
| defaultValue: number, | ||
| _context?: Record<string, string | number | boolean> | ||
| ): Promise<number> { | ||
| return defaultValue; | ||
| } | ||
|
|
||
| async getObjectValue<T extends object>( | ||
| _flagKey: string, | ||
| defaultValue: T, | ||
| _context?: Record<string, string | number | boolean> | ||
| ): Promise<T> { | ||
| return defaultValue; | ||
| } | ||
|
|
||
| async getBooleanDetails( | ||
| flagKey: string, | ||
| defaultValue: boolean, | ||
| _context?: Record<string, string | number | boolean> | ||
| ): Promise<EvaluationDetails<boolean>> { | ||
| return { | ||
| flagKey, | ||
| value: defaultValue, | ||
| reason: "DEFAULT", | ||
| }; | ||
| } | ||
|
|
||
| async getStringDetails( | ||
| flagKey: string, | ||
| defaultValue: string, | ||
| _context?: Record<string, string | number | boolean> | ||
| ): Promise<EvaluationDetails<string>> { | ||
| return { | ||
| flagKey, | ||
| value: defaultValue, | ||
| reason: "DEFAULT", | ||
| }; | ||
| } | ||
|
|
||
| async getNumberDetails( | ||
| flagKey: string, | ||
| defaultValue: number, | ||
| _context?: Record<string, string | number | boolean> | ||
| ): Promise<EvaluationDetails<number>> { | ||
| return { | ||
| flagKey, | ||
| value: defaultValue, | ||
| reason: "DEFAULT", | ||
| }; | ||
| } | ||
|
|
||
| async getObjectDetails<T extends object>( | ||
| flagKey: string, | ||
| defaultValue: T, | ||
| _context?: Record<string, string | number | boolean> | ||
| ): Promise<EvaluationDetails<T>> { | ||
| return { | ||
| flagKey, | ||
| value: defaultValue, | ||
| reason: "DEFAULT", | ||
| }; | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.