@startup-api/cloudflare 0.3.2 → 0.4.0

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.
@@ -1,6 +1,7 @@
1
1
  import { StartupAPIEnv } from '../StartupAPIEnv';
2
2
  import { CookieManager } from '../CookieManager';
3
3
  import { getUserFromSession, checkAndClearStaleSession, isAdmin, parseCookies, getActiveProviders } from './utils';
4
+ import type { ProviderConfigs } from '../auth/providers';
4
5
  import { Plan } from '../billing/Plan';
5
6
  import { UserProfileSchema } from '../schemas/user';
6
7
  import { SystemAccountSchema, MemberSchema } from '../schemas/account';
@@ -11,6 +12,7 @@ export async function handleAdmin(
11
12
  env: StartupAPIEnv,
12
13
  usersPath: string,
13
14
  cookieManager: CookieManager,
15
+ providerConfigs: ProviderConfigs = {},
14
16
  ): Promise<Response> {
15
17
  const user = await getUserFromSession(request, env, cookieManager);
16
18
  if (!user || !isAdmin(user, env)) {
@@ -31,7 +33,7 @@ export async function handleAdmin(
31
33
  html = html.replace(/\{\{ssr:([a-z0-9_]+)\}\}/g, (match, key) => {
32
34
  const replacements: Record<string, string> = {
33
35
  plans_json: JSON.stringify(Plan.getAll()).replace(/"/g, '&quot;'),
34
- providers: getActiveProviders(env).join(','),
36
+ providers: getActiveProviders(env, providerConfigs).join(','),
35
37
  };
36
38
  return replacements[key] !== undefined ? replacements[key] : match;
37
39
  });
@@ -1,6 +1,7 @@
1
1
  import { StartupAPIEnv } from '../StartupAPIEnv';
2
2
  import { CookieManager } from '../CookieManager';
3
3
  import { getUserFromSession, checkAndClearStaleSession, isAdmin, getActiveProviders } from './utils';
4
+ import type { ProviderConfigs } from '../auth/providers';
4
5
  import { Plan } from '../billing/Plan';
5
6
 
6
7
  export async function handleSSR(
@@ -9,6 +10,7 @@ export async function handleSSR(
9
10
  url: URL,
10
11
  usersPath: string,
11
12
  cookieManager: CookieManager,
13
+ providerConfigs: ProviderConfigs = {},
12
14
  ): Promise<Response> {
13
15
  const user = await getUserFromSession(request, env, cookieManager);
14
16
  if (!user) {
@@ -90,7 +92,7 @@ export async function handleSSR(
90
92
  // Prepare SSR values
91
93
  const replacements: Record<string, string> = {
92
94
  plans_json: JSON.stringify(Plan.getAll()).replace(/"/g, '&quot;'),
93
- providers: getActiveProviders(env).join(','),
95
+ providers: getActiveProviders(env, providerConfigs).join(','),
94
96
  profile_json: JSON.stringify(data).replace(/"/g, '&quot;'),
95
97
  credentials_json: JSON.stringify(credentials).replace(/"/g, '&quot;'),
96
98
  profile_name: data.profile.name || 'Anonymous',
@@ -105,7 +107,7 @@ export async function handleSSR(
105
107
  : '',
106
108
  nav_account_display: account && (account.role === 1 || data.is_admin) ? 'display: block;' : 'display: none;',
107
109
  credentials_list_html: renderCredentialsList(credentials, data.credential?.provider),
108
- link_credentials_html: renderLinkCredentialsList(getActiveProviders(env), url.href),
110
+ link_credentials_html: renderLinkCredentialsList(getActiveProviders(env, providerConfigs), url.href),
109
111
  };
110
112
 
111
113
  if (account) {
@@ -212,6 +214,8 @@ function getProviderIcon(provider: string): string {
212
214
  return '<svg viewBox="0 0 24 24" width="24" height="24" class="twitch-icon"><path d="M11.571 4.714h1.715v5.143H11.57zm4.715 0H18v5.143h-1.714zM6 0L1.714 4.286v15.428h5.143V24l4.286-4.286h3.428L22.286 12V0zm14.571 11.143l-3.428 3.428h-3.429l-3 3v-3H6.857V1.714h13.714z" fill="currentColor"/></svg>';
213
215
  } else if (provider === 'patreon') {
214
216
  return '<svg viewBox="0 0 24 24" width="24" height="24" class="patreon-icon"><path d="M14.82 2.41c3.96 0 7.18 3.24 7.18 7.21 0 3.96-3.22 7.18-7.18 7.18-3.97 0-7.21-3.22-7.21-7.18 0-3.97 3.24-7.21 7.21-7.21M2 21.6h3.5V2.41H2V21.6z" fill="currentColor"/></svg>';
217
+ } else if (provider === 'atproto') {
218
+ return '<svg viewBox="0 0 24 24" width="24" height="24" class="atproto-icon"><path d="M12 10.5C10.9 8.4 8.2 6.3 6.3 6c-1.5-.2-1.8.7-1.5 2 .2 1 1.5 5 2.3 6 .9 1.2 2 1.4 3 1.2-1.7.3-3.2 1-1.2 3 .9.9 1.6.3 2.1-.6.5-1 .8-2.1 1-2.6.2.5.5 1.6 1 2.6.5.9 1.2 1.5 2.1.6 2-2 .5-2.7-1.2-3 1 .2 2.1 0 3-1.2.8-1 2.1-5 2.3-6 .3-1.3 0-2.2-1.5-2-1.9.3-4.6 2.4-5.7 4.5z" fill="#0085FF"/></svg>';
215
219
  }
216
220
  return '';
217
221
  }
@@ -1,7 +1,9 @@
1
1
  import { StartupAPIEnv } from '../StartupAPIEnv';
2
2
  import { CookieManager } from '../CookieManager';
3
+ import { isAtprotoEnabled } from '../auth/AtprotoProvider';
4
+ import type { ProviderConfigs } from '../auth/providers';
3
5
 
4
- export function getActiveProviders(env: StartupAPIEnv): string[] {
6
+ export function getActiveProviders(env: StartupAPIEnv, providerConfigs: ProviderConfigs = {}): string[] {
5
7
  const providers: string[] = [];
6
8
  if (env.GOOGLE_CLIENT_ID && env.GOOGLE_CLIENT_SECRET) {
7
9
  providers.push('google');
@@ -12,6 +14,10 @@ export function getActiveProviders(env: StartupAPIEnv): string[] {
12
14
  if (env.PATREON_CLIENT_ID && env.PATREON_CLIENT_SECRET) {
13
15
  providers.push('patreon');
14
16
  }
17
+ // atproto has no env credentials; it is enabled purely via factory config.
18
+ if (isAtprotoEnabled(providerConfigs.atproto)) {
19
+ providers.push('atproto');
20
+ }
15
21
  return providers;
16
22
  }
17
23
 
@@ -28,6 +28,12 @@ export const ProviderOptionsSchema = z.object({
28
28
  scopes: z.union([z.string(), z.array(z.string())]).optional(),
29
29
  /** Patreon only: restrict entitlements to a single campaign id. */
30
30
  campaignId: z.string().optional(),
31
+ /** atproto only: display name advertised in the client-metadata document. Default: "StartupAPI". */
32
+ clientName: z.string().optional(),
33
+ /** atproto only: override the PLC directory used to resolve did:plc identities. Default: https://plc.directory. */
34
+ plcUrl: z.string().optional(),
35
+ /** atproto only: override the DNS-over-HTTPS resolver used for handle resolution. */
36
+ dohUrl: z.string().optional(),
31
37
  freshness: ProviderFreshnessSchema.optional(),
32
38
  });
33
39
 
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable */
2
- // Generated by Wrangler by running `wrangler types` (hash: 38595a6a948093665f11cb1bc4cd28e8)
2
+ // Generated by Wrangler by running `wrangler types` (hash: 21e6c5c76a7bbde8583fcbcc839c03e7)
3
3
  // Runtime types generated with workerd@1.20260120.0 2025-09-27 global_fetch_strictly_public
4
4
  declare namespace Cloudflare {
5
5
  interface GlobalProps {
@@ -15,7 +15,6 @@ declare namespace Cloudflare {
15
15
  ORIGIN_URL: "https://startup-api-demo-origin.sergeychernyshev.workers.dev/";
16
16
  TWITCH_CLIENT_ID: "";
17
17
  TWITCH_CLIENT_SECRET: "";
18
- GITHUB_PROJECT_ID: string;
19
18
  USER: DurableObjectNamespace<import("./src/index").UserDO>;
20
19
  ACCOUNT: DurableObjectNamespace<import("./src/index").AccountDO>;
21
20
  SYSTEM: DurableObjectNamespace<import("./src/index").SystemDO>;
@@ -36,7 +35,6 @@ declare namespace Cloudflare {
36
35
  PATREON_CLIENT_ID: "";
37
36
  PATREON_CLIENT_SECRET: "";
38
37
  PATREON_WEBHOOK_SECRET: "";
39
- GITHUB_PROJECT_ID: string;
40
38
  USER: DurableObjectNamespace<import("./src/index").UserDO>;
41
39
  ACCOUNT: DurableObjectNamespace<import("./src/index").AccountDO>;
42
40
  SYSTEM: DurableObjectNamespace<import("./src/index").SystemDO>;
@@ -56,14 +54,12 @@ declare namespace Cloudflare {
56
54
  PATREON_CLIENT_ID: "patreon-id";
57
55
  PATREON_CLIENT_SECRET: "patreon-secret";
58
56
  PATREON_WEBHOOK_SECRET: "whsec-test";
59
- GITHUB_PROJECT_ID: string;
60
57
  USER: DurableObjectNamespace<import("./src/index").UserDO>;
61
58
  ACCOUNT: DurableObjectNamespace<import("./src/index").AccountDO>;
62
59
  SYSTEM: DurableObjectNamespace<import("./src/index").SystemDO>;
63
60
  CREDENTIAL: DurableObjectNamespace<import("./src/index").CredentialDO>;
64
61
  }
65
62
  interface Env {
66
- GITHUB_PROJECT_ID: string;
67
63
  IMAGE_STORAGE: R2Bucket;
68
64
  ASSETS: Fetcher;
69
65
  ENVIRONMENT?: "preview" | "" | "test";