@plutocms/supabase 0.30.0 → 0.31.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.
- package/CHANGELOG.md +7 -0
- package/app/components/EnvPersistWarning.vue +11 -9
- package/app/components/SupabaseLogo.vue +47 -0
- package/app/components/backend/SupabaseBackendDetails.vue +1 -1
- package/app/components/mail/AuthEmailsPanel.vue +3 -2
- package/app/pages/admin/migrations.vue +21 -19
- package/app/pages/admin/roles.vue +117 -119
- package/app/pages/admin/setup.vue +160 -271
- package/app/pages/admin/users.vue +191 -189
- package/i18n/locales/en.json +17 -19
- package/i18n/locales/pt-BR.json +17 -19
- package/modules/internal/supabase-types-shim.ts +27 -0
- package/modules/pluto-migrations.ts +17 -10
- package/package.json +2 -2
- package/app/layouts/setup.vue +0 -13
|
@@ -266,183 +266,185 @@ function menuItems(user: AccessUser): DropdownMenuItem[][] {
|
|
|
266
266
|
</script>
|
|
267
267
|
|
|
268
268
|
<template>
|
|
269
|
-
<
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
<
|
|
273
|
-
|
|
274
|
-
</h1>
|
|
275
|
-
|
|
276
|
-
<PlutoAdminNavTabs />
|
|
277
|
-
|
|
278
|
-
<div class="flex flex-wrap items-start justify-between gap-4">
|
|
279
|
-
<div>
|
|
280
|
-
<h2 class="text-xl font-semibold">
|
|
281
|
-
{{ t('supabase.access.users.title') }}
|
|
282
|
-
</h2>
|
|
283
|
-
<p class="text-muted text-sm">
|
|
284
|
-
{{ t('supabase.access.users.description') }}
|
|
285
|
-
</p>
|
|
286
|
-
</div>
|
|
287
|
-
|
|
288
|
-
<UButton v-if="isAdmin" icon="lucide:user-plus" @click="openInvite">
|
|
289
|
-
{{ t('supabase.access.users.invite') }}
|
|
290
|
-
</UButton>
|
|
291
|
-
</div>
|
|
292
|
-
|
|
293
|
-
<UAlert
|
|
294
|
-
v-if="!allowed"
|
|
295
|
-
:title="t('pluto.settings.noPermission.title')"
|
|
296
|
-
:description="
|
|
297
|
-
t('pluto.settings.noPermission.description', {
|
|
298
|
-
page: t('supabase.access.users.title'),
|
|
299
|
-
})
|
|
300
|
-
"
|
|
301
|
-
icon="lucide:lock"
|
|
302
|
-
color="warning"
|
|
303
|
-
/>
|
|
304
|
-
|
|
305
|
-
<!-- Loading -->
|
|
306
|
-
<div
|
|
307
|
-
v-else-if="status === 'loading'"
|
|
308
|
-
class="flex flex-col gap-y-3"
|
|
309
|
-
aria-busy="true"
|
|
310
|
-
>
|
|
311
|
-
<USkeleton v-for="row in 4" :key="row" class="h-12 w-full" />
|
|
312
|
-
</div>
|
|
313
|
-
|
|
314
|
-
<!-- Error -->
|
|
315
|
-
<UAlert
|
|
316
|
-
v-else-if="status === 'error'"
|
|
317
|
-
:title="t('supabase.access.users.error.title')"
|
|
318
|
-
:description="loadError"
|
|
319
|
-
:actions="[
|
|
320
|
-
{
|
|
321
|
-
label: t('pluto.common.tryAgain'),
|
|
322
|
-
color: 'neutral',
|
|
323
|
-
variant: 'outline',
|
|
324
|
-
onClick: load,
|
|
325
|
-
},
|
|
326
|
-
]"
|
|
327
|
-
color="error"
|
|
328
|
-
variant="subtle"
|
|
329
|
-
icon="lucide:circle-x"
|
|
330
|
-
/>
|
|
331
|
-
|
|
332
|
-
<!-- Empty -->
|
|
333
|
-
<UEmpty
|
|
334
|
-
v-else-if="users.length === 0"
|
|
335
|
-
:title="t('supabase.access.users.empty.title')"
|
|
336
|
-
:description="t('supabase.access.users.empty.description')"
|
|
337
|
-
:actions="
|
|
338
|
-
isAdmin
|
|
339
|
-
? [
|
|
340
|
-
{
|
|
341
|
-
label: t('supabase.access.users.invite'),
|
|
342
|
-
icon: 'lucide:user-plus',
|
|
343
|
-
onClick: openInvite,
|
|
344
|
-
},
|
|
345
|
-
]
|
|
346
|
-
: []
|
|
347
|
-
"
|
|
269
|
+
<PlutoViewAdminPanel>
|
|
270
|
+
<!-- The section (the Users item of the menu) and its tabs, like Settings. -->
|
|
271
|
+
<template #toolbar>
|
|
272
|
+
<PlutoViewToolbar
|
|
273
|
+
:title="t('supabase.access.users.title')"
|
|
348
274
|
icon="lucide:users"
|
|
349
|
-
/>
|
|
350
|
-
|
|
351
|
-
<!-- The list -->
|
|
352
|
-
<UTable
|
|
353
|
-
v-else
|
|
354
|
-
:data="users"
|
|
355
|
-
:columns="columns"
|
|
356
|
-
class="border-default rounded-lg border"
|
|
357
275
|
>
|
|
358
|
-
<template #
|
|
359
|
-
<
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
userDisplayName(row.original)
|
|
363
|
-
}}</span>
|
|
364
|
-
<UBadge
|
|
365
|
-
v-if="row.original.id === selfId"
|
|
366
|
-
:label="t('supabase.access.users.you')"
|
|
367
|
-
color="primary"
|
|
368
|
-
variant="subtle"
|
|
369
|
-
size="sm"
|
|
370
|
-
/>
|
|
371
|
-
</span>
|
|
372
|
-
<span
|
|
373
|
-
v-if="row.original.email"
|
|
374
|
-
class="text-muted truncate text-sm"
|
|
375
|
-
>{{ row.original.email }}</span
|
|
376
|
-
>
|
|
377
|
-
</div>
|
|
276
|
+
<template #right>
|
|
277
|
+
<UButton v-if="isAdmin" icon="lucide:user-plus" @click="openInvite">
|
|
278
|
+
{{ t('supabase.access.users.invite') }}
|
|
279
|
+
</UButton>
|
|
378
280
|
</template>
|
|
281
|
+
</PlutoViewToolbar>
|
|
379
282
|
|
|
380
|
-
|
|
381
|
-
|
|
283
|
+
<PlutoAdminNavTabs />
|
|
284
|
+
</template>
|
|
285
|
+
|
|
286
|
+
<p class="text-muted text-sm">
|
|
287
|
+
{{ t('supabase.access.users.description') }}
|
|
288
|
+
</p>
|
|
289
|
+
|
|
290
|
+
<UAlert
|
|
291
|
+
v-if="!allowed"
|
|
292
|
+
:title="t('pluto.settings.noPermission.title')"
|
|
293
|
+
:description="
|
|
294
|
+
t('pluto.settings.noPermission.description', {
|
|
295
|
+
page: t('supabase.access.users.title'),
|
|
296
|
+
})
|
|
297
|
+
"
|
|
298
|
+
icon="lucide:lock"
|
|
299
|
+
color="warning"
|
|
300
|
+
/>
|
|
301
|
+
|
|
302
|
+
<!-- Loading -->
|
|
303
|
+
<div
|
|
304
|
+
v-else-if="status === 'loading'"
|
|
305
|
+
class="flex flex-col gap-y-3"
|
|
306
|
+
aria-busy="true"
|
|
307
|
+
>
|
|
308
|
+
<USkeleton v-for="row in 4" :key="row" class="h-12 w-full" />
|
|
309
|
+
</div>
|
|
310
|
+
|
|
311
|
+
<!-- Error -->
|
|
312
|
+
<UAlert
|
|
313
|
+
v-else-if="status === 'error'"
|
|
314
|
+
:title="t('supabase.access.users.error.title')"
|
|
315
|
+
:description="loadError"
|
|
316
|
+
:actions="[
|
|
317
|
+
{
|
|
318
|
+
label: t('pluto.common.tryAgain'),
|
|
319
|
+
color: 'neutral',
|
|
320
|
+
variant: 'outline',
|
|
321
|
+
onClick: load,
|
|
322
|
+
},
|
|
323
|
+
]"
|
|
324
|
+
color="error"
|
|
325
|
+
variant="subtle"
|
|
326
|
+
icon="lucide:circle-x"
|
|
327
|
+
/>
|
|
328
|
+
|
|
329
|
+
<!-- Empty -->
|
|
330
|
+
<UEmpty
|
|
331
|
+
v-else-if="users.length === 0"
|
|
332
|
+
:title="t('supabase.access.users.empty.title')"
|
|
333
|
+
:description="t('supabase.access.users.empty.description')"
|
|
334
|
+
:actions="
|
|
335
|
+
isAdmin
|
|
336
|
+
? [
|
|
337
|
+
{
|
|
338
|
+
label: t('supabase.access.users.invite'),
|
|
339
|
+
icon: 'lucide:user-plus',
|
|
340
|
+
onClick: openInvite,
|
|
341
|
+
},
|
|
342
|
+
]
|
|
343
|
+
: []
|
|
344
|
+
"
|
|
345
|
+
icon="lucide:users"
|
|
346
|
+
/>
|
|
347
|
+
|
|
348
|
+
<!-- The list -->
|
|
349
|
+
<UTable
|
|
350
|
+
v-else
|
|
351
|
+
:data="users"
|
|
352
|
+
:columns="columns"
|
|
353
|
+
class="border-default rounded-lg border"
|
|
354
|
+
>
|
|
355
|
+
<template #user-cell="{ row }">
|
|
356
|
+
<div class="flex min-w-0 flex-col">
|
|
357
|
+
<span class="flex items-center gap-2">
|
|
358
|
+
<span class="text-highlighted truncate font-medium">{{
|
|
359
|
+
userDisplayName(row.original)
|
|
360
|
+
}}</span>
|
|
382
361
|
<UBadge
|
|
383
|
-
v-if="
|
|
384
|
-
:label="t('supabase.access.users.
|
|
362
|
+
v-if="row.original.id === selfId"
|
|
363
|
+
:label="t('supabase.access.users.you')"
|
|
385
364
|
color="primary"
|
|
386
365
|
variant="subtle"
|
|
366
|
+
size="sm"
|
|
387
367
|
/>
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
368
|
+
</span>
|
|
369
|
+
<span v-if="row.original.email" class="text-muted truncate text-sm">{{
|
|
370
|
+
row.original.email
|
|
371
|
+
}}</span>
|
|
372
|
+
</div>
|
|
373
|
+
</template>
|
|
374
|
+
|
|
375
|
+
<template #roles-cell="{ row }">
|
|
376
|
+
<div class="flex flex-wrap gap-1">
|
|
377
|
+
<UBadge
|
|
378
|
+
v-if="isAdminUser(row.original)"
|
|
379
|
+
:label="t('supabase.access.users.administrator')"
|
|
380
|
+
color="primary"
|
|
381
|
+
variant="subtle"
|
|
382
|
+
/>
|
|
383
|
+
<template v-else>
|
|
402
384
|
<UBadge
|
|
403
|
-
v-
|
|
404
|
-
:
|
|
405
|
-
|
|
385
|
+
v-for="key in row.original.roles"
|
|
386
|
+
:key="key"
|
|
387
|
+
:label="roleLabelOf(roles, key)"
|
|
388
|
+
color="neutral"
|
|
406
389
|
variant="subtle"
|
|
407
390
|
/>
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
</
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
:
|
|
445
|
-
|
|
391
|
+
</template>
|
|
392
|
+
</div>
|
|
393
|
+
</template>
|
|
394
|
+
|
|
395
|
+
<template #status-cell="{ row }">
|
|
396
|
+
<div class="flex flex-col items-start gap-1">
|
|
397
|
+
<UBadge
|
|
398
|
+
v-if="userStatus(row.original) === 'active'"
|
|
399
|
+
:label="t('supabase.access.users.status.active')"
|
|
400
|
+
color="success"
|
|
401
|
+
variant="subtle"
|
|
402
|
+
/>
|
|
403
|
+
<template v-else>
|
|
404
|
+
<UBadge
|
|
405
|
+
:label="t('supabase.access.users.status.invited')"
|
|
406
|
+
color="warning"
|
|
407
|
+
variant="subtle"
|
|
408
|
+
/>
|
|
409
|
+
<span v-if="row.original.invited_at" class="text-muted text-xs">
|
|
410
|
+
{{
|
|
411
|
+
t('supabase.access.users.status.invitedOn', {
|
|
412
|
+
date: dateText(row.original.invited_at, {
|
|
413
|
+
dateStyle: 'medium',
|
|
414
|
+
}),
|
|
415
|
+
})
|
|
416
|
+
}}
|
|
417
|
+
</span>
|
|
418
|
+
</template>
|
|
419
|
+
</div>
|
|
420
|
+
</template>
|
|
421
|
+
|
|
422
|
+
<template #lastSignIn-cell="{ row }">
|
|
423
|
+
<span v-if="row.original.last_sign_in_at" class="text-sm">
|
|
424
|
+
{{
|
|
425
|
+
dateText(row.original.last_sign_in_at, {
|
|
426
|
+
dateStyle: 'medium',
|
|
427
|
+
timeStyle: 'short',
|
|
428
|
+
})
|
|
429
|
+
}}
|
|
430
|
+
</span>
|
|
431
|
+
<span v-else class="text-muted text-sm">{{
|
|
432
|
+
t('supabase.access.users.neverSignedIn')
|
|
433
|
+
}}</span>
|
|
434
|
+
</template>
|
|
435
|
+
|
|
436
|
+
<template #actions-cell="{ row }">
|
|
437
|
+
<div v-if="isAdmin" class="flex justify-end">
|
|
438
|
+
<UDropdownMenu
|
|
439
|
+
:items="menuItems(row.original)"
|
|
440
|
+
:content="{ align: 'end' }"
|
|
441
|
+
>
|
|
442
|
+
<UTooltip
|
|
443
|
+
:text="
|
|
444
|
+
t('supabase.access.users.actionsLabel', {
|
|
445
|
+
name: userDisplayName(row.original),
|
|
446
|
+
})
|
|
447
|
+
"
|
|
446
448
|
>
|
|
447
449
|
<UButton
|
|
448
450
|
:aria-label="
|
|
@@ -454,27 +456,27 @@ function menuItems(user: AccessUser): DropdownMenuItem[][] {
|
|
|
454
456
|
color="neutral"
|
|
455
457
|
variant="ghost"
|
|
456
458
|
/>
|
|
457
|
-
</
|
|
458
|
-
</
|
|
459
|
-
</
|
|
460
|
-
</
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
</
|
|
459
|
+
</UTooltip>
|
|
460
|
+
</UDropdownMenu>
|
|
461
|
+
</div>
|
|
462
|
+
</template>
|
|
463
|
+
</UTable>
|
|
464
|
+
|
|
465
|
+
<!-- Lazy: the chunk loads on the first open. -->
|
|
466
|
+
<InviteModal
|
|
467
|
+
v-if="inviteMounted"
|
|
468
|
+
v-model:open="inviteOpen"
|
|
469
|
+
:roles="roles"
|
|
470
|
+
:capabilities="capabilities"
|
|
471
|
+
@done="load"
|
|
472
|
+
/>
|
|
473
|
+
<EditRolesSlideover
|
|
474
|
+
v-if="editMounted"
|
|
475
|
+
v-model:open="editOpen"
|
|
476
|
+
:user="editUser"
|
|
477
|
+
:roles="roles"
|
|
478
|
+
:self="editUser?.id === selfId"
|
|
479
|
+
@saved="load"
|
|
480
|
+
/>
|
|
481
|
+
</PlutoViewAdminPanel>
|
|
480
482
|
</template>
|
package/i18n/locales/en.json
CHANGED
|
@@ -146,22 +146,20 @@
|
|
|
146
146
|
"checkConsole": "Please check the console for more details."
|
|
147
147
|
},
|
|
148
148
|
"setup": {
|
|
149
|
-
"title": "
|
|
150
|
-
"
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
},
|
|
154
|
-
"
|
|
155
|
-
"
|
|
156
|
-
"
|
|
157
|
-
"
|
|
158
|
-
"
|
|
159
|
-
"
|
|
160
|
-
"
|
|
161
|
-
"
|
|
162
|
-
"
|
|
163
|
-
"technicalDetailsStored": "After the setup is complete, the password will NOT be stored or used for any other purpose.",
|
|
164
|
-
"restartDescription": "Saving your connection string writes it to .env. In development, that restarts the server automatically. The page will briefly show a reconnecting message — this is expected, not an error.",
|
|
149
|
+
"title": "Set up the database",
|
|
150
|
+
"description": "Pluto creates its tables in your Supabase project. Paste the connection details of the database.",
|
|
151
|
+
"connectionHelp": "Copy the URI of the Transaction pooler from the {link} of your project.",
|
|
152
|
+
"connectionHelpLink": "Connect panel",
|
|
153
|
+
"passwordHelp": "It replaces {placeholder} in the URI. You can reset it in the {link}.",
|
|
154
|
+
"passwordHelpLink": "database settings",
|
|
155
|
+
"stored": "The connection stays on the server: it is saved in `.env` as `DATABASE_URL`, for the next updates of the tables. It is never sent back to the browser.",
|
|
156
|
+
"howItWorks": "What happens",
|
|
157
|
+
"detailsRequest": "The button sends the connection to a {route} of this site.",
|
|
158
|
+
"detailsRoute": "server route",
|
|
159
|
+
"detailsRun": "The server connects to your database and runs the {files} of Pluto and of its layers.",
|
|
160
|
+
"detailsFiles": "SQL migrations",
|
|
161
|
+
"restartNote": "In development, saving `.env` restarts the server. The page waits and reconnects.",
|
|
162
|
+
"submit": "Set up the database",
|
|
165
163
|
"restartingDescription": "Setup is finishing. Reconnecting…",
|
|
166
164
|
"reconnectedDescription": "The server is back. Your database has been set up.",
|
|
167
165
|
"failed": "Database setup failed",
|
|
@@ -169,9 +167,9 @@
|
|
|
169
167
|
"complete": "Database setup complete",
|
|
170
168
|
"completeDescription": "Your database has been set up successfully.",
|
|
171
169
|
"error": "Error setting up the database",
|
|
172
|
-
"doneTitle": "
|
|
173
|
-
"doneDescription": "
|
|
174
|
-
"goToSignup": "
|
|
170
|
+
"doneTitle": "The database is ready",
|
|
171
|
+
"doneDescription": "Now create your administrator account.",
|
|
172
|
+
"goToSignup": "Create the account"
|
|
175
173
|
},
|
|
176
174
|
"migrations": {
|
|
177
175
|
"title": "Migrations",
|
package/i18n/locales/pt-BR.json
CHANGED
|
@@ -146,22 +146,20 @@
|
|
|
146
146
|
"checkConsole": "Verifique o console para ver mais detalhes."
|
|
147
147
|
},
|
|
148
148
|
"setup": {
|
|
149
|
-
"title": "
|
|
150
|
-
"
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
},
|
|
154
|
-
"
|
|
155
|
-
"
|
|
156
|
-
"
|
|
157
|
-
"
|
|
158
|
-
"
|
|
159
|
-
"
|
|
160
|
-
"
|
|
161
|
-
"
|
|
162
|
-
"
|
|
163
|
-
"technicalDetailsStored": "Depois que a configuração terminar, a senha NÃO será armazenada nem usada para nenhum outro fim.",
|
|
164
|
-
"restartDescription": "Salvar sua string de conexão a grava no arquivo .env. Em desenvolvimento, isso reinicia o servidor automaticamente. A página vai exibir brevemente uma mensagem de reconexão. Isso é esperado e não é um erro.",
|
|
149
|
+
"title": "Configure o banco de dados",
|
|
150
|
+
"description": "O Pluto cria as tabelas dele no seu projeto do Supabase. Cole os dados de conexão do banco de dados.",
|
|
151
|
+
"connectionHelp": "Copie a URI do Transaction pooler no {link} do seu projeto.",
|
|
152
|
+
"connectionHelpLink": "painel Connect",
|
|
153
|
+
"passwordHelp": "Ela substitui {placeholder} na URI. Você pode redefini-la nas {link}.",
|
|
154
|
+
"passwordHelpLink": "configurações do banco de dados",
|
|
155
|
+
"stored": "A conexão fica no servidor: ela é salva no `.env` como `DATABASE_URL`, para as próximas atualizações das tabelas. Ela nunca volta para o navegador.",
|
|
156
|
+
"howItWorks": "O que acontece",
|
|
157
|
+
"detailsRequest": "O botão envia a conexão para uma {route} deste site.",
|
|
158
|
+
"detailsRoute": "rota do servidor",
|
|
159
|
+
"detailsRun": "O servidor se conecta ao seu banco de dados e roda as {files} do Pluto e das camadas dele.",
|
|
160
|
+
"detailsFiles": "migrações SQL",
|
|
161
|
+
"restartNote": "Em desenvolvimento, salvar o `.env` reinicia o servidor. A página espera e se reconecta.",
|
|
162
|
+
"submit": "Configurar o banco de dados",
|
|
165
163
|
"restartingDescription": "A configuração está terminando. Reconectando…",
|
|
166
164
|
"reconnectedDescription": "O servidor voltou. Seu banco de dados foi configurado.",
|
|
167
165
|
"failed": "Falha ao configurar o banco de dados",
|
|
@@ -169,9 +167,9 @@
|
|
|
169
167
|
"complete": "Banco de dados configurado",
|
|
170
168
|
"completeDescription": "Seu banco de dados foi configurado com sucesso.",
|
|
171
169
|
"error": "Erro ao configurar o banco de dados",
|
|
172
|
-
"doneTitle": "
|
|
173
|
-
"doneDescription": "
|
|
174
|
-
"goToSignup": "
|
|
170
|
+
"doneTitle": "O banco de dados está pronto",
|
|
171
|
+
"doneDescription": "Agora crie sua conta de administrador.",
|
|
172
|
+
"goToSignup": "Criar a conta"
|
|
175
173
|
},
|
|
176
174
|
"migrations": {
|
|
177
175
|
"title": "Migrações",
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Not a Nuxt module: Nuxt loads every file of modules/ (and modules/*/index.ts), not this folder.
|
|
2
|
+
/**
|
|
3
|
+
* A shim that pluto-migrations wrote: one re-export of the types of an @plutocms/supabase copy
|
|
4
|
+
* (installed, or linked from a local checkout).
|
|
5
|
+
*/
|
|
6
|
+
const SEEDED_SHIM = /^export \* from '[^']*\/shared\/types\/supabase'\s*$/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The text to write to the app's `shared/types/supabase.ts`, or `null` to leave the file as it
|
|
10
|
+
* is. A missing file gets the shim. A shim that pluto-migrations wrote earlier gets the new path
|
|
11
|
+
* when the path changed: a package manager with versioned folders (Bun's
|
|
12
|
+
* `node_modules/.bun/@plutocms+supabase@<version>...`) moves the package on each update, and the
|
|
13
|
+
* old path then has no types. A file with other text (types that the app generated) stays.
|
|
14
|
+
*/
|
|
15
|
+
export function supabaseTypesShim(
|
|
16
|
+
existing: string | undefined,
|
|
17
|
+
importSpecifier: string
|
|
18
|
+
): string | null {
|
|
19
|
+
const shim = `export * from '${importSpecifier}'\n`
|
|
20
|
+
if (existing === undefined) {
|
|
21
|
+
return shim
|
|
22
|
+
}
|
|
23
|
+
if (SEEDED_SHIM.test(existing) && existing.trim() !== shim.trim()) {
|
|
24
|
+
return shim
|
|
25
|
+
}
|
|
26
|
+
return null
|
|
27
|
+
}
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from 'node:fs'
|
|
10
10
|
import { basename, dirname, join, relative } from 'node:path'
|
|
11
11
|
import { createResolver, defineNuxtModule, getLayerDirectories } from 'nuxt/kit'
|
|
12
|
+
import { supabaseTypesShim } from './internal/supabase-types-shim'
|
|
12
13
|
|
|
13
14
|
const noTransactionPattern = /^--\s*pluto:no-transaction\b/
|
|
14
15
|
|
|
@@ -116,7 +117,9 @@ export default defineNuxtModule({
|
|
|
116
117
|
nuxt.options.rootDir,
|
|
117
118
|
'shared/types/supabase.ts'
|
|
118
119
|
)
|
|
119
|
-
|
|
120
|
+
// Seed the shim when the app has none, and fix the path of an earlier
|
|
121
|
+
// shim (see supabaseTypesShim).
|
|
122
|
+
{
|
|
120
123
|
// Resolve *this exact* @plutocms/supabase instance's own snapshot
|
|
121
124
|
// (local-linked or npm-installed, whichever is actually running)
|
|
122
125
|
// rather than a bare package specifier, which would re-resolve
|
|
@@ -132,15 +135,19 @@ export default defineNuxtModule({
|
|
|
132
135
|
importSpecifier = `./${importSpecifier}`
|
|
133
136
|
}
|
|
134
137
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
138
|
+
const existing = existsSync(consumerTypesPath)
|
|
139
|
+
? readFileSync(consumerTypesPath, 'utf-8')
|
|
140
|
+
: undefined
|
|
141
|
+
const shim = supabaseTypesShim(existing, importSpecifier)
|
|
142
|
+
if (shim !== null) {
|
|
143
|
+
mkdirSync(consumerTypesDir, { recursive: true })
|
|
144
|
+
writeFileSync(consumerTypesPath, shim, 'utf-8')
|
|
145
|
+
console.warn(
|
|
146
|
+
existing === undefined
|
|
147
|
+
? '[pluto-migrations] Seeded shared/types/supabase.ts (re-exporting @plutocms/supabase types; no generated types found yet).'
|
|
148
|
+
: '[pluto-migrations] Updated the path in shared/types/supabase.ts (the @plutocms/supabase package moved).'
|
|
149
|
+
)
|
|
150
|
+
}
|
|
144
151
|
}
|
|
145
152
|
|
|
146
153
|
const layerDirs = getLayerDirectories()
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plutocms/supabase",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.31.0",
|
|
5
5
|
"description": "Supabase backend layer for Pluto",
|
|
6
6
|
"author": "Victor Ribeiro",
|
|
7
7
|
"license": "MIT",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@nuxt/ui": "^4.12.0",
|
|
33
33
|
"@nuxtjs/supabase": "^2.1.0",
|
|
34
|
-
"@plutocms/core": ">=0.
|
|
34
|
+
"@plutocms/core": ">=0.68.0 <1.0.0",
|
|
35
35
|
"@supabase/supabase-js": "^2.117.3",
|
|
36
36
|
"postgres": "^3.4.9",
|
|
37
37
|
"supabase": "^2.121.0",
|
package/app/layouts/setup.vue
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts"></script>
|
|
2
|
-
|
|
3
|
-
<template>
|
|
4
|
-
<div
|
|
5
|
-
class="dark:bg-admin-content light:bg-white font-outfit flex h-full grow flex-col"
|
|
6
|
-
>
|
|
7
|
-
<div class="flex h-full justify-center">
|
|
8
|
-
<div class="grow overflow-hidden">
|
|
9
|
-
<slot />
|
|
10
|
-
</div>
|
|
11
|
-
</div>
|
|
12
|
-
</div>
|
|
13
|
-
</template>
|