@happyvertical/smrt-template-sveltekit 0.38.26 → 0.39.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/AGENTS.md +45 -26
- package/README.md +118 -80
- package/index.js +4 -4
- package/package.json +10 -8
- package/template/.env.example +4 -8
- package/template/AGENTS.md +29 -28
- package/template/README.md +232 -398
- package/template/package.json +21 -12
- package/template/smrt.config.ts +1 -16
- package/template/src/app.d.ts +5 -4
- package/template/src/app.html +0 -1
- package/template/src/hooks.server.ts +27 -111
- package/template/src/lib/objects/Item.ts +23 -22
- package/template/src/lib/objects/index.ts +1 -1
- package/template/src/lib/server/smrt.ts +14 -22
- package/template/src/lib/server/tenancy.ts +81 -234
- package/template/src/routes/+layout.server.ts +12 -66
- package/template/src/routes/+layout.svelte +64 -76
- package/template/src/routes/+page.server.ts +67 -70
- package/template/src/routes/+page.svelte +141 -109
- package/template/src/routes/settings/+page.svelte +1 -1
- package/template/vite.config.ts +14 -4
- package/LICENSE +0 -7
|
@@ -1,106 +1,103 @@
|
|
|
1
|
-
|
|
2
|
-
* Home page server load + demo mutation.
|
|
3
|
-
*
|
|
4
|
-
* This file is the reference data-loading pattern for SMRT + SvelteKit apps:
|
|
5
|
-
*
|
|
6
|
-
* 1. **Query collections in a server `load`** — not with a client-side
|
|
7
|
-
* `fetch` on mount. SvelteKit runs this during SSR, serializes the
|
|
8
|
-
* returned data into the initial HTML, and hydrates it on the client
|
|
9
|
-
* without re-fetching. The page renders with its data on first paint;
|
|
10
|
-
* there is no empty-then-fetch waterfall and no duplicate first-render
|
|
11
|
-
* request. Server loads read the database directly through the
|
|
12
|
-
* collection API — they do not round-trip through your own
|
|
13
|
-
* `/api/*` routes.
|
|
14
|
-
*
|
|
15
|
-
* 2. **Declare one dependency key per collection** with
|
|
16
|
-
* `depends('smrt:<collection>')`, where `<collection>` matches the
|
|
17
|
-
* generated REST route segment (`/api/items` → `smrt:items`). After a
|
|
18
|
-
* mutation, client code calls `invalidate('smrt:<collection>')`
|
|
19
|
-
* (see `+page.svelte`) and every load that declared the key re-runs.
|
|
20
|
-
*
|
|
21
|
-
* 3. **Opt read-heavy SSR reads into the collection read cache** with
|
|
22
|
-
* `cache: { ttl }`. Mutations that go through SMRT (`create()`,
|
|
23
|
-
* `save()`, `delete()`) invalidate the table's cache entries
|
|
24
|
-
* in-process automatically, so the post-mutation `invalidate()`
|
|
25
|
-
* re-runs this load against fresh rows. See "Data loading" in the
|
|
26
|
-
* README for multi-replica caveats and when NOT to cache.
|
|
27
|
-
*/
|
|
28
|
-
|
|
1
|
+
import { assertOperationPermission } from '@happyvertical/smrt-users';
|
|
29
2
|
import { fail } from '@sveltejs/kit';
|
|
3
|
+
|
|
30
4
|
import type { Item } from '$lib/objects/Item';
|
|
31
|
-
import { getCollection } from '$lib/server/smrt';
|
|
5
|
+
import { getCollection, getSmrtConfig } from '$lib/server/smrt';
|
|
32
6
|
import type { Actions, PageServerLoad } from './$types';
|
|
33
7
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
8
|
+
const READ_PERMISSION = 'items.read';
|
|
9
|
+
const CREATE_PERMISSION = 'items.create';
|
|
10
|
+
|
|
11
|
+
export interface ItemRow {
|
|
12
|
+
id: string;
|
|
13
|
+
title: string;
|
|
14
|
+
status: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const load: PageServerLoad = async ({ depends, locals }) => {
|
|
37
18
|
depends('smrt:items');
|
|
38
19
|
|
|
20
|
+
const authenticated = Boolean(locals.user);
|
|
21
|
+
const hasTenant = Boolean(locals.tenantId);
|
|
22
|
+
const canRead =
|
|
23
|
+
authenticated && hasTenant && locals.permissions.includes(READ_PERMISSION);
|
|
24
|
+
const canCreate =
|
|
25
|
+
authenticated && hasTenant && locals.permissions.includes(CREATE_PERMISSION);
|
|
26
|
+
|
|
27
|
+
if (!canRead) {
|
|
28
|
+
return {
|
|
29
|
+
items: [] as ItemRow[],
|
|
30
|
+
canCreate,
|
|
31
|
+
loadError: null as string | null,
|
|
32
|
+
accessMessage: !authenticated
|
|
33
|
+
? 'Sign in before loading tenant data.'
|
|
34
|
+
: !hasTenant
|
|
35
|
+
? 'Select a tenant through a membership-gated session switch.'
|
|
36
|
+
: `Your active role does not grant ${READ_PERMISSION}.`,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
39
40
|
try {
|
|
40
41
|
const items = await getCollection<Item>('Item');
|
|
41
42
|
const rows = await items.list({
|
|
42
43
|
orderBy: 'created_at DESC',
|
|
43
44
|
limit: 50,
|
|
44
|
-
// Opt this SSR read into the collection read cache (issue #1499).
|
|
45
|
-
// Safe here because all writes go through SMRT, which invalidates the
|
|
46
|
-
// table's entries in this process. Running multiple replicas? Add
|
|
47
|
-
// `crossProcess: true` or drop the cache — see the README.
|
|
48
|
-
cache: { ttl: 30_000 },
|
|
49
45
|
});
|
|
50
46
|
|
|
51
47
|
return {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
items: rows
|
|
59
|
-
.filter((item): item is Item & { id: string } => Boolean(item.id))
|
|
60
|
-
.map((item) => ({
|
|
61
|
-
id: item.id,
|
|
62
|
-
title: item.title,
|
|
63
|
-
status: item.status,
|
|
64
|
-
})),
|
|
48
|
+
items: rows.flatMap((item): ItemRow[] =>
|
|
49
|
+
item.id
|
|
50
|
+
? [{ id: item.id, title: item.title, status: item.status }]
|
|
51
|
+
: [],
|
|
52
|
+
),
|
|
53
|
+
canCreate,
|
|
65
54
|
loadError: null as string | null,
|
|
55
|
+
accessMessage: null as string | null,
|
|
66
56
|
};
|
|
67
|
-
} catch (
|
|
68
|
-
// First run before `smrt db:setup` has created the tables: render the
|
|
69
|
-
// page with guidance instead of a 500.
|
|
57
|
+
} catch (error) {
|
|
70
58
|
return {
|
|
71
|
-
items: [] as
|
|
72
|
-
|
|
59
|
+
items: [] as ItemRow[],
|
|
60
|
+
canCreate,
|
|
61
|
+
loadError:
|
|
62
|
+
error instanceof Error ? error.message : 'Failed to load items',
|
|
63
|
+
accessMessage: null as string | null,
|
|
73
64
|
};
|
|
74
65
|
}
|
|
75
66
|
};
|
|
76
67
|
|
|
77
68
|
export const actions: Actions = {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
69
|
+
create: async ({ request, locals }) => {
|
|
70
|
+
if (!locals.user?.id || !locals.tenantId) {
|
|
71
|
+
return fail(401, { error: 'Authentication and an active tenant are required.' });
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const decision = await assertOperationPermission({
|
|
75
|
+
...getSmrtConfig('Item'),
|
|
76
|
+
action: 'create',
|
|
77
|
+
collection: 'items',
|
|
78
|
+
onDeny: 'return',
|
|
79
|
+
permissionSet: locals.permissions,
|
|
80
|
+
tenantId: locals.tenantId,
|
|
81
|
+
userId: locals.user.id,
|
|
82
|
+
});
|
|
83
|
+
if (!decision.allowed) {
|
|
84
|
+
return fail(403, { error: `Missing permission: ${CREATE_PERMISSION}` });
|
|
85
|
+
}
|
|
86
|
+
|
|
89
87
|
const form = await request.formData();
|
|
90
88
|
const title = String(form.get('title') ?? '').trim();
|
|
91
|
-
|
|
92
89
|
if (!title) {
|
|
93
|
-
return fail(400, { title, error: 'Title is required' });
|
|
90
|
+
return fail(400, { title, error: 'Title is required.' });
|
|
94
91
|
}
|
|
95
92
|
|
|
96
93
|
try {
|
|
97
94
|
const items = await getCollection<Item>('Item');
|
|
98
95
|
await items.create({ title });
|
|
99
96
|
return { created: title };
|
|
100
|
-
} catch (
|
|
97
|
+
} catch (error) {
|
|
101
98
|
return fail(500, {
|
|
102
99
|
title,
|
|
103
|
-
error:
|
|
100
|
+
error: error instanceof Error ? error.message : 'Failed to create item',
|
|
104
101
|
});
|
|
105
102
|
}
|
|
106
103
|
},
|
|
@@ -3,158 +3,191 @@
|
|
|
3
3
|
import { invalidate } from '$app/navigation';
|
|
4
4
|
import type { PageProps } from './$types';
|
|
5
5
|
|
|
6
|
-
// `data` comes from the server load in `+page.server.ts`. It is fetched
|
|
7
|
-
// during SSR, serialized into the initial HTML, and hydrated here — the
|
|
8
|
-
// first client render issues NO fetch for it. It re-runs only when
|
|
9
|
-
// something calls `invalidate('smrt:items')` (below) or on navigation.
|
|
10
6
|
let { data, form }: PageProps = $props();
|
|
11
|
-
|
|
12
7
|
let creating = $state(false);
|
|
13
8
|
</script>
|
|
14
9
|
|
|
15
10
|
<svelte:head>
|
|
16
|
-
<title>
|
|
11
|
+
<title>s-m-r-t SvelteKit starter</title>
|
|
17
12
|
</svelte:head>
|
|
18
13
|
|
|
19
|
-
<!--
|
|
20
|
-
This page renders inside the root layout's <AdminShell> `<main>`
|
|
21
|
-
(`src/routes/+layout.svelte`). Its server load + `invalidate('smrt:items')`
|
|
22
|
-
refresh flow is unchanged by the shell — the shell is chrome around the
|
|
23
|
-
page, not a replacement for its data loading. A plain wrapper element (not a
|
|
24
|
-
second <main>) keeps the HTML valid.
|
|
25
|
-
-->
|
|
26
14
|
<div class="page">
|
|
27
|
-
<
|
|
15
|
+
<header>
|
|
16
|
+
<p class="eyebrow">s-m-r-t 0.38.25</p>
|
|
17
|
+
<h1>Learn the application foundation</h1>
|
|
18
|
+
<p>
|
|
19
|
+
One object, SQLite defaults, server-loaded data, generated interfaces,
|
|
20
|
+
session-authorized tenancy, and room to grow.
|
|
21
|
+
</p>
|
|
22
|
+
</header>
|
|
28
23
|
|
|
29
24
|
<section>
|
|
30
|
-
<
|
|
25
|
+
<div class="section-heading">
|
|
26
|
+
<div>
|
|
27
|
+
<h2>Items</h2>
|
|
28
|
+
<p>The initial list comes from <code>+page.server.ts</code>.</p>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
31
|
|
|
32
32
|
{#if data.loadError}
|
|
33
|
-
<p class="error">{data.loadError}</p>
|
|
34
|
-
<p>
|
|
33
|
+
<p class="notice notice--error">{data.loadError}</p>
|
|
34
|
+
<p>Run <code>pnpm db:migrate</code> after changing object fields.</p>
|
|
35
|
+
{:else if data.accessMessage}
|
|
36
|
+
<p class="notice">{data.accessMessage}</p>
|
|
35
37
|
{:else if data.items.length === 0}
|
|
36
|
-
<p>No items yet
|
|
38
|
+
<p class="notice">No items yet.</p>
|
|
37
39
|
{:else}
|
|
38
|
-
<ul>
|
|
40
|
+
<ul class="items">
|
|
39
41
|
{#each data.items as item (item.id)}
|
|
40
42
|
<li>
|
|
41
43
|
<strong>{item.title}</strong>
|
|
42
|
-
<span
|
|
44
|
+
<span>{item.status}</span>
|
|
43
45
|
</li>
|
|
44
46
|
{/each}
|
|
45
47
|
</ul>
|
|
46
48
|
{/if}
|
|
47
49
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
try {
|
|
63
|
-
// Apply the action result (sets `form`, resets the input) but
|
|
64
|
-
// skip SvelteKit's default invalidateAll() — we re-run only the
|
|
65
|
-
// loads that depend on this collection.
|
|
66
|
-
await update({ invalidateAll: false });
|
|
67
|
-
if (result.type === 'success') {
|
|
68
|
-
await invalidate('smrt:items');
|
|
50
|
+
{#if data.canCreate}
|
|
51
|
+
<form
|
|
52
|
+
method="POST"
|
|
53
|
+
action="?/create"
|
|
54
|
+
use:enhance={() => {
|
|
55
|
+
creating = true;
|
|
56
|
+
return async ({ result, update }) => {
|
|
57
|
+
try {
|
|
58
|
+
await update({ invalidateAll: false });
|
|
59
|
+
if (result.type === 'success') {
|
|
60
|
+
await invalidate('smrt:items');
|
|
61
|
+
}
|
|
62
|
+
} finally {
|
|
63
|
+
creating = false;
|
|
69
64
|
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
required
|
|
83
|
-
/>
|
|
84
|
-
<button type="submit" disabled={creating}>
|
|
85
|
-
{creating ? 'Creating…' : 'Create item'}
|
|
86
|
-
</button>
|
|
87
|
-
</form>
|
|
65
|
+
};
|
|
66
|
+
}}
|
|
67
|
+
>
|
|
68
|
+
<label for="title">New item</label>
|
|
69
|
+
<div class="form-row">
|
|
70
|
+
<input id="title" name="title" placeholder="Write a title" required />
|
|
71
|
+
<button type="submit" disabled={creating}>
|
|
72
|
+
{creating ? 'Creating…' : 'Create item'}
|
|
73
|
+
</button>
|
|
74
|
+
</div>
|
|
75
|
+
</form>
|
|
76
|
+
{/if}
|
|
88
77
|
|
|
89
78
|
{#if form?.error}
|
|
90
|
-
<p class="error">{form.error}</p>
|
|
79
|
+
<p class="notice notice--error">{form.error}</p>
|
|
91
80
|
{/if}
|
|
92
81
|
</section>
|
|
93
82
|
|
|
94
83
|
<section>
|
|
95
|
-
<h2>
|
|
96
|
-
<
|
|
97
|
-
<li>Edit <code>src/lib/objects/Item.ts</code
|
|
98
|
-
<li>
|
|
99
|
-
<li>
|
|
100
|
-
<li>
|
|
101
|
-
|
|
102
|
-
</ul>
|
|
84
|
+
<h2>Where to extend</h2>
|
|
85
|
+
<ol>
|
|
86
|
+
<li>Edit <code>src/lib/objects/Item.ts</code>.</li>
|
|
87
|
+
<li>Run <code>pnpm db:migrate</code>.</li>
|
|
88
|
+
<li>Add pages that query collections in <code>+page.server.ts</code>.</li>
|
|
89
|
+
<li>Add membership-gated login and tenant-switch actions for your app.</li>
|
|
90
|
+
</ol>
|
|
103
91
|
</section>
|
|
104
92
|
</div>
|
|
105
93
|
|
|
106
94
|
<style>
|
|
107
95
|
.page {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
96
|
+
display: grid;
|
|
97
|
+
gap: var(--smrt-spacing-6);
|
|
98
|
+
width: min(100%, 56rem);
|
|
99
|
+
margin-inline: auto;
|
|
100
|
+
padding: var(--smrt-spacing-8);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
header,
|
|
104
|
+
section,
|
|
105
|
+
.section-heading,
|
|
106
|
+
form {
|
|
107
|
+
display: grid;
|
|
108
|
+
gap: var(--smrt-spacing-3);
|
|
112
109
|
}
|
|
113
110
|
|
|
114
|
-
|
|
115
|
-
|
|
111
|
+
header p,
|
|
112
|
+
h1,
|
|
113
|
+
h2,
|
|
114
|
+
section p {
|
|
115
|
+
margin: 0;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.eyebrow {
|
|
119
|
+
color: var(--smrt-color-primary);
|
|
120
|
+
font: var(--smrt-typography-label-large);
|
|
121
|
+
letter-spacing: 0.08em;
|
|
122
|
+
text-transform: uppercase;
|
|
116
123
|
}
|
|
117
124
|
|
|
118
125
|
section {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
126
|
+
padding: var(--smrt-spacing-6);
|
|
127
|
+
border: 1px solid var(--smrt-color-outline-variant);
|
|
128
|
+
border-radius: var(--smrt-radius-large);
|
|
129
|
+
background: var(--smrt-color-surface);
|
|
123
130
|
}
|
|
124
131
|
|
|
125
|
-
.
|
|
126
|
-
|
|
132
|
+
.notice {
|
|
133
|
+
padding: var(--smrt-spacing-3);
|
|
134
|
+
border-radius: var(--smrt-radius-medium);
|
|
135
|
+
background: var(--smrt-color-surface-container);
|
|
136
|
+
color: var(--smrt-color-on-surface-variant);
|
|
127
137
|
}
|
|
128
138
|
|
|
129
|
-
.
|
|
130
|
-
|
|
131
|
-
background: #e0e0e0;
|
|
132
|
-
padding: 2px 8px;
|
|
133
|
-
border-radius: var(--smrt-radius-sm, 4px);
|
|
134
|
-
margin-left: 8px;
|
|
139
|
+
.notice--error {
|
|
140
|
+
color: var(--smrt-color-error);
|
|
135
141
|
}
|
|
136
142
|
|
|
137
|
-
|
|
143
|
+
.items {
|
|
144
|
+
display: grid;
|
|
145
|
+
gap: var(--smrt-spacing-2);
|
|
146
|
+
margin: 0;
|
|
147
|
+
padding: 0;
|
|
148
|
+
list-style: none;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.items li {
|
|
138
152
|
display: flex;
|
|
139
|
-
|
|
140
|
-
|
|
153
|
+
justify-content: space-between;
|
|
154
|
+
gap: var(--smrt-spacing-3);
|
|
155
|
+
padding-block: var(--smrt-spacing-2);
|
|
156
|
+
border-block-end: 1px solid var(--smrt-color-outline-variant);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.items span {
|
|
160
|
+
color: var(--smrt-color-on-surface-variant);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
label {
|
|
164
|
+
font-weight: var(--smrt-typography-weight-semibold);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.form-row {
|
|
168
|
+
display: flex;
|
|
169
|
+
gap: var(--smrt-spacing-2);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
input,
|
|
173
|
+
button {
|
|
174
|
+
min-height: 2.75rem;
|
|
175
|
+
padding-inline: var(--smrt-spacing-3);
|
|
176
|
+
border-radius: var(--smrt-radius-medium);
|
|
177
|
+
font: inherit;
|
|
141
178
|
}
|
|
142
179
|
|
|
143
180
|
input {
|
|
144
181
|
flex: 1;
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
font-size: 1em;
|
|
182
|
+
border: 1px solid var(--smrt-color-outline);
|
|
183
|
+
background: var(--smrt-color-surface);
|
|
184
|
+
color: var(--smrt-color-on-surface);
|
|
149
185
|
}
|
|
150
186
|
|
|
151
187
|
button {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
background: #667eea;
|
|
156
|
-
color: white;
|
|
157
|
-
font-size: 1em;
|
|
188
|
+
border: 0;
|
|
189
|
+
background: var(--smrt-color-primary);
|
|
190
|
+
color: var(--smrt-color-on-primary);
|
|
158
191
|
cursor: pointer;
|
|
159
192
|
}
|
|
160
193
|
|
|
@@ -164,18 +197,17 @@
|
|
|
164
197
|
}
|
|
165
198
|
|
|
166
199
|
code {
|
|
167
|
-
|
|
168
|
-
padding: 2px 6px;
|
|
169
|
-
border-radius: var(--smrt-radius-sm, 4px);
|
|
170
|
-
font-size: 0.9em;
|
|
200
|
+
font-family: var(--smrt-typography-code-font-family, monospace);
|
|
171
201
|
}
|
|
172
202
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
203
|
+
@media (max-width: 42rem) {
|
|
204
|
+
.page {
|
|
205
|
+
padding: var(--smrt-spacing-4);
|
|
206
|
+
}
|
|
177
207
|
|
|
178
|
-
|
|
179
|
-
|
|
208
|
+
.form-row {
|
|
209
|
+
align-items: stretch;
|
|
210
|
+
flex-direction: column;
|
|
211
|
+
}
|
|
180
212
|
}
|
|
181
213
|
</style>
|
package/template/vite.config.ts
CHANGED
|
@@ -18,10 +18,24 @@ export default defineConfig({
|
|
|
18
18
|
},
|
|
19
19
|
plugins: [
|
|
20
20
|
sveltekit(),
|
|
21
|
+
// Only packages whose object manifests this app consumes belong here.
|
|
22
|
+
// Keeping the list explicit avoids treating tooling/UI packages as domain
|
|
23
|
+
// model providers and makes generated runtime registration deterministic.
|
|
24
|
+
smrtConsumer({
|
|
25
|
+
packages: [
|
|
26
|
+
'@happyvertical/smrt-profiles',
|
|
27
|
+
'@happyvertical/smrt-tenancy',
|
|
28
|
+
'@happyvertical/smrt-users',
|
|
29
|
+
],
|
|
30
|
+
generateTypes: true,
|
|
31
|
+
typesDir: 'src/lib/types/smrt-generated',
|
|
32
|
+
svelteKit: true,
|
|
33
|
+
}),
|
|
21
34
|
smrtPlugin({
|
|
22
35
|
include: ['src/lib/objects/**/*.ts'],
|
|
23
36
|
exclude: ['**/*.test.ts', '**/*.spec.ts'],
|
|
24
37
|
generateTypes: true,
|
|
38
|
+
typeDeclarationsPath: 'src/lib/types/smrt-generated',
|
|
25
39
|
svelteKit: {
|
|
26
40
|
enabled: true,
|
|
27
41
|
routesDir: 'src/routes/api',
|
|
@@ -30,9 +44,5 @@ export default defineConfig({
|
|
|
30
44
|
configFileName: 'smrt.ts',
|
|
31
45
|
},
|
|
32
46
|
}),
|
|
33
|
-
// Required alongside smrtPlugin(): this project depends on external SMRT
|
|
34
|
-
// packages (@happyvertical/smrt-users, smrt-tenancy, …), and the consumer
|
|
35
|
-
// plugin emits `.smrt/register.js` so their classes load for CLI/runtime.
|
|
36
|
-
smrtConsumer(),
|
|
37
47
|
],
|
|
38
48
|
});
|
package/LICENSE
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
Copyright <2025> <Happy Vertical Corporation>
|
|
2
|
-
|
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
-
|
|
5
|
-
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
-
|
|
7
|
-
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|