@plutocms/supabase 0.11.0 → 0.11.1

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.11.1](https://github.com/plutocms/supabase/compare/v0.11.0...v0.11.1) (2026-10-21)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **deps:** use @plutocms/pluto 0.17 ([#91](https://github.com/plutocms/supabase/issues/91)) ([7deeac5](https://github.com/plutocms/supabase/commit/7deeac5379ddaac0317fa457897190c0850e8ffc))
9
+ * **typegen:** keep the PostgREST version block and the app's format ([#90](https://github.com/plutocms/supabase/issues/90)) ([2518c33](https://github.com/plutocms/supabase/commit/2518c33f69fe188e69d93695819d7d3ca19932d7))
10
+
11
+
12
+ ### Performance Improvements
13
+
14
+ * **admin:** load the admin components on demand and start the setup check early ([#89](https://github.com/plutocms/supabase/issues/89)) ([f0d36bc](https://github.com/plutocms/supabase/commit/f0d36bc7d46f911522990653cd93ebb523c5a774))
15
+
3
16
  ## [0.11.0](https://github.com/plutocms/supabase/compare/v0.10.0...v0.11.0) (2026-10-20)
4
17
 
5
18
 
@@ -1,6 +1,16 @@
1
- import AuthSignIn from '../components/auth/AuthSignIn.vue'
2
- import MigrationsBanner from '../components/migrations/MigrationsBanner.vue'
3
- import SettingsGeneralPanel from '../components/settings/SettingsGeneralPanel.vue'
1
+ import { defineAsyncComponent } from 'vue'
2
+
3
+ // The three components load on demand. They stay out of the entry chunk. Core
4
+ // shows a skeleton while each chunk loads.
5
+ const AuthSignIn = defineAsyncComponent(
6
+ () => import('../components/auth/AuthSignIn.vue')
7
+ )
8
+ const MigrationsBanner = defineAsyncComponent(
9
+ () => import('../components/migrations/MigrationsBanner.vue')
10
+ )
11
+ const SettingsGeneralPanel = defineAsyncComponent(
12
+ () => import('../components/settings/SettingsGeneralPanel.vue')
13
+ )
4
14
 
5
15
  export default defineNuxtPlugin(() => {
6
16
  // Read at setup, while the Nuxt context exists. The driver below calls it
@@ -35,11 +45,7 @@ export default defineNuxtPlugin(() => {
35
45
  // again each time.
36
46
  const setupDone = useState<boolean>('supabase-setup-done', () => false)
37
47
 
38
- async function readSetupState(): Promise<SetupState> {
39
- if (setupDone.value) {
40
- return 'done'
41
- }
42
-
48
+ async function fetchSetupState(): Promise<SetupState> {
43
49
  let state: SetupState = 'unknown'
44
50
  try {
45
51
  state = setupStateFromResponse(
@@ -56,6 +62,27 @@ export default defineNuxtPlugin(() => {
56
62
  return state
57
63
  }
58
64
 
65
+ // On a cold load of an admin path, the request starts here, at plugin setup.
66
+ // The guard then awaits a request that is already in flight. The guard takes
67
+ // this promise once, so a later navigation reads the state again.
68
+ let earlyState: Promise<SetupState> | null =
69
+ import.meta.client &&
70
+ !setupDone.value &&
71
+ /^\/admin(?:\/|$)/.test(window.location.pathname)
72
+ ? fetchSetupState()
73
+ : null
74
+
75
+ async function readSetupState(): Promise<SetupState> {
76
+ if (setupDone.value) {
77
+ return 'done'
78
+ }
79
+
80
+ const early = earlyState
81
+ earlyState = null
82
+
83
+ return early ?? fetchSetupState()
84
+ }
85
+
59
86
  if (import.meta.client) {
60
87
  watch(
61
88
  [() => Boolean(session.value), hasSettingsModified],
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@plutocms/supabase",
3
3
  "type": "module",
4
- "version": "0.11.0",
4
+ "version": "0.11.1",
5
5
  "trustedDependencies": [
6
6
  "@parcel/watcher",
7
7
  "@plutocms/pluto",
@@ -39,7 +39,7 @@
39
39
  "@nuxt/eslint": "^1.17.0",
40
40
  "@nuxt/ui": "^4.12.0",
41
41
  "@nuxtjs/supabase": "^2.1.0",
42
- "@plutocms/pluto": "^0.16.0",
42
+ "@plutocms/pluto": "^0.17.0",
43
43
  "@plutocms/utils": "^0.2.1",
44
44
  "postgres": "^3.4.9",
45
45
  "supabase": "^2.121.0",
@@ -1,6 +1,8 @@
1
1
  import { execFile } from 'node:child_process'
2
2
  import { existsSync, readFileSync, writeFileSync } from 'node:fs'
3
+ import { createRequire } from 'node:module'
3
4
  import { join } from 'node:path'
5
+ import { pathToFileURL } from 'node:url'
4
6
  import { promisify } from 'node:util'
5
7
 
6
8
  const execFileAsync = promisify(execFile)
@@ -17,6 +19,63 @@ function resolveSupabaseBin(rootDir: string): string {
17
19
  return existsSync(localBin) ? localBin : 'supabase'
18
20
  }
19
21
 
22
+ // The block, with its leading comment lines. The block has no nested braces.
23
+ const INTERNAL_BLOCK = /(?:^[ \t]*\/\/[^\n]*\n)*^[ \t]*__InternalSupabase:\s*\{[^{}]*\}[ \t]*\n/m
24
+ const DATABASE_OPEN = /^export type Database = \{[ \t]*\n/m
25
+
26
+ /**
27
+ * Keeps the `__InternalSupabase` block of the existing types file.
28
+ *
29
+ * The `--db-url` mode of the Supabase CLI does not write this block. It
30
+ * holds the PostgREST version that supabase-js reads for its typings. When
31
+ * the new output has no block and the existing file has one, this function
32
+ * copies the existing block into the new output. In every other case it
33
+ * returns the new output as it is.
34
+ */
35
+ export function keepInternalSupabase(
36
+ next: string,
37
+ existing: string | null
38
+ ): string {
39
+ if (!existing || next.includes('__InternalSupabase')) {
40
+ return next
41
+ }
42
+
43
+ const block = existing.match(INTERNAL_BLOCK)?.[0]
44
+ const open = next.match(DATABASE_OPEN)
45
+
46
+ if (!block || !open || open.index === undefined) {
47
+ return next
48
+ }
49
+
50
+ const at = open.index + open[0].length
51
+
52
+ return next.slice(0, at) + block + next.slice(at)
53
+ }
54
+
55
+ /**
56
+ * Formats the text with the Prettier of the app. It resolves Prettier from
57
+ * `rootDir`. It returns the text unchanged when the app has no Prettier or
58
+ * when the format fails.
59
+ */
60
+ async function formatWithAppPrettier(
61
+ rootDir: string,
62
+ filePath: string,
63
+ text: string
64
+ ): Promise<string> {
65
+ try {
66
+ const entry = createRequire(join(rootDir, 'package.json')).resolve(
67
+ 'prettier'
68
+ )
69
+ const prettier = await import(pathToFileURL(entry).href)
70
+ const api = prettier.default ?? prettier
71
+ const options = (await api.resolveConfig(filePath)) ?? {}
72
+
73
+ return await api.format(text, { ...options, filepath: filePath })
74
+ } catch {
75
+ return text
76
+ }
77
+ }
78
+
20
79
  /**
21
80
  * Regenerates the Supabase `Database` types from the live database schema
22
81
  * and writes them to <rootDir>/shared/types/supabase.ts, only touching the
@@ -56,11 +115,17 @@ export async function regenerateSupabaseTypes(
56
115
  ? readFileSync(targetPath, 'utf-8')
57
116
  : null
58
117
 
59
- if (existing === stdout) {
118
+ const processed = await formatWithAppPrettier(
119
+ rootDir,
120
+ targetPath,
121
+ keepInternalSupabase(stdout, existing)
122
+ )
123
+
124
+ if (existing === processed) {
60
125
  return
61
126
  }
62
127
 
63
- writeFileSync(targetPath, stdout, 'utf-8')
128
+ writeFileSync(targetPath, processed, 'utf-8')
64
129
  console.warn(`[typegen] Regenerated Supabase types at ${targetPath}`)
65
130
  } catch (error) {
66
131
  console.warn('[typegen] Failed to regenerate Supabase types:', error)