Skip to content

Commit

Permalink
Put back supabasejs (#854)
Browse files Browse the repository at this point in the history
Signed-off-by: Marcos Candeia <[email protected]>
  • Loading branch information
mcandeia authored Sep 27, 2024
1 parent e42d186 commit 0ff221c
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 4 deletions.
1 change: 1 addition & 0 deletions deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export {
View,
} from "npm:@opentelemetry/[email protected]";

export * as supabase from "jsr:@supabase/[email protected]";
export { logs, SeverityNumber } from "npm:@opentelemetry/[email protected]";
export type { Logger } from "npm:@opentelemetry/[email protected]";
export { OTLPLogExporter } from "npm:@opentelemetry/[email protected]";
Expand Down
5 changes: 5 additions & 0 deletions engine/decofile/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import type { PromiseOrValue } from "../core/utils.ts";
import { ENTRYPOINT } from "./constants.ts";
import { fromEndpoint } from "./fetcher.ts";
import { newFsProvider } from "./fs.ts";
import { newRealtime } from "./realtime.ts";
import { fromConfigsTable } from "./release.ts";

export interface SelectionConfig {
audiences: unknown[];
Expand Down Expand Up @@ -102,6 +104,7 @@ const DECOFILE_PATH_FROM_ENV = Deno.env.get(DECOFILE_RELEASE_ENV_VAR);
* @returns the config store provider.
*/
export const getProvider = async (
site: string,
localStorageOnly = false,
): Promise<DecofileProvider> => {
const providers = [];
Expand All @@ -122,6 +125,8 @@ export const getProvider = async (
),
);
providers.push(fromEndpoint(endpoint));
} else {
providers.push(newRealtime(fromConfigsTable(site), true)); // if not deploy so no background is needed
}

if (Deno.env.has("USE_LOCAL_STORAGE")) {
Expand Down
102 changes: 102 additions & 0 deletions engine/decofile/release.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import type { supabase } from "../../deps.ts";
import getSupabaseClient from "../../supabase.ts";
import { randId as ulid } from "../../utils/rand.ts";
import { singleFlight } from "../core/utils.ts";
import type {
RealtimeDecofileProvider,
VersionedDecofile,
} from "./realtime.ts";

const TABLE = "configs";
const fetchDecofile = (
site: string,
): PromiseLike<{ data: VersionedDecofile | null; error: unknown }> => {
return getSupabaseClient().from(TABLE).select("state, revision").eq(
"site",
site,
).maybeSingle();
};

const JITTER_TIME_MS = 2000;
type Fetcher = () => ReturnType<typeof fetchDecofile>;
// Supabase client setup
const subscribeForDecofileChanges = (
site: string,
fetcher: Fetcher,
) =>
(
callback: (res: VersionedDecofile) => unknown,
subscriptionCallback: (
status: `${supabase.REALTIME_SUBSCRIBE_STATES}`,
err?: Error,
) => void,
) => {
return getSupabaseClient()
.channel("changes")
.on(
"postgres_changes",
{
event: "*",
schema: "public",
table: TABLE,
filter: `site=eq.${site}`,
},
(payload) => {
const newPayload = payload.new as VersionedDecofile;
if (newPayload?.state === undefined) {
console.warn("state is too big, fetching from supabase");
// we have added a jitter of 2s to prevent too many requests being issued at same time.
const jitter = Math.floor(JITTER_TIME_MS * Math.random());
setTimeout(() => {
fetcher().then(async (resp) => {
const { data, error } = resp;
if (error || !data) {
console.error("error when fetching config", error, "retrying");
const { data: secondTryData, error: secondTryError } =
await fetcher();

if (secondTryError || !secondTryData) {
console.error("error when fetching config", error);
return;
}

callback(secondTryData);
return;
}
callback(data);
});
}, jitter);
} else {
callback(newPayload);
}
},
)
.subscribe(subscriptionCallback);
};

/**
* Create a supabase decofile provider based on `configs` table.
* @param site the site name
* @returns the supabaseDecofileProvider.
*/
export const fromConfigsTable = (
site: string,
): RealtimeDecofileProvider => {
const sf = singleFlight<{ data: VersionedDecofile | null; error: unknown }>();
const fetcher = () =>
sf.do(
"flight",
async () => {
const { data, error } = await fetchDecofile(site);
return {
data: data ??
{ state: {}, revision: ulid() },
error,
};
},
);
return {
get: fetcher,
subscribe: subscribeForDecofileChanges(site, fetcher),
};
};
4 changes: 2 additions & 2 deletions engine/manifest/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ export const fulfillContext = async <
}
ctx.namespace ??= `deco-sites/${currentSite}`;
ctx.site = currentSite!;
const provider = release ?? await getProvider();
const provider = release ?? await getProvider(ctx.site);
const runtimePromise = deferred<DecoRuntimeState<T>>();
ctx.runtime = runtimePromise.finally(() => {
ctx.instance.readyAt = new Date();
Expand Down Expand Up @@ -442,7 +442,7 @@ export const $live = async <T extends AppManifest>(
(curr, acc) => buildRuntime<AppManifest, RouteContext>(curr, acc),
[m, {}, []] as [AppManifest, ResolverMap<RouteContext>, DanglingRecover[]],
);
const provider = release ?? await getProvider();
const provider = release ?? await getProvider(context.site);
context.release = provider;
const resolver = new ReleaseResolver<RouteContext>({
resolvers: { ...resolvers, ...defaultResolvers },
Expand Down
2 changes: 1 addition & 1 deletion runtime/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export class Deco<TAppManifest extends AppManifest = AppManifest> {
opts?: DecoOptions<TAppManifest>,
): Promise<Deco<TAppManifest>> {
const site = opts?.site ?? siteNameFromEnv() ?? randomSiteName();
const decofile = opts?.decofile ?? await getProvider();
const decofile = opts?.decofile ?? await getProvider(site);
const manifest = opts?.manifest ?? (await import(
toFileUrl(join(Deno.cwd(), "manifest.gen.ts")).href
).then((mod) => mod.default));
Expand Down
8 changes: 7 additions & 1 deletion scripts/codemod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,20 @@ const newJsrPackages = [
"@deco/dev",
];

const LATEST_WORKING_ADMIN_V1_VERSION = "1.101.22";
const LATEST_WORKING_ADMIN_V1_VERSION = "1.103.0";
const pinDecoVersion = denoJSON((json) => {
let decoEntry = json.content.imports?.["deco/"];
if (decoEntry) {
const [registry] = decoEntry.split("@");
decoEntry = `${registry}@${LATEST_WORKING_ADMIN_V1_VERSION}/`;
}
return {
content: {
...json.content,
imports: {
...json.content.imports,
"@deco/deco": `jsr:@deco/deco@${LATEST_WORKING_ADMIN_V1_VERSION}`,
...decoEntry && { "deco/": decoEntry },
},
},
};
Expand Down
38 changes: 38 additions & 0 deletions supabase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { supabase } from "./deps.ts";

let client: supabase.SupabaseClient | null = null;

const SUPABASE_LIVE_ENDPOINT_ENV_VAR = "SUPABASE_LIVE_ENDPOINT";
const SUPABASE_LIVE_ANON_KEY_ENV_VAR = "SUPABASE_LIVE_ANON_KEY";
const DEFAULT_SUPABASE_LIVE_ENDPOINT =
"https://ozksgdmyrqcxcwhnbepg.supabase.co";
// From supabase docs:
// "This key is safe to use in a browser if you have enabled Row Level Security for your tables and configured policies."
export const SUPABASE_LIVE_ENDPOINT = typeof Deno !== "undefined"
? Deno.env.get(SUPABASE_LIVE_ENDPOINT_ENV_VAR) ??
DEFAULT_SUPABASE_LIVE_ENDPOINT
: DEFAULT_SUPABASE_LIVE_ENDPOINT;

const DEFAULT_SUPABASE_LIVE_ANON_KEY =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im96a3NnZG15cnFjeGN3aG5iZXBnIiwicm9sZSI6ImFub24iLCJpYXQiOjE2NTY3MjM3NDYsImV4cCI6MTk3MjI5OTc0Nn0.HMdsG6NZlq6dvYFCK1_tuJh38TmsqLeN8H4OktTHt_M";

export const SUPABASE_LIVE_ANON_KEY = typeof Deno !== "undefined"
? Deno.env.get(SUPABASE_LIVE_ANON_KEY_ENV_VAR) ??
DEFAULT_SUPABASE_LIVE_ANON_KEY
: DEFAULT_SUPABASE_LIVE_ANON_KEY;

let userEndpoint = SUPABASE_LIVE_ENDPOINT;
let userKey = SUPABASE_LIVE_ANON_KEY;

export function setupSupabase(endpoint: string, key: string) {
userEndpoint = endpoint;
userKey = key;
}

export default function getSupabaseClient(accessToken?: string) {
if (!client) {
client = supabase.createClient(userEndpoint, accessToken || userKey);
}

return client;
}

0 comments on commit 0ff221c

Please sign in to comment.